Merge branch 'master' into 8044609-ssl

This commit is contained in:
Seán Coffey 2025-09-16 10:53:07 +00:00
commit c21bca38af
1816 changed files with 36981 additions and 19074 deletions

View File

@ -64,33 +64,33 @@ jobs:
gnu-arch: aarch64
debian-arch: arm64
debian-repository: https://httpredir.debian.org/debian/
debian-version: bookworm
debian-version: trixie
tolerate-sysroot-errors: false
- target-cpu: arm
gnu-arch: arm
debian-arch: armhf
debian-repository: https://httpredir.debian.org/debian/
debian-version: bookworm
debian-version: trixie
tolerate-sysroot-errors: false
gnu-abi: eabihf
- target-cpu: s390x
gnu-arch: s390x
debian-arch: s390x
debian-repository: https://httpredir.debian.org/debian/
debian-version: bookworm
debian-version: trixie
tolerate-sysroot-errors: false
- target-cpu: ppc64le
gnu-arch: powerpc64le
debian-arch: ppc64el
debian-repository: https://httpredir.debian.org/debian/
debian-version: bookworm
debian-version: trixie
tolerate-sysroot-errors: false
- target-cpu: riscv64
gnu-arch: riscv64
debian-arch: riscv64
debian-repository: https://httpredir.debian.org/debian/
debian-version: sid
tolerate-sysroot-errors: true
debian-version: trixie
tolerate-sysroot-errors: false
steps:
- name: 'Checkout the JDK source'

View File

@ -1,6 +1,6 @@
#!/bin/sh
#
# Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
# Copyright (c) 2019, 2025, Oracle and/or its affiliates. All rights reserved.
# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
#
# This code is free software; you can redistribute it and/or modify it
@ -52,12 +52,39 @@
# include the SCM state that was used to build it, which can be found in ${JDK_N_INSTALL}/release,
# in property "SOURCE".
source_path="$(dirname ${0})"
this_script_dir="$(cd -- "${source_path}" > /dev/null && pwd)"
if test -z "${this_script_dir}"; then
echo "Error: Could not determine location of this script"
exit 1
fi
symbols_dir="$(dirname $this_script_dir)/src/jdk.compiler/share/data/symbols"
if [ ! -d $symbols_dir ] ; then
echo "Cannot locate symbols directory: $symbols_dir" >&2
exit 1
fi
generator_dir="$(dirname $this_script_dir)/make/langtools/src/classes/build/tools/symbolgenerator"
if [ "$1x" = "x" ] ; then
echo "Must provide the target JDK as a parameter:" >&2
echo "$0 <target-jdk>" >&2
exit 1
fi;
if [ ! -d $1 ] ; then
echo "Target JDK argument is not a directory:" $1 >&2
exit 1
fi;
if [ ! -x $1/bin/java ] ; then
echo "Target JDK argument is not a valid JDK: $1" >&2
exit 1
fi;
cd $symbols_dir
if [ ! -f symbols ] ; then
echo "Must run inside the src/jdk.compiler/share/data/symbols directory" >&2
exit 1
@ -72,5 +99,5 @@ $1/bin/java --add-exports jdk.compiler/com.sun.tools.javac.api=ALL-UNNAMED \
--add-exports jdk.compiler/com.sun.tools.javac.jvm=ALL-UNNAMED \
--add-exports jdk.compiler/com.sun.tools.javac.util=ALL-UNNAMED \
--add-modules jdk.jdeps \
../../../../../make/langtools/src/classes/build/tools/symbolgenerator/CreateSymbols.java \
$generator_dir/CreateSymbols.java \
build-description-incremental symbols include.list

View File

@ -1,6 +1,6 @@
#! /bin/sh -f
#
# Copyright (c) 2012, 2020, Oracle and/or its affiliates. All rights reserved.
# Copyright (c) 2012, 2025, Oracle and/or its affiliates. All rights reserved.
# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
#
# This code is free software; you can redistribute it and/or modify it
@ -62,7 +62,7 @@ B=`basename "${script_directory}"`
script_dir="`cd \"${D}\" 2>/dev/null && pwd || echo \"${D}\"`/${B}"
# set up a variable for the template directory
template_dir=${script_dir}/../data/license-templates
template_dir=${script_dir}/../make/data/license-templates
# Check existence of the template directory.
if [ ! -d ${template_dir} ] ; then

View File

@ -1,191 +0,0 @@
#
# Copyright (c) 2014, 2025, Oracle and/or its affiliates. All rights reserved.
# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
#
# This code is free software; you can redistribute it and/or modify it
# under the terms of the GNU General Public License version 2 only, as
# published by the Free Software Foundation.
#
# This code is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
# version 2 for more details (a copy is included in the LICENSE file that
# accompanied this code).
#
# You should have received a copy of the GNU General Public License version
# 2 along with this work; if not, write to the Free Software Foundation,
# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
#
# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
# or visit www.oracle.com if you need additional information or have any
# questions.
#
src/bsd : jdk/src/bsd
src/demo : jdk/src/demo
src/java.activation : jaxws/src/java.activation
src/java.base : jdk/src/java.base
src/java.compiler : langtools/src/java.compiler
src/java.corba : corba/src/java.corba
src/java.datatransfer : jdk/src/java.datatransfer
src/java.desktop : jdk/src/java.desktop
src/java.instrument : jdk/src/java.instrument
src/java.logging : jdk/src/java.logging
src/java.management : jdk/src/java.management
src/java.management.rmi : jdk/src/java.management.rmi
src/java.naming : jdk/src/java.naming
src/java.prefs : jdk/src/java.prefs
src/java.rmi : jdk/src/java.rmi
src/java.scripting : jdk/src/java.scripting
src/java.se : jdk/src/java.se
src/java.security.jgss : jdk/src/java.security.jgss
src/java.security.sasl : jdk/src/java.security.sasl
src/java.se.ee : jdk/src/java.se.ee
src/java.smartcardio : jdk/src/java.smartcardio
src/java.sql : jdk/src/java.sql
src/java.sql.rowset : jdk/src/java.sql.rowset
src/java.transaction : jdk/src/java.transaction
src/java.xml : jaxp/src/java.xml
src/java.xml.bind : jaxws/src/java.xml.bind
src/java.xml.crypto : jdk/src/java.xml.crypto
src/java.xml.ws : jaxws/src/java.xml.ws
src/java.xml.ws.annotation : jaxws/src/java.xml.ws.annotation
src/jdk.accessibility : jdk/src/jdk.accessibility
src/jdk.aot : hotspot/src/jdk.aot
src/jdk.attach : jdk/src/jdk.attach
src/jdk.charsets : jdk/src/jdk.charsets
src/jdk.compiler : jdk/src/jdk.compiler langtools/src/jdk.compiler
src/jdk.crypto.cryptoki : jdk/src/jdk.crypto.cryptoki
src/jdk.crypto.ec : jdk/src/jdk.crypto.ec
src/jdk.crypto.mscapi : jdk/src/jdk.crypto.mscapi
src/jdk.dynalink : nashorn/src/jdk.dynalink
src/jdk.editpad : jdk/src/jdk.editpad
src/jdk.hotspot.agent : hotspot/src/jdk.hotspot.agent
src/jdk.httpserver : jdk/src/jdk.httpserver
src/jdk.incubator.httpclient : jdk/src/jdk.incubator.httpclient
src/jdk.internal.ed : jdk/src/jdk.internal.ed
src/jdk.internal.jvmstat : jdk/src/jdk.internal.jvmstat
src/jdk.internal.le : jdk/src/jdk.internal.le
src/jdk.internal.opt : jdk/src/jdk.internal.opt
src/jdk.internal.vm.ci : hotspot/src/jdk.internal.vm.ci
src/jdk.internal.vm.compiler : hotspot/src/jdk.internal.vm.compiler
src/jdk.jartool : jdk/src/jdk.jartool
src/jdk.javadoc : langtools/src/jdk.javadoc
src/jdk.jcmd : jdk/src/jdk.jcmd
src/jdk.jconsole : jdk/src/jdk.jconsole
src/jdk.jdeps : langtools/src/jdk.jdeps
src/jdk.jdi : jdk/src/jdk.jdi
src/jdk.jdwp.agent : jdk/src/jdk.jdwp.agent
src/jdk.jlink : jdk/src/jdk.jlink
src/jdk.jshell : langtools/src/jdk.jshell
src/jdk.jstatd : jdk/src/jdk.jstatd
src/jdk.localedata : jdk/src/jdk.localedata
src/jdk.management : jdk/src/jdk.management
src/jdk.management.agent : jdk/src/jdk.management.agent
src/jdk.naming.dns : jdk/src/jdk.naming.dns
src/jdk.naming.rmi : jdk/src/jdk.naming.rmi
src/jdk.net : jdk/src/jdk.net
src/jdk.pack : jdk/src/jdk.pack
src/jdk.scripting.nashorn : nashorn/src/jdk.scripting.nashorn
src/jdk.scripting.nashorn.shell : nashorn/src/jdk.scripting.nashorn.shell
src/jdk.sctp : jdk/src/jdk.sctp
src/jdk.security.auth : jdk/src/jdk.security.auth
src/jdk.security.jgss : jdk/src/jdk.security.jgss
src/jdk.unsupported : jdk/src/jdk.unsupported
src/jdk.xml.bind : jaxws/src/jdk.xml.bind
src/jdk.xml.dom : jaxp/src/jdk.xml.dom
src/jdk.xml.ws : jaxws/src/jdk.xml.ws
src/jdk.zipfs : jdk/src/jdk.zipfs
src/langtools/sample : langtools/src/sample
src/linux : jdk/src/linux
src/sample : jdk/src/sample
src/hotspot/share : hotspot/src/share/vm
src/hotspot/cpu/aarch64 : hotspot/src/cpu/aarch64/vm
src/hotspot/cpu/arm : hotspot/src/cpu/arm/vm
src/hotspot/cpu/ppc : hotspot/src/cpu/ppc/vm
src/hotspot/cpu/s390 : hotspot/src/cpu/s390/vm
src/hotspot/cpu/x86 : hotspot/src/cpu/x86/vm
src/hotspot/cpu/zero : hotspot/src/cpu/zero/vm
src/hotspot/os/aix : hotspot/src/os/aix/vm
src/hotspot/os/bsd : hotspot/src/os/bsd/vm
src/hotspot/os/linux : hotspot/src/os/linux/vm
src/hotspot/os/posix/dtrace : hotspot/src/os/posix/dtrace
src/hotspot/os/posix : hotspot/src/os/posix/vm
src/hotspot/os/windows : hotspot/src/os/windows/vm
src/hotspot/os_cpu/aix_ppc : hotspot/src/os_cpu/aix_ppc/vm
src/hotspot/os_cpu/bsd_x86 : hotspot/src/os_cpu/bsd_x86/vm
src/hotspot/os_cpu/bsd_zero : hotspot/src/os_cpu/bsd_zero/vm
src/hotspot/os_cpu/linux_aarch64 : hotspot/src/os_cpu/linux_aarch64/vm
src/hotspot/os_cpu/linux_arm : hotspot/src/os_cpu/linux_arm/vm
src/hotspot/os_cpu/linux_ppc : hotspot/src/os_cpu/linux_ppc/vm
src/hotspot/os_cpu/linux_s390 : hotspot/src/os_cpu/linux_s390/vm
src/hotspot/os_cpu/linux_x86 : hotspot/src/os_cpu/linux_x86/vm
src/hotspot/os_cpu/linux_zero : hotspot/src/os_cpu/linux_zero/vm
src/hotspot/os_cpu/windows_x86 : hotspot/src/os_cpu/windows_x86/vm
src/hotspot : hotspot/src
src/utils/IdealGraphVisualizer : hotspot/src/share/tools/IdealGraphVisualizer
src/utils/LogCompilation : hotspot/src/share/tools/LogCompilation
src/utils/hsdis : hotspot/src/share/tools/hsdis
src/utils/reorder : jdk/make/non-build-utils/reorder
src/utils/src/build : jdk/make/non-build-utils/src/build
make/BuildNashorn.gmk : nashorn/make/BuildNashorn.gmk
make/CompileDemos.gmk : jdk/make/CompileDemos.gmk
make/CompileInterimLangtools.gmk : langtools/make/CompileInterim.gmk
make/CompileModuleTools.gmk : jdk/make/CompileModuleTools.gmk
make/CompileToolsHotspot.gmk : hotspot/make/CompileTools.gmk
make/CompileToolsJdk.gmk : jdk/make/CompileTools.gmk
make/CopyInterimCLDRConverter.gmk : jdk/make/CopyInterimCLDRConverter.gmk
make/GenerateModuleSummary.gmk : jdk/make/GenerateModuleSummary.gmk
make/ModuleTools.gmk : jdk/make/ModuleTools.gmk
make/ToolsJdk.gmk : jdk/make/Tools.gmk
make/ToolsLangtools.gmk : langtools/make/Tools.gmk
make/UnpackSecurity.gmk : jdk/make/UnpackSecurity.gmk
make/autoconf : common/autoconf
make/conf : common/conf
make/copy : jdk/make/copy
make/copy/Copy-java.corba.gmk : corba/make/copy/Copy-java.corba.gmk
make/corba : corba/make
make/data : jdk/make/data
make/gendata : jdk/make/gendata
make/gendata/Gendata-jdk.compiler.gmk : langtools/make/gendata/Gendata-jdk.compiler.gmk
make/gensrc : jdk/make/gensrc
make/gensrc/Gensrc-java.corba.gmk : corba/make/gensrc/Gensrc-java.corba.gmk
make/gensrc/Gensrc-jdk.compiler.gmk : langtools/make/gensrc/Gensrc-jdk.compiler.gmk
make/gensrc/Gensrc-jdk.hotspot.agent.gmk : hotspot/make/gensrc/Gensrc-jdk.hotspot.agent.gmk
make/gensrc/Gensrc-jdk.internal.vm.compiler.gmk : hotspot/make/gensrc/Gensrc-jdk.internal.vm.compiler.gmk
make/gensrc/Gensrc-jdk.javadoc.gmk : langtools/make/gensrc/Gensrc-jdk.javadoc.gmk
make/gensrc/Gensrc-jdk.jdeps.gmk : langtools/make/gensrc/Gensrc-jdk.jdeps.gmk
make/gensrc/Gensrc-jdk.jshell.gmk : langtools/make/gensrc/Gensrc-jdk.jshell.gmk
make/gensrc/GensrcCommonLangtools.gmk : langtools/make/gensrc/GensrcCommon.gmk
make/hotspot : hotspot/make
make/jdk : jdk/make
make/langtools : langtools/make
make/launcher : jdk/make/launcher
make/lib : jdk/make/lib
make/lib/Lib-jdk.hotspot.agent.gmk : hotspot/make/lib/Lib-jdk.hotspot.agent.gmk
make/mapfiles : jdk/make/mapfiles
make/mapfiles/libjsig : hotspot/make/mapfiles/libjsig
make/mapfiles/libjvm_db : hotspot/make/mapfiles/libjvm_db
make/mapfiles/libjvm_dtrace : hotspot/make/mapfiles/libjvm_dtrace
make/mapfiles/libsaproc : hotspot/make/mapfiles/libsaproc
make/nashorn : nashorn/make
make/nb_native : common/nb_native
make/scripts/addNotices.sh : jdk/make/scripts/addNotices.sh
make/scripts/compare.sh : common/bin/compare.sh
make/scripts/compare_exceptions.sh.incl : common/bin/compare_exceptions.sh.incl
make/scripts/genExceptions.sh : jdk/make/scripts/genExceptions.sh
make/scripts/hide_important_warnings_from_javac.sh : common/bin/hide_important_warnings_from_javac.sh
make/scripts/logger.sh : common/bin/logger.sh
make/src/native/fixpath.c : common/src/fixpath.c
make/test/JtregNativeHotspot.gmk : hotspot/make/test/JtregNative.gmk
make/test/JtregNativeJdk.gmk : jdk/make/test/JtregNative.gmk
test/jdk : jdk/test
test/langtools : langtools/test
test/nashorn : nashorn/test
test/jaxp : jaxp/test
test/hotspot/gtest : hotspot/test/native
test/hotspot/jtreg : hotspot/test
bin : common/bin
bin/nashorn : nashorn/bin
doc : common/doc
doc/nashorn : nashorn/docs

View File

@ -1,237 +0,0 @@
#!/bin/bash
#
# Copyright (c) 2014, 2017, Oracle and/or its affiliates. All rights reserved.
# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
#
# This code is free software; you can redistribute it and/or modify it
# under the terms of the GNU General Public License version 2 only, as
# published by the Free Software Foundation.
#
# This code is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
# version 2 for more details (a copy is included in the LICENSE file that
# accompanied this code).
#
# You should have received a copy of the GNU General Public License version
# 2 along with this work; if not, write to the Free Software Foundation,
# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
#
# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
# or visit www.oracle.com if you need additional information or have any
# questions.
#
# Script for updating a patch file as per the shuffled/unshuffled source location.
usage() {
echo "Usage: $0 [-h|--help] [-v|--verbose] [-to9|-to10] [-r <repo>] <input_patch> <output_patch>"
echo "where:"
echo " -to9 create patches appropriate for a JDK 9 source tree"
echo " When going to 9, the output patches will be suffixed with the"
echo " repo name"
echo " -to10 create patches appropriate for a JDK 10 source tree"
echo " -r <repo> specify repo for source patch, set to 'top' for top repo"
echo " <input_patch> is the input patch file, that needs shuffling/unshuffling"
echo " <output_patch> is the updated patch file "
echo " "
exit 1
}
SCRIPT_DIR=`dirname $0`
UNSHUFFLE_LIST=$SCRIPT_DIR"/unshuffle_list.txt"
if [ ! -f "$UNSHUFFLE_LIST" ] ; then
echo "FATAL: cannot find $UNSHUFFLE_LIST" >&2
exit 1
fi
vflag="false"
while [ $# -gt 0 ]
do
case $1 in
-h | --help )
usage
;;
-v | --verbose )
vflag="true"
;;
-r)
repo="$2"
shift
;;
-to9)
shuffle_to=9
;;
-to10)
shuffle_to=10
;;
-*) # bad option
usage
;;
* ) # non option
break
;;
esac
shift
done
# Make sure we have the right number of arguments
if [ ! $# -eq 2 ] ; then
echo "ERROR: Invalid number of arguments." >&2
usage
fi
# Check the given repo
repos="top corba jaxp jaxws jdk langtools nashorn hotspot"
found="false"
if [ -n "$repo" ]; then
for r in $repos ; do
if [ $repo = "$r" ] ; then
found="true"
break;
fi
done
if [ $found = "false" ] ; then
echo "ERROR: Unknown repo: $repo. Should be one of [$repos]." >&2
usage
fi
fi
if [ "$shuffle_to" != "9" -a "$shuffle_to" != "10" ]; then
echo "ERROR: Must pick either -to9 or -to10"
exit 1
fi
# When going to 10, a repo must be specified for the source patch
if [ "$shuffle_to" = "10" -a -z "$repo" ]; then
echo "ERROR: Must specify src repo for JDK 9 patch"
exit 1
fi
# Check given input/output files
input="$1"
if [ "x$input" = "x-" ] ; then
input="/dev/stdin"
fi
if [ ! -f $input -a "x$input" != "x/dev/stdin" ] ; then
echo "ERROR: Cannot find input patch file: $input" >&2
exit 1
fi
output="$2"
if [ "x$output" = "x-" ] ; then
output="/dev/stdout"
fi
base_output="$output"
if [ "$shuffle_to" = "10" ]; then
if [ -f $output -a "x$output" != "x/dev/stdout" ] ; then
echo "ERROR: Output patch already exists: $output" >&2
exit 1
fi
else
for r in $repos; do
if [ -f "$output.$r" ]; then
echo "ERROR: Output patch already exists: $output.$r" >&2
exit 1
fi
done
fi
verbose() {
if [ ${vflag} = "true" ] ; then
echo "$@" >&2
fi
}
unshuffle() {
line=$@
verbose "Attempting to rewrite: \"$line\""
# Retrieve the file name
path=
if echo "$line" | egrep '^diff' > /dev/null ; then
if ! echo "$line" | egrep '\-\-git' > /dev/null ; then
echo "ERROR: Only git patches supported. Please use 'hg export --git ...'." >&2
exit 1
fi
path="`echo "$line" | sed -e s@'diff --git a/'@@ -e s@' b/.*$'@@`"
elif echo "$line" | egrep '^\-\-\-' > /dev/null ; then
path="`echo "$line" | sed -e s@'--- a/'@@`"
elif echo "$line" | egrep '^\+\+\+' > /dev/null ; then
path="`echo "$line" | sed s@'+++ b/'@@`"
fi
verbose "Extracted path: \"$path\""
# Find the most specific matches in the shuffle list
matches=
if [ -n "$repo" -a "$repo" != "top" ]; then
matchpath="$repo"/"$path"/x
else
matchpath="$path"/x
fi
while [ "$matchpath" != "" ] ; do
matchpath="`echo $matchpath | sed s@'\(.*\)/.*$'@'\1'@`"
if [ "$shuffle_to" = "10" ] ; then
pattern=": $matchpath$"
else
pattern="^$matchpath :"
fi
verbose "Attempting to find \"$matchpath\""
matches=`egrep "$pattern" "$UNSHUFFLE_LIST"`
if ! [ "x${matches}" = "x" ] ; then
verbose "Got matches: [$matches]"
break;
fi
if ! echo "$matchpath" | egrep '.*/.*' > /dev/null ; then
break;
fi
done
# Rewrite the line, if we have a match
if ! [ "x${matches}" = "x" ] ; then
shuffled="${matches%% : *}"
unshuffled="${matches#* : }"
patch_suffix_9=""
for r in $repos; do
if [ "$unshuffled" != "${unshuffled#$r}" ]; then
unshuffled="${unshuffled#$r\/}"
patch_suffix_9=".$r"
fi
done
verbose "shuffled: $shuffled"
verbose "unshuffled: $unshuffled"
verbose "patch_suffix_9: $patch_suffix_9"
if [ "$shuffle_to" = "10" ] ; then
newline="`echo "$line" | sed -e s@"$unshuffled"@"$shuffled"@g`"
else
newline="`echo "$line" | sed -e s@"$shuffled"@"$unshuffled"@g`"
output=$base_output$patch_suffix_9
verbose "Writing to $output"
fi
verbose "Rewriting to \"$newline\""
echo "$newline" >> $output
else
echo "WARNING: no match found for $path"
echo "$line" >> $output
fi
}
while IFS= read -r line
do
if echo "$line" | egrep '^diff|^\-\-\-|^\+\+\+' > /dev/null ; then
unshuffle "$line"
else
printf "%s\n" "$line" >> $output
fi
done < "$input"

View File

@ -62,17 +62,22 @@ Help()
echo "options:"
echo "-c Specifies the company. Set to Oracle by default."
echo "-y Specifies the copyright year. Set to current year by default."
echo "-b Specifies the base reference for change set lookup."
echo "-f Updates the copyright for all change sets in a given year,"
echo " as specified by -y."
echo " as specified by -y. Overrides -b flag."
echo "-h Print this help."
echo
}
full_year=false
base_reference=master
# Process options
while getopts "c:fhy:" option; do
while getopts "b:c:fhy:" option; do
case $option in
b) # supplied base reference
base_reference=${OPTARG}
;;
c) # supplied company year
company=${OPTARG}
;;
@ -111,7 +116,7 @@ else
if [ "$full_year" = "true" ]; then
vcs_list_changesets=(git log --no-merges --since="${year}-01-01T00:00:00Z" --until="${year}-12-31T23:59:59Z" --pretty=tformat:"%H")
else
vcs_list_changesets=(git log --no-merges 'master..HEAD' --since="${year}-01-01T00:00:00Z" --until="${year}-12-31T23:59:59Z" --pretty=tformat:"%H")
vcs_list_changesets=(git log --no-merges "${base_reference}..HEAD" --since="${year}-01-01T00:00:00Z" --until="${year}-12-31T23:59:59Z" --pretty=tformat:"%H")
fi
vcs_changeset_message=(git log -1 --pretty=tformat:"%B") # followed by ${changeset}
vcs_changeset_files=(git diff-tree --no-commit-id --name-only -r) # followed by ${changeset}

111
bin/update_pch.sh Normal file
View File

@ -0,0 +1,111 @@
#!/bin/sh
# Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved.
# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
#
# This code is free software; you can redistribute it and/or modify it
# under the terms of the GNU General Public License version 2 only, as
# published by the Free Software Foundation.
#
# This code is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
# version 2 for more details (a copy is included in the LICENSE file that
# accompanied this code).
#
# You should have received a copy of the GNU General Public License version
# 2 along with this work; if not, write to the Free Software Foundation,
# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
#
# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
# or visit www.oracle.com if you need additional information or have any
# questions.
# The output of this script may require some degree of human curation:
# - Redundant headers, e.g. both x.hpp, x.inline.hpp are included;
# - Headers relative to a non-default feature should be protected by an
# appropriate 'if' clause to make sure all variants can build without
# errors.
source_path="$(dirname ${0})"
this_script_dir="$(cd -- "${source_path}" > /dev/null && pwd)"
if test -z "${this_script_dir}"; then
echo "Error: Could not determine location of this script"
exit 1
fi
# Work in top directory
cd $this_script_dir/..
# Time threshold for header compilation, if the time exceeds the
# threshold the header will be precompiled.
if [ -z "$MIN_MS" ]; then
MIN_MS=100000
fi
if [ -z "$CLEAN" ]; then
CLEAN=true
elif [ "$CLEAN" != "true" ] && [ "$CLEAN" != "false" ]; then
echo "Expected either 'true' or 'false' for CLEAN"
fi
# CBA_PATH should point to a valid ClangBuildAnalyzer executable.
# Build steps:
# git clone --depth 1 git@github.com:aras-p/ClangBuildAnalyzer.git
# cd ClangBuildAnalyzer
# make -f projects/make/Makefile
if [ -z "$CBA_PATH" ]; then
CBA_PATH="./ClangBuildAnalyzer/build/ClangBuildAnalyzer"
fi
set -eux
PRECOMPILED_HPP="src/hotspot/share/precompiled/precompiled.hpp"
CBA_CONFIG="ClangBuildAnalyzer.ini"
TIMESTAMP="$(date +%Y%m%d-%H%M)"
RUN_NAME="pch_update_$TIMESTAMP"
CBA_OUTPUT="cba_out_$TIMESTAMP"
if [ "$CLEAN" = "true" ]; then
trap 'rm -rf "build/'"$RUN_NAME"'" "$CBA_OUTPUT" "$CBA_CONFIG"' EXIT
fi
sh configure --with-toolchain-type=clang \
--with-conf-name="$RUN_NAME" \
--disable-precompiled-headers \
--with-extra-cxxflags="-ftime-trace" \
--with-extra-cflags="-ftime-trace"
make clean CONF_NAME="$RUN_NAME"
make hotspot CONF_NAME="$RUN_NAME"
"$CBA_PATH" --all "./build/$RUN_NAME/hotspot/variant-server/libjvm/objs" \
"$CBA_OUTPUT"
# Preserve license and comments on top
cat "$PRECOMPILED_HPP" | awk '/^#include/ {exit} {print}' > "$PRECOMPILED_HPP.tmp"
if [ ! -f "$CBA_CONFIG" ]; then
cat <<EOF > "$CBA_CONFIG"
[counts]
header=100
headerChain=0
template=0
function=0
fileCodegen=0
fileParse=0
[misc]
onlyRootHeaders=true
EOF
fi
"$CBA_PATH" --analyze "$CBA_OUTPUT" | \
grep " ms: " | \
# Keep the headers more expensive than ${1}ms
awk -v x="$MIN_MS" '$1 < x { exit } { print $3 }' | \
# Filter away non-hotspot headers
grep hotspot/share | \
awk -F "hotspot/share/" '{ printf "#include \"%s\"\n", $2 }' \
>> "$PRECOMPILED_HPP.tmp"
mv "$PRECOMPILED_HPP.tmp" "$PRECOMPILED_HPP"
java test/hotspot/jtreg/sources/SortIncludes.java --update "$PRECOMPILED_HPP"

View File

@ -50,6 +50,9 @@ id="toc-factoring-and-class-design">Factoring and Class Design</a></li>
<li><a href="#commenting" id="toc-commenting">Commenting</a></li>
<li><a href="#macros" id="toc-macros">Macros</a></li>
<li><a href="#whitespace" id="toc-whitespace">Whitespace</a></li>
<li><a href="#avoid-implicit-conversions-to-bool"
id="toc-avoid-implicit-conversions-to-bool">Avoid implicit conversions
to bool</a></li>
<li><a href="#miscellaneous"
id="toc-miscellaneous">Miscellaneous</a></li>
</ul></li>
@ -72,28 +75,78 @@ Standard Library</a></li>
Deduction</a></li>
<li><a href="#expression-sfinae" id="toc-expression-sfinae">Expression
SFINAE</a></li>
<li><a href="#trailing-return-type-syntax-for-functions"
id="toc-trailing-return-type-syntax-for-functions">Trailing return type
syntax for functions</a></li>
<li><a href="#non-type-template-parameter-values"
id="toc-non-type-template-parameter-values">Non-type template parameter
values</a></li>
<li><a href="#enum" id="toc-enum">enum</a></li>
<li><a href="#alignas" id="toc-alignas">alignas</a></li>
<li><a href="#thread_local" id="toc-thread_local">thread_local</a></li>
<li><a href="#nullptr" id="toc-nullptr">nullptr</a></li>
<li><a href="#atomic" id="toc-atomic">&lt;atomic&gt;</a></li>
<li><a href="#variable-templates-and-inline-variables"
id="toc-variable-templates-and-inline-variables">Variable Templates and
Inline Variables</a></li>
<li><a href="#initializing-variables-with-static-storage-duration"
id="toc-initializing-variables-with-static-storage-duration">Initializing
variables with static storage duration</a></li>
<li><a href="#uniform-initialization"
id="toc-uniform-initialization">Uniform Initialization</a></li>
<li><a href="#mandatory-copy-elision"
id="toc-mandatory-copy-elision">Mandatory Copy Elision</a></li>
<li><a href="#local-function-objects"
id="toc-local-function-objects">Local Function Objects</a></li>
<li><a href="#inheriting-constructors"
id="toc-inheriting-constructors">Inheriting constructors</a></li>
<li><a href="#attributes" id="toc-attributes">Attributes</a></li>
<li><a href="#noexcept" id="toc-noexcept">noexcept</a></li>
<li><a href="#enhanced-selection-statements"
id="toc-enhanced-selection-statements">Enhanced selection
statements</a></li>
<li><a href="#expression-evaluation-order"
id="toc-expression-evaluation-order">Expression Evaluation
Order</a></li>
<li><a href="#compatibility-with-c11"
id="toc-compatibility-with-c11">Compatibility with C11</a></li>
<li><a href="#additional-permitted-features"
id="toc-additional-permitted-features">Additional Permitted
Features</a></li>
</ul></li>
<li><a href="#excluded-features" id="toc-excluded-features">Excluded
Features</a>
<ul>
<li><a href="#structured-bindings"
id="toc-structured-bindings">Structured Bindings</a></li>
<li><a href="#file-system-library" id="toc-file-system-library">File
System Library</a></li>
<li><a href="#aggregate-extensions"
id="toc-aggregate-extensions">Aggregate Extensions</a></li>
<li><a href="#additional-excluded-features"
id="toc-additional-excluded-features">Additional Excluded
Features</a></li>
</ul></li>
<li><a href="#undecided-features" id="toc-undecided-features">Undecided
Features</a>
<ul>
<li><a href="#stdoptional"
id="toc-stdoptional">std::optional&lt;&gt;</a></li>
<li><a href="#stdbyte" id="toc-stdbyte">std::byte</a></li>
<li><a href="#string-views" id="toc-string-views">String Views</a></li>
<li><a href="#substring-and-subsequence-searching"
id="toc-substring-and-subsequence-searching">Substring and Subsequence
Searching</a></li>
<li><a href="#new-and-delete-with-over-aligned-data"
id="toc-new-and-delete-with-over-aligned-data"><code>new</code> and
<code>delete</code> with Over-Aligned Data</a></li>
<li><a href="#stdto_chars-and-stdfrom_chars"
id="toc-stdto_chars-and-stdfrom_chars"><code>std::to_chars()</code> and
<code>std::from_chars</code></a></li>
<li><a href="#stdlaunder"
id="toc-stdlaunder"><code>std::launder()</code></a></li>
<li><a href="#additional-undecided-features"
id="toc-additional-undecided-features">Additional Undecided
Features</a></li>
</ul></li>
</ul>
@ -209,6 +262,16 @@ lines of code. Name what you must repeat.</p></li>
attribute, the change should be done with a "setter" accessor matched to
the simple "getter".</p></li>
</ul>
<h4 id="conventions-for-lock-free-code">Conventions for Lock-free
Code</h4>
<p>Sometimes variables are accessed concurrently without appropriate
synchronization context, such as a held mutex or at a safepoint. In such
cases the variable should be declared <code>volatile</code> and it
should NOT be accessed as a normal C++ lvalue. Rather, access should be
performed via functions from <code>Atomic</code>, such as
<code>Atomic::load</code>, <code>Atomic::store</code>, etc.</p>
<p>This special formulation makes it more clear to maintainers that the
variable is accessed concurrently in a lock-free manner.</p>
<h3 id="source-files">Source Files</h3>
<ul>
<li><p>All source files must have a globally unique basename. The build
@ -408,22 +471,25 @@ adjust new lines horizontally to be consistent with that organization.
(E.g., trailing backslashes on long macro definitions often
align.)</p></li>
</ul>
<h3 id="miscellaneous">Miscellaneous</h3>
<ul>
<li><p>Use the <a href="https://en.cppreference.com/w/cpp/language/raii"
title="Resource Acquisition Is Initialization">Resource Acquisition Is
Initialization</a> (RAII) design pattern to manage bracketed critical
sections. See class <code>ResourceMark</code> for an example.</p></li>
<li><p>Avoid implicit conversions to <code>bool</code>.</p>
<h3 id="avoid-implicit-conversions-to-bool">Avoid implicit conversions
to bool</h3>
<ul>
<li>Use <code>bool</code> for boolean values.</li>
<li>Do not use ints or pointers as (implicit) booleans with
<code>&amp;&amp;</code>, <code>||</code>, <code>if</code>,
<code>while</code>. Instead, compare explicitly, i.e.
<code>if (x != 0)</code> or <code>if (ptr != nullptr)</code>, etc.</li>
<li>Do not use declarations in <em>condition</em> forms, i.e. don't use
<code>if (T v = value) { ... }</code>.</li>
</ul></li>
<li>Do not use non-boolean declarations in <em>condition</em> forms,
i.e. don't use <code>if (T v = value) { ... }</code>. But see <a
href="#enhanced-selection-statements">Enhanced selection
statements</a>.</li>
</ul>
<h3 id="miscellaneous">Miscellaneous</h3>
<ul>
<li><p>Use the <a href="https://en.cppreference.com/w/cpp/language/raii"
title="Resource Acquisition Is Initialization">Resource Acquisition Is
Initialization</a> (RAII) design pattern to manage bracketed critical
sections. See class <code>ResourceMark</code> for an example.</p></li>
<li><p>Use functions from globalDefinitions.hpp and related files when
performing bitwise operations on integers. Do not code directly as C
operators, unless they are extremely simple. (Examples:
@ -435,16 +501,16 @@ default case. It is ok to have an empty default with comment.</p></li>
</ul>
<h2 id="use-of-c-features">Use of C++ Features</h2>
<p>HotSpot was originally written in a subset of the C++98/03 language.
More recently, support for C++14 is provided, though again, HotSpot only
More recently, support for C++17 is provided, though again, HotSpot only
uses a subset. (Backports to JDK versions lacking support for more
recent Standards must of course stick with the original C++98/03
subset.)</p>
<p>This section describes that subset. Features from the C++98/03
language may be used unless explicitly excluded here. Features from
C++11 and C++14 may be explicitly permitted or explicitly excluded, and
discussed accordingly here. There is a third category, undecided
features, about which HotSpot developers have not yet reached a
consensus, or perhaps have not discussed at all. Use of these features
C++11, C++14, and C++17 may be explicitly permitted or explicitly
excluded, and discussed accordingly here. There is a third category,
undecided features, about which HotSpot developers have not yet reached
a consensus, or perhaps have not discussed at all. Use of these features
is also excluded.</p>
<p>(The use of some features may not be immediately obvious and may slip
in anyway, since the compiler will accept them. The code review process
@ -453,9 +519,9 @@ is the main defense against this.)</p>
provide more extensive discussion or rationale for limitations. Features
that don't have their own subsection are listed in omnibus feature
sections for permitted, excluded, and undecided features.</p>
<p>Lists of new features for C++11 and C++14, along with links to their
descriptions, can be found in the online documentation for some of the
compilers and libraries. The C++14 Standard is the definitive
<p>Lists of new features for C++11, C++14, and C++17, along with links
to their descriptions, can be found in the online documentation for some
of the compilers and libraries. The C++17 Standard is the definitive
description.</p>
<ul>
<li><a href="https://gcc.gnu.org/projects/cxx-status.html">C++ Standards
@ -652,12 +718,42 @@ href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2006/n1984.pdf">n1984</
For local variables, this can be used to make the code clearer by
eliminating type information that is obvious or irrelevant. Excessive
use can make code much harder to understand.</p></li>
<li><p>Function return type deduction (<a
<li><p><code>auto</code> for non-type template parameters (<a
href="http://wg21.link/p0127r2">p0127r2</a>)<br> <code>auto</code> may
be used as a placeholder for the type of a non-type template parameter.
The type is deduced from the value provided in a template
instantiation.</p></li>
</ul>
<p><a name="function-return-type-deduction"></a> * Function return type
deduction (<a
href="https://isocpp.org/files/papers/N3638.html">n3638</a>)<br> Only
use if the function body has a very small number of <code>return</code>
statements, and generally relatively little other code.</p></li>
statements, and generally relatively little other code.</p>
<ul>
<li>Class template argument deduction (<a
href="http://wg21.link/n3602">n3602</a>, <a
href="http://wg21.link/p0091r3">p0091r3</a>)<br> The template arguments
of a class template may be deduced from the arguments to a constructor.
This is similar to ordinary function argument deduction, though partial
deduction with only <em>some</em> template arguments explicitly provided
is not permitted for class template argument deduction. Deduction guides
may be used to provide additional control over the deduction. As with
<code>auto</code> variable declarations, excessive use can make code
harder to understand, because explicit type information is lacking. But
it can also remove the need to be explicit about types that are either
obvious, or that are very hard to write. For example, these allow the
addition of a scope-guard mechanism with nice syntax; something like
this</li>
</ul>
<pre><code> ScopeGuard guard{[&amp;]{ ... cleanup code ... }};</code></pre>
<ul>
<li><p>Also see <a href="#lambdaexpressions">lambda
expressions</a>.</p></li>
<li><p><code>decltype(auto)</code> should be avoided, whether for
variables, for non-type template parameters, or for function return
types. There are subtle and complex differences between this placeholder
type and <code>auto</code>. Any use would need very careful
explanation.</p></li>
</ul>
<h3 id="expression-sfinae">Expression SFINAE</h3>
<p><a href="https://en.cppreference.com/w/cpp/language/sfinae"
@ -682,6 +778,53 @@ class="uri">https://gcc.gnu.org/bugzilla/show_bug.cgi?id=95468</a><br>
<a
href="https://developercommunity.visualstudio.com/content/problem/396562/sizeof-deduced-type-is-sometimes-not-a-constant-ex.html"
class="uri">https://developercommunity.visualstudio.com/content/problem/396562/sizeof-deduced-type-is-sometimes-not-a-constant-ex.html</a></p>
<h3 id="trailing-return-type-syntax-for-functions">Trailing return type
syntax for functions</h3>
<p>A function's return type may be specified after the parameters and
qualifiers (<a
href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2541.htm">n2541</a>).
In such a declaration the normal return type is <code>auto</code> and
the return type is indicated by <code>-&gt;</code> followed by the type.
Although both use <code>auto</code> in the "normal" leading return type
position, this differs from <a
href="#function-return-type-deduction">function return type
deduction</a>, in that the return type is explicit rather than deduced,
but specified in a trailing position.</p>
<p>Use of trailing return types is permitted. However, the normal,
leading position for the return type is preferred. A trailing return
type should only be used where it provides some benefit. Such benefits
usually arise because a trailing return type is in a different scope
than a leading return type.</p>
<ul>
<li><p>If the function identifier is a nested name specifier, then the
trailing return type occurs in the nested scope. This may permit simpler
naming in the return type because of the different name lookup
context.</p></li>
<li><p>The trailing return type is in the scope of the parameters,
making their types accessible via <code>decltype</code>. For
example</p></li>
</ul>
<pre><code>template&lt;typename T, typename U&gt; auto add(T t, U u) -&gt; decltype(t + u);</code></pre>
<p>rather than</p>
<pre><code>template&lt;typename T, typename U&gt; decltype((*(T*)0) + (*(U*)0)) add(T t, U u);</code></pre>
<ul>
<li>Complex calculated leading return types may obscure the normal
syntactic boundaries, making it more difficult for a reader to find the
function name and parameters. This is particularly common in cases where
the return type is being used for <a
href="https://en.cppreference.com/w/cpp/language/sfinae"
title="Substitution Failure Is Not An Error">SFINAE</a>. A trailing
return type may be preferable in such situations.</li>
</ul>
<h3 id="non-type-template-parameter-values">Non-type template parameter
values</h3>
<p>C++17 extended the arguments permitted for non-type template
parameters (<a href="http://wg21.link/n4268">n4268</a>). The kinds of
values (the parameter types) aren't changed. However, the values can now
be the result of arbitrary constant expressions (with a few restrictions
on the result), rather than a much more limited and restrictive set of
expressions. In particular, the argument for a pointer or reference type
parameter can now be the result of a constexpr function.</p>
<h3 id="enum">enum</h3>
<p>Where appropriate, <em>scoped-enums</em> should be used. (<a
href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2347.pdf">n2347</a>)</p>
@ -795,6 +938,41 @@ differ from what the Java compilers implement.</p>
"conservative" memory ordering, which may differ from (may be stronger
than) sequentially consistent. There are algorithms in HotSpot that are
believed to rely on that ordering.</p>
<h3 id="variable-templates-and-inline-variables">Variable Templates and
Inline Variables</h3>
<p>The use of variable templates (including static data member
templates) (<a href="https://wg21.link/N3651">N3651</a>) is permitted.
They provide parameterized variables and constants in a simple and
direct form, instead of requiring the use of various workarounds.</p>
<p>Variables with static storage duration and variable templates may be
declared <code>inline</code> (<a
href="https://wg21.link/p0386r2">p0386r2</a>), and this usage is
permitted. This has similar effects as for declaring a function inline:
it can be defined, identically, in multiple translation units, must be
defined in every translation unit in which it is <a
href="https://en.cppreference.com/w/cpp/language/definition"
title="One Definition Rule">ODR used</a>, and the behavior of the
program is as if there is exactly one variable.</p>
<p>Declaring a variable inline allows the complete definition to be in a
header file, rather than having a declaration in a header and the
definition in a .cpp file. The guidance on <a
href="#initializing-variables-with-static-storage-duration">initialization</a>
of such variables still applies. Inline variables with dynamic
initializations can make initialization order problems worse. The few
ordering constraints that exist for non-inline variables don't apply, as
there isn't a single program-designated translation unit containing the
definition.</p>
<p>A <code>constexpr</code> static data member or static data member
template is implicitly <code>inline</code>. As a consequence, an <a
href="https://en.cppreference.com/w/cpp/language/definition"
title="One Definition Rule">ODR use</a> of such a member doesn't require
a definition in some .cpp file. (This is a change from pre-C++17.
Beginning with C++17, such a definition is considered a duplicate
definition, and is deprecated.)</p>
<p>Declaring a <code>thread_local</code> variable template or
<code>inline</code> variable is forbidden in HotSpot code. <a
href="#thread_local">The use of <code>thread_local</code></a> is already
heavily restricted.</p>
<h3
id="initializing-variables-with-static-storage-duration">Initializing
variables with static storage duration</h3>
@ -846,6 +1024,45 @@ initialization</a></li>
<p>Although related, the use of <code>std::initializer_list</code>
remains forbidden, as part of the avoidance of the C++ Standard Library
in HotSpot code.</p>
<h3 id="mandatory-copy-elision">Mandatory Copy Elision</h3>
<p><a href="https://en.wikipedia.org/wiki/Copy_elision">Copy elision</a>
(or <a
href="https://cn.cppreference.com/w/cpp/language/copy_elision.html">here</a>)
is a compiler optimization used to avoid potentially expensive copies in
certain situations. It is critical to making practical the performance
of return by value or pass by value. It is also unusual in not following
the as-if rule for optimizations - copy elision can be applied even if
doing so bypasses side-effects of copying/moving the object. The C++
standard explicitly permits this.</p>
<p>However, because it's an optional optimization, the relevant
copy/move constructor must be available and accessible, in case the
compiler chooses to not apply the optimization even in a situation where
permitted.</p>
<p>C++17 changed some cases of copy elision so that there is never a
copy/move in these cases (<a
href="http://wg21.link/p0135r1">p0135r1</a>). The interesting cases
involve a function that returns an unnamed temporary object, and
constructors. In such cases the object being initialized from the
temporary is always direct initialized, with no copy/move ever involved;
see <a href="https://en.wikipedia.org/wiki/Copy_elision#RVO"
title="Return Value Optimization">RVO</a> and more specifically <a
href="https://cn.cppreference.com/w/cpp/language/copy_elision.html"
title="Unnamed Return Value Optimization">URVO</a>.</p>
<p>Since this is now standard behavior it can't be avoided in the
covered situations. This could change the behavior of code that relied
on side effects by constructors, but that's both uncommon and was
already problematic because of the previous optional copy elision. But
HotSpot code can, and should, explicitly take advantage of this newly
required behavior where it makes sense to do so.</p>
<p>For example, it may be beneficial to delay construction of the result
of a function until the return statement, rather than having a local
variable that is modified into the desired state and then returned.
(Though <a href="https://en.wikipedia.org/wiki/Copy_elision#NRVO"
title="Named Return Value Optimization">NRVO</a> may apply in that
case.)</p>
<p>It is also now possible to define a factory function for a class that
is neither movable nor copyable, if it can be written in a way that
makes use of this feature.</p>
<h3 id="local-function-objects">Local Function Objects</h3>
<ul>
<li>Local function objects, including lambda expressions, may be
@ -918,6 +1135,13 @@ href="https://en.wikipedia.org/wiki/Partial_application"
title="Partial Application">partial application</a>. Again here, lambdas
are typically much simpler and less verbose than function object
classes.</p>
<p>A lambda is a constexpr function if either the parameter declaration
clause is followed by <code>constexpr</code>, or it satisfies the
requirements for a constexpr function (<a
href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2016/p0170r1.pdf">p0170r1</a>).
Thus, using a lambda to package up some computation doesn't incur
unnecessary overhead or prevent use in a context required to be
compile-time evaluated (such as an array size).</p>
<p>Because of these benefits, lambda expressions are permitted in
HotSpot code, with some restrictions and usage guidance. An anonymous
lambda is one which is passed directly as an argument. A named lambda is
@ -965,6 +1189,18 @@ making the captured value unaffected by modifications to the outer
variable. But this only applies to captured auto variables, not member
variables, and is inconsistent with referential transparency.</p></li>
</ul></li>
<li><p>By-value capture of <code>this</code> (using a capture list like
<code>[*this]</code> (<a
href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2016/p0018r3.html">p0018r3</a>))
is also not permitted. One of the motivating use-cases is when the
lifetime of the lambda exceeds the lifetime of the object for the
containing member function. That is, we have an upward lambda that is
capturing <code>this</code> of the enclosing method. But again, that
use-case doesn't apply if only downward lambdas are used. Another
use-case is when we simply want the lambda to be operating on a copy of
<code>this</code> for some reason. This is sufficiently uncommon that it
can be handled by manual copying, so readers don't need to understand
this rare syntax.</p></li>
<li><p>Non-capturing lambdas (with an empty capture list -
<code>[]</code>) have limited utility. There are cases where no captures
are required (pure functions, for example), but if the function is small
@ -974,14 +1210,15 @@ href="https://isocpp.org/files/papers/N3649.html">N3649</a>) are not
permitted. Capture initializers inherently increase the complexity of
the capture list, and provide little benefit over an additional in-scope
local variable.</p></li>
</ul>
<p>The use of <code>mutable</code> lambda expressions is forbidden
<li><p>The use of <code>mutable</code> lambda expressions is forbidden
because there don't seem to be many, if any, good use-cases for them in
HotSpot. A lambda expression needs to be mutable in order to modify a
by-value captured value. But with only downward lambdas, such usage
seems likely to be rare and complicated. It is better to use a function
object class in any such cases that arise, rather than requiring all
HotSpot developers to understand this relatively obscure feature.</p>
HotSpot developers to understand this relatively obscure
feature.</p></li>
</ul>
<p>While it is possible to directly invoke an anonymous lambda
expression, that feature should not be used, as such a form can be
confusing to readers. Instead, name the lambda and call it by name.</p>
@ -1099,23 +1336,12 @@ href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2540.htm">n2540</
<p>C++11 provides simple syntax allowing a class to inherit the
constructors of a base class. Unfortunately there are a number of
problems with the original specification, and C++17 contains significant
revisions (<a
href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/p0136r1.html"
title="p0136r1">p0136r1</a> opens with a list of 8 Core Issues). Since
HotSpot doesn't support use of C++17, use of inherited constructors
could run into those problems. Such uses might also change behavior in a
future HotSpot update to use C++17 or later, potentially in subtle ways
that could lead to hard to diagnose problems. Because of this, HotSpot
code must not use inherited constructors.</p>
<p>Note that gcc7 provides the <code>-fnew-inheriting-ctors</code>
option to use the <a
href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/p0136r1.html"
title="p0136r1">p0136r1</a> semantics. This is enabled by default when
using C++17 or later. It is also enabled by default for
<code>fabi-version=11</code> (introduced by gcc7) or higher when using
C++11/14, as the change is considered a Defect Report that applies to
those versions. Earlier versions of gcc don't have that option, and
other supported compilers may not have anything similar.</p>
revisions (<a href="http:/wg21.link/p0136r1" title="p0136r1">p0136r1</a>
opens with a list of 8 Core Issues). Although those issues have been
addressed, the benefits from this feature are small compared to the
complexity. Because of this, HotSpot code must not use inherited
constructors.</p>
<p><a href="http://wg21.link/p0195r0">p0195r0</a></p>
<h3 id="attributes">Attributes</h3>
<p>The use of some attributes (<a
href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2761.pdf">n2761</a>)
@ -1131,9 +1357,17 @@ those cases HotSpot has a preferred location.</p>
beginning of the function's declaration, rather than between the
function name and the parameter list.</li>
</ul>
<p><a href="http://wg21.link/p0068r0">p0068r0</a> is the initial
proposal for the attributes added by C++17.)</p>
<p>Only the following attributes are permitted:</p>
<ul>
<li><code>[[noreturn]]</code></li>
<li><code>[[nodiscard]]</code> (<a
href="http://wg21.link/p0189r1">p0189r1</a>)</li>
<li><code>[[maybe_unused]]</code> (<a
href="http://wg21.link/p0212r1">p0212r1</a>)</li>
<li><code>[[fallthrough]]</code> (<a
href="http://wg21.link/p0188">p0188r1</a>)</li>
</ul>
<p>The following attributes are expressly forbidden:</p>
<ul>
@ -1141,6 +1375,23 @@ function name and the parameter list.</li>
<code>memory_order_consume</code>.</li>
<li><code>[[deprecated]]</code> - Not relevant in HotSpot code.</li>
</ul>
<p>Direct use of non-standard (and presumably scoped) attributes in
shared code is also forbidden. Using such would depend on the C++17
feature that an attribute not recognized by the implementation is
ignored (<a href="http://wg21.link/p0283r2">p0283r2</a>). If such an
attribute is needed in shared code, the well-established technique of
providing an <code>ATTRIBUTE_XXX</code> macro with per-compiler
definitions (sometimes empty) should be used. Compilers may warn about
unrecognized attributes (whether by name or by location), in order to
report typos or misuse. Disabling such warnings globally would not be
desirable.</p>
<p>The use of <code>using</code> directives in attribute lists is also
forbidden. (<a href="http://wg21.link/p0028r0">p0028r0</a>) (<a
href="http://wg21.link/p0028r4">p0028r4</a>) We don't generally use
scoped attributes in attribute lists with other attributes. Rather, uses
of scoped attributes (which are implementation defined) are generally
hidden behind a portability macro that includes the surrounding
brackets.</p>
<h3 id="noexcept">noexcept</h3>
<p>Use of <code>noexcept</code> exception specifications (<a
href="http://wg21.link/n3050">n3050</a>) are permitted with restrictions
@ -1190,9 +1441,72 @@ Standard Library facilities.</p></li>
functions not declared <code>noexcept</code>. So HotSpot code doesn't
ever need to check, either with conditional exception specifications or
with <code>noexcept</code> expressions.</p>
<p>The exception specification is part of the type of a function (<a
href="http://wg21.link/p0012r1">p0012r1</a>. This likely has little
impact on HotSpot code, since the use of <code>noexcept</code> is
expected to be rare.</p>
<p>Dynamic exception specifications were deprecated in C++11. C++17
removed all but <code>throw()</code>, with that remaining a deprecated
equivalent to <code>noexcept</code>.</p>
<h3 id="enhanced-selection-statements">Enhanced selection
statements</h3>
<p>C++17 modified the <em>condition</em> part of <code>if</code> and
<code>switch</code> statements, permitting an <em>init-statement</em> to
be included (<a href="http://wg21.link/p0305r1">p0305r1</a>).</p>
<p>Use of this feature is permitted. (However, complex uses may
interfere with readability.) Limiting the scope of a variable involved
in the condition, while also making the value available to the
statement's body, can improve readability. The alternative method of
scope-limiting by introducing a nested scope isn't very popular and is
rarely used.</p>
<p>This new syntax is in addition to the <em>condition</em> being a
declaration with a <em>brace-or-equal-initializer</em>. For an
<code>if</code> statement this new sytax gains that benefit without
violating the long-standing guidance against using <a
href="#avoid-implicit-conversions-to-bool">implicit conversions to
<code>bool</code></a>, which still stands.</p>
<p>For example, uses of Unified Logging sometimes explicitly check
whether a <code>LogTarget</code> is enabled. Instead of</p>
<pre><code> LogTarget(...) lt;
if (lt.is_enabled()) {
LogStream log(lt);
... use log ...
}
... lt is accessible but probably not needed here ...</code></pre>
<p>using this feature one could write</p>
<pre><code> if (LogTarget(...) lt; lt.is_enabled()) {
LogStream log(lt);
... use log ...
}</code></pre>
<p>C++17 also added compile-time <code>if</code> statements (<a
href="http://wg21.link/p0292r2">p0292r2</a>). Use of
<code>if constexpr</code> is permitted. This feature can replace and
(sometimes vastly) simplify many uses of <a
href="https://en.cppreference.com/w/cpp/language/sfinae"
title="Substitution Failure Is Not An Error">SFINAE</a>. The same
declaration and initialization guidance for the <em>condition</em> part
apply here as for ordinary <code>if</code> statements.</p>
<h3 id="expression-evaluation-order">Expression Evaluation Order</h3>
<p>C++17 tightened up the evaluation order for some kinds of
subexpressions (<a href="http://wg21.link/p0138r2">p0138r2</a>). Note,
however, that the Alternate Evaluation Order for Function Calls
alternative in that paper was adopted, rather than the strict left to
right order of evaluation for function call arguments that was proposed
in the main body of the paper.</p>
<p>The primary purpose of this change seems to be to make certain kinds
of call chaining well defined. That's not a style widely used in
HotSpot. In general it is better to continue to avoid questions in this
area by isolating operations with side effects from other statements. In
particular, continue to avoid modifying a value in an expression where
it is also used.</p>
<h3 id="compatibility-with-c11">Compatibility with C11</h3>
<p>C++17 refers to C11 rather than C99. This means that C11 libraries
and functions may be used in HotSpot. There may be limitations because
of differing levels of compatibility among various compilers and
versions of those compilers.</p>
<p>Note that the C parts of the JDK have been built with C11 selected
for some time (<a
href="https://bugs.openjdk.org/browse/JDK-8292008">JDK-8292008</a>).</p>
<h3 id="additional-permitted-features">Additional Permitted
Features</h3>
<ul>
@ -1208,8 +1522,10 @@ href="https://isocpp.org/files/papers/n3778.html">n3778</a>)</p></li>
href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2242.pdf">n2242</a>)
(<a
href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2555.pdf">n2555</a>)</p></li>
<li><p>Static assertions (<a
href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2004/n1720.html">n1720</a>)</p></li>
<li><p>Static assertions (<a href="http://wg21.link/n1720">n1720</a>)
(<a href="http://wg21.link/n3928">n3928</a>)<br> Both the original
(C++11) two-argument form and the new (C++17) single-argument form are
permitted.</p></li>
<li><p><code>decltype</code> (<a
href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2343.pdf">n2343</a>)
(<a
@ -1251,8 +1567,62 @@ href="http://www.open-std.org/JTC1/SC22/WG21/docs/papers/2009/n2930.html">n2930<
href="https://en.cppreference.com/w/cpp/language/range-for">range-for</a>)</p></li>
<li><p>Unrestricted Unions (<a
href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2544.pdf">n2544</a>)</p></li>
<li><p>Preprocessor Condition <code>__has_include</code> (<a
href="http://wg21.link/p0061r0">p0061r0</a>) (<a
href="http://wg21.link/p0061r1">p0061r1</a>)</p></li>
<li><p>Hexadecimal Floating-Point Literals (<a
href="http://wg21.link/p0245r1">p0245r1</a>)</p></li>
<li><p>Construction Rules for <code>enum class</code> Values (<a
href="http://wg21.link/p0138r2">p0138r2</a>)</p></li>
<li><p>Allow <code>typename</code> in template template parameter (<a
href="http://wg21.link/n4051">n4051</a>) — template template parameters
are barely used (if at all) in HotSpot, but there's no reason to
artificially disallow this syntactic regularization in any such
uses.</p></li>
</ul>
<h3 id="excluded-features">Excluded Features</h3>
<h2 id="excluded-features">Excluded Features</h2>
<h3 id="structured-bindings">Structured Bindings</h3>
<p>The use of structured bindings <a
href="http://wg21.link/p0217r3">p0217r3</a> is forbidden. Preferred
approaches for handling functions with multiple return values
include</p>
<ul>
<li><p>Return a named class/struct intended for that purpose, with named
and typed members/accessors.</p></li>
<li><p>Return a value along with out parameters (usually pointers,
sometimes references).</p></li>
<li><p>Designate a sentinel "failure" value in the normal return value
type, with some out of band location for additional information. For
example, this is the model typically used with <code>errno</code>, where
a function returns a normal result, or -1 to indicate an error, with
additional error information in <code>errno</code>.</p></li>
</ul>
<p>There is a strong preference for names and explicit types, as opposed
to offsets and implicit types. For example, there are folks who strongly
dislike that some of the Standard Library functions return
<code>std::pair</code> because <code>first</code> and
<code>second</code> members don't carry any useful information.</p>
<h3 id="file-system-library">File System Library</h3>
<p>The use of the File System library is forbidden. HotSpot doesn't do
very much with files, and already has adequate mechanisms for its needs.
Rewriting in terms of this new library doesn't provide any obviously
significant benefits. Having a mix of the existing usage and uses of
this new library would be confusing.</p>
<p><a href="http://wg21.link/n4100">n4100</a> <a
href="http://wg21.link/p0218r0">p0218r0</a> <a
href="http://wg21.link/p0219r1">p0219r1</a> <a
href="http://wg21.link/p0317r1">p0317r1</a> <a
href="http://wg21.link/p0392r0">p0392r0</a> <a
href="http://wg21.link/p0430r2">p0430r2</a> <a
href="http://wg21.link/p0492r2">p0492r2</a> <a
href="http://wg21.link/p1164r1">p1164r1</a></p>
<h3 id="aggregate-extensions">Aggregate Extensions</h3>
<p>Aggregates with base classes are forbidden. C++17 allows aggregate
initialization for classes with base classes (<a
href="https://wg21.link/p0017r1">p0017r1</a>). HotSpot makes very little
use of aggregate classes, preferring explicit constructors even for very
simple classes.</p>
<h3 id="additional-excluded-features">Additional Excluded Features</h3>
<ul>
<li><p>New string and character literals</p>
<ul>
@ -1285,22 +1655,236 @@ useful.</p></li>
operator overloading is used, ensure the semantics conform to the normal
expected behavior of the operation.</p></li>
<li><p>Avoid most implicit conversion constructors and (implicit or
explicit) conversion operators. (Note that conversion to
<code>bool</code> isn't needed in HotSpot code because of the "no
implicit boolean" guideline.)</p></li>
explicit) conversion operators. Conversion to <code>bool</code>
operators aren't needed because of the <a
href="#avoid-implicit-conversions-to-bool">no implicit boolean</a>
guideline.)</p></li>
<li><p>Avoid <code>goto</code> statements.</p></li>
<li><p>Attributes for namespaces and enumerators (<a
href="http://wg21.link/n4266">n4266</a> — The only applicable attribute
is <a href="#attributes"><code>[[deprecated]]</code></a>, which is
forbidden.</p></li>
<li><p>Variadic <code>using</code> declarations (<a
href="http://wg21.link/p0195r2">p0195r2</a>)</p></li>
<li><p><code>std::variant&lt;&gt;</code> (<a
href="http://wg21.link/p0088r3">p0088r3</a>) — Even if more of the C++
Standard Library is permitted, this class will remain forbidded. Invalid
accesses are indicated by throwing exceptions.</p></li>
<li><p><code>std::any</code> (<a
href="http://wg21.link/p0220r1">p0220r1</a>) — Even if more of the C++
Standard Library is permitted, this class will remain forbidden. It may
require allocation, and always uses the standard allocator. It requires
<a href="https://en.wikipedia.org/wiki/Run-time_type_information"
title="Runtime Type Information">RTTI</a>.</p></li>
<li><p><code>std::as_const()</code> (<a
href="http://wg21.link/p0007r1">p0007r1</a>) — If sufficiently useful,
HotSpot could add such a function. It would likely be added to
globalDefinitions.hpp, where there are already some similar small
utilities.</p></li>
<li><p><code>std::clamp()</code> (<a
href="http://wg21.link/p002501">p002501</a>) — This function is already
provided in globalDefinitions.hpp.</p></li>
<li><p>Parallel STL Algorithms (<a
href="http://wg21.link/p0024r2">p0024r2</a>) — Even if more of the C++
Standard Library is permitted, these will remain forbidden. They are
built on the standard C++ threading mechanisms. HotSpot doesn't use
those mechanisms, instead providing and using its own.</p></li>
<li><p>Cache Line Sizes <a href="http://wg21.link/p0154r1">p0154r1</a>
HotSpot has its own mechanisms for this, using values like
<code>DEFAULT_CACHE_LINE_SIZE</code>. The platform-specific
implementation of the HotSpot mechanisms might use these library
functions, but there is no reason to move away from the current
approach. Quoting from <a href="https://www.cppstd17.com"
title="C++17: The Complete Guide">JOSUTTIS</a>: "... if you know better,
use specific values, but using these values is better than any assumed
fixed size for code supporting multiple platforms."</p></li>
<li><p><code>register</code> storage class removal <a
href="http://wg21.link/p0001r1">p0001r1</a> — The <code>register</code>
storage class has been removed. <code>register</code> is still a
keyword, so still can't be used for normal purposes. Also, this doesn't
affect the use of <code>register</code> for gcc-style extended asm code;
that's a different syntactic element with a different meaning.</p></li>
<li><p>Value of <code>__cplusplus</code> — Testing whether
<code>__cplusplus</code> is defined or not is permitted, and indeed
required. But the value should not need to be examined. The value is
changed with each revision of the Standard. But we build HotSpot and
(most of) the rest of the JDK with a specifically selected version of
the Standard. The value of <code>__cplusplus</code> should be known and
unchanging until we change the project's build configuration again. So
examining the value shouldn't ever be necessary.</p></li>
<li><p>Removal of <code>++</code> for <code>bool</code> (<a
href="http://wg21.link/p0003r1">p0003r1</a>)</p></li>
<li><p>Removal of trigraphs (<a
href="http://wg21.link/n4086">n4086</a>)</p></li>
</ul>
<h3 id="undecided-features">Undecided Features</h3>
<h2 id="undecided-features">Undecided Features</h2>
<p>This list is incomplete; it serves to explicitly call out some
features that have not yet been discussed.</p>
<p>Some features are undecided (so implicitly forbidden) because we
don't expect to use them at all. This might be reconsidered if someone
finds a good use case.</p>
<p>Some Standard Library features are undecided (so implicitly
forbidden) because, while this Style Guide forbids the use of such, they
may be sufficiently useful that we want to permit them anyway. Doing so
may require some idiomatic mechanism for addressing things like
<code>assert</code> incompatibility, incompatibility with HotSpot's
<code>FORBID_C_FUNCTION</code> mechanism, and the like.</p>
<h3 id="stdoptional">std::optional&lt;&gt;</h3>
<p>It is undecided whether to permit the use of
<code>std::optional&lt;&gt;</code> (<a
href="http://wg21.link/p0220r1">p0220r1</a>). It may be sufficiently
useful that it should be permitted despite the usual prohibition against
using Standard Library facilities. Use of the <code>value()</code>
member function must be forbidden, as it reports an invalid access by
throwing an exception.</p>
<h3 id="stdbyte">std::byte</h3>
<p>It is undecided whether to permit the use of the
<code>std::byte</code> type (<a
href="http://wg21.link/p0298r3">p0298r3</a>). It may be sufficiently
useful that it should be permitted despite the usual prohibition against
using Standard Library facilities.</p>
<p>It has been suggested that changing the HotSpot <code>address</code>
type to use <code>std::byte</code> has some benefits. That is,
replace</p>
<pre><code>typedef u_char* address;
typedef const u_char* const_address;</code></pre>
<pre><code>using address = std::byte*;
using const_address = const std::byte*;</code></pre>
<p>in globalDefinitions.hpp.</p>
<p>A specific benefit that was mentioned is that it might improve the
horrible way that gdb handles our current definition of the
<code>address</code> type.</p>
<pre><code>#include &lt;cstddef&gt;
typedef unsigned char* address;
typedef std::byte* address_b;
int main() {
char* mem;
address addr = (address)mem;
address_b addr_b = (address_b)mem;
return 0;
}</code></pre>
<pre><code>(gdb) p addr
$1 = (address) 0x7ffff7fe4fa0 &lt;dl_main&gt; &quot;\363\017\036\372Uf\017\357\300H\211\345AWI\211\377AVAUATSH\201\354\210\002&quot;
(gdb) p addr_b
$2 = (address_b) 0x7ffff7fe4fa0 &lt;dl_main&gt;</code></pre>
<p>This needs to be explored. Some folks have said they will do so.</p>
<h3 id="string-views">String Views</h3>
<p>It is undecided whether to permit the use of
<code>std::string_view</code> (<a
href="http://wg21.link/p0220r1">p0220r1</a>).</p>
<p>HotSpot doesn't use <code>std::string</code>, but uses
<code>char*</code> strings a lot. Wrapping such in a
<code>std::string_view</code> to enable the use of various algorithms
could be useful. But since HotSpot also doesn't permit use of
<code>&lt;algorithm&gt;</code> and the like, that only gets the limited
set of algorithms provided by the view class directly.</p>
<p>There is also the issue of <code>NUL</code> termination; string views
are not necessarily <code>NUL</code> terminated. Moreover, if one goes
to the work of making one that is <code>NUL</code> terminated, that
terminator is included in the size.</p>
<p>There are other caveats. Permitting use of string views would require
discussion of those.</p>
<h3 id="substring-and-subsequence-searching">Substring and Subsequence
Searching</h3>
<p>In addition to simple substring searching, the Standard Library now
includes Boyer-Moore and Boyer-Moore-Horspool searchers, in case someone
wants to search really large texts. That seems an unlikely use-case for
HotSpot. See <a href="http://wg21.link/p0220r1">p0220r1</a>.</p>
<h3 id="new-and-delete-with-over-aligned-data"><code>new</code> and
<code>delete</code> with Over-Aligned Data</h3>
<p>It is undecided whether to permit the use of dynamic allocation of
overaligned types (<a href="http://wg21.link/n3396">n3396</a>).</p>
<p>HotSpot currently only has a couple of over-aligned types that are
dynamically allocated. These are handled manually, not going through
<code>new</code> expressions, as that couldn't work before C++17.</p>
<p>One of the ways an over-aligned type might arise is by aligning a
data member. This might be done to avoid destructive interference for
concurrent accesses. But HotSpot uses a different approach, using
explicit padding. Again, this is in part because <code>new</code> and
<code>delete</code> of overaligned types didn't work. But we might
prefer to continue this approach.</p>
<p>We would need to add <code>operator new</code> overloads to
<code>CHeapObj&lt;&gt;</code> and possibly in other places in order to
support this. However, it has been suggested that implementing it
(efficiently) on top of NMT might be difficult. Note that
<code>posix_memalign</code> / <code>_aligned_malloc</code> don't help
here, because of NMT's use of malloc headers.</p>
<p>If we don't support it we may want to add <code>operator new</code>
overloads that are deleted, to prevent attempted uses.</p>
<p>Alignment usage in non-HotSpot parts of the OpenJDK:</p>
<ul>
<li><p><code>alignas</code> used once in harfbuzz, to align a
variable.</p></li>
<li><p>libpipewire has <code>#define SPA_ALIGNED</code> macro using gcc
<code>aligned</code> attribute, but doesn't use it.</p></li>
<li><p>libsleef has <code>#define ALIGNED</code> macro using gcc
<code>aligned</code> attribute. It is not used for class or member
declarations.</p></li>
</ul>
<h3 id="stdto_chars-and-stdfrom_chars"><code>std::to_chars()</code> and
<code>std::from_chars</code></h3>
<p>It is undecided whether to permit the use of
<code>std::to_chars()</code> and <code>std::from_chars()</code> (<a
href="http://wg21.link/p0067r5">p0067r5</a>).</p>
<p>These functions provide low-level conversions between character
sequences and numeric values. This seems like a good candidate for use
in HotSpot, potentially replacing various clumsy or less performant
alternatives. There is no memory allocation. Parsing failures are
indicated via error codes rather than exceptions. Various other nice for
HotSpot properties.</p>
<p>Note that the published C++17 Standard puts these in
<code>&lt;utility&gt;</code>, but a defect report moved them to
<code>&lt;charconv&gt;</code>. This also needs
<code>&lt;system_error&gt;</code>.</p>
<p>This would require upgrading the minimum gcc version to 11.1 for
floating point conversion support. The minimum Visual Studio version is
already sufficient. The minimum clang version requirement hasn't been
determined yet.</p>
<h3 id="stdlaunder"><code>std::launder()</code></h3>
<p>It is undecided whether to permit the use of
<code>std::launder()</code> (<a
href="http://wg21.link/p0137r1">p0137r1</a>).</p>
<p>Change to permitted if we discover a place where we need it. Or maybe
we should just permit it, but hope we don't need it.</p>
<p>Also, C++20 revised the relevant part of Object Lifetime in a way
that seems more permissive and with less need of laundering. We don't
know if implementations of prior versions take advantage of the
difference.</p>
<p>See Object Lifetime: C++17 6.8/8, C++20 6.7.3/8</p>
<h3 id="additional-undecided-features">Additional Undecided
Features</h3>
<ul>
<li><p>Trailing return type syntax for functions (<a
href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2541.htm">n2541</a>)</p></li>
<li><p>Variable templates (<a
href="https://isocpp.org/files/papers/N3651.pdf">n3651</a>)</p></li>
<li><p>Member initializers and aggregates (<a
href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2013/n3653.html">n3653</a>)</p></li>
<li><p>Rvalue references and move semantics</p></li>
<li><p>Shorthand for nested namespaces (<a
href="http://wg21.link/n4230">n4230</a>) — HotSpot makes very little use
of namespaces, so this seemingly innocuous feature probably isn't useful
to us.</p></li>
<li><p>Direct list initialization with <code>auto</code> (<a
href="http://wg21.link/n3681">n3681</a>) — This change fixed some issues
with direct list initialization and <code>auto</code>. But we don't use
that feature much, if at all. And perhaps shouldn't be using
it.</p></li>
<li><p>UTF-8 Character Literals (<a
href="http://wg21.link/n4267">n4267</a>) — Do we have a use-case for
this?</p></li>
<li><p>Fold Expressions (<a href="http://wg21.link/n4295">n4295</a>) —
Provides a simple way to apply operators to a parameter pack. HotSpot
doesn't use variadic templates very much. That makes it questionable
that developers should need to know about this feature. But if someone
does come up with a good use-case, it's likely that the alternatives are
significantly worse, because pack manipulation without this can be
complicated.</p></li>
<li><p><code>std::invoke&lt;&gt;()</code> (<a
href="http://wg21.link/n4169">n4169</a>)</p></li>
</ul>
</body>
</html>

View File

@ -135,6 +135,17 @@ lines of code. Name what you must repeat.
change should be done with a "setter" accessor matched to the simple
"getter".
#### Conventions for Lock-free Code
Sometimes variables are accessed concurrently without appropriate synchronization
context, such as a held mutex or at a safepoint. In such cases the variable should
be declared `volatile` and it should NOT be accessed as a normal C++ lvalue. Rather,
access should be performed via functions from `Atomic`, such as `Atomic::load`,
`Atomic::store`, etc.
This special formulation makes it more clear to maintainers that the variable is
accessed concurrently in a lock-free manner.
### Source Files
* All source files must have a globally unique basename. The build
@ -366,20 +377,22 @@ adjust new lines horizontally to be consistent with that
organization. (E.g., trailing backslashes on long macro definitions
often align.)
### Avoid implicit conversions to bool
* Use `bool` for boolean values.
* Do not use ints or pointers as (implicit) booleans with `&&`, `||`,
`if`, `while`. Instead, compare explicitly, i.e. `if (x != 0)` or
`if (ptr != nullptr)`, etc.
* Do not use non-boolean declarations in _condition_ forms, i.e. don't use
`if (T v = value) { ... }`. But see
[Enhanced selection statements](#enhanced-selection-statements).
### Miscellaneous
* Use the [Resource Acquisition Is Initialization][RAII] (RAII)
design pattern to manage bracketed critical
sections. See class `ResourceMark` for an example.
* Avoid implicit conversions to `bool`.
* Use `bool` for boolean values.
* Do not use ints or pointers as (implicit) booleans with `&&`, `||`,
`if`, `while`. Instead, compare explicitly, i.e. `if (x != 0)` or
`if (ptr != nullptr)`, etc.
* Do not use declarations in _condition_ forms, i.e. don't use
`if (T v = value) { ... }`.
* Use functions from globalDefinitions.hpp and related files when
performing bitwise
operations on integers. Do not code directly as C operators, unless
@ -391,18 +404,17 @@ they are extremely simple. (Examples: `align_up`, `is_power_of_2`,
* Always enumerate all cases in a switch statement or provide a default
case. It is ok to have an empty default with comment.
## Use of C++ Features
HotSpot was originally written in a subset of the C++98/03 language.
More recently, support for C++14 is provided, though again,
More recently, support for C++17 is provided, though again,
HotSpot only uses a subset. (Backports to JDK versions lacking
support for more recent Standards must of course stick with the
original C++98/03 subset.)
This section describes that subset. Features from the C++98/03
language may be used unless explicitly excluded here. Features from
C++11 and C++14 may be explicitly permitted or explicitly excluded,
C++11, C++14, and C++17 may be explicitly permitted or explicitly excluded,
and discussed accordingly here. There is a third category, undecided
features, about which HotSpot developers have not yet reached a
consensus, or perhaps have not discussed at all. Use of these
@ -417,9 +429,9 @@ more extensive discussion or rationale for limitations. Features that
don't have their own subsection are listed in omnibus feature sections
for permitted, excluded, and undecided features.
Lists of new features for C++11 and C++14, along with links to their
Lists of new features for C++11, C++14, and C++17, along with links to their
descriptions, can be found in the online documentation for some of the
compilers and libraries. The C++14 Standard is the definitive
compilers and libraries. The C++17 Standard is the definitive
description.
* [C++ Standards Support in GCC](https://gcc.gnu.org/projects/cxx-status.html)
@ -624,13 +636,41 @@ For local variables, this can be used to make the code clearer by
eliminating type information that is obvious or irrelevant. Excessive
use can make code much harder to understand.
* `auto` for non-type template parameters
([p0127r2](http://wg21.link/p0127r2))<br>
`auto` may be used as a placeholder for the type of a non-type template
parameter. The type is deduced from the value provided in a template
instantiation.
<a name="function-return-type-deduction"></a>
* Function return type deduction
([n3638](https://isocpp.org/files/papers/N3638.html))<br>
Only use if the function body has a very small number of `return`
statements, and generally relatively little other code.
* Class template argument deduction
([n3602](http://wg21.link/n3602), [p0091r3](http://wg21.link/p0091r3))<br>
The template arguments of a class template may be deduced from the arguments
to a constructor. This is similar to ordinary function argument deduction,
though partial deduction with only _some_ template arguments explicitly
provided is not permitted for class template argument deduction. Deduction
guides may be used to provide additional control over the deduction. As with
`auto` variable declarations, excessive use can make code harder to
understand, because explicit type information is lacking. But it can also
remove the need to be explicit about types that are either obvious, or that
are very hard to write. For example, these allow the addition of a scope-guard
mechanism with nice syntax; something like this
```
ScopeGuard guard{[&]{ ... cleanup code ... }};
```
* Also see [lambda expressions](#lambdaexpressions).
* `decltype(auto)` should be avoided, whether for variables, for non-type
template parameters, or for function return types. There are subtle and
complex differences between this placeholder type and `auto`. Any use would
need very careful explanation.
### Expression SFINAE
[Substitution Failure Is Not An Error][SFINAE] (SFINAE)
@ -652,6 +692,52 @@ Here are a few closely related example bugs:<br>
<https://gcc.gnu.org/bugzilla/show_bug.cgi?id=95468><br>
<https://developercommunity.visualstudio.com/content/problem/396562/sizeof-deduced-type-is-sometimes-not-a-constant-ex.html>
### Trailing return type syntax for functions
A function's return type may be specified after the parameters and qualifiers
([n2541](http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2541.htm)).
In such a declaration the normal return type is `auto` and the return type is
indicated by `->` followed by the type. Although both use `auto` in the
"normal" leading return type position, this differs from
[function return type deduction](#function-return-type-deduction),
in that the return type is explicit rather than deduced, but specified in a
trailing position.
Use of trailing return types is permitted. However, the normal, leading
position for the return type is preferred. A trailing return type should only
be used where it provides some benefit. Such benefits usually arise because a
trailing return type is in a different scope than a leading return type.
* If the function identifier is a nested name specifier, then the trailing
return type occurs in the nested scope. This may permit simpler naming in the
return type because of the different name lookup context.
* The trailing return type is in the scope of the parameters, making their
types accessible via `decltype`. For example
```
template<typename T, typename U> auto add(T t, U u) -> decltype(t + u);
```
rather than
```
template<typename T, typename U> decltype((*(T*)0) + (*(U*)0)) add(T t, U u);
```
* Complex calculated leading return types may obscure the normal syntactic
boundaries, making it more difficult for a reader to find the function name and
parameters. This is particularly common in cases where the return type is
being used for [SFINAE]. A trailing return type may be preferable in such
situations.
### Non-type template parameter values
C++17 extended the arguments permitted for non-type template parameters
([n4268](http://wg21.link/n4268)). The kinds of values (the parameter types)
aren't changed. However, the values can now be the result of arbitrary
constant expressions (with a few restrictions on the result), rather than a
much more limited and restrictive set of expressions. In particular, the
argument for a pointer or reference type parameter can now be the result of a
constexpr function.
### enum
Where appropriate, _scoped-enums_ should be used.
@ -770,6 +856,39 @@ ordering, which may differ from (may be stronger than) sequentially
consistent. There are algorithms in HotSpot that are believed to rely
on that ordering.
### Variable Templates and Inline Variables
The use of variable templates (including static data member templates)
([N3651](https://wg21.link/N3651)) is permitted. They provide parameterized
variables and constants in a simple and direct form, instead of requiring the
use of various workarounds.
Variables with static storage duration and variable templates may be declared
`inline` ([p0386r2](https://wg21.link/p0386r2)), and this usage is
permitted. This has similar effects as for declaring a function inline: it can
be defined, identically, in multiple translation units, must be defined in
every translation unit in which it is [ODR used][ODR], and the behavior of the
program is as if there is exactly one variable.
Declaring a variable inline allows the complete definition to be in a header
file, rather than having a declaration in a header and the definition in a
.cpp file. The guidance on
[initialization](#initializing-variables-with-static-storage-duration) of such
variables still applies. Inline variables with dynamic initializations can
make initialization order problems worse. The few ordering constraints
that exist for non-inline variables don't apply, as there isn't a single
program-designated translation unit containing the definition.
A `constexpr` static data member or static data member template
is implicitly `inline`. As a consequence, an
[ODR use][ODR] of such a member doesn't require a definition in some .cpp
file. (This is a change from pre-C++17. Beginning with C++17, such a
definition is considered a duplicate definition, and is deprecated.)
Declaring a `thread_local` variable template or `inline` variable is forbidden
in HotSpot code. [The use of `thread_local`](#thread_local) is already
heavily restricted.
### Initializing variables with static storage duration
Variables with static storage duration and _dynamic initialization_
@ -813,6 +932,53 @@ Some relevant sections from cppreference.com:
Although related, the use of `std::initializer_list` remains forbidden, as
part of the avoidance of the C++ Standard Library in HotSpot code.
### Mandatory Copy Elision
[Copy elision](https://en.wikipedia.org/wiki/Copy_elision)
(or [here](https://cn.cppreference.com/w/cpp/language/copy_elision.html))
is a compiler optimization used to avoid potentially expensive copies in
certain situations. It is critical to making practical the performance of
return by value or pass by value. It is also unusual in not following the
as-if rule for optimizations - copy elision can be applied even if doing so
bypasses side-effects of copying/moving the object. The C++ standard
explicitly permits this.
However, because it's an optional optimization, the relevant copy/move
constructor must be available and accessible, in case the compiler chooses to
not apply the optimization even in a situation where permitted.
C++17 changed some cases of copy elision so that there is never a copy/move in
these cases ([p0135r1](http://wg21.link/p0135r1)). The interesting cases
involve a function that returns an unnamed temporary object, and constructors.
In such cases the object being initialized from the temporary is always direct
initialized, with no copy/move ever involved; see [RVO] and more specifically
[URVO].
Since this is now standard behavior it can't be avoided in the covered
situations. This could change the behavior of code that relied on side effects
by constructors, but that's both uncommon and was already problematic because
of the previous optional copy elision. But HotSpot code can, and should,
explicitly take advantage of this newly required behavior where it makes sense
to do so.
For example, it may be beneficial to delay construction of the result of a
function until the return statement, rather than having a local variable that
is modified into the desired state and then returned. (Though [NRVO] may apply
in that case.)
It is also now possible to define a factory function for a class that is
neither movable nor copyable, if it can be written in a way that makes use of
this feature.
[RVO]: https://en.wikipedia.org/wiki/Copy_elision#RVO
"Return Value Optimization"
[NRVO]: https://en.wikipedia.org/wiki/Copy_elision#NRVO
"Named Return Value Optimization"
[URVO]: https://cn.cppreference.com/w/cpp/language/copy_elision.html
"Unnamed Return Value Optimization"
### Local Function Objects
* Local function objects, including lambda expressions, may be used.
@ -881,6 +1047,12 @@ Another use for local functions is [partial application][PARTIALAPP]. Again
here, lambdas are typically much simpler and less verbose than function
object classes.
A lambda is a constexpr function if either the parameter declaration clause is
followed by `constexpr`, or it satisfies the requirements for a constexpr
function ([p0170r1]). Thus, using a lambda to package up some computation
doesn't incur unnecessary overhead or prevent use in a context required to be
compile-time evaluated (such as an array size).
Because of these benefits, lambda expressions are permitted in HotSpot code,
with some restrictions and usage guidance. An anonymous lambda is one which
is passed directly as an argument. A named lambda is the value of a
@ -932,6 +1104,17 @@ the most part they don't apply to HotSpot code, given other usage restrictions.
applies to captured auto variables, not member variables, and is
inconsistent with referential transparency.
* By-value capture of `this` (using a capture list like `[*this]` ([p0018r3]))
is also not permitted. One of the motivating use-cases is when the lifetime of
the lambda exceeds the lifetime of the object for the containing member
function. That is, we have an upward lambda that is capturing `this` of the
enclosing method. But again, that use-case doesn't apply if only downward
lambdas are used.
Another use-case is when we simply want the lambda to be operating on a copy
of `this` for some reason. This is sufficiently uncommon that it can be
handled by manual copying, so readers don't need to understand this rare
syntax.
* Non-capturing lambdas (with an empty capture list - `[]`) have limited
utility. There are cases where no captures are required (pure functions,
for example), but if the function is small and simple then that's obvious
@ -941,7 +1124,7 @@ anyway.
Capture initializers inherently increase the complexity of the capture list,
and provide little benefit over an additional in-scope local variable.
The use of `mutable` lambda expressions is forbidden because there don't
* The use of `mutable` lambda expressions is forbidden because there don't
seem to be many, if any, good use-cases for them in HotSpot. A lambda
expression needs to be mutable in order to modify a by-value captured value.
But with only downward lambdas, such usage seems likely to be rare and
@ -1088,21 +1271,12 @@ Do not use _inheriting constructors_
C++11 provides simple syntax allowing a class to inherit the constructors of a
base class. Unfortunately there are a number of problems with the original
specification, and C++17 contains significant revisions ([p0136r1] opens with
a list of 8 Core Issues). Since HotSpot doesn't support use of C++17, use of
inherited constructors could run into those problems. Such uses might also
change behavior in a future HotSpot update to use C++17 or later, potentially
in subtle ways that could lead to hard to diagnose problems. Because of this,
HotSpot code must not use inherited constructors.
a list of 8 Core Issues). Although those issues have been addressed, the
benefits from this feature are small compared to the complexity. Because of
this, HotSpot code must not use inherited constructors.
Note that gcc7 provides the `-fnew-inheriting-ctors` option to use the
[p0136r1] semantics. This is enabled by default when using C++17 or later.
It is also enabled by default for `fabi-version=11` (introduced by gcc7) or
higher when using C++11/14, as the change is considered a Defect Report that
applies to those versions. Earlier versions of gcc don't have that option,
and other supported compilers may not have anything similar.
[p0136r1]: http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/p0136r1.html
"p0136r1"
[p0136r1]: http:/wg21.link/p0136r1 "p0136r1"
[p0195r0](http://wg21.link/p0195r0)
### Attributes
@ -1121,15 +1295,39 @@ preferred location.
function's declaration, rather than between the function name and the parameter
list.
[p0068r0](http://wg21.link/p0068r0) is the initial proposal for the attributes
added by C++17.)
Only the following attributes are permitted:
* `[[noreturn]]`
* `[[nodiscard]]` ([p0189r1](http://wg21.link/p0189r1))
* `[[maybe_unused]]` ([p0212r1](http://wg21.link/p0212r1))
* `[[fallthrough]]` ([p0188r1](http://wg21.link/p0188))
The following attributes are expressly forbidden:
* `[[carries_dependency]]` - Related to `memory_order_consume`.
* `[[deprecated]]` - Not relevant in HotSpot code.
Direct use of non-standard (and presumably scoped) attributes in shared code
is also forbidden. Using such would depend on the C++17 feature that an
attribute not recognized by the implementation is ignored
([p0283r2](http://wg21.link/p0283r2)). If such an attribute is needed in
shared code, the well-established technique of providing an `ATTRIBUTE_XXX`
macro with per-compiler definitions (sometimes empty) should be
used. Compilers may warn about unrecognized attributes (whether by name or by
location), in order to report typos or misuse. Disabling such warnings
globally would not be desirable.
The use of `using` directives in attribute lists is also forbidden.
([p0028r0](http://wg21.link/p0028r0))
([p0028r4](http://wg21.link/p0028r4))
We don't generally use scoped attributes in attribute lists with other
attributes. Rather, uses of scoped attributes (which are implementation
defined) are generally hidden behind a portability macro that includes the
surrounding brackets.
### noexcept
Use of `noexcept` exception specifications
@ -1178,9 +1376,79 @@ HotSpot code can assume no exceptions will ever be thrown, even from functions
not declared `noexcept`. So HotSpot code doesn't ever need to check, either
with conditional exception specifications or with `noexcept` expressions.
The exception specification is part of the type of a function
([p0012r1](http://wg21.link/p0012r1). This likely has little impact on HotSpot
code, since the use of `noexcept` is expected to be rare.
Dynamic exception specifications were deprecated in C++11. C++17 removed all
but `throw()`, with that remaining a deprecated equivalent to `noexcept`.
### Enhanced selection statements
C++17 modified the _condition_ part of `if` and `switch` statements, permitting
an _init-statement_ to be included
([p0305r1](http://wg21.link/p0305r1)).
Use of this feature is permitted. (However, complex uses may interfere with
readability.) Limiting the scope of a variable involved in the condition,
while also making the value available to the statement's body, can improve
readability. The alternative method of scope-limiting by introducing a nested
scope isn't very popular and is rarely used.
This new syntax is in addition to the _condition_ being a declaration with a
_brace-or-equal-initializer_. For an `if` statement this new sytax gains that
benefit without violating the long-standing guidance against using
[implicit conversions to `bool`](#avoid-implicit-conversions-to-bool),
which still stands.
For example, uses of Unified Logging sometimes explicitly check whether a
`LogTarget` is enabled. Instead of
```
LogTarget(...) lt;
if (lt.is_enabled()) {
LogStream log(lt);
... use log ...
}
... lt is accessible but probably not needed here ...
```
using this feature one could write
```
if (LogTarget(...) lt; lt.is_enabled()) {
LogStream log(lt);
... use log ...
}
```
C++17 also added compile-time `if` statements
([p0292r2](http://wg21.link/p0292r2)). Use of `if constexpr` is
permitted. This feature can replace and (sometimes vastly) simplify many uses
of [SFINAE]. The same declaration and initialization guidance for the
_condition_ part apply here as for ordinary `if` statements.
### Expression Evaluation Order
C++17 tightened up the evaluation order for some kinds of subexpressions
([p0138r2](http://wg21.link/p0138r2)). Note, however, that the Alternate
Evaluation Order for Function Calls alternative in that paper was adopted,
rather than the strict left to right order of evaluation for function call
arguments that was proposed in the main body of the paper.
The primary purpose of this change seems to be to make certain kinds of call
chaining well defined. That's not a style widely used in HotSpot. In general
it is better to continue to avoid questions in this area by isolating
operations with side effects from other statements. In particular, continue to
avoid modifying a value in an expression where it is also used.
### Compatibility with C11
C++17 refers to C11 rather than C99. This means that C11 libraries and
functions may be used in HotSpot. There may be limitations because of
differing levels of compatibility among various compilers and versions of
those compilers.
Note that the C parts of the JDK have been built with C11 selected for some
time ([JDK-8292008](https://bugs.openjdk.org/browse/JDK-8292008)).
### Additional Permitted Features
* `alignof`
@ -1198,7 +1466,10 @@ but `throw()`, with that remaining a deprecated equivalent to `noexcept`.
([n2555](http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2555.pdf))
* Static assertions
([n1720](http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2004/n1720.html))
([n1720](http://wg21.link/n1720))
([n3928](http://wg21.link/n3928))<br>
Both the original (C++11) two-argument form and the new (C++17)
single-argument form are permitted.
* `decltype`
([n2343](http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2343.pdf))
@ -1245,7 +1516,72 @@ but `throw()`, with that remaining a deprecated equivalent to `noexcept`.
* Unrestricted Unions
([n2544](http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2544.pdf))
### Excluded Features
* Preprocessor Condition `__has_include`
([p0061r0](http://wg21.link/p0061r0))
([p0061r1](http://wg21.link/p0061r1))
* Hexadecimal Floating-Point Literals
([p0245r1](http://wg21.link/p0245r1))
* Construction Rules for `enum class` Values
([p0138r2](http://wg21.link/p0138r2))
* Allow `typename` in template template parameter
([n4051](http://wg21.link/n4051)) &mdash; template template parameters are
barely used (if at all) in HotSpot, but there's no reason to artificially
disallow this syntactic regularization in any such uses.
## Excluded Features
### Structured Bindings
The use of structured bindings [p0217r3](http://wg21.link/p0217r3) is
forbidden. Preferred approaches for handling functions with multiple return
values include
* Return a named class/struct intended for that purpose, with named and typed
members/accessors.
* Return a value along with out parameters (usually pointers, sometimes
references).
* Designate a sentinel "failure" value in the normal return value type, with
some out of band location for additional information. For example, this is
the model typically used with `errno`, where a function returns a normal
result, or -1 to indicate an error, with additional error information in
`errno`.
There is a strong preference for names and explicit types, as opposed to
offsets and implicit types. For example, there are folks who strongly dislike
that some of the Standard Library functions return `std::pair` because `first`
and `second` members don't carry any useful information.
### File System Library
The use of the File System library is forbidden. HotSpot doesn't do very much
with files, and already has adequate mechanisms for its needs. Rewriting in
terms of this new library doesn't provide any obviously significant
benefits. Having a mix of the existing usage and uses of this new library
would be confusing.
[n4100](http://wg21.link/n4100)
[p0218r0](http://wg21.link/p0218r0)
[p0219r1](http://wg21.link/p0219r1)
[p0317r1](http://wg21.link/p0317r1)
[p0392r0](http://wg21.link/p0392r0)
[p0430r2](http://wg21.link/p0430r2)
[p0492r2](http://wg21.link/p0492r2)
[p1164r1](http://wg21.link/p1164r1)
### Aggregate Extensions
Aggregates with base classes are forbidden. C++17 allows aggregate
initialization for classes with base classes
([p0017r1](https://wg21.link/p0017r1)). HotSpot makes very little use of
aggregate classes, preferring explicit constructors even for very simple
classes.
### Additional Excluded Features
* New string and character literals
* New character types
@ -1281,27 +1617,277 @@ operator overloading is used, ensure the semantics conform to the
normal expected behavior of the operation.
* Avoid most implicit conversion constructors and (implicit or explicit)
conversion operators. (Note that conversion to `bool` isn't needed
in HotSpot code because of the "no implicit boolean" guideline.)
conversion operators. Conversion to `bool` operators aren't needed
because of the
[no implicit boolean](#avoid-implicit-conversions-to-bool)
guideline.)
* Avoid `goto` statements.
### Undecided Features
* Attributes for namespaces and enumerators
([n4266](http://wg21.link/n4266) &mdash;
The only applicable attribute is [`[[deprecated]]`](#attributes), which is
forbidden.
* Variadic `using` declarations
([p0195r2](http://wg21.link/p0195r2))
* `std::variant<>`
([p0088r3](http://wg21.link/p0088r3)) &mdash;
Even if more of the C++ Standard Library is permitted, this class will remain
forbidded. Invalid accesses are indicated by throwing exceptions.
* `std::any`
([p0220r1](http://wg21.link/p0220r1)) &mdash;
Even if more of the C++ Standard Library is permitted, this class will remain
forbidden. It may require allocation, and always uses the standard
allocator. It requires [RTTI].
* `std::as_const()`
([p0007r1](http://wg21.link/p0007r1)) &mdash;
If sufficiently useful, HotSpot could add such a function. It would likely be
added to globalDefinitions.hpp, where there are already some similar small
utilities.
* `std::clamp()`
([p002501](http://wg21.link/p002501)) &mdash;
This function is already provided in globalDefinitions.hpp.
* Parallel STL Algorithms
([p0024r2](http://wg21.link/p0024r2)) &mdash;
Even if more of the C++ Standard Library is permitted, these will remain
forbidden. They are built on the standard C++ threading mechanisms. HotSpot
doesn't use those mechanisms, instead providing and using its own.
* Cache Line Sizes
[p0154r1](http://wg21.link/p0154r1) &mdash;
HotSpot has its own mechanisms for this, using values like
`DEFAULT_CACHE_LINE_SIZE`. The platform-specific implementation of the HotSpot
mechanisms might use these library functions, but there is no reason to move
away from the current approach. Quoting from [JOSUTTIS]: "... if you know better,
use specific values, but using these values is better than any assumed fixed
size for code supporting multiple platforms."
* `register` storage class removal
[p0001r1](http://wg21.link/p0001r1) &mdash;
The `register` storage class has been removed. `register` is still a keyword,
so still can't be used for normal purposes. Also, this doesn't affect the use
of `register` for gcc-style extended asm code; that's a different syntactic
element with a different meaning.
* Value of `__cplusplus` &mdash;
Testing whether `__cplusplus` is defined or not is permitted, and indeed
required. But the value should not need to be examined. The value is changed
with each revision of the Standard. But we build HotSpot and (most of) the
rest of the JDK with a specifically selected version of the Standard. The
value of `__cplusplus` should be known and unchanging until we change the
project's build configuration again. So examining the value shouldn't ever be
necessary.
* Removal of `++` for `bool`
([p0003r1](http://wg21.link/p0003r1))
* Removal of trigraphs
([n4086](http://wg21.link/n4086))
## Undecided Features
This list is incomplete; it serves to explicitly call out some
features that have not yet been discussed.
Some features are undecided (so implicitly forbidden) because we don't expect
to use them at all. This might be reconsidered if someone finds a good use
case.
Some Standard Library features are undecided (so implicitly forbidden)
because, while this Style Guide forbids the use of such, they may be
sufficiently useful that we want to permit them anyway. Doing so may require
some idiomatic mechanism for addressing things like `assert` incompatibility,
incompatibility with HotSpot's `FORBID_C_FUNCTION` mechanism, and the like.
### std::optional<>
It is undecided whether to permit the use of `std::optional<>`
([p0220r1](http://wg21.link/p0220r1)). It may be sufficiently useful that it
should be permitted despite the usual prohibition against using Standard
Library facilities. Use of the `value()` member function must be forbidden, as
it reports an invalid access by throwing an exception.
### std::byte
It is undecided whether to permit the use of the `std::byte` type
([p0298r3](http://wg21.link/p0298r3)). It may be sufficiently useful that it
should be permitted despite the usual prohibition against using Standard
Library facilities.
It has been suggested that changing the HotSpot `address` type to use
`std::byte` has some benefits. That is, replace
```
typedef u_char* address;
typedef const u_char* const_address;
```
```
using address = std::byte*;
using const_address = const std::byte*;
```
in globalDefinitions.hpp.
A specific benefit that was mentioned is that it might improve the horrible
way that gdb handles our current definition of the `address` type.
```
#include <cstddef>
typedef unsigned char* address;
typedef std::byte* address_b;
int main() {
char* mem;
address addr = (address)mem;
address_b addr_b = (address_b)mem;
return 0;
}
```
```
(gdb) p addr
$1 = (address) 0x7ffff7fe4fa0 <dl_main> "\363\017\036\372Uf\017\357\300H\211\345AWI\211\377AVAUATSH\201\354\210\002"
(gdb) p addr_b
$2 = (address_b) 0x7ffff7fe4fa0 <dl_main>
```
This needs to be explored. Some folks have said they will do so.
### String Views
It is undecided whether to permit the use of `std::string_view`
([p0220r1](http://wg21.link/p0220r1)).
HotSpot doesn't use `std::string`, but uses `char*` strings a lot. Wrapping
such in a `std::string_view` to enable the use of various algorithms could be
useful. But since HotSpot also doesn't permit use of `<algorithm>` and the
like, that only gets the limited set of algorithms provided by the view class
directly.
There is also the issue of `NUL` termination; string views are not necessarily
`NUL` terminated. Moreover, if one goes to the work of making one that is
`NUL` terminated, that terminator is included in the size.
There are other caveats. Permitting use of string views would require
discussion of those.
### Substring and Subsequence Searching
In addition to simple substring searching, the Standard Library now includes
Boyer-Moore and Boyer-Moore-Horspool searchers, in case someone wants to
search really large texts. That seems an unlikely use-case for HotSpot. See
[p0220r1](http://wg21.link/p0220r1).
### `new` and `delete` with Over-Aligned Data
It is undecided whether to permit the use of dynamic allocation of overaligned
types ([n3396](http://wg21.link/n3396)).
HotSpot currently only has a couple of over-aligned types that are dynamically
allocated. These are handled manually, not going through `new` expressions, as
that couldn't work before C++17.
One of the ways an over-aligned type might arise is by aligning a data member.
This might be done to avoid destructive interference for concurrent accesses.
But HotSpot uses a different approach, using explicit padding. Again, this is
in part because `new` and `delete` of overaligned types didn't work. But we
might prefer to continue this approach.
We would need to add `operator new` overloads to `CHeapObj<>` and possibly in
other places in order to support this. However, it has been suggested that
implementing it (efficiently) on top of NMT might be difficult. Note that
`posix_memalign` / `_aligned_malloc` don't help here, because of NMT's use of
malloc headers.
If we don't support it we may want to add `operator new` overloads that are
deleted, to prevent attempted uses.
Alignment usage in non-HotSpot parts of the OpenJDK:
* `alignas` used once in harfbuzz, to align a variable.
* libpipewire has `#define SPA_ALIGNED` macro using gcc `aligned` attribute,
but doesn't use it.
* libsleef has `#define ALIGNED` macro using gcc `aligned` attribute. It is
not used for class or member declarations.
### `std::to_chars()` and `std::from_chars`
It is undecided whether to permit the use of `std::to_chars()` and
`std::from_chars()` ([p0067r5](http://wg21.link/p0067r5)).
These functions provide low-level conversions between character sequences and
numeric values. This seems like a good candidate for use in HotSpot,
potentially replacing various clumsy or less performant alternatives. There is
no memory allocation. Parsing failures are indicated via error codes rather
than exceptions. Various other nice for HotSpot properties.
Note that the published C++17 Standard puts these in `<utility>`, but a defect
report moved them to `<charconv>`. This also needs `<system_error>`.
This would require upgrading the minimum gcc version to 11.1 for floating
point conversion support. The minimum Visual Studio version is already
sufficient. The minimum clang version requirement hasn't been determined yet.
### `std::launder()`
It is undecided whether to permit the use of `std::launder()`
([p0137r1](http://wg21.link/p0137r1)).
Change to permitted if we discover a place where we need it. Or maybe we
should just permit it, but hope we don't need it.
Also, C++20 revised the relevant part of Object Lifetime in a way that seems
more permissive and with less need of laundering. We don't know if
implementations of prior versions take advantage of the difference.
See Object Lifetime: C++17 6.8/8, C++20 6.7.3/8
### Additional Undecided Features
* Trailing return type syntax for functions
([n2541](http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2541.htm))
* Variable templates
([n3651](https://isocpp.org/files/papers/N3651.pdf))
* Member initializers and aggregates
([n3653](http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2013/n3653.html))
* Rvalue references and move semantics
* Shorthand for nested namespaces
([n4230](http://wg21.link/n4230)) &mdash;
HotSpot makes very little use of namespaces, so this seemingly innocuous
feature probably isn't useful to us.
* Direct list initialization with `auto`
([n3681](http://wg21.link/n3681)) &mdash;
This change fixed some issues with direct list initialization and `auto`. But
we don't use that feature much, if at all. And perhaps shouldn't be using it.
* UTF-8 Character Literals
([n4267](http://wg21.link/n4267)) &mdash;
Do we have a use-case for this?
* Fold Expressions
([n4295](http://wg21.link/n4295)) &mdash;
Provides a simple way to apply operators to a parameter pack. HotSpot doesn't
use variadic templates very much. That makes it questionable that developers
should need to know about this feature. But if someone does come up with a
good use-case, it's likely that the alternatives are significantly worse,
because pack manipulation without this can be complicated.
* `std::invoke<>()`
([n4169](http://wg21.link/n4169))
[ADL]: https://en.cppreference.com/w/cpp/language/adl
"Argument Dependent Lookup"
@ -1319,3 +1905,6 @@ features that have not yet been discussed.
[PARTIALAPP]: https://en.wikipedia.org/wiki/Partial_application
"Partial Application"
[JOSUTTIS]: https://www.cppstd17.com
"C++17: The Complete Guide"

View File

@ -398,7 +398,8 @@ TEST_OPTS keywords.</p>
<h4 id="jobs">JOBS</h4>
<p>Currently only applies to JTReg.</p>
<h4 id="timeout_factor">TIMEOUT_FACTOR</h4>
<p>Currently only applies to JTReg.</p>
<p>Currently only applies to <a href="#timeout_factor-1">JTReg
-timeoutFactor</a>.</p>
<h4 id="java_options">JAVA_OPTIONS</h4>
<p>Applies to JTReg, GTest and Micro.</p>
<h4 id="vm_options">VM_OPTIONS</h4>
@ -444,8 +445,12 @@ otherwise it defaults to JOBS, except for Hotspot, where the default is
<em>number of CPU cores/2</em>, but never more than <em>memory size in
GB/2</em>.</p>
<h4 id="timeout_factor-1">TIMEOUT_FACTOR</h4>
<p>The timeout factor (<code>-timeoutFactor</code>).</p>
<p>Defaults to 4.</p>
<p>The <code>TIMEOUT_FACTOR</code> is forwarded to JTReg framework
itself (<code>-timeoutFactor</code>). Also, some test cases that
programmatically wait a certain amount of time will apply this factor.
If we run in forced compilation mode (<code>-Xcomp</code>), the build
system will automatically adjust this factor to compensate for less
performance. Defaults to 1.</p>
<h4 id="failure_handler_timeout">FAILURE_HANDLER_TIMEOUT</h4>
<p>Sets the argument <code>-timeoutHandlerTimeout</code> for JTReg. The
default value is 0. This is only valid if the failure handler is

View File

@ -324,7 +324,7 @@ Currently only applies to JTReg.
#### TIMEOUT_FACTOR
Currently only applies to JTReg.
Currently only applies to [JTReg -timeoutFactor](#timeout_factor-1).
#### JAVA_OPTIONS
@ -383,9 +383,11 @@ never more than *memory size in GB/2*.
#### TIMEOUT_FACTOR
The timeout factor (`-timeoutFactor`).
Defaults to 4.
The `TIMEOUT_FACTOR` is forwarded to JTReg framework itself
(`-timeoutFactor`). Also, some test cases that programmatically wait a
certain amount of time will apply this factor. If we run in forced
compilation mode (`-Xcomp`), the build system will automatically
adjust this factor to compensate for less performance. Defaults to 1.
#### FAILURE_HANDLER_TIMEOUT

View File

@ -301,7 +301,7 @@ ifneq ($(filter product-bundles% legacy-bundles, $(MAKECMDGOALS)), )
$(call LogWarn, Signing $(JDK_BUNDLE_NAME))
$(CODESIGN) -s "$(MACOSX_CODESIGN_IDENTITY)" \
--timestamp --options runtime --deep --force \
$(JDK_MACOSX_BUNDLE_DIR_SIGNED)/$(JDK_MACOSX_BUNDLE_TOP_DIR) $(LOG_DEBUG)
$(JDK_MACOSX_BUNDLE_DIR_SIGNED)/$(JDK_MACOSX_BUNDLE_TOP_SUBDIR) $(LOG_DEBUG)
$(TOUCH) $@
$(eval $(call SetupBundleFile, BUILD_JDK_BUNDLE, \
@ -330,7 +330,7 @@ ifneq ($(filter product-bundles% legacy-bundles, $(MAKECMDGOALS)), )
$(call LogWarn, Signing $(JRE_BUNDLE_NAME))
$(CODESIGN) -s "$(MACOSX_CODESIGN_IDENTITY)" \
--timestamp --options runtime --deep --force \
$(JRE_MACOSX_BUNDLE_DIR_SIGNED)/$(JRE_MACOSX_BUNDLE_TOP_DIR) $(LOG_DEBUG)
$(JRE_MACOSX_BUNDLE_DIR_SIGNED)/$(JRE_MACOSX_BUNDLE_TOP_SUBDIR) $(LOG_DEBUG)
$(TOUCH) $@
$(eval $(call SetupBundleFile, BUILD_JRE_BUNDLE, \

View File

@ -257,6 +257,7 @@ $(eval $(call SetupExecute, create_$(JMOD_FILE), \
WARN := Creating $(INTERIM_MSG)$(JMOD_FILE), \
DEPS := $(DEPS), \
OUTPUT_FILE := $(JMODS_DIR)/$(JMOD_FILE), \
WORKING_DIR := $(WORKSPACE_ROOT), \
SUPPORT_DIR := $(JMODS_SUPPORT_DIR), \
PRE_COMMAND := $(RM) $(JMODS_DIR)/$(JMOD_FILE) $(JMODS_SUPPORT_DIR)/$(JMOD_FILE), \
COMMAND := $(JMOD) $(JMOD_SMALL_FLAGS) create --module-version $(VERSION_SHORT) \

View File

@ -509,7 +509,7 @@ define SetupRunGtestTestBody
$$(call LogWarn)
$$(call LogWarn, Running test '$$($1_TEST)')
$$(call MakeDir, $$($1_TEST_RESULTS_DIR) $$($1_TEST_SUPPORT_DIR))
$$(call ExecuteWithLog, $$($1_TEST_SUPPORT_DIR)/gtest, ( \
$$(call ExecuteWithLog, $$($1_TEST_SUPPORT_DIR)/gtest, \
$$(CD) $$($1_TEST_SUPPORT_DIR) && \
$$(FIXPATH) $$(TEST_IMAGE_DIR)/hotspot/gtest/$$($1_VARIANT)/gtestLauncher \
-jdk $(JDK_UNDER_TEST) $$($1_GTEST_FILTER) \
@ -520,7 +520,7 @@ define SetupRunGtestTestBody
> >($(TEE) $$($1_TEST_RESULTS_DIR)/gtest.txt) \
&& $$(ECHO) $$$$? > $$($1_EXITCODE) \
|| $$(ECHO) $$$$? > $$($1_EXITCODE) \
))
)
$1_RESULT_FILE := $$($1_TEST_RESULTS_DIR)/gtest.txt
@ -644,7 +644,7 @@ define SetupRunMicroTestBody
$$(call LogWarn)
$$(call LogWarn, Running test '$$($1_TEST)')
$$(call MakeDir, $$($1_TEST_RESULTS_DIR) $$($1_TEST_SUPPORT_DIR))
$$(call ExecuteWithLog, $$($1_TEST_SUPPORT_DIR)/micro, ( \
$$(call ExecuteWithLog, $$($1_TEST_SUPPORT_DIR)/micro, \
$$(CD) $$(TEST_IMAGE_DIR) && \
$$(FIXPATH) $$($1_MICRO_TEST_JDK)/bin/java $$($1_MICRO_JAVA_OPTIONS) \
-jar $$($1_MICRO_BENCHMARKS_JAR) \
@ -655,7 +655,7 @@ define SetupRunMicroTestBody
> >($(TEE) $$($1_TEST_RESULTS_DIR)/micro.txt) \
&& $$(ECHO) $$$$? > $$($1_EXITCODE) \
|| $$(ECHO) $$$$? > $$($1_EXITCODE) \
))
)
$1_RESULT_FILE := $$($1_TEST_RESULTS_DIR)/micro.txt
@ -758,34 +758,34 @@ define SetupAOTBody
ifeq ($$($1_TRAINING), onestep)
$$(call LogWarn, AOT: Create AOT cache $$($1_AOT_JDK_CACHE) in one step with flags: $$($1_VM_OPTIONS)) \
$$(call ExecuteWithLog, $$($1_AOT_JDK_OUTPUT_DIR), ( \
$$(call ExecuteWithLog, $$($1_AOT_JDK_OUTPUT_DIR), \
cd $$($1_AOT_JDK_OUTPUT_DIR); \
$(JAR) --extract --file $(TEST_IMAGE_DIR)/setup_aot/TestSetupAOT.jar; \
$$(FIXPATH) $(JDK_UNDER_TEST)/bin/java $$($1_VM_OPTIONS) \
-Xlog:class+load,aot,aot+class=debug:file=$$($1_AOT_JDK_CACHE).log -Xlog:cds*=error -Xlog:aot*=error \
-Xlog:class+load$$(COMMA)aot$$(COMMA)aot+class=debug:file=$$($1_AOT_JDK_CACHE).log -Xlog:cds*=error -Xlog:aot*=error \
-XX:AOTMode=record -XX:AOTCacheOutput=$$($1_AOT_JDK_CACHE) \
TestSetupAOT $$($1_AOT_JDK_OUTPUT_DIR) > $$($1_AOT_JDK_LOG) \
))
)
else
$$(call LogWarn, AOT: Create cache configuration) \
$$(call ExecuteWithLog, $$($1_AOT_JDK_OUTPUT_DIR), ( \
$$(call ExecuteWithLog, $$($1_AOT_JDK_OUTPUT_DIR), \
cd $$($1_AOT_JDK_OUTPUT_DIR); \
$(JAR) --extract --file $(TEST_IMAGE_DIR)/setup_aot/TestSetupAOT.jar; \
$$(FIXPATH) $(JDK_UNDER_TEST)/bin/java $$($1_VM_OPTIONS) \
-Xlog:class+load,aot,aot+class=debug:file=$$($1_AOT_JDK_CONF).log -Xlog:cds*=error -Xlog:aot*=error \
-Xlog:class+load$$(COMMA)aot$$(COMMA)aot+class=debug:file=$$($1_AOT_JDK_CONF).log -Xlog:cds*=error -Xlog:aot*=error \
-XX:AOTMode=record -XX:AOTConfiguration=$$($1_AOT_JDK_CONF) \
TestSetupAOT $$($1_AOT_JDK_OUTPUT_DIR) > $$($1_AOT_JDK_LOG) \
))
)
$$(call LogWarn, AOT: Generate AOT cache $$($1_AOT_JDK_CACHE) with flags: $$($1_VM_OPTIONS))
$$(call ExecuteWithLog, $$($1_AOT_JDK_OUTPUT_DIR), ( \
$$(call ExecuteWithLog, $$($1_AOT_JDK_OUTPUT_DIR), \
$$(FIXPATH) $(JDK_UNDER_TEST)/bin/java \
$$($1_VM_OPTIONS) -Xlog:aot,aot+class=debug:file=$$($1_AOT_JDK_CACHE).log -Xlog:cds*=error -Xlog:aot*=error \
$$($1_VM_OPTIONS) -Xlog:aot$$(COMMA)aot+class=debug:file=$$($1_AOT_JDK_CACHE).log -Xlog:cds*=error -Xlog:aot*=error \
-XX:ExtraSharedClassListFile=$(JDK_UNDER_TEST)/lib/classlist \
-XX:AOTMode=create -XX:AOTConfiguration=$$($1_AOT_JDK_CONF) -XX:AOTCache=$$($1_AOT_JDK_CACHE) \
))
)
endif
@ -946,7 +946,8 @@ define SetupRunJtregTestBody
JTREG_ALL_OPTIONS := $$(JTREG_JAVA_OPTIONS) $$(JTREG_VM_OPTIONS)
JTREG_AUTO_PROBLEM_LISTS :=
JTREG_AUTO_TIMEOUT_FACTOR := 4
# Please reach consensus before changing this. It was not easy changing it to a `1`.
JTREG_AUTO_TIMEOUT_FACTOR := 1
ifneq ($$(findstring -Xcomp, $$(JTREG_ALL_OPTIONS)), )
JTREG_AUTO_PROBLEM_LISTS += ProblemList-Xcomp.txt
@ -1084,9 +1085,9 @@ define SetupRunJtregTestBody
$$(call LogWarn, Running test '$$($1_TEST)')
$$(call MakeDir, $$($1_TEST_RESULTS_DIR) $$($1_TEST_SUPPORT_DIR) \
$$($1_TEST_TMP_DIR))
$$(call ExecuteWithLog, $$($1_TEST_SUPPORT_DIR)/jtreg, ( \
$$(call ExecuteWithLog, $$($1_TEST_SUPPORT_DIR)/jtreg, \
$$(COV_ENVIRONMENT) $$($1_COMMAND_LINE) \
))
)
$1_RESULT_FILE := $$($1_TEST_RESULTS_DIR)/text/stats.txt
@ -1203,12 +1204,12 @@ define SetupRunSpecialTestBody
$$(call LogWarn)
$$(call LogWarn, Running test '$$($1_TEST)')
$$(call MakeDir, $$($1_TEST_RESULTS_DIR) $$($1_TEST_SUPPORT_DIR))
$$(call ExecuteWithLog, $$($1_TEST_SUPPORT_DIR)/test-execution, ( \
$$(call ExecuteWithLog, $$($1_TEST_SUPPORT_DIR)/test-execution, \
$$($1_TEST_COMMAND_LINE) \
> >($(TEE) $$($1_TEST_RESULTS_DIR)/test-output.txt) \
&& $$(ECHO) $$$$? > $$($1_EXITCODE) \
|| $$(ECHO) $$$$? > $$($1_EXITCODE) \
))
)
# We can not parse the various "special" tests.
parse-test-$1: run-test-$1

View File

@ -111,7 +111,7 @@ else ifeq ($(call isTargetOs, aix), true)
INFO := Generating export list for $(notdir $(lib)), \
DEPS := $(lib), \
OUTPUT_FILE := $(lib).exp, \
COMMAND := ( $(AR) $(ARFLAGS) -w $(lib) | $(GREP) -v '^\.' | $(AWK) '{print $$1}' | $(SORT) -u > $(lib).exp ), \
COMMAND := $(AR) $(ARFLAGS) -w $(lib) | $(GREP) -v '^\.' | $(AWK) '{print $$1}' | $(SORT) -u > $(lib).exp, \
)) \
$(eval STATIC_LIB_EXPORT_FILES += $(lib).exp) \
)

View File

@ -130,6 +130,9 @@ TOOL_PUBLICSUFFIXLIST = $(JAVA_SMALL) -cp $(BUILDTOOLS_OUTPUTDIR)/jdk_tools_clas
TOOL_FIXUPPANDOC = $(JAVA_SMALL) -cp $(BUILDTOOLS_OUTPUTDIR)/jdk_tools_classes \
build.tools.fixuppandoc.Main
TOOL_VARHANDLEGUARDMETHODGENERATOR = $(JAVA_SMALL) -cp $(BUILDTOOLS_OUTPUTDIR)/jdk_tools_classes \
build.tools.methodhandle.VarHandleGuardMethodGenerator
################################################################################
# Executable javascript filter for man page generation using pandoc.

View File

@ -81,8 +81,8 @@ SLEEF_CMAKE_FILE := toolchains/$(OPENJDK_TARGET_CPU)-$(SLEEF_TOOLCHAIN_TYPE).cma
$(eval $(call SetupExecute, sleef_native_config, \
INFO := Configuring native sleef build, \
OUTPUT_DIR := $(SLEEF_NATIVE_BUILD_DIR), \
COMMAND := cd $(SLEEF_SOURCE_DIR) && $(CMAKE) -S . -B \
$(SLEEF_NATIVE_BUILD_DIR), \
WORKING_DIR := $(SLEEF_SOURCE_DIR), \
COMMAND := $(CMAKE) -S . -B $(SLEEF_NATIVE_BUILD_DIR), \
))
TARGETS := $(sleef_native_config)
@ -91,8 +91,8 @@ $(eval $(call SetupExecute, sleef_native_build, \
INFO := Building native sleef, \
DEPS := $(sleef_native_config), \
OUTPUT_DIR := $(SLEEF_NATIVE_BUILD_DIR), \
COMMAND := cd $(SLEEF_SOURCE_DIR) && $(CMAKE) --build \
$(SLEEF_NATIVE_BUILD_DIR) -j, \
WORKING_DIR := $(SLEEF_SOURCE_DIR), \
COMMAND := $(CMAKE) --build $(SLEEF_NATIVE_BUILD_DIR) -j, \
))
TARGETS := $(sleef_native_build)
@ -101,8 +101,8 @@ $(eval $(call SetupExecute, sleef_cross_config, \
INFO := Configuring cross-compiling sleef build, \
DEPS := $(sleef_native_build), \
OUTPUT_DIR := $(SLEEF_CROSS_BUILD_DIR), \
COMMAND := cd $(SLEEF_SOURCE_DIR) && $(CMAKE) -S . -B \
$(SLEEF_CROSS_BUILD_DIR) \
WORKING_DIR := $(SLEEF_SOURCE_DIR), \
COMMAND := $(CMAKE) -S . -B $(SLEEF_CROSS_BUILD_DIR) \
-DCMAKE_C_COMPILER=$(CC) \
-DCMAKE_TOOLCHAIN_FILE=$(SLEEF_CMAKE_FILE) \
-DNATIVE_BUILD_DIR=$(SLEEF_NATIVE_BUILD_DIR) \
@ -116,8 +116,8 @@ $(eval $(call SetupExecute, sleef_cross_build, \
INFO := Building cross-compiling sleef, \
DEPS := $(sleef_cross_config), \
OUTPUT_DIR := $(SLEEF_NATIVE_BUILD_DIR), \
COMMAND := cd $(SLEEF_SOURCE_DIR) && $(CMAKE) --build \
$(SLEEF_CROSS_BUILD_DIR) -j, \
WORKING_DIR := $(SLEEF_SOURCE_DIR), \
COMMAND := $(CMAKE) --build $(SLEEF_CROSS_BUILD_DIR) -j, \
))
TARGETS := $(sleef_cross_build)

View File

@ -210,17 +210,8 @@ AC_DEFUN([BASIC_SETUP_XCODE_SYSROOT],
if test $? -ne 0; then
AC_MSG_ERROR([The xcodebuild tool in the devkit reports an error: $XCODEBUILD_OUTPUT])
fi
elif test "x$TOOLCHAIN_PATH" != x; then
UTIL_LOOKUP_PROGS(XCODEBUILD, xcodebuild, $TOOLCHAIN_PATH)
if test "x$XCODEBUILD" != x; then
XCODEBUILD_OUTPUT=`"$XCODEBUILD" -version 2>&1`
if test $? -ne 0; then
AC_MSG_WARN([Ignoring the located xcodebuild tool $XCODEBUILD due to an error: $XCODEBUILD_OUTPUT])
XCODEBUILD=
fi
fi
else
UTIL_LOOKUP_PROGS(XCODEBUILD, xcodebuild)
UTIL_LOOKUP_TOOLCHAIN_PROGS(XCODEBUILD, xcodebuild)
if test "x$XCODEBUILD" != x; then
XCODEBUILD_OUTPUT=`"$XCODEBUILD" -version 2>&1`
if test $? -ne 0; then
@ -348,21 +339,11 @@ AC_DEFUN_ONCE([BASIC_SETUP_DEVKIT],
# You can force the sysroot if the sysroot encoded into the compiler tools
# is not correct.
AC_ARG_WITH(sys-root, [AS_HELP_STRING([--with-sys-root],
[alias for --with-sysroot for backwards compatibility])],
[SYSROOT=$with_sys_root]
)
AC_ARG_WITH(sysroot, [AS_HELP_STRING([--with-sysroot],
[use this directory as sysroot])],
[SYSROOT=$with_sysroot]
)
AC_ARG_WITH([tools-dir], [AS_HELP_STRING([--with-tools-dir],
[alias for --with-toolchain-path for backwards compatibility])],
[UTIL_PREPEND_TO_PATH([TOOLCHAIN_PATH],$with_tools_dir)]
)
AC_ARG_WITH([toolchain-path], [AS_HELP_STRING([--with-toolchain-path],
[prepend these directories when searching for toolchain binaries (compilers etc)])],
[UTIL_PREPEND_TO_PATH([TOOLCHAIN_PATH],$with_toolchain_path)]
@ -371,6 +352,9 @@ AC_DEFUN_ONCE([BASIC_SETUP_DEVKIT],
AC_ARG_WITH([xcode-path], [AS_HELP_STRING([--with-xcode-path],
[set up toolchain on Mac OS using a path to an Xcode installation])])
UTIL_DEPRECATED_ARG_WITH(sys-root)
UTIL_DEPRECATED_ARG_WITH(tools-dir)
if test "x$with_xcode_path" != x; then
if test "x$OPENJDK_BUILD_OS" = "xmacosx"; then
UTIL_PREPEND_TO_PATH([TOOLCHAIN_PATH],

View File

@ -207,29 +207,14 @@ AC_DEFUN([BASIC_CHECK_GNU_MAKE],
UTIL_SETUP_TOOL(MAKE,
[
# Try our hardest to locate a correct version of GNU make
UTIL_LOOKUP_PROGS(CHECK_GMAKE, gmake)
UTIL_LOOKUP_TOOLCHAIN_PROGS(CHECK_GMAKE, gmake)
BASIC_CHECK_MAKE_VERSION("$CHECK_GMAKE", [gmake in PATH])
if test "x$FOUND_MAKE" = x; then
UTIL_LOOKUP_PROGS(CHECK_MAKE, make)
UTIL_LOOKUP_TOOLCHAIN_PROGS(CHECK_MAKE, make)
BASIC_CHECK_MAKE_VERSION("$CHECK_MAKE", [make in PATH])
fi
if test "x$FOUND_MAKE" = x; then
if test "x$TOOLCHAIN_PATH" != x; then
# We have a toolchain path, check that as well before giving up.
OLD_PATH=$PATH
PATH=$TOOLCHAIN_PATH:$PATH
UTIL_LOOKUP_PROGS(CHECK_TOOLSDIR_GMAKE, gmake)
BASIC_CHECK_MAKE_VERSION("$CHECK_TOOLSDIR_GMAKE", [gmake in tools-dir])
if test "x$FOUND_MAKE" = x; then
UTIL_LOOKUP_PROGS(CHECK_TOOLSDIR_MAKE, make)
BASIC_CHECK_MAKE_VERSION("$CHECK_TOOLSDIR_MAKE", [make in tools-dir])
fi
PATH=$OLD_PATH
fi
fi
if test "x$FOUND_MAKE" = x; then
AC_MSG_ERROR([Cannot find GNU make $MAKE_REQUIRED_VERSION or newer! Please put it in the path, or add e.g. MAKE=/opt/gmake3.81/make as argument to configure.])
fi

View File

@ -162,12 +162,7 @@ AC_DEFUN([BPERF_SETUP_CCACHE],
# Check if ccache is available
CCACHE_AVAILABLE=true
OLD_PATH="$PATH"
if test "x$TOOLCHAIN_PATH" != x; then
PATH=$TOOLCHAIN_PATH:$PATH
fi
UTIL_LOOKUP_PROGS(CCACHE, ccache)
PATH="$OLD_PATH"
UTIL_LOOKUP_TOOLCHAIN_PROGS(CCACHE, ccache)
AC_MSG_CHECKING([if ccache is available])
if test "x$TOOLCHAIN_TYPE" != "xgcc" && test "x$TOOLCHAIN_TYPE" != "xclang"; then

View File

@ -110,4 +110,4 @@ $MV $OUTPUTDIR/compare.log $OUTPUTDIR/compare.log.old 2> /dev/null
export SCRIPT_DIR="$( cd "$( dirname "$0" )" > /dev/null && pwd )"
$BASH $TOPDIR/make/scripts/logger.sh $OUTPUTDIR/compare.log $BASH "$REAL_COMPARE_SCRIPT" "$@"
$BASH $TOPDIR/make/scripts/compare-logger.sh $OUTPUTDIR/compare.log $BASH "$REAL_COMPARE_SCRIPT" "$@"

View File

@ -221,6 +221,9 @@ JDKOPT_SETUP_UNDEFINED_BEHAVIOR_SANITIZER
# LeakSanitizer
JDKOPT_SETUP_LEAK_SANITIZER
# Setup static analyzer
JDKOPT_SETUP_STATIC_ANALYZER
# Fallback linker
# This needs to go before 'LIB_DETERMINE_DEPENDENCIES'
JDKOPT_SETUP_FALLBACK_LINKER

View File

@ -597,11 +597,11 @@ AC_DEFUN([FLAGS_SETUP_CFLAGS_HELPER],
# CXXFLAGS C++ language level for all of JDK, including Hotspot.
if test "x$TOOLCHAIN_TYPE" = xgcc || test "x$TOOLCHAIN_TYPE" = xclang; then
LANGSTD_CXXFLAGS="-std=c++14"
LANGSTD_CXXFLAGS="-std=c++17"
elif test "x$TOOLCHAIN_TYPE" = xmicrosoft; then
LANGSTD_CXXFLAGS="-std:c++14"
LANGSTD_CXXFLAGS="-std:c++17"
else
AC_MSG_ERROR([Cannot enable C++14 for this toolchain])
AC_MSG_ERROR([Cannot enable C++17 for this toolchain])
fi
TOOLCHAIN_CFLAGS_JDK_CXXONLY="$TOOLCHAIN_CFLAGS_JDK_CXXONLY $LANGSTD_CXXFLAGS"
TOOLCHAIN_CFLAGS_JVM="$TOOLCHAIN_CFLAGS_JVM $LANGSTD_CXXFLAGS"

View File

@ -74,7 +74,7 @@ AC_DEFUN([FLAGS_SETUP_LDFLAGS_HELPER],
# Clang needs the lld linker to work correctly
BASIC_LDFLAGS="-fuse-ld=lld -Wl,--exclude-libs,ALL"
if test "x$CXX_IS_USER_SUPPLIED" = xfalse && test "x$CC_IS_USER_SUPPLIED" = xfalse; then
UTIL_REQUIRE_PROGS(LLD, lld, $TOOLCHAIN_PATH:$PATH)
UTIL_REQUIRE_TOOLCHAIN_PROGS(LLD, lld)
fi
fi
if test "x$OPENJDK_TARGET_OS" = xaix; then

View File

@ -320,12 +320,16 @@ AC_DEFUN([FLAGS_SETUP_TOOLCHAIN_CONTROL],
[
if test "x$TOOLCHAIN_TYPE" = xmicrosoft; then
CC_OUT_OPTION=-Fo
if test "x$OPENJDK_TARGET_CPU" != xaarch64; then
AS_NON_ASM_EXTENSION_OPTION=-Ta
fi
else
# The option used to specify the target .o,.a or .so file.
# When compiling, how to specify the to be created object file.
CC_OUT_OPTION='-o$(SPACE)'
fi
AC_SUBST(CC_OUT_OPTION)
AC_SUBST(AS_NON_ASM_EXTENSION_OPTION)
# Generate make dependency files
if test "x$TOOLCHAIN_TYPE" = xgcc; then

View File

@ -479,6 +479,31 @@ AC_DEFUN_ONCE([JDKOPT_SETUP_ADDRESS_SANITIZER],
AC_SUBST(ASAN_ENABLED)
])
################################################################################
#
# Static analyzer
#
AC_DEFUN_ONCE([JDKOPT_SETUP_STATIC_ANALYZER],
[
UTIL_ARG_ENABLE(NAME: static-analyzer, DEFAULT: false, RESULT: STATIC_ANALYZER_ENABLED,
DESC: [enable the GCC static analyzer],
CHECK_AVAILABLE: [
AC_MSG_CHECKING([if static analyzer is available])
if test "x$TOOLCHAIN_TYPE" = "xgcc"; then
AC_MSG_RESULT([yes])
else
AC_MSG_RESULT([no])
AVAILABLE=false
fi
],
IF_ENABLED: [
STATIC_ANALYZER_CFLAGS="-fanalyzer -Wno-analyzer-fd-leak"
CFLAGS_JDKLIB="$CFLAGS_JDKLIB $STATIC_ANALYZER_CFLAGS"
CFLAGS_JDKEXE="$CFLAGS_JDKEXE $STATIC_ANALYZER_CFLAGS"
])
AC_SUBST(STATIC_ANALYZER_ENABLED)
])
################################################################################
#
# LeakSanitizer

View File

@ -492,6 +492,7 @@ CXX_VERSION_NUMBER := @CXX_VERSION_NUMBER@
HOTSPOT_TOOLCHAIN_TYPE := @HOTSPOT_TOOLCHAIN_TYPE@
CC_OUT_OPTION := @CC_OUT_OPTION@
AS_NON_ASM_EXTENSION_OPTION := @AS_NON_ASM_EXTENSION_OPTION@
# Flags used for overriding the default opt setting for a C/C++ source file.
C_O_FLAG_HIGHEST_JVM := @C_O_FLAG_HIGHEST_JVM@
@ -897,12 +898,14 @@ JDK_MACOSX_BUNDLE_DIR = $(IMAGES_OUTPUTDIR)/$(JDK_MACOSX_BUNDLE_SUBDIR)
JRE_MACOSX_BUNDLE_DIR = $(IMAGES_OUTPUTDIR)/$(JRE_MACOSX_BUNDLE_SUBDIR)
JDK_MACOSX_BUNDLE_DIR_SIGNED = $(IMAGES_OUTPUTDIR)/$(JDK_MACOSX_BUNDLE_SUBDIR_SIGNED)
JRE_MACOSX_BUNDLE_DIR_SIGNED = $(IMAGES_OUTPUTDIR)/$(JRE_MACOSX_BUNDLE_SUBDIR_SIGNED)
JDK_MACOSX_BUNDLE_TOP_DIR = jdk-$(VERSION_NUMBER).jdk
JRE_MACOSX_BUNDLE_TOP_DIR = jre-$(VERSION_NUMBER).jre
JDK_MACOSX_CONTENTS_SUBDIR = $(JDK_MACOSX_BUNDLE_TOP_DIR)/Contents
JRE_MACOSX_CONTENTS_SUBDIR = $(JRE_MACOSX_BUNDLE_TOP_DIR)/Contents
JDK_MACOSX_BUNDLE_TOP_SUBDIR = jdk-$(VERSION_NUMBER).jdk
JRE_MACOSX_BUNDLE_TOP_SUBDIR = jre-$(VERSION_NUMBER).jre
JDK_MACOSX_CONTENTS_SUBDIR = $(JDK_MACOSX_BUNDLE_TOP_SUBDIR)/Contents
JRE_MACOSX_CONTENTS_SUBDIR = $(JRE_MACOSX_BUNDLE_TOP_SUBDIR)/Contents
JDK_MACOSX_CONTENTS_DIR = $(JDK_MACOSX_BUNDLE_DIR)/$(JDK_MACOSX_CONTENTS_SUBDIR)
JRE_MACOSX_CONTENTS_DIR = $(JRE_MACOSX_BUNDLE_DIR)/$(JRE_MACOSX_CONTENTS_SUBDIR)
JDK_MACOSX_BUNDLE_TOP_DIR = $(JDK_MACOSX_BUNDLE_DIR)/$(JDK_MACOSX_BUNDLE_TOP_SUBDIR)
JRE_MACOSX_BUNDLE_TOP_DIR = $(JRE_MACOSX_BUNDLE_DIR)/$(JRE_MACOSX_BUNDLE_TOP_SUBDIR)
# Bundle names
ifneq ($(VERSION_BUILD), )

View File

@ -276,9 +276,6 @@ AC_DEFUN_ONCE([TOOLCHAIN_PRE_DETECTION],
ORG_CFLAGS="$CFLAGS"
ORG_CXXFLAGS="$CXXFLAGS"
# autoconf magic only relies on PATH, so update it if tools dir is specified
OLD_PATH="$PATH"
if test "x$OPENJDK_BUILD_OS" = "xmacosx"; then
if test "x$XCODEBUILD" != x; then
XCODE_VERSION_OUTPUT=`"$XCODEBUILD" -version 2> /dev/null | $HEAD -n 1`
@ -300,9 +297,10 @@ AC_DEFUN_ONCE([TOOLCHAIN_PRE_DETECTION],
fi
AC_SUBST(TOOLCHAIN_VERSION)
# Finally prepend TOOLCHAIN_PATH to the PATH, to allow --with-tools-dir to
# override all other locations.
if test "x$TOOLCHAIN_PATH" != x; then
# For the microsoft toolchain the toolchain path needs to be added to the
# normal path, or the compiler will not work in some situations in later
# configure checks.
if test "x$TOOLCHAIN_TYPE" = "xmicrosoft" && test "x$TOOLCHAIN_PATH" != x; then
export PATH=$TOOLCHAIN_PATH:$PATH
fi
])
@ -310,13 +308,6 @@ AC_DEFUN_ONCE([TOOLCHAIN_PRE_DETECTION],
# Restore path, etc
AC_DEFUN_ONCE([TOOLCHAIN_POST_DETECTION],
[
# Restore old path, except for the microsoft toolchain, which requires the
# toolchain path to remain in place. Otherwise the compiler will not work in
# some situations in later configure checks.
if test "x$TOOLCHAIN_TYPE" != "xmicrosoft"; then
PATH="$OLD_PATH"
fi
# Restore the flags to the user specified values.
# This is necessary since AC_PROG_CC defaults CFLAGS to "-g -O2"
CFLAGS="$ORG_CFLAGS"

View File

@ -458,17 +458,18 @@ AC_DEFUN([UTIL_LOOKUP_PROGS],
################################################################################
# Call UTIL_SETUP_TOOL with AC_CHECK_TOOLS to locate the tool. This will look
# first for cross-compilation tools.
# first for tools using the cross-compilation prefix, and then for tools without
# this prefix. For each of these name variants, it will look first in the
# toolchain path, and then in the normal path.
# $1: variable to set
# $2: executable name (or list of names) to look for
# $3: [path]
AC_DEFUN([UTIL_LOOKUP_TOOLCHAIN_PROGS],
[
if test "x$ac_tool_prefix" = x; then
UTIL_LOOKUP_PROGS($1, $2, $3)
UTIL_LOOKUP_PROGS($1, $2, [$TOOLCHAIN_PATH:$PATH])
else
prefixed_names=$(for name in $2; do echo ${ac_tool_prefix}${name} $name; done)
UTIL_LOOKUP_PROGS($1, $prefixed_names, $3)
UTIL_LOOKUP_PROGS($1, $prefixed_names, [$TOOLCHAIN_PATH:$PATH])
fi
])
@ -497,10 +498,9 @@ AC_DEFUN([UTIL_REQUIRE_PROGS],
# Like UTIL_LOOKUP_PROGS but fails if no tool was found.
# $1: variable to set
# $2: executable name (or list of names) to look for
# $3: [path]
AC_DEFUN([UTIL_REQUIRE_TOOLCHAIN_PROGS],
[
UTIL_LOOKUP_TOOLCHAIN_PROGS($1, $2, $3)
UTIL_LOOKUP_TOOLCHAIN_PROGS($1, $2)
UTIL_CHECK_NONEMPTY($1)
])

View File

@ -45,6 +45,9 @@ ifeq ($(INCLUDE), true)
# e.g. a simple sed replacement on the input file. If the operations are
# unrelated to the main COMMAND, this is not a suitable solution.
#
# Before execution, the current working directory is changed to SUPPORT_DIR.
# This can be overridden with WORKING_DIR.
#
# If your command outputs a variety of files, or if it's really a single file
# but you don't really care about the output from the perspective, you can just
# supply an OUTPUT_DIR. You are supposed to make sure the command creates files
@ -75,9 +78,12 @@ ifeq ($(INCLUDE), true)
# OUTPUT_DIR : The directory that will contain the result from the command
# OUTPUT_FILE : Use this if the command results in a single output file
# SUPPORT_DIR : Where to store generated support files
# WORKING_DIR : Directory to cd to before executing the command
# INFO : Message to display at LOG=info level when running command (optional)
# WARN : Message to display at LOG=warn level when running command (optional)
# DEPS : Dependencies for the execution to take place
# DRYRUN : Set to true to perform everything but executing the command \
# (defaults to false, primarily intended for debugging)
#
# Setup make rules for copying files, with an option to do more complex
@ -133,6 +139,10 @@ define SetupExecuteBody
endif
ifeq ($$($1_WORKING_DIR), )
$1_WORKING_DIR := $$($1_SUPPORT_DIR)
endif
ifeq ($$($1_INFO)$$($1_WARN), )
# If neither info nor warn is provided, add basic info text.
$1_INFO := Running commands for $1
@ -147,14 +157,19 @@ define SetupExecuteBody
ifneq ($$($1_INFO), )
$$(call LogInfo, $$($1_INFO))
endif
$$(call MakeDir, $$($1_SUPPORT_DIR) $$($1_OUTPUT_DIR))
$$(call MakeDir, $$(call EncodeSpace, $$($1_WORKING_DIR)) $$(call EncodeSpace, $$($1_SUPPORT_DIR)) $$(call EncodeSpace, $$($1_OUTPUT_DIR)))
$$(call ExecuteWithLog, $$($1_BASE)_pre, \
$$($1_PRE_COMMAND))
cd $$($1_WORKING_DIR) && $$($1_PRE_COMMAND))
$$(TOUCH) $$@
$$($1_EXEC_RESULT): $$($1_PRE_MARKER)
$$(call ExecuteWithLog, $$($1_BASE)_exec, \
$$($1_COMMAND))
ifneq ($$($1_DRYRUN), true)
$$(call ExecuteWithLog, $$($1_BASE)_exec, \
cd $$($1_WORKING_DIR) && $$($1_COMMAND))
else
$$(call LogWarn, DRYRUN enabled for $1, not actually running command)
$$(TOUCH) $$@
endif
ifeq ($$($1_EXEC_RESULT), $$($1_EXEC_MARKER))
$$(TOUCH) $$@
endif
@ -168,9 +183,14 @@ define SetupExecuteBody
ifneq ($$($1_INFO), )
$$(call LogInfo, $$($1_INFO))
endif
$$(call MakeDir, $$(call EncodeSpace, $$($1_SUPPORT_DIR)) $$(call EncodeSpace, $$($1_OUTPUT_DIR)))
$$(call ExecuteWithLog, $$($1_BASE)_exec, \
$$($1_COMMAND))
$$(call MakeDir, $$(call EncodeSpace, $$($1_WORKING_DIR)) $$(call EncodeSpace, $$($1_SUPPORT_DIR)) $$(call EncodeSpace, $$($1_OUTPUT_DIR)))
ifneq ($$($1_DRYRUN), true)
$$(call ExecuteWithLog, $$($1_BASE)_exec, \
cd $$($1_WORKING_DIR) && $$($1_COMMAND))
else
$$(call LogWarn, DRYRUN enabled for $1, not actually running command)
$$(TOUCH) $$@
endif
ifeq ($$($1_EXEC_RESULT), $$($1_EXEC_MARKER))
$$(TOUCH) $$@
endif
@ -182,7 +202,7 @@ define SetupExecuteBody
$$($1_FINAL_RESULT): $$($1_EXEC_RESULT)
$$(call ExecuteWithLog, $$($1_BASE)_post, \
$$($1_POST_COMMAND))
cd $$($1_WORKING_DIR) && $$($1_POST_COMMAND))
$$(TOUCH) $$@
$1 += $$($1_FINAL_RESULT)

View File

@ -284,6 +284,12 @@ else
LogCmdlines =
endif
# Check if the command line contains redirection, that is <, > or >>,
# and if so, return a value that is interpreted as true in a make $(if)
# construct.
is_redirect = \
$(if $(filter < > >>, $1), true)
################################################################################
# ExecuteWithLog will run a command and log the output appropriately. This is
# meant to be used by commands that do "real" work, like a compilation.
@ -291,21 +297,23 @@ endif
# of the build in case of failure. The command line itself is stored in a file,
# and also logged to stdout if the LOG=cmdlines option has been given.
#
# NOTE: If the command redirects stdout, the caller needs to wrap it in a
# subshell (by adding parentheses around it), otherwise the redirect to the
# subshell tee process will create a race condition where the target file may
# not be fully written when the make recipe is done.
#
# Param 1 - The path to base the name of the log file / command line file on
# Param 2 - The command to run
ExecuteWithLog = \
$(call LogCmdlines, Executing: [$(strip $2)]) \
$(call LogCmdlines, Executing: \
[$(if $(call is_redirect, $2),$(LEFT_PAREN) )$(strip $2)$(if $(call \
is_redirect, $2), $(RIGHT_PAREN))]) \
$(call MakeDir, $(dir $(strip $1)) $(MAKESUPPORT_OUTPUTDIR)/failure-logs) \
$(call WriteFile, $2, $(strip $1).cmdline) \
( $(RM) $(strip $1).log && $(strip $2) > >($(TEE) -a $(strip $1).log) 2> >($(TEE) -a $(strip $1).log >&2) || \
( $(RM) $(strip $1).log && \
$(if $(call is_redirect, $2),$(LEFT_PAREN) )$(strip $2)$(if $(call \
is_redirect, $2), $(RIGHT_PAREN)) \
> >($(TEE) -a $(strip $1).log) 2> >($(TEE) -a $(strip $1).log >&2) || \
( exitcode=$(DOLLAR)? && \
$(CP) $(strip $1).log $(MAKESUPPORT_OUTPUTDIR)/failure-logs/$(subst /,_,$(patsubst $(OUTPUTDIR)/%,%,$(strip $1))).log && \
$(CP) $(strip $1).cmdline $(MAKESUPPORT_OUTPUTDIR)/failure-logs/$(subst /,_,$(patsubst $(OUTPUTDIR)/%,%,$(strip $1))).cmdline && \
$(CP) $(strip $1).log $(MAKESUPPORT_OUTPUTDIR)/failure-logs/$(subst \
/,_,$(patsubst $(OUTPUTDIR)/%,%,$(strip $1))).log && \
$(CP) $(strip $1).cmdline $(MAKESUPPORT_OUTPUTDIR)/failure-logs/$(subst \
/,_,$(patsubst $(OUTPUTDIR)/%,%,$(strip $1))).cmdline && \
exit $(DOLLAR)exitcode ) )
################################################################################

View File

@ -27,10 +27,15 @@
# MakeIncludeEnd.gmk should be included last of all in all include files
################################################################################
# Hook to include the corresponding custom file, if present.
ifneq ($(NO_CUSTOM_EXTENSIONS), true)
CUSTOM_POST_NAME := $(subst .gmk,-post.gmk, $(THIS_INCLUDE))
$(eval $(call IncludeCustomExtension, $(CUSTOM_POST_NAME)))
ifneq ($(INCLUDE_GUARD_$(THIS_INCLUDE)), true)
# This was the first time this file was included. Prevent future inclusion.
INCLUDE_GUARD_$(THIS_INCLUDE) := true
# Hook to include the corresponding custom file, if present.
ifneq ($(NO_CUSTOM_EXTENSIONS), true)
CUSTOM_POST_NAME := $(subst .gmk,-post.gmk, $(THIS_INCLUDE))
$(eval $(call IncludeCustomExtension, $(CUSTOM_POST_NAME)))
endif
endif
# Pop our helper name off the stack

View File

@ -70,7 +70,6 @@ INCLUDE_STACK := $(THIS_INCLUDE) $(INCLUDE_STACK)
# Setup an automatic include guard
ifneq ($(INCLUDE_GUARD_$(THIS_INCLUDE)), true)
INCLUDE_GUARD_$(THIS_INCLUDE) := true
INCLUDE := true
# Hook to include the corresponding custom file, if present.

View File

@ -109,7 +109,7 @@ define ProcessMarkdown
$$(call LogInfo, Post-processing markdown file $2)
$$(call MakeDir, $$(SUPPORT_OUTPUTDIR)/markdown $$($1_$2_TARGET_DIR))
$$(call ExecuteWithLog, $$(SUPPORT_OUTPUTDIR)/markdown/$$($1_$2_MARKER)_post, \
( $$($1_POST_PROCESS) $$($1_$2_PANDOC_OUTPUT) > $$($1_$2_OUTPUT_FILE) ) )
$$($1_POST_PROCESS) $$($1_$2_PANDOC_OUTPUT) > $$($1_$2_OUTPUT_FILE) )
endif
$1 += $$($1_$2_OUTPUT_FILE)

View File

@ -55,6 +55,42 @@ uppercase = \
$(uppercase_result) \
)
lowercase_table := A,a B,b C,c D,d E,e F,f G,g H,h I,i J,j K,k L,l M,m N,n O,o \
P,p Q,q R,r S,s T,t U,u V,v W,w X,x Y,y Z,z
lowercase_internal = \
$(if $(strip $1), $$(subst $(firstword $1), $(call lowercase_internal, \
$(wordlist 2, $(words $1), $1), $2)), $2)
# Convert a string to lower case. Works only on a-z.
# $1 - The string to convert
lowercase = \
$(strip \
$(eval lowercase_result := $(call lowercase_internal, $(lowercase_table), $1)) \
$(lowercase_result) \
)
lowercase_letters := a b c d e f g h i j k l m n o p q r s t u v w x y z
uppercase_letters := A B C D E F G H I J K L M N O P Q R S T U V W X Y Z
titlecase_internal = \
$(strip $(or \
$(strip $(foreach l, $(lowercase_letters) $(uppercase_letters), \
$(if $(filter $l%, $1), \
$(call uppercase, $l)$(call lowercase, $(patsubst $l%,%,$1))))), \
$1))
# Convert a string to Title Case. Works only on a-z.
# $1 - The string to convert
titlecase = \
$(strip $(foreach w, $1, $(call titlecase_internal, $w)))
# Returns the first character of a string. Works only on a-z.
# $1 - The string to extract the first character from
firstchar = \
$(strip $(foreach l, $(lowercase_letters) $(uppercase_letters), \
$(if $(filter $l%, $(firstword $1)), $l)))
################################################################################
# Creates a sequence of increasing numbers (inclusive).
# Param 1 - starting number

View File

@ -0,0 +1,228 @@
#
# Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved.
# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
#
# This code is free software; you can redistribute it and/or modify it
# under the terms of the GNU General Public License version 2 only, as
# published by the Free Software Foundation. Oracle designates this
# particular file as subject to the "Classpath" exception as provided
# by Oracle in the LICENSE file that accompanied this code.
#
# This code is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
# version 2 for more details (a copy is included in the LICENSE file that
# accompanied this code).
#
# You should have received a copy of the GNU General Public License version
# 2 along with this work; if not, write to the Free Software Foundation,
# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
#
# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
# or visit www.oracle.com if you need additional information or have any
# questions.
#
include MakeIncludeStart.gmk
ifeq ($(INCLUDE), true)
################################################################################
# This file defines macros that sets up rules for running the spp.Spp build tool
################################################################################
include Execute.gmk
include $(TOPDIR)/make/ToolsJdk.gmk
NON_BYTE_NUMBER_TYPES := char short int long float double
NUMBER_TYPES := byte $(NON_BYTE_NUMBER_TYPES)
PRIMITIVE_TYPES := boolean $(NUMBER_TYPES)
################################################################################
# The Conv function converts a type given as first argument (as a normal Java
# native type name), into one of several corresponding strings, depending on
# the aspect given in the second argument
#
# The implementation dispatches the call to one of several Conv_<aspect> macros.
#
# arg $1: the type to convert
# arg $2: the aspect to convert for
# arg $3: byte order (only needed for certain aspects)
#
Conv = \
$(strip $(call Conv_$(strip $2),$(strip $1),$(strip $3)))
################################################################################
# Conv_<aspect> implementations
# Return a single letter representing the type (lowercase first letter)
Conv_x = \
$(call firstchar, $1)
# Return capitalized type name
Conv_Type = \
$(call titlecase, $1)
# Return the full descriptive name of the type, e.g. int -> integer
Conv_fulltype = \
$(if $(filter char, $1), \
character, \
$(if $(filter int, $1), \
integer, \
$1 \
) \
)
# Return the capitalized full descriptive name of the type, e.g. int -> Integer
Conv_Fulltype = \
$(call titlecase, $(call Conv_fulltype, $1))
# Return log2 bits per value (0-3)
Conv_LBPV = \
$(if $(filter byte, $1), \
0, \
$(if $(filter char short, $1), \
1, \
$(if $(filter int float, $1), \
2, \
$(if $(filter long double, $1), \
3))))
# Return float or int category
Conv_category = \
$(if $(filter float double, $1), \
floatingPointType, \
integralType \
)
# Return stream information for char
Conv_streams = \
$(if $(filter char, $1), streamableType)
# Return stream type information for char
Conv_streamtype = \
$(if $(filter char, $1), int)
# Return capitalized stream type information for char
Conv_Streamtype = \
$(if $(filter char, $1), Int)
# Return article to use for type in English text
Conv_a = \
$(if $(filter int, $1), an, a)
# Return capitalized article to use for type in English text
Conv_A = \
$(if $(filter int, $1), An, A)
# Return integer type with same size as the type
Conv_memtype = \
$(if $(filter float, $1), int, $(if $(filter double, $1), long, $1))
# Return capitalized integer type with same size as the type
Conv_Memtype = \
$(call titlecase, $(call Conv, $1, memtype))
# Return capitalized full descriptive name for integer type with same size as the type
Conv_FullMemtype = \
$(call Conv, $(call Conv, $1, memtype), Fulltype)
# Return Type or Memtype depending on byte order
# arg $2: BYTE_ORDER
Conv_Swaptype = \
$(if $(filter U, $2), \
$(call Conv, $1, Type), \
$(call Conv, $1, Memtype))
# Return fromBits method name for floating types, depending on byte order
# arg $2: BYTE_ORDER
Conv_fromBits = \
$(if $(filter float double, $1), \
$(if $(filter U, $2), , \
$(call Conv, $1, Type).$(call Conv, $1, memtype)BitsTo$(call Conv, $1, Type)))
# Return toBits method name for floating types, depending on byte order
# arg $2: BYTE_ORDER
Conv_toBits = \
$(if $(filter float double, $1), \
$(if $(filter U, $2), , \
$(call Conv, $1, Type).$1ToRaw$(call Conv, $(call Conv, $1, memtype), Type)Bits))
# Return swap method name, depending on byte order
# arg $2: BYTE_ORDER
Conv_swap = \
$(if $(filter S, $2), Bits.swap)
# Return word describing the number of bytes required by type
Conv_nbytes = \
$(if $(filter 0, $(call Conv, $1, LBPV)), one, \
$(if $(filter 1, $(call Conv, $1, LBPV)), two, \
$(if $(filter 2, $(call Conv, $1, LBPV)), four, \
$(if $(filter 3, $(call Conv, $1, LBPV)), eight))))
# Return word describing the number of bytes required by type, minus one
Conv_nbytesButOne = \
$(if $(filter 0, $(call Conv, $1, LBPV)), zero, \
$(if $(filter 1, $(call Conv, $1, LBPV)), one, \
$(if $(filter 2, $(call Conv, $1, LBPV)), three, \
$(if $(filter 3, $(call Conv, $1, LBPV)), seven))))
################################################################################
# Setup make rules that runs the spp.Spp build tool on an input file.
#
# Parameter 1 is the name of the rule. This name is used as variable prefix,
# and the targets generated are listed in a variable by that name.
#
# Remaining parameters are named arguments. These include:
# BEGIN_END Set to true to exclude everything outside #begin/#end (default: false)
# SUBST_EMPTY_LINES Set to false to not generate empty lines for removed lines (default: true)
# SOURCE_FILE The input file to process (required)
# OUTPUT_FILE The output file (required)
# INFO Override default message to print (optional)
# KEYS One or more keys to control the generation (optional)
# REPLACEMENTS one or more text replacement patterns, using the syntax:
# VAR=VALUE [VAR=VALUE] ...
#
SetupStreamPreProcessing = $(NamedParamsMacroTemplate)
define SetupStreamPreProcessingBody
# Verify arguments
ifeq ($$($1_SOURCE_FILE), )
$$(error Must specify SOURCE_FILE (in $1))
endif
ifeq ($$($1_OUTPUT_FILE), )
$$(error Must specify OUTPUT_FILE (in $1))
endif
$1_COMMAND_LINE :=
ifeq ($$($1_BEGIN_END), true)
$1_COMMAND_LINE += -be
endif
ifeq ($$($1_SUBST_EMPTY_LINES), false)
$1_COMMAND_LINE += -nel
endif
$1_COMMAND_LINE += $$(foreach k, $$($1_KEYS), -K$$k)
$1_COMMAND_LINE += $$(subst $$$$(SPACE), ,$$(foreach d, $$($1_REPLACEMENTS), -D$$d))
$1_COMMAND_LINE += -i$$($1_SOURCE_FILE) -o$$($1_OUTPUT_FILE).tmp
ifeq ($$($1_INFO), )
$1_INFO := Preprocessing $$(notdir $$($1_SOURCE_FILE)) for $(MODULE)
endif
$$(eval $$(call SetupExecute, RUN_SPP_$1, \
INFO := $$($1_INFO), \
DEPS := $$($1_SOURCE_FILE) $$(BUILD_TOOLS_JDK), \
OUTPUT_FILE := $$($1_OUTPUT_FILE), \
COMMAND := $$(TOOL_SPP) $$($1_COMMAND_LINE), \
PRE_COMMAND := $$(RM) $$($1_OUTPUT_FILE).tmp $$($1_OUTPUT_FILE), \
POST_COMMAND := $$(MV) $$($1_OUTPUT_FILE).tmp $$($1_OUTPUT_FILE), \
))
$1 += $$(RUN_SPP_$1)
endef
################################################################################
endif # include guard
include MakeIncludeEnd.gmk

View File

@ -155,12 +155,6 @@ define CreateCompiledNativeFileBody
endif
$1_FLAGS := $$($1_FLAGS) -DASSEMBLY_SRC_FILE='"$$($1_REL_ASM_SRC)"' \
-include $(TOPDIR)/make/data/autoheaders/assemblyprefix.h
else ifeq ($(TOOLCHAIN_TYPE), microsoft)
ifeq ($(OPENJDK_TARGET_CPU), aarch64)
$1_NON_ASM_EXTENSION_FLAG :=
else
$1_NON_ASM_EXTENSION_FLAG := "-Ta"
endif
endif
else ifneq ($$(filter %.cpp %.cc %.mm, $$($1_FILENAME)), )
# Compile as a C++ or Objective-C++ file
@ -242,7 +236,7 @@ define CreateCompiledNativeFileBody
# For assembler calls just create empty dependency lists
$$(call ExecuteWithLog, $$@, $$(call MakeCommandRelative, \
$$($1_COMPILER) $$($1_FLAGS) \
$(CC_OUT_OPTION)$$($1_OBJ) $$($1_NON_ASM_EXTENSION_FLAG) $$($1_SRC_FILE))) \
$(CC_OUT_OPTION)$$($1_OBJ) $(AS_NON_ASM_EXTENSION_OPTION) $$($1_SRC_FILE))) \
| $(TR) -d '\r' | $(GREP) -v -e "Assembling:" || test "$$$$?" = "1" ; \
$(ECHO) > $$($1_DEPS_FILE) ; \
$(ECHO) > $$($1_DEPS_TARGETS_FILE)

View File

@ -113,9 +113,10 @@ define CreateDynamicLibraryOrExecutableMicrosoft
$$(CHMOD) +x $$($1_TARGET)
endif
ifneq ($$($1_MANIFEST), )
$$($1_MT) -nologo -manifest $$($1_MANIFEST) \
-identity:"$$($1_NAME).exe, version=$$($1_MANIFEST_VERSION)" \
-outputresource:$$@;#1
$$(call ExecuteWithLog, $$($1_OBJECT_DIR)/$$($1_SAFE_NAME)_run_mt, \
$$($1_MT) -nologo -manifest $$($1_MANIFEST) \
-identity:"$$($1_NAME).exe$$(COMMA) version=$$($1_MANIFEST_VERSION)" \
'-outputresource:$$($1_TARGET);$$(HASH)1')
endif
ifneq ($(SIGNING_HOOK), )
$$(call ExecuteWithLog, $$($1_OBJECT_DIR)/$$($1_SAFE_NAME)_call_signing_hook, \

View File

@ -47,8 +47,9 @@ ifeq ($(call check-jvm-feature, dtrace), true)
$(call LogInfo, Generating dtrace header file $(@F))
$(call MakeDir, $(@D) $(DTRACE_SUPPORT_DIR))
$(call ExecuteWithLog, $(DTRACE_SUPPORT_DIR)/$(@F).d, \
($(CPP) $(DTRACE_CPP_FLAGS) $(SYSROOT_CFLAGS) $< > $(DTRACE_SUPPORT_DIR)/$(@F).d))
$(call ExecuteWithLog, $@, $(DTRACE) $(DTRACE_FLAGS) -h -o $@ -s $(DTRACE_SUPPORT_DIR)/$(@F).d)
$(CPP) $(DTRACE_CPP_FLAGS) $(SYSROOT_CFLAGS) $< > $(DTRACE_SUPPORT_DIR)/$(@F).d)
$(call ExecuteWithLog, $@, \
$(DTRACE) $(DTRACE_FLAGS) -h -o $@ -s $(DTRACE_SUPPORT_DIR)/$(@F).d)
# Process all .d files in DTRACE_SOURCE_DIR. They are:
# hotspot_jni.d hotspot.d hs_private.d

View File

@ -62,13 +62,13 @@ $(eval $(call SetupJdkLibrary, BUILD_GTEST_LIBGTEST, \
DISABLED_WARNINGS_gcc := format-nonliteral maybe-uninitialized undef \
unused-result zero-as-null-pointer-constant, \
DISABLED_WARNINGS_clang := format-nonliteral undef unused-result, \
DISABLED_WARNINGS_microsoft := 4530, \
DEFAULT_CFLAGS := false, \
CFLAGS := $(JVM_CFLAGS) \
-I$(GTEST_FRAMEWORK_SRC)/googletest \
-I$(GTEST_FRAMEWORK_SRC)/googletest/include \
-I$(GTEST_FRAMEWORK_SRC)/googlemock \
-I$(GTEST_FRAMEWORK_SRC)/googlemock/include, \
CFLAGS_windows := -EHsc, \
CFLAGS_macosx := -DGTEST_OS_MAC=1, \
OPTIMIZATION := $(JVM_OPTIMIZATION), \
COPY_DEBUG_SYMBOLS := $(GTEST_COPY_DEBUG_SYMBOLS), \
@ -98,7 +98,6 @@ $(eval $(call SetupJdkLibrary, BUILD_GTEST_LIBJVM, \
-I$(GTEST_FRAMEWORK_SRC)/googletest/include \
-I$(GTEST_FRAMEWORK_SRC)/googlemock/include \
$(addprefix -I, $(GTEST_TEST_SRC)), \
CFLAGS_windows := -EHsc, \
CFLAGS_macosx := -DGTEST_OS_MAC=1, \
DISABLED_WARNINGS_gcc := $(DISABLED_WARNINGS_gcc) \
undef stringop-overflow, \
@ -110,7 +109,7 @@ $(eval $(call SetupJdkLibrary, BUILD_GTEST_LIBJVM, \
self-assign-overloaded, \
DISABLED_WARNINGS_clang_test_g1ServiceThread.cpp := delete-abstract-non-virtual-dtor, \
DISABLED_WARNINGS_clang_test_logDecorations.cpp := missing-field-initializers, \
DISABLED_WARNINGS_microsoft := $(DISABLED_WARNINGS_microsoft), \
DISABLED_WARNINGS_microsoft := $(DISABLED_WARNINGS_microsoft) 4530, \
LD_SET_ORIGIN := false, \
DEFAULT_LDFLAGS := false, \
LDFLAGS := $(JVM_LDFLAGS), \

View File

@ -97,11 +97,13 @@ CFLAGS_VM_VERSION := \
DISABLED_WARNINGS_gcc := array-bounds comment delete-non-virtual-dtor \
empty-body format-zero-length implicit-fallthrough int-in-bool-context \
invalid-offsetof \
maybe-uninitialized missing-field-initializers \
shift-negative-value unknown-pragmas unused-but-set-variable \
unused-local-typedefs unused-variable
DISABLED_WARNINGS_clang := delete-non-abstract-non-virtual-dtor missing-braces \
DISABLED_WARNINGS_clang := delete-non-abstract-non-virtual-dtor \
invalid-offsetof missing-braces \
sometimes-uninitialized unknown-pragmas unused-but-set-variable \
unused-function unused-local-typedef unused-private-field unused-variable

View File

@ -1,7 +1,7 @@
// Configure cpptools IntelliSense
"C_Cpp.intelliSenseCachePath": "{{OUTPUTDIR}}/.vscode",
"C_Cpp.default.compileCommands": "{{OUTPUTDIR}}/compile_commands.json",
"C_Cpp.default.cppStandard": "c++14",
"C_Cpp.default.cppStandard": "c++17",
"C_Cpp.default.compilerPath": "{{COMPILER}}",
// Configure ccls

View File

@ -1,7 +1,7 @@
// Configure cpptools IntelliSense
"C_Cpp.intelliSenseCachePath": "{{OUTPUTDIR}}/.vscode",
"C_Cpp.default.compileCommands": "{{OUTPUTDIR}}/compile_commands.json",
"C_Cpp.default.cppStandard": "c++14",
"C_Cpp.default.cppStandard": "c++17",
"C_Cpp.default.compilerPath": "{{COMPILER}}",
// Configure clangd

View File

@ -1,5 +1,5 @@
// Configure cpptools IntelliSense
"C_Cpp.intelliSenseCachePath": "{{OUTPUTDIR}}/.vscode",
"C_Cpp.default.compileCommands": "{{OUTPUTDIR}}/compile_commands.json",
"C_Cpp.default.cppStandard": "c++14",
"C_Cpp.default.cppStandard": "c++17",
"C_Cpp.default.compilerPath": "{{COMPILER}}",

View File

@ -1,7 +1,7 @@
// Configure cpptools IntelliSense
"C_Cpp.intelliSenseCachePath": "{{OUTPUTDIR}}/.vscode",
"C_Cpp.default.compileCommands": "{{OUTPUTDIR}}/compile_commands.json",
"C_Cpp.default.cppStandard": "c++14",
"C_Cpp.default.cppStandard": "c++17",
"C_Cpp.default.compilerPath": "{{COMPILER}}",
// Configure RTags

View File

@ -79,6 +79,7 @@ class Bundle {
"NumberElements/nan",
"NumberElements/currencyDecimal",
"NumberElements/currencyGroup",
"NumberElements/lenientMinusSigns",
};
private static final String[] TIME_PATTERN_KEYS = {

View File

@ -844,6 +844,26 @@ class LDMLParseHandler extends AbstractLDMLHandler<Object> {
});
break;
// Lenient parsing
case "parseLenients":
if ("lenient".equals(attributes.getValue("level"))) {
pushKeyContainer(qName, attributes, attributes.getValue("scope"));
} else {
pushIgnoredContainer(qName);
}
break;
case "parseLenient":
// Use only the lenient minus sign for now
if (currentContainer instanceof KeyContainer kc
&& kc.getKey().equals("number")
&& attributes.getValue("sample").equals("-")) {
pushStringEntry(qName, attributes, currentNumberingSystem + "NumberElements/lenientMinusSigns");
} else {
pushIgnoredContainer(qName);
}
break;
default:
// treat anything else as a container
pushContainer(qName, attributes);
@ -1150,6 +1170,14 @@ class LDMLParseHandler extends AbstractLDMLHandler<Object> {
currentStyle = "";
putIfEntry();
break;
case "parseLenient":
if (currentContainer instanceof StringEntry se) {
// Convert to a simple concatenation of lenient minuses
// e.g. "[\--﹣ −⁻₋ ]" -> "--﹣‐‑‒–−⁻₋➖" for the root locale
put(se.getKey(), se.getValue().replaceAll("[\\[\\]\\\\ ]", ""));
}
break;
default:
putIfEntry();
}

View File

@ -0,0 +1,325 @@
/*
* Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. 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 build.tools.methodhandle;
import java.io.PrintWriter;
import java.lang.classfile.TypeKind;
import java.lang.invoke.MethodType;
import java.lang.invoke.VarHandle;
import java.lang.reflect.Method;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.StandardOpenOption;
import java.util.ArrayList;
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.Stream;
/**
* A helper program to generate the VarHandleGuards class with a set of
* static guard methods each of which corresponds to a particular shape and
* performs a type check of the symbolic type descriptor with the VarHandle
* type descriptor before linking/invoking to the underlying operation as
* characterized by the operation member name on the VarForm of the
* VarHandle.
* <p>
* The generated class essentially encapsulates pre-compiled LambdaForms,
* one for each method, for the most common set of method signatures.
* This reduces static initialization costs, footprint costs, and circular
* dependencies that may arise if a class is generated per LambdaForm.
* <p>
* A maximum of L*T*S methods will be generated where L is the number of
* access modes kinds (or unique operation signatures) and T is the number
* of variable types and S is the number of shapes (such as instance field,
* static field, or array access).
* If there are 4 unique operation signatures, 5 basic types (Object, int,
* long, float, double), and 3 shapes then a maximum of 60 methods will be
* generated. However, the number is likely to be less since there may
* be duplicate signatures.
* <p>
* Each method is annotated with @LambdaForm.Compiled to inform the runtime
* that such methods should be treated as if a method of a class that is the
* result of compiling a LambdaForm. Annotation of such methods is
* important for correct evaluation of certain assertions and method return
* type profiling in HotSpot.
*
* @see java.lang.invoke.GenerateJLIClassesHelper
*/
public final class VarHandleGuardMethodGenerator {
static final String CLASS_HEADER = """
/*
* Copyright (c) 2014, 2025, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* 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.invoke;
import jdk.internal.vm.annotation.AOTSafeClassInitializer;
import jdk.internal.vm.annotation.ForceInline;
import jdk.internal.vm.annotation.Hidden;
// This file is generated by build.tools.methodhandle.VarHandleGuardMethodGenerator.
// Do not edit!
@AOTSafeClassInitializer
final class VarHandleGuards {
""";
static final String GUARD_METHOD_SIG_TEMPLATE = "<RETURN> <NAME>_<SIGNATURE>(<PARAMS>)";
static final String GUARD_METHOD_TEMPLATE =
"""
@ForceInline
@LambdaForm.Compiled
@Hidden
static final <METHOD> throws Throwable {
boolean direct = handle.checkAccessModeThenIsDirect(ad);
if (direct && handle.vform.methodType_table[ad.type] == ad.symbolicMethodTypeErased) {
<RESULT_ERASED>MethodHandle.linkToStatic(<LINK_TO_STATIC_ARGS>);<RETURN_ERASED>
} else {
MethodHandle mh = handle.getMethodHandle(ad.mode);
<RETURN>mh.asType(ad.symbolicMethodTypeInvoker).invokeBasic(<LINK_TO_INVOKER_ARGS>);
}
}""";
static final String GUARD_METHOD_TEMPLATE_V =
"""
@ForceInline
@LambdaForm.Compiled
@Hidden
static final <METHOD> throws Throwable {
boolean direct = handle.checkAccessModeThenIsDirect(ad);
if (direct && handle.vform.methodType_table[ad.type] == ad.symbolicMethodTypeErased) {
MethodHandle.linkToStatic(<LINK_TO_STATIC_ARGS>);
} else if (direct && handle.vform.getMethodType_V(ad.type) == ad.symbolicMethodTypeErased) {
MethodHandle.linkToStatic(<LINK_TO_STATIC_ARGS>);
} else {
MethodHandle mh = handle.getMethodHandle(ad.mode);
mh.asType(ad.symbolicMethodTypeInvoker).invokeBasic(<LINK_TO_INVOKER_ARGS>);
}
}""";
// A template for deriving the operations
// could be supported by annotating VarHandle directly with the
// operation kind and shape
interface VarHandleTemplate {
Object get();
void set(Object value);
boolean compareAndSet(Object actualValue, Object expectedValue);
Object compareAndExchange(Object actualValue, Object expectedValue);
Object getAndUpdate(Object value);
}
record HandleType(Class<?> receiver, Class<?>... intermediates) {
}
public static void main(String... args) throws Throwable {
if (args.length != 1) {
System.err.println("Usage: java VarHandleGuardMethodGenerator VarHandleGuards.java");
System.exit(1);
}
Path outputFile = Path.of(args[0]);
try (PrintWriter pw = new PrintWriter(Files.newBufferedWriter(
outputFile,
StandardCharsets.UTF_8,
StandardOpenOption.CREATE,
StandardOpenOption.TRUNCATE_EXISTING))) {
print(pw);
}
}
public static void print(PrintWriter pw) {
pw.println(CLASS_HEADER);
// Declare the stream of shapes
List<HandleType> hts = List.of(
// Object->T
new HandleType(Object.class),
// <static>->T
new HandleType(null),
// Array[index]->T
new HandleType(Object.class, int.class),
// MS[base]->T
new HandleType(Object.class, long.class),
// MS[base][offset]->T
new HandleType(Object.class, long.class, long.class)
);
// The 5 JVM calling convention types
List<Class<?>> basicTypes = List.of(Object.class, int.class, long.class, float.class, double.class);
Stream.of(VarHandleTemplate.class.getMethods()).<MethodType>
mapMulti((m, sink) -> {
for (var ht : hts) {
for (var bt : basicTypes) {
sink.accept(generateMethodType(m, ht.receiver, bt, ht.intermediates));
}
}
}).
distinct().
map(VarHandleGuardMethodGenerator::generateMethod).
forEach(pw::println);
pw.println("}");
}
static MethodType generateMethodType(Method m, Class<?> receiver, Class<?> value, Class<?>... intermediates) {
Class<?> returnType = m.getReturnType() == Object.class
? value : m.getReturnType();
List<Class<?>> params = new ArrayList<>();
if (receiver != null)
params.add(receiver);
Collections.addAll(params, intermediates);
for (var p : m.getParameters()) {
params.add(value);
}
return MethodType.methodType(returnType, params);
}
static String generateMethod(MethodType mt) {
Class<?> returnType = mt.returnType();
var params = new LinkedHashMap<String, String>();
params.put("handle", className(VarHandle.class));
for (int i = 0; i < mt.parameterCount(); i++) {
params.put("arg" + i, className(mt.parameterType(i)));
}
params.put("ad", "VarHandle.AccessDescriptor");
// Generate method signature line
String RETURN = className(returnType);
String NAME = "guard";
String SIGNATURE = getSignature(mt);
String PARAMS = params.entrySet().stream().
map(e -> e.getValue() + " " + e.getKey()).
collect(Collectors.joining(", "));
String METHOD = GUARD_METHOD_SIG_TEMPLATE.
replace("<RETURN>", RETURN).
replace("<NAME>", NAME).
replace("<SIGNATURE>", SIGNATURE).
replace("<PARAMS>", PARAMS);
// Generate method
params.remove("ad");
List<String> LINK_TO_STATIC_ARGS = new ArrayList<>(params.keySet());
LINK_TO_STATIC_ARGS.add("handle.vform.getMemberName(ad.mode)");
List<String> LINK_TO_INVOKER_ARGS = new ArrayList<>(params.keySet());
LINK_TO_INVOKER_ARGS.set(0, LINK_TO_INVOKER_ARGS.get(0) + ".asDirect()");
RETURN = returnType == void.class
? ""
: returnType == Object.class
? "return "
: "return (" + returnType.getName() + ") ";
String RESULT_ERASED = returnType == void.class
? ""
: returnType != Object.class
? "return (" + returnType.getName() + ") "
: "Object r = ";
String RETURN_ERASED = returnType != Object.class
? ""
: "\n return ad.returnType.cast(r);";
String template = returnType == void.class
? GUARD_METHOD_TEMPLATE_V
: GUARD_METHOD_TEMPLATE;
return template.
replace("<METHOD>", METHOD).
replace("<NAME>", NAME).
replaceAll("<RETURN>", RETURN).
replace("<RESULT_ERASED>", RESULT_ERASED).
replace("<RETURN_ERASED>", RETURN_ERASED).
replaceAll("<LINK_TO_STATIC_ARGS>", String.join(", ", LINK_TO_STATIC_ARGS)).
replace("<LINK_TO_INVOKER_ARGS>", String.join(", ", LINK_TO_INVOKER_ARGS))
.indent(4);
}
static String className(Class<?> c) {
String n = c.getCanonicalName();
if (n == null)
throw new IllegalArgumentException("Not representable in source code: " + c);
if (!c.isPrimitive() && c.getPackageName().equals("java.lang")) {
n = n.substring("java.lang.".length());
} else if (c.getPackageName().equals("java.lang.invoke")) {
n = n.substring("java.lang.invoke.".length());
}
return n;
}
static String getSignature(MethodType m) {
StringBuilder sb = new StringBuilder(m.parameterCount() + 1);
for (int i = 0; i < m.parameterCount(); i++) {
Class<?> pt = m.parameterType(i);
sb.append(getCharType(pt));
}
sb.append('_').append(getCharType(m.returnType()));
return sb.toString();
}
static char getCharType(Class<?> pt) {
return TypeKind.from(pt).upperBound().descriptorString().charAt(0);
}
}

View File

@ -26,6 +26,8 @@
################################################################################
include GensrcCommon.gmk
include GensrcProperties.gmk
include GensrcStreamPreProcessing.gmk
include gensrc/GensrcBuffer.gmk
include gensrc/GensrcCharacterData.gmk
@ -71,8 +73,6 @@ TARGETS += $(CLDR_GEN_DONE)
################################################################################
include GensrcProperties.gmk
$(eval $(call SetupCompileProperties, LIST_RESOURCE_BUNDLE, \
SRC_DIRS := $(MODULE_SRC)/share/classes/sun/launcher/resources, \
CLASS := ListResourceBundle, \

View File

@ -28,363 +28,222 @@ ifeq ($(INCLUDE), true)
################################################################################
GENSRC_BUFFER :=
BUFFER_INPUT_DIR := $(MODULE_SRC)/share/classes/java/nio
BUFFER_OUTPUT_DIR := $(SUPPORT_OUTPUTDIR)/gensrc/java.base/java/nio
GENSRC_BUFFER_DST := $(SUPPORT_OUTPUTDIR)/gensrc/java.base/java/nio
################################################################################
# Helper method to setup generation of bin snippets.
# Will add the generated snippet file name to $1_BIN_SNIPPET_FILES.
#
# arg $1: $1 as passed into SetupGenBuffer
# arg $2: type for this bin snippet
define SetupGenBufferBinSnippets
$1_$2_TMP := $$(BUFFER_OUTPUT_DIR)/$1.java.bin-snippet.$2
GENSRC_BUFFER_SRC := $(MODULE_SRC)/share/classes/java/nio
###
$(GENSRC_BUFFER_DST)/_the.buffer.dir:
$(call LogInfo, Generating buffer classes)
$(call MakeDir, $(@D))
$(TOUCH) $@
define fixRw
$1_RW := $2
$1_rwkey := rw
ifeq (R, $2)
$1_rwkey := ro
endif
endef
define typesAndBits
# param 1 target
# param 2 type
# param 3 BO
$1_a := a
$1_A := A
$1_type := $2
ifeq ($2, byte)
$1_x := b
$1_Type := Byte
$1_fulltype := byte
$1_Fulltype := Byte
$1_category := integralType
$1_LBPV := 0
endif
ifeq ($2, char)
$1_x := c
$1_Type := Char
$1_fulltype := character
$1_Fulltype := Character
$1_category := integralType
$1_streams := streamableType
$1_streamtype := int
$1_Streamtype := Int
$1_LBPV := 1
endif
ifeq ($2, short)
$1_x := s
$1_Type := Short
$1_fulltype := short
$1_Fulltype := Short
$1_category := integralType
$1_LBPV := 1
endif
ifeq ($2, int)
$1_a := an
$1_A := An
$1_x := i
$1_Type := Int
$1_fulltype := integer
$1_Fulltype := Integer
$1_category := integralType
$1_LBPV := 2
endif
ifeq ($2, long)
$1_x := l
$1_Type := Long
$1_fulltype := long
$1_Fulltype := Long
$1_category := integralType
$1_LBPV := 3
endif
ifeq ($2, float)
$1_x := f
$1_Type := Float
$1_fulltype := float
$1_Fulltype := Float
$1_category := floatingPointType
$1_LBPV := 2
endif
ifeq ($2, double)
$1_x := d
$1_Type := Double
$1_fulltype := double
$1_Fulltype := Double
$1_category := floatingPointType
$1_LBPV := 3
endif
$1_Swaptype := $$($1_Type)
$1_memtype := $2
$1_Memtype := $$($1_Type)
ifeq ($2, float)
$1_memtype := int
$1_Memtype := Int
ifneq ($3, U)
$1_Swaptype := Int
$1_fromBits := Float.intBitsToFloat
$1_toBits := Float.floatToRawIntBits
endif
endif
ifeq ($2, double)
$1_memtype := long
$1_Memtype := Long
ifneq ($3, U)
$1_Swaptype := Long
$1_fromBits := Double.longBitsToDouble
$1_toBits := Double.doubleToRawLongBits
endif
endif
ifeq ($3, S)
$1_swap := Bits.swap
endif
endef
define genBinOps
# param 1 target
# param 2 type
# param 3 BO
# param 4 RW
# param 5 nbytes
# param 6 nbytesButOne
$(call typesAndBits,$1,$2,$3)
$(call fixRw,$1,$4)
$1_nbytes := $5
$1_nbytesButOne := $6
$1_CMD := $(TOOL_SPP) \
-Dtype=$$($1_type) \
-DType=$$($1_Type) \
-Dfulltype=$$($1_fulltype) \
-Dmemtype=$$($1_memtype) \
-DMemtype=$$($1_Memtype) \
-DfromBits=$$($1_fromBits) \
-DtoBits=$$($1_toBits) \
-DLG_BYTES_PER_VALUE=$$($1_LBPV) \
-DBYTES_PER_VALUE="(1 << $$($1_LBPV))" \
-Dnbytes=$$($1_nbytes) \
-DnbytesButOne=$$($1_nbytesButOne) \
-DRW=$$($1_RW) \
-K$$($1_rwkey) \
-Da=$$($1_a) \
-be
endef
define SetupGenBuffer
# param 1 is for output file
# param 2 is template dependency
# param 3-9 are named args.
# type :=
# BIN :=
# RW := Mutability (R)ead-only (W)ritable
# BO := (U)nswapped/(S)wapped/(L)ittle/(B)ig
#
$(if $3,$1_$(strip $3))
$(if $4,$1_$(strip $4))
$(if $5,$1_$(strip $5))
$(if $6,$1_$(strip $6))
$(if $7,$1_$(strip $7))
$(if $8,$1_$(strip $8))
$(if $9,$1_$(strip $9))
$(if $(10),$1_$(strip $(10)))
$(if $(11),$1_$(strip $(11)))
$(if $(12),$1_$(strip $(12)))
$(if $(13),$1_$(strip $(13)))
$(if $(14),$1_$(strip $(14)))
$(foreach i,3 4 5 6 7 8 9 10 11 12 13 14 15,$(if $($i),$1_$(strip $($i)))$(NEWLINE))
$(call LogSetupMacroEntry,SetupGenBuffer($1),$2,$3,$4,$5,$6,$7,$8,$9,$(10),$(11),$(12),$(13),$(14),$(15))
$(if $(16),$(error Internal makefile error: Too many arguments to SetupGenBuffer, please update GensrcBuffer.gmk))
$(call fixRw,$1,$$($1_RW))
$(call typesAndBits,$1,$$($1_type),$$($1_BO))
$1_DST := $(GENSRC_BUFFER_DST)/$1.java
$1_SRC := $(GENSRC_BUFFER_SRC)/$(strip $2).java.template
$1_SRC_BIN := $(GENSRC_BUFFER_SRC)/$(strip $2)-bin.java.template
$1_DEP := $$($1_SRC)
ifneq ($$($1_BIN), 1)
$1_DEP := $$($1_SRC)
$1_OUT := $$($1_DST)
$1_$2_LBPV := $$(call Conv, $2, LBPV)
ifeq ($$($1_READ_ONLY), true)
$1_$2_RW_KEYS := ro
$1_$2_RW_REPLACEMENT := R
else
$1_DEP += $$($1_SRC) $$($1_SRC_BIN)
$1_OUT := $(GENSRC_BUFFER_DST)/$1.binop.0.java
$1_$2_RW_KEYS := rw
$1_$2_RW_REPLACEMENT :=
endif
ifeq ($$($1_BIN), 1)
$(call genBinOps,$1_char,char,$$($1_BO),$$($1_RW),two,one)
$(call genBinOps,$1_short,short,$$($1_BO),$$($1_RW),two,one)
$(call genBinOps,$1_int,int,$$($1_BO),$$($1_RW),four,three)
$(call genBinOps,$1_long,long,$$($1_BO),$$($1_RW),eight,seven)
$(call genBinOps,$1_float,float,$$($1_BO),$$($1_RW),four,three)
$(call genBinOps,$1_double,double,$$($1_BO),$$($1_RW),eight,seven)
endif
$$($1_DST): $$($1_DEP) $(GENSRC_BUFFER_DST)/_the.buffer.dir
$(RM) $$($1_OUT).tmp
$(TOOL_SPP) -i$$($1_SRC) -o$$($1_OUT).tmp \
-K$$($1_type) \
-K$$($1_category) \
-K$$($1_streams) \
-Dtype=$$($1_type) \
-DType=$$($1_Type) \
-Dfulltype=$$($1_fulltype) \
-DFulltype=$$($1_Fulltype) \
-Dstreamtype=$$($1_streamtype) \
-DStreamtype=$$($1_Streamtype) \
-Dx=$$($1_x) \
-Dmemtype=$$($1_memtype) \
-DMemtype=$$($1_Memtype) \
-DSwaptype=$$($1_Swaptype) \
-DfromBits=$$($1_fromBits) \
-DtoBits=$$($1_toBits) \
-DLG_BYTES_PER_VALUE=$$($1_LBPV) \
-DBYTES_PER_VALUE="(1 << $$($1_LBPV))" \
-DBO=$$($1_BO) \
-Dswap=$$($1_swap) \
-DRW=$$($1_RW) \
-K$$($1_rwkey) \
-Da=$$($1_a) \
-DA=$$($1_A) \
-Kbo$$($1_BO)
$(MV) $$($1_OUT).tmp $$($1_OUT)
# Do the extra bin thing
ifeq ($$($1_BIN), 1)
$(SED) -e '/#BIN/,$$$$d' < $$($1_OUT) > $$($1_DST).tmp
$(RM) $$($1_OUT)
$$($1_char_CMD) -i$$($1_SRC_BIN) -o$$($1_DST).tmp
$$($1_short_CMD) -i$$($1_SRC_BIN) -o$$($1_DST).tmp
$$($1_int_CMD) -i$$($1_SRC_BIN) -o$$($1_DST).tmp
$$($1_long_CMD) -i$$($1_SRC_BIN) -o$$($1_DST).tmp
$$($1_float_CMD) -i$$($1_SRC_BIN) -o$$($1_DST).tmp
$$($1_double_CMD) -i$$($1_SRC_BIN) -o$$($1_DST).tmp
$(ECHO) "}" >> $$($1_DST).tmp
mv $$($1_DST).tmp $$($1_DST)
endif
GENSRC_BUFFER += $$($1_DST)
$$(eval $$(call SetupStreamPreProcessing, GEN_BUFFER_BIN_$1_$2, \
SOURCE_FILE := $$(BUFFER_INPUT_DIR)/$$($1_TEMPLATE)-bin.java.template, \
OUTPUT_FILE := $$($1_$2_TMP), \
INFO := Generating buffer class bin snippets for $1 ($2), \
BEGIN_END := true, \
KEYS := \
$$($1_$2_RW_KEYS), \
REPLACEMENTS := \
type=$2 \
RW=$$($1_$2_RW_REPLACEMENT) \
LG_BYTES_PER_VALUE=$$($1_$2_LBPV) \
BYTES_PER_VALUE="(1$$$$(SPACE)<<$$$$(SPACE)$$($1_$2_LBPV))" \
a=$$(call Conv, $2, a) \
fulltype=$$(call Conv, $2, fulltype) \
memtype=$$(call Conv, $2, memtype) \
Memtype=$$(call Conv, $2, Memtype) \
nbytes=$$(call Conv, $2, nbytes) \
nbytesButOne=$$(call Conv, $2, nbytesButOne) \
Type=$$(call Conv, $2, Type) \
fromBits=$$(call Conv, $2, fromBits, $$($1_BYTE_ORDER)) \
toBits=$$(call Conv, $2, toBits, $$($1_BYTE_ORDER)), \
))
TARGETS += $$(GEN_BUFFER_$1_$2)
$1_BIN_SNIPPET_FILES += $$($1_$2_TMP)
endef
###
X_BUF := X-Buffer
$(eval $(call SetupGenBuffer,ByteBuffer, $(X_BUF), type := byte, BIN := 1))
$(eval $(call SetupGenBuffer,CharBuffer, $(X_BUF), type := char))
$(eval $(call SetupGenBuffer,ShortBuffer, $(X_BUF), type := short))
$(eval $(call SetupGenBuffer,IntBuffer, $(X_BUF), type := int))
$(eval $(call SetupGenBuffer,LongBuffer, $(X_BUF), type := long))
$(eval $(call SetupGenBuffer,FloatBuffer, $(X_BUF), type := float))
$(eval $(call SetupGenBuffer,DoubleBuffer,$(X_BUF), type := double))
# Buffers whose contents are heap-allocated
################################################################################
# Setup make rules that creates a generated buffer class java source file,
# according to specifications provided.
#
HEAP_X_BUF := Heap-X-Buffer
$(eval $(call SetupGenBuffer,HeapByteBuffer, $(HEAP_X_BUF), type := byte))
$(eval $(call SetupGenBuffer,HeapByteBufferR, $(HEAP_X_BUF), type := byte, RW := R))
$(eval $(call SetupGenBuffer,HeapCharBuffer, $(HEAP_X_BUF), type := char))
$(eval $(call SetupGenBuffer,HeapCharBufferR, $(HEAP_X_BUF), type := char, RW := R))
$(eval $(call SetupGenBuffer,HeapShortBuffer, $(HEAP_X_BUF), type := short))
$(eval $(call SetupGenBuffer,HeapShortBufferR, $(HEAP_X_BUF), type := short, RW := R))
$(eval $(call SetupGenBuffer,HeapIntBuffer, $(HEAP_X_BUF), type := int))
$(eval $(call SetupGenBuffer,HeapIntBufferR, $(HEAP_X_BUF), type := int, RW := R))
$(eval $(call SetupGenBuffer,HeapLongBuffer, $(HEAP_X_BUF), type := long))
$(eval $(call SetupGenBuffer,HeapLongBufferR, $(HEAP_X_BUF), type := long, RW := R))
$(eval $(call SetupGenBuffer,HeapFloatBuffer, $(HEAP_X_BUF), type := float))
$(eval $(call SetupGenBuffer,HeapFloatBufferR, $(HEAP_X_BUF), type := float, RW := R))
$(eval $(call SetupGenBuffer,HeapDoubleBuffer, $(HEAP_X_BUF), type := double))
$(eval $(call SetupGenBuffer,HeapDoubleBufferR,$(HEAP_X_BUF), type := double, RW := R))
# Direct byte buffer
# Parameter 1 is the name of the rule. This name is used as variable prefix,
# and the targets generated are listed in a variable by that name. The output
# file name is also based on this.
#
DIRECT_X_BUF := Direct-X-Buffer
$(eval $(call SetupGenBuffer,DirectByteBuffer, $(DIRECT_X_BUF), type := byte, BIN := 1))
$(eval $(call SetupGenBuffer,DirectByteBufferR,$(DIRECT_X_BUF), type := byte, BIN := 1, RW := R))
# Unswapped views of direct byte buffers
# Remaining parameters are named arguments. These include:
# TYPE The native type
# TEMPLATE The base file name of the template to use
# BYTE_ORDER (U)nswapped/(S)wapped/(L)ittle/(B)ig
# READ_ONLY Set to true to generate read-only buffers (default: false)
# GENERATE_BIN Set to true to generate bin snippets (default: false)
#
$(eval $(call SetupGenBuffer,DirectCharBufferU, $(DIRECT_X_BUF), type := char, BO := U))
$(eval $(call SetupGenBuffer,DirectCharBufferRU, $(DIRECT_X_BUF), type := char, RW := R, BO := U))
$(eval $(call SetupGenBuffer,DirectShortBufferU, $(DIRECT_X_BUF), type := short, BO := U))
$(eval $(call SetupGenBuffer,DirectShortBufferRU, $(DIRECT_X_BUF), type := short, RW := R, BO := U))
$(eval $(call SetupGenBuffer,DirectIntBufferU, $(DIRECT_X_BUF), type := int, BO := U))
$(eval $(call SetupGenBuffer,DirectIntBufferRU, $(DIRECT_X_BUF), type := int, RW := R, BO := U))
$(eval $(call SetupGenBuffer,DirectLongBufferU, $(DIRECT_X_BUF), type := long, BO := U))
$(eval $(call SetupGenBuffer,DirectLongBufferRU, $(DIRECT_X_BUF), type := long, RW := R, BO := U))
$(eval $(call SetupGenBuffer,DirectFloatBufferU, $(DIRECT_X_BUF), type := float, BO := U))
$(eval $(call SetupGenBuffer,DirectFloatBufferRU, $(DIRECT_X_BUF), type := float, RW := R, BO := U))
$(eval $(call SetupGenBuffer,DirectDoubleBufferU, $(DIRECT_X_BUF), type := double, BO := U))
$(eval $(call SetupGenBuffer,DirectDoubleBufferRU,$(DIRECT_X_BUF), type := double, RW := R, BO := U))
SetupGenBuffer = $(NamedParamsMacroTemplate)
define SetupGenBufferBody
$1_OUTPUT := $$(BUFFER_OUTPUT_DIR)/$1.java
ifeq ($$($1_GENERATE_BIN), true)
# After generating the buffer class, we need to do further post processing,
# so output to a temporary file
$1_REAL_OUTPUT := $$($1_OUTPUT)
$1_OUTPUT := $$($1_OUTPUT).bin-snippet.tmp
endif
# Swapped views of direct byte buffers
$1_LBPV := $$(call Conv, $$($1_TYPE), LBPV)
ifeq ($$($1_READ_ONLY), true)
$1_RW_KEYS := ro
$1_RW_REPLACEMENT := R
else
$1_RW_KEYS := rw
$1_RW_REPLACEMENT :=
endif
$$(eval $$(call SetupStreamPreProcessing, GEN_BUFFER_$1, \
SOURCE_FILE := $$(BUFFER_INPUT_DIR)/$$($1_TEMPLATE).java.template, \
OUTPUT_FILE := $$($1_OUTPUT), \
INFO := Generating buffer class $1.java, \
KEYS := \
$$($1_TYPE) \
$$($1_RW_KEYS) \
bo$$($1_BYTE_ORDER) \
$$(call Conv, $$($1_TYPE), category) \
$$(call Conv, $$($1_TYPE), streams), \
REPLACEMENTS := \
type=$$($1_TYPE) \
BO=$$($1_BYTE_ORDER) \
RW=$$($1_RW_REPLACEMENT) \
LG_BYTES_PER_VALUE=$$($1_LBPV) \
BYTES_PER_VALUE="(1$$$$(SPACE)<<$$$$(SPACE)$$($1_$2_LBPV))" \
a=$$(call Conv, $$($1_TYPE), a) \
A=$$(call Conv, $$($1_TYPE), A) \
fulltype=$$(call Conv, $$($1_TYPE), fulltype) \
Fulltype=$$(call Conv, $$($1_TYPE), Fulltype) \
memtype=$$(call Conv, $$($1_TYPE), memtype) \
Memtype=$$(call Conv, $$($1_TYPE), Memtype) \
streamtype=$$(call Conv, $$($1_TYPE), streamtype) \
Streamtype=$$(call Conv, $$($1_TYPE), Streamtype) \
Type=$$(call Conv, $$($1_TYPE), Type) \
x=$$(call Conv, $$($1_TYPE), x) \
fromBits=$$(call Conv, $$($1_TYPE), fromBits, $$($1_BYTE_ORDER)) \
toBits=$$(call Conv, $$($1_TYPE), toBits, $$($1_BYTE_ORDER)) \
swap=$$(call Conv, $$($1_TYPE), swap, $$($1_BYTE_ORDER)) \
Swaptype=$$(call Conv, $$($1_TYPE), Swaptype, $$($1_BYTE_ORDER)), \
))
TARGETS += $$(GEN_BUFFER_$1)
$1 += $$(GEN_BUFFER_$1)
ifeq ($$($1_GENERATE_BIN), true)
# Setup generation of snippet files, one for each non-byte type. This will
# populate $1_BIN_SNIPPET_FILES.
$1_BIN_SNIPPET_FILES :=
$$(foreach t, $$(NON_BYTE_NUMBER_TYPES), \
$$(eval $$(call SetupGenBufferBinSnippets,$1,$$t)) \
)
# Inject these snippets in the file generated by GEN_BUFFER_$1
$$($1_REAL_OUTPUT): $$($1_OUTPUT) $$($1_BIN_SNIPPET_FILES)
$$(call LogInfo, Concatenating buffer class bin snippets for $1)
# Delete everything from the line containing #BIN and below
$$(SED) -e '/#BIN/,$$$$d' < $$($1_OUTPUT) > $$($1_REAL_OUTPUT).tmp
$$(CAT) $$($1_BIN_SNIPPET_FILES) >> $$($1_REAL_OUTPUT).tmp
$$(ECHO) "}" >> $$($1_REAL_OUTPUT).tmp
$$(MV) $$($1_REAL_OUTPUT).tmp $$($1_REAL_OUTPUT)
TARGETS += $$($1_REAL_OUTPUT)
$1 += $$($1_REAL_OUTPUT)
endif
endef
################################################################################
# Helper method to setup generation of all buffer classes, for a given
# modifiability state (read-only or not)
#
$(eval $(call SetupGenBuffer,DirectCharBufferS, $(DIRECT_X_BUF), type := char, BO := S))
$(eval $(call SetupGenBuffer,DirectCharBufferRS, $(DIRECT_X_BUF), type := char, RW := R, BO := S))
$(eval $(call SetupGenBuffer,DirectShortBufferS, $(DIRECT_X_BUF), type := short, BO := S))
$(eval $(call SetupGenBuffer,DirectShortBufferRS, $(DIRECT_X_BUF), type := short, RW := R, BO := S))
$(eval $(call SetupGenBuffer,DirectIntBufferS, $(DIRECT_X_BUF), type := int, BO := S))
$(eval $(call SetupGenBuffer,DirectIntBufferRS, $(DIRECT_X_BUF), type := int, RW := R, BO := S))
$(eval $(call SetupGenBuffer,DirectLongBufferS, $(DIRECT_X_BUF), type := long, BO := S))
$(eval $(call SetupGenBuffer,DirectLongBufferRS, $(DIRECT_X_BUF), type := long, RW := R, BO := S))
$(eval $(call SetupGenBuffer,DirectFloatBufferS, $(DIRECT_X_BUF), type := float, BO := S))
$(eval $(call SetupGenBuffer,DirectFloatBufferRS, $(DIRECT_X_BUF), type := float, RW := R, BO := S))
$(eval $(call SetupGenBuffer,DirectDoubleBufferS, $(DIRECT_X_BUF), type := double, BO := S))
$(eval $(call SetupGenBuffer,DirectDoubleBufferRS,$(DIRECT_X_BUF), type := double, RW := R, BO := S))
# arg $1: READ_ONLY argument, true or false
# arg $2: Modifiability marker for class name (R or empty)
define SetupGenerateBuffersWithRO
ifeq ($1, false)
# The basic buffer classes are not generated in READ_ONLY versions
$$(eval $$(call SetupGenBuffer, ByteBuffer, \
TYPE := byte, \
TEMPLATE := X-Buffer, \
GENERATE_BIN := true, \
))
TARGETS += $$(ByteBuffer)
# Big-endian views of byte buffers
#
BYTE_X_BUF := ByteBufferAs-X-Buffer
$$(foreach t, $$(NON_BYTE_NUMBER_TYPES), \
$$(eval $$(call SetupGenBuffer, $$(call titlecase, $$t)Buffer, \
TYPE := $$t, \
TEMPLATE := X-Buffer, \
)) \
$$(eval TARGETS += $$($$(call titlecase, $$t)Buffer)) \
)
endif
$(eval $(call SetupGenBuffer,ByteBufferAsCharBufferB, $(BYTE_X_BUF), type := char, BO := B))
$(eval $(call SetupGenBuffer,ByteBufferAsCharBufferRB, $(BYTE_X_BUF), type := char, RW := R, BO := B))
$(eval $(call SetupGenBuffer,ByteBufferAsShortBufferB, $(BYTE_X_BUF), type := short, BO := B))
$(eval $(call SetupGenBuffer,ByteBufferAsShortBufferRB, $(BYTE_X_BUF), type := short, RW := R, BO := B))
$(eval $(call SetupGenBuffer,ByteBufferAsIntBufferB, $(BYTE_X_BUF), type := int, BO := B))
$(eval $(call SetupGenBuffer,ByteBufferAsIntBufferRB, $(BYTE_X_BUF), type := int, RW := R, BO := B))
$(eval $(call SetupGenBuffer,ByteBufferAsLongBufferB, $(BYTE_X_BUF), type := long, BO := B))
$(eval $(call SetupGenBuffer,ByteBufferAsLongBufferRB, $(BYTE_X_BUF), type := long, RW := R, BO := B))
$(eval $(call SetupGenBuffer,ByteBufferAsFloatBufferB, $(BYTE_X_BUF), type := float, BO := B))
$(eval $(call SetupGenBuffer,ByteBufferAsFloatBufferRB, $(BYTE_X_BUF), type := float, RW := R, BO := B))
$(eval $(call SetupGenBuffer,ByteBufferAsDoubleBufferB, $(BYTE_X_BUF), type := double, BO := B))
$(eval $(call SetupGenBuffer,ByteBufferAsDoubleBufferRB,$(BYTE_X_BUF), type := double, RW := R, BO := B))
# Buffers whose contents are heap-allocated, one for every type
$$(foreach t, $$(NUMBER_TYPES), \
$$(eval $$(call SetupGenBuffer, Heap$$(call titlecase, $$t)Buffer$2, \
TYPE := $$t, \
TEMPLATE := Heap-X-Buffer, \
READ_ONLY := $1, \
)) \
$$(eval TARGETS += $$(Heap$$(call titlecase, $$t)Buffer$2)) \
)
# Little-endian views of byte buffers
#
$(eval $(call SetupGenBuffer,ByteBufferAsCharBufferL, $(BYTE_X_BUF), type := char, BO := L))
$(eval $(call SetupGenBuffer,ByteBufferAsCharBufferRL, $(BYTE_X_BUF), type := char, RW := R, BO := L))
$(eval $(call SetupGenBuffer,ByteBufferAsShortBufferL, $(BYTE_X_BUF), type := short, BO := L))
$(eval $(call SetupGenBuffer,ByteBufferAsShortBufferRL, $(BYTE_X_BUF), type := short, RW := R, BO := L))
$(eval $(call SetupGenBuffer,ByteBufferAsIntBufferL, $(BYTE_X_BUF), type := int, BO := L))
$(eval $(call SetupGenBuffer,ByteBufferAsIntBufferRL, $(BYTE_X_BUF), type := int, RW := R, BO := L))
$(eval $(call SetupGenBuffer,ByteBufferAsLongBufferL, $(BYTE_X_BUF), type := long, BO := L))
$(eval $(call SetupGenBuffer,ByteBufferAsLongBufferRL, $(BYTE_X_BUF), type := long, RW := R, BO := L))
$(eval $(call SetupGenBuffer,ByteBufferAsFloatBufferL, $(BYTE_X_BUF), type := float, BO := L))
$(eval $(call SetupGenBuffer,ByteBufferAsFloatBufferRL, $(BYTE_X_BUF), type := float, RW := R, BO := L))
$(eval $(call SetupGenBuffer,ByteBufferAsDoubleBufferL, $(BYTE_X_BUF), type := double, BO := L))
$(eval $(call SetupGenBuffer,ByteBufferAsDoubleBufferRL,$(BYTE_X_BUF), type := double, RW := R, BO := L))
# Treat byte special for DirectByteBuffer classes
$$(eval $$(call SetupGenBuffer, DirectByteBuffer$2, \
TEMPLATE := Direct-X-Buffer, \
TYPE := byte, \
GENERATE_BIN := true, \
READ_ONLY := $1, \
))
TARGETS += $$(DirectByteBuffer$2)
###
# Generate Swapped and Unswapped views of the direct byte buffers, each for
# every non-byte type
$$(foreach b, U S, \
$$(foreach t, $$(NON_BYTE_NUMBER_TYPES), \
$$(eval $$(call SetupGenBuffer, Direct$$(call titlecase, $$t)Buffer$2$$b, \
TYPE := $$t, \
TEMPLATE := Direct-X-Buffer, \
BYTE_ORDER := $$b, \
READ_ONLY := $1, \
)) \
$$(eval TARGETS += $$(Direct$$(call titlecase, $$t)Buffer$2$$b)) \
) \
)
$(GENSRC_BUFFER): $(BUILD_TOOLS_JDK)
# Generate Big and Little endian views of the direct byte buffers, each for
# every non-byte type
$$(foreach b, B L, \
$$(foreach t, $$(NON_BYTE_NUMBER_TYPES), \
$$(eval $$(call SetupGenBuffer, ByteBufferAs$$(call titlecase, $$t)Buffer$2$$b, \
TYPE := $$t, \
TEMPLATE := ByteBufferAs-X-Buffer, \
BYTE_ORDER := $$b, \
READ_ONLY := $1, \
)) \
$$(eval TARGETS += $$(ByteBufferAs$$(call titlecase, $$t)Buffer$2$$b)) \
) \
)
endef
TARGETS += $(GENSRC_BUFFER)
################################################################################
# Generate buffers in both read-write and read-only variants for all buffers
$(eval $(call SetupGenerateBuffersWithRO,false,))
$(eval $(call SetupGenerateBuffersWithRO,true,R))
################################################################################

View File

@ -28,91 +28,74 @@ ifeq ($(INCLUDE), true)
################################################################################
GENSRC_CHARSETCODER :=
GENSRC_CHARSETCODER_DST := $(SUPPORT_OUTPUTDIR)/gensrc/java.base/java/nio/charset
GENSRC_CHARSETCODER_SRC := $(MODULE_SRC)/share/classes/java/nio
GENSRC_CHARSETCODER_TEMPLATE := $(GENSRC_CHARSETCODER_SRC)/charset/Charset-X-Coder.java.template
CHARSETCODER_INPUT := $(MODULE_SRC)/share/classes/java/nio/charset/Charset-X-Coder.java.template
CHARSETCODER_OUTPUT_DIR := $(SUPPORT_OUTPUTDIR)/gensrc/java.base/java/nio/charset
################################################################################
$(GENSRC_CHARSETCODER_DST)/CharsetDecoder.java: $(GENSRC_CHARSETCODER_TEMPLATE)
$(call MakeTargetDir)
$(RM) $@.tmp
$(call ExecuteWithLog, $(SUPPORT_OUTPUTDIR)/gensrc/java.base/_charset_decoder, \
$(TOOL_SPP) -i$< -o$@.tmp \
-Kdecoder \
-DA='A' \
-Da='a' \
-DCode='Decode' \
-Dcode='decode' \
-DitypesPhrase='bytes in a specific charset' \
-DotypesPhrase='sixteen-bit Unicode characters' \
-Ditype='byte' \
-Dotype='character' \
-DItype='Byte' \
-DOtype='Char' \
-Dcoder='decoder' \
-DCoder='Decoder' \
-Dcoding='decoding' \
-DOtherCoder='Encoder' \
-DreplTypeName='string' \
-DdefaultRepl='"\\uFFFD"' \
-DdefaultReplName='<code>"\&#92;uFFFD"<\/code>' \
-DreplType='String' \
-DreplFQType='java.lang.String' \
-DreplLength='length()' \
-DItypesPerOtype='CharsPerByte' \
-DnotLegal='not legal for this charset' \
-Dotypes-per-itype='chars-per-byte' \
-DoutSequence='Unicode character')
$(MV) $@.tmp $@
$(eval $(call SetupStreamPreProcessing, GEN_CHARSETDECODER, \
SOURCE_FILE := $(CHARSETCODER_INPUT), \
OUTPUT_FILE := $(CHARSETCODER_OUTPUT_DIR)/CharsetDecoder.java, \
INFO := Generating CharsetDecoder.java, \
KEYS := decoder, \
REPLACEMENTS := \
A='A' \
a='a' \
Code='Decode' \
code='decode' \
itypesPhrase='bytes$$(SPACE)in$$(SPACE)a$$(SPACE)specific$$(SPACE)charset' \
otypesPhrase='sixteen-bit$$(SPACE)Unicode$$(SPACE)characters' \
itype='byte' \
otype='character' \
Itype='Byte' \
Otype='Char' \
coder='decoder' \
Coder='Decoder' \
coding='decoding' \
OtherCoder='Encoder' \
replTypeName='string' \
replType='String' \
replFQType='java.lang.String' \
replLength='length()' \
ItypesPerOtype='CharsPerByte' \
notLegal='not$$(SPACE)legal$$(SPACE)for$$(SPACE)this$$(SPACE)charset' \
otypes-per-itype='chars-per-byte' \
outSequence='Unicode$$(SPACE)character', \
))
GENSRC_CHARSETCODER += $(GENSRC_CHARSETCODER_DST)/CharsetDecoder.java
TARGETS += $(GEN_CHARSETDECODER)
################################################################################
$(eval $(call SetupStreamPreProcessing, GEN_CHARSETENCODER, \
SOURCE_FILE := $(CHARSETCODER_INPUT), \
OUTPUT_FILE := $(CHARSETCODER_OUTPUT_DIR)/CharsetEncoder.java, \
INFO := Generating CharsetEncoder.java, \
KEYS := encoder, \
REPLACEMENTS := \
A='An' \
a='an' \
Code='Encode' \
code='encode' \
itypesPhrase='sixteen-bit$$(SPACE)Unicode$$(SPACE)characters' \
otypesPhrase='bytes$$(SPACE)in$$(SPACE)a$$(SPACE)specific$$(SPACE)charset' \
itype='character' \
otype='byte' \
Itype='Char' \
Otype='Byte' \
coder='encoder' \
Coder='Encoder' \
coding='encoding' \
OtherCoder='Decoder' \
replTypeName='byte$$(SPACE)array' \
replType='byte[]' \
replFQType='byte[]' \
replLength='length' \
ItypesPerOtype='BytesPerChar' \
notLegal='not$$(SPACE)a$$(SPACE)legal$$(SPACE)sixteen-bit$$(SPACE)Unicode$$(SPACE)sequence' \
otypes-per-itype='bytes-per-char' \
outSequence='byte$$(SPACE)sequence$$(SPACE)in$$(SPACE)the$$(SPACE)given$$(SPACE)charset', \
))
$(GENSRC_CHARSETCODER_DST)/CharsetEncoder.java: $(GENSRC_CHARSETCODER_TEMPLATE)
$(call MakeTargetDir)
$(RM) $@.tmp
$(call ExecuteWithLog, $(SUPPORT_OUTPUTDIR)/gensrc/java.base/_charset_encoder, \
$(TOOL_SPP) -i$< -o$@.tmp \
-Kencoder \
-DA='An' \
-Da='an' \
-DCode='Encode' \
-Dcode='encode' \
-DitypesPhrase='sixteen-bit Unicode characters' \
-DotypesPhrase='bytes in a specific charset' \
-Ditype='character' \
-Dotype='byte' \
-DItype='Char' \
-DOtype='Byte' \
-Dcoder='encoder' \
-DCoder='Encoder' \
-Dcoding='encoding' \
-DOtherCoder='Decoder' \
-DreplTypeName='byte array' \
-DdefaultRepl='new byte[] { (byte)'"'"\\?"'"' }' \
-DdefaultReplName='<code>{<\/code>\&nbsp;<code>(byte)'"'"\\?"'"'<\/code>\&nbsp;<code>}<\/code>' \
-DreplType='byte[]' \
-DreplFQType='byte[]' \
-DreplLength='length' \
-DItypesPerOtype='BytesPerChar' \
-DnotLegal='not a legal sixteen-bit Unicode sequence' \
-Dotypes-per-itype='bytes-per-char' \
-DoutSequence='byte sequence in the given charset')
$(MV) $@.tmp $@
GENSRC_CHARSETCODER += $(GENSRC_CHARSETCODER_DST)/CharsetEncoder.java
################################################################################
$(GENSRC_CHARSETCODER): $(BUILD_TOOLS_JDK)
TARGETS += $(GENSRC_CHARSETCODER)
TARGETS += $(GEN_CHARSETENCODER)
################################################################################

View File

@ -28,144 +28,77 @@ ifeq ($(INCLUDE), true)
################################################################################
SCOPED_MEMORY_ACCESS_GENSRC_DIR := $(SUPPORT_OUTPUTDIR)/gensrc/java.base/jdk/internal/misc
SCOPED_MEMORY_ACCESS_SRC_DIR := $(MODULE_SRC)/share/classes/jdk/internal/misc
SCOPED_MEMORY_ACCESS_TEMPLATE := $(SCOPED_MEMORY_ACCESS_SRC_DIR)/X-ScopedMemoryAccess.java.template
SCOPED_MEMORY_ACCESS_BIN_TEMPLATE := $(SCOPED_MEMORY_ACCESS_SRC_DIR)/X-ScopedMemoryAccess-bin.java.template
SCOPED_MEMORY_ACCESS_DEST := $(SCOPED_MEMORY_ACCESS_GENSRC_DIR)/ScopedMemoryAccess.java
SCOPED_INPUT_DIR := $(MODULE_SRC)/share/classes/jdk/internal/misc
SCOPED_INPUT := $(SCOPED_INPUT_DIR)/X-ScopedMemoryAccess.java.template
SCOPED_OUTPUT := $(SUPPORT_OUTPUTDIR)/gensrc/java.base/jdk/internal/misc/ScopedMemoryAccess.java
################################################################################
# Setup a rule for generating the ScopedMemoryAccess java class
# Param 1 - Variable declaration prefix
# Param 2 - Type with first letter capitalized
define GenerateScopedOp
# Helper method to setup generation of scoped snippets.
# Will add the generated snippet file name to SCOPED_SNIPPET_FILES.
#
# arg $1: type for this snippet
define SetupGenScopedSnippets
$1_SCOPED_SNIPPET_FILE := $$(SCOPED_OUTPUT).snippet.$1
$1_Type := $2
ifeq ($$($1_Type), Boolean)
$1_type := boolean
$1_BoxType := $$($1_Type)
$1_rawType := $$($1_type)
$1_RawType := $$($1_Type)
$1_RawBoxType := $$($1_BoxType)
$1_ARGS += -KCAS
$1_KEYS := $1 CAS
ifneq ($$(filter byte, $1),)
$1_KEYS += byte
endif
ifneq ($$(filter float double, $1),)
$1_KEYS += floatingPoint
endif
ifneq ($$(filter char short int long, $1),)
$1_KEYS += Unaligned
endif
ifneq ($$(filter boolean byte char short, $1),)
$1_KEYS += ShorterThanInt
endif
ifeq ($$(filter boolean, $1),)
$1_KEYS += AtomicAdd
endif
ifeq ($$(filter float double, $1),)
$1_KEYS += Bitwise
endif
ifeq ($$($1_Type), Byte)
$1_type := byte
$1_BoxType := $$($1_Type)
$$(eval $$(call SetupStreamPreProcessing, GEN_SCOPED_SNIPPET_$1, \
SOURCE_FILE := $$(SCOPED_INPUT_DIR)/X-ScopedMemoryAccess-bin.java.template, \
OUTPUT_FILE := $$($1_SCOPED_SNIPPET_FILE), \
INFO := Generating snippets for ScopedMemoryAccess ($1), \
SUBST_EMPTY_LINES := false, \
KEYS := $$($1_KEYS), \
REPLACEMENTS := \
type=$1 \
Type=$$(call Conv, $1, Type), \
))
TARGETS += $$(GEN_SCOPED_SNIPPET_$1)
$1_rawType := $$($1_type)
$1_RawType := $$($1_Type)
$1_RawBoxType := $$($1_BoxType)
$1_ARGS += -KCAS
$1_ARGS += -Kbyte
endif
ifeq ($$($1_Type), Short)
$1_type := short
$1_BoxType := $$($1_Type)
$1_rawType := $$($1_type)
$1_RawType := $$($1_Type)
$1_RawBoxType := $$($1_BoxType)
$1_ARGS += -KCAS
$1_ARGS += -KUnaligned
endif
ifeq ($$($1_Type), Char)
$1_type := char
$1_BoxType := Character
$1_rawType := $$($1_type)
$1_RawType := $$($1_Type)
$1_RawBoxType := $$($1_BoxType)
$1_ARGS += -KCAS
$1_ARGS += -KUnaligned
endif
ifeq ($$($1_Type), Int)
$1_type := int
$1_BoxType := Integer
$1_rawType := $$($1_type)
$1_RawType := $$($1_Type)
$1_RawBoxType := $$($1_BoxType)
$1_ARGS += -KCAS
$1_ARGS += -KUnaligned
endif
ifeq ($$($1_Type), Long)
$1_type := long
$1_BoxType := $$($1_Type)
$1_rawType := $$($1_type)
$1_RawType := $$($1_Type)
$1_RawBoxType := $$($1_BoxType)
$1_ARGS += -KCAS
$1_ARGS += -KUnaligned
endif
ifeq ($$($1_Type), Float)
$1_type := float
$1_BoxType := $$($1_Type)
$1_rawType := int
$1_RawType := Int
$1_RawBoxType := Integer
$1_ARGS += -KCAS
$1_ARGS += -KfloatingPoint
endif
ifeq ($$($1_Type), Double)
$1_type := double
$1_BoxType := $$($1_Type)
$1_rawType := long
$1_RawType := Long
$1_RawBoxType := Long
$1_ARGS += -KCAS
$1_ARGS += -KfloatingPoint
endif
ifneq ($$(findstring $$($1_Type), Byte Short Char Int Long Float Double), )
$1_ARGS += -KAtomicAdd
endif
ifneq ($$(findstring $$($1_Type), Boolean Byte Short Char Int Long), )
$1_ARGS += -KBitwise
endif
ifneq ($$(findstring $$($1_Type), Boolean Byte Short Char), )
$1_ARGS += -KShorterThanInt
endif
SCOPED_SNIPPET_FILES += $$($1_SCOPED_SNIPPET_FILE)
endef
################################################################################
# Setup a rule for generating the ScopedMemoryAccess java class
# Setup generation of snippet files, one for each primitive type. This will
# populate SCOPED_SNIPPET_FILES.
SCOPE_MEMORY_ACCESS_TYPES := Boolean Byte Short Char Int Long Float Double
$(foreach t, $(SCOPE_MEMORY_ACCESS_TYPES), \
$(eval $(call GenerateScopedOp,BIN_$t,$t)))
# SCOPED_TYPES is identical to PRIMITIVE_TYPES, but with a slightly different
# order. Keep the original SCOPED_TYPES order for now to not change the
# generated file.
SCOPED_TYPES := boolean byte short char int long float double
$(SCOPED_MEMORY_ACCESS_DEST): $(BUILD_TOOLS_JDK) $(SCOPED_MEMORY_ACCESS_TEMPLATE) $(SCOPED_MEMORY_ACCESS_BIN_TEMPLATE)
$(call MakeDir, $(SCOPED_MEMORY_ACCESS_GENSRC_DIR))
$(CAT) $(SCOPED_MEMORY_ACCESS_TEMPLATE) > $(SCOPED_MEMORY_ACCESS_DEST)
$(foreach t, $(SCOPE_MEMORY_ACCESS_TYPES), \
$(TOOL_SPP) -nel -K$(BIN_$t_type) -Dtype=$(BIN_$t_type) -DType=$(BIN_$t_Type) $(BIN_$t_ARGS) \
-i$(SCOPED_MEMORY_ACCESS_BIN_TEMPLATE) -o$(SCOPED_MEMORY_ACCESS_DEST) ;)
$(ECHO) "}" >> $(SCOPED_MEMORY_ACCESS_DEST)
SCOPED_SNIPPET_FILES :=
$(foreach t, $(SCOPED_TYPES), \
$(eval $(call SetupGenScopedSnippets,$t)) \
)
TARGETS += $(SCOPED_MEMORY_ACCESS_DEST)
# Setup a rule for generating the ScopedMemoryAccess java class by incorporating
# those snippets
$(SCOPED_OUTPUT): $(SCOPED_INPUT) $(SCOPED_SNIPPET_FILES)
$(call LogInfo, Concatenating snippets for ScopedMemoryAccess.java)
$(CAT) $(SCOPED_INPUT) > $(SCOPED_OUTPUT).tmp
$(CAT) $(SCOPED_SNIPPET_FILES) >> $(SCOPED_OUTPUT).tmp
$(ECHO) "}" >> $(SCOPED_OUTPUT).tmp
$(MV) $(SCOPED_OUTPUT).tmp $(SCOPED_OUTPUT)
TARGETS += $(SCOPED_OUTPUT)
################################################################################

View File

@ -28,277 +28,144 @@ ifeq ($(INCLUDE), true)
################################################################################
GENSRC_VARHANDLES :=
VARHANDLES_GENSRC_DIR := $(SUPPORT_OUTPUTDIR)/gensrc/java.base/java/lang/invoke
VARHANDLES_SRC_DIR := $(MODULE_SRC)/share/classes/java/lang/invoke
VARHANDLES_INPUT_DIR := $(MODULE_SRC)/share/classes/java/lang/invoke
VARHANDLES_OUTPUT_DIR := $(SUPPORT_OUTPUTDIR)/gensrc/java.base/java/lang/invoke
################################################################################
# Setup a rule for generating a VarHandle java class
# Param 1 - Variable declaration prefix
# Param 2 - Type with first letter capitalized
#
# arg $1: type for this varhandle
define GenerateVarHandle
VARHANDLE_$1_type := $$(strip $$(if $$(filter reference, $1), Object, $1))
VARHANDLE_$1_Type := $$(call Conv, $1, Type)
$1_Type := $2
$1_FILENAME := $(VARHANDLES_GENSRC_DIR)/VarHandle$$($1_Type)s.java
$1_ARGS += -KCAS
ifneq ($$(findstring $$($1_Type), Byte Short Char Int Long Float Double), )
$1_ARGS += -KAtomicAdd
$1_KEYS := $$(VARHANDLE_$1_type) CAS
ifneq ($$(filter byte short char, $1),)
$1_KEYS += ShorterThanInt
endif
ifeq ($$(filter boolean reference, $1),)
$1_KEYS += AtomicAdd
endif
ifeq ($$(filter float double reference, $1),)
$1_KEYS += Bitwise
endif
ifneq ($$(findstring $$($1_Type), Boolean Byte Short Char Int Long), )
$1_ARGS += -KBitwise
endif
ifneq ($$(findstring $$($1_Type), Byte Short Char), )
$1_ARGS += -KShorterThanInt
endif
$$($1_FILENAME): $(VARHANDLES_SRC_DIR)/X-VarHandle.java.template $(BUILD_TOOLS_JDK)
ifeq ($$($1_Type), Reference)
$$(eval $1_type := Object)
else
$$(eval $1_type := $$$$(shell $(TR) '[:upper:]' '[:lower:]' <<< $$$$($1_Type)))
endif
$$(call MakeDir, $$(@D))
$(RM) $$@
$(TOOL_SPP) -nel -K$$($1_type) -Dtype=$$($1_type) -DType=$$($1_Type) \
$$($1_ARGS) -i$$< -o$$@
GENSRC_VARHANDLES += $$($1_FILENAME)
$$(eval $$(call SetupStreamPreProcessing, GEN_VARHANDLE_$1, \
SOURCE_FILE := $$(VARHANDLES_INPUT_DIR)/X-VarHandle.java.template, \
OUTPUT_FILE := $$(VARHANDLES_OUTPUT_DIR)/VarHandle$$(VARHANDLE_$1_Type)s.java, \
INFO := Generating VarHandle class for $1, \
SUBST_EMPTY_LINES := false, \
KEYS := $$($1_KEYS), \
REPLACEMENTS := \
type=$$(VARHANDLE_$1_type) \
Type=$$(VARHANDLE_$1_Type), \
))
TARGETS += $$(GEN_VARHANDLE_$1)
endef
################################################################################
################################################################################
# Setup a rule for generating a VarHandleByteArray java class
# Param 1 - Variable declaration prefix
# Param 2 - Type with first letter capitalized
#
# arg $1: type for this varhandle
define GenerateVarHandleByteArray
VARHANDLE_BYTEARRAY_$1_Type := $$(call Conv, $1, Type)
$1_Type := $2
$1_FILENAME := $(VARHANDLES_GENSRC_DIR)/VarHandleByteArrayAs$$($1_Type)s.java
ifeq ($$($1_Type), Short)
$1_type := short
$1_BoxType := $$($1_Type)
$1_rawType := $$($1_type)
$1_RawType := $$($1_Type)
$1_RawBoxType := $$($1_BoxType)
$1_KEYS := $1
ifneq ($$(filter int long float double, $1),)
$1_KEYS += CAS
endif
ifneq ($$(filter float double, $1),)
$1_KEYS += floatingPoint
endif
ifneq ($$(filter int long, $1),)
$1_KEYS += AtomicAdd Bitwise
endif
ifeq ($$($1_Type), Char)
$1_type := char
$1_BoxType := Character
$1_rawType := $$($1_type)
$1_RawType := $$($1_Type)
$1_RawBoxType := $$($1_BoxType)
endif
ifeq ($$($1_Type), Int)
$1_type := int
$1_BoxType := Integer
$1_rawType := $$($1_type)
$1_RawType := $$($1_Type)
$1_RawBoxType := $$($1_BoxType)
$1_ARGS += -KCAS
$1_ARGS += -KAtomicAdd
$1_ARGS += -KBitwise
endif
ifeq ($$($1_Type), Long)
$1_type := long
$1_BoxType := $$($1_Type)
$1_rawType := $$($1_type)
$1_RawType := $$($1_Type)
$1_RawBoxType := $$($1_BoxType)
$1_ARGS += -KCAS
$1_ARGS += -KAtomicAdd
$1_ARGS += -KBitwise
endif
ifeq ($$($1_Type), Float)
$1_type := float
$1_BoxType := $$($1_Type)
$1_rawType := int
$1_RawType := Int
$1_RawBoxType := Integer
$1_ARGS += -KCAS
$1_ARGS += -KfloatingPoint
endif
ifeq ($$($1_Type), Double)
$1_type := double
$1_BoxType := $$($1_Type)
$1_rawType := long
$1_RawType := Long
$1_RawBoxType := Long
$1_ARGS += -KCAS
$1_ARGS += -KfloatingPoint
endif
$$($1_FILENAME): $(VARHANDLES_SRC_DIR)/X-VarHandleByteArrayView.java.template $(BUILD_TOOLS_JDK)
$$(call MakeDir, $$(@D))
$(RM) $$@
$(TOOL_SPP) -nel -K$$($1_type) \
-Dtype=$$($1_type) -DType=$$($1_Type) -DBoxType=$$($1_BoxType) \
-DrawType=$$($1_rawType) -DRawType=$$($1_RawType) -DRawBoxType=$$($1_RawBoxType) \
$$($1_ARGS) -i$$< -o$$@
GENSRC_VARHANDLES += $$($1_FILENAME)
$$(eval $$(call SetupStreamPreProcessing, GEN_VARHANDLE_BYTEARRAY_$1, \
SOURCE_FILE := $$(VARHANDLES_INPUT_DIR)/X-VarHandleByteArrayView.java.template, \
OUTPUT_FILE := $$(VARHANDLES_OUTPUT_DIR)/VarHandleByteArrayAs$$(VARHANDLE_BYTEARRAY_$1_Type)s.java, \
INFO := Generating VarHandleByteArray class for $1, \
SUBST_EMPTY_LINES := false, \
KEYS := $$($1_KEYS), \
REPLACEMENTS := \
type=$1 \
Type=$$(VARHANDLE_BYTEARRAY_$1_Type) \
BoxType=$$(call Conv, $1, Fulltype) \
rawType=$$(call Conv, $1, memtype) \
RawType=$$(call Conv, $1, Memtype) \
RawBoxType=$$(call Conv, $1, FullMemtype), \
))
TARGETS += $$(GEN_VARHANDLE_BYTEARRAY_$1)
endef
################################################################################
################################################################################
# Setup a rule for generating a memory segment var handle view class
# Param 1 - Variable declaration prefix
# Param 2 - Type with first letter capitalized
# Setup a rule for generating a VarHandleMemorySegment java class
#
# arg $1: type for this varhandle
define GenerateVarHandleMemorySegment
VARHANDLE_SEGMENT_$1_Type := $$(call Conv, $1, Type)
$1_Type := $2
$1_FILENAME := $(VARHANDLES_GENSRC_DIR)/VarHandleSegmentAs$$($1_Type)s.java
ifeq ($$($1_Type), Boolean)
$1_type := boolean
$1_BoxType := $$($1_Type)
$1_rawType := $$($1_type)
$1_RawType := $$($1_Type)
$1_RawBoxType := $$($1_BoxType)
$1_ARGS += -Kbyte
$1_ARGS += -KShorterThanInt
$1_KEYS := $1
ifneq ($$(filter int long float double, $1),)
$1_KEYS += CAS
endif
ifneq ($$(filter boolean byte, $1),)
$1_KEYS += byte
endif
ifneq ($$(filter float double, $1),)
$1_KEYS += floatingPoint
endif
ifneq ($$(filter boolean byte short char, $1),)
$1_KEYS += ShorterThanInt
endif
ifneq ($$(filter int long, $1),)
$1_KEYS += AtomicAdd Bitwise
endif
ifeq ($$($1_Type), Byte)
$1_type := byte
$1_BoxType := $$($1_Type)
$1_rawType := $$($1_type)
$1_RawType := $$($1_Type)
$1_RawBoxType := $$($1_BoxType)
$1_ARGS += -Kbyte
$1_ARGS += -KShorterThanInt
endif
ifeq ($$($1_Type), Short)
$1_type := short
$1_BoxType := $$($1_Type)
$1_rawType := $$($1_type)
$1_RawType := $$($1_Type)
$1_RawBoxType := $$($1_BoxType)
$1_ARGS += -KShorterThanInt
endif
ifeq ($$($1_Type), Char)
$1_type := char
$1_BoxType := Character
$1_rawType := $$($1_type)
$1_RawType := $$($1_Type)
$1_RawBoxType := $$($1_BoxType)
$1_ARGS += -KShorterThanInt
endif
ifeq ($$($1_Type), Int)
$1_type := int
$1_BoxType := Integer
$1_rawType := $$($1_type)
$1_RawType := $$($1_Type)
$1_RawBoxType := $$($1_BoxType)
$1_ARGS += -KCAS
$1_ARGS += -KAtomicAdd
$1_ARGS += -KBitwise
endif
ifeq ($$($1_Type), Long)
$1_type := long
$1_BoxType := $$($1_Type)
$1_rawType := $$($1_type)
$1_RawType := $$($1_Type)
$1_RawBoxType := $$($1_BoxType)
$1_ARGS += -KCAS
$1_ARGS += -KAtomicAdd
$1_ARGS += -KBitwise
endif
ifeq ($$($1_Type), Float)
$1_type := float
$1_BoxType := $$($1_Type)
$1_rawType := int
$1_RawType := Int
$1_RawBoxType := Integer
$1_ARGS += -KCAS
$1_ARGS += -KfloatingPoint
endif
ifeq ($$($1_Type), Double)
$1_type := double
$1_BoxType := $$($1_Type)
$1_rawType := long
$1_RawType := Long
$1_RawBoxType := Long
$1_ARGS += -KCAS
$1_ARGS += -KfloatingPoint
endif
$$($1_FILENAME): $(VARHANDLES_SRC_DIR)/X-VarHandleSegmentView.java.template $(BUILD_TOOLS_JDK)
$$(call MakeDir, $$(@D))
$(RM) $$@
$(TOOL_SPP) -nel -K$$($1_type) \
-Dtype=$$($1_type) -DType=$$($1_Type) -DBoxType=$$($1_BoxType) \
-DrawType=$$($1_rawType) -DRawType=$$($1_RawType) -DRawBoxType=$$($1_RawBoxType) \
$$($1_ARGS) -i$$< -o$$@
GENSRC_VARHANDLES += $$($1_FILENAME)
$$(eval $$(call SetupStreamPreProcessing, GEN_VARHANDLE_SEGMENT_$1, \
SOURCE_FILE := $$(VARHANDLES_INPUT_DIR)/X-VarHandleSegmentView.java.template, \
OUTPUT_FILE := $$(VARHANDLES_OUTPUT_DIR)/VarHandleSegmentAs$$(VARHANDLE_SEGMENT_$1_Type)s.java, \
INFO := Generating VarHandleSegment class for $1, \
SUBST_EMPTY_LINES := false, \
KEYS := $$($1_KEYS), \
REPLACEMENTS := \
type=$1 \
Type=$$(VARHANDLE_SEGMENT_$1_Type) \
BoxType=$$(call Conv, $1, Fulltype) \
rawType=$$(call Conv, $1, memtype) \
RawType=$$(call Conv, $1, Memtype) \
RawBoxType=$$(call Conv, $1, FullMemtype), \
))
TARGETS += $$(GEN_VARHANDLE_SEGMENT_$1)
endef
################################################################################
# Generate all VarHandle related classes
# List the types to generate source for, with capitalized first letter
VARHANDLES_TYPES := Boolean Byte Short Char Int Long Float Double Reference
$(foreach t, $(VARHANDLES_TYPES), \
$(eval $(call GenerateVarHandle,VAR_HANDLE_$t,$t)))
$(foreach t, $(PRIMITIVE_TYPES) reference, \
$(eval $(call GenerateVarHandle,$t)) \
)
# List the types to generate source for, with capitalized first letter
VARHANDLES_BYTE_ARRAY_TYPES := Short Char Int Long Float Double
$(foreach t, $(VARHANDLES_BYTE_ARRAY_TYPES), \
$(eval $(call GenerateVarHandleByteArray,VAR_HANDLE_BYTE_ARRAY_$t,$t)))
$(foreach t, $(NON_BYTE_NUMBER_TYPES), \
$(eval $(call GenerateVarHandleByteArray,$t)) \
)
# List the types to generate source for, with capitalized first letter
VARHANDLES_MEMORY_SEGMENT_TYPES := Boolean Byte Short Char Int Long Float Double
$(foreach t, $(VARHANDLES_MEMORY_SEGMENT_TYPES), \
$(eval $(call GenerateVarHandleMemorySegment,VAR_HANDLE_MEMORY_SEGMENT_$t,$t)))
$(foreach t, $(PRIMITIVE_TYPES), \
$(eval $(call GenerateVarHandleMemorySegment,$t)) \
)
TARGETS += $(GENSRC_VARHANDLES)
################################################################################
GENSRC_VARHANDLEGUARDS := $(VARHANDLES_OUTPUT_DIR)/VarHandleGuards.java
$(GENSRC_VARHANDLEGUARDS): $(BUILD_TOOLS_JDK)
$(call LogInfo, Generating $@)
$(call MakeTargetDir)
$(TOOL_VARHANDLEGUARDMETHODGENERATOR) \
$(GENSRC_VARHANDLEGUARDS)
TARGETS += $(GENSRC_VARHANDLEGUARDS)
################################################################################

View File

@ -68,7 +68,7 @@ $(eval $(call SetupJdkExecutable, BUILD_JPACKAGEAPPLAUNCHER, \
-rpath @executable_path/../PlugIns/, \
LIBS_macosx := -framework Cocoa, \
LIBS_windows := msi.lib ole32.lib shell32.lib shlwapi.lib user32.lib, \
LIBS_linux := $(LIBDL), \
LIBS_linux := $(LIBDL) $(LIBPTHREAD), \
MANIFEST := $(JAVA_MANIFEST), \
MANIFEST_VERSION := $(VERSION_NUMBER_FOUR_POSITIONS) \
))
@ -97,7 +97,7 @@ ifeq ($(call isTargetOs, linux), true)
DISABLED_WARNINGS_clang_JvmLauncherLib.c := format-nonliteral, \
DISABLED_WARNINGS_clang_tstrings.cpp := format-nonliteral, \
LD_SET_ORIGIN := false, \
LIBS_linux := $(LIBDL), \
LIBS_linux := $(LIBDL) $(LIBPTHREAD), \
))
TARGETS += $(BUILD_LIBJPACKAGEAPPLAUNCHERAUX)

View File

@ -1,36 +0,0 @@
#!/bin/bash
#
# Copyright (c) 2012, 2020, Oracle and/or its affiliates. All rights reserved.
# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
#
# This code is free software; you can redistribute it and/or modify it
# under the terms of the GNU General Public License version 2 only, as
# published by the Free Software Foundation.
#
# This code is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
# version 2 for more details (a copy is included in the LICENSE file that
# accompanied this code).
#
# You should have received a copy of the GNU General Public License version
# 2 along with this work; if not, write to the Free Software Foundation,
# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
#
# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
# or visit www.oracle.com if you need additional information or have any
# questions.
#
GREP=grep
#
EXP="Note: Some input files use or override a deprecated API."
EXP="${EXP}|Note: Recompile with -Xlint:deprecation for details."
EXP="${EXP}|Note: Some input files use unchecked or unsafe operations."
EXP="${EXP}|Note: Recompile with -Xlint:unchecked for details."
EXP="${EXP}| warning"
EXP="${EXP}|uses or overrides a deprecated API."
EXP="${EXP}|uses unchecked or unsafe operations."
#
${GREP} --line-buffered -v -E "${EXP}"

View File

@ -138,6 +138,7 @@ ifneq ($(filter build-test-jdk-jtreg-native, $(MAKECMDGOALS)), )
OUTPUT_DIR := $(BUILD_JDK_JTREG_OUTPUT_DIR), \
EXCLUDE := $(BUILD_JDK_JTREG_EXCLUDE), \
EXTRA_FILES := $(BUILD_JDK_JTREG_EXTRA_FILES), \
LIBS := $(LIBPTHREAD), \
))
endif

View File

@ -4412,10 +4412,9 @@ operand immI8()
%}
// 8 bit signed value (simm8), or #simm8 LSL 8.
operand immI8_shift8()
operand immIDupV()
%{
predicate((n->get_int() <= 127 && n->get_int() >= -128) ||
(n->get_int() <= 32512 && n->get_int() >= -32768 && (n->get_int() & 0xff) == 0));
predicate(Assembler::operand_valid_for_sve_dup_immediate((int64_t)n->get_int()));
match(ConI);
op_cost(0);
@ -4424,10 +4423,9 @@ operand immI8_shift8()
%}
// 8 bit signed value (simm8), or #simm8 LSL 8.
operand immL8_shift8()
operand immLDupV()
%{
predicate((n->get_long() <= 127 && n->get_long() >= -128) ||
(n->get_long() <= 32512 && n->get_long() >= -32768 && (n->get_long() & 0xff) == 0));
predicate(Assembler::operand_valid_for_sve_dup_immediate(n->get_long()));
match(ConL);
op_cost(0);
@ -4435,6 +4433,17 @@ operand immL8_shift8()
interface(CONST_INTER);
%}
// 8 bit signed value (simm8), or #simm8 LSL 8.
operand immHDupV()
%{
predicate(Assembler::operand_valid_for_sve_dup_immediate((int64_t)n->geth()));
match(ConH);
op_cost(0);
format %{ %}
interface(CONST_INTER);
%}
// 8 bit integer valid for vector add sub immediate
operand immBAddSubV()
%{
@ -5956,9 +5965,6 @@ attributes %{
instruction_unit_size = 4; // An instruction is 4 bytes long
instruction_fetch_unit_size = 64; // The processor fetches one line
instruction_fetch_units = 1; // of 64 bytes
// List of nop instructions
nops( MachNop );
%}
// We don't use an actual pipeline model so don't care about resources
@ -7077,18 +7083,16 @@ instruct loadConD(vRegD dst, immD con) %{
%}
// Load Half Float Constant
// The "ldr" instruction loads a 32-bit word from the constant pool into a
// 32-bit register but only the bottom half will be populated and the top
// 16 bits are zero.
instruct loadConH(vRegF dst, immH con) %{
match(Set dst con);
format %{
"ldrs $dst, [$constantaddress]\t# load from constant table: half float=$con\n\t"
%}
format %{ "mov rscratch1, $con\n\t"
"fmov $dst, rscratch1"
%}
ins_encode %{
__ ldrs(as_FloatRegister($dst$$reg), $constantaddress($con));
__ movw(rscratch1, (uint32_t)$con$$constant);
__ fmovs($dst$$FloatRegister, rscratch1);
%}
ins_pipe(fp_load_constant_s);
ins_pipe(pipe_class_default);
%}
// Store Instructions

View File

@ -4875,7 +4875,7 @@ instruct replicateB_imm8_gt128b(vReg dst, immI8 con) %{
ins_pipe(pipe_slow);
%}
instruct replicateI_imm8_gt128b(vReg dst, immI8_shift8 con) %{
instruct replicateI_imm8_gt128b(vReg dst, immIDupV con) %{
predicate(Matcher::vector_length_in_bytes(n) > 16 &&
(Matcher::vector_element_basic_type(n) == T_SHORT ||
Matcher::vector_element_basic_type(n) == T_INT));
@ -4898,7 +4898,7 @@ instruct replicateL_imm_128b(vReg dst, immL con) %{
ins_pipe(pipe_slow);
%}
instruct replicateL_imm8_gt128b(vReg dst, immL8_shift8 con) %{
instruct replicateL_imm8_gt128b(vReg dst, immLDupV con) %{
predicate(Matcher::vector_length_in_bytes(n) > 16);
match(Set dst (Replicate con));
format %{ "replicateL_imm8_gt128b $dst, $con\t# vector > 128 bits" %}
@ -4909,19 +4909,27 @@ instruct replicateL_imm8_gt128b(vReg dst, immL8_shift8 con) %{
ins_pipe(pipe_slow);
%}
// Replicate a 16-bit half precision float value
instruct replicateHF_imm(vReg dst, immH con) %{
// Replicate an immediate 16-bit half precision float value
instruct replicateHF_imm_le128b(vReg dst, immH con) %{
predicate(Matcher::vector_length_in_bytes(n) <= 16);
match(Set dst (Replicate con));
format %{ "replicateHF_imm $dst, $con\t# replicate immediate half-precision float" %}
format %{ "replicateHF_imm_le128b $dst, $con\t# vector <= 128 bits" %}
ins_encode %{
uint length_in_bytes = Matcher::vector_length_in_bytes(this);
int imm = (int)($con$$constant) & 0xffff;
if (VM_Version::use_neon_for_vector(length_in_bytes)) {
__ mov($dst$$FloatRegister, get_arrangement(this), imm);
} else { // length_in_bytes must be > 16 and SVE should be enabled
assert(UseSVE > 0, "must be sve");
__ sve_dup($dst$$FloatRegister, __ H, imm);
}
__ mov($dst$$FloatRegister, get_arrangement(this), imm);
%}
ins_pipe(pipe_slow);
%}
// Replicate a 16-bit half precision float which is within the limits
// for the operand - immHDupV
instruct replicateHF_imm8_gt128b(vReg dst, immHDupV con) %{
predicate(Matcher::vector_length_in_bytes(n) > 16);
match(Set dst (Replicate con));
format %{ "replicateHF_imm8_gt128b $dst, $con\t# vector > 128 bits" %}
ins_encode %{
assert(UseSVE > 0, "must be sve");
__ sve_dup($dst$$FloatRegister, __ H, (int)($con$$constant));
%}
ins_pipe(pipe_slow);
%}

View File

@ -3107,7 +3107,7 @@ instruct replicateB_imm8_gt128b(vReg dst, immI8 con) %{
ins_pipe(pipe_slow);
%}
instruct replicateI_imm8_gt128b(vReg dst, immI8_shift8 con) %{
instruct replicateI_imm8_gt128b(vReg dst, immIDupV con) %{
predicate(Matcher::vector_length_in_bytes(n) > 16 &&
(Matcher::vector_element_basic_type(n) == T_SHORT ||
Matcher::vector_element_basic_type(n) == T_INT));
@ -3130,7 +3130,7 @@ instruct replicateL_imm_128b(vReg dst, immL con) %{
ins_pipe(pipe_slow);
%}
instruct replicateL_imm8_gt128b(vReg dst, immL8_shift8 con) %{
instruct replicateL_imm8_gt128b(vReg dst, immLDupV con) %{
predicate(Matcher::vector_length_in_bytes(n) > 16);
match(Set dst (Replicate con));
format %{ "replicateL_imm8_gt128b $dst, $con\t# vector > 128 bits" %}
@ -3141,19 +3141,27 @@ instruct replicateL_imm8_gt128b(vReg dst, immL8_shift8 con) %{
ins_pipe(pipe_slow);
%}
// Replicate a 16-bit half precision float value
instruct replicateHF_imm(vReg dst, immH con) %{
// Replicate an immediate 16-bit half precision float value
instruct replicateHF_imm_le128b(vReg dst, immH con) %{
predicate(Matcher::vector_length_in_bytes(n) <= 16);
match(Set dst (Replicate con));
format %{ "replicateHF_imm $dst, $con\t# replicate immediate half-precision float" %}
format %{ "replicateHF_imm_le128b $dst, $con\t# vector <= 128 bits" %}
ins_encode %{
uint length_in_bytes = Matcher::vector_length_in_bytes(this);
int imm = (int)($con$$constant) & 0xffff;
if (VM_Version::use_neon_for_vector(length_in_bytes)) {
__ mov($dst$$FloatRegister, get_arrangement(this), imm);
} else { // length_in_bytes must be > 16 and SVE should be enabled
assert(UseSVE > 0, "must be sve");
__ sve_dup($dst$$FloatRegister, __ H, imm);
}
__ mov($dst$$FloatRegister, get_arrangement(this), imm);
%}
ins_pipe(pipe_slow);
%}
// Replicate a 16-bit half precision float which is within the limits
// for the operand - immHDupV
instruct replicateHF_imm8_gt128b(vReg dst, immHDupV con) %{
predicate(Matcher::vector_length_in_bytes(n) > 16);
match(Set dst (Replicate con));
format %{ "replicateHF_imm8_gt128b $dst, $con\t# vector > 128 bits" %}
ins_encode %{
assert(UseSVE > 0, "must be sve");
__ sve_dup($dst$$FloatRegister, __ H, (int)($con$$constant));
%}
ins_pipe(pipe_slow);
%}

View File

@ -434,6 +434,11 @@ int Assembler::operand_valid_for_movi_immediate(uint64_t imm64, SIMD_Arrangement
return -1;
}
bool Assembler::operand_valid_for_sve_dup_immediate(int64_t imm) {
return ((imm >= -128 && imm <= 127) ||
(((imm & 0xff) == 0) && imm >= -32768 && imm <= 32512));
}
bool Assembler::operand_valid_for_sve_logical_immediate(unsigned elembits, uint64_t imm) {
return encode_sve_logical_immediate(elembits, imm) != 0xffffffff;
}

View File

@ -3814,7 +3814,11 @@ private:
starti;
assert(T != Q, "invalid size");
int sh = 0;
if (imm8 <= 127 && imm8 >= -128) {
if (isFloat) {
assert(T != B, "invalid size");
assert((imm8 >> 8) == 0, "invalid immediate");
sh = 0;
} else if (imm8 <= 127 && imm8 >= -128) {
sh = 0;
} else if (T != B && imm8 <= 32512 && imm8 >= -32768 && (imm8 & 0xff) == 0) {
sh = 1;
@ -3824,7 +3828,7 @@ private:
}
int m = isMerge ? 1 : 0;
f(0b00000101, 31, 24), f(T, 23, 22), f(0b01, 21, 20);
prf(Pg, 16), f(isFloat ? 1 : 0, 15), f(m, 14), f(sh, 13), sf(imm8, 12, 5), rf(Zd, 0);
prf(Pg, 16), f(isFloat ? 1 : 0, 15), f(m, 14), f(sh, 13), f(imm8 & 0xff, 12, 5), rf(Zd, 0);
}
public:
@ -3834,7 +3838,7 @@ public:
}
// SVE copy floating-point immediate to vector elements (predicated)
void sve_cpy(FloatRegister Zd, SIMD_RegVariant T, PRegister Pg, double d) {
sve_cpy(Zd, T, Pg, checked_cast<int8_t>(pack(d)), /*isMerge*/true, /*isFloat*/true);
sve_cpy(Zd, T, Pg, checked_cast<uint8_t>(pack(d)), /*isMerge*/true, /*isFloat*/true);
}
// SVE conditionally select elements from two vectors
@ -4324,6 +4328,7 @@ public:
static bool operand_valid_for_sve_add_sub_immediate(int64_t imm);
static bool operand_valid_for_float_immediate(double imm);
static int operand_valid_for_movi_immediate(uint64_t imm64, SIMD_Arrangement T);
static bool operand_valid_for_sve_dup_immediate(int64_t imm);
void emit_data64(jlong data, relocInfo::relocType rtype, int format = 0);
void emit_data64(jlong data, RelocationHolder const& rspec, int format = 0);

View File

@ -2585,11 +2585,6 @@ void LIR_Assembler::emit_profile_call(LIR_OpProfileCall* op) {
}
void LIR_Assembler::emit_delay(LIR_OpDelay*) {
Unimplemented();
}
void LIR_Assembler::monitor_address(int monitor_no, LIR_Opr dst) {
__ lea(dst->as_register(), frame_map()->address_for_monitor_lock(monitor_no));
}

View File

@ -702,10 +702,10 @@ static void printbc(Method *m, intptr_t bcx) {
if (m->validate_bci_from_bcp((address)bcx) < 0
|| !m->contains((address)bcx)) {
name = "???";
snprintf(buf, sizeof buf, "(bad)");
os::snprintf_checked(buf, sizeof buf, "(bad)");
} else {
int bci = m->bci_from((address)bcx);
snprintf(buf, sizeof buf, "%d", bci);
os::snprintf_checked(buf, sizeof buf, "%d", bci);
name = Bytecodes::name(m->code_at(bci));
}
ResourceMark rm;

View File

@ -275,7 +275,7 @@ address BarrierSetAssembler::patching_epoch_addr() {
}
void BarrierSetAssembler::increment_patching_epoch() {
Atomic::inc(&_patching_epoch);
AtomicAccess::inc(&_patching_epoch);
}
void BarrierSetAssembler::clear_patching_epoch() {
@ -331,13 +331,7 @@ void BarrierSetAssembler::nmethod_entry_barrier(MacroAssembler* masm, Label* slo
__ ldr(rscratch2, thread_disarmed_and_epoch_addr);
__ cmp(rscratch1, rscratch2);
} else {
assert(patching_type == NMethodPatchingType::conc_data_patch, "must be");
// Subsequent loads of oops must occur after load of guard value.
// BarrierSetNMethod::disarm sets guard with release semantics.
__ membar(__ LoadLoad);
Address thread_disarmed_addr(rthread, in_bytes(bs_nm->thread_disarmed_guard_value_offset()));
__ ldrw(rscratch2, thread_disarmed_addr);
__ cmpw(rscratch1, rscratch2);
ShouldNotReachHere();
}
__ br(condition, barrier_target);

View File

@ -39,8 +39,7 @@ class Node;
enum class NMethodPatchingType {
stw_instruction_and_data_patch,
conc_instruction_and_data_patch,
conc_data_patch
conc_instruction_and_data_patch
};
class BarrierSetAssembler: public CHeapObj<mtGC> {

View File

@ -58,8 +58,6 @@ static int entry_barrier_offset(nmethod* nm) {
return -4 * (4 + slow_path_size(nm));
case NMethodPatchingType::conc_instruction_and_data_patch:
return -4 * (10 + slow_path_size(nm));
case NMethodPatchingType::conc_data_patch:
return -4 * (5 + slow_path_size(nm));
}
ShouldNotReachHere();
return 0;
@ -114,11 +112,25 @@ public:
}
int get_value() {
return Atomic::load_acquire(guard_addr());
return AtomicAccess::load_acquire(guard_addr());
}
void set_value(int value) {
Atomic::release_store(guard_addr(), value);
void set_value(int value, int bit_mask) {
if (bit_mask == ~0) {
AtomicAccess::release_store(guard_addr(), value);
return;
}
assert((value & ~bit_mask) == 0, "trying to set bits outside the mask");
value &= bit_mask;
int old_value = AtomicAccess::load(guard_addr());
while (true) {
// Only bits in the mask are changed
int new_value = value | (old_value & ~bit_mask);
if (new_value == old_value) break;
int v = AtomicAccess::cmpxchg(guard_addr(), old_value, new_value, memory_order_release);
if (v == old_value) break;
old_value = v;
}
}
bool check_barrier(err_msg& msg) const;
@ -181,7 +193,7 @@ void BarrierSetNMethod::deoptimize(nmethod* nm, address* return_address_ptr) {
new_frame->pc = SharedRuntime::get_handle_wrong_method_stub();
}
void BarrierSetNMethod::set_guard_value(nmethod* nm, int value) {
void BarrierSetNMethod::set_guard_value(nmethod* nm, int value, int bit_mask) {
if (!supports_entry_barrier(nm)) {
return;
}
@ -198,7 +210,7 @@ void BarrierSetNMethod::set_guard_value(nmethod* nm, int value) {
}
NativeNMethodBarrier barrier(nm);
barrier.set_value(value);
barrier.set_value(value, bit_mask);
}
int BarrierSetNMethod::guard_value(nmethod* nm) {

View File

@ -67,7 +67,7 @@ private:
Register scratch, RegSet saved_regs);
public:
virtual NMethodPatchingType nmethod_patching_type() { return NMethodPatchingType::conc_data_patch; }
virtual NMethodPatchingType nmethod_patching_type() { return NMethodPatchingType::conc_instruction_and_data_patch; }
#ifdef COMPILER1
void gen_pre_barrier_stub(LIR_Assembler* ce, ShenandoahPreBarrierStub* stub);

View File

@ -2259,7 +2259,7 @@ void MacroAssembler::movptr(Register r, uintptr_t imm64) {
#ifndef PRODUCT
{
char buffer[64];
snprintf(buffer, sizeof(buffer), "0x%" PRIX64, (uint64_t)imm64);
os::snprintf_checked(buffer, sizeof(buffer), "0x%" PRIX64, (uint64_t)imm64);
block_comment(buffer);
}
#endif
@ -2317,7 +2317,7 @@ void MacroAssembler::mov_immediate64(Register dst, uint64_t imm64)
#ifndef PRODUCT
{
char buffer[64];
snprintf(buffer, sizeof(buffer), "0x%" PRIX64, imm64);
os::snprintf_checked(buffer, sizeof(buffer), "0x%" PRIX64, imm64);
block_comment(buffer);
}
#endif
@ -2430,7 +2430,7 @@ void MacroAssembler::mov_immediate32(Register dst, uint32_t imm32)
#ifndef PRODUCT
{
char buffer[64];
snprintf(buffer, sizeof(buffer), "0x%" PRIX32, imm32);
os::snprintf_checked(buffer, sizeof(buffer), "0x%" PRIX32, imm32);
block_comment(buffer);
}
#endif
@ -2902,11 +2902,11 @@ int MacroAssembler::push_fp(unsigned int bitset, Register stack, FpPushPopMode m
{
char buffer[48];
if (mode == PushPopSVE) {
snprintf(buffer, sizeof(buffer), "push_fp: %d SVE registers", count);
os::snprintf_checked(buffer, sizeof(buffer), "push_fp: %d SVE registers", count);
} else if (mode == PushPopNeon) {
snprintf(buffer, sizeof(buffer), "push_fp: %d Neon registers", count);
os::snprintf_checked(buffer, sizeof(buffer), "push_fp: %d Neon registers", count);
} else {
snprintf(buffer, sizeof(buffer), "push_fp: %d fp registers", count);
os::snprintf_checked(buffer, sizeof(buffer), "push_fp: %d fp registers", count);
}
block_comment(buffer);
}
@ -3014,11 +3014,11 @@ int MacroAssembler::pop_fp(unsigned int bitset, Register stack, FpPushPopMode mo
{
char buffer[48];
if (mode == PushPopSVE) {
snprintf(buffer, sizeof(buffer), "pop_fp: %d SVE registers", count);
os::snprintf_checked(buffer, sizeof(buffer), "pop_fp: %d SVE registers", count);
} else if (mode == PushPopNeon) {
snprintf(buffer, sizeof(buffer), "pop_fp: %d Neon registers", count);
os::snprintf_checked(buffer, sizeof(buffer), "pop_fp: %d Neon registers", count);
} else {
snprintf(buffer, sizeof(buffer), "pop_fp: %d fp registers", count);
os::snprintf_checked(buffer, sizeof(buffer), "pop_fp: %d fp registers", count);
}
block_comment(buffer);
}
@ -5920,7 +5920,7 @@ address MacroAssembler::arrays_equals(Register a1, Register a2, Register tmp3,
{
const char kind = (elem_size == 2) ? 'U' : 'L';
char comment[64];
snprintf(comment, sizeof comment, "array_equals%c{", kind);
os::snprintf_checked(comment, sizeof comment, "array_equals%c{", kind);
BLOCK_COMMENT(comment);
}
#endif
@ -6118,7 +6118,7 @@ void MacroAssembler::string_equals(Register a1, Register a2,
#ifndef PRODUCT
{
char comment[64];
snprintf(comment, sizeof comment, "{string_equalsL");
os::snprintf_checked(comment, sizeof comment, "{string_equalsL");
BLOCK_COMMENT(comment);
}
#endif
@ -6266,7 +6266,7 @@ address MacroAssembler::zero_words(Register base, uint64_t cnt)
#ifndef PRODUCT
{
char buf[64];
snprintf(buf, sizeof buf, "zero_words (count = %" PRIu64 ") {", cnt);
os::snprintf_checked(buf, sizeof buf, "zero_words (count = %" PRIu64 ") {", cnt);
BLOCK_COMMENT(buf);
}
#endif

View File

@ -42,7 +42,7 @@
#include "prims/methodHandles.hpp"
#include "prims/upcallLinker.hpp"
#include "runtime/arguments.hpp"
#include "runtime/atomic.hpp"
#include "runtime/atomicAccess.hpp"
#include "runtime/continuation.hpp"
#include "runtime/continuationEntry.inline.hpp"
#include "runtime/frame.inline.hpp"
@ -10265,7 +10265,7 @@ class StubGenerator: public StubCodeGenerator {
#if defined (LINUX) && !defined (__ARM_FEATURE_ATOMICS)
// ARMv8.1 LSE versions of the atomic stubs used by Atomic::PlatformXX.
// ARMv8.1 LSE versions of the atomic stubs used by AtomicAccess::PlatformXX.
//
// If LSE is in use, generate LSE versions of all the stubs. The
// non-LSE versions are in atomic_aarch64.S.

View File

@ -721,12 +721,12 @@ void VM_Version::initialize_cpu_information(void) {
_no_of_cores = os::processor_count();
_no_of_threads = _no_of_cores;
_no_of_sockets = _no_of_cores;
snprintf(_cpu_name, CPU_TYPE_DESC_BUF_SIZE - 1, "AArch64");
os::snprintf_checked(_cpu_name, CPU_TYPE_DESC_BUF_SIZE - 1, "AArch64");
int desc_len = snprintf(_cpu_desc, CPU_DETAILED_DESC_BUF_SIZE, "AArch64 ");
int desc_len = os::snprintf(_cpu_desc, CPU_DETAILED_DESC_BUF_SIZE, "AArch64 ");
get_compatible_board(_cpu_desc + desc_len, CPU_DETAILED_DESC_BUF_SIZE - desc_len);
desc_len = (int)strlen(_cpu_desc);
snprintf(_cpu_desc + desc_len, CPU_DETAILED_DESC_BUF_SIZE - desc_len, " %s", _cpu_info_string);
os::snprintf_checked(_cpu_desc + desc_len, CPU_DETAILED_DESC_BUF_SIZE - desc_len, " %s", _cpu_info_string);
_initialized = true;
}

View File

@ -2638,9 +2638,6 @@ attributes %{
instruction_unit_size = 4; // An instruction is 4 bytes long
instruction_fetch_unit_size = 16; // The processor fetches one line
instruction_fetch_units = 1; // of 16 bytes
// List of nop instructions
nops( Nop_A0, Nop_A1, Nop_MS, Nop_FA, Nop_BR );
%}
//----------RESOURCES----------------------------------------------------------
@ -3284,18 +3281,18 @@ pipe_class loadPollP(iRegP poll) %{
%}
pipe_class br(Universe br, label labl) %{
single_instruction_with_delay_slot;
single_instruction;
BR : R;
%}
pipe_class br_cc(Universe br, cmpOp cmp, flagsReg cr, label labl) %{
single_instruction_with_delay_slot;
single_instruction;
cr : E(read);
BR : R;
%}
pipe_class br_reg(Universe br, cmpOp cmp, iRegI op1, label labl) %{
single_instruction_with_delay_slot;
single_instruction;
op1 : E(read);
BR : R;
MS : R;
@ -3326,14 +3323,14 @@ pipe_class call(method meth) %{
%}
pipe_class tail_call(Universe ignore, label labl) %{
single_instruction; has_delay_slot;
single_instruction;
fixed_latency(100);
BR : R(1);
MS : R(1);
%}
pipe_class ret(Universe ignore) %{
single_instruction; has_delay_slot;
single_instruction;
BR : R(1);
MS : R(1);
%}
@ -3376,14 +3373,6 @@ pipe_class cadd_cmpltmask( iRegI p, iRegI q, iRegI y ) %{
IALU : R(3)
%}
// Perform a compare, then move conditionally in a branch delay slot.
pipe_class min_max( iRegI src2, iRegI srcdst ) %{
src2 : E(read);
srcdst : E(read);
IALU : R;
BR : R;
%}
// Define the class for the Nop node
define %{
MachNop = ialu_nop;
@ -9056,7 +9045,7 @@ instruct clear_array(iRegX cnt, iRegP base, iRegI temp, iRegX zero, Universe dum
format %{ "MOV $zero,0\n"
" MOV $temp,$cnt\n"
"loop: SUBS $temp,$temp,4\t! Count down a dword of bytes\n"
" STR.ge $zero,[$base+$temp]\t! delay slot"
" STR.ge $zero,[$base+$temp]\n"
" B.gt loop\t\t! Clearing loop\n" %}
ins_encode %{
__ mov($zero$$Register, 0);

View File

@ -2552,11 +2552,6 @@ void LIR_Assembler::emit_profile_type(LIR_OpProfileType* op) {
fatal("Type profiling not implemented on this platform");
}
void LIR_Assembler::emit_delay(LIR_OpDelay*) {
Unimplemented();
}
void LIR_Assembler::monitor_address(int monitor_no, LIR_Opr dst) {
Address mon_addr = frame_map()->address_for_monitor_lock(monitor_no);
__ add_slow(dst->as_pointer_register(), mon_addr.base(), mon_addr.disp());

View File

@ -48,11 +48,25 @@ class NativeNMethodBarrier: public NativeInstruction {
public:
int get_value() {
return Atomic::load_acquire(guard_addr());
return AtomicAccess::load_acquire(guard_addr());
}
void set_value(int value) {
Atomic::release_store(guard_addr(), value);
void set_value(int value, int bit_mask) {
if (bit_mask == ~0) {
AtomicAccess::release_store(guard_addr(), value);
return;
}
assert((value & ~bit_mask) == 0, "trying to set bits outside the mask");
value &= bit_mask;
int old_value = AtomicAccess::load(guard_addr());
while (true) {
// Only bits in the mask are changed
int new_value = value | (old_value & ~bit_mask);
if (new_value == old_value) break;
int v = AtomicAccess::cmpxchg(guard_addr(), old_value, new_value, memory_order_release);
if (v == old_value) break;
old_value = v;
}
}
void verify() const;
@ -115,7 +129,7 @@ void BarrierSetNMethod::deoptimize(nmethod* nm, address* return_address_ptr) {
new_frame->pc = SharedRuntime::get_handle_wrong_method_stub();
}
void BarrierSetNMethod::set_guard_value(nmethod* nm, int value) {
void BarrierSetNMethod::set_guard_value(nmethod* nm, int value, int bit_mask) {
if (!supports_entry_barrier(nm)) {
return;
}
@ -123,7 +137,7 @@ void BarrierSetNMethod::set_guard_value(nmethod* nm, int value) {
// Disarms the nmethod guard emitted by BarrierSetAssembler::nmethod_entry_barrier.
// Symmetric "LDR; DMB ISHLD" is in the nmethod barrier.
NativeNMethodBarrier* barrier = native_nmethod_barrier(nm);
barrier->set_value(value);
barrier->set_value(value, bit_mask);
}
int BarrierSetNMethod::guard_value(nmethod* nm) {

View File

@ -839,7 +839,7 @@ void MacroAssembler::_verify_oop(Register reg, const char* s, const char* file,
char buffer[64];
#ifdef COMPILER1
if (CommentedAssembly) {
snprintf(buffer, sizeof(buffer), "verify_oop at %d", offset());
os::snprintf_checked(buffer, sizeof(buffer), "verify_oop at %d", offset());
block_comment(buffer);
}
#endif

View File

@ -421,7 +421,8 @@ class StubGenerator: public StubCodeGenerator {
}
// As per atomic.hpp the Atomic read-modify-write operations must be logically implemented as:
// As per atomicAccess.hpp the atomic read-modify-write operations must be
// logically implemented as:
// <fence>; <op>; <membar StoreLoad|StoreStore>
// But for load-linked/store-conditional based systems a fence here simply means
// no load/store can be reordered with respect to the initial load-linked, so we have:
@ -440,7 +441,7 @@ class StubGenerator: public StubCodeGenerator {
// be removed in the future.
// Implementation of atomic_add(jint add_value, volatile jint* dest)
// used by Atomic::add(volatile jint* dest, jint add_value)
// used by AtomicAccess::add(volatile jint* dest, jint add_value)
//
// Arguments :
//
@ -492,7 +493,7 @@ class StubGenerator: public StubCodeGenerator {
}
// Implementation of jint atomic_xchg(jint exchange_value, volatile jint* dest)
// used by Atomic::add(volatile jint* dest, jint exchange_value)
// used by AtomicAccess::add(volatile jint* dest, jint exchange_value)
//
// Arguments :
//
@ -542,7 +543,7 @@ class StubGenerator: public StubCodeGenerator {
}
// Implementation of jint atomic_cmpxchg(jint exchange_value, volatile jint *dest, jint compare_value)
// used by Atomic::cmpxchg(volatile jint *dest, jint compare_value, jint exchange_value)
// used by AtomicAccess::cmpxchg(volatile jint *dest, jint compare_value, jint exchange_value)
//
// Arguments :
//
@ -582,7 +583,7 @@ class StubGenerator: public StubCodeGenerator {
return start;
}
// Support for jlong Atomic::cmpxchg(jlong exchange_value, volatile jlong *dest, jlong compare_value)
// Support for jlong AtomicAccess::cmpxchg(jlong exchange_value, volatile jlong *dest, jlong compare_value)
// reordered before by a wrapper to (jlong compare_value, jlong exchange_value, volatile jlong *dest)
//
// Arguments :

View File

@ -362,7 +362,7 @@ void VM_Version::initialize_cpu_information(void) {
_no_of_cores = os::processor_count();
_no_of_threads = _no_of_cores;
_no_of_sockets = _no_of_cores;
snprintf(_cpu_name, CPU_TYPE_DESC_BUF_SIZE - 1, "ARM%d", _arm_arch);
snprintf(_cpu_desc, CPU_DETAILED_DESC_BUF_SIZE, "%s", _cpu_info_string);
os::snprintf_checked(_cpu_name, CPU_TYPE_DESC_BUF_SIZE - 1, "ARM%d", _arm_arch);
os::snprintf_checked(_cpu_desc, CPU_DETAILED_DESC_BUF_SIZE, "%s", _cpu_info_string);
_initialized = true;
}

View File

@ -100,7 +100,7 @@ int AbstractInterpreter::size_activation(int max_stack,
// It is also guaranteed to be walkable even though it is in a skeletal state
//
// is_top_frame == true:
// We're processing the *oldest* interpreter frame!
// We're processing the *youngest* interpreter frame on top of stack!
//
// pop_frame_extra_args:
// If this is != 0 we are returning to a deoptimized frame by popping
@ -131,8 +131,9 @@ void AbstractInterpreter::layout_activation(Method* method,
#ifdef ASSERT
if (caller->is_interpreted_frame()) {
assert(locals_base <= caller->interpreter_frame_expression_stack(), "bad placement");
const int caller_abi_bytesize = (is_bottom_frame ? frame::top_ijava_frame_abi_size : frame::parent_ijava_frame_abi_size);
intptr_t* l2 = caller->sp() + method->max_locals() - 1 + (caller_abi_bytesize / Interpreter::stackElementSize);
// If the bottom frame's caller was thawed then it has frame::java_abi (aka parent_ijava_frame_abi).
// With an ordinary i2c call it would keep the larger frame::top_ijava_frame_abi
intptr_t* l2 = caller->sp() + method->max_locals() - 1 + (frame::parent_ijava_frame_abi_size / Interpreter::stackElementSize);
assert(locals_base >= l2, "bad placement");
}
#endif

View File

@ -2747,11 +2747,6 @@ void LIR_Assembler::align_backward_branch_target() {
}
void LIR_Assembler::emit_delay(LIR_OpDelay* op) {
Unimplemented();
}
void LIR_Assembler::negate(LIR_Opr left, LIR_Opr dest, LIR_Opr tmp) {
// tmp must be unused
assert(tmp->is_illegal(), "wasting a register if tmp is allocated");

View File

@ -183,12 +183,9 @@ void BarrierSetAssembler::nmethod_entry_barrier(MacroAssembler* masm, Register t
BarrierSetNMethod* bs_nm = BarrierSet::barrier_set()->barrier_set_nmethod();
assert_different_registers(tmp, R0);
__ block_comment("nmethod_entry_barrier (nmethod_entry_barrier) {");
__ align(8); // must align the following block which requires atomic updates
// Load stub address using toc (fixed instruction size, unlike load_const_optimized)
__ calculate_address_from_global_toc(tmp, StubRoutines::method_entry_barrier(),
true, true, false); // 2 instructions
__ mtctr(tmp);
__ block_comment("nmethod_entry_barrier (nmethod_entry_barrier) {");
// This is a compound instruction. Patching support is provided by NativeMovRegMem.
// Actual patching is done in (platform-specific part of) BarrierSetNMethod.
@ -198,6 +195,11 @@ void BarrierSetAssembler::nmethod_entry_barrier(MacroAssembler* masm, Register t
__ ld(R0, in_bytes(bs_nm->thread_disarmed_guard_value_offset()), R16_thread);
__ cmpw(CR0, R0, tmp);
// Load stub address using toc (fixed instruction size, unlike load_const_optimized)
__ calculate_address_from_global_toc(tmp, StubRoutines::method_entry_barrier(),
true, true, false); // 2 instructions
__ mtctr(tmp);
__ bnectrl(CR0);
// Oops may have been changed. Make those updates observable.

View File

@ -40,8 +40,7 @@ class Node;
enum class NMethodPatchingType {
stw_instruction_and_data_patch,
conc_instruction_and_data_patch,
conc_data_patch
conc_instruction_and_data_patch
};
class BarrierSetAssembler: public CHeapObj<mtGC> {

View File

@ -38,7 +38,7 @@ class NativeNMethodBarrier: public NativeInstruction {
NativeMovRegMem* get_patchable_instruction_handle() const {
// Endianness is handled by NativeMovRegMem
return reinterpret_cast<NativeMovRegMem*>(get_barrier_start_address() + 3 * 4);
return reinterpret_cast<NativeMovRegMem*>(get_barrier_start_address());
}
public:
@ -47,7 +47,7 @@ public:
return get_patchable_instruction_handle()->offset();
}
void release_set_guard_value(int value) {
void release_set_guard_value(int value, int bit_mask) {
// Patching is not atomic.
// Stale observations of the "armed" state is okay as invoking the barrier stub in that case has no
// unwanted side effects. Disarming is thus a non-critical operation.
@ -55,8 +55,37 @@ public:
OrderAccess::release(); // Release modified oops
// Set the guard value (naming of 'offset' function is misleading).
get_patchable_instruction_handle()->set_offset(value);
if (bit_mask == ~0) {
// Set the guard value (naming of 'offset' function is misleading).
get_patchable_instruction_handle()->set_offset(value);
return;
}
assert((value & ~bit_mask) == 0, "trying to set bits outside the mask");
value &= bit_mask;
NativeMovRegMem* mov = get_patchable_instruction_handle();
assert(align_up(mov->instruction_address(), sizeof(uint64_t)) ==
align_down(mov->instruction_address(), sizeof(uint64_t)), "instruction not aligned");
uint64_t *instr = (uint64_t*)mov->instruction_address();
assert(NativeMovRegMem::instruction_size == sizeof(*instr), "must be");
union {
u_char buf[NativeMovRegMem::instruction_size];
uint64_t u64;
} new_mov_instr, old_mov_instr;
new_mov_instr.u64 = old_mov_instr.u64 = AtomicAccess::load(instr);
while (true) {
// Only bits in the mask are changed
int old_value = nativeMovRegMem_at(old_mov_instr.buf)->offset();
int new_value = value | (old_value & ~bit_mask);
if (new_value == old_value) return; // skip icache flush if nothing changed
nativeMovRegMem_at(new_mov_instr.buf)->set_offset(new_value, false /* no icache flush */);
// Swap in the new value
uint64_t v = AtomicAccess::cmpxchg(instr, old_mov_instr.u64, new_mov_instr.u64, memory_order_relaxed);
if (v == old_mov_instr.u64) break;
old_mov_instr.u64 = v;
}
ICache::ppc64_flush_icache_bytes(addr_at(0), NativeMovRegMem::instruction_size);
}
void verify() const {
@ -66,12 +95,6 @@ public:
uint* current_instruction = reinterpret_cast<uint*>(get_barrier_start_address());
// calculate_address_from_global_toc (compound instruction)
verify_op_code_manually(current_instruction, MacroAssembler::is_addis(*current_instruction));
verify_op_code_manually(current_instruction, MacroAssembler::is_addi(*current_instruction));
verify_op_code_manually(current_instruction, MacroAssembler::is_mtctr(*current_instruction));
get_patchable_instruction_handle()->verify();
current_instruction += 2;
@ -80,6 +103,12 @@ public:
// cmpw (mnemonic)
verify_op_code(current_instruction, Assembler::CMP_OPCODE);
// calculate_address_from_global_toc (compound instruction)
verify_op_code_manually(current_instruction, MacroAssembler::is_addis(*current_instruction));
verify_op_code_manually(current_instruction, MacroAssembler::is_addi(*current_instruction));
verify_op_code_manually(current_instruction, MacroAssembler::is_mtctr(*current_instruction));
// bnectrl (mnemonic) (weak check; not checking the exact type)
verify_op_code(current_instruction, Assembler::BCCTR_OPCODE);
@ -117,13 +146,13 @@ void BarrierSetNMethod::deoptimize(nmethod* nm, address* return_address_ptr) {
// Thus, there's nothing to do here.
}
void BarrierSetNMethod::set_guard_value(nmethod* nm, int value) {
void BarrierSetNMethod::set_guard_value(nmethod* nm, int value, int bit_mask) {
if (!supports_entry_barrier(nm)) {
return;
}
NativeNMethodBarrier* barrier = get_nmethod_barrier(nm);
barrier->release_set_guard_value(value);
barrier->release_set_guard_value(value, bit_mask);
}
int BarrierSetNMethod::guard_value(nmethod* nm) {

View File

@ -69,7 +69,7 @@ private:
Register preserve);
public:
virtual NMethodPatchingType nmethod_patching_type() { return NMethodPatchingType::conc_data_patch; }
virtual NMethodPatchingType nmethod_patching_type() { return NMethodPatchingType::conc_instruction_and_data_patch; }
/* ==== C1 stubs ==== */
#ifdef COMPILER1

View File

@ -347,7 +347,7 @@ void NativeGeneralJump::replace_mt_safe(address instr_addr, address code_buffer)
// Finally patch out the jump.
volatile juint *jump_addr = (volatile juint*)instr_addr;
// Release not needed because caller uses invalidate_range after copying the remaining bytes.
//Atomic::release_store(jump_addr, *((juint*)code_buffer));
//AtomicAccess::release_store(jump_addr, *((juint*)code_buffer));
*jump_addr = *((juint*)code_buffer); // atomically store code over branch instruction
ICache::ppc64_flush_icache_bytes(instr_addr, NativeGeneralJump::instruction_size);
}

View File

@ -462,7 +462,7 @@ class NativeMovRegMem: public NativeInstruction {
return ((*hi_ptr) << 16) | ((*lo_ptr) & 0xFFFF);
}
void set_offset(intptr_t x) {
void set_offset(intptr_t x, bool flush_icache = true) {
#ifdef VM_LITTLE_ENDIAN
short *hi_ptr = (short*)(addr_at(0));
short *lo_ptr = (short*)(addr_at(4));
@ -472,7 +472,9 @@ class NativeMovRegMem: public NativeInstruction {
#endif
*hi_ptr = x >> 16;
*lo_ptr = x & 0xFFFF;
ICache::ppc64_flush_icache_bytes(addr_at(0), NativeMovRegMem::instruction_size);
if (flush_icache) {
ICache::ppc64_flush_icache_bytes(addr_at(0), NativeMovRegMem::instruction_size);
}
}
void add_offset_in_bytes(intptr_t radd_offset) {

View File

@ -4920,10 +4920,6 @@ attributes %{
// ...in one line
instruction_fetch_units = 1
// Unused, list one so that array generated by adlc is not empty.
// Aix compiler chokes if _nop_count = 0.
nops(fxNop);
%}
//----------RESOURCES----------------------------------------------------------

View File

@ -625,7 +625,7 @@ void VM_Version::initialize_cpu_information(void) {
_no_of_cores = os::processor_count();
_no_of_threads = _no_of_cores;
_no_of_sockets = _no_of_cores;
snprintf(_cpu_name, CPU_TYPE_DESC_BUF_SIZE, "PowerPC POWER%lu", PowerArchitecturePPC64);
snprintf(_cpu_desc, CPU_DETAILED_DESC_BUF_SIZE, "PPC %s", cpu_info_string());
os::snprintf_checked(_cpu_name, CPU_TYPE_DESC_BUF_SIZE, "PowerPC POWER%lu", PowerArchitecturePPC64);
os::snprintf_checked(_cpu_desc, CPU_DETAILED_DESC_BUF_SIZE, "PPC %s", cpu_info_string());
_initialized = true;
}

View File

@ -912,6 +912,32 @@ protected:
emit(insn);
}
public:
static uint32_t encode_jal(Register Rd, const int32_t offset) {
guarantee(is_simm21(offset) && ((offset % 2) == 0), "offset is invalid.");
uint32_t insn = 0;
patch((address)&insn, 6, 0, 0b1101111);
patch_reg((address)&insn, 7, Rd);
patch((address)&insn, 19, 12, (uint32_t)((offset >> 12) & 0xff));
patch((address)&insn, 20, (uint32_t)((offset >> 11) & 0x1));
patch((address)&insn, 30, 21, (uint32_t)((offset >> 1) & 0x3ff));
patch((address)&insn, 31, (uint32_t)((offset >> 20) & 0x1));
return insn;
}
static uint32_t encode_jalr(Register Rd, Register Rs, const int32_t offset) {
guarantee(is_simm12(offset), "offset is invalid.");
uint32_t insn = 0;
patch((address)&insn, 6, 0, 0b1100111);
patch_reg((address)&insn, 7, Rd);
patch((address)&insn, 14, 12, 0b000);
patch_reg((address)&insn, 15, Rs);
int32_t val = offset & 0xfff;
patch((address)&insn, 31, 20, val);
return insn;
}
protected:
enum barrier {
@ -1988,6 +2014,7 @@ enum VectorMask {
// Vector Narrowing Integer Right Shift Instructions
INSN(vnsra_wi, 0b1010111, 0b011, 0b101101);
INSN(vnsrl_wi, 0b1010111, 0b011, 0b101100);
#undef INSN

View File

@ -1590,8 +1590,6 @@ void LIR_Assembler::emit_profile_call(LIR_OpProfileCall* op) {
}
}
void LIR_Assembler::emit_delay(LIR_OpDelay*) { Unimplemented(); }
void LIR_Assembler::monitor_address(int monitor_no, LIR_Opr dst) {
__ la(dst->as_register(), frame_map()->address_for_monitor_lock(monitor_no));
}

View File

@ -2248,41 +2248,80 @@ static void float_to_float16_v_slow_path(C2_MacroAssembler& masm,
#define __ masm.
VectorRegister dst = stub.data<0>();
VectorRegister src = stub.data<1>();
VectorRegister tmp = stub.data<2>();
VectorRegister vtmp = stub.data<2>();
assert_different_registers(dst, src, vtmp);
__ bind(stub.entry());
// Active elements (NaNs) are marked in v0 mask register.
// mul is already set to mf2 in float_to_float16_v.
// preserve the payloads of non-canonical NaNs.
__ vnsra_wi(dst, src, 13, Assembler::v0_t);
// Float (32 bits)
// Bit: 31 30 to 23 22 to 0
// +---+------------------+-----------------------------+
// | S | Exponent | Mantissa (Fraction) |
// +---+------------------+-----------------------------+
// 1 bit 8 bits 23 bits
//
// Float (16 bits)
// Bit: 15 14 to 10 9 to 0
// +---+----------------+------------------+
// | S | Exponent | Mantissa |
// +---+----------------+------------------+
// 1 bit 5 bits 10 bits
const int fp_sign_bits = 1;
const int fp32_bits = 32;
const int fp32_mantissa_2nd_part_bits = 9;
const int fp32_mantissa_3rd_part_bits = 4;
const int fp16_exponent_bits = 5;
const int fp16_mantissa_bits = 10;
// preserve the sign bit.
__ vnsra_wi(tmp, src, 26, Assembler::v0_t);
__ vsll_vi(tmp, tmp, 10, Assembler::v0_t);
__ mv(t0, 0x3ff);
__ vor_vx(tmp, tmp, t0, Assembler::v0_t);
// preserve the sign bit and exponent, clear mantissa.
__ vnsra_wi(dst, src, fp32_bits - fp_sign_bits - fp16_exponent_bits, Assembler::v0_t);
__ vsll_vi(dst, dst, fp16_mantissa_bits, Assembler::v0_t);
// get the result by merging sign bit and payloads of preserved non-canonical NaNs.
__ vand_vv(dst, dst, tmp, Assembler::v0_t);
// Preserve high order bit of float NaN in the
// binary16 result NaN (tenth bit); OR in remaining
// bits into lower 9 bits of binary 16 significand.
// | (doppel & 0x007f_e000) >> 13 // 10 bits
// | (doppel & 0x0000_1ff0) >> 4 // 9 bits
// | (doppel & 0x0000_000f)); // 4 bits
//
// Check j.l.Float.floatToFloat16 for more information.
// 10 bits
__ vnsrl_wi(vtmp, src, fp32_mantissa_2nd_part_bits + fp32_mantissa_3rd_part_bits, Assembler::v0_t);
__ mv(t0, 0x3ff); // retain first part of mantissa in a float 32
__ vand_vx(vtmp, vtmp, t0, Assembler::v0_t);
__ vor_vv(dst, dst, vtmp, Assembler::v0_t);
// 9 bits
__ vnsrl_wi(vtmp, src, fp32_mantissa_3rd_part_bits, Assembler::v0_t);
__ mv(t0, 0x1ff); // retain second part of mantissa in a float 32
__ vand_vx(vtmp, vtmp, t0, Assembler::v0_t);
__ vor_vv(dst, dst, vtmp, Assembler::v0_t);
// 4 bits
// Narrow shift is necessary to move data from 32 bits element to 16 bits element in vector register.
__ vnsrl_wi(vtmp, src, 0, Assembler::v0_t);
__ vand_vi(vtmp, vtmp, 0xf, Assembler::v0_t);
__ vor_vv(dst, dst, vtmp, Assembler::v0_t);
__ j(stub.continuation());
#undef __
}
// j.l.Float.float16ToFloat
void C2_MacroAssembler::float_to_float16_v(VectorRegister dst, VectorRegister src, VectorRegister vtmp,
Register tmp, uint vector_length) {
void C2_MacroAssembler::float_to_float16_v(VectorRegister dst, VectorRegister src,
VectorRegister vtmp, Register tmp, uint vector_length) {
assert_different_registers(dst, src, vtmp);
auto stub = C2CodeStub::make<VectorRegister, VectorRegister, VectorRegister>
(dst, src, vtmp, 28, float_to_float16_v_slow_path);
(dst, src, vtmp, 56, float_to_float16_v_slow_path);
// On riscv, NaN needs a special process as vfncvt_f_f_w does not work in that case.
vsetvli_helper(BasicType::T_FLOAT, vector_length, Assembler::m1);
// check whether there is a NaN.
// replace v_fclass with vmseq_vv as performance optimization.
// replace v_fclass with vmfne_vv as performance optimization.
vmfne_vv(v0, src, src);
vcpop_m(t0, v0);

View File

@ -217,7 +217,7 @@ address BarrierSetAssembler::patching_epoch_addr() {
}
void BarrierSetAssembler::increment_patching_epoch() {
Atomic::inc(&_patching_epoch);
AtomicAccess::inc(&_patching_epoch);
}
void BarrierSetAssembler::clear_patching_epoch() {
@ -241,10 +241,6 @@ void BarrierSetAssembler::nmethod_entry_barrier(MacroAssembler* masm, Label* slo
__ lwu(t0, *guard);
switch (patching_type) {
case NMethodPatchingType::conc_data_patch:
// Subsequent loads of oops must occur after load of guard value.
// BarrierSetNMethod::disarm sets guard with release semantics.
__ membar(MacroAssembler::LoadLoad); // fall through to stw_instruction_and_data_patch
case NMethodPatchingType::stw_instruction_and_data_patch:
{
// With STW patching, no data or instructions are updated concurrently,

View File

@ -40,8 +40,7 @@ class Node;
enum class NMethodPatchingType {
stw_instruction_and_data_patch,
conc_instruction_and_data_patch,
conc_data_patch
conc_instruction_and_data_patch
};
class BarrierSetAssembler: public CHeapObj<mtGC> {

View File

@ -50,8 +50,6 @@ static int entry_barrier_offset(nmethod* nm) {
switch (bs_asm->nmethod_patching_type()) {
case NMethodPatchingType::stw_instruction_and_data_patch:
return -4 * (4 + slow_path_size(nm));
case NMethodPatchingType::conc_data_patch:
return -4 * (5 + slow_path_size(nm));
case NMethodPatchingType::conc_instruction_and_data_patch:
return -4 * (15 + slow_path_size(nm));
}
@ -108,11 +106,25 @@ public:
}
int get_value() {
return Atomic::load_acquire(guard_addr());
return AtomicAccess::load_acquire(guard_addr());
}
void set_value(int value) {
Atomic::release_store(guard_addr(), value);
void set_value(int value, int bit_mask) {
if (bit_mask == ~0) {
AtomicAccess::release_store(guard_addr(), value);
return;
}
assert((value & ~bit_mask) == 0, "trying to set bits outside the mask");
value &= bit_mask;
int old_value = AtomicAccess::load(guard_addr());
while (true) {
// Only bits in the mask are changed
int new_value = value | (old_value & ~bit_mask);
if (new_value == old_value) break;
int v = AtomicAccess::cmpxchg(guard_addr(), old_value, new_value, memory_order_release);
if (v == old_value) break;
old_value = v;
}
}
bool check_barrier(err_msg& msg) const;
@ -194,7 +206,7 @@ void BarrierSetNMethod::deoptimize(nmethod* nm, address* return_address_ptr) {
new_frame->pc = SharedRuntime::get_handle_wrong_method_stub();
}
void BarrierSetNMethod::set_guard_value(nmethod* nm, int value) {
void BarrierSetNMethod::set_guard_value(nmethod* nm, int value, int bit_mask) {
if (!supports_entry_barrier(nm)) {
return;
}
@ -211,7 +223,7 @@ void BarrierSetNMethod::set_guard_value(nmethod* nm, int value) {
}
NativeNMethodBarrier barrier(nm);
barrier.set_value(value);
barrier.set_value(value, bit_mask);
}
int BarrierSetNMethod::guard_value(nmethod* nm) {

View File

@ -69,7 +69,7 @@ private:
public:
virtual NMethodPatchingType nmethod_patching_type() { return NMethodPatchingType::conc_data_patch; }
virtual NMethodPatchingType nmethod_patching_type() { return NMethodPatchingType::conc_instruction_and_data_patch; }
#ifdef COMPILER1
void gen_pre_barrier_stub(LIR_Assembler* ce, ShenandoahPreBarrierStub* stub);

View File

@ -2679,7 +2679,7 @@ void MacroAssembler::movptr(Register Rd, address addr, int32_t &offset, Register
#ifndef PRODUCT
{
char buffer[64];
snprintf(buffer, sizeof(buffer), "0x%" PRIx64, uimm64);
os::snprintf_checked(buffer, sizeof(buffer), "0x%" PRIx64, uimm64);
block_comment(buffer);
}
#endif
@ -3402,6 +3402,8 @@ void MacroAssembler::decode_klass_not_null(Register r, Register tmp) {
void MacroAssembler::decode_klass_not_null(Register dst, Register src, Register tmp) {
assert(UseCompressedClassPointers, "should only be used for compressed headers");
assert_different_registers(dst, tmp);
assert_different_registers(src, tmp);
if (CompressedKlassPointers::base() == nullptr) {
if (CompressedKlassPointers::shift() != 0) {
@ -3412,18 +3414,13 @@ void MacroAssembler::decode_klass_not_null(Register dst, Register src, Register
return;
}
Register xbase = dst;
if (dst == src) {
xbase = tmp;
}
Register xbase = tmp;
assert_different_registers(src, xbase);
mv(xbase, (uintptr_t)CompressedKlassPointers::base());
if (CompressedKlassPointers::shift() != 0) {
Register t = src == dst ? dst : t0;
assert_different_registers(t, xbase);
shadd(dst, src, xbase, t, CompressedKlassPointers::shift());
// dst = (src << shift) + xbase
shadd(dst, src, xbase, dst /* temporary, dst != xbase */, CompressedKlassPointers::shift());
} else {
add(dst, xbase, src);
}
@ -5874,13 +5871,14 @@ void MacroAssembler::fill_words(Register base, Register cnt, Register value) {
// in cnt.
//
// NOTE: This is intended to be used in the zero_blocks() stub. If
// you want to use it elsewhere, note that cnt must be >= CacheLineSize.
// you want to use it elsewhere, note that cnt must be >= zicboz_block_size.
void MacroAssembler::zero_dcache_blocks(Register base, Register cnt, Register tmp1, Register tmp2) {
int zicboz_block_size = VM_Version::zicboz_block_size.value();
Label initial_table_end, loop;
// Align base with cache line size.
neg(tmp1, base);
andi(tmp1, tmp1, CacheLineSize - 1);
andi(tmp1, tmp1, zicboz_block_size - 1);
// tmp1: the number of bytes to be filled to align the base with cache line size.
add(base, base, tmp1);
@ -5890,16 +5888,16 @@ void MacroAssembler::zero_dcache_blocks(Register base, Register cnt, Register tm
la(tmp1, initial_table_end);
sub(tmp2, tmp1, tmp2);
jr(tmp2);
for (int i = -CacheLineSize + wordSize; i < 0; i += wordSize) {
for (int i = -zicboz_block_size + wordSize; i < 0; i += wordSize) {
sd(zr, Address(base, i));
}
bind(initial_table_end);
mv(tmp1, CacheLineSize / wordSize);
mv(tmp1, zicboz_block_size / wordSize);
bind(loop);
cbo_zero(base);
sub(cnt, cnt, tmp1);
addi(base, base, CacheLineSize);
addi(base, base, zicboz_block_size);
bge(cnt, tmp1, loop);
}

View File

@ -93,14 +93,60 @@ void MethodHandles::verify_klass(MacroAssembler* _masm,
void MethodHandles::verify_ref_kind(MacroAssembler* _masm, int ref_kind, Register member_reg, Register temp) {}
void MethodHandles::verify_method(MacroAssembler* _masm, Register method, vmIntrinsics::ID iid) {
BLOCK_COMMENT("verify_method {");
__ verify_method_ptr(method);
if (VerifyMethodHandles) {
Label L_ok;
assert_different_registers(method, t0, t1);
const Register method_holder = t1;
__ load_method_holder(method_holder, method);
switch (iid) {
case vmIntrinsicID::_invokeBasic:
// Require compiled LambdaForm class to be fully initialized.
__ lbu(t0, Address(method_holder, InstanceKlass::init_state_offset()));
__ membar(MacroAssembler::LoadLoad | MacroAssembler::LoadStore);
__ mv(t1, InstanceKlass::fully_initialized);
__ beq(t0, t1, L_ok);
break;
case vmIntrinsicID::_linkToStatic:
__ clinit_barrier(method_holder, t0, &L_ok);
break;
case vmIntrinsicID::_linkToVirtual:
case vmIntrinsicID::_linkToSpecial:
case vmIntrinsicID::_linkToInterface:
// Class initialization check is too strong here. Just ensure that class initialization has been initiated.
__ lbu(t0, Address(method_holder, InstanceKlass::init_state_offset()));
__ membar(MacroAssembler::LoadLoad | MacroAssembler::LoadStore);
__ mv(t1, InstanceKlass::being_initialized);
__ bge(t0, t1, L_ok);
// init_state check failed, but it may be an abstract interface method
__ lhu(t0, Address(method, Method::access_flags_offset()));
__ test_bit(t1, t0, exact_log2(JVM_ACC_ABSTRACT));
__ bnez(t1, L_ok);
break;
default:
fatal("unexpected intrinsic %d: %s", vmIntrinsics::as_int(iid), vmIntrinsics::name_at(iid));
}
// Method holder init state check failed for a concrete method.
__ stop("Method holder klass is not initialized");
__ BIND(L_ok);
}
BLOCK_COMMENT("} verify_method");
}
#endif //ASSERT
void MethodHandles::jump_from_method_handle(MacroAssembler* _masm, Register method, Register temp,
bool for_compiler_entry) {
bool for_compiler_entry, vmIntrinsics::ID iid) {
assert(method == xmethod, "interpreter calling convention");
Label L_no_such_method;
__ beqz(xmethod, L_no_such_method);
__ verify_method_ptr(method);
verify_method(_masm, method, iid);
if (!for_compiler_entry && JvmtiExport::can_post_interpreter_events()) {
Label run_compiled_code;
@ -158,7 +204,7 @@ void MethodHandles::jump_to_lambda_form(MacroAssembler* _masm,
__ BIND(L);
}
jump_from_method_handle(_masm, method_temp, temp2, for_compiler_entry);
jump_from_method_handle(_masm, method_temp, temp2, for_compiler_entry, vmIntrinsics::_invokeBasic);
BLOCK_COMMENT("} jump_to_lambda_form");
}
@ -437,8 +483,7 @@ void MethodHandles::generate_method_handle_dispatch(MacroAssembler* _masm,
// After figuring out which concrete method to call, jump into it.
// Note that this works in the interpreter with no data motion.
// But the compiled version will require that r2_recv be shifted out.
__ verify_method_ptr(xmethod);
jump_from_method_handle(_masm, xmethod, temp1, for_compiler_entry);
jump_from_method_handle(_masm, xmethod, temp1, for_compiler_entry, iid);
if (iid == vmIntrinsics::_linkToInterface) {
__ bind(L_incompatible_class_change_error);
__ far_jump(RuntimeAddress(SharedRuntime::throw_IncompatibleClassChangeError_entry()));

View File

@ -39,6 +39,8 @@ public:
Register obj, vmClassID klass_id,
const char* error_message = "wrong klass") NOT_DEBUG_RETURN;
static void verify_method(MacroAssembler* _masm, Register method, vmIntrinsics::ID iid) NOT_DEBUG_RETURN;
static void verify_method_handle(MacroAssembler* _masm, Register mh_reg) {
verify_klass(_masm, mh_reg, VM_CLASS_ID(java_lang_invoke_MethodHandle),
"reference is a MH");
@ -49,7 +51,7 @@ public:
// Similar to InterpreterMacroAssembler::jump_from_interpreted.
// Takes care of special dispatch from single stepping too.
static void jump_from_method_handle(MacroAssembler* _masm, Register method, Register temp,
bool for_compiler_entry);
bool for_compiler_entry, vmIntrinsics::ID iid);
static void jump_to_lambda_form(MacroAssembler* _masm,
Register recv, Register method_temp,

View File

@ -28,11 +28,13 @@
#include "code/compiledIC.hpp"
#include "nativeInst_riscv.hpp"
#include "oops/oop.inline.hpp"
#include "runtime/atomicAccess.hpp"
#include "runtime/handles.hpp"
#include "runtime/orderAccess.hpp"
#include "runtime/safepoint.hpp"
#include "runtime/sharedRuntime.hpp"
#include "runtime/stubRoutines.hpp"
#include "utilities/align.hpp"
#include "utilities/ostream.hpp"
#ifdef COMPILER1
#include "c1/c1_Runtime1.hpp"
@ -52,15 +54,15 @@ address NativeCall::destination() const {
address addr = instruction_address();
assert(NativeCall::is_at(addr), "unexpected code at call site");
address destination = MacroAssembler::target_addr_for_insn(addr);
address stub_addr = MacroAssembler::target_addr_for_insn(addr);
CodeBlob* cb = CodeCache::find_blob(addr);
assert(cb != nullptr && cb->is_nmethod(), "nmethod expected");
nmethod *nm = (nmethod *)cb;
assert(nm != nullptr, "Sanity");
assert(nm->stub_contains(destination), "Sanity");
assert(destination != nullptr, "Sanity");
return stub_address_destination_at(destination);
assert(nm->stub_contains(stub_addr), "Sanity");
assert(stub_addr != nullptr, "Sanity");
return stub_address_destination_at(stub_addr);
}
address NativeCall::reloc_destination() {
@ -89,6 +91,30 @@ void NativeCall::print() {
tty->print_cr(PTR_FORMAT ": auipc,ld,jalr x1, offset/reg, ", p2i(instruction_address()));
}
void NativeCall::optimize_call(address dest, bool mt_safe) {
// Skip over auipc + ld
address jmp_ins_pc = instruction_address() + 2 * NativeInstruction::instruction_size;
// Rutime calls may be unaligned, but they are never changed after relocation.
assert(!mt_safe || is_aligned(jmp_ins_pc, NativeInstruction::instruction_size), "Must be naturally aligned: %p", jmp_ins_pc);
// If reachable use JAL
if (Assembler::reachable_from_branch_at(jmp_ins_pc, dest)) {
int64_t distance = dest - jmp_ins_pc;
uint32_t new_jal = Assembler::encode_jal(ra, distance);
AtomicAccess::store((uint32_t *)jmp_ins_pc, new_jal);
} else if (!MacroAssembler::is_jalr_at(jmp_ins_pc)) { // The jalr is always identical: jalr ra, 0(t1)
uint32_t new_jalr = Assembler::encode_jalr(ra, t1, 0);
AtomicAccess::store((uint32_t *)jmp_ins_pc, new_jalr);
} else {
// No change to instruction stream
return;
}
// We changed instruction stream
if (mt_safe) {
// IC invalidate provides a leading full fence, it thus happens after we changed the instruction stream.
ICache::invalidate_range(jmp_ins_pc, NativeInstruction::instruction_size);
}
}
bool NativeCall::set_destination_mt_safe(address dest) {
assert(NativeCall::is_at(instruction_address()), "unexpected code at call site");
assert((CodeCache_lock->is_locked() || SafepointSynchronize::is_at_safepoint()) ||
@ -96,15 +122,17 @@ bool NativeCall::set_destination_mt_safe(address dest) {
"concurrent code patching");
address stub_addr = stub_address();
if (stub_addr != nullptr) {
set_stub_address_destination_at(stub_addr, dest);
return true;
}
assert(stub_addr != nullptr, "No stub?");
set_stub_address_destination_at(stub_addr, dest); // release
// optimize_call happens after we stored new address in addr stub.
// patches jalr -> jal/jal -> jalr depending on dest
optimize_call(dest, true);
return false;
return true;
}
bool NativeCall::reloc_set_destination(address dest) {
// The argument passed in is the address to the stub containing the destination
bool NativeCall::reloc_set_destination(address stub_addr) {
address call_addr = instruction_address();
assert(NativeCall::is_at(call_addr), "unexpected code at call site");
@ -113,10 +141,12 @@ bool NativeCall::reloc_set_destination(address dest) {
if (code->is_nmethod()) {
// TODO: Need to revisit this when porting the AOT features.
assert(dest != nullptr, "Sanity");
assert(dest == trampoline_stub_Relocation::get_trampoline_for(call_addr,
code->as_nmethod()), "Sanity");
MacroAssembler::pd_patch_instruction_size(call_addr, dest);
assert(stub_addr != nullptr, "Sanity");
assert(stub_addr == trampoline_stub_Relocation::get_trampoline_for(call_addr, code->as_nmethod()), "Sanity");
MacroAssembler::pd_patch_instruction_size(call_addr, stub_addr); // patches auipc + ld to stub_addr
address dest = stub_address_destination_at(stub_addr);
optimize_call(dest, false); // patches jalr -> jal/jal -> jalr depending on dest
}
return true;
@ -142,9 +172,9 @@ address NativeCall::stub_address() {
CodeBlob *code = CodeCache::find_blob(call_addr);
assert(code != nullptr, "Could not find the containing code blob");
address dest = MacroAssembler::target_addr_for_insn(call_addr);
assert(code->contains(dest), "Sanity");
return dest;
address stub_addr = MacroAssembler::target_addr_for_insn(call_addr);
assert(code->contains(stub_addr), "Sanity");
return stub_addr;
}
bool NativeCall::is_at(address addr) {
@ -160,6 +190,15 @@ bool NativeCall::is_at(address addr) {
(MacroAssembler::extract_rd(addr + 2 * instr_size) == x1)) {
return true;
}
if (MacroAssembler::is_auipc_at(addr) &&
MacroAssembler::is_ld_at(addr + instr_size) &&
MacroAssembler::is_jal_at(addr + 2 * instr_size) &&
(MacroAssembler::extract_rd(addr) == x6) &&
(MacroAssembler::extract_rd(addr + instr_size) == x6) &&
(MacroAssembler::extract_rs1(addr + instr_size) == x6) &&
(MacroAssembler::extract_rd(addr + 2 * instr_size) == x1)) {
return true;
}
return false;
}

View File

@ -156,6 +156,10 @@ class NativeCall: private NativeInstruction {
static void set_stub_address_destination_at(address dest, address value);
// return target address at stub
static address stub_address_destination_at(address src);
// We either have a jalr or jal depending on distance to old destination.
// This method emits a new jal if new destination is within jal reach.
// Otherwise restores the jalr which can reach any destination.
void optimize_call(address dest, bool mt_safe = true);
};
// An interface for accessing/manipulating native mov reg, imm instructions.

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