mirror of
https://github.com/openjdk/jdk.git
synced 2026-08-03 22:55:40 +00:00
Merge branch 'master' into JDK-8348611 to fix conflict.
This commit is contained in:
commit
a356d884b2
@ -5,3 +5,7 @@ trim_trailing_whitespace = true
|
||||
|
||||
[Makefile]
|
||||
trim_trailing_whitespace = true
|
||||
|
||||
[src/hotspot/**.{cpp,hpp,h}]
|
||||
indent_style = space
|
||||
indent_size = 2
|
||||
|
||||
@ -594,7 +594,7 @@ to compile successfully without issues.</p>
|
||||
</tr>
|
||||
<tr class="odd">
|
||||
<td>Windows</td>
|
||||
<td>Microsoft Visual Studio 2022 version 17.6.5</td>
|
||||
<td>Microsoft Visual Studio 2022 version 17.13.2</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
@ -390,11 +390,11 @@ possible to compile the JDK with both older and newer versions, but the closer
|
||||
you stay to this list, the more likely you are to compile successfully without
|
||||
issues.
|
||||
|
||||
| Operating system | Toolchain version |
|
||||
| ------------------ | ------------------------------------------- |
|
||||
| Linux | gcc 14.2.0 |
|
||||
| macOS | Apple Xcode 14.3.1 (using clang 14.0.3) |
|
||||
| Windows | Microsoft Visual Studio 2022 version 17.6.5 |
|
||||
| Operating system | Toolchain version |
|
||||
| ------------------ | -------------------------------------------- |
|
||||
| Linux | gcc 14.2.0 |
|
||||
| macOS | Apple Xcode 14.3.1 (using clang 14.0.3) |
|
||||
| Windows | Microsoft Visual Studio 2022 version 17.13.2 |
|
||||
|
||||
All compilers are expected to be able to handle the C11 language standard for
|
||||
C, and C++14 for C++.
|
||||
|
||||
@ -174,9 +174,11 @@ else
|
||||
JRE_IMAGE_HOMEDIR := $(JRE_IMAGE_DIR)
|
||||
JDK_BUNDLE_SUBDIR := jdk-$(VERSION_NUMBER)
|
||||
JRE_BUNDLE_SUBDIR := jre-$(VERSION_NUMBER)
|
||||
STATIC_JDK_BUNDLE_SUBDIR := static-jdk-$(VERSION_NUMBER)
|
||||
ifneq ($(DEBUG_LEVEL), release)
|
||||
JDK_BUNDLE_SUBDIR := $(JDK_BUNDLE_SUBDIR)/$(DEBUG_LEVEL)
|
||||
JRE_BUNDLE_SUBDIR := $(JRE_BUNDLE_SUBDIR)/$(DEBUG_LEVEL)
|
||||
STATIC_JDK_BUNDLE_SUBDIR := $(STATIC_JDK_BUNDLE_SUBDIR)/$(DEBUG_LEVEL)
|
||||
endif
|
||||
# In certain situations, the JDK_IMAGE_DIR points to an image without the
|
||||
# the symbols and demos. If so, the symobls and demos can be found in a
|
||||
@ -500,6 +502,21 @@ ifneq ($(filter static-libs-graal-bundles, $(MAKECMDGOALS)), )
|
||||
STATIC_LIBS_GRAAL_TARGETS += $(BUILD_STATIC_LIBS_GRAAL_BUNDLE)
|
||||
endif
|
||||
|
||||
#################################################################################
|
||||
|
||||
ifneq ($(filter static-jdk-bundles, $(MAKECMDGOALS)), )
|
||||
STATIC_JDK_BUNDLE_FILES := $(call FindFiles, $(STATIC_JDK_IMAGE_DIR))
|
||||
|
||||
$(eval $(call SetupBundleFile, BUILD_STATIC_JDK_BUNDLE, \
|
||||
BUNDLE_NAME := $(STATIC_JDK_BUNDLE_NAME), \
|
||||
FILES := $(STATIC_JDK_BUNDLE_FILES), \
|
||||
BASE_DIRS := $(STATIC_JDK_IMAGE_DIR), \
|
||||
SUBDIR := $(STATIC_JDK_BUNDLE_SUBDIR), \
|
||||
))
|
||||
|
||||
STATIC_JDK_TARGETS += $(BUILD_STATIC_JDK_BUNDLE)
|
||||
endif
|
||||
|
||||
################################################################################
|
||||
|
||||
product-bundles: $(PRODUCT_TARGETS)
|
||||
@ -510,11 +527,12 @@ docs-javase-bundles: $(DOCS_JAVASE_TARGETS)
|
||||
docs-reference-bundles: $(DOCS_REFERENCE_TARGETS)
|
||||
static-libs-bundles: $(STATIC_LIBS_TARGETS)
|
||||
static-libs-graal-bundles: $(STATIC_LIBS_GRAAL_TARGETS)
|
||||
static-jdk-bundles: $(STATIC_JDK_TARGETS)
|
||||
jcov-bundles: $(JCOV_TARGETS)
|
||||
|
||||
.PHONY: product-bundles test-bundles \
|
||||
docs-jdk-bundles docs-javase-bundles docs-reference-bundles \
|
||||
static-libs-bundles static-libs-graal-bundles jcov-bundles
|
||||
static-libs-bundles static-libs-graal-bundles static-jdk-bundles jcov-bundles
|
||||
|
||||
################################################################################
|
||||
|
||||
|
||||
@ -98,7 +98,7 @@ JAVADOC_DISABLED_DOCLINT_PACKAGES := org.w3c.* javax.smartcardio
|
||||
JAVADOC_OPTIONS := -use -keywords -notimestamp \
|
||||
-serialwarn -encoding ISO-8859-1 -docencoding UTF-8 -breakiterator \
|
||||
-splitIndex --system none -javafx --expand-requires transitive \
|
||||
--override-methods=summary
|
||||
--override-methods=summary --syntax-highlight
|
||||
|
||||
# The reference options must stay stable to allow for comparisons across the
|
||||
# development cycle.
|
||||
|
||||
@ -66,7 +66,7 @@ endif
|
||||
# default classlist is minimal, let's filter out the '@cp' lines until we can
|
||||
# find a proper solution.
|
||||
CLASSLIST_FILE_VM_OPTS = \
|
||||
-Duser.language=en -Duser.country=US
|
||||
-Duser.language=en -Duser.country=US --enable-native-access=ALL-UNNAMED
|
||||
|
||||
# Save the stderr output of the command and print it along with stdout in case
|
||||
# something goes wrong.
|
||||
|
||||
@ -875,6 +875,12 @@ $(eval $(call SetupTarget, static-libs-graal-bundles, \
|
||||
DEPS := static-libs-graal-image, \
|
||||
))
|
||||
|
||||
$(eval $(call SetupTarget, static-jdk-bundles, \
|
||||
MAKEFILE := Bundles, \
|
||||
TARGET := static-jdk-bundles, \
|
||||
DEPS := static-jdk-image, \
|
||||
))
|
||||
|
||||
ifeq ($(JCOV_ENABLED), true)
|
||||
$(eval $(call SetupTarget, jcov-bundles, \
|
||||
MAKEFILE := Bundles, \
|
||||
|
||||
@ -520,8 +520,21 @@ AC_DEFUN_ONCE([JDKOPT_SETUP_UNDEFINED_BEHAVIOR_SANITIZER],
|
||||
# Silence them for now.
|
||||
UBSAN_CHECKS="-fsanitize=undefined -fsanitize=float-divide-by-zero -fno-sanitize=shift-base -fno-sanitize=alignment \
|
||||
$ADDITIONAL_UBSAN_CHECKS"
|
||||
UBSAN_CFLAGS="$UBSAN_CHECKS -Wno-stringop-truncation -Wno-format-overflow -Wno-array-bounds -Wno-stringop-overflow -fno-omit-frame-pointer -DUNDEFINED_BEHAVIOR_SANITIZER"
|
||||
UBSAN_CFLAGS="$UBSAN_CHECKS -Wno-array-bounds -fno-omit-frame-pointer -DUNDEFINED_BEHAVIOR_SANITIZER"
|
||||
if test "x$TOOLCHAIN_TYPE" = "xgcc"; then
|
||||
UBSAN_CFLAGS="$UBSAN_CFLAGS -Wno-format-overflow -Wno-stringop-overflow -Wno-stringop-truncation"
|
||||
fi
|
||||
UBSAN_LDFLAGS="$UBSAN_CHECKS"
|
||||
# On AIX, the llvm_symbolizer is not found out of the box, so we have to provide the
|
||||
# full qualified llvm_symbolizer path in the __ubsan_default_options() function in
|
||||
# make/data/ubsan/ubsan_default_options.c. To get it there we compile our sources
|
||||
# with an additional define LLVM_SYMBOLIZER, which we set here.
|
||||
# To calculate the correct llvm_symbolizer path we can use the location of the compiler, because
|
||||
# their relation is fixed.
|
||||
if test "x$TOOLCHAIN_TYPE" = "xclang" && test "x$OPENJDK_TARGET_OS" = "xaix"; then
|
||||
UBSAN_CFLAGS="$UBSAN_CFLAGS -fno-sanitize=function,vptr -DLLVM_SYMBOLIZER=$(dirname $(dirname $CC))/tools/ibm-llvm-symbolizer"
|
||||
UBSAN_LDFLAGS="$UBSAN_LDFLAGS -fno-sanitize=function,vptr -Wl,-bbigtoc"
|
||||
fi
|
||||
UTIL_ARG_ENABLE(NAME: ubsan, DEFAULT: false, RESULT: UBSAN_ENABLED,
|
||||
DESC: [enable UndefinedBehaviorSanitizer],
|
||||
CHECK_AVAILABLE: [
|
||||
|
||||
@ -846,10 +846,12 @@ SVE_CFLAGS := @SVE_CFLAGS@
|
||||
JDK_IMAGE_SUBDIR := jdk
|
||||
JRE_IMAGE_SUBDIR := jre
|
||||
JCOV_IMAGE_SUBDIR := jdk-jcov
|
||||
STATIC_JDK_IMAGE_SUBDIR := static-jdk
|
||||
|
||||
# Colon left out to be able to override output dir for bootcycle-images
|
||||
JDK_IMAGE_DIR = $(IMAGES_OUTPUTDIR)/$(JDK_IMAGE_SUBDIR)
|
||||
JRE_IMAGE_DIR = $(IMAGES_OUTPUTDIR)/$(JRE_IMAGE_SUBDIR)
|
||||
STATIC_JDK_IMAGE_DIR = $(IMAGES_OUTPUTDIR)/$(STATIC_JDK_IMAGE_SUBDIR)
|
||||
JCOV_IMAGE_DIR = $(IMAGES_OUTPUTDIR)/$(JCOV_IMAGE_SUBDIR)
|
||||
|
||||
# Test image, as above
|
||||
@ -929,6 +931,7 @@ DOCS_JAVASE_BUNDLE_NAME := javase-$(BASE_NAME)_doc-api-spec$(DEBUG_PART).tar.gz
|
||||
DOCS_REFERENCE_BUNDLE_NAME := jdk-reference-$(BASE_NAME)_doc-api-spec$(DEBUG_PART).tar.gz
|
||||
STATIC_LIBS_BUNDLE_NAME := jdk-$(BASE_NAME)_bin-static-libs$(DEBUG_PART).tar.gz
|
||||
STATIC_LIBS_GRAAL_BUNDLE_NAME := jdk-$(BASE_NAME)_bin-static-libs-graal$(DEBUG_PART).tar.gz
|
||||
STATIC_JDK_BUNDLE_NAME := static-jdk-$(BASE_NAME)_bin$(DEBUG_PART).$(JDK_BUNDLE_EXTENSION)
|
||||
JCOV_BUNDLE_NAME := jdk-jcov-$(BASE_NAME)_bin$(DEBUG_PART).$(JDK_BUNDLE_EXTENSION)
|
||||
|
||||
JDK_BUNDLE := $(BUNDLES_OUTPUTDIR)/$(JDK_BUNDLE_NAME)
|
||||
@ -939,6 +942,7 @@ TEST_BUNDLE := $(BUNDLES_OUTPUTDIR)/$(TEST_BUNDLE_NAME)
|
||||
DOCS_JDK_BUNDLE := $(BUNDLES_OUTPUTDIR)/$(DOCS_JDK_BUNDLE_NAME)
|
||||
DOCS_JAVASE_BUNDLE := $(BUNDLES_OUTPUTDIR)/$(DOCS_JAVASE_BUNDLE_NAME)
|
||||
DOCS_REFERENCE_BUNDLE := $(BUNDLES_OUTPUTDIR)/$(DOCS_REFERENCE_BUNDLE_NAME)
|
||||
STATIC_JDK_BUNDLE := $(BUNDLES_OUTPUTDIR)/$(STATIC_JDK_BUNDLE_NAME)
|
||||
JCOV_BUNDLE := $(BUNDLES_OUTPUTDIR)/$(JCOV_BUNDLE_NAME)
|
||||
|
||||
# This macro is called to allow inclusion of closed source counterparts.
|
||||
|
||||
@ -1090,7 +1090,7 @@ var getJibProfilesDependencies = function (input, common) {
|
||||
var devkit_platform_revisions = {
|
||||
linux_x64: "gcc14.2.0-OL6.4+1.0",
|
||||
macosx: "Xcode14.3.1+1.0",
|
||||
windows_x64: "VS2022-17.6.5+1.0",
|
||||
windows_x64: "VS2022-17.13.2+1.0",
|
||||
linux_aarch64: "gcc14.2.0-OL7.6+1.0",
|
||||
linux_arm: "gcc8.2.0-Fedora27+1.0",
|
||||
linux_ppc64le: "gcc14.2.0-Fedora_41+1.0",
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2022, 2023, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2022, 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
|
||||
@ -43,6 +43,18 @@
|
||||
#define ATTRIBUTE_USED
|
||||
#endif
|
||||
|
||||
// On AIX, the llvm_symbolizer is not found out of the box, so we have to provide the
|
||||
// full qualified llvm_symbolizer path in the __ubsan_default_options() function.
|
||||
// To get it here we compile our sources with an additional define LLVM_SYMBOLIZER
|
||||
// containing the path, which we set in make/autoconf/jdk-options.m4.
|
||||
#ifdef LLVM_SYMBOLIZER
|
||||
#define _LLVM_SYMBOLIZER(X) ",external_symbolizer_path=" X_LLVM_SYMBOLIZER(X)
|
||||
#define X_LLVM_SYMBOLIZER(X) #X
|
||||
#else
|
||||
#define LLVM_SYMBOLIZER
|
||||
#define _LLVM_SYMBOLIZER(X)
|
||||
#endif
|
||||
|
||||
// Override weak symbol exposed by UBSan to override default options. This is called by UBSan
|
||||
// extremely early during library loading, before main is called. We need to override the default
|
||||
// options because by default UBSan only prints a warning for each occurrence. We want jtreg tests
|
||||
@ -50,5 +62,5 @@
|
||||
// thread so it is easier to track down. You can override these options by setting the environment
|
||||
// variable UBSAN_OPTIONS.
|
||||
ATTRIBUTE_DEFAULT_VISIBILITY ATTRIBUTE_USED const char* __ubsan_default_options() {
|
||||
return "halt_on_error=1,print_stacktrace=1";
|
||||
return "halt_on_error=1,print_stacktrace=1" _LLVM_SYMBOLIZER(LLVM_SYMBOLIZER);
|
||||
}
|
||||
|
||||
@ -56,16 +56,22 @@ BUILD_DIR="${SCRIPT_DIR}/../../build/devkit"
|
||||
|
||||
UNAME_SYSTEM=`uname -s`
|
||||
UNAME_RELEASE=`uname -r`
|
||||
UNAME_OS=`uname -o`
|
||||
|
||||
# Detect cygwin or WSL
|
||||
IS_CYGWIN=`echo $UNAME_SYSTEM | grep -i CYGWIN`
|
||||
IS_WSL=`echo $UNAME_RELEASE | grep Microsoft`
|
||||
IS_MSYS=`echo $UNAME_OS | grep -i Msys`
|
||||
MSYS2_ARG_CONV_EXCL="*" # make "cmd.exe /c" work for msys2
|
||||
CMD_EXE="cmd.exe /c"
|
||||
if test "x$IS_CYGWIN" != "x"; then
|
||||
BUILD_ENV="cygwin"
|
||||
elif test "x$IS_MSYS" != "x"; then
|
||||
BUILD_ENV="cygwin"
|
||||
elif test "x$IS_WSL" != "x"; then
|
||||
BUILD_ENV="wsl"
|
||||
else
|
||||
echo "Unknown environment; only Cygwin and WSL are supported."
|
||||
echo "Unknown environment; only Cygwin/MSYS2/WSL are supported."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
@ -76,7 +82,7 @@ elif test "x$BUILD_ENV" = "xwsl"; then
|
||||
fi
|
||||
|
||||
# Work around the insanely named ProgramFiles(x86) env variable
|
||||
PROGRAMFILES_X86="$($WINDOWS_PATH_TO_UNIX_PATH "$(cmd.exe /c set | sed -n 's/^ProgramFiles(x86)=//p' | tr -d '\r')")"
|
||||
PROGRAMFILES_X86="$($WINDOWS_PATH_TO_UNIX_PATH "$(${CMD_EXE} set | sed -n 's/^ProgramFiles(x86)=//p' | tr -d '\r')")"
|
||||
PROGRAMFILES="$($WINDOWS_PATH_TO_UNIX_PATH "$PROGRAMFILES")"
|
||||
|
||||
case $VS_VERSION in
|
||||
@ -99,13 +105,15 @@ esac
|
||||
|
||||
|
||||
# Find Visual Studio installation dir
|
||||
VSNNNCOMNTOOLS=`cmd.exe /c echo %VS${VS_VERSION_NUM_NODOT}COMNTOOLS% | tr -d '\r'`
|
||||
VSNNNCOMNTOOLS=`${CMD_EXE} echo %VS${VS_VERSION_NUM_NODOT}COMNTOOLS% | tr -d '\r'`
|
||||
VSNNNCOMNTOOLS="$($WINDOWS_PATH_TO_UNIX_PATH "$VSNNNCOMNTOOLS")"
|
||||
if [ -d "$VSNNNCOMNTOOLS" ]; then
|
||||
VS_INSTALL_DIR="$($WINDOWS_PATH_TO_UNIX_PATH "$VSNNNCOMNTOOLS/../..")"
|
||||
VS_INSTALL_DIR="$VSNNNCOMNTOOLS/../.."
|
||||
else
|
||||
VS_INSTALL_DIR="${MSVC_PROGRAMFILES_DIR}/Microsoft Visual Studio/$VS_VERSION"
|
||||
VS_INSTALL_DIR="$(ls -d "${VS_INSTALL_DIR}/"{Community,Professional,Enterprise} 2>/dev/null | head -n1)"
|
||||
fi
|
||||
echo "VSNNNCOMNTOOLS: $VSNNNCOMNTOOLS"
|
||||
echo "VS_INSTALL_DIR: $VS_INSTALL_DIR"
|
||||
|
||||
# Extract semantic version
|
||||
@ -180,7 +188,11 @@ cp $DEVKIT_ROOT/VC/redist/arm64/$MSVCP_DLL $DEVKIT_ROOT/VC/bin/arm64
|
||||
################################################################################
|
||||
# Copy SDK files
|
||||
|
||||
SDK_INSTALL_DIR="$PROGRAMFILES_X86/Windows Kits/$SDK_VERSION"
|
||||
SDK_INSTALL_DIR=`${CMD_EXE} echo %WindowsSdkDir% | tr -d '\r'`
|
||||
SDK_INSTALL_DIR="$($WINDOWS_PATH_TO_UNIX_PATH "$SDK_INSTALL_DIR")"
|
||||
if [ ! -d "$SDK_INSTALL_DIR" ]; then
|
||||
SDK_INSTALL_DIR="$PROGRAMFILES_X86/Windows Kits/$SDK_VERSION"
|
||||
fi
|
||||
echo "SDK_INSTALL_DIR: $SDK_INSTALL_DIR"
|
||||
|
||||
SDK_FULL_VERSION="$(ls "$SDK_INSTALL_DIR/bin" | sort -r -n | head -n1)"
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2016, 2024, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2016, 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
|
||||
@ -31,6 +31,8 @@
|
||||
*/
|
||||
package build.tools.classlist;
|
||||
|
||||
import java.lang.foreign.FunctionDescriptor;
|
||||
import java.lang.foreign.Linker;
|
||||
import java.lang.invoke.MethodHandle;
|
||||
import java.lang.invoke.MethodHandles;
|
||||
import java.lang.invoke.MethodType;
|
||||
@ -59,6 +61,7 @@ public class HelloClasslist {
|
||||
|
||||
private static final Logger LOGGER = Logger.getLogger("Hello");
|
||||
|
||||
@SuppressWarnings("restricted")
|
||||
public static void main(String ... args) throws Throwable {
|
||||
|
||||
FileSystems.getDefault();
|
||||
@ -141,6 +144,7 @@ public class HelloClasslist {
|
||||
HelloClasslist.class.getMethod("staticMethod_V").invoke(null);
|
||||
var obj = HelloClasslist.class.getMethod("staticMethod_L_L", Object.class).invoke(null, instance);
|
||||
HelloClasslist.class.getField("field").get(instance);
|
||||
MethodHandles.Lookup.ClassOption.class.getEnumConstants();
|
||||
|
||||
// A selection of trivial and relatively common MH operations
|
||||
invoke(MethodHandles.identity(double.class), 1.0);
|
||||
@ -160,6 +164,9 @@ public class HelloClasslist {
|
||||
case B b -> b.b;
|
||||
default -> 17;
|
||||
};
|
||||
// record run-time methods
|
||||
o.equals(new B(5));
|
||||
o.hashCode();
|
||||
LOGGER.log(Level.FINE, "Value: " + value);
|
||||
|
||||
// The Striped64$Cell is loaded rarely only when there's a contention among
|
||||
@ -167,6 +174,10 @@ public class HelloClasslist {
|
||||
// an inconsistency in the classlist between builds (see JDK-8295951).
|
||||
// To avoid the problem, load the class explicitly.
|
||||
Class<?> striped64Class = Class.forName("java.util.concurrent.atomic.Striped64$Cell");
|
||||
|
||||
// Initialize FFM linkers
|
||||
var signature = FunctionDescriptor.ofVoid();
|
||||
Linker.nativeLinker().downcallHandle(signature);
|
||||
}
|
||||
|
||||
public HelloClasslist() {}
|
||||
|
||||
@ -158,6 +158,7 @@ endif
|
||||
|
||||
$(eval $(call SetupJdkLibrary, BUILD_LIBSYSLOOKUP, \
|
||||
NAME := syslookup, \
|
||||
EXTRA_HEADER_DIRS := java.base:libjava, \
|
||||
LD_SET_ORIGIN := false, \
|
||||
LDFLAGS_linux := -Wl$(COMMA)--no-as-needed, \
|
||||
LDFLAGS_aix := -brtl -bexpfull, \
|
||||
|
||||
@ -1,3 +0,0 @@
|
||||
[*.{cpp,hpp,c,h}]
|
||||
indent_style = space
|
||||
indent_size = 2
|
||||
@ -1,5 +1,5 @@
|
||||
//
|
||||
// Copyright (c) 2003, 2024, Oracle and/or its affiliates. All rights reserved.
|
||||
// Copyright (c) 2003, 2025, Oracle and/or its affiliates. All rights reserved.
|
||||
// Copyright (c) 2014, 2024, Red Hat, Inc. All rights reserved.
|
||||
// DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
//
|
||||
@ -2296,6 +2296,26 @@ bool Matcher::match_rule_supported(int opcode) {
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
case Op_FmaHF:
|
||||
// UseFMA flag also needs to be checked along with FEAT_FP16
|
||||
if (!UseFMA || !is_feat_fp16_supported()) {
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
case Op_AddHF:
|
||||
case Op_SubHF:
|
||||
case Op_MulHF:
|
||||
case Op_DivHF:
|
||||
case Op_MinHF:
|
||||
case Op_MaxHF:
|
||||
case Op_SqrtHF:
|
||||
// Half-precision floating point scalar operations require FEAT_FP16
|
||||
// to be available. FEAT_FP16 is enabled if both "fphp" and "asimdhp"
|
||||
// features are supported.
|
||||
if (!is_feat_fp16_supported()) {
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
return true; // Per default match rules are supported.
|
||||
@ -2306,11 +2326,11 @@ const RegMask* Matcher::predicate_reg_mask(void) {
|
||||
}
|
||||
|
||||
bool Matcher::supports_vector_calling_convention(void) {
|
||||
return EnableVectorSupport && UseVectorStubs;
|
||||
return EnableVectorSupport;
|
||||
}
|
||||
|
||||
OptoRegPair Matcher::vector_return_value(uint ideal_reg) {
|
||||
assert(EnableVectorSupport && UseVectorStubs, "sanity");
|
||||
assert(EnableVectorSupport, "sanity");
|
||||
int lo = V0_num;
|
||||
int hi = V0_H_num;
|
||||
if (ideal_reg == Op_VecX || ideal_reg == Op_VecA) {
|
||||
@ -4599,6 +4619,15 @@ operand immF0()
|
||||
interface(CONST_INTER);
|
||||
%}
|
||||
|
||||
// Half Float (FP16) Immediate
|
||||
operand immH()
|
||||
%{
|
||||
match(ConH);
|
||||
op_cost(0);
|
||||
format %{ %}
|
||||
interface(CONST_INTER);
|
||||
%}
|
||||
|
||||
//
|
||||
operand immFPacked()
|
||||
%{
|
||||
@ -6942,6 +6971,21 @@ instruct loadConD(vRegD dst, immD con) %{
|
||||
ins_pipe(fp_load_constant_d);
|
||||
%}
|
||||
|
||||
// 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"
|
||||
%}
|
||||
ins_encode %{
|
||||
__ ldrs(as_FloatRegister($dst$$reg), $constantaddress($con));
|
||||
%}
|
||||
ins_pipe(fp_load_constant_s);
|
||||
%}
|
||||
|
||||
// Store Instructions
|
||||
|
||||
// Store Byte
|
||||
@ -8144,6 +8188,7 @@ instruct castPP(iRegPNoSp dst)
|
||||
|
||||
instruct castII(iRegI dst)
|
||||
%{
|
||||
predicate(VerifyConstraintCasts == 0);
|
||||
match(Set dst (CastII dst));
|
||||
|
||||
size(0);
|
||||
@ -8153,8 +8198,22 @@ instruct castII(iRegI dst)
|
||||
ins_pipe(pipe_class_empty);
|
||||
%}
|
||||
|
||||
instruct castII_checked(iRegI dst, rFlagsReg cr)
|
||||
%{
|
||||
predicate(VerifyConstraintCasts > 0);
|
||||
match(Set dst (CastII dst));
|
||||
effect(KILL cr);
|
||||
|
||||
format %{ "# castII_checked of $dst" %}
|
||||
ins_encode %{
|
||||
__ verify_int_in_range(_idx, bottom_type()->is_int(), $dst$$Register, rscratch1);
|
||||
%}
|
||||
ins_pipe(pipe_slow);
|
||||
%}
|
||||
|
||||
instruct castLL(iRegL dst)
|
||||
%{
|
||||
predicate(VerifyConstraintCasts == 0);
|
||||
match(Set dst (CastLL dst));
|
||||
|
||||
size(0);
|
||||
@ -8164,6 +8223,19 @@ instruct castLL(iRegL dst)
|
||||
ins_pipe(pipe_class_empty);
|
||||
%}
|
||||
|
||||
instruct castLL_checked(iRegL dst, rFlagsReg cr)
|
||||
%{
|
||||
predicate(VerifyConstraintCasts > 0);
|
||||
match(Set dst (CastLL dst));
|
||||
effect(KILL cr);
|
||||
|
||||
format %{ "# castLL_checked of $dst" %}
|
||||
ins_encode %{
|
||||
__ verify_long_in_range(_idx, bottom_type()->is_long(), $dst$$Register, rscratch1);
|
||||
%}
|
||||
ins_pipe(pipe_slow);
|
||||
%}
|
||||
|
||||
instruct castFF(vRegF dst)
|
||||
%{
|
||||
match(Set dst (CastFF dst));
|
||||
@ -13606,6 +13678,17 @@ instruct bits_reverse_L(iRegLNoSp dst, iRegL src)
|
||||
// ============================================================================
|
||||
// Floating Point Arithmetic Instructions
|
||||
|
||||
instruct addHF_reg_reg(vRegF dst, vRegF src1, vRegF src2) %{
|
||||
match(Set dst (AddHF src1 src2));
|
||||
format %{ "faddh $dst, $src1, $src2" %}
|
||||
ins_encode %{
|
||||
__ faddh($dst$$FloatRegister,
|
||||
$src1$$FloatRegister,
|
||||
$src2$$FloatRegister);
|
||||
%}
|
||||
ins_pipe(fp_dop_reg_reg_s);
|
||||
%}
|
||||
|
||||
instruct addF_reg_reg(vRegF dst, vRegF src1, vRegF src2) %{
|
||||
match(Set dst (AddF src1 src2));
|
||||
|
||||
@ -13636,6 +13719,17 @@ instruct addD_reg_reg(vRegD dst, vRegD src1, vRegD src2) %{
|
||||
ins_pipe(fp_dop_reg_reg_d);
|
||||
%}
|
||||
|
||||
instruct subHF_reg_reg(vRegF dst, vRegF src1, vRegF src2) %{
|
||||
match(Set dst (SubHF src1 src2));
|
||||
format %{ "fsubh $dst, $src1, $src2" %}
|
||||
ins_encode %{
|
||||
__ fsubh($dst$$FloatRegister,
|
||||
$src1$$FloatRegister,
|
||||
$src2$$FloatRegister);
|
||||
%}
|
||||
ins_pipe(fp_dop_reg_reg_s);
|
||||
%}
|
||||
|
||||
instruct subF_reg_reg(vRegF dst, vRegF src1, vRegF src2) %{
|
||||
match(Set dst (SubF src1 src2));
|
||||
|
||||
@ -13666,6 +13760,17 @@ instruct subD_reg_reg(vRegD dst, vRegD src1, vRegD src2) %{
|
||||
ins_pipe(fp_dop_reg_reg_d);
|
||||
%}
|
||||
|
||||
instruct mulHF_reg_reg(vRegF dst, vRegF src1, vRegF src2) %{
|
||||
match(Set dst (MulHF src1 src2));
|
||||
format %{ "fmulh $dst, $src1, $src2" %}
|
||||
ins_encode %{
|
||||
__ fmulh($dst$$FloatRegister,
|
||||
$src1$$FloatRegister,
|
||||
$src2$$FloatRegister);
|
||||
%}
|
||||
ins_pipe(fp_dop_reg_reg_s);
|
||||
%}
|
||||
|
||||
instruct mulF_reg_reg(vRegF dst, vRegF src1, vRegF src2) %{
|
||||
match(Set dst (MulF src1 src2));
|
||||
|
||||
@ -13696,6 +13801,20 @@ instruct mulD_reg_reg(vRegD dst, vRegD src1, vRegD src2) %{
|
||||
ins_pipe(fp_dop_reg_reg_d);
|
||||
%}
|
||||
|
||||
// src1 * src2 + src3 (half-precision float)
|
||||
instruct maddHF_reg_reg(vRegF dst, vRegF src1, vRegF src2, vRegF src3) %{
|
||||
match(Set dst (FmaHF src3 (Binary src1 src2)));
|
||||
format %{ "fmaddh $dst, $src1, $src2, $src3" %}
|
||||
ins_encode %{
|
||||
assert(UseFMA, "Needs FMA instructions support.");
|
||||
__ fmaddh($dst$$FloatRegister,
|
||||
$src1$$FloatRegister,
|
||||
$src2$$FloatRegister,
|
||||
$src3$$FloatRegister);
|
||||
%}
|
||||
ins_pipe(pipe_class_default);
|
||||
%}
|
||||
|
||||
// src1 * src2 + src3
|
||||
instruct maddF_reg_reg(vRegF dst, vRegF src1, vRegF src2, vRegF src3) %{
|
||||
match(Set dst (FmaF src3 (Binary src1 src2)));
|
||||
@ -13837,6 +13956,29 @@ instruct mnsubD_reg_reg(vRegD dst, vRegD src1, vRegD src2, vRegD src3, immD0 zer
|
||||
ins_pipe(pipe_class_default);
|
||||
%}
|
||||
|
||||
// Math.max(HH)H (half-precision float)
|
||||
instruct maxHF_reg_reg(vRegF dst, vRegF src1, vRegF src2) %{
|
||||
match(Set dst (MaxHF src1 src2));
|
||||
format %{ "fmaxh $dst, $src1, $src2" %}
|
||||
ins_encode %{
|
||||
__ fmaxh($dst$$FloatRegister,
|
||||
$src1$$FloatRegister,
|
||||
$src2$$FloatRegister);
|
||||
%}
|
||||
ins_pipe(fp_dop_reg_reg_s);
|
||||
%}
|
||||
|
||||
// Math.min(HH)H (half-precision float)
|
||||
instruct minHF_reg_reg(vRegF dst, vRegF src1, vRegF src2) %{
|
||||
match(Set dst (MinHF src1 src2));
|
||||
format %{ "fminh $dst, $src1, $src2" %}
|
||||
ins_encode %{
|
||||
__ fminh($dst$$FloatRegister,
|
||||
$src1$$FloatRegister,
|
||||
$src2$$FloatRegister);
|
||||
%}
|
||||
ins_pipe(fp_dop_reg_reg_s);
|
||||
%}
|
||||
|
||||
// Math.max(FF)F
|
||||
instruct maxF_reg_reg(vRegF dst, vRegF src1, vRegF src2) %{
|
||||
@ -13894,6 +14036,16 @@ instruct minD_reg_reg(vRegD dst, vRegD src1, vRegD src2) %{
|
||||
ins_pipe(fp_dop_reg_reg_d);
|
||||
%}
|
||||
|
||||
instruct divHF_reg_reg(vRegF dst, vRegF src1, vRegF src2) %{
|
||||
match(Set dst (DivHF src1 src2));
|
||||
format %{ "fdivh $dst, $src1, $src2" %}
|
||||
ins_encode %{
|
||||
__ fdivh($dst$$FloatRegister,
|
||||
$src1$$FloatRegister,
|
||||
$src2$$FloatRegister);
|
||||
%}
|
||||
ins_pipe(fp_div_s);
|
||||
%}
|
||||
|
||||
instruct divF_reg_reg(vRegF dst, vRegF src1, vRegF src2) %{
|
||||
match(Set dst (DivF src1 src2));
|
||||
@ -14067,6 +14219,16 @@ instruct sqrtF_reg(vRegF dst, vRegF src) %{
|
||||
ins_pipe(fp_div_d);
|
||||
%}
|
||||
|
||||
instruct sqrtHF_reg(vRegF dst, vRegF src) %{
|
||||
match(Set dst (SqrtHF src));
|
||||
format %{ "fsqrth $dst, $src" %}
|
||||
ins_encode %{
|
||||
__ fsqrth($dst$$FloatRegister,
|
||||
$src$$FloatRegister);
|
||||
%}
|
||||
ins_pipe(fp_div_s);
|
||||
%}
|
||||
|
||||
// Math.rint, floor, ceil
|
||||
instruct roundD_reg(vRegD dst, vRegD src, immI rmode) %{
|
||||
match(Set dst (RoundDoubleMode src rmode));
|
||||
@ -17116,6 +17278,64 @@ instruct expandBitsL_memcon(iRegINoSp dst, memory8 mem, immL mask,
|
||||
ins_pipe(pipe_slow);
|
||||
%}
|
||||
|
||||
//----------------------------- Reinterpret ----------------------------------
|
||||
// Reinterpret a half-precision float value in a floating point register to a general purpose register
|
||||
instruct reinterpretHF2S(iRegINoSp dst, vRegF src) %{
|
||||
match(Set dst (ReinterpretHF2S src));
|
||||
format %{ "reinterpretHF2S $dst, $src" %}
|
||||
ins_encode %{
|
||||
__ smov($dst$$Register, $src$$FloatRegister, __ H, 0);
|
||||
%}
|
||||
ins_pipe(pipe_slow);
|
||||
%}
|
||||
|
||||
// Reinterpret a half-precision float value in a general purpose register to a floating point register
|
||||
instruct reinterpretS2HF(vRegF dst, iRegINoSp src) %{
|
||||
match(Set dst (ReinterpretS2HF src));
|
||||
format %{ "reinterpretS2HF $dst, $src" %}
|
||||
ins_encode %{
|
||||
__ mov($dst$$FloatRegister, __ H, 0, $src$$Register);
|
||||
%}
|
||||
ins_pipe(pipe_slow);
|
||||
%}
|
||||
|
||||
// Without this optimization, ReinterpretS2HF (ConvF2HF src) would result in the following
|
||||
// instructions (the first two are for ConvF2HF and the last instruction is for ReinterpretS2HF) -
|
||||
// fcvt $tmp1_fpr, $src_fpr // Convert float to half-precision float
|
||||
// mov $tmp2_gpr, $tmp1_fpr // Move half-precision float in FPR to a GPR
|
||||
// mov $dst_fpr, $tmp2_gpr // Move the result from a GPR to an FPR
|
||||
// The move from FPR to GPR in ConvF2HF and the move from GPR to FPR in ReinterpretS2HF
|
||||
// can be omitted in this pattern, resulting in -
|
||||
// fcvt $dst, $src // Convert float to half-precision float
|
||||
instruct convF2HFAndS2HF(vRegF dst, vRegF src)
|
||||
%{
|
||||
match(Set dst (ReinterpretS2HF (ConvF2HF src)));
|
||||
format %{ "convF2HFAndS2HF $dst, $src" %}
|
||||
ins_encode %{
|
||||
__ fcvtsh($dst$$FloatRegister, $src$$FloatRegister);
|
||||
%}
|
||||
ins_pipe(pipe_slow);
|
||||
%}
|
||||
|
||||
// Without this optimization, ConvHF2F (ReinterpretHF2S src) would result in the following
|
||||
// instructions (the first one is for ReinterpretHF2S and the last two are for ConvHF2F) -
|
||||
// mov $tmp1_gpr, $src_fpr // Move the half-precision float from an FPR to a GPR
|
||||
// mov $tmp2_fpr, $tmp1_gpr // Move the same value from GPR to an FPR
|
||||
// fcvt $dst_fpr, $tmp2_fpr // Convert the half-precision float to 32-bit float
|
||||
// The move from FPR to GPR in ReinterpretHF2S and the move from GPR to FPR in ConvHF2F
|
||||
// can be omitted as the input (src) is already in an FPR required for the fcvths instruction
|
||||
// resulting in -
|
||||
// fcvt $dst, $src // Convert half-precision float to a 32-bit float
|
||||
instruct convHF2SAndHF2F(vRegF dst, vRegF src)
|
||||
%{
|
||||
match(Set dst (ConvHF2F (ReinterpretHF2S src)));
|
||||
format %{ "convHF2SAndHF2F $dst, $src" %}
|
||||
ins_encode %{
|
||||
__ fcvths($dst$$FloatRegister, $src$$FloatRegister);
|
||||
%}
|
||||
ins_pipe(pipe_slow);
|
||||
%}
|
||||
|
||||
// ============================================================================
|
||||
// This name is KNOWN by the ADLC and cannot be changed.
|
||||
// The ADLC forces a 'TypeRawPtr::BOTTOM' output type
|
||||
|
||||
@ -2032,6 +2032,8 @@ void mvnw(Register Rd, Register Rm,
|
||||
INSN(fsqrtd, 0b01, 0b000011);
|
||||
INSN(fcvtd, 0b01, 0b000100); // Double-precision to single-precision
|
||||
|
||||
INSN(fsqrth, 0b11, 0b000011); // Half-precision sqrt
|
||||
|
||||
private:
|
||||
void _fcvt_narrow_extend(FloatRegister Vd, SIMD_Arrangement Ta,
|
||||
FloatRegister Vn, SIMD_Arrangement Tb, bool do_extend) {
|
||||
@ -2059,37 +2061,68 @@ public:
|
||||
#undef INSN
|
||||
|
||||
// Floating-point data-processing (2 source)
|
||||
void data_processing(unsigned op31, unsigned type, unsigned opcode,
|
||||
void data_processing(unsigned op31, unsigned type, unsigned opcode, unsigned op21,
|
||||
FloatRegister Vd, FloatRegister Vn, FloatRegister Vm) {
|
||||
starti;
|
||||
f(op31, 31, 29);
|
||||
f(0b11110, 28, 24);
|
||||
f(type, 23, 22), f(1, 21), f(opcode, 15, 10);
|
||||
f(type, 23, 22), f(op21, 21), f(opcode, 15, 10);
|
||||
rf(Vm, 16), rf(Vn, 5), rf(Vd, 0);
|
||||
}
|
||||
|
||||
#define INSN(NAME, op31, type, opcode) \
|
||||
#define INSN(NAME, op31, type, opcode, op21) \
|
||||
void NAME(FloatRegister Vd, FloatRegister Vn, FloatRegister Vm) { \
|
||||
data_processing(op31, type, opcode, Vd, Vn, Vm); \
|
||||
data_processing(op31, type, opcode, op21, Vd, Vn, Vm); \
|
||||
}
|
||||
|
||||
INSN(fabds, 0b011, 0b10, 0b110101);
|
||||
INSN(fmuls, 0b000, 0b00, 0b000010);
|
||||
INSN(fdivs, 0b000, 0b00, 0b000110);
|
||||
INSN(fadds, 0b000, 0b00, 0b001010);
|
||||
INSN(fsubs, 0b000, 0b00, 0b001110);
|
||||
INSN(fmaxs, 0b000, 0b00, 0b010010);
|
||||
INSN(fmins, 0b000, 0b00, 0b010110);
|
||||
INSN(fnmuls, 0b000, 0b00, 0b100010);
|
||||
INSN(fmuls, 0b000, 0b00, 0b000010, 0b1);
|
||||
INSN(fdivs, 0b000, 0b00, 0b000110, 0b1);
|
||||
INSN(fadds, 0b000, 0b00, 0b001010, 0b1);
|
||||
INSN(fsubs, 0b000, 0b00, 0b001110, 0b1);
|
||||
INSN(fmaxs, 0b000, 0b00, 0b010010, 0b1);
|
||||
INSN(fmins, 0b000, 0b00, 0b010110, 0b1);
|
||||
INSN(fnmuls, 0b000, 0b00, 0b100010, 0b1);
|
||||
|
||||
INSN(fabdd, 0b011, 0b11, 0b110101);
|
||||
INSN(fmuld, 0b000, 0b01, 0b000010);
|
||||
INSN(fdivd, 0b000, 0b01, 0b000110);
|
||||
INSN(faddd, 0b000, 0b01, 0b001010);
|
||||
INSN(fsubd, 0b000, 0b01, 0b001110);
|
||||
INSN(fmaxd, 0b000, 0b01, 0b010010);
|
||||
INSN(fmind, 0b000, 0b01, 0b010110);
|
||||
INSN(fnmuld, 0b000, 0b01, 0b100010);
|
||||
INSN(fmuld, 0b000, 0b01, 0b000010, 0b1);
|
||||
INSN(fdivd, 0b000, 0b01, 0b000110, 0b1);
|
||||
INSN(faddd, 0b000, 0b01, 0b001010, 0b1);
|
||||
INSN(fsubd, 0b000, 0b01, 0b001110, 0b1);
|
||||
INSN(fmaxd, 0b000, 0b01, 0b010010, 0b1);
|
||||
INSN(fmind, 0b000, 0b01, 0b010110, 0b1);
|
||||
INSN(fnmuld, 0b000, 0b01, 0b100010, 0b1);
|
||||
|
||||
// Half-precision floating-point instructions
|
||||
INSN(fmulh, 0b000, 0b11, 0b000010, 0b1);
|
||||
INSN(fdivh, 0b000, 0b11, 0b000110, 0b1);
|
||||
INSN(faddh, 0b000, 0b11, 0b001010, 0b1);
|
||||
INSN(fsubh, 0b000, 0b11, 0b001110, 0b1);
|
||||
INSN(fmaxh, 0b000, 0b11, 0b010010, 0b1);
|
||||
INSN(fminh, 0b000, 0b11, 0b010110, 0b1);
|
||||
INSN(fnmulh, 0b000, 0b11, 0b100010, 0b1);
|
||||
#undef INSN
|
||||
|
||||
// Advanced SIMD scalar three same
|
||||
#define INSN(NAME, U, size, opcode) \
|
||||
void NAME(FloatRegister Vd, FloatRegister Vn, FloatRegister Vm) { \
|
||||
starti; \
|
||||
f(0b01, 31, 30), f(U, 29), f(0b11110, 28, 24), f(size, 23, 22), f(1, 21); \
|
||||
rf(Vm, 16), f(opcode, 15, 11), f(1, 10), rf(Vn, 5), rf(Vd, 0); \
|
||||
}
|
||||
|
||||
INSN(fabds, 0b1, 0b10, 0b11010); // Floating-point Absolute Difference (single-precision)
|
||||
INSN(fabdd, 0b1, 0b11, 0b11010); // Floating-point Absolute Difference (double-precision)
|
||||
|
||||
#undef INSN
|
||||
|
||||
// Advanced SIMD scalar three same FP16
|
||||
#define INSN(NAME, U, a, opcode) \
|
||||
void NAME(FloatRegister Vd, FloatRegister Vn, FloatRegister Vm) { \
|
||||
starti; \
|
||||
f(0b01, 31, 30), f(U, 29), f(0b11110, 28, 24), f(a, 23), f(0b10, 22, 21); \
|
||||
rf(Vm, 16), f(0b00, 15, 14), f(opcode, 13, 11), f(1, 10), rf(Vn, 5), rf(Vd, 0); \
|
||||
}
|
||||
|
||||
INSN(fabdh, 0b1, 0b1, 0b010); // Floating-point Absolute Difference (half-precision float)
|
||||
|
||||
#undef INSN
|
||||
|
||||
@ -2120,6 +2153,7 @@ public:
|
||||
INSN(fnmaddd, 0b000, 0b01, 1, 0);
|
||||
INSN(fnmsub, 0b000, 0b01, 1, 1);
|
||||
|
||||
INSN(fmaddh, 0b000, 0b11, 0, 0); // half-precision fused multiply-add (scalar)
|
||||
#undef INSN
|
||||
|
||||
// Floating-point conditional select
|
||||
|
||||
@ -69,7 +69,7 @@ void RangeCheckStub::emit_code(LIR_Assembler* ce) {
|
||||
__ far_call(RuntimeAddress(a));
|
||||
ce->add_call_info_here(_info);
|
||||
ce->verify_oop_map(_info);
|
||||
debug_only(__ should_not_reach_here());
|
||||
DEBUG_ONLY(__ should_not_reach_here());
|
||||
return;
|
||||
}
|
||||
|
||||
@ -90,7 +90,7 @@ void RangeCheckStub::emit_code(LIR_Assembler* ce) {
|
||||
__ blr(lr);
|
||||
ce->add_call_info_here(_info);
|
||||
ce->verify_oop_map(_info);
|
||||
debug_only(__ should_not_reach_here());
|
||||
DEBUG_ONLY(__ should_not_reach_here());
|
||||
}
|
||||
|
||||
PredicateFailedStub::PredicateFailedStub(CodeEmitInfo* info) {
|
||||
@ -103,7 +103,7 @@ void PredicateFailedStub::emit_code(LIR_Assembler* ce) {
|
||||
__ far_call(RuntimeAddress(a));
|
||||
ce->add_call_info_here(_info);
|
||||
ce->verify_oop_map(_info);
|
||||
debug_only(__ should_not_reach_here());
|
||||
DEBUG_ONLY(__ should_not_reach_here());
|
||||
}
|
||||
|
||||
void DivByZeroStub::emit_code(LIR_Assembler* ce) {
|
||||
@ -274,7 +274,7 @@ void ImplicitNullCheckStub::emit_code(LIR_Assembler* ce) {
|
||||
__ far_call(RuntimeAddress(a));
|
||||
ce->add_call_info_here(_info);
|
||||
ce->verify_oop_map(_info);
|
||||
debug_only(__ should_not_reach_here());
|
||||
DEBUG_ONLY(__ should_not_reach_here());
|
||||
}
|
||||
|
||||
|
||||
@ -289,7 +289,7 @@ void SimpleExceptionStub::emit_code(LIR_Assembler* ce) {
|
||||
}
|
||||
__ far_call(RuntimeAddress(Runtime1::entry_for(_stub)), rscratch2);
|
||||
ce->add_call_info_here(_info);
|
||||
debug_only(__ should_not_reach_here());
|
||||
DEBUG_ONLY(__ should_not_reach_here());
|
||||
}
|
||||
|
||||
|
||||
|
||||
@ -2743,3 +2743,107 @@ bool C2_MacroAssembler::in_scratch_emit_size() {
|
||||
}
|
||||
return MacroAssembler::in_scratch_emit_size();
|
||||
}
|
||||
|
||||
static void abort_verify_int_in_range(uint idx, jint val, jint lo, jint hi) {
|
||||
fatal("Invalid CastII, idx: %u, val: %d, lo: %d, hi: %d", idx, val, lo, hi);
|
||||
}
|
||||
|
||||
void C2_MacroAssembler::verify_int_in_range(uint idx, const TypeInt* t, Register rval, Register rtmp) {
|
||||
assert(!t->empty() && !t->singleton(), "%s", Type::str(t));
|
||||
if (t == TypeInt::INT) {
|
||||
return;
|
||||
}
|
||||
BLOCK_COMMENT("verify_int_in_range {");
|
||||
Label L_success, L_failure;
|
||||
|
||||
jint lo = t->_lo;
|
||||
jint hi = t->_hi;
|
||||
|
||||
if (lo != min_jint && hi != max_jint) {
|
||||
subsw(rtmp, rval, lo);
|
||||
br(Assembler::LT, L_failure);
|
||||
subsw(rtmp, rval, hi);
|
||||
br(Assembler::LE, L_success);
|
||||
} else if (lo != min_jint) {
|
||||
subsw(rtmp, rval, lo);
|
||||
br(Assembler::GE, L_success);
|
||||
} else if (hi != max_jint) {
|
||||
subsw(rtmp, rval, hi);
|
||||
br(Assembler::LE, L_success);
|
||||
} else {
|
||||
ShouldNotReachHere();
|
||||
}
|
||||
|
||||
bind(L_failure);
|
||||
movw(c_rarg0, idx);
|
||||
mov(c_rarg1, rval);
|
||||
movw(c_rarg2, lo);
|
||||
movw(c_rarg3, hi);
|
||||
reconstruct_frame_pointer(rtmp);
|
||||
rt_call(CAST_FROM_FN_PTR(address, abort_verify_int_in_range), rtmp);
|
||||
hlt(0);
|
||||
|
||||
bind(L_success);
|
||||
BLOCK_COMMENT("} verify_int_in_range");
|
||||
}
|
||||
|
||||
static void abort_verify_long_in_range(uint idx, jlong val, jlong lo, jlong hi) {
|
||||
fatal("Invalid CastLL, idx: %u, val: " JLONG_FORMAT ", lo: " JLONG_FORMAT ", hi: " JLONG_FORMAT, idx, val, lo, hi);
|
||||
}
|
||||
|
||||
void C2_MacroAssembler::verify_long_in_range(uint idx, const TypeLong* t, Register rval, Register rtmp) {
|
||||
assert(!t->empty() && !t->singleton(), "%s", Type::str(t));
|
||||
if (t == TypeLong::LONG) {
|
||||
return;
|
||||
}
|
||||
BLOCK_COMMENT("verify_long_in_range {");
|
||||
Label L_success, L_failure;
|
||||
|
||||
jlong lo = t->_lo;
|
||||
jlong hi = t->_hi;
|
||||
|
||||
if (lo != min_jlong && hi != max_jlong) {
|
||||
subs(rtmp, rval, lo);
|
||||
br(Assembler::LT, L_failure);
|
||||
subs(rtmp, rval, hi);
|
||||
br(Assembler::LE, L_success);
|
||||
} else if (lo != min_jlong) {
|
||||
subs(rtmp, rval, lo);
|
||||
br(Assembler::GE, L_success);
|
||||
} else if (hi != max_jlong) {
|
||||
subs(rtmp, rval, hi);
|
||||
br(Assembler::LE, L_success);
|
||||
} else {
|
||||
ShouldNotReachHere();
|
||||
}
|
||||
|
||||
bind(L_failure);
|
||||
movw(c_rarg0, idx);
|
||||
mov(c_rarg1, rval);
|
||||
mov(c_rarg2, lo);
|
||||
mov(c_rarg3, hi);
|
||||
reconstruct_frame_pointer(rtmp);
|
||||
rt_call(CAST_FROM_FN_PTR(address, abort_verify_long_in_range), rtmp);
|
||||
hlt(0);
|
||||
|
||||
bind(L_success);
|
||||
BLOCK_COMMENT("} verify_long_in_range");
|
||||
}
|
||||
|
||||
void C2_MacroAssembler::reconstruct_frame_pointer(Register rtmp) {
|
||||
const int framesize = Compile::current()->output()->frame_size_in_bytes();
|
||||
if (PreserveFramePointer) {
|
||||
// frame pointer is valid
|
||||
#ifdef ASSERT
|
||||
// Verify frame pointer value in rfp.
|
||||
add(rtmp, sp, framesize - 2 * wordSize);
|
||||
Label L_success;
|
||||
cmp(rfp, rtmp);
|
||||
br(Assembler::EQ, L_success);
|
||||
stop("frame pointer mismatch");
|
||||
bind(L_success);
|
||||
#endif // ASSERT
|
||||
} else {
|
||||
add(rfp, sp, framesize - 2 * wordSize);
|
||||
}
|
||||
}
|
||||
|
||||
@ -188,4 +188,9 @@
|
||||
void vector_signum_sve(FloatRegister dst, FloatRegister src, FloatRegister zero,
|
||||
FloatRegister one, FloatRegister vtmp, PRegister pgtmp, SIMD_RegVariant T);
|
||||
|
||||
void verify_int_in_range(uint idx, const TypeInt* t, Register val, Register tmp);
|
||||
void verify_long_in_range(uint idx, const TypeLong* t, Register val, Register tmp);
|
||||
|
||||
void reconstruct_frame_pointer(Register rtmp);
|
||||
|
||||
#endif // CPU_AARCH64_C2_MACROASSEMBLER_AARCH64_HPP
|
||||
|
||||
@ -70,7 +70,7 @@ static char* reserve_at_eor_compatible_address(size_t size, bool aslr) {
|
||||
const uint64_t immediate = ((uint64_t)immediates[index]) << 32;
|
||||
assert(immediate > 0 && Assembler::operand_valid_for_logical_immediate(/*is32*/false, immediate),
|
||||
"Invalid immediate %d " UINT64_FORMAT, index, immediate);
|
||||
result = os::attempt_reserve_memory_at((char*)immediate, size, false);
|
||||
result = os::attempt_reserve_memory_at((char*)immediate, size, mtNone);
|
||||
if (result == nullptr) {
|
||||
log_trace(metaspace, map)("Failed to attach at " UINT64_FORMAT_X, immediate);
|
||||
}
|
||||
@ -114,7 +114,7 @@ char* CompressedKlassPointers::reserve_address_space_for_compressed_classes(size
|
||||
if (result == nullptr) {
|
||||
constexpr size_t alignment = nth_bit(32);
|
||||
log_debug(metaspace, map)("Trying to reserve at a 32-bit-aligned address");
|
||||
result = os::reserve_memory_aligned(size, alignment, false);
|
||||
result = os::reserve_memory_aligned(size, alignment, mtNone);
|
||||
}
|
||||
|
||||
return result;
|
||||
|
||||
@ -1003,9 +1003,6 @@ void MacroAssembler::c2bool(Register x) {
|
||||
|
||||
address MacroAssembler::ic_call(address entry, jint method_index) {
|
||||
RelocationHolder rh = virtual_call_Relocation::spec(pc(), method_index);
|
||||
// address const_ptr = long_constant((jlong)Universe::non_oop_word());
|
||||
// uintptr_t offset;
|
||||
// ldr_constant(rscratch2, const_ptr);
|
||||
movptr(rscratch2, (intptr_t)Universe::non_oop_word());
|
||||
return trampoline_call(Address(entry, rh));
|
||||
}
|
||||
@ -5520,9 +5517,8 @@ void MacroAssembler::movoop(Register dst, jobject obj) {
|
||||
mov(dst, Address((address)obj, rspec));
|
||||
} else {
|
||||
address dummy = address(uintptr_t(pc()) & -wordSize); // A nearby aligned address
|
||||
ldr_constant(dst, Address(dummy, rspec));
|
||||
ldr(dst, Address(dummy, rspec));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Move a metadata address into a register.
|
||||
|
||||
@ -1472,16 +1472,6 @@ public:
|
||||
|
||||
public:
|
||||
|
||||
void ldr_constant(Register dest, const Address &const_addr) {
|
||||
if (NearCpool) {
|
||||
ldr(dest, const_addr);
|
||||
} else {
|
||||
uint64_t offset;
|
||||
adrp(dest, InternalAddress(const_addr.target()), offset);
|
||||
ldr(dest, Address(dest, offset));
|
||||
}
|
||||
}
|
||||
|
||||
address read_polling_page(Register r, relocInfo::relocType rtype);
|
||||
void get_polling_page(Register dest, relocInfo::relocType rtype);
|
||||
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2021, 2024, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2021, 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
|
||||
@ -200,4 +200,8 @@
|
||||
return false;
|
||||
}
|
||||
|
||||
// Is FEAT_FP16 supported for this CPU?
|
||||
static bool is_feat_fp16_supported() {
|
||||
return (VM_Version::supports_fphp() && VM_Version::supports_asimdhp());
|
||||
}
|
||||
#endif // CPU_AARCH64_MATCHER_AARCH64_HPP
|
||||
|
||||
@ -65,6 +65,9 @@ UncommonTrapBlob* OptoRuntime::generate_uncommon_trap_blob() {
|
||||
// Setup code generation tools
|
||||
const char* name = OptoRuntime::stub_name(OptoStubId::uncommon_trap_id);
|
||||
CodeBuffer buffer(name, 2048, 1024);
|
||||
if (buffer.blob() == nullptr) {
|
||||
return nullptr;
|
||||
}
|
||||
MacroAssembler* masm = new MacroAssembler(&buffer);
|
||||
|
||||
assert(SimpleRuntimeFrame::framesize % 4 == 0, "sp not 16-byte aligned");
|
||||
@ -285,6 +288,9 @@ ExceptionBlob* OptoRuntime::generate_exception_blob() {
|
||||
// Setup code generation tools
|
||||
const char* name = OptoRuntime::stub_name(OptoStubId::exception_id);
|
||||
CodeBuffer buffer(name, 2048, 1024);
|
||||
if (buffer.blob() == nullptr) {
|
||||
return nullptr;
|
||||
}
|
||||
MacroAssembler* masm = new MacroAssembler(&buffer);
|
||||
|
||||
// TODO check various assumptions made here
|
||||
|
||||
@ -11166,79 +11166,6 @@ class StubGenerator: public StubCodeGenerator {
|
||||
// }
|
||||
};
|
||||
|
||||
void generate_vector_math_stubs() {
|
||||
// Get native vector math stub routine addresses
|
||||
void* libsleef = nullptr;
|
||||
char ebuf[1024];
|
||||
char dll_name[JVM_MAXPATHLEN];
|
||||
if (os::dll_locate_lib(dll_name, sizeof(dll_name), Arguments::get_dll_dir(), "sleef")) {
|
||||
libsleef = os::dll_load(dll_name, ebuf, sizeof ebuf);
|
||||
}
|
||||
if (libsleef == nullptr) {
|
||||
log_info(library)("Failed to load native vector math library, %s!", ebuf);
|
||||
return;
|
||||
}
|
||||
// Method naming convention
|
||||
// All the methods are named as <OP><T><N>_<U><suffix>
|
||||
// Where:
|
||||
// <OP> is the operation name, e.g. sin
|
||||
// <T> is optional to indicate float/double
|
||||
// "f/d" for vector float/double operation
|
||||
// <N> is the number of elements in the vector
|
||||
// "2/4" for neon, and "x" for sve
|
||||
// <U> is the precision level
|
||||
// "u10/u05" represents 1.0/0.5 ULP error bounds
|
||||
// We use "u10" for all operations by default
|
||||
// But for those functions do not have u10 support, we use "u05" instead
|
||||
// <suffix> indicates neon/sve
|
||||
// "sve/advsimd" for sve/neon implementations
|
||||
// e.g. sinfx_u10sve is the method for computing vector float sin using SVE instructions
|
||||
// cosd2_u10advsimd is the method for computing 2 elements vector double cos using NEON instructions
|
||||
//
|
||||
log_info(library)("Loaded library %s, handle " INTPTR_FORMAT, JNI_LIB_PREFIX "sleef" JNI_LIB_SUFFIX, p2i(libsleef));
|
||||
|
||||
// Math vector stubs implemented with SVE for scalable vector size.
|
||||
if (UseSVE > 0) {
|
||||
for (int op = 0; op < VectorSupport::NUM_VECTOR_OP_MATH; op++) {
|
||||
int vop = VectorSupport::VECTOR_OP_MATH_START + op;
|
||||
// Skip "tanh" because there is performance regression
|
||||
if (vop == VectorSupport::VECTOR_OP_TANH) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// The native library does not support u10 level of "hypot".
|
||||
const char* ulf = (vop == VectorSupport::VECTOR_OP_HYPOT) ? "u05" : "u10";
|
||||
|
||||
snprintf(ebuf, sizeof(ebuf), "%sfx_%ssve", VectorSupport::mathname[op], ulf);
|
||||
StubRoutines::_vector_f_math[VectorSupport::VEC_SIZE_SCALABLE][op] = (address)os::dll_lookup(libsleef, ebuf);
|
||||
|
||||
snprintf(ebuf, sizeof(ebuf), "%sdx_%ssve", VectorSupport::mathname[op], ulf);
|
||||
StubRoutines::_vector_d_math[VectorSupport::VEC_SIZE_SCALABLE][op] = (address)os::dll_lookup(libsleef, ebuf);
|
||||
}
|
||||
}
|
||||
|
||||
// Math vector stubs implemented with NEON for 64/128 bits vector size.
|
||||
for (int op = 0; op < VectorSupport::NUM_VECTOR_OP_MATH; op++) {
|
||||
int vop = VectorSupport::VECTOR_OP_MATH_START + op;
|
||||
// Skip "tanh" because there is performance regression
|
||||
if (vop == VectorSupport::VECTOR_OP_TANH) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// The native library does not support u10 level of "hypot".
|
||||
const char* ulf = (vop == VectorSupport::VECTOR_OP_HYPOT) ? "u05" : "u10";
|
||||
|
||||
snprintf(ebuf, sizeof(ebuf), "%sf4_%sadvsimd", VectorSupport::mathname[op], ulf);
|
||||
StubRoutines::_vector_f_math[VectorSupport::VEC_SIZE_64][op] = (address)os::dll_lookup(libsleef, ebuf);
|
||||
|
||||
snprintf(ebuf, sizeof(ebuf), "%sf4_%sadvsimd", VectorSupport::mathname[op], ulf);
|
||||
StubRoutines::_vector_f_math[VectorSupport::VEC_SIZE_128][op] = (address)os::dll_lookup(libsleef, ebuf);
|
||||
|
||||
snprintf(ebuf, sizeof(ebuf), "%sd2_%sadvsimd", VectorSupport::mathname[op], ulf);
|
||||
StubRoutines::_vector_d_math[VectorSupport::VEC_SIZE_128][op] = (address)os::dll_lookup(libsleef, ebuf);
|
||||
}
|
||||
}
|
||||
|
||||
// Initialization
|
||||
void generate_initial_stubs() {
|
||||
// Generate initial stubs and initializes the entry points
|
||||
@ -11392,8 +11319,6 @@ class StubGenerator: public StubCodeGenerator {
|
||||
StubRoutines::_montgomerySquare = g.generate_multiply();
|
||||
}
|
||||
|
||||
generate_vector_math_stubs();
|
||||
|
||||
#endif // COMPILER2
|
||||
|
||||
if (UseChaCha20Intrinsics) {
|
||||
|
||||
@ -642,6 +642,7 @@ void VM_Version::initialize() {
|
||||
if (_model2) {
|
||||
os::snprintf_checked(buf + buf_used_len, sizeof(buf) - buf_used_len, "(0x%03x)", _model2);
|
||||
}
|
||||
size_t features_offset = strnlen(buf, sizeof(buf));
|
||||
#define ADD_FEATURE_IF_SUPPORTED(id, name, bit) \
|
||||
do { \
|
||||
if (VM_Version::supports_##name()) strcat(buf, ", " #name); \
|
||||
@ -649,7 +650,11 @@ void VM_Version::initialize() {
|
||||
CPU_FEATURE_FLAGS(ADD_FEATURE_IF_SUPPORTED)
|
||||
#undef ADD_FEATURE_IF_SUPPORTED
|
||||
|
||||
_features_string = os::strdup(buf);
|
||||
_cpu_info_string = os::strdup(buf);
|
||||
|
||||
_features_string = extract_features_string(_cpu_info_string,
|
||||
strnlen(_cpu_info_string, sizeof(buf)),
|
||||
features_offset);
|
||||
}
|
||||
|
||||
#if defined(LINUX)
|
||||
@ -716,7 +721,7 @@ void VM_Version::initialize_cpu_information(void) {
|
||||
int desc_len = 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", _features_string);
|
||||
snprintf(_cpu_desc + desc_len, CPU_DETAILED_DESC_BUF_SIZE - desc_len, " %s", _cpu_info_string);
|
||||
|
||||
_initialized = true;
|
||||
}
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 1997, 2024, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 1997, 2025, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2014, 2020, Red Hat Inc. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
@ -125,6 +125,8 @@ enum Ampere_CPU_Model {
|
||||
decl(SHA2, sha256, 6) \
|
||||
decl(CRC32, crc32, 7) \
|
||||
decl(LSE, lse, 8) \
|
||||
decl(FPHP, fphp, 9) \
|
||||
decl(ASIMDHP, asimdhp, 10) \
|
||||
decl(DCPOP, dcpop, 16) \
|
||||
decl(SHA3, sha3, 17) \
|
||||
decl(SHA512, sha512, 21) \
|
||||
|
||||
@ -1238,11 +1238,11 @@ encode %{
|
||||
enc_class save_last_PC %{
|
||||
// preserve mark
|
||||
address mark = __ inst_mark();
|
||||
debug_only(int off0 = __ offset());
|
||||
DEBUG_ONLY(int off0 = __ offset());
|
||||
int ret_addr_offset = as_MachCall()->ret_addr_offset();
|
||||
__ adr(LR, mark + ret_addr_offset);
|
||||
__ str(LR, Address(Rthread, JavaThread::last_Java_pc_offset()));
|
||||
debug_only(int off1 = __ offset());
|
||||
DEBUG_ONLY(int off1 = __ offset());
|
||||
assert(off1 - off0 == 2 * Assembler::InstructionSize, "correct size prediction");
|
||||
// restore mark
|
||||
__ set_inst_mark(mark);
|
||||
@ -1251,11 +1251,11 @@ encode %{
|
||||
enc_class preserve_SP %{
|
||||
// preserve mark
|
||||
address mark = __ inst_mark();
|
||||
debug_only(int off0 = __ offset());
|
||||
DEBUG_ONLY(int off0 = __ offset());
|
||||
// FP is preserved across all calls, even compiled calls.
|
||||
// Use it to preserve SP in places where the callee might change the SP.
|
||||
__ mov(Rmh_SP_save, SP);
|
||||
debug_only(int off1 = __ offset());
|
||||
DEBUG_ONLY(int off1 = __ offset());
|
||||
assert(off1 - off0 == 4, "correct size prediction");
|
||||
// restore mark
|
||||
__ set_inst_mark(mark);
|
||||
|
||||
@ -59,7 +59,7 @@ void RangeCheckStub::emit_code(LIR_Assembler* ce) {
|
||||
__ call(Runtime1::entry_for(C1StubId::predicate_failed_trap_id), relocInfo::runtime_call_type);
|
||||
ce->add_call_info_here(_info);
|
||||
ce->verify_oop_map(_info);
|
||||
debug_only(__ should_not_reach_here());
|
||||
DEBUG_ONLY(__ should_not_reach_here());
|
||||
return;
|
||||
}
|
||||
// Pass the array index on stack because all registers must be preserved
|
||||
@ -91,7 +91,7 @@ void PredicateFailedStub::emit_code(LIR_Assembler* ce) {
|
||||
__ call(Runtime1::entry_for(C1StubId::predicate_failed_trap_id), relocInfo::runtime_call_type);
|
||||
ce->add_call_info_here(_info);
|
||||
ce->verify_oop_map(_info);
|
||||
debug_only(__ should_not_reach_here());
|
||||
DEBUG_ONLY(__ should_not_reach_here());
|
||||
}
|
||||
|
||||
void DivByZeroStub::emit_code(LIR_Assembler* ce) {
|
||||
|
||||
@ -72,7 +72,7 @@ void NativeNMethodBarrier::verify() const {
|
||||
static NativeNMethodBarrier* native_nmethod_barrier(nmethod* nm) {
|
||||
address barrier_address = nm->code_begin() + nm->frame_complete_offset() - entry_barrier_bytes;
|
||||
NativeNMethodBarrier* barrier = reinterpret_cast<NativeNMethodBarrier*>(barrier_address);
|
||||
debug_only(barrier->verify());
|
||||
DEBUG_ONLY(barrier->verify());
|
||||
return barrier;
|
||||
}
|
||||
|
||||
|
||||
@ -54,6 +54,9 @@ UncommonTrapBlob* OptoRuntime::generate_uncommon_trap_blob() {
|
||||
// Measured 8/7/03 at 660 in 32bit debug build
|
||||
CodeBuffer buffer(name, 2000, 512);
|
||||
#endif
|
||||
if (buffer.blob() == nullptr) {
|
||||
return nullptr;
|
||||
}
|
||||
// bypassed when code generation useless
|
||||
MacroAssembler* masm = new MacroAssembler(&buffer);
|
||||
const Register Rublock = R6;
|
||||
@ -209,6 +212,9 @@ ExceptionBlob* OptoRuntime::generate_exception_blob() {
|
||||
// Measured 8/7/03 at 256 in 32bit debug build
|
||||
const char* name = OptoRuntime::stub_name(OptoStubId::exception_id);
|
||||
CodeBuffer buffer(name, 600, 512);
|
||||
if (buffer.blob() == nullptr) {
|
||||
return nullptr;
|
||||
}
|
||||
MacroAssembler* masm = new MacroAssembler(&buffer);
|
||||
|
||||
int framesize_in_words = 2; // FP + LR
|
||||
|
||||
@ -295,7 +295,7 @@ void VM_Version::initialize() {
|
||||
(has_multiprocessing_extensions() ? ", mp_ext" : ""));
|
||||
|
||||
// buf is started with ", " or is empty
|
||||
_features_string = os::strdup(buf);
|
||||
_cpu_info_string = os::strdup(buf);
|
||||
|
||||
if (has_simd()) {
|
||||
if (FLAG_IS_DEFAULT(UsePopCountInstruction)) {
|
||||
@ -363,6 +363,6 @@ void VM_Version::initialize_cpu_information(void) {
|
||||
_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", _features_string);
|
||||
snprintf(_cpu_desc, CPU_DETAILED_DESC_BUF_SIZE, "%s", _cpu_info_string);
|
||||
_initialized = true;
|
||||
}
|
||||
|
||||
@ -74,7 +74,7 @@ void RangeCheckStub::emit_code(LIR_Assembler* ce) {
|
||||
__ bctrl();
|
||||
ce->add_call_info_here(_info);
|
||||
ce->verify_oop_map(_info);
|
||||
debug_only(__ illtrap());
|
||||
DEBUG_ONLY(__ illtrap());
|
||||
return;
|
||||
}
|
||||
|
||||
@ -98,7 +98,7 @@ void RangeCheckStub::emit_code(LIR_Assembler* ce) {
|
||||
__ bctrl();
|
||||
ce->add_call_info_here(_info);
|
||||
ce->verify_oop_map(_info);
|
||||
debug_only(__ illtrap());
|
||||
DEBUG_ONLY(__ illtrap());
|
||||
}
|
||||
|
||||
|
||||
@ -115,7 +115,7 @@ void PredicateFailedStub::emit_code(LIR_Assembler* ce) {
|
||||
__ bctrl();
|
||||
ce->add_call_info_here(_info);
|
||||
ce->verify_oop_map(_info);
|
||||
debug_only(__ illtrap());
|
||||
DEBUG_ONLY(__ illtrap());
|
||||
}
|
||||
|
||||
|
||||
@ -156,7 +156,7 @@ void DivByZeroStub::emit_code(LIR_Assembler* ce) {
|
||||
__ bctrl();
|
||||
ce->add_call_info_here(_info);
|
||||
ce->verify_oop_map(_info);
|
||||
debug_only(__ illtrap());
|
||||
DEBUG_ONLY(__ illtrap());
|
||||
}
|
||||
|
||||
|
||||
@ -179,7 +179,7 @@ void ImplicitNullCheckStub::emit_code(LIR_Assembler* ce) {
|
||||
__ bctrl();
|
||||
ce->add_call_info_here(_info);
|
||||
ce->verify_oop_map(_info);
|
||||
debug_only(__ illtrap());
|
||||
DEBUG_ONLY(__ illtrap());
|
||||
}
|
||||
|
||||
|
||||
@ -193,7 +193,7 @@ void SimpleExceptionStub::emit_code(LIR_Assembler* ce) {
|
||||
__ mtctr(R0);
|
||||
__ bctrl();
|
||||
ce->add_call_info_here(_info);
|
||||
debug_only( __ illtrap(); )
|
||||
DEBUG_ONLY( __ illtrap(); )
|
||||
}
|
||||
|
||||
|
||||
@ -441,7 +441,7 @@ void DeoptimizeStub::emit_code(LIR_Assembler* ce) {
|
||||
__ load_const_optimized(R0, _trap_request); // Pass trap request in R0.
|
||||
__ bctrl();
|
||||
ce->add_call_info_here(_info);
|
||||
debug_only(__ illtrap());
|
||||
DEBUG_ONLY(__ illtrap());
|
||||
}
|
||||
|
||||
|
||||
|
||||
@ -189,7 +189,7 @@ LIR_Opr FrameMap::_caller_save_fpu_regs[] = {};
|
||||
|
||||
FloatRegister FrameMap::nr2floatreg (int rnr) {
|
||||
assert(_init_done, "tables not initialized");
|
||||
debug_only(fpu_range_check(rnr);)
|
||||
DEBUG_ONLY(fpu_range_check(rnr);)
|
||||
return _fpu_regs[rnr];
|
||||
}
|
||||
|
||||
|
||||
@ -108,7 +108,7 @@ static NativeNMethodBarrier* get_nmethod_barrier(nmethod* nm) {
|
||||
}
|
||||
|
||||
auto barrier = reinterpret_cast<NativeNMethodBarrier*>(barrier_address);
|
||||
debug_only(barrier->verify());
|
||||
DEBUG_ONLY(barrier->verify());
|
||||
return barrier;
|
||||
}
|
||||
|
||||
|
||||
@ -73,6 +73,9 @@ ExceptionBlob* OptoRuntime::generate_exception_blob() {
|
||||
// Setup code generation tools.
|
||||
const char* name = OptoRuntime::stub_name(OptoStubId::exception_id);
|
||||
CodeBuffer buffer(name, 2048, 1024);
|
||||
if (buffer.blob() == nullptr) {
|
||||
return nullptr;
|
||||
}
|
||||
InterpreterMacroAssembler* masm = new InterpreterMacroAssembler(&buffer);
|
||||
|
||||
address start = __ pc();
|
||||
|
||||
@ -3106,6 +3106,9 @@ UncommonTrapBlob* OptoRuntime::generate_uncommon_trap_blob() {
|
||||
// Setup code generation tools.
|
||||
const char* name = OptoRuntime::stub_name(OptoStubId::uncommon_trap_id);
|
||||
CodeBuffer buffer(name, 2048, 1024);
|
||||
if (buffer.blob() == nullptr) {
|
||||
return nullptr;
|
||||
}
|
||||
InterpreterMacroAssembler* masm = new InterpreterMacroAssembler(&buffer);
|
||||
address start = __ pc();
|
||||
|
||||
|
||||
@ -219,7 +219,7 @@ void VM_Version::initialize() {
|
||||
(has_brw() ? " brw" : "")
|
||||
// Make sure number of %s matches num_features!
|
||||
);
|
||||
_features_string = os::strdup(buf);
|
||||
_cpu_info_string = os::strdup(buf);
|
||||
if (Verbose) {
|
||||
print_features();
|
||||
}
|
||||
@ -519,7 +519,7 @@ void VM_Version::print_platform_virtualization_info(outputStream* st) {
|
||||
}
|
||||
|
||||
void VM_Version::print_features() {
|
||||
tty->print_cr("Version: %s L1_data_cache_line_size=%d", features_string(), L1_data_cache_line_size());
|
||||
tty->print_cr("Version: %s L1_data_cache_line_size=%d", cpu_info_string(), L1_data_cache_line_size());
|
||||
|
||||
if (Verbose) {
|
||||
if (ContendedPaddingWidth > 0) {
|
||||
@ -726,6 +726,6 @@ void VM_Version::initialize_cpu_information(void) {
|
||||
_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", features_string());
|
||||
snprintf(_cpu_desc, CPU_DETAILED_DESC_BUF_SIZE, "PPC %s", cpu_info_string());
|
||||
_initialized = true;
|
||||
}
|
||||
|
||||
@ -2323,6 +2323,7 @@ enum Nf {
|
||||
}
|
||||
|
||||
// Vector Bit-manipulation used in Cryptography (Zvbb) Extension
|
||||
INSN(vandn_vx, 0b1010111, 0b100, 0b000001);
|
||||
INSN(vrol_vx, 0b1010111, 0b100, 0b010101);
|
||||
INSN(vror_vx, 0b1010111, 0b100, 0b010100);
|
||||
|
||||
|
||||
@ -70,7 +70,7 @@ void RangeCheckStub::emit_code(LIR_Assembler* ce) {
|
||||
__ far_call(RuntimeAddress(a));
|
||||
ce->add_call_info_here(_info);
|
||||
ce->verify_oop_map(_info);
|
||||
debug_only(__ should_not_reach_here());
|
||||
DEBUG_ONLY(__ should_not_reach_here());
|
||||
return;
|
||||
}
|
||||
|
||||
@ -92,7 +92,7 @@ void RangeCheckStub::emit_code(LIR_Assembler* ce) {
|
||||
__ rt_call(Runtime1::entry_for(stub_id), ra);
|
||||
ce->add_call_info_here(_info);
|
||||
ce->verify_oop_map(_info);
|
||||
debug_only(__ should_not_reach_here());
|
||||
DEBUG_ONLY(__ should_not_reach_here());
|
||||
}
|
||||
|
||||
PredicateFailedStub::PredicateFailedStub(CodeEmitInfo* info) {
|
||||
@ -105,7 +105,7 @@ void PredicateFailedStub::emit_code(LIR_Assembler* ce) {
|
||||
__ far_call(RuntimeAddress(a));
|
||||
ce->add_call_info_here(_info);
|
||||
ce->verify_oop_map(_info);
|
||||
debug_only(__ should_not_reach_here());
|
||||
DEBUG_ONLY(__ should_not_reach_here());
|
||||
}
|
||||
|
||||
void DivByZeroStub::emit_code(LIR_Assembler* ce) {
|
||||
@ -258,7 +258,7 @@ void ImplicitNullCheckStub::emit_code(LIR_Assembler* ce) {
|
||||
__ far_call(RuntimeAddress(a));
|
||||
ce->add_call_info_here(_info);
|
||||
ce->verify_oop_map(_info);
|
||||
debug_only(__ should_not_reach_here());
|
||||
DEBUG_ONLY(__ should_not_reach_here());
|
||||
}
|
||||
|
||||
void SimpleExceptionStub::emit_code(LIR_Assembler* ce) {
|
||||
@ -272,7 +272,7 @@ void SimpleExceptionStub::emit_code(LIR_Assembler* ce) {
|
||||
}
|
||||
__ far_call(RuntimeAddress(Runtime1::entry_for(_stub)));
|
||||
ce->add_call_info_here(_info);
|
||||
debug_only(__ should_not_reach_here());
|
||||
DEBUG_ONLY(__ should_not_reach_here());
|
||||
}
|
||||
|
||||
void ArrayCopyStub::emit_code(LIR_Assembler* ce) {
|
||||
|
||||
@ -300,7 +300,7 @@ public:
|
||||
inline NativeGeneralJump* nativeGeneralJump_at(address addr) {
|
||||
assert_cond(addr != nullptr);
|
||||
NativeGeneralJump* jump = (NativeGeneralJump*)(addr);
|
||||
debug_only(jump->verify();)
|
||||
DEBUG_ONLY(jump->verify();)
|
||||
return jump;
|
||||
}
|
||||
|
||||
|
||||
@ -1596,7 +1596,8 @@ uint MachSpillCopyNode::implementation(C2_MacroAssembler *masm, PhaseRegAlloc *r
|
||||
__ unspill(as_VectorRegister(Matcher::_regEncode[dst_lo]), ra_->reg2offset(src_lo));
|
||||
} else if (src_lo_rc == rc_vector && dst_lo_rc == rc_vector) {
|
||||
// vpr to vpr
|
||||
__ vmv1r_v(as_VectorRegister(Matcher::_regEncode[dst_lo]), as_VectorRegister(Matcher::_regEncode[src_lo]));
|
||||
__ vsetvli_helper(T_BYTE, MaxVectorSize);
|
||||
__ vmv_v_v(as_VectorRegister(Matcher::_regEncode[dst_lo]), as_VectorRegister(Matcher::_regEncode[src_lo]));
|
||||
} else {
|
||||
ShouldNotReachHere();
|
||||
}
|
||||
@ -1614,7 +1615,8 @@ uint MachSpillCopyNode::implementation(C2_MacroAssembler *masm, PhaseRegAlloc *r
|
||||
__ unspill_vmask(as_VectorRegister(Matcher::_regEncode[dst_lo]), ra_->reg2offset(src_lo));
|
||||
} else if (src_lo_rc == rc_vector && dst_lo_rc == rc_vector) {
|
||||
// vmask to vmask
|
||||
__ vmv1r_v(as_VectorRegister(Matcher::_regEncode[dst_lo]), as_VectorRegister(Matcher::_regEncode[src_lo]));
|
||||
__ vsetvli_helper(T_BYTE, MaxVectorSize >> 3);
|
||||
__ vmv_v_v(as_VectorRegister(Matcher::_regEncode[dst_lo]), as_VectorRegister(Matcher::_regEncode[src_lo]));
|
||||
} else {
|
||||
ShouldNotReachHere();
|
||||
}
|
||||
@ -1914,9 +1916,10 @@ bool Matcher::match_rule_supported(int opcode) {
|
||||
|
||||
case Op_FmaF:
|
||||
case Op_FmaD:
|
||||
return UseFMA;
|
||||
case Op_FmaVF:
|
||||
case Op_FmaVD:
|
||||
return UseFMA;
|
||||
return UseRVV && UseFMA;
|
||||
|
||||
case Op_ConvHF2F:
|
||||
case Op_ConvF2HF:
|
||||
@ -1950,11 +1953,11 @@ const RegMask* Matcher::predicate_reg_mask(void) {
|
||||
|
||||
// Vector calling convention not yet implemented.
|
||||
bool Matcher::supports_vector_calling_convention(void) {
|
||||
return EnableVectorSupport && UseVectorStubs;
|
||||
return EnableVectorSupport;
|
||||
}
|
||||
|
||||
OptoRegPair Matcher::vector_return_value(uint ideal_reg) {
|
||||
assert(EnableVectorSupport && UseVectorStubs, "sanity");
|
||||
assert(EnableVectorSupport, "sanity");
|
||||
assert(ideal_reg == Op_VecA, "sanity");
|
||||
// check more info at https://github.com/riscv-non-isa/riscv-elf-psabi-doc/blob/master/riscv-cc.adoc
|
||||
int lo = V8_num;
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@ -63,6 +63,9 @@ UncommonTrapBlob* OptoRuntime::generate_uncommon_trap_blob() {
|
||||
// Setup code generation tools
|
||||
const char* name = OptoRuntime::stub_name(OptoStubId::uncommon_trap_id);
|
||||
CodeBuffer buffer(name, 2048, 1024);
|
||||
if (buffer.blob() == nullptr) {
|
||||
return nullptr;
|
||||
}
|
||||
MacroAssembler* masm = new MacroAssembler(&buffer);
|
||||
assert_cond(masm != nullptr);
|
||||
|
||||
@ -282,6 +285,9 @@ ExceptionBlob* OptoRuntime::generate_exception_blob() {
|
||||
// Setup code generation tools
|
||||
const char* name = OptoRuntime::stub_name(OptoStubId::exception_id);
|
||||
CodeBuffer buffer(name, 2048, 1024);
|
||||
if (buffer.blob() == nullptr) {
|
||||
return nullptr;
|
||||
}
|
||||
MacroAssembler* masm = new MacroAssembler(&buffer);
|
||||
assert_cond(masm != nullptr);
|
||||
|
||||
|
||||
@ -6458,58 +6458,6 @@ static const int64_t right_3_bits = right_n_bits(3);
|
||||
return start;
|
||||
}
|
||||
|
||||
void generate_vector_math_stubs() {
|
||||
if (!UseRVV) {
|
||||
log_info(library)("vector is not supported, skip loading vector math (sleef) library!");
|
||||
return;
|
||||
}
|
||||
|
||||
// Get native vector math stub routine addresses
|
||||
void* libsleef = nullptr;
|
||||
char ebuf[1024];
|
||||
char dll_name[JVM_MAXPATHLEN];
|
||||
if (os::dll_locate_lib(dll_name, sizeof(dll_name), Arguments::get_dll_dir(), "sleef")) {
|
||||
libsleef = os::dll_load(dll_name, ebuf, sizeof ebuf);
|
||||
}
|
||||
if (libsleef == nullptr) {
|
||||
log_info(library)("Failed to load native vector math (sleef) library, %s!", ebuf);
|
||||
return;
|
||||
}
|
||||
|
||||
// Method naming convention
|
||||
// All the methods are named as <OP><T>_<U><suffix>
|
||||
//
|
||||
// Where:
|
||||
// <OP> is the operation name, e.g. sin, cos
|
||||
// <T> is to indicate float/double
|
||||
// "fx/dx" for vector float/double operation
|
||||
// <U> is the precision level
|
||||
// "u10/u05" represents 1.0/0.5 ULP error bounds
|
||||
// We use "u10" for all operations by default
|
||||
// But for those functions do not have u10 support, we use "u05" instead
|
||||
// <suffix> rvv, indicates riscv vector extension
|
||||
//
|
||||
// e.g. sinfx_u10rvv is the method for computing vector float sin using rvv instructions
|
||||
//
|
||||
log_info(library)("Loaded library %s, handle " INTPTR_FORMAT, JNI_LIB_PREFIX "sleef" JNI_LIB_SUFFIX, p2i(libsleef));
|
||||
|
||||
for (int op = 0; op < VectorSupport::NUM_VECTOR_OP_MATH; op++) {
|
||||
int vop = VectorSupport::VECTOR_OP_MATH_START + op;
|
||||
if (vop == VectorSupport::VECTOR_OP_TANH) { // skip tanh because of performance regression
|
||||
continue;
|
||||
}
|
||||
|
||||
// The native library does not support u10 level of "hypot".
|
||||
const char* ulf = (vop == VectorSupport::VECTOR_OP_HYPOT) ? "u05" : "u10";
|
||||
|
||||
snprintf(ebuf, sizeof(ebuf), "%sfx_%srvv", VectorSupport::mathname[op], ulf);
|
||||
StubRoutines::_vector_f_math[VectorSupport::VEC_SIZE_SCALABLE][op] = (address)os::dll_lookup(libsleef, ebuf);
|
||||
|
||||
snprintf(ebuf, sizeof(ebuf), "%sdx_%srvv", VectorSupport::mathname[op], ulf);
|
||||
StubRoutines::_vector_d_math[VectorSupport::VEC_SIZE_SCALABLE][op] = (address)os::dll_lookup(libsleef, ebuf);
|
||||
}
|
||||
}
|
||||
|
||||
#endif // COMPILER2
|
||||
|
||||
/**
|
||||
@ -6741,8 +6689,6 @@ static const int64_t right_3_bits = right_n_bits(3);
|
||||
|
||||
generate_string_indexof_stubs();
|
||||
|
||||
generate_vector_math_stubs();
|
||||
|
||||
#endif // COMPILER2
|
||||
}
|
||||
|
||||
|
||||
@ -468,7 +468,7 @@ void VM_Version::initialize_cpu_information(void) {
|
||||
_no_of_threads = _no_of_cores;
|
||||
_no_of_sockets = _no_of_cores;
|
||||
snprintf(_cpu_name, CPU_TYPE_DESC_BUF_SIZE - 1, "RISCV64");
|
||||
snprintf(_cpu_desc, CPU_DETAILED_DESC_BUF_SIZE, "RISCV64 %s", features_string());
|
||||
snprintf(_cpu_desc, CPU_DETAILED_DESC_BUF_SIZE, "RISCV64 %s", cpu_info_string());
|
||||
_initialized = true;
|
||||
}
|
||||
|
||||
|
||||
@ -52,7 +52,7 @@ void RangeCheckStub::emit_code(LIR_Assembler* ce) {
|
||||
CHECK_BAILOUT();
|
||||
ce->add_call_info_here(_info);
|
||||
ce->verify_oop_map(_info);
|
||||
debug_only(__ should_not_reach_here());
|
||||
DEBUG_ONLY(__ should_not_reach_here());
|
||||
return;
|
||||
}
|
||||
|
||||
@ -74,7 +74,7 @@ void RangeCheckStub::emit_code(LIR_Assembler* ce) {
|
||||
CHECK_BAILOUT();
|
||||
ce->add_call_info_here(_info);
|
||||
ce->verify_oop_map(_info);
|
||||
debug_only(__ should_not_reach_here());
|
||||
DEBUG_ONLY(__ should_not_reach_here());
|
||||
}
|
||||
|
||||
PredicateFailedStub::PredicateFailedStub(CodeEmitInfo* info) {
|
||||
@ -88,7 +88,7 @@ void PredicateFailedStub::emit_code(LIR_Assembler* ce) {
|
||||
CHECK_BAILOUT();
|
||||
ce->add_call_info_here(_info);
|
||||
ce->verify_oop_map(_info);
|
||||
debug_only(__ should_not_reach_here());
|
||||
DEBUG_ONLY(__ should_not_reach_here());
|
||||
}
|
||||
|
||||
void CounterOverflowStub::emit_code(LIR_Assembler* ce) {
|
||||
@ -116,7 +116,7 @@ void DivByZeroStub::emit_code(LIR_Assembler* ce) {
|
||||
ce->emit_call_c(Runtime1::entry_for (C1StubId::throw_div0_exception_id));
|
||||
CHECK_BAILOUT();
|
||||
ce->add_call_info_here(_info);
|
||||
debug_only(__ should_not_reach_here());
|
||||
DEBUG_ONLY(__ should_not_reach_here());
|
||||
}
|
||||
|
||||
void ImplicitNullCheckStub::emit_code(LIR_Assembler* ce) {
|
||||
@ -134,7 +134,7 @@ void ImplicitNullCheckStub::emit_code(LIR_Assembler* ce) {
|
||||
CHECK_BAILOUT();
|
||||
ce->add_call_info_here(_info);
|
||||
ce->verify_oop_map(_info);
|
||||
debug_only(__ should_not_reach_here());
|
||||
DEBUG_ONLY(__ should_not_reach_here());
|
||||
}
|
||||
|
||||
// Note: pass object in Z_R1_scratch
|
||||
@ -147,7 +147,7 @@ void SimpleExceptionStub::emit_code(LIR_Assembler* ce) {
|
||||
ce->emit_call_c(a);
|
||||
CHECK_BAILOUT();
|
||||
ce->add_call_info_here(_info);
|
||||
debug_only(__ should_not_reach_here());
|
||||
DEBUG_ONLY(__ should_not_reach_here());
|
||||
}
|
||||
|
||||
NewInstanceStub::NewInstanceStub(LIR_Opr klass_reg, LIR_Opr result, ciInstanceKlass* klass, CodeEmitInfo* info, C1StubId stub_id) {
|
||||
|
||||
@ -144,13 +144,13 @@ LIR_Opr FrameMap::_caller_save_fpu_regs[] = {};
|
||||
// c1 rnr -> FloatRegister
|
||||
FloatRegister FrameMap::nr2floatreg (int rnr) {
|
||||
assert(_init_done, "tables not initialized");
|
||||
debug_only(fpu_range_check(rnr);)
|
||||
DEBUG_ONLY(fpu_range_check(rnr);)
|
||||
return _fpu_rnr2reg[rnr];
|
||||
}
|
||||
|
||||
void FrameMap::map_float_register(int rnr, FloatRegister reg) {
|
||||
debug_only(fpu_range_check(rnr);)
|
||||
debug_only(fpu_range_check(reg->encoding());)
|
||||
DEBUG_ONLY(fpu_range_check(rnr);)
|
||||
DEBUG_ONLY(fpu_range_check(reg->encoding());)
|
||||
_fpu_rnr2reg[rnr] = reg; // mapping c1 regnr. -> FloatRegister
|
||||
_fpu_reg2rnr[reg->encoding()] = rnr; // mapping assembler encoding -> c1 regnr.
|
||||
}
|
||||
|
||||
@ -107,7 +107,7 @@
|
||||
static int fpu_reg2rnr (FloatRegister reg) {
|
||||
assert(_init_done, "tables not initialized");
|
||||
int c1rnr = _fpu_reg2rnr[reg->encoding()];
|
||||
debug_only(fpu_range_check(c1rnr);)
|
||||
DEBUG_ONLY(fpu_range_check(c1rnr);)
|
||||
return c1rnr;
|
||||
}
|
||||
|
||||
|
||||
@ -40,7 +40,7 @@ class NativeMethodBarrier: public NativeInstruction {
|
||||
address get_patchable_data_address() const {
|
||||
address inst_addr = get_barrier_start_address() + PATCHABLE_INSTRUCTION_OFFSET;
|
||||
|
||||
debug_only(Assembler::is_z_cfi(*((long*)inst_addr)));
|
||||
DEBUG_ONLY(Assembler::is_z_cfi(*((long*)inst_addr)));
|
||||
return inst_addr + 2;
|
||||
}
|
||||
|
||||
@ -91,7 +91,7 @@ static NativeMethodBarrier* get_nmethod_barrier(nmethod* nm) {
|
||||
address barrier_address = nm->code_begin() + nm->frame_complete_offset() - NativeMethodBarrier::BARRIER_TOTAL_LENGTH;
|
||||
auto barrier = reinterpret_cast<NativeMethodBarrier*>(barrier_address);
|
||||
|
||||
debug_only(barrier->verify());
|
||||
DEBUG_ONLY(barrier->verify());
|
||||
return barrier;
|
||||
}
|
||||
|
||||
|
||||
@ -444,7 +444,7 @@ void InterpreterMacroAssembler::gen_subtype_check(Register Rsub_klass,
|
||||
// Useful if consumed previously by access via stackTop().
|
||||
void InterpreterMacroAssembler::popx(int len) {
|
||||
add2reg(Z_esp, len*Interpreter::stackElementSize);
|
||||
debug_only(verify_esp(Z_esp, Z_R1_scratch));
|
||||
DEBUG_ONLY(verify_esp(Z_esp, Z_R1_scratch));
|
||||
}
|
||||
|
||||
// Get Address object of stack top. No checks. No pop.
|
||||
@ -458,38 +458,38 @@ void InterpreterMacroAssembler::pop_i(Register r) {
|
||||
z_l(r, Interpreter::expr_offset_in_bytes(0), Z_esp);
|
||||
add2reg(Z_esp, Interpreter::stackElementSize);
|
||||
assert_different_registers(r, Z_R1_scratch);
|
||||
debug_only(verify_esp(Z_esp, Z_R1_scratch));
|
||||
DEBUG_ONLY(verify_esp(Z_esp, Z_R1_scratch));
|
||||
}
|
||||
|
||||
void InterpreterMacroAssembler::pop_ptr(Register r) {
|
||||
z_lg(r, Interpreter::expr_offset_in_bytes(0), Z_esp);
|
||||
add2reg(Z_esp, Interpreter::stackElementSize);
|
||||
assert_different_registers(r, Z_R1_scratch);
|
||||
debug_only(verify_esp(Z_esp, Z_R1_scratch));
|
||||
DEBUG_ONLY(verify_esp(Z_esp, Z_R1_scratch));
|
||||
}
|
||||
|
||||
void InterpreterMacroAssembler::pop_l(Register r) {
|
||||
z_lg(r, Interpreter::expr_offset_in_bytes(0), Z_esp);
|
||||
add2reg(Z_esp, 2*Interpreter::stackElementSize);
|
||||
assert_different_registers(r, Z_R1_scratch);
|
||||
debug_only(verify_esp(Z_esp, Z_R1_scratch));
|
||||
DEBUG_ONLY(verify_esp(Z_esp, Z_R1_scratch));
|
||||
}
|
||||
|
||||
void InterpreterMacroAssembler::pop_f(FloatRegister f) {
|
||||
mem2freg_opt(f, Address(Z_esp, Interpreter::expr_offset_in_bytes(0)), false);
|
||||
add2reg(Z_esp, Interpreter::stackElementSize);
|
||||
debug_only(verify_esp(Z_esp, Z_R1_scratch));
|
||||
DEBUG_ONLY(verify_esp(Z_esp, Z_R1_scratch));
|
||||
}
|
||||
|
||||
void InterpreterMacroAssembler::pop_d(FloatRegister f) {
|
||||
mem2freg_opt(f, Address(Z_esp, Interpreter::expr_offset_in_bytes(0)), true);
|
||||
add2reg(Z_esp, 2*Interpreter::stackElementSize);
|
||||
debug_only(verify_esp(Z_esp, Z_R1_scratch));
|
||||
DEBUG_ONLY(verify_esp(Z_esp, Z_R1_scratch));
|
||||
}
|
||||
|
||||
void InterpreterMacroAssembler::push_i(Register r) {
|
||||
assert_different_registers(r, Z_R1_scratch);
|
||||
debug_only(verify_esp(Z_esp, Z_R1_scratch));
|
||||
DEBUG_ONLY(verify_esp(Z_esp, Z_R1_scratch));
|
||||
z_st(r, Address(Z_esp));
|
||||
add2reg(Z_esp, -Interpreter::stackElementSize);
|
||||
}
|
||||
@ -501,7 +501,7 @@ void InterpreterMacroAssembler::push_ptr(Register r) {
|
||||
|
||||
void InterpreterMacroAssembler::push_l(Register r) {
|
||||
assert_different_registers(r, Z_R1_scratch);
|
||||
debug_only(verify_esp(Z_esp, Z_R1_scratch));
|
||||
DEBUG_ONLY(verify_esp(Z_esp, Z_R1_scratch));
|
||||
int offset = -Interpreter::stackElementSize;
|
||||
z_stg(r, Address(Z_esp, offset));
|
||||
clear_mem(Address(Z_esp), Interpreter::stackElementSize);
|
||||
@ -509,13 +509,13 @@ void InterpreterMacroAssembler::push_l(Register r) {
|
||||
}
|
||||
|
||||
void InterpreterMacroAssembler::push_f(FloatRegister f) {
|
||||
debug_only(verify_esp(Z_esp, Z_R1_scratch));
|
||||
DEBUG_ONLY(verify_esp(Z_esp, Z_R1_scratch));
|
||||
freg2mem_opt(f, Address(Z_esp), false);
|
||||
add2reg(Z_esp, -Interpreter::stackElementSize);
|
||||
}
|
||||
|
||||
void InterpreterMacroAssembler::push_d(FloatRegister d) {
|
||||
debug_only(verify_esp(Z_esp, Z_R1_scratch));
|
||||
DEBUG_ONLY(verify_esp(Z_esp, Z_R1_scratch));
|
||||
int offset = -Interpreter::stackElementSize;
|
||||
freg2mem_opt(d, Address(Z_esp, offset));
|
||||
add2reg(Z_esp, 2 * offset);
|
||||
|
||||
@ -72,6 +72,9 @@ ExceptionBlob* OptoRuntime::generate_exception_blob() {
|
||||
// Setup code generation tools
|
||||
const char* name = OptoRuntime::stub_name(OptoStubId::exception_id);
|
||||
CodeBuffer buffer(name, 2048, 1024);
|
||||
if (buffer.blob() == nullptr) {
|
||||
return nullptr;
|
||||
}
|
||||
MacroAssembler* masm = new MacroAssembler(&buffer);
|
||||
|
||||
Register handle_exception = Z_ARG5;
|
||||
|
||||
@ -2768,6 +2768,9 @@ UncommonTrapBlob* OptoRuntime::generate_uncommon_trap_blob() {
|
||||
// Setup code generation tools
|
||||
const char* name = OptoRuntime::stub_name(OptoStubId::uncommon_trap_id);
|
||||
CodeBuffer buffer(name, 2048, 1024);
|
||||
if (buffer.blob() == nullptr) {
|
||||
return nullptr;
|
||||
}
|
||||
InterpreterMacroAssembler* masm = new InterpreterMacroAssembler(&buffer);
|
||||
|
||||
Register unroll_block_reg = Z_tmp_1;
|
||||
|
||||
@ -90,7 +90,7 @@ static const char* z_features[] = {" ",
|
||||
|
||||
void VM_Version::initialize() {
|
||||
determine_features(); // Get processor capabilities.
|
||||
set_features_string(); // Set a descriptive feature indication.
|
||||
set_cpu_info_string(); // Set a descriptive feature indication.
|
||||
|
||||
if (Verbose || PrintAssembly || PrintStubCode) {
|
||||
print_features_internal("CPU Version as detected internally:", PrintAssembly || PrintStubCode);
|
||||
@ -388,9 +388,9 @@ int VM_Version::get_model_index() {
|
||||
}
|
||||
|
||||
|
||||
void VM_Version::set_features_string() {
|
||||
// A note on the _features_string format:
|
||||
// There are jtreg tests checking the _features_string for various properties.
|
||||
void VM_Version::set_cpu_info_string() {
|
||||
// A note on the _cpu_info_string format:
|
||||
// There are jtreg tests checking the _cpu_info_string for various properties.
|
||||
// For some strange reason, these tests require the string to contain
|
||||
// only _lowercase_ characters. Keep that in mind when being surprised
|
||||
// about the unusual notation of features - and when adding new ones.
|
||||
@ -412,29 +412,29 @@ void VM_Version::set_features_string() {
|
||||
_model_string = "unknown model";
|
||||
strcpy(buf, "z/Architecture (ambiguous detection)");
|
||||
}
|
||||
_features_string = os::strdup(buf);
|
||||
_cpu_info_string = os::strdup(buf);
|
||||
|
||||
if (has_Crypto_AES()) {
|
||||
assert(strlen(_features_string) + 3*8 < sizeof(buf), "increase buffer size");
|
||||
assert(strlen(_cpu_info_string) + 3*8 < sizeof(buf), "increase buffer size");
|
||||
jio_snprintf(buf, sizeof(buf), "%s%s%s%s",
|
||||
_features_string,
|
||||
_cpu_info_string,
|
||||
has_Crypto_AES128() ? ", aes128" : "",
|
||||
has_Crypto_AES192() ? ", aes192" : "",
|
||||
has_Crypto_AES256() ? ", aes256" : "");
|
||||
os::free((void *)_features_string);
|
||||
_features_string = os::strdup(buf);
|
||||
os::free((void *)_cpu_info_string);
|
||||
_cpu_info_string = os::strdup(buf);
|
||||
}
|
||||
|
||||
if (has_Crypto_SHA()) {
|
||||
assert(strlen(_features_string) + 6 + 2*8 + 7 < sizeof(buf), "increase buffer size");
|
||||
assert(strlen(_cpu_info_string) + 6 + 2*8 + 7 < sizeof(buf), "increase buffer size");
|
||||
jio_snprintf(buf, sizeof(buf), "%s%s%s%s%s",
|
||||
_features_string,
|
||||
_cpu_info_string,
|
||||
has_Crypto_SHA1() ? ", sha1" : "",
|
||||
has_Crypto_SHA256() ? ", sha256" : "",
|
||||
has_Crypto_SHA512() ? ", sha512" : "",
|
||||
has_Crypto_GHASH() ? ", ghash" : "");
|
||||
os::free((void *)_features_string);
|
||||
_features_string = os::strdup(buf);
|
||||
os::free((void *)_cpu_info_string);
|
||||
_cpu_info_string = os::strdup(buf);
|
||||
}
|
||||
}
|
||||
|
||||
@ -464,7 +464,7 @@ bool VM_Version::test_feature_bit(unsigned long* featureBuffer, int featureNum,
|
||||
}
|
||||
|
||||
void VM_Version::print_features_internal(const char* text, bool print_anyway) {
|
||||
tty->print_cr("%s %s", text, features_string());
|
||||
tty->print_cr("%s %s", text, cpu_info_string());
|
||||
tty->cr();
|
||||
|
||||
if (Verbose || print_anyway) {
|
||||
@ -906,7 +906,7 @@ void VM_Version::set_features_from(const char* march) {
|
||||
err = true;
|
||||
}
|
||||
if (!err) {
|
||||
set_features_string();
|
||||
set_cpu_info_string();
|
||||
if (prt || PrintAssembly) {
|
||||
print_features_internal("CPU Version as set by cmdline option:", prt);
|
||||
}
|
||||
@ -1542,6 +1542,6 @@ void VM_Version::initialize_cpu_information(void) {
|
||||
_no_of_threads = _no_of_cores;
|
||||
_no_of_sockets = _no_of_cores;
|
||||
snprintf(_cpu_name, CPU_TYPE_DESC_BUF_SIZE, "s390 %s", VM_Version::get_model_string());
|
||||
snprintf(_cpu_desc, CPU_DETAILED_DESC_BUF_SIZE, "s390 %s", features_string());
|
||||
snprintf(_cpu_desc, CPU_DETAILED_DESC_BUF_SIZE, "s390 %s", cpu_info_string());
|
||||
_initialized = true;
|
||||
}
|
||||
|
||||
@ -148,7 +148,7 @@ class VM_Version: public Abstract_VM_Version {
|
||||
|
||||
static bool test_feature_bit(unsigned long* featureBuffer, int featureNum, unsigned int bufLen);
|
||||
static int get_model_index();
|
||||
static void set_features_string();
|
||||
static void set_cpu_info_string();
|
||||
static void print_features_internal(const char* text, bool print_anyway=false);
|
||||
static void determine_features();
|
||||
static long call_getFeatures(unsigned long* buffer, int buflen, int functionCode);
|
||||
|
||||
@ -801,7 +801,7 @@ address Assembler::locate_operand(address inst, WhichOperand which) {
|
||||
address ip = inst;
|
||||
bool is_64bit = false;
|
||||
|
||||
debug_only(bool has_disp32 = false);
|
||||
DEBUG_ONLY(bool has_disp32 = false);
|
||||
int tail_size = 0; // other random bytes (#32, #16, etc.) at end of insn
|
||||
|
||||
again_after_prefix:
|
||||
@ -859,7 +859,7 @@ address Assembler::locate_operand(address inst, WhichOperand which) {
|
||||
case 0x8A: // movb r, a
|
||||
case 0x8B: // movl r, a
|
||||
case 0x8F: // popl a
|
||||
debug_only(has_disp32 = true);
|
||||
DEBUG_ONLY(has_disp32 = true);
|
||||
break;
|
||||
|
||||
case 0x68: // pushq #32
|
||||
@ -898,10 +898,10 @@ address Assembler::locate_operand(address inst, WhichOperand which) {
|
||||
|
||||
case 0x8B: // movw r, a
|
||||
case 0x89: // movw a, r
|
||||
debug_only(has_disp32 = true);
|
||||
DEBUG_ONLY(has_disp32 = true);
|
||||
break;
|
||||
case 0xC7: // movw a, #16
|
||||
debug_only(has_disp32 = true);
|
||||
DEBUG_ONLY(has_disp32 = true);
|
||||
tail_size = 2; // the imm16
|
||||
break;
|
||||
case 0x0F: // several SSE/SSE2 variants
|
||||
@ -923,7 +923,7 @@ address Assembler::locate_operand(address inst, WhichOperand which) {
|
||||
case 0x69: // imul r, a, #32
|
||||
case 0xC7: // movl a, #32(oop?)
|
||||
tail_size = 4;
|
||||
debug_only(has_disp32 = true); // has both kinds of operands!
|
||||
DEBUG_ONLY(has_disp32 = true); // has both kinds of operands!
|
||||
break;
|
||||
|
||||
case 0x0F: // movx..., etc.
|
||||
@ -932,11 +932,11 @@ address Assembler::locate_operand(address inst, WhichOperand which) {
|
||||
tail_size = 1;
|
||||
case 0x38: // ptest, pmovzxbw
|
||||
ip++; // skip opcode
|
||||
debug_only(has_disp32 = true); // has both kinds of operands!
|
||||
DEBUG_ONLY(has_disp32 = true); // has both kinds of operands!
|
||||
break;
|
||||
|
||||
case 0x70: // pshufd r, r/a, #8
|
||||
debug_only(has_disp32 = true); // has both kinds of operands!
|
||||
DEBUG_ONLY(has_disp32 = true); // has both kinds of operands!
|
||||
case 0x73: // psrldq r, #8
|
||||
tail_size = 1;
|
||||
break;
|
||||
@ -961,7 +961,7 @@ address Assembler::locate_operand(address inst, WhichOperand which) {
|
||||
case 0xAE: // ldmxcsr, stmxcsr, fxrstor, fxsave, clflush
|
||||
case 0xD6: // movq
|
||||
case 0xFE: // paddd
|
||||
debug_only(has_disp32 = true);
|
||||
DEBUG_ONLY(has_disp32 = true);
|
||||
break;
|
||||
|
||||
case 0xAD: // shrd r, a, %cl
|
||||
@ -976,18 +976,18 @@ address Assembler::locate_operand(address inst, WhichOperand which) {
|
||||
case 0xC1: // xaddl
|
||||
case 0xC7: // cmpxchg8
|
||||
case REP16(0x90): // setcc a
|
||||
debug_only(has_disp32 = true);
|
||||
DEBUG_ONLY(has_disp32 = true);
|
||||
// fall out of the switch to decode the address
|
||||
break;
|
||||
|
||||
case 0xC4: // pinsrw r, a, #8
|
||||
debug_only(has_disp32 = true);
|
||||
DEBUG_ONLY(has_disp32 = true);
|
||||
case 0xC5: // pextrw r, r, #8
|
||||
tail_size = 1; // the imm8
|
||||
break;
|
||||
|
||||
case 0xAC: // shrd r, a, #8
|
||||
debug_only(has_disp32 = true);
|
||||
DEBUG_ONLY(has_disp32 = true);
|
||||
tail_size = 1; // the imm8
|
||||
break;
|
||||
|
||||
@ -1004,12 +1004,12 @@ address Assembler::locate_operand(address inst, WhichOperand which) {
|
||||
// also: orl, adcl, sbbl, andl, subl, xorl, cmpl
|
||||
// on 32bit in the case of cmpl, the imm might be an oop
|
||||
tail_size = 4;
|
||||
debug_only(has_disp32 = true); // has both kinds of operands!
|
||||
DEBUG_ONLY(has_disp32 = true); // has both kinds of operands!
|
||||
break;
|
||||
|
||||
case 0x83: // addl a, #8; addl r, #8
|
||||
// also: orl, adcl, sbbl, andl, subl, xorl, cmpl
|
||||
debug_only(has_disp32 = true); // has both kinds of operands!
|
||||
DEBUG_ONLY(has_disp32 = true); // has both kinds of operands!
|
||||
tail_size = 1;
|
||||
break;
|
||||
|
||||
@ -1026,7 +1026,7 @@ address Assembler::locate_operand(address inst, WhichOperand which) {
|
||||
case 0x9B:
|
||||
switch (0xFF & *ip++) {
|
||||
case 0xD9: // fnstcw a
|
||||
debug_only(has_disp32 = true);
|
||||
DEBUG_ONLY(has_disp32 = true);
|
||||
break;
|
||||
default:
|
||||
ShouldNotReachHere();
|
||||
@ -1045,7 +1045,7 @@ address Assembler::locate_operand(address inst, WhichOperand which) {
|
||||
case 0x87: // xchg r, a
|
||||
case REP4(0x38): // cmp...
|
||||
case 0x85: // test r, a
|
||||
debug_only(has_disp32 = true); // has both kinds of operands!
|
||||
DEBUG_ONLY(has_disp32 = true); // has both kinds of operands!
|
||||
break;
|
||||
|
||||
case 0xA8: // testb rax, #8
|
||||
@ -1057,7 +1057,7 @@ address Assembler::locate_operand(address inst, WhichOperand which) {
|
||||
case 0xC6: // movb a, #8
|
||||
case 0x80: // cmpb a, #8
|
||||
case 0x6B: // imul r, a, #8
|
||||
debug_only(has_disp32 = true); // has both kinds of operands!
|
||||
DEBUG_ONLY(has_disp32 = true); // has both kinds of operands!
|
||||
tail_size = 1; // the imm8
|
||||
break;
|
||||
|
||||
@ -1109,7 +1109,7 @@ address Assembler::locate_operand(address inst, WhichOperand which) {
|
||||
break;
|
||||
}
|
||||
ip++; // skip opcode
|
||||
debug_only(has_disp32 = true); // has both kinds of operands!
|
||||
DEBUG_ONLY(has_disp32 = true); // has both kinds of operands!
|
||||
break;
|
||||
|
||||
case 0x62: // EVEX_4bytes
|
||||
@ -1135,7 +1135,7 @@ address Assembler::locate_operand(address inst, WhichOperand which) {
|
||||
break;
|
||||
}
|
||||
ip++; // skip opcode
|
||||
debug_only(has_disp32 = true); // has both kinds of operands!
|
||||
DEBUG_ONLY(has_disp32 = true); // has both kinds of operands!
|
||||
break;
|
||||
|
||||
case 0xD1: // sal a, 1; sar a, 1; shl a, 1; shr a, 1
|
||||
@ -1147,7 +1147,7 @@ address Assembler::locate_operand(address inst, WhichOperand which) {
|
||||
case 0xD8: // fadd_s a; fsubr_s a; fmul_s a; fdivr_s a; fcomp_s a
|
||||
case 0xDC: // fadd_d a; fsubr_d a; fmul_d a; fdivr_d a; fcomp_d a
|
||||
case 0xDE: // faddp_d a; fsubrp_d a; fmulp_d a; fdivrp_d a; fcompp_d a
|
||||
debug_only(has_disp32 = true);
|
||||
DEBUG_ONLY(has_disp32 = true);
|
||||
break;
|
||||
|
||||
case 0xE8: // call rdisp32
|
||||
@ -1184,7 +1184,7 @@ address Assembler::locate_operand(address inst, WhichOperand which) {
|
||||
default:
|
||||
ip++;
|
||||
}
|
||||
debug_only(has_disp32 = true); // has both kinds of operands!
|
||||
DEBUG_ONLY(has_disp32 = true); // has both kinds of operands!
|
||||
break;
|
||||
|
||||
default:
|
||||
|
||||
@ -68,7 +68,7 @@ void RangeCheckStub::emit_code(LIR_Assembler* ce) {
|
||||
__ call(RuntimeAddress(a));
|
||||
ce->add_call_info_here(_info);
|
||||
ce->verify_oop_map(_info);
|
||||
debug_only(__ should_not_reach_here());
|
||||
DEBUG_ONLY(__ should_not_reach_here());
|
||||
return;
|
||||
}
|
||||
|
||||
@ -88,7 +88,7 @@ void RangeCheckStub::emit_code(LIR_Assembler* ce) {
|
||||
__ call(RuntimeAddress(Runtime1::entry_for(stub_id)));
|
||||
ce->add_call_info_here(_info);
|
||||
ce->verify_oop_map(_info);
|
||||
debug_only(__ should_not_reach_here());
|
||||
DEBUG_ONLY(__ should_not_reach_here());
|
||||
}
|
||||
|
||||
PredicateFailedStub::PredicateFailedStub(CodeEmitInfo* info) {
|
||||
@ -101,7 +101,7 @@ void PredicateFailedStub::emit_code(LIR_Assembler* ce) {
|
||||
__ call(RuntimeAddress(a));
|
||||
ce->add_call_info_here(_info);
|
||||
ce->verify_oop_map(_info);
|
||||
debug_only(__ should_not_reach_here());
|
||||
DEBUG_ONLY(__ should_not_reach_here());
|
||||
}
|
||||
|
||||
void DivByZeroStub::emit_code(LIR_Assembler* ce) {
|
||||
@ -111,7 +111,7 @@ void DivByZeroStub::emit_code(LIR_Assembler* ce) {
|
||||
__ bind(_entry);
|
||||
__ call(RuntimeAddress(Runtime1::entry_for(C1StubId::throw_div0_exception_id)));
|
||||
ce->add_call_info_here(_info);
|
||||
debug_only(__ should_not_reach_here());
|
||||
DEBUG_ONLY(__ should_not_reach_here());
|
||||
}
|
||||
|
||||
|
||||
@ -399,7 +399,7 @@ void ImplicitNullCheckStub::emit_code(LIR_Assembler* ce) {
|
||||
__ call(RuntimeAddress(a));
|
||||
ce->add_call_info_here(_info);
|
||||
ce->verify_oop_map(_info);
|
||||
debug_only(__ should_not_reach_here());
|
||||
DEBUG_ONLY(__ should_not_reach_here());
|
||||
}
|
||||
|
||||
|
||||
@ -413,7 +413,7 @@ void SimpleExceptionStub::emit_code(LIR_Assembler* ce) {
|
||||
}
|
||||
__ call(RuntimeAddress(Runtime1::entry_for(_stub)));
|
||||
ce->add_call_info_here(_info);
|
||||
debug_only(__ should_not_reach_here());
|
||||
DEBUG_ONLY(__ should_not_reach_here());
|
||||
}
|
||||
|
||||
|
||||
|
||||
@ -787,6 +787,119 @@ void C2_MacroAssembler::fast_unlock_lightweight(Register obj, Register reg_rax,
|
||||
// C2 uses the value of ZF to determine the continuation.
|
||||
}
|
||||
|
||||
static void abort_verify_int_in_range(uint idx, jint val, jint lo, jint hi) {
|
||||
fatal("Invalid CastII, idx: %u, val: %d, lo: %d, hi: %d", idx, val, lo, hi);
|
||||
}
|
||||
|
||||
static void reconstruct_frame_pointer_helper(MacroAssembler* masm, Register dst) {
|
||||
const int framesize = Compile::current()->output()->frame_size_in_bytes();
|
||||
masm->movptr(dst, rsp);
|
||||
if (framesize > 2 * wordSize) {
|
||||
masm->addptr(dst, framesize - 2 * wordSize);
|
||||
}
|
||||
}
|
||||
|
||||
void C2_MacroAssembler::reconstruct_frame_pointer(Register rtmp) {
|
||||
if (PreserveFramePointer) {
|
||||
// frame pointer is valid
|
||||
#ifdef ASSERT
|
||||
// Verify frame pointer value in rbp.
|
||||
reconstruct_frame_pointer_helper(this, rtmp);
|
||||
Label L_success;
|
||||
cmpq(rbp, rtmp);
|
||||
jccb(Assembler::equal, L_success);
|
||||
STOP("frame pointer mismatch");
|
||||
bind(L_success);
|
||||
#endif // ASSERT
|
||||
} else {
|
||||
reconstruct_frame_pointer_helper(this, rbp);
|
||||
}
|
||||
}
|
||||
|
||||
void C2_MacroAssembler::verify_int_in_range(uint idx, const TypeInt* t, Register val) {
|
||||
jint lo = t->_lo;
|
||||
jint hi = t->_hi;
|
||||
assert(lo < hi, "type should not be empty or constant, idx: %u, lo: %d, hi: %d", idx, lo, hi);
|
||||
if (t == TypeInt::INT) {
|
||||
return;
|
||||
}
|
||||
|
||||
BLOCK_COMMENT("CastII {");
|
||||
Label fail;
|
||||
Label succeed;
|
||||
if (hi == max_jint) {
|
||||
cmpl(val, lo);
|
||||
jccb(Assembler::greaterEqual, succeed);
|
||||
} else {
|
||||
if (lo != min_jint) {
|
||||
cmpl(val, lo);
|
||||
jccb(Assembler::less, fail);
|
||||
}
|
||||
cmpl(val, hi);
|
||||
jccb(Assembler::lessEqual, succeed);
|
||||
}
|
||||
|
||||
bind(fail);
|
||||
movl(c_rarg0, idx);
|
||||
movl(c_rarg1, val);
|
||||
movl(c_rarg2, lo);
|
||||
movl(c_rarg3, hi);
|
||||
reconstruct_frame_pointer(rscratch1);
|
||||
call(RuntimeAddress(CAST_FROM_FN_PTR(address, abort_verify_int_in_range)));
|
||||
hlt();
|
||||
bind(succeed);
|
||||
BLOCK_COMMENT("} // CastII");
|
||||
}
|
||||
|
||||
static void abort_verify_long_in_range(uint idx, jlong val, jlong lo, jlong hi) {
|
||||
fatal("Invalid CastLL, idx: %u, val: " JLONG_FORMAT ", lo: " JLONG_FORMAT ", hi: " JLONG_FORMAT, idx, val, lo, hi);
|
||||
}
|
||||
|
||||
void C2_MacroAssembler::verify_long_in_range(uint idx, const TypeLong* t, Register val, Register tmp) {
|
||||
jlong lo = t->_lo;
|
||||
jlong hi = t->_hi;
|
||||
assert(lo < hi, "type should not be empty or constant, idx: %u, lo: " JLONG_FORMAT ", hi: " JLONG_FORMAT, idx, lo, hi);
|
||||
if (t == TypeLong::LONG) {
|
||||
return;
|
||||
}
|
||||
|
||||
BLOCK_COMMENT("CastLL {");
|
||||
Label fail;
|
||||
Label succeed;
|
||||
|
||||
auto cmp_val = [&](jlong bound) {
|
||||
if (is_simm32(bound)) {
|
||||
cmpq(val, checked_cast<int>(bound));
|
||||
} else {
|
||||
mov64(tmp, bound);
|
||||
cmpq(val, tmp);
|
||||
}
|
||||
};
|
||||
|
||||
if (hi == max_jlong) {
|
||||
cmp_val(lo);
|
||||
jccb(Assembler::greaterEqual, succeed);
|
||||
} else {
|
||||
if (lo != min_jlong) {
|
||||
cmp_val(lo);
|
||||
jccb(Assembler::less, fail);
|
||||
}
|
||||
cmp_val(hi);
|
||||
jccb(Assembler::lessEqual, succeed);
|
||||
}
|
||||
|
||||
bind(fail);
|
||||
movl(c_rarg0, idx);
|
||||
movq(c_rarg1, val);
|
||||
mov64(c_rarg2, lo);
|
||||
mov64(c_rarg3, hi);
|
||||
reconstruct_frame_pointer(rscratch1);
|
||||
call(RuntimeAddress(CAST_FROM_FN_PTR(address, abort_verify_long_in_range)));
|
||||
hlt();
|
||||
bind(succeed);
|
||||
BLOCK_COMMENT("} // CastLL");
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------------------------
|
||||
// Generic instructions support for use in .ad files C2 code generation
|
||||
|
||||
|
||||
@ -44,6 +44,9 @@ public:
|
||||
Register t, Register thread);
|
||||
void fast_unlock_lightweight(Register obj, Register reg_rax, Register t, Register thread);
|
||||
|
||||
void verify_int_in_range(uint idx, const TypeInt* t, Register val);
|
||||
void verify_long_in_range(uint idx, const TypeLong* t, Register val, Register tmp);
|
||||
|
||||
// Generic instructions support for use in .ad files C2 code generation
|
||||
void vabsnegd(int opcode, XMMRegister dst, XMMRegister src);
|
||||
void vabsnegd(int opcode, XMMRegister dst, XMMRegister src, int vector_len);
|
||||
@ -574,4 +577,7 @@ public:
|
||||
|
||||
void scalar_max_min_fp16(int opcode, XMMRegister dst, XMMRegister src1, XMMRegister src2,
|
||||
KRegister ktmp, XMMRegister xtmp1, XMMRegister xtmp2);
|
||||
|
||||
void reconstruct_frame_pointer(Register rtmp);
|
||||
|
||||
#endif // CPU_X86_C2_MACROASSEMBLER_X86_HPP
|
||||
|
||||
@ -34,9 +34,7 @@ const bool CCallingConventionRequiresIntsAsLongs = false;
|
||||
|
||||
#define SUPPORTS_NATIVE_CX8
|
||||
|
||||
#ifdef _LP64
|
||||
#define SUPPORT_MONITOR_COUNT
|
||||
#endif
|
||||
|
||||
#define CPU_MULTI_COPY_ATOMIC
|
||||
|
||||
@ -44,15 +42,11 @@ const bool CCallingConventionRequiresIntsAsLongs = false;
|
||||
#define DEFAULT_CACHE_LINE_SIZE 64
|
||||
|
||||
// The default padding size for data structures to avoid false sharing.
|
||||
#ifdef _LP64
|
||||
// The common wisdom is that adjacent cache line prefetchers on some hardware
|
||||
// may pull two cache lines on access, so we have to pessimistically assume twice
|
||||
// the cache line size for padding. TODO: Check if this is still true for modern
|
||||
// hardware. If not, DEFAULT_CACHE_LINE_SIZE might as well suffice.
|
||||
#define DEFAULT_PADDING_SIZE (DEFAULT_CACHE_LINE_SIZE*2)
|
||||
#else
|
||||
#define DEFAULT_PADDING_SIZE DEFAULT_CACHE_LINE_SIZE
|
||||
#endif
|
||||
|
||||
#if defined(LINUX) || defined(__APPLE__)
|
||||
#define SUPPORT_RESERVED_STACK_AREA
|
||||
|
||||
@ -61,29 +61,19 @@ define_pd_global(intx, InlineSmallCode, 1000);
|
||||
#define MIN_STACK_RED_PAGES DEFAULT_STACK_RED_PAGES
|
||||
#define MIN_STACK_RESERVED_PAGES (0)
|
||||
|
||||
#ifdef _LP64
|
||||
// Java_java_net_SocketOutputStream_socketWrite0() uses a 64k buffer on the
|
||||
// stack if compiled for unix and LP64. To pass stack overflow tests we need
|
||||
// 20 shadow pages.
|
||||
// stack if compiled for unix. To pass stack overflow tests we need 20 shadow pages.
|
||||
#define DEFAULT_STACK_SHADOW_PAGES (NOT_WIN64(20) WIN64_ONLY(8) DEBUG_ONLY(+4))
|
||||
// For those clients that do not use write socket, we allow
|
||||
// the min range value to be below that of the default
|
||||
#define MIN_STACK_SHADOW_PAGES (NOT_WIN64(10) WIN64_ONLY(8) DEBUG_ONLY(+4))
|
||||
#else
|
||||
#define DEFAULT_STACK_SHADOW_PAGES (4 DEBUG_ONLY(+5))
|
||||
#define MIN_STACK_SHADOW_PAGES DEFAULT_STACK_SHADOW_PAGES
|
||||
#endif // _LP64
|
||||
|
||||
define_pd_global(intx, StackYellowPages, DEFAULT_STACK_YELLOW_PAGES);
|
||||
define_pd_global(intx, StackRedPages, DEFAULT_STACK_RED_PAGES);
|
||||
define_pd_global(intx, StackShadowPages, DEFAULT_STACK_SHADOW_PAGES);
|
||||
define_pd_global(intx, StackReservedPages, DEFAULT_STACK_RESERVED_PAGES);
|
||||
|
||||
#ifdef _LP64
|
||||
define_pd_global(bool, VMContinuations, true);
|
||||
#else
|
||||
define_pd_global(bool, VMContinuations, false);
|
||||
#endif
|
||||
|
||||
define_pd_global(bool, RewriteBytecodes, true);
|
||||
define_pd_global(bool, RewriteFrequentPairs, true);
|
||||
|
||||
@ -67,9 +67,7 @@ void NativeCall::print() {
|
||||
// Inserts a native call instruction at a given pc
|
||||
void NativeCall::insert(address code_pos, address entry) {
|
||||
intptr_t disp = (intptr_t)entry - ((intptr_t)code_pos + 1 + 4);
|
||||
#ifdef AMD64
|
||||
guarantee(disp == (intptr_t)(jint)disp, "must be 32-bit offset");
|
||||
#endif // AMD64
|
||||
*code_pos = instruction_code;
|
||||
*((int32_t *)(code_pos+1)) = (int32_t) disp;
|
||||
ICache::invalidate_range(code_pos, instruction_size);
|
||||
@ -140,7 +138,7 @@ bool NativeCall::is_displacement_aligned() {
|
||||
// Used in the runtime linkage of calls; see class CompiledIC.
|
||||
// (Cf. 4506997 and 4479829, where threads witnessed garbage displacements.)
|
||||
void NativeCall::set_destination_mt_safe(address dest) {
|
||||
debug_only(verify());
|
||||
DEBUG_ONLY(verify());
|
||||
// Make sure patching code is locked. No two threads can patch at the same
|
||||
// time but one may be executing this code.
|
||||
assert(CodeCache_lock->is_locked() || SafepointSynchronize::is_at_safepoint() ||
|
||||
@ -157,7 +155,6 @@ void NativeCall::set_destination_mt_safe(address dest) {
|
||||
|
||||
|
||||
void NativeMovConstReg::verify() {
|
||||
#ifdef AMD64
|
||||
// make sure code pattern is actually a mov reg64, imm64 instruction
|
||||
bool valid_rex_prefix = ubyte_at(0) == Assembler::REX_W || ubyte_at(0) == Assembler::REX_WB;
|
||||
bool valid_rex2_prefix = ubyte_at(0) == Assembler::REX2 &&
|
||||
@ -169,12 +166,6 @@ void NativeMovConstReg::verify() {
|
||||
print();
|
||||
fatal("not a REX.W[B] mov reg64, imm64");
|
||||
}
|
||||
#else
|
||||
// make sure code pattern is actually a mov reg, imm32 instruction
|
||||
u_char test_byte = *(u_char*)instruction_address();
|
||||
u_char test_byte_2 = test_byte & ( 0xff ^ register_mask);
|
||||
if (test_byte_2 != instruction_code) fatal("not a mov reg, imm32");
|
||||
#endif // AMD64
|
||||
}
|
||||
|
||||
|
||||
@ -192,12 +183,10 @@ int NativeMovRegMem::instruction_start() const {
|
||||
// See comment in Assembler::locate_operand() about VEX prefixes.
|
||||
if (instr_0 == instruction_VEX_prefix_2bytes) {
|
||||
assert((UseAVX > 0), "shouldn't have VEX prefix");
|
||||
NOT_LP64(assert((0xC0 & ubyte_at(1)) == 0xC0, "shouldn't have LDS and LES instructions"));
|
||||
return 2;
|
||||
}
|
||||
if (instr_0 == instruction_VEX_prefix_3bytes) {
|
||||
assert((UseAVX > 0), "shouldn't have VEX prefix");
|
||||
NOT_LP64(assert((0xC0 & ubyte_at(1)) == 0xC0, "shouldn't have LDS and LES instructions"));
|
||||
return 3;
|
||||
}
|
||||
if (instr_0 == instruction_EVEX_prefix_4bytes) {
|
||||
@ -313,8 +302,7 @@ void NativeMovRegMem::print() {
|
||||
void NativeLoadAddress::verify() {
|
||||
// make sure code pattern is actually a mov [reg+offset], reg instruction
|
||||
u_char test_byte = *(u_char*)instruction_address();
|
||||
if ( ! ((test_byte == lea_instruction_code)
|
||||
LP64_ONLY(|| (test_byte == mov64_instruction_code) ))) {
|
||||
if ((test_byte != lea_instruction_code) && (test_byte != mov64_instruction_code)) {
|
||||
fatal ("not a lea reg, [reg+offs] instruction");
|
||||
}
|
||||
}
|
||||
@ -340,9 +328,7 @@ void NativeJump::verify() {
|
||||
|
||||
void NativeJump::insert(address code_pos, address entry) {
|
||||
intptr_t disp = (intptr_t)entry - ((intptr_t)code_pos + 1 + 4);
|
||||
#ifdef AMD64
|
||||
guarantee(disp == (intptr_t)(int32_t)disp, "must be 32-bit offset");
|
||||
#endif // AMD64
|
||||
|
||||
*code_pos = instruction_code;
|
||||
*((int32_t*)(code_pos + 1)) = (int32_t)disp;
|
||||
@ -355,11 +341,7 @@ void NativeJump::check_verified_entry_alignment(address entry, address verified_
|
||||
// in use. The patching in that instance must happen only when certain
|
||||
// alignment restrictions are true. These guarantees check those
|
||||
// conditions.
|
||||
#ifdef AMD64
|
||||
const int linesize = 64;
|
||||
#else
|
||||
const int linesize = 32;
|
||||
#endif // AMD64
|
||||
|
||||
// Must be wordSize aligned
|
||||
guarantee(((uintptr_t) verified_entry & (wordSize -1)) == 0,
|
||||
@ -386,7 +368,6 @@ void NativeJump::check_verified_entry_alignment(address entry, address verified_
|
||||
//
|
||||
void NativeJump::patch_verified_entry(address entry, address verified_entry, address dest) {
|
||||
// complete jump instruction (to be inserted) is in code_buffer;
|
||||
#ifdef _LP64
|
||||
union {
|
||||
jlong cb_long;
|
||||
unsigned char code_buffer[8];
|
||||
@ -402,43 +383,6 @@ void NativeJump::patch_verified_entry(address entry, address verified_entry, add
|
||||
|
||||
Atomic::store((jlong *) verified_entry, u.cb_long);
|
||||
ICache::invalidate_range(verified_entry, 8);
|
||||
|
||||
#else
|
||||
unsigned char code_buffer[5];
|
||||
code_buffer[0] = instruction_code;
|
||||
intptr_t disp = (intptr_t)dest - ((intptr_t)verified_entry + 1 + 4);
|
||||
*(int32_t*)(code_buffer + 1) = (int32_t)disp;
|
||||
|
||||
check_verified_entry_alignment(entry, verified_entry);
|
||||
|
||||
// Can't call nativeJump_at() because it's asserts jump exists
|
||||
NativeJump* n_jump = (NativeJump*) verified_entry;
|
||||
|
||||
//First patch dummy jmp in place
|
||||
|
||||
unsigned char patch[4];
|
||||
assert(sizeof(patch)==sizeof(int32_t), "sanity check");
|
||||
patch[0] = 0xEB; // jmp rel8
|
||||
patch[1] = 0xFE; // jmp to self
|
||||
patch[2] = 0xEB;
|
||||
patch[3] = 0xFE;
|
||||
|
||||
// First patch dummy jmp in place
|
||||
*(int32_t*)verified_entry = *(int32_t *)patch;
|
||||
|
||||
n_jump->wrote(0);
|
||||
|
||||
// Patch 5th byte (from jump instruction)
|
||||
verified_entry[4] = code_buffer[4];
|
||||
|
||||
n_jump->wrote(4);
|
||||
|
||||
// Patch bytes 0-3 (from jump instruction)
|
||||
*(int32_t*)verified_entry = *(int32_t *)code_buffer;
|
||||
// Invalidate. Opteron requires a flush after every write.
|
||||
n_jump->wrote(0);
|
||||
#endif // _LP64
|
||||
|
||||
}
|
||||
|
||||
void NativeIllegalInstruction::insert(address code_pos) {
|
||||
@ -455,9 +399,7 @@ void NativeGeneralJump::verify() {
|
||||
|
||||
void NativeGeneralJump::insert_unconditional(address code_pos, address entry) {
|
||||
intptr_t disp = (intptr_t)entry - ((intptr_t)code_pos + 1 + 4);
|
||||
#ifdef AMD64
|
||||
guarantee(disp == (intptr_t)(int32_t)disp, "must be 32-bit offset");
|
||||
#endif // AMD64
|
||||
|
||||
*code_pos = unconditional_long_jump;
|
||||
*((int32_t *)(code_pos+1)) = (int32_t) disp;
|
||||
|
||||
@ -126,10 +126,8 @@ class NativeCall: public NativeInstruction {
|
||||
address return_address() const { return addr_at(return_address_offset); }
|
||||
address destination() const;
|
||||
void set_destination(address dest) {
|
||||
#ifdef AMD64
|
||||
intptr_t disp = dest - return_address();
|
||||
guarantee(disp == (intptr_t)(jint)disp, "must be 32-bit offset");
|
||||
#endif // AMD64
|
||||
set_int_at(displacement_offset, (int)(dest - return_address()));
|
||||
}
|
||||
// Returns whether the 4-byte displacement operand is 4-byte aligned.
|
||||
@ -211,15 +209,9 @@ class NativeCallReg: public NativeInstruction {
|
||||
// Instruction format for implied addressing mode immediate operand move to register instruction:
|
||||
// [REX/REX2] [OPCODE] [IMM32]
|
||||
class NativeMovConstReg: public NativeInstruction {
|
||||
#ifdef AMD64
|
||||
static const bool has_rex = true;
|
||||
static const int rex_size = 1;
|
||||
static const int rex2_size = 2;
|
||||
#else
|
||||
static const bool has_rex = false;
|
||||
static const int rex_size = 0;
|
||||
static const int rex2_size = 0;
|
||||
#endif // AMD64
|
||||
public:
|
||||
enum Intel_specific_constants {
|
||||
instruction_code = 0xB8,
|
||||
@ -390,13 +382,8 @@ inline NativeMovRegMem* nativeMovRegMem_at (address address) {
|
||||
// leal reg, [reg + offset]
|
||||
|
||||
class NativeLoadAddress: public NativeMovRegMem {
|
||||
#ifdef AMD64
|
||||
static const bool has_rex = true;
|
||||
static const int rex_size = 1;
|
||||
#else
|
||||
static const bool has_rex = false;
|
||||
static const int rex_size = 0;
|
||||
#endif // AMD64
|
||||
public:
|
||||
enum Intel_specific_constants {
|
||||
instruction_prefix_wide = Assembler::REX_W,
|
||||
@ -447,9 +434,7 @@ class NativeJump: public NativeInstruction {
|
||||
if (dest == (address) -1) {
|
||||
val = -5; // jump to self
|
||||
}
|
||||
#ifdef AMD64
|
||||
assert((labs(val) & 0xFFFFFFFF00000000) == 0 || dest == (address)-1, "must be 32bit offset or -1");
|
||||
#endif // AMD64
|
||||
set_int_at(data_offset, (jint)val);
|
||||
}
|
||||
|
||||
@ -503,7 +488,7 @@ class NativeGeneralJump: public NativeInstruction {
|
||||
|
||||
inline NativeGeneralJump* nativeGeneralJump_at(address address) {
|
||||
NativeGeneralJump* jump = (NativeGeneralJump*)(address);
|
||||
debug_only(jump->verify();)
|
||||
DEBUG_ONLY(jump->verify();)
|
||||
return jump;
|
||||
}
|
||||
|
||||
@ -572,19 +557,14 @@ inline bool NativeInstruction::is_jump_reg() {
|
||||
inline bool NativeInstruction::is_cond_jump() { return (int_at(0) & 0xF0FF) == 0x800F /* long jump */ ||
|
||||
(ubyte_at(0) & 0xF0) == 0x70; /* short jump */ }
|
||||
inline bool NativeInstruction::is_safepoint_poll() {
|
||||
#ifdef AMD64
|
||||
const bool has_rex_prefix = ubyte_at(0) == NativeTstRegMem::instruction_rex_b_prefix;
|
||||
const int test_offset = has_rex2_prefix() ? 2 : (has_rex_prefix ? 1 : 0);
|
||||
#else
|
||||
const int test_offset = 0;
|
||||
#endif
|
||||
const bool is_test_opcode = ubyte_at(test_offset) == NativeTstRegMem::instruction_code_memXregl;
|
||||
const bool is_rax_target = (ubyte_at(test_offset + 1) & NativeTstRegMem::modrm_mask) == NativeTstRegMem::modrm_reg;
|
||||
return is_test_opcode && is_rax_target;
|
||||
}
|
||||
|
||||
inline bool NativeInstruction::is_mov_literal64() {
|
||||
#ifdef AMD64
|
||||
bool valid_rex_prefix = ubyte_at(0) == Assembler::REX_W || ubyte_at(0) == Assembler::REX_WB;
|
||||
bool valid_rex2_prefix = ubyte_at(0) == Assembler::REX2 &&
|
||||
(ubyte_at(1) == Assembler::REX2BIT_W ||
|
||||
@ -593,9 +573,6 @@ inline bool NativeInstruction::is_mov_literal64() {
|
||||
|
||||
int opcode = has_rex2_prefix() ? ubyte_at(2) : ubyte_at(1);
|
||||
return ((valid_rex_prefix || valid_rex2_prefix) && (opcode & (0xff ^ NativeMovConstReg::register_mask)) == 0xB8);
|
||||
#else
|
||||
return false;
|
||||
#endif // AMD64
|
||||
}
|
||||
|
||||
class NativePostCallNop: public NativeInstruction {
|
||||
|
||||
@ -61,6 +61,9 @@ UncommonTrapBlob* OptoRuntime::generate_uncommon_trap_blob() {
|
||||
// Setup code generation tools
|
||||
const char* name = OptoRuntime::stub_name(OptoStubId::uncommon_trap_id);
|
||||
CodeBuffer buffer(name, 2048, 1024);
|
||||
if (buffer.blob() == nullptr) {
|
||||
return nullptr;
|
||||
}
|
||||
MacroAssembler* masm = new MacroAssembler(&buffer);
|
||||
|
||||
assert(SimpleRuntimeFrame::framesize % 4 == 0, "sp not 16-byte aligned");
|
||||
@ -267,6 +270,9 @@ ExceptionBlob* OptoRuntime::generate_exception_blob() {
|
||||
// Setup code generation tools
|
||||
const char* name = OptoRuntime::stub_name(OptoStubId::exception_id);
|
||||
CodeBuffer buffer(name, 2048, 1024);
|
||||
if (buffer.blob() == nullptr) {
|
||||
return nullptr;
|
||||
}
|
||||
MacroAssembler* masm = new MacroAssembler(&buffer);
|
||||
|
||||
|
||||
|
||||
@ -4333,70 +4333,6 @@ void StubGenerator::generate_compiler_stubs() {
|
||||
}
|
||||
}
|
||||
|
||||
// Get svml stub routine addresses
|
||||
void *libjsvml = nullptr;
|
||||
char ebuf[1024];
|
||||
char dll_name[JVM_MAXPATHLEN];
|
||||
if (os::dll_locate_lib(dll_name, sizeof(dll_name), Arguments::get_dll_dir(), "jsvml")) {
|
||||
libjsvml = os::dll_load(dll_name, ebuf, sizeof ebuf);
|
||||
}
|
||||
if (libjsvml != nullptr) {
|
||||
// SVML method naming convention
|
||||
// All the methods are named as __jsvml_op<T><N>_ha_<VV>
|
||||
// Where:
|
||||
// ha stands for high accuracy
|
||||
// <T> is optional to indicate float/double
|
||||
// Set to f for vector float operation
|
||||
// Omitted for vector double operation
|
||||
// <N> is the number of elements in the vector
|
||||
// 1, 2, 4, 8, 16
|
||||
// e.g. 128 bit float vector has 4 float elements
|
||||
// <VV> indicates the avx/sse level:
|
||||
// z0 is AVX512, l9 is AVX2, e9 is AVX1 and ex is for SSE2
|
||||
// e.g. __jsvml_expf16_ha_z0 is the method for computing 16 element vector float exp using AVX 512 insns
|
||||
// __jsvml_exp8_ha_z0 is the method for computing 8 element vector double exp using AVX 512 insns
|
||||
|
||||
log_info(library)("Loaded library %s, handle " INTPTR_FORMAT, JNI_LIB_PREFIX "jsvml" JNI_LIB_SUFFIX, p2i(libjsvml));
|
||||
if (UseAVX > 2) {
|
||||
for (int op = 0; op < VectorSupport::NUM_VECTOR_OP_MATH; op++) {
|
||||
int vop = VectorSupport::VECTOR_OP_MATH_START + op;
|
||||
if ((!VM_Version::supports_avx512dq()) &&
|
||||
(vop == VectorSupport::VECTOR_OP_LOG || vop == VectorSupport::VECTOR_OP_LOG10 || vop == VectorSupport::VECTOR_OP_POW)) {
|
||||
continue;
|
||||
}
|
||||
snprintf(ebuf, sizeof(ebuf), "__jsvml_%sf16_ha_z0", VectorSupport::mathname[op]);
|
||||
StubRoutines::_vector_f_math[VectorSupport::VEC_SIZE_512][op] = (address)os::dll_lookup(libjsvml, ebuf);
|
||||
|
||||
snprintf(ebuf, sizeof(ebuf), "__jsvml_%s8_ha_z0", VectorSupport::mathname[op]);
|
||||
StubRoutines::_vector_d_math[VectorSupport::VEC_SIZE_512][op] = (address)os::dll_lookup(libjsvml, ebuf);
|
||||
}
|
||||
}
|
||||
const char* avx_sse_str = (UseAVX >= 2) ? "l9" : ((UseAVX == 1) ? "e9" : "ex");
|
||||
for (int op = 0; op < VectorSupport::NUM_VECTOR_OP_MATH; op++) {
|
||||
int vop = VectorSupport::VECTOR_OP_MATH_START + op;
|
||||
if (vop == VectorSupport::VECTOR_OP_POW) {
|
||||
continue;
|
||||
}
|
||||
snprintf(ebuf, sizeof(ebuf), "__jsvml_%sf4_ha_%s", VectorSupport::mathname[op], avx_sse_str);
|
||||
StubRoutines::_vector_f_math[VectorSupport::VEC_SIZE_64][op] = (address)os::dll_lookup(libjsvml, ebuf);
|
||||
|
||||
snprintf(ebuf, sizeof(ebuf), "__jsvml_%sf4_ha_%s", VectorSupport::mathname[op], avx_sse_str);
|
||||
StubRoutines::_vector_f_math[VectorSupport::VEC_SIZE_128][op] = (address)os::dll_lookup(libjsvml, ebuf);
|
||||
|
||||
snprintf(ebuf, sizeof(ebuf), "__jsvml_%sf8_ha_%s", VectorSupport::mathname[op], avx_sse_str);
|
||||
StubRoutines::_vector_f_math[VectorSupport::VEC_SIZE_256][op] = (address)os::dll_lookup(libjsvml, ebuf);
|
||||
|
||||
snprintf(ebuf, sizeof(ebuf), "__jsvml_%s1_ha_%s", VectorSupport::mathname[op], avx_sse_str);
|
||||
StubRoutines::_vector_d_math[VectorSupport::VEC_SIZE_64][op] = (address)os::dll_lookup(libjsvml, ebuf);
|
||||
|
||||
snprintf(ebuf, sizeof(ebuf), "__jsvml_%s2_ha_%s", VectorSupport::mathname[op], avx_sse_str);
|
||||
StubRoutines::_vector_d_math[VectorSupport::VEC_SIZE_128][op] = (address)os::dll_lookup(libjsvml, ebuf);
|
||||
|
||||
snprintf(ebuf, sizeof(ebuf), "__jsvml_%s4_ha_%s", VectorSupport::mathname[op], avx_sse_str);
|
||||
StubRoutines::_vector_d_math[VectorSupport::VEC_SIZE_256][op] = (address)os::dll_lookup(libjsvml, ebuf);
|
||||
}
|
||||
}
|
||||
|
||||
#endif // COMPILER2
|
||||
#endif // COMPILER2_OR_JVMCI
|
||||
}
|
||||
|
||||
@ -72,8 +72,6 @@ static get_cpu_info_stub_t get_cpu_info_stub = nullptr;
|
||||
static detect_virt_stub_t detect_virt_stub = nullptr;
|
||||
static clear_apx_test_state_t clear_apx_test_state_stub = nullptr;
|
||||
|
||||
#ifdef _LP64
|
||||
|
||||
bool VM_Version::supports_clflush() {
|
||||
// clflush should always be available on x86_64
|
||||
// if not we are in real trouble because we rely on it
|
||||
@ -87,7 +85,6 @@ bool VM_Version::supports_clflush() {
|
||||
assert ((!Universe::is_fully_initialized() || (_features & CPU_FLUSH) != 0), "clflush should be available");
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
#define CPUID_STANDARD_FN 0x0
|
||||
#define CPUID_STANDARD_FN_1 0x1
|
||||
@ -107,7 +104,6 @@ class VM_Version_StubGenerator: public StubCodeGenerator {
|
||||
|
||||
VM_Version_StubGenerator(CodeBuffer *c) : StubCodeGenerator(c) {}
|
||||
|
||||
#if defined(_LP64)
|
||||
address clear_apx_test_state() {
|
||||
# define __ _masm->
|
||||
address start = __ pc();
|
||||
@ -126,7 +122,6 @@ class VM_Version_StubGenerator: public StubCodeGenerator {
|
||||
__ ret(0);
|
||||
return start;
|
||||
}
|
||||
#endif
|
||||
|
||||
address generate_get_cpu_info() {
|
||||
// Flags to test CPU type.
|
||||
@ -151,14 +146,10 @@ class VM_Version_StubGenerator: public StubCodeGenerator {
|
||||
//
|
||||
// void get_cpu_info(VM_Version::CpuidInfo* cpuid_info);
|
||||
//
|
||||
// LP64: rcx and rdx are first and second argument registers on windows
|
||||
// rcx and rdx are first and second argument registers on windows
|
||||
|
||||
__ push(rbp);
|
||||
#ifdef _LP64
|
||||
__ mov(rbp, c_rarg0); // cpuid_info address
|
||||
#else
|
||||
__ movptr(rbp, Address(rsp, 8)); // cpuid_info address
|
||||
#endif
|
||||
__ push(rbx);
|
||||
__ push(rsi);
|
||||
__ pushf(); // preserve rbx, and flags
|
||||
@ -418,7 +409,6 @@ class VM_Version_StubGenerator: public StubCodeGenerator {
|
||||
__ movl(Address(rsi, 8), rcx);
|
||||
__ movl(Address(rsi,12), rdx);
|
||||
|
||||
#if defined(_LP64)
|
||||
//
|
||||
// Check if OS has enabled XGETBV instruction to access XCR0
|
||||
// (OSXSAVE feature flag) and CPU supports APX
|
||||
@ -453,7 +443,6 @@ class VM_Version_StubGenerator: public StubCodeGenerator {
|
||||
__ movq(Address(rsi, 8), r31);
|
||||
|
||||
UseAPX = save_apx;
|
||||
#endif
|
||||
#endif
|
||||
__ bind(vector_save_restore);
|
||||
//
|
||||
@ -527,10 +516,8 @@ class VM_Version_StubGenerator: public StubCodeGenerator {
|
||||
__ movdl(xmm0, rcx);
|
||||
__ vpbroadcastd(xmm0, xmm0, Assembler::AVX_512bit);
|
||||
__ evmovdqul(xmm7, xmm0, Assembler::AVX_512bit);
|
||||
#ifdef _LP64
|
||||
__ evmovdqul(xmm8, xmm0, Assembler::AVX_512bit);
|
||||
__ evmovdqul(xmm31, xmm0, Assembler::AVX_512bit);
|
||||
#endif
|
||||
VM_Version::clean_cpuFeatures();
|
||||
__ jmp(save_restore_except);
|
||||
}
|
||||
@ -556,10 +543,8 @@ class VM_Version_StubGenerator: public StubCodeGenerator {
|
||||
__ pshufd(xmm0, xmm0, 0x00);
|
||||
__ vinsertf128_high(xmm0, xmm0);
|
||||
__ vmovdqu(xmm7, xmm0);
|
||||
#ifdef _LP64
|
||||
__ vmovdqu(xmm8, xmm0);
|
||||
__ vmovdqu(xmm15, xmm0);
|
||||
#endif
|
||||
VM_Version::clean_cpuFeatures();
|
||||
|
||||
__ bind(save_restore_except);
|
||||
@ -600,10 +585,8 @@ class VM_Version_StubGenerator: public StubCodeGenerator {
|
||||
__ lea(rsi, Address(rbp, in_bytes(VM_Version::zmm_save_offset())));
|
||||
__ evmovdqul(Address(rsi, 0), xmm0, Assembler::AVX_512bit);
|
||||
__ evmovdqul(Address(rsi, 64), xmm7, Assembler::AVX_512bit);
|
||||
#ifdef _LP64
|
||||
__ evmovdqul(Address(rsi, 128), xmm8, Assembler::AVX_512bit);
|
||||
__ evmovdqul(Address(rsi, 192), xmm31, Assembler::AVX_512bit);
|
||||
#endif
|
||||
|
||||
#ifdef _WINDOWS
|
||||
__ evmovdqul(xmm31, Address(rsp, 0), Assembler::AVX_512bit);
|
||||
@ -628,10 +611,8 @@ class VM_Version_StubGenerator: public StubCodeGenerator {
|
||||
__ lea(rsi, Address(rbp, in_bytes(VM_Version::ymm_save_offset())));
|
||||
__ vmovdqu(Address(rsi, 0), xmm0);
|
||||
__ vmovdqu(Address(rsi, 32), xmm7);
|
||||
#ifdef _LP64
|
||||
__ vmovdqu(Address(rsi, 64), xmm8);
|
||||
__ vmovdqu(Address(rsi, 96), xmm15);
|
||||
#endif
|
||||
|
||||
#ifdef _WINDOWS
|
||||
__ vmovdqu(xmm15, Address(rsp, 0));
|
||||
@ -687,13 +668,8 @@ class VM_Version_StubGenerator: public StubCodeGenerator {
|
||||
__ push(rbx);
|
||||
__ push(rsi); // for Windows
|
||||
|
||||
#ifdef _LP64
|
||||
__ mov(rax, c_rarg0); // CPUID leaf
|
||||
__ mov(rsi, c_rarg1); // register array address (eax, ebx, ecx, edx)
|
||||
#else
|
||||
__ movptr(rax, Address(rsp, 16)); // CPUID leaf
|
||||
__ movptr(rsi, Address(rsp, 20)); // register array address
|
||||
#endif
|
||||
|
||||
__ cpuid();
|
||||
|
||||
@ -734,14 +710,10 @@ class VM_Version_StubGenerator: public StubCodeGenerator {
|
||||
//
|
||||
// void getCPUIDBrandString(VM_Version::CpuidInfo* cpuid_info);
|
||||
//
|
||||
// LP64: rcx and rdx are first and second argument registers on windows
|
||||
// rcx and rdx are first and second argument registers on windows
|
||||
|
||||
__ push(rbp);
|
||||
#ifdef _LP64
|
||||
__ mov(rbp, c_rarg0); // cpuid_info address
|
||||
#else
|
||||
__ movptr(rbp, Address(rsp, 8)); // cpuid_info address
|
||||
#endif
|
||||
__ push(rbx);
|
||||
__ push(rsi);
|
||||
__ pushf(); // preserve rbx, and flags
|
||||
@ -889,19 +861,16 @@ void VM_Version::get_processor_features() {
|
||||
// xchg and xadd instructions
|
||||
_supports_atomic_getset4 = true;
|
||||
_supports_atomic_getadd4 = true;
|
||||
LP64_ONLY(_supports_atomic_getset8 = true);
|
||||
LP64_ONLY(_supports_atomic_getadd8 = true);
|
||||
_supports_atomic_getset8 = true;
|
||||
_supports_atomic_getadd8 = true;
|
||||
|
||||
#ifdef _LP64
|
||||
// OS should support SSE for x64 and hardware should support at least SSE2.
|
||||
if (!VM_Version::supports_sse2()) {
|
||||
vm_exit_during_initialization("Unknown x64 processor: SSE2 not supported");
|
||||
}
|
||||
// in 64 bit the use of SSE2 is the minimum
|
||||
if (UseSSE < 2) UseSSE = 2;
|
||||
#endif
|
||||
|
||||
#ifdef AMD64
|
||||
// flush_icache_stub have to be generated first.
|
||||
// That is why Icache line size is hard coded in ICache class,
|
||||
// see icache_x86.hpp. It is also the reason why we can't use
|
||||
@ -913,9 +882,7 @@ void VM_Version::get_processor_features() {
|
||||
guarantee(_cpuid_info.std_cpuid1_edx.bits.clflush != 0, "clflush is not supported");
|
||||
// clflush_size is size in quadwords (8 bytes).
|
||||
guarantee(_cpuid_info.std_cpuid1_ebx.bits.clflush_size == 8, "such clflush size is not supported");
|
||||
#endif
|
||||
|
||||
#ifdef _LP64
|
||||
// assigning this field effectively enables Unsafe.writebackMemory()
|
||||
// by initing UnsafeConstant.DATA_CACHE_LINE_FLUSH_SIZE to non-zero
|
||||
// that is only implemented on x86_64 and only if the OS plays ball
|
||||
@ -924,7 +891,6 @@ void VM_Version::get_processor_features() {
|
||||
// let if default to zero thereby disabling writeback
|
||||
_data_cache_line_flush_size = _cpuid_info.std_cpuid1_ebx.bits.clflush_size * 8;
|
||||
}
|
||||
#endif
|
||||
|
||||
// Check if processor has Intel Ecore
|
||||
if (FLAG_IS_DEFAULT(EnableX86ECoreOpts) && is_intel() && cpu_family() == 6 &&
|
||||
@ -1114,15 +1080,19 @@ void VM_Version::get_processor_features() {
|
||||
}
|
||||
|
||||
char buf[1024];
|
||||
int res = jio_snprintf(
|
||||
int cpu_info_size = jio_snprintf(
|
||||
buf, sizeof(buf),
|
||||
"(%u cores per cpu, %u threads per core) family %d model %d stepping %d microcode 0x%x",
|
||||
cores_per_cpu(), threads_per_core(),
|
||||
cpu_family(), _model, _stepping, os::cpu_microcode_revision());
|
||||
assert(res > 0, "not enough temporary space allocated");
|
||||
insert_features_names(buf + res, sizeof(buf) - res, _features_names);
|
||||
assert(cpu_info_size > 0, "not enough temporary space allocated");
|
||||
insert_features_names(buf + cpu_info_size, sizeof(buf) - cpu_info_size, _features_names);
|
||||
|
||||
_features_string = os::strdup(buf);
|
||||
_cpu_info_string = os::strdup(buf);
|
||||
|
||||
_features_string = extract_features_string(_cpu_info_string,
|
||||
strnlen(_cpu_info_string, sizeof(buf)),
|
||||
cpu_info_size);
|
||||
|
||||
// Use AES instructions if available.
|
||||
if (supports_aes()) {
|
||||
@ -1206,7 +1176,6 @@ void VM_Version::get_processor_features() {
|
||||
FLAG_SET_DEFAULT(UseCRC32Intrinsics, false);
|
||||
}
|
||||
|
||||
#ifdef _LP64
|
||||
if (supports_avx2()) {
|
||||
if (FLAG_IS_DEFAULT(UseAdler32Intrinsics)) {
|
||||
UseAdler32Intrinsics = true;
|
||||
@ -1217,12 +1186,6 @@ void VM_Version::get_processor_features() {
|
||||
}
|
||||
FLAG_SET_DEFAULT(UseAdler32Intrinsics, false);
|
||||
}
|
||||
#else
|
||||
if (UseAdler32Intrinsics) {
|
||||
warning("Adler32Intrinsics not available on this CPU.");
|
||||
FLAG_SET_DEFAULT(UseAdler32Intrinsics, false);
|
||||
}
|
||||
#endif
|
||||
|
||||
if (supports_sse4_2() && supports_clmul()) {
|
||||
if (FLAG_IS_DEFAULT(UseCRC32CIntrinsics)) {
|
||||
@ -1246,7 +1209,6 @@ void VM_Version::get_processor_features() {
|
||||
FLAG_SET_DEFAULT(UseGHASHIntrinsics, false);
|
||||
}
|
||||
|
||||
#ifdef _LP64
|
||||
// ChaCha20 Intrinsics
|
||||
// As long as the system supports AVX as a baseline we can do a
|
||||
// SIMD-enabled block function. StubGenerator makes the determination
|
||||
@ -1262,24 +1224,14 @@ void VM_Version::get_processor_features() {
|
||||
}
|
||||
FLAG_SET_DEFAULT(UseChaCha20Intrinsics, false);
|
||||
}
|
||||
#else
|
||||
// No support currently for ChaCha20 intrinsics on 32-bit platforms
|
||||
if (UseChaCha20Intrinsics) {
|
||||
warning("ChaCha20 intrinsics are not available on this CPU.");
|
||||
FLAG_SET_DEFAULT(UseChaCha20Intrinsics, false);
|
||||
}
|
||||
#endif // _LP64
|
||||
|
||||
// Dilithium Intrinsics
|
||||
// Currently we only have them for AVX512
|
||||
#ifdef _LP64
|
||||
if (supports_evex() && supports_avx512bw()) {
|
||||
if (FLAG_IS_DEFAULT(UseDilithiumIntrinsics)) {
|
||||
UseDilithiumIntrinsics = true;
|
||||
}
|
||||
} else
|
||||
#endif
|
||||
if (UseDilithiumIntrinsics) {
|
||||
} else if (UseDilithiumIntrinsics) {
|
||||
warning("Intrinsics for ML-DSA are not available on this CPU.");
|
||||
FLAG_SET_DEFAULT(UseDilithiumIntrinsics, false);
|
||||
}
|
||||
@ -1308,7 +1260,7 @@ void VM_Version::get_processor_features() {
|
||||
UseMD5Intrinsics = true;
|
||||
}
|
||||
|
||||
if (supports_sha() LP64_ONLY(|| (supports_avx2() && supports_bmi2()))) {
|
||||
if (supports_sha() || (supports_avx2() && supports_bmi2())) {
|
||||
if (FLAG_IS_DEFAULT(UseSHA)) {
|
||||
UseSHA = true;
|
||||
}
|
||||
@ -1335,27 +1287,20 @@ void VM_Version::get_processor_features() {
|
||||
FLAG_SET_DEFAULT(UseSHA256Intrinsics, false);
|
||||
}
|
||||
|
||||
#ifdef _LP64
|
||||
// These are only supported on 64-bit
|
||||
if (UseSHA && supports_avx2() && (supports_bmi2() || supports_sha512())) {
|
||||
if (FLAG_IS_DEFAULT(UseSHA512Intrinsics)) {
|
||||
FLAG_SET_DEFAULT(UseSHA512Intrinsics, true);
|
||||
}
|
||||
} else
|
||||
#endif
|
||||
if (UseSHA512Intrinsics) {
|
||||
} else if (UseSHA512Intrinsics) {
|
||||
warning("Intrinsics for SHA-384 and SHA-512 crypto hash functions not available on this CPU.");
|
||||
FLAG_SET_DEFAULT(UseSHA512Intrinsics, false);
|
||||
}
|
||||
|
||||
#ifdef _LP64
|
||||
if (supports_evex() && supports_avx512bw()) {
|
||||
if (FLAG_IS_DEFAULT(UseSHA3Intrinsics)) {
|
||||
UseSHA3Intrinsics = true;
|
||||
}
|
||||
} else
|
||||
#endif
|
||||
if (UseSHA3Intrinsics) {
|
||||
} else if (UseSHA3Intrinsics) {
|
||||
warning("Intrinsics for SHA3-224, SHA3-256, SHA3-384 and SHA3-512 crypto hash functions not available on this CPU.");
|
||||
FLAG_SET_DEFAULT(UseSHA3Intrinsics, false);
|
||||
}
|
||||
@ -1377,11 +1322,7 @@ void VM_Version::get_processor_features() {
|
||||
max_vector_size = 64;
|
||||
}
|
||||
|
||||
#ifdef _LP64
|
||||
int min_vector_size = 4; // We require MaxVectorSize to be at least 4 on 64bit
|
||||
#else
|
||||
int min_vector_size = 0;
|
||||
#endif
|
||||
|
||||
if (!FLAG_IS_DEFAULT(MaxVectorSize)) {
|
||||
if (MaxVectorSize < min_vector_size) {
|
||||
@ -1405,7 +1346,7 @@ void VM_Version::get_processor_features() {
|
||||
if (MaxVectorSize > 0) {
|
||||
if (supports_avx() && PrintMiscellaneous && Verbose && TraceNewVectors) {
|
||||
tty->print_cr("State of YMM registers after signal handle:");
|
||||
int nreg = 2 LP64_ONLY(+2);
|
||||
int nreg = 4;
|
||||
const char* ymm_name[4] = {"0", "7", "8", "15"};
|
||||
for (int i = 0; i < nreg; i++) {
|
||||
tty->print("YMM%s:", ymm_name[i]);
|
||||
@ -1418,31 +1359,24 @@ void VM_Version::get_processor_features() {
|
||||
}
|
||||
#endif // COMPILER2 && ASSERT
|
||||
|
||||
#ifdef _LP64
|
||||
if ((supports_avx512ifma() && supports_avx512vlbw()) || supports_avxifma()) {
|
||||
if (FLAG_IS_DEFAULT(UsePoly1305Intrinsics)) {
|
||||
FLAG_SET_DEFAULT(UsePoly1305Intrinsics, true);
|
||||
}
|
||||
} else
|
||||
#endif
|
||||
if (UsePoly1305Intrinsics) {
|
||||
} else if (UsePoly1305Intrinsics) {
|
||||
warning("Intrinsics for Poly1305 crypto hash functions not available on this CPU.");
|
||||
FLAG_SET_DEFAULT(UsePoly1305Intrinsics, false);
|
||||
}
|
||||
|
||||
#ifdef _LP64
|
||||
if ((supports_avx512ifma() && supports_avx512vlbw()) || supports_avxifma()) {
|
||||
if (FLAG_IS_DEFAULT(UseIntPolyIntrinsics)) {
|
||||
FLAG_SET_DEFAULT(UseIntPolyIntrinsics, true);
|
||||
}
|
||||
} else
|
||||
#endif
|
||||
if (UseIntPolyIntrinsics) {
|
||||
} else if (UseIntPolyIntrinsics) {
|
||||
warning("Intrinsics for Polynomial crypto functions not available on this CPU.");
|
||||
FLAG_SET_DEFAULT(UseIntPolyIntrinsics, false);
|
||||
}
|
||||
|
||||
#ifdef _LP64
|
||||
if (FLAG_IS_DEFAULT(UseMultiplyToLenIntrinsic)) {
|
||||
UseMultiplyToLenIntrinsic = true;
|
||||
}
|
||||
@ -1458,38 +1392,6 @@ void VM_Version::get_processor_features() {
|
||||
if (FLAG_IS_DEFAULT(UseMontgomerySquareIntrinsic)) {
|
||||
UseMontgomerySquareIntrinsic = true;
|
||||
}
|
||||
#else
|
||||
if (UseMultiplyToLenIntrinsic) {
|
||||
if (!FLAG_IS_DEFAULT(UseMultiplyToLenIntrinsic)) {
|
||||
warning("multiplyToLen intrinsic is not available in 32-bit VM");
|
||||
}
|
||||
FLAG_SET_DEFAULT(UseMultiplyToLenIntrinsic, false);
|
||||
}
|
||||
if (UseMontgomeryMultiplyIntrinsic) {
|
||||
if (!FLAG_IS_DEFAULT(UseMontgomeryMultiplyIntrinsic)) {
|
||||
warning("montgomeryMultiply intrinsic is not available in 32-bit VM");
|
||||
}
|
||||
FLAG_SET_DEFAULT(UseMontgomeryMultiplyIntrinsic, false);
|
||||
}
|
||||
if (UseMontgomerySquareIntrinsic) {
|
||||
if (!FLAG_IS_DEFAULT(UseMontgomerySquareIntrinsic)) {
|
||||
warning("montgomerySquare intrinsic is not available in 32-bit VM");
|
||||
}
|
||||
FLAG_SET_DEFAULT(UseMontgomerySquareIntrinsic, false);
|
||||
}
|
||||
if (UseSquareToLenIntrinsic) {
|
||||
if (!FLAG_IS_DEFAULT(UseSquareToLenIntrinsic)) {
|
||||
warning("squareToLen intrinsic is not available in 32-bit VM");
|
||||
}
|
||||
FLAG_SET_DEFAULT(UseSquareToLenIntrinsic, false);
|
||||
}
|
||||
if (UseMulAddIntrinsic) {
|
||||
if (!FLAG_IS_DEFAULT(UseMulAddIntrinsic)) {
|
||||
warning("mulAdd intrinsic is not available in 32-bit VM");
|
||||
}
|
||||
FLAG_SET_DEFAULT(UseMulAddIntrinsic, false);
|
||||
}
|
||||
#endif // _LP64
|
||||
#endif // COMPILER2_OR_JVMCI
|
||||
|
||||
// On new cpus instructions which update whole XMM register should be used
|
||||
@ -1766,7 +1668,6 @@ void VM_Version::get_processor_features() {
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef _LP64
|
||||
if (UseSSE42Intrinsics) {
|
||||
if (FLAG_IS_DEFAULT(UseVectorizedMismatchIntrinsic)) {
|
||||
UseVectorizedMismatchIntrinsic = true;
|
||||
@ -1783,20 +1684,6 @@ void VM_Version::get_processor_features() {
|
||||
warning("vectorizedHashCode intrinsics are not available on this CPU");
|
||||
FLAG_SET_DEFAULT(UseVectorizedHashCodeIntrinsic, false);
|
||||
}
|
||||
#else
|
||||
if (UseVectorizedMismatchIntrinsic) {
|
||||
if (!FLAG_IS_DEFAULT(UseVectorizedMismatchIntrinsic)) {
|
||||
warning("vectorizedMismatch intrinsic is not available in 32-bit VM");
|
||||
}
|
||||
FLAG_SET_DEFAULT(UseVectorizedMismatchIntrinsic, false);
|
||||
}
|
||||
if (UseVectorizedHashCodeIntrinsic) {
|
||||
if (!FLAG_IS_DEFAULT(UseVectorizedHashCodeIntrinsic)) {
|
||||
warning("vectorizedHashCode intrinsic is not available in 32-bit VM");
|
||||
}
|
||||
FLAG_SET_DEFAULT(UseVectorizedHashCodeIntrinsic, false);
|
||||
}
|
||||
#endif // _LP64
|
||||
|
||||
// Use count leading zeros count instruction if available.
|
||||
if (supports_lzcnt()) {
|
||||
@ -1945,7 +1832,6 @@ void VM_Version::get_processor_features() {
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef _LP64
|
||||
// Prefetch settings
|
||||
|
||||
// Prefetch interval for gc copy/scan == 9 dcache lines. Derived from
|
||||
@ -1964,7 +1850,6 @@ void VM_Version::get_processor_features() {
|
||||
if (FLAG_IS_DEFAULT(PrefetchScanIntervalInBytes)) {
|
||||
FLAG_SET_DEFAULT(PrefetchScanIntervalInBytes, 576);
|
||||
}
|
||||
#endif
|
||||
|
||||
if (FLAG_IS_DEFAULT(ContendedPaddingWidth) &&
|
||||
(cache_line_size > ContendedPaddingWidth))
|
||||
@ -2195,11 +2080,9 @@ int VM_Version::avx3_threshold() {
|
||||
FLAG_IS_DEFAULT(AVX3Threshold)) ? 0 : AVX3Threshold;
|
||||
}
|
||||
|
||||
#if defined(_LP64)
|
||||
void VM_Version::clear_apx_test_state() {
|
||||
clear_apx_test_state_stub();
|
||||
}
|
||||
#endif
|
||||
|
||||
static bool _vm_version_initialized = false;
|
||||
|
||||
@ -2217,14 +2100,11 @@ void VM_Version::initialize() {
|
||||
g.generate_get_cpu_info());
|
||||
detect_virt_stub = CAST_TO_FN_PTR(detect_virt_stub_t,
|
||||
g.generate_detect_virt());
|
||||
|
||||
#if defined(_LP64)
|
||||
clear_apx_test_state_stub = CAST_TO_FN_PTR(clear_apx_test_state_t,
|
||||
g.clear_apx_test_state());
|
||||
#endif
|
||||
get_processor_features();
|
||||
|
||||
LP64_ONLY(Assembler::precompute_instructions();)
|
||||
Assembler::precompute_instructions();
|
||||
|
||||
if (VM_Version::supports_hv()) { // Supports hypervisor
|
||||
check_virtualizations();
|
||||
@ -2991,12 +2871,10 @@ uint64_t VM_Version::CpuidInfo::feature_flags() const {
|
||||
result |= CPU_CMOV;
|
||||
if (std_cpuid1_edx.bits.clflush != 0)
|
||||
result |= CPU_FLUSH;
|
||||
#ifdef _LP64
|
||||
// clflush should always be available on x86_64
|
||||
// if not we are in real trouble because we rely on it
|
||||
// to flush the code cache.
|
||||
assert ((result & CPU_FLUSH) != 0, "clflush should be available");
|
||||
#endif
|
||||
if (std_cpuid1_edx.bits.fxsr != 0 || (is_amd_family() &&
|
||||
ext_cpuid1_edx.bits.fxsr != 0))
|
||||
result |= CPU_FXSR;
|
||||
@ -3168,7 +3046,7 @@ uint64_t VM_Version::CpuidInfo::feature_flags() const {
|
||||
|
||||
bool VM_Version::os_supports_avx_vectors() {
|
||||
bool retVal = false;
|
||||
int nreg = 2 LP64_ONLY(+2);
|
||||
int nreg = 4;
|
||||
if (supports_evex()) {
|
||||
// Verify that OS save/restore all bits of EVEX registers
|
||||
// during signal processing.
|
||||
@ -3324,11 +3202,7 @@ int VM_Version::allocate_prefetch_distance(bool use_watermark_prefetch) {
|
||||
if (supports_sse4_2() && supports_ht()) { // Nehalem based cpus
|
||||
return 192;
|
||||
} else if (use_watermark_prefetch) { // watermark prefetching on Core
|
||||
#ifdef _LP64
|
||||
return 384;
|
||||
#else
|
||||
return 320;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
if (supports_sse2()) {
|
||||
|
||||
@ -642,7 +642,7 @@ public:
|
||||
static void set_cpuinfo_cont_addr_apx(address pc) { _cpuinfo_cont_addr_apx = pc; }
|
||||
static address cpuinfo_cont_addr_apx() { return _cpuinfo_cont_addr_apx; }
|
||||
|
||||
LP64_ONLY(static void clear_apx_test_state());
|
||||
static void clear_apx_test_state();
|
||||
|
||||
static void clean_cpuFeatures() { _features = 0; }
|
||||
static void set_avx_cpuFeatures() { _features |= (CPU_SSE | CPU_SSE2 | CPU_AVX | CPU_VZEROUPPER ); }
|
||||
@ -839,12 +839,12 @@ public:
|
||||
|
||||
// x86_64 supports fast class initialization checks
|
||||
static bool supports_fast_class_init_checks() {
|
||||
return LP64_ONLY(true) NOT_LP64(false); // not implemented on x86_32
|
||||
return true;
|
||||
}
|
||||
|
||||
// x86_64 supports secondary supers table
|
||||
constexpr static bool supports_secondary_supers_table() {
|
||||
return LP64_ONLY(true) NOT_LP64(false); // not implemented on x86_32
|
||||
return true;
|
||||
}
|
||||
|
||||
constexpr static bool supports_stack_watermark_barrier() {
|
||||
@ -879,11 +879,7 @@ public:
|
||||
// synchronize with other memory ops. so, it needs preceding
|
||||
// and trailing StoreStore fences.
|
||||
|
||||
#ifdef _LP64
|
||||
static bool supports_clflush(); // Can't inline due to header file conflict
|
||||
#else
|
||||
static bool supports_clflush() { return ((_features & CPU_FLUSH) != 0); }
|
||||
#endif // _LP64
|
||||
|
||||
// Note: CPU_FLUSHOPT and CPU_CLWB bits should always be zero for 32-bit
|
||||
static bool supports_clflushopt() { return ((_features & CPU_FLUSHOPT) != 0); }
|
||||
|
||||
@ -422,6 +422,18 @@ source_hpp %{
|
||||
|
||||
#include "peephole_x86_64.hpp"
|
||||
|
||||
bool castLL_is_imm32(const Node* n);
|
||||
|
||||
%}
|
||||
|
||||
source %{
|
||||
|
||||
bool castLL_is_imm32(const Node* n) {
|
||||
assert(n->is_CastLL(), "must be a CastLL");
|
||||
const TypeLong* t = n->bottom_type()->is_long();
|
||||
return (t->_lo == min_jlong || Assembler::is_simm32(t->_lo)) && (t->_hi == max_jlong || Assembler::is_simm32(t->_hi));
|
||||
}
|
||||
|
||||
%}
|
||||
|
||||
// Register masks
|
||||
@ -1584,14 +1596,11 @@ uint MachUEPNode::size(PhaseRegAlloc* ra_) const
|
||||
//=============================================================================
|
||||
|
||||
bool Matcher::supports_vector_calling_convention(void) {
|
||||
if (EnableVectorSupport && UseVectorStubs) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
return EnableVectorSupport;
|
||||
}
|
||||
|
||||
OptoRegPair Matcher::vector_return_value(uint ideal_reg) {
|
||||
assert(EnableVectorSupport && UseVectorStubs, "sanity");
|
||||
assert(EnableVectorSupport, "sanity");
|
||||
int lo = XMM0_num;
|
||||
int hi = XMM0b_num;
|
||||
if (ideal_reg == Op_VecX) hi = XMM0d_num;
|
||||
@ -1838,14 +1847,14 @@ encode %{
|
||||
%}
|
||||
|
||||
enc_class clear_avx %{
|
||||
debug_only(int off0 = __ offset());
|
||||
DEBUG_ONLY(int off0 = __ offset());
|
||||
if (generate_vzeroupper(Compile::current())) {
|
||||
// Clear upper bits of YMM registers to avoid AVX <-> SSE transition penalty
|
||||
// Clear upper bits of YMM registers when current compiled code uses
|
||||
// wide vectors to avoid AVX <-> SSE transition penalty during call.
|
||||
__ vzeroupper();
|
||||
}
|
||||
debug_only(int off1 = __ offset());
|
||||
DEBUG_ONLY(int off1 = __ offset());
|
||||
assert(off1 - off0 == clear_avx_size(), "correct size prediction");
|
||||
%}
|
||||
|
||||
@ -7605,6 +7614,7 @@ instruct castPP(rRegP dst)
|
||||
|
||||
instruct castII(rRegI dst)
|
||||
%{
|
||||
predicate(VerifyConstraintCasts == 0);
|
||||
match(Set dst (CastII dst));
|
||||
|
||||
size(0);
|
||||
@ -7614,8 +7624,22 @@ instruct castII(rRegI dst)
|
||||
ins_pipe(empty);
|
||||
%}
|
||||
|
||||
instruct castII_checked(rRegI dst, rFlagsReg cr)
|
||||
%{
|
||||
predicate(VerifyConstraintCasts > 0);
|
||||
match(Set dst (CastII dst));
|
||||
|
||||
effect(KILL cr);
|
||||
format %{ "# cast_checked_II $dst" %}
|
||||
ins_encode %{
|
||||
__ verify_int_in_range(_idx, bottom_type()->is_int(), $dst$$Register);
|
||||
%}
|
||||
ins_pipe(pipe_slow);
|
||||
%}
|
||||
|
||||
instruct castLL(rRegL dst)
|
||||
%{
|
||||
predicate(VerifyConstraintCasts == 0);
|
||||
match(Set dst (CastLL dst));
|
||||
|
||||
size(0);
|
||||
@ -7625,6 +7649,32 @@ instruct castLL(rRegL dst)
|
||||
ins_pipe(empty);
|
||||
%}
|
||||
|
||||
instruct castLL_checked_L32(rRegL dst, rFlagsReg cr)
|
||||
%{
|
||||
predicate(VerifyConstraintCasts > 0 && castLL_is_imm32(n));
|
||||
match(Set dst (CastLL dst));
|
||||
|
||||
effect(KILL cr);
|
||||
format %{ "# cast_checked_LL $dst" %}
|
||||
ins_encode %{
|
||||
__ verify_long_in_range(_idx, bottom_type()->is_long(), $dst$$Register, noreg);
|
||||
%}
|
||||
ins_pipe(pipe_slow);
|
||||
%}
|
||||
|
||||
instruct castLL_checked(rRegL dst, rRegL tmp, rFlagsReg cr)
|
||||
%{
|
||||
predicate(VerifyConstraintCasts > 0 && !castLL_is_imm32(n));
|
||||
match(Set dst (CastLL dst));
|
||||
|
||||
effect(KILL cr, TEMP tmp);
|
||||
format %{ "# cast_checked_LL $dst\tusing $tmp as TEMP" %}
|
||||
ins_encode %{
|
||||
__ verify_long_in_range(_idx, bottom_type()->is_long(), $dst$$Register, $tmp$$Register);
|
||||
%}
|
||||
ins_pipe(pipe_slow);
|
||||
%}
|
||||
|
||||
instruct castFF(regF dst)
|
||||
%{
|
||||
match(Set dst (CastFF dst));
|
||||
|
||||
@ -151,6 +151,6 @@ void VM_Version::initialize_cpu_information(void) {
|
||||
_no_of_threads = _no_of_cores;
|
||||
_no_of_sockets = _no_of_cores;
|
||||
snprintf(_cpu_name, CPU_TYPE_DESC_BUF_SIZE - 1, "Zero VM");
|
||||
snprintf(_cpu_desc, CPU_DETAILED_DESC_BUF_SIZE, "%s", _features_string);
|
||||
snprintf(_cpu_desc, CPU_DETAILED_DESC_BUF_SIZE, "%s", _cpu_info_string);
|
||||
_initialized = true;
|
||||
}
|
||||
|
||||
@ -132,8 +132,6 @@ extern "C" int getargs(procsinfo*, int, char*, int);
|
||||
|
||||
#define MAX_PATH (2 * K)
|
||||
|
||||
// for timer info max values which include all bits
|
||||
#define ALL_64_BITS CONST64(0xFFFFFFFFFFFFFFFF)
|
||||
// for multipage initialization error analysis (in 'g_multipage_error')
|
||||
#define ERROR_MP_OS_TOO_OLD 100
|
||||
#define ERROR_MP_EXTSHM_ACTIVE 101
|
||||
@ -906,7 +904,7 @@ jlong os::javaTimeNanos() {
|
||||
}
|
||||
|
||||
void os::javaTimeNanos_info(jvmtiTimerInfo *info_ptr) {
|
||||
info_ptr->max_value = ALL_64_BITS;
|
||||
info_ptr->max_value = all_bits_jlong;
|
||||
// mread_real_time() is monotonic (see 'os::javaTimeNanos()')
|
||||
info_ptr->may_skip_backward = false;
|
||||
info_ptr->may_skip_forward = false;
|
||||
@ -2571,14 +2569,14 @@ jlong os::thread_cpu_time(Thread *thread, bool user_sys_cpu_time) {
|
||||
}
|
||||
|
||||
void os::current_thread_cpu_time_info(jvmtiTimerInfo *info_ptr) {
|
||||
info_ptr->max_value = ALL_64_BITS; // will not wrap in less than 64 bits
|
||||
info_ptr->max_value = all_bits_jlong; // will not wrap in less than 64 bits
|
||||
info_ptr->may_skip_backward = false; // elapsed time not wall time
|
||||
info_ptr->may_skip_forward = false; // elapsed time not wall time
|
||||
info_ptr->kind = JVMTI_TIMER_TOTAL_CPU; // user+system time is returned
|
||||
}
|
||||
|
||||
void os::thread_cpu_time_info(jvmtiTimerInfo *info_ptr) {
|
||||
info_ptr->max_value = ALL_64_BITS; // will not wrap in less than 64 bits
|
||||
info_ptr->max_value = all_bits_jlong; // will not wrap in less than 64 bits
|
||||
info_ptr->may_skip_backward = false; // elapsed time not wall time
|
||||
info_ptr->may_skip_forward = false; // elapsed time not wall time
|
||||
info_ptr->kind = JVMTI_TIMER_TOTAL_CPU; // user+system time is returned
|
||||
|
||||
@ -72,7 +72,7 @@ enum {
|
||||
* Get info for requested PID from /proc/<pid>/psinfo file
|
||||
*/
|
||||
static bool read_psinfo(const u_longlong_t& pid, psinfo_t& psinfo) {
|
||||
static size_t BUF_LENGTH = 32 + sizeof(u_longlong_t);
|
||||
const size_t BUF_LENGTH = 32 + sizeof(u_longlong_t);
|
||||
|
||||
FILE* fp;
|
||||
char buf[BUF_LENGTH];
|
||||
@ -118,7 +118,6 @@ static OSReturn get_lcpu_ticks(perfstat_id_t* lcpu_name, cpu_tick_store_t* ptick
|
||||
* Return CPU load caused by the currently executing process (the jvm).
|
||||
*/
|
||||
static OSReturn get_jvm_load(double* jvm_uload, double* jvm_sload) {
|
||||
static clock_t ticks_per_sec = sysconf(_SC_CLK_TCK);
|
||||
static u_longlong_t last_timebase = 0;
|
||||
|
||||
perfstat_process_t jvm_stats;
|
||||
@ -204,8 +203,6 @@ static bool populate_lcpu_names(int ncpus, perfstat_id_t* lcpu_names) {
|
||||
* (Context Switches / Tick) * (Tick / s) = Context Switches per second
|
||||
*/
|
||||
static OSReturn perf_context_switch_rate(double* rate) {
|
||||
static clock_t ticks_per_sec = sysconf(_SC_CLK_TCK);
|
||||
|
||||
u_longlong_t ticks;
|
||||
perfstat_cpu_total_t cpu_stats;
|
||||
|
||||
@ -214,7 +211,7 @@ static OSReturn perf_context_switch_rate(double* rate) {
|
||||
}
|
||||
|
||||
ticks = cpu_stats.user + cpu_stats.sys + cpu_stats.idle + cpu_stats.wait;
|
||||
*rate = (cpu_stats.pswitch / ticks) * ticks_per_sec;
|
||||
*rate = (cpu_stats.pswitch / ticks) * os::Posix::clock_tics_per_second();
|
||||
|
||||
return OS_OK;
|
||||
}
|
||||
|
||||
@ -77,7 +77,7 @@ ZPhysicalMemoryBacking::ZPhysicalMemoryBacking(size_t max_capacity)
|
||||
_initialized(false) {
|
||||
|
||||
// Reserve address space for backing memory
|
||||
_base = (uintptr_t)os::reserve_memory(max_capacity, false, mtJavaHeap);
|
||||
_base = (uintptr_t)os::reserve_memory(max_capacity, mtJavaHeap);
|
||||
if (_base == 0) {
|
||||
// Failed
|
||||
ZInitialize::error("Failed to reserve address space for backing memory");
|
||||
|
||||
@ -114,9 +114,6 @@
|
||||
|
||||
#define MAX_PATH (2 * K)
|
||||
|
||||
// for timer info max values which include all bits
|
||||
#define ALL_64_BITS CONST64(0xFFFFFFFFFFFFFFFF)
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// global variables
|
||||
julong os::Bsd::_physical_memory = 0;
|
||||
@ -815,7 +812,7 @@ jlong os::javaTimeNanos() {
|
||||
}
|
||||
|
||||
void os::javaTimeNanos_info(jvmtiTimerInfo *info_ptr) {
|
||||
info_ptr->max_value = ALL_64_BITS;
|
||||
info_ptr->max_value = all_bits_jlong;
|
||||
info_ptr->may_skip_backward = false; // not subject to resetting or drifting
|
||||
info_ptr->may_skip_forward = false; // not subject to resetting or drifting
|
||||
info_ptr->kind = JVMTI_TIMER_ELAPSED; // elapsed not CPU time
|
||||
@ -2423,14 +2420,14 @@ jlong os::thread_cpu_time(Thread *thread, bool user_sys_cpu_time) {
|
||||
|
||||
|
||||
void os::current_thread_cpu_time_info(jvmtiTimerInfo *info_ptr) {
|
||||
info_ptr->max_value = ALL_64_BITS; // will not wrap in less than 64 bits
|
||||
info_ptr->max_value = all_bits_jlong; // will not wrap in less than 64 bits
|
||||
info_ptr->may_skip_backward = false; // elapsed time not wall time
|
||||
info_ptr->may_skip_forward = false; // elapsed time not wall time
|
||||
info_ptr->kind = JVMTI_TIMER_TOTAL_CPU; // user+system time is returned
|
||||
}
|
||||
|
||||
void os::thread_cpu_time_info(jvmtiTimerInfo *info_ptr) {
|
||||
info_ptr->max_value = ALL_64_BITS; // will not wrap in less than 64 bits
|
||||
info_ptr->max_value = all_bits_jlong; // will not wrap in less than 64 bits
|
||||
info_ptr->may_skip_backward = false; // elapsed time not wall time
|
||||
info_ptr->may_skip_forward = false; // elapsed time not wall time
|
||||
info_ptr->kind = JVMTI_TIMER_TOTAL_CPU; // user+system time is returned
|
||||
|
||||
@ -139,9 +139,6 @@
|
||||
|
||||
#define MAX_PATH (2 * K)
|
||||
|
||||
// for timer info max values which include all bits
|
||||
#define ALL_64_BITS CONST64(0xFFFFFFFFFFFFFFFF)
|
||||
|
||||
#ifdef MUSL_LIBC
|
||||
// dlvsym is not a part of POSIX
|
||||
// and musl libc doesn't implement it.
|
||||
@ -213,8 +210,6 @@ typedef int (*malloc_info_func_t)(int options, FILE *stream);
|
||||
static malloc_info_func_t g_malloc_info = nullptr;
|
||||
#endif // __GLIBC__
|
||||
|
||||
static int clock_tics_per_sec = 100;
|
||||
|
||||
// If the VM might have been created on the primordial thread, we need to resolve the
|
||||
// primordial thread stack bounds and check if the current thread might be the
|
||||
// primordial thread in places. If we know that the primordial thread is never used,
|
||||
@ -1667,7 +1662,7 @@ void * os::dll_load(const char *filename, char *ebuf, int ebuflen) {
|
||||
}
|
||||
|
||||
ThreadInVMfromNative tiv(jt);
|
||||
debug_only(VMNativeEntryWrapper vew;)
|
||||
DEBUG_ONLY(VMNativeEntryWrapper vew;)
|
||||
|
||||
VM_LinuxDllLoad op(filename, ebuf, ebuflen);
|
||||
VMThread::execute(&op);
|
||||
@ -4381,8 +4376,6 @@ static void check_pax(void) {
|
||||
// this is called _before_ most of the global arguments have been parsed
|
||||
void os::init(void) {
|
||||
char dummy; // used to get a guess on initial stack address
|
||||
|
||||
clock_tics_per_sec = checked_cast<int>(sysconf(_SC_CLK_TCK));
|
||||
int sys_pg_size = checked_cast<int>(sysconf(_SC_PAGESIZE));
|
||||
if (sys_pg_size < 0) {
|
||||
fatal("os_linux.cpp: os::init: sysconf failed (%s)",
|
||||
@ -4575,7 +4568,7 @@ static void workaround_expand_exec_shield_cs_limit() {
|
||||
*/
|
||||
char* hint = (char*)(os::Linux::initial_thread_stack_bottom() -
|
||||
(StackOverflow::stack_guard_zone_size() + page_size));
|
||||
char* codebuf = os::attempt_reserve_memory_at(hint, page_size, false, mtThread);
|
||||
char* codebuf = os::attempt_reserve_memory_at(hint, page_size, mtThread);
|
||||
|
||||
if (codebuf == nullptr) {
|
||||
// JDK-8197429: There may be a stack gap of one megabyte between
|
||||
@ -4583,7 +4576,7 @@ static void workaround_expand_exec_shield_cs_limit() {
|
||||
// Linux kernel workaround for CVE-2017-1000364. If we failed to
|
||||
// map our codebuf, try again at an address one megabyte lower.
|
||||
hint -= 1 * M;
|
||||
codebuf = os::attempt_reserve_memory_at(hint, page_size, false, mtThread);
|
||||
codebuf = os::attempt_reserve_memory_at(hint, page_size, mtThread);
|
||||
}
|
||||
|
||||
if ((codebuf == nullptr) || (!os::commit_memory(codebuf, page_size, true))) {
|
||||
@ -5135,21 +5128,21 @@ static jlong slow_thread_cpu_time(Thread *thread, bool user_sys_cpu_time) {
|
||||
&user_time, &sys_time);
|
||||
if (count != 13) return -1;
|
||||
if (user_sys_cpu_time) {
|
||||
return ((jlong)sys_time + (jlong)user_time) * (1000000000 / clock_tics_per_sec);
|
||||
return ((jlong)sys_time + (jlong)user_time) * (1000000000 / os::Posix::clock_tics_per_second());
|
||||
} else {
|
||||
return (jlong)user_time * (1000000000 / clock_tics_per_sec);
|
||||
return (jlong)user_time * (1000000000 / os::Posix::clock_tics_per_second());
|
||||
}
|
||||
}
|
||||
|
||||
void os::current_thread_cpu_time_info(jvmtiTimerInfo *info_ptr) {
|
||||
info_ptr->max_value = ALL_64_BITS; // will not wrap in less than 64 bits
|
||||
info_ptr->max_value = all_bits_jlong; // will not wrap in less than 64 bits
|
||||
info_ptr->may_skip_backward = false; // elapsed time not wall time
|
||||
info_ptr->may_skip_forward = false; // elapsed time not wall time
|
||||
info_ptr->kind = JVMTI_TIMER_TOTAL_CPU; // user+system time is returned
|
||||
}
|
||||
|
||||
void os::thread_cpu_time_info(jvmtiTimerInfo *info_ptr) {
|
||||
info_ptr->max_value = ALL_64_BITS; // will not wrap in less than 64 bits
|
||||
info_ptr->max_value = all_bits_jlong; // will not wrap in less than 64 bits
|
||||
info_ptr->may_skip_backward = false; // elapsed time not wall time
|
||||
info_ptr->may_skip_forward = false; // elapsed time not wall time
|
||||
info_ptr->kind = JVMTI_TIMER_TOTAL_CPU; // user+system time is returned
|
||||
|
||||
@ -492,9 +492,9 @@ static char* chop_extra_memory(size_t size, size_t alignment, char* extra_base,
|
||||
// Multiple threads can race in this code, and can remap over each other with MAP_FIXED,
|
||||
// so on posix, unmap the section at the start and at the end of the chunk that we mapped
|
||||
// rather than unmapping and remapping the whole chunk to get requested alignment.
|
||||
char* os::reserve_memory_aligned(size_t size, size_t alignment, bool exec) {
|
||||
char* os::reserve_memory_aligned(size_t size, size_t alignment, MemTag mem_tag, bool exec) {
|
||||
size_t extra_size = calculate_aligned_extra_size(size, alignment);
|
||||
char* extra_base = os::reserve_memory(extra_size, exec);
|
||||
char* extra_base = os::reserve_memory(extra_size, mem_tag, exec);
|
||||
if (extra_base == nullptr) {
|
||||
return nullptr;
|
||||
}
|
||||
@ -1326,6 +1326,10 @@ void os::Posix::init_2(void) {
|
||||
_use_clock_monotonic_condattr ? "CLOCK_MONOTONIC" : "the default clock");
|
||||
}
|
||||
|
||||
int os::Posix::clock_tics_per_second() {
|
||||
return clock_tics_per_sec;
|
||||
}
|
||||
|
||||
// Utility to convert the given timeout to an absolute timespec
|
||||
// (based on the appropriate clock) to use with pthread_cond_timewait,
|
||||
// and sem_timedwait().
|
||||
@ -1473,12 +1477,9 @@ jlong os::javaTimeNanos() {
|
||||
return result;
|
||||
}
|
||||
|
||||
// for timer info max values which include all bits
|
||||
#define ALL_64_BITS CONST64(0xFFFFFFFFFFFFFFFF)
|
||||
|
||||
void os::javaTimeNanos_info(jvmtiTimerInfo *info_ptr) {
|
||||
// CLOCK_MONOTONIC - amount of time since some arbitrary point in the past
|
||||
info_ptr->max_value = ALL_64_BITS;
|
||||
info_ptr->max_value = all_bits_jlong;
|
||||
info_ptr->may_skip_backward = false; // not subject to resetting or drifting
|
||||
info_ptr->may_skip_forward = false; // not subject to resetting or drifting
|
||||
info_ptr->kind = JVMTI_TIMER_ELAPSED; // elapsed not CPU time
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 1999, 2024, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 1999, 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
|
||||
@ -91,6 +91,9 @@ public:
|
||||
|
||||
static void to_RTC_abstime(timespec* abstime, int64_t millis);
|
||||
|
||||
// clock ticks per second of the system
|
||||
static int clock_tics_per_second();
|
||||
|
||||
static bool handle_stack_overflow(JavaThread* thread, address addr, address pc,
|
||||
const void* ucVoid,
|
||||
address* stub);
|
||||
|
||||
@ -64,7 +64,7 @@ static char* backing_store_file_name = nullptr; // name of the backing store
|
||||
static char* create_standard_memory(size_t size) {
|
||||
|
||||
// allocate an aligned chuck of memory
|
||||
char* mapAddress = os::reserve_memory(size);
|
||||
char* mapAddress = os::reserve_memory(size, mtInternal);
|
||||
|
||||
if (mapAddress == nullptr) {
|
||||
return nullptr;
|
||||
|
||||
@ -147,7 +147,7 @@ public:
|
||||
};
|
||||
|
||||
|
||||
debug_only(static bool signal_sets_initialized = false);
|
||||
DEBUG_ONLY(static bool signal_sets_initialized = false);
|
||||
static sigset_t unblocked_sigs, vm_sigs, preinstalled_sigs;
|
||||
|
||||
// Our own signal handlers should never ever get replaced by a third party one.
|
||||
@ -1547,7 +1547,7 @@ static void signal_sets_init() {
|
||||
if (!ReduceSignalUsage) {
|
||||
sigaddset(&vm_sigs, BREAK_SIGNAL);
|
||||
}
|
||||
debug_only(signal_sets_initialized = true);
|
||||
DEBUG_ONLY(signal_sets_initialized = true);
|
||||
}
|
||||
|
||||
// These are signals that are unblocked while a thread is running Java.
|
||||
|
||||
@ -112,9 +112,6 @@
|
||||
#include <winsock2.h>
|
||||
#include <versionhelpers.h>
|
||||
|
||||
// for timer info max values which include all bits
|
||||
#define ALL_64_BITS CONST64(-1)
|
||||
|
||||
// For DLL loading/load error detection
|
||||
// Values of PE COFF
|
||||
#define IMAGE_FILE_PTR_TO_SIGNATURE 0x3c
|
||||
@ -1225,16 +1222,16 @@ void os::javaTimeNanos_info(jvmtiTimerInfo *info_ptr) {
|
||||
if (freq < NANOSECS_PER_SEC) {
|
||||
// the performance counter is 64 bits and we will
|
||||
// be multiplying it -- so no wrap in 64 bits
|
||||
info_ptr->max_value = ALL_64_BITS;
|
||||
info_ptr->max_value = all_bits_jlong;
|
||||
} else if (freq > NANOSECS_PER_SEC) {
|
||||
// use the max value the counter can reach to
|
||||
// determine the max value which could be returned
|
||||
julong max_counter = (julong)ALL_64_BITS;
|
||||
julong max_counter = (julong)all_bits_jlong;
|
||||
info_ptr->max_value = (jlong)(max_counter / (freq / NANOSECS_PER_SEC));
|
||||
} else {
|
||||
// the performance counter is 64 bits and we will
|
||||
// be using it directly -- so no wrap in 64 bits
|
||||
info_ptr->max_value = ALL_64_BITS;
|
||||
info_ptr->max_value = all_bits_jlong;
|
||||
}
|
||||
|
||||
// using a counter, so no skipping
|
||||
@ -3020,7 +3017,7 @@ static char* allocate_pages_individually(size_t bytes, char* addr, DWORD flags,
|
||||
PAGE_READWRITE);
|
||||
// If reservation failed, return null
|
||||
if (p_buf == nullptr) return nullptr;
|
||||
MemTracker::record_virtual_memory_reserve((address)p_buf, size_of_reserve, CALLER_PC);
|
||||
MemTracker::record_virtual_memory_reserve((address)p_buf, size_of_reserve, CALLER_PC, mtNone);
|
||||
os::release_memory(p_buf, bytes + chunk_size);
|
||||
|
||||
// we still need to round up to a page boundary (in case we are using large pages)
|
||||
@ -3081,7 +3078,7 @@ static char* allocate_pages_individually(size_t bytes, char* addr, DWORD flags,
|
||||
// need to create a dummy 'reserve' record to match
|
||||
// the release.
|
||||
MemTracker::record_virtual_memory_reserve((address)p_buf,
|
||||
bytes_to_release, CALLER_PC);
|
||||
bytes_to_release, CALLER_PC, mtNone);
|
||||
os::release_memory(p_buf, bytes_to_release);
|
||||
}
|
||||
#ifdef ASSERT
|
||||
@ -3099,9 +3096,9 @@ static char* allocate_pages_individually(size_t bytes, char* addr, DWORD flags,
|
||||
// Although the memory is allocated individually, it is returned as one.
|
||||
// NMT records it as one block.
|
||||
if ((flags & MEM_COMMIT) != 0) {
|
||||
MemTracker::record_virtual_memory_reserve_and_commit((address)p_buf, bytes, CALLER_PC);
|
||||
MemTracker::record_virtual_memory_reserve_and_commit((address)p_buf, bytes, CALLER_PC, mtNone);
|
||||
} else {
|
||||
MemTracker::record_virtual_memory_reserve((address)p_buf, bytes, CALLER_PC);
|
||||
MemTracker::record_virtual_memory_reserve((address)p_buf, bytes, CALLER_PC, mtNone);
|
||||
}
|
||||
|
||||
// made it this far, success
|
||||
@ -3241,7 +3238,7 @@ char* os::replace_existing_mapping_with_file_mapping(char* base, size_t size, in
|
||||
// Multiple threads can race in this code but it's not possible to unmap small sections of
|
||||
// virtual space to get requested alignment, like posix-like os's.
|
||||
// Windows prevents multiple thread from remapping over each other so this loop is thread-safe.
|
||||
static char* map_or_reserve_memory_aligned(size_t size, size_t alignment, int file_desc, MemTag mem_tag = mtNone) {
|
||||
static char* map_or_reserve_memory_aligned(size_t size, size_t alignment, int file_desc, MemTag mem_tag) {
|
||||
assert(is_aligned(alignment, os::vm_allocation_granularity()),
|
||||
"Alignment must be a multiple of allocation granularity (page size)");
|
||||
assert(is_aligned(size, os::vm_allocation_granularity()),
|
||||
@ -3255,7 +3252,7 @@ static char* map_or_reserve_memory_aligned(size_t size, size_t alignment, int fi
|
||||
|
||||
for (int attempt = 0; attempt < max_attempts && aligned_base == nullptr; attempt ++) {
|
||||
char* extra_base = file_desc != -1 ? os::map_memory_to_file(extra_size, file_desc, mem_tag) :
|
||||
os::reserve_memory(extra_size, false, mem_tag);
|
||||
os::reserve_memory(extra_size, mem_tag);
|
||||
if (extra_base == nullptr) {
|
||||
return nullptr;
|
||||
}
|
||||
@ -3272,7 +3269,7 @@ static char* map_or_reserve_memory_aligned(size_t size, size_t alignment, int fi
|
||||
// Attempt to map, into the just vacated space, the slightly smaller aligned area.
|
||||
// Which may fail, hence the loop.
|
||||
aligned_base = file_desc != -1 ? os::attempt_map_memory_to_file_at(aligned_base, size, file_desc, mem_tag) :
|
||||
os::attempt_reserve_memory_at(aligned_base, size, false, mem_tag);
|
||||
os::attempt_reserve_memory_at(aligned_base, size, mem_tag);
|
||||
}
|
||||
|
||||
assert(aligned_base != nullptr,
|
||||
@ -3281,9 +3278,9 @@ static char* map_or_reserve_memory_aligned(size_t size, size_t alignment, int fi
|
||||
return aligned_base;
|
||||
}
|
||||
|
||||
char* os::reserve_memory_aligned(size_t size, size_t alignment, bool exec) {
|
||||
char* os::reserve_memory_aligned(size_t size, size_t alignment, MemTag mem_tag, bool exec) {
|
||||
// exec can be ignored
|
||||
return map_or_reserve_memory_aligned(size, alignment, -1 /* file_desc */);
|
||||
return map_or_reserve_memory_aligned(size, alignment, -1/* file_desc */, mem_tag);
|
||||
}
|
||||
|
||||
char* os::map_memory_to_file_aligned(size_t size, size_t alignment, int fd, MemTag mem_tag) {
|
||||
@ -4813,14 +4810,14 @@ jlong os::thread_cpu_time(Thread* thread, bool user_sys_cpu_time) {
|
||||
}
|
||||
|
||||
void os::current_thread_cpu_time_info(jvmtiTimerInfo *info_ptr) {
|
||||
info_ptr->max_value = ALL_64_BITS; // the max value -- all 64 bits
|
||||
info_ptr->max_value = all_bits_jlong; // the max value -- all 64 bits
|
||||
info_ptr->may_skip_backward = false; // GetThreadTimes returns absolute time
|
||||
info_ptr->may_skip_forward = false; // GetThreadTimes returns absolute time
|
||||
info_ptr->kind = JVMTI_TIMER_TOTAL_CPU; // user+system time is returned
|
||||
}
|
||||
|
||||
void os::thread_cpu_time_info(jvmtiTimerInfo *info_ptr) {
|
||||
info_ptr->max_value = ALL_64_BITS; // the max value -- all 64 bits
|
||||
info_ptr->max_value = all_bits_jlong; // the max value -- all 64 bits
|
||||
info_ptr->may_skip_backward = false; // GetThreadTimes returns absolute time
|
||||
info_ptr->may_skip_forward = false; // GetThreadTimes returns absolute time
|
||||
info_ptr->kind = JVMTI_TIMER_TOTAL_CPU; // user+system time is returned
|
||||
@ -5188,7 +5185,7 @@ char* os::pd_map_memory(int fd, const char* file_name, size_t file_offset,
|
||||
}
|
||||
|
||||
// Record virtual memory allocation
|
||||
MemTracker::record_virtual_memory_reserve_and_commit((address)addr, bytes, CALLER_PC);
|
||||
MemTracker::record_virtual_memory_reserve_and_commit((address)addr, bytes, CALLER_PC, mtNone);
|
||||
|
||||
DWORD bytes_read;
|
||||
OVERLAPPED overlapped;
|
||||
|
||||
@ -54,7 +54,7 @@ typedef BOOL (WINAPI *SetSecurityDescriptorControlFnPtr)(
|
||||
static char* create_standard_memory(size_t size) {
|
||||
|
||||
// allocate an aligned chuck of memory
|
||||
char* mapAddress = os::reserve_memory(size);
|
||||
char* mapAddress = os::reserve_memory(size, mtInternal);
|
||||
|
||||
if (mapAddress == nullptr) {
|
||||
return nullptr;
|
||||
|
||||
@ -75,6 +75,14 @@
|
||||
#define HWCAP_PACA (1 << 30)
|
||||
#endif
|
||||
|
||||
#ifndef HWCAP_FPHP
|
||||
#define HWCAP_FPHP (1<<9)
|
||||
#endif
|
||||
|
||||
#ifndef HWCAP_ASIMDHP
|
||||
#define HWCAP_ASIMDHP (1<<10)
|
||||
#endif
|
||||
|
||||
#ifndef HWCAP2_SVE2
|
||||
#define HWCAP2_SVE2 (1 << 1)
|
||||
#endif
|
||||
@ -119,6 +127,8 @@ void VM_Version::get_os_cpu_info() {
|
||||
static_assert(CPU_SHA512 == HWCAP_SHA512, "Flag CPU_SHA512 must follow Linux HWCAP");
|
||||
static_assert(CPU_SVE == HWCAP_SVE, "Flag CPU_SVE must follow Linux HWCAP");
|
||||
static_assert(CPU_PACA == HWCAP_PACA, "Flag CPU_PACA must follow Linux HWCAP");
|
||||
static_assert(CPU_FPHP == HWCAP_FPHP, "Flag CPU_FPHP must follow Linux HWCAP");
|
||||
static_assert(CPU_ASIMDHP == HWCAP_ASIMDHP, "Flag CPU_ASIMDHP must follow Linux HWCAP");
|
||||
_features = auxv & (
|
||||
HWCAP_FP |
|
||||
HWCAP_ASIMD |
|
||||
@ -133,7 +143,9 @@ void VM_Version::get_os_cpu_info() {
|
||||
HWCAP_SHA3 |
|
||||
HWCAP_SHA512 |
|
||||
HWCAP_SVE |
|
||||
HWCAP_PACA);
|
||||
HWCAP_PACA |
|
||||
HWCAP_FPHP |
|
||||
HWCAP_ASIMDHP);
|
||||
|
||||
if (auxv2 & HWCAP2_SVE2) _features |= CPU_SVE2;
|
||||
if (auxv2 & HWCAP2_SVEBITPERM) _features |= CPU_SVEBITPERM;
|
||||
|
||||
@ -129,6 +129,9 @@ void VM_Version::setup_cpu_available_features() {
|
||||
snprintf(buf, sizeof(buf)/2, "%s ", uarch);
|
||||
}
|
||||
os::free((void*) uarch);
|
||||
|
||||
int features_offset = strnlen(buf, sizeof(buf));
|
||||
|
||||
strcat(buf, "rv64");
|
||||
int i = 0;
|
||||
while (_feature_list[i] != nullptr) {
|
||||
@ -191,7 +194,9 @@ void VM_Version::setup_cpu_available_features() {
|
||||
}
|
||||
}
|
||||
|
||||
_features_string = os::strdup(buf);
|
||||
_cpu_info_string = os::strdup(buf);
|
||||
|
||||
_features_string = _cpu_info_string + features_offset;
|
||||
}
|
||||
|
||||
void VM_Version::os_aux_features() {
|
||||
|
||||
@ -73,7 +73,7 @@ class Label;
|
||||
*/
|
||||
class Label {
|
||||
private:
|
||||
enum { PatchCacheSize = 4 debug_only( +4 ) };
|
||||
enum { PatchCacheSize = 4 DEBUG_ONLY( +4 ) };
|
||||
|
||||
// _loc encodes both the binding state (via its sign)
|
||||
// and the binding locator (via its value) of a label.
|
||||
|
||||
@ -92,7 +92,7 @@ CodeBuffer::CodeBuffer(CodeBlob* blob) DEBUG_ONLY(: Scrubber(this, sizeof(*this)
|
||||
// Provide code buffer with meaningful name
|
||||
initialize_misc(blob->name());
|
||||
initialize(blob->content_begin(), blob->content_size());
|
||||
debug_only(verify_section_allocation();)
|
||||
DEBUG_ONLY(verify_section_allocation();)
|
||||
}
|
||||
|
||||
void CodeBuffer::initialize(csize_t code_size, csize_t locs_size) {
|
||||
@ -120,7 +120,7 @@ void CodeBuffer::initialize(csize_t code_size, csize_t locs_size) {
|
||||
_insts.initialize_locs(locs_size / sizeof(relocInfo));
|
||||
}
|
||||
|
||||
debug_only(verify_section_allocation();)
|
||||
DEBUG_ONLY(verify_section_allocation();)
|
||||
}
|
||||
|
||||
|
||||
@ -494,7 +494,7 @@ void CodeBuffer::compute_final_layout(CodeBuffer* dest) const {
|
||||
prev_cs = cs;
|
||||
}
|
||||
|
||||
debug_only(dest_cs->_start = nullptr); // defeat double-initialization assert
|
||||
DEBUG_ONLY(dest_cs->_start = nullptr); // defeat double-initialization assert
|
||||
dest_cs->initialize(buf+buf_offset, csize);
|
||||
dest_cs->set_end(buf+buf_offset+csize);
|
||||
assert(dest_cs->is_allocated(), "must always be allocated");
|
||||
@ -505,7 +505,7 @@ void CodeBuffer::compute_final_layout(CodeBuffer* dest) const {
|
||||
|
||||
// Done calculating sections; did it come out to the right end?
|
||||
assert(buf_offset == total_content_size(), "sanity");
|
||||
debug_only(dest->verify_section_allocation();)
|
||||
DEBUG_ONLY(dest->verify_section_allocation();)
|
||||
}
|
||||
|
||||
// Append an oop reference that keeps the class alive.
|
||||
@ -939,11 +939,11 @@ void CodeBuffer::expand(CodeSection* which_cs, csize_t amount) {
|
||||
cb.set_blob(nullptr);
|
||||
|
||||
// Zap the old code buffer contents, to avoid mistakenly using them.
|
||||
debug_only(Copy::fill_to_bytes(bxp->_total_start, bxp->_total_size,
|
||||
DEBUG_ONLY(Copy::fill_to_bytes(bxp->_total_start, bxp->_total_size,
|
||||
badCodeHeapFreeVal);)
|
||||
|
||||
// Make certain that the new sections are all snugly inside the new blob.
|
||||
debug_only(verify_section_allocation();)
|
||||
DEBUG_ONLY(verify_section_allocation();)
|
||||
|
||||
#ifndef PRODUCT
|
||||
_decode_begin = nullptr; // sanity
|
||||
@ -1042,6 +1042,9 @@ void CodeBuffer::shared_stub_to_interp_for(ciMethod* callee, csize_t call_offset
|
||||
|
||||
#ifndef PRODUCT
|
||||
void CodeBuffer::block_comment(ptrdiff_t offset, const char* comment) {
|
||||
if (insts()->scratch_emit()) {
|
||||
return;
|
||||
}
|
||||
if (_collect_comments) {
|
||||
const char* str = _asm_remarks.insert(offset, comment);
|
||||
postcond(str != comment);
|
||||
@ -1049,6 +1052,9 @@ void CodeBuffer::block_comment(ptrdiff_t offset, const char* comment) {
|
||||
}
|
||||
|
||||
const char* CodeBuffer::code_string(const char* str) {
|
||||
if (insts()->scratch_emit()) {
|
||||
return str;
|
||||
}
|
||||
const char* tmp = _dbg_strings.insert(str);
|
||||
postcond(tmp != str);
|
||||
return tmp;
|
||||
|
||||
@ -121,8 +121,8 @@ class CodeSection {
|
||||
_locs_own = false;
|
||||
_scratch_emit = false;
|
||||
_skipped_instructions_size = 0;
|
||||
debug_only(_index = -1);
|
||||
debug_only(_outer = (CodeBuffer*)badAddress);
|
||||
DEBUG_ONLY(_index = -1);
|
||||
DEBUG_ONLY(_outer = (CodeBuffer*)badAddress);
|
||||
}
|
||||
|
||||
void initialize_outer(CodeBuffer* outer, int8_t index) {
|
||||
@ -535,7 +535,7 @@ class CodeBuffer: public StackObj DEBUG_ONLY(COMMA private Scrubber) {
|
||||
assert(code_start != nullptr, "sanity");
|
||||
initialize_misc("static buffer");
|
||||
initialize(code_start, code_size);
|
||||
debug_only(verify_section_allocation();)
|
||||
DEBUG_ONLY(verify_section_allocation();)
|
||||
}
|
||||
|
||||
// (2) CodeBuffer referring to pre-allocated CodeBlob.
|
||||
|
||||
@ -109,19 +109,19 @@ class FrameMap : public CompilationResourceObj {
|
||||
|
||||
static Register cpu_rnr2reg (int rnr) {
|
||||
assert(_init_done, "tables not initialized");
|
||||
debug_only(cpu_range_check(rnr);)
|
||||
DEBUG_ONLY(cpu_range_check(rnr);)
|
||||
return _cpu_rnr2reg[rnr];
|
||||
}
|
||||
|
||||
static int cpu_reg2rnr (Register reg) {
|
||||
assert(_init_done, "tables not initialized");
|
||||
debug_only(cpu_range_check(reg->encoding());)
|
||||
DEBUG_ONLY(cpu_range_check(reg->encoding());)
|
||||
return _cpu_reg2rnr[reg->encoding()];
|
||||
}
|
||||
|
||||
static void map_register(int rnr, Register reg) {
|
||||
debug_only(cpu_range_check(rnr);)
|
||||
debug_only(cpu_range_check(reg->encoding());)
|
||||
DEBUG_ONLY(cpu_range_check(rnr);)
|
||||
DEBUG_ONLY(cpu_range_check(reg->encoding());)
|
||||
_cpu_rnr2reg[rnr] = reg;
|
||||
_cpu_reg2rnr[reg->encoding()] = rnr;
|
||||
}
|
||||
|
||||
@ -1363,7 +1363,7 @@ int Runtime1::move_klass_patching(JavaThread* current) {
|
||||
//
|
||||
// NOTE: we are still in Java
|
||||
//
|
||||
debug_only(NoHandleMark nhm;)
|
||||
DEBUG_ONLY(NoHandleMark nhm;)
|
||||
{
|
||||
// Enter VM mode
|
||||
ResetNoHandleMark rnhm;
|
||||
@ -1380,7 +1380,7 @@ int Runtime1::move_mirror_patching(JavaThread* current) {
|
||||
//
|
||||
// NOTE: we are still in Java
|
||||
//
|
||||
debug_only(NoHandleMark nhm;)
|
||||
DEBUG_ONLY(NoHandleMark nhm;)
|
||||
{
|
||||
// Enter VM mode
|
||||
ResetNoHandleMark rnhm;
|
||||
@ -1397,7 +1397,7 @@ int Runtime1::move_appendix_patching(JavaThread* current) {
|
||||
//
|
||||
// NOTE: we are still in Java
|
||||
//
|
||||
debug_only(NoHandleMark nhm;)
|
||||
DEBUG_ONLY(NoHandleMark nhm;)
|
||||
{
|
||||
// Enter VM mode
|
||||
ResetNoHandleMark rnhm;
|
||||
|
||||
@ -25,6 +25,7 @@
|
||||
#include "cds/aotClassLinker.hpp"
|
||||
#include "cds/aotArtifactFinder.hpp"
|
||||
#include "cds/aotClassInitializer.hpp"
|
||||
#include "cds/aotReferenceObjSupport.hpp"
|
||||
#include "cds/dumpTimeClassInfo.inline.hpp"
|
||||
#include "cds/heapShared.hpp"
|
||||
#include "cds/lambdaProxyClassDictionary.hpp"
|
||||
@ -73,6 +74,7 @@ void AOTArtifactFinder::find_artifacts() {
|
||||
// Note, if a class is not excluded, it does NOT mean it will be automatically included
|
||||
// into the AOT cache -- that will be decided by the code below.
|
||||
SystemDictionaryShared::finish_exclusion_checks();
|
||||
AOTReferenceObjSupport::init_keep_alive_objs_table();
|
||||
|
||||
start_scanning_for_oops();
|
||||
|
||||
|
||||
@ -338,7 +338,8 @@ bool AOTClassInitializer::can_archive_initialized_mirror(InstanceKlass* ik) {
|
||||
bool AOTClassInitializer::is_runtime_setup_required(InstanceKlass* ik) {
|
||||
return ik == vmClasses::Class_klass() ||
|
||||
ik == vmClasses::internal_Unsafe_klass() ||
|
||||
ik == vmClasses::ConcurrentHashMap_klass();
|
||||
ik == vmClasses::ConcurrentHashMap_klass() ||
|
||||
ik == vmClasses::Reference_klass();
|
||||
}
|
||||
|
||||
void AOTClassInitializer::call_runtime_setup(JavaThread* current, InstanceKlass* ik) {
|
||||
|
||||
240
src/hotspot/share/cds/aotReferenceObjSupport.cpp
Normal file
240
src/hotspot/share/cds/aotReferenceObjSupport.cpp
Normal file
@ -0,0 +1,240 @@
|
||||
/*
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "cds/aotReferenceObjSupport.hpp"
|
||||
#include "cds/heapShared.hpp"
|
||||
#include "classfile/javaClasses.hpp"
|
||||
#include "classfile/symbolTable.hpp"
|
||||
#include "classfile/systemDictionary.hpp"
|
||||
#include "classfile/vmSymbols.hpp"
|
||||
#include "logging/log.hpp"
|
||||
#include "memory/resourceArea.hpp"
|
||||
#include "memory/universe.hpp"
|
||||
#include "oops/oop.inline.hpp"
|
||||
#include "oops/oopHandle.inline.hpp"
|
||||
#include "runtime/fieldDescriptor.inline.hpp"
|
||||
#include "runtime/javaCalls.hpp"
|
||||
#include "utilities/resourceHash.hpp"
|
||||
|
||||
// Handling of java.lang.ref.Reference objects in the AOT cache
|
||||
// ============================================================
|
||||
//
|
||||
// When AOTArtifactFinder finds an oop which is a instance of java.lang.ref.Reference:
|
||||
//
|
||||
// - We check if the oop is eligible to be stored in the AOT cache. If not, the AOT cache
|
||||
// creation fails -- see AOTReferenceObjSupport::check_if_ref_obj()
|
||||
//
|
||||
// - Otherwise, we store the oop into the AOT cache, but we unconditionally reset its
|
||||
// "next" and "discovered" fields to null. Otherwise, if AOTArtifactFinder follows these
|
||||
// fields, it may found unrelated objects that we don't intend to cache.
|
||||
//
|
||||
// Eligibility
|
||||
// ===========
|
||||
//
|
||||
// [1] A reference that does not require special clean up (i.e., Reference::queue == ReferenceQueue.NULL_QUEUE)
|
||||
// is eligible.
|
||||
//
|
||||
// [2] A reference that REQUIRE specials clean up (i.e., Reference::queue != ReferenceQueue.NULL_QUEUE)
|
||||
// is eligible ONLY if its referent is not null.
|
||||
//
|
||||
// As of this version, the only oops in group [2] that can be found by AOTArtifactFinder are
|
||||
// the keys used by ReferencedKeyMap in the implementation of MethodType::internTable.
|
||||
// stabilize_cached_reference_objects() ensures that all keys found by AOTArtifactFinder are eligible.
|
||||
//
|
||||
// The purpose of the error check in check_if_ref_obj() is to guard against changes in the JDK core
|
||||
// libs that might introduce new types of oops in group [2] into the AOT cache.
|
||||
//
|
||||
// Reasons for the eligibility restrictions
|
||||
// ========================================
|
||||
//
|
||||
// Reference handling is complex. In this version, we implement only enough functionality to support
|
||||
// the use of Weak/Soft references used by java.lang.invoke.
|
||||
//
|
||||
// We intend to evolve the implementation in the future by
|
||||
// -- implementing more assemblySetup() operations for other use cases, and/or
|
||||
// -- relaxing the eligibility restrictions.
|
||||
//
|
||||
//
|
||||
// null referents for group [1]
|
||||
// ============================
|
||||
//
|
||||
// Any cached reference R1 of group [1] is allowed to have a null referent.
|
||||
// This can happen in the following situations:
|
||||
// (a) R1.clear() was called by Java code during the assembly phase.
|
||||
// (b) The referent has been collected, and R1 is in the "pending" state.
|
||||
// In case (b), the "next" and "discovered" fields of the cached copy of R1 will
|
||||
// be set to null. During the production run:
|
||||
// - It would appear to the Java program as if immediately during VM start-up, the referent
|
||||
// was collected and ReferenceThread completed processing of R1.
|
||||
// - It would appear to the GC as if immediately during VM start-up, the Java program called
|
||||
// R1.clear().
|
||||
|
||||
#if INCLUDE_CDS_JAVA_HEAP
|
||||
|
||||
class KeepAliveObjectsTable : public ResourceHashtable<oop, bool,
|
||||
36137, // prime number
|
||||
AnyObj::C_HEAP,
|
||||
mtClassShared,
|
||||
HeapShared::oop_hash> {};
|
||||
|
||||
static KeepAliveObjectsTable* _keep_alive_objs_table;
|
||||
static OopHandle _keep_alive_objs_array;
|
||||
static OopHandle _null_queue;
|
||||
|
||||
bool AOTReferenceObjSupport::is_enabled() {
|
||||
// For simplicity, AOTReferenceObjSupport is enabled only when dumping method handles.
|
||||
// Otherwise we won't see Reference objects in the AOT cache. Let's be conservative now.
|
||||
return CDSConfig::is_dumping_method_handles();
|
||||
}
|
||||
|
||||
void AOTReferenceObjSupport::initialize(TRAPS) {
|
||||
if (!AOTReferenceObjSupport::is_enabled()) {
|
||||
return;
|
||||
}
|
||||
|
||||
TempNewSymbol class_name = SymbolTable::new_symbol("java/lang/ref/ReferenceQueue");
|
||||
Klass* k = SystemDictionary::resolve_or_fail(class_name, true, CHECK);
|
||||
InstanceKlass* ik = InstanceKlass::cast(k);
|
||||
ik->initialize(CHECK);
|
||||
|
||||
TempNewSymbol field_name = SymbolTable::new_symbol("NULL_QUEUE");
|
||||
fieldDescriptor fd;
|
||||
bool found = ik->find_local_field(field_name, vmSymbols::referencequeue_signature(), &fd);
|
||||
precond(found);
|
||||
precond(fd.is_static());
|
||||
|
||||
_null_queue = OopHandle(Universe::vm_global(), ik->java_mirror()->obj_field(fd.offset()));
|
||||
}
|
||||
|
||||
// Ensure that all group [2] references found by AOTArtifactFinder are eligible.
|
||||
void AOTReferenceObjSupport::stabilize_cached_reference_objects(TRAPS) {
|
||||
if (AOTReferenceObjSupport::is_enabled()) {
|
||||
// This assert means that the MethodType and MethodTypeForm tables won't be
|
||||
// updated concurrently, so we can remove GC'ed entries ...
|
||||
assert(CDSConfig::allow_only_single_java_thread(), "Required");
|
||||
|
||||
{
|
||||
TempNewSymbol method_name = SymbolTable::new_symbol("assemblySetup");
|
||||
JavaValue result(T_VOID);
|
||||
JavaCalls::call_static(&result, vmClasses::MethodType_klass(),
|
||||
method_name,
|
||||
vmSymbols::void_method_signature(),
|
||||
CHECK);
|
||||
}
|
||||
|
||||
{
|
||||
Symbol* cds_name = vmSymbols::jdk_internal_misc_CDS();
|
||||
Klass* cds_klass = SystemDictionary::resolve_or_fail(cds_name, true /*throw error*/, CHECK);
|
||||
TempNewSymbol method_name = SymbolTable::new_symbol("getKeepAliveObjects");
|
||||
TempNewSymbol method_sig = SymbolTable::new_symbol("()[Ljava/lang/Object;");
|
||||
JavaValue result(T_OBJECT);
|
||||
JavaCalls::call_static(&result, cds_klass, method_name, method_sig, CHECK);
|
||||
|
||||
_keep_alive_objs_array = OopHandle(Universe::vm_global(), result.get_oop());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void AOTReferenceObjSupport::init_keep_alive_objs_table() {
|
||||
assert_at_safepoint(); // _keep_alive_objs_table uses raw oops
|
||||
oop a = _keep_alive_objs_array.resolve();
|
||||
if (a != nullptr) {
|
||||
precond(a->is_objArray());
|
||||
precond(AOTReferenceObjSupport::is_enabled());
|
||||
objArrayOop array = objArrayOop(a);
|
||||
|
||||
_keep_alive_objs_table = new (mtClass)KeepAliveObjectsTable();
|
||||
for (int i = 0; i < array->length(); i++) {
|
||||
oop obj = array->obj_at(i);
|
||||
_keep_alive_objs_table->put(obj, true); // The array may have duplicated entries but that's OK.
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Returns true IFF obj is an instance of java.lang.ref.Reference. If so, perform extra eligibility checks.
|
||||
bool AOTReferenceObjSupport::check_if_ref_obj(oop obj) {
|
||||
// We have a single Java thread. This means java.lang.ref.Reference$ReferenceHandler thread
|
||||
// is not running. Otherwise the checks for next/discovered may not work.
|
||||
precond(CDSConfig::allow_only_single_java_thread());
|
||||
assert_at_safepoint(); // _keep_alive_objs_table uses raw oops
|
||||
|
||||
if (obj->klass()->is_subclass_of(vmClasses::Reference_klass())) {
|
||||
precond(AOTReferenceObjSupport::is_enabled());
|
||||
precond(JavaClasses::is_supported_for_archiving(obj));
|
||||
precond(_keep_alive_objs_table != nullptr);
|
||||
|
||||
// GC needs to know about this load, It will keep referent alive until the current safepoint ends.
|
||||
oop referent = HeapAccess<ON_UNKNOWN_OOP_REF>::oop_load_at(obj, java_lang_ref_Reference::referent_offset());
|
||||
|
||||
oop queue = obj->obj_field(java_lang_ref_Reference::queue_offset());
|
||||
oop next = java_lang_ref_Reference::next(obj);
|
||||
oop discovered = java_lang_ref_Reference::discovered(obj);
|
||||
bool needs_special_cleanup = (queue != _null_queue.resolve());
|
||||
|
||||
// If you see the errors below, you probably modified the implementation of java.lang.invoke.
|
||||
// Please check the comments at the top of this file.
|
||||
if (needs_special_cleanup && (referent == nullptr || !_keep_alive_objs_table->contains(referent))) {
|
||||
ResourceMark rm;
|
||||
|
||||
log_error(cds, heap)("Cannot archive reference object " PTR_FORMAT " of class %s",
|
||||
p2i(obj), obj->klass()->external_name());
|
||||
log_error(cds, heap)("referent = " PTR_FORMAT
|
||||
", queue = " PTR_FORMAT
|
||||
", next = " PTR_FORMAT
|
||||
", discovered = " PTR_FORMAT,
|
||||
p2i(referent), p2i(queue), p2i(next), p2i(discovered));
|
||||
log_error(cds, heap)("This object requires special clean up as its queue is not ReferenceQueue::N" "ULL ("
|
||||
PTR_FORMAT ")", p2i(_null_queue.resolve()));
|
||||
log_error(cds, heap)("%s", (referent == nullptr) ?
|
||||
"referent cannot be null" : "referent is not registered with CDS.keepAlive()");
|
||||
HeapShared::debug_trace();
|
||||
MetaspaceShared::unrecoverable_writing_error();
|
||||
}
|
||||
|
||||
if (log_is_enabled(Info, cds, ref)) {
|
||||
ResourceMark rm;
|
||||
log_info(cds, ref)("Reference obj:"
|
||||
" r=" PTR_FORMAT
|
||||
" q=" PTR_FORMAT
|
||||
" n=" PTR_FORMAT
|
||||
" d=" PTR_FORMAT
|
||||
" %s",
|
||||
p2i(referent),
|
||||
p2i(queue),
|
||||
p2i(next),
|
||||
p2i(discovered),
|
||||
obj->klass()->external_name());
|
||||
}
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool AOTReferenceObjSupport::skip_field(int field_offset) {
|
||||
return (field_offset == java_lang_ref_Reference::next_offset() ||
|
||||
field_offset == java_lang_ref_Reference::discovered_offset());
|
||||
}
|
||||
|
||||
#endif // INCLUDE_CDS_JAVA_HEAP
|
||||
45
src/hotspot/share/cds/aotReferenceObjSupport.hpp
Normal file
45
src/hotspot/share/cds/aotReferenceObjSupport.hpp
Normal file
@ -0,0 +1,45 @@
|
||||
/*
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef SHARE_CDS_AOTREFERENCEOBJSUPPORT_HPP
|
||||
#define SHARE_CDS_AOTREFERENCEOBJSUPPORT_HPP
|
||||
|
||||
#include "memory/allStatic.hpp"
|
||||
#include "oops/oopsHierarchy.hpp"
|
||||
#include "utilities/exceptions.hpp"
|
||||
|
||||
// Support for ahead-of-time allocated instances of java.lang.ref.Reference
|
||||
|
||||
class AOTReferenceObjSupport : AllStatic {
|
||||
|
||||
public:
|
||||
static void initialize(TRAPS);
|
||||
static void stabilize_cached_reference_objects(TRAPS);
|
||||
static void init_keep_alive_objs_table() NOT_CDS_JAVA_HEAP_RETURN;
|
||||
static bool check_if_ref_obj(oop obj);
|
||||
static bool skip_field(int field_offset);
|
||||
static bool is_enabled();
|
||||
};
|
||||
|
||||
#endif // SHARE_CDS_AOTREFERENCEOBJSUPPORT_HPP
|
||||
@ -309,7 +309,8 @@ address ArchiveBuilder::reserve_buffer() {
|
||||
size_t buffer_size = LP64_ONLY(CompressedClassSpaceSize) NOT_LP64(256 * M);
|
||||
ReservedSpace rs = MemoryReserver::reserve(buffer_size,
|
||||
MetaspaceShared::core_region_alignment(),
|
||||
os::vm_page_size());
|
||||
os::vm_page_size(),
|
||||
mtClassShared);
|
||||
if (!rs.is_reserved()) {
|
||||
log_error(cds)("Failed to reserve %zu bytes of output buffer.", buffer_size);
|
||||
MetaspaceShared::unrecoverable_writing_error();
|
||||
@ -1201,7 +1202,7 @@ class ArchiveBuilder::CDSMapLogger : AllStatic {
|
||||
#undef _LOG_PREFIX
|
||||
|
||||
// Log information about a region, whose address at dump time is [base .. top). At
|
||||
// runtime, this region will be mapped to requested_base. requested_base is 0 if this
|
||||
// runtime, this region will be mapped to requested_base. requested_base is nullptr if this
|
||||
// region will be mapped at os-selected addresses (such as the bitmap region), or will
|
||||
// be accessed with os::read (the header).
|
||||
//
|
||||
@ -1210,7 +1211,11 @@ class ArchiveBuilder::CDSMapLogger : AllStatic {
|
||||
static void log_region(const char* name, address base, address top, address requested_base) {
|
||||
size_t size = top - base;
|
||||
base = requested_base;
|
||||
top = requested_base + size;
|
||||
if (requested_base == nullptr) {
|
||||
top = (address)size;
|
||||
} else {
|
||||
top = requested_base + size;
|
||||
}
|
||||
log_info(cds, map)("[%-18s " PTR_FORMAT " - " PTR_FORMAT " %9zu bytes]",
|
||||
name, p2i(base), p2i(top), size);
|
||||
}
|
||||
|
||||
@ -22,6 +22,7 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#include "cds/aotReferenceObjSupport.hpp"
|
||||
#include "cds/archiveHeapWriter.hpp"
|
||||
#include "cds/cdsConfig.hpp"
|
||||
#include "cds/filemap.hpp"
|
||||
@ -607,18 +608,27 @@ class ArchiveHeapWriter::EmbeddedOopRelocator: public BasicOopIterateClosure {
|
||||
oop _src_obj;
|
||||
address _buffered_obj;
|
||||
CHeapBitMap* _oopmap;
|
||||
|
||||
bool _is_java_lang_ref;
|
||||
public:
|
||||
EmbeddedOopRelocator(oop src_obj, address buffered_obj, CHeapBitMap* oopmap) :
|
||||
_src_obj(src_obj), _buffered_obj(buffered_obj), _oopmap(oopmap) {}
|
||||
_src_obj(src_obj), _buffered_obj(buffered_obj), _oopmap(oopmap)
|
||||
{
|
||||
_is_java_lang_ref = AOTReferenceObjSupport::check_if_ref_obj(src_obj);
|
||||
}
|
||||
|
||||
void do_oop(narrowOop *p) { EmbeddedOopRelocator::do_oop_work(p); }
|
||||
void do_oop( oop *p) { EmbeddedOopRelocator::do_oop_work(p); }
|
||||
|
||||
private:
|
||||
template <class T> void do_oop_work(T *p) {
|
||||
size_t field_offset = pointer_delta(p, _src_obj, sizeof(char));
|
||||
ArchiveHeapWriter::relocate_field_in_buffer<T>((T*)(_buffered_obj + field_offset), _oopmap);
|
||||
int field_offset = pointer_delta_as_int((char*)p, cast_from_oop<char*>(_src_obj));
|
||||
T* field_addr = (T*)(_buffered_obj + field_offset);
|
||||
if (_is_java_lang_ref && AOTReferenceObjSupport::skip_field(field_offset)) {
|
||||
// Do not copy these fields. Set them to null
|
||||
*field_addr = (T)0x0;
|
||||
} else {
|
||||
ArchiveHeapWriter::relocate_field_in_buffer<T>(field_addr, _oopmap);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@ -536,9 +536,6 @@ bool CDSConfig::check_vm_args_consistency(bool patch_mod_javabase, bool mode_fla
|
||||
// run to another which resulting in non-determinstic CDS archives.
|
||||
// Disable UseStringDeduplication while dumping CDS archive.
|
||||
UseStringDeduplication = false;
|
||||
|
||||
// Don't use SoftReferences so that objects used by java.lang.invoke tables can be archived.
|
||||
Arguments::PropertyList_add(new SystemProperty("java.lang.invoke.MethodHandleNatives.USE_SOFT_CACHE", "false", false));
|
||||
}
|
||||
|
||||
// RecordDynamicDumpInfo is not compatible with ArchiveClassesAtExit
|
||||
|
||||
@ -1066,10 +1066,10 @@ void FileMapInfo::close() {
|
||||
*/
|
||||
static char* map_memory(int fd, const char* file_name, size_t file_offset,
|
||||
char *addr, size_t bytes, bool read_only,
|
||||
bool allow_exec, MemTag mem_tag = mtNone) {
|
||||
bool allow_exec, MemTag mem_tag) {
|
||||
char* mem = os::map_memory(fd, file_name, file_offset, addr, bytes,
|
||||
AlwaysPreTouch ? false : read_only,
|
||||
allow_exec, mem_tag);
|
||||
mem_tag, AlwaysPreTouch ? false : read_only,
|
||||
allow_exec);
|
||||
if (mem != nullptr && AlwaysPreTouch) {
|
||||
os::pretouch_memory(mem, mem + bytes);
|
||||
}
|
||||
@ -1094,7 +1094,7 @@ bool FileMapInfo::remap_shared_readonly_as_readwrite() {
|
||||
assert(WINDOWS_ONLY(false) NOT_WINDOWS(true), "Don't call on Windows");
|
||||
// Replace old mapping with new one that is writable.
|
||||
char *base = os::map_memory(_fd, _full_path, r->file_offset(),
|
||||
addr, size, false /* !read_only */,
|
||||
addr, size, mtNone, false /* !read_only */,
|
||||
r->allow_exec());
|
||||
close();
|
||||
// These have to be errors because the shared region is now unmapped.
|
||||
@ -1620,7 +1620,7 @@ bool FileMapInfo::map_heap_region_impl() {
|
||||
} else {
|
||||
base = map_memory(_fd, _full_path, r->file_offset(),
|
||||
addr, _mapped_heap_memregion.byte_size(), r->read_only(),
|
||||
r->allow_exec());
|
||||
r->allow_exec(), mtJavaHeap);
|
||||
if (base == nullptr || base != addr) {
|
||||
dealloc_heap_region();
|
||||
log_info(cds)("UseSharedSpaces: Unable to map at required address in java heap. "
|
||||
|
||||
@ -25,6 +25,7 @@
|
||||
#include "cds/aotArtifactFinder.hpp"
|
||||
#include "cds/aotClassInitializer.hpp"
|
||||
#include "cds/aotClassLocation.hpp"
|
||||
#include "cds/aotReferenceObjSupport.hpp"
|
||||
#include "cds/archiveBuilder.hpp"
|
||||
#include "cds/archiveHeapLoader.hpp"
|
||||
#include "cds/archiveHeapWriter.hpp"
|
||||
@ -1363,34 +1364,37 @@ void HeapShared::clear_archived_roots_of(Klass* k) {
|
||||
}
|
||||
}
|
||||
|
||||
// Push all oops that are referenced by _referencing_obj onto the _stack.
|
||||
class HeapShared::ReferentPusher: public BasicOopIterateClosure {
|
||||
// Push all oop fields (or oop array elemenets in case of an objArray) in
|
||||
// _referencing_obj onto the _stack.
|
||||
class HeapShared::OopFieldPusher: public BasicOopIterateClosure {
|
||||
PendingOopStack* _stack;
|
||||
GrowableArray<oop> _found_oop_fields;
|
||||
int _level;
|
||||
bool _record_klasses_only;
|
||||
KlassSubGraphInfo* _subgraph_info;
|
||||
oop _referencing_obj;
|
||||
bool _is_java_lang_ref;
|
||||
public:
|
||||
ReferentPusher(PendingOopStack* stack,
|
||||
int level,
|
||||
bool record_klasses_only,
|
||||
KlassSubGraphInfo* subgraph_info,
|
||||
oop orig) :
|
||||
OopFieldPusher(PendingOopStack* stack,
|
||||
int level,
|
||||
bool record_klasses_only,
|
||||
KlassSubGraphInfo* subgraph_info,
|
||||
oop orig) :
|
||||
_stack(stack),
|
||||
_found_oop_fields(),
|
||||
_level(level),
|
||||
_record_klasses_only(record_klasses_only),
|
||||
_subgraph_info(subgraph_info),
|
||||
_referencing_obj(orig) {
|
||||
_is_java_lang_ref = AOTReferenceObjSupport::check_if_ref_obj(orig);
|
||||
}
|
||||
void do_oop(narrowOop *p) { ReferentPusher::do_oop_work(p); }
|
||||
void do_oop( oop *p) { ReferentPusher::do_oop_work(p); }
|
||||
void do_oop(narrowOop *p) { OopFieldPusher::do_oop_work(p); }
|
||||
void do_oop( oop *p) { OopFieldPusher::do_oop_work(p); }
|
||||
|
||||
~ReferentPusher() {
|
||||
~OopFieldPusher() {
|
||||
while (_found_oop_fields.length() > 0) {
|
||||
// This produces the exact same traversal order as the previous version
|
||||
// of ReferentPusher that recurses on the C stack -- a depth-first search,
|
||||
// of OopFieldPusher that recurses on the C stack -- a depth-first search,
|
||||
// walking the oop fields in _referencing_obj by ascending field offsets.
|
||||
oop obj = _found_oop_fields.pop();
|
||||
_stack->push(PendingOop(obj, _referencing_obj, _level + 1));
|
||||
@ -1399,14 +1403,18 @@ class HeapShared::ReferentPusher: public BasicOopIterateClosure {
|
||||
|
||||
protected:
|
||||
template <class T> void do_oop_work(T *p) {
|
||||
oop obj = RawAccess<>::oop_load(p);
|
||||
int field_offset = pointer_delta_as_int((char*)p, cast_from_oop<char*>(_referencing_obj));
|
||||
oop obj = HeapAccess<ON_UNKNOWN_OOP_REF>::oop_load_at(_referencing_obj, field_offset);
|
||||
if (!CompressedOops::is_null(obj)) {
|
||||
size_t field_delta = pointer_delta(p, _referencing_obj, sizeof(char));
|
||||
if (_is_java_lang_ref && AOTReferenceObjSupport::skip_field(field_offset)) {
|
||||
// Do not follow these fields. They will be cleared to null.
|
||||
return;
|
||||
}
|
||||
|
||||
if (!_record_klasses_only && log_is_enabled(Debug, cds, heap)) {
|
||||
ResourceMark rm;
|
||||
log_debug(cds, heap)("(%d) %s[%zu] ==> " PTR_FORMAT " size %zu %s", _level,
|
||||
_referencing_obj->klass()->external_name(), field_delta,
|
||||
log_debug(cds, heap)("(%d) %s[%d] ==> " PTR_FORMAT " size %zu %s", _level,
|
||||
_referencing_obj->klass()->external_name(), field_offset,
|
||||
p2i(obj), obj->size() * HeapWordSize, obj->klass()->external_name());
|
||||
if (log_is_enabled(Trace, cds, heap)) {
|
||||
LogTarget(Trace, cds, heap) log;
|
||||
@ -1586,7 +1594,7 @@ bool HeapShared::walk_one_object(PendingOopStack* stack, int level, KlassSubGrap
|
||||
// Find all the oops that are referenced by orig_obj, push them onto the stack
|
||||
// so we can work on them next.
|
||||
ResourceMark rm;
|
||||
ReferentPusher pusher(stack, level, record_klasses_only, subgraph_info, orig_obj);
|
||||
OopFieldPusher pusher(stack, level, record_klasses_only, subgraph_info, orig_obj);
|
||||
orig_obj->oop_iterate(&pusher);
|
||||
}
|
||||
|
||||
@ -1613,7 +1621,7 @@ bool HeapShared::walk_one_object(PendingOopStack* stack, int level, KlassSubGrap
|
||||
// - No java.lang.Class instance (java mirror) can be included inside
|
||||
// an archived sub-graph. Mirror can only be the sub-graph entry object.
|
||||
//
|
||||
// The Java heap object sub-graph archiving process (see ReferentPusher):
|
||||
// The Java heap object sub-graph archiving process (see OopFieldPusher):
|
||||
//
|
||||
// 1) Java object sub-graph archiving starts from a given static field
|
||||
// within a Class instance (java mirror). If the static field is a
|
||||
|
||||
@ -164,8 +164,8 @@ private:
|
||||
|
||||
static void count_allocation(size_t size);
|
||||
static void print_stats();
|
||||
static void debug_trace();
|
||||
public:
|
||||
static void debug_trace();
|
||||
static unsigned oop_hash(oop const& p);
|
||||
static unsigned string_oop_hash(oop const& string) {
|
||||
return java_lang_String::hash_code(string);
|
||||
@ -357,7 +357,7 @@ private:
|
||||
int level() const { return _level; }
|
||||
};
|
||||
|
||||
class ReferentPusher;
|
||||
class OopFieldPusher;
|
||||
using PendingOopStack = GrowableArrayCHeap<PendingOop, mtClassShared>;
|
||||
|
||||
static PendingOop _object_being_archived;
|
||||
|
||||
@ -28,6 +28,7 @@
|
||||
#include "cds/aotClassLocation.hpp"
|
||||
#include "cds/aotConstantPoolResolver.hpp"
|
||||
#include "cds/aotLinkedClassBulkLoader.hpp"
|
||||
#include "cds/aotReferenceObjSupport.hpp"
|
||||
#include "cds/archiveBuilder.hpp"
|
||||
#include "cds/archiveHeapLoader.hpp"
|
||||
#include "cds/archiveHeapWriter.hpp"
|
||||
@ -962,22 +963,14 @@ void MetaspaceShared::preload_and_dump_impl(StaticArchiveBuilder& builder, TRAPS
|
||||
#if INCLUDE_CDS_JAVA_HEAP
|
||||
if (CDSConfig::is_dumping_heap()) {
|
||||
ArchiveHeapWriter::init();
|
||||
|
||||
if (CDSConfig::is_dumping_full_module_graph()) {
|
||||
ClassLoaderDataShared::ensure_module_entry_tables_exist();
|
||||
HeapShared::reset_archived_object_states(CHECK);
|
||||
}
|
||||
|
||||
if (CDSConfig::is_dumping_method_handles()) {
|
||||
// This assert means that the MethodType and MethodTypeForm tables won't be
|
||||
// updated concurrently when we are saving their contents into a side table.
|
||||
assert(CDSConfig::allow_only_single_java_thread(), "Required");
|
||||
|
||||
JavaValue result(T_VOID);
|
||||
JavaCalls::call_static(&result, vmClasses::MethodType_klass(),
|
||||
vmSymbols::createArchivedObjects(),
|
||||
vmSymbols::void_method_signature(),
|
||||
CHECK);
|
||||
}
|
||||
AOTReferenceObjSupport::initialize(CHECK);
|
||||
AOTReferenceObjSupport::stabilize_cached_reference_objects(CHECK);
|
||||
|
||||
if (CDSConfig::is_initing_classes_at_dump_time()) {
|
||||
// java.lang.Class::reflectionFactory cannot be archived yet. We set this field
|
||||
@ -1345,7 +1338,7 @@ MapArchiveResult MetaspaceShared::map_archives(FileMapInfo* static_mapinfo, File
|
||||
if (prot_zone_size > 0) {
|
||||
assert(prot_zone_size >= os::vm_allocation_granularity(), "must be"); // not just page size!
|
||||
char* p = os::attempt_reserve_memory_at(mapped_base_address, prot_zone_size,
|
||||
false, MemTag::mtClassShared);
|
||||
mtClassShared);
|
||||
assert(p == mapped_base_address || p == nullptr, "must be");
|
||||
if (p == nullptr) {
|
||||
log_debug(cds)("Failed to re-reserve protection zone");
|
||||
@ -1537,7 +1530,8 @@ char* MetaspaceShared::reserve_address_space_for_archives(FileMapInfo* static_ma
|
||||
archive_space_rs = MemoryReserver::reserve((char*)base_address,
|
||||
archive_space_size,
|
||||
archive_space_alignment,
|
||||
os::vm_page_size());
|
||||
os::vm_page_size(),
|
||||
mtNone);
|
||||
if (archive_space_rs.is_reserved()) {
|
||||
assert(base_address == nullptr ||
|
||||
(address)archive_space_rs.base() == base_address, "Sanity");
|
||||
@ -1605,11 +1599,13 @@ char* MetaspaceShared::reserve_address_space_for_archives(FileMapInfo* static_ma
|
||||
archive_space_rs = MemoryReserver::reserve((char*)base_address,
|
||||
archive_space_size,
|
||||
archive_space_alignment,
|
||||
os::vm_page_size());
|
||||
os::vm_page_size(),
|
||||
mtNone);
|
||||
class_space_rs = MemoryReserver::reserve((char*)ccs_base,
|
||||
class_space_size,
|
||||
class_space_alignment,
|
||||
os::vm_page_size());
|
||||
os::vm_page_size(),
|
||||
mtNone);
|
||||
}
|
||||
if (!archive_space_rs.is_reserved() || !class_space_rs.is_reserved()) {
|
||||
release_reserved_spaces(total_space_rs, archive_space_rs, class_space_rs);
|
||||
@ -1622,7 +1618,8 @@ char* MetaspaceShared::reserve_address_space_for_archives(FileMapInfo* static_ma
|
||||
total_space_rs = MemoryReserver::reserve((char*) base_address,
|
||||
total_range_size,
|
||||
base_address_alignment,
|
||||
os::vm_page_size());
|
||||
os::vm_page_size(),
|
||||
mtNone);
|
||||
} else {
|
||||
// We did not manage to reserve at the preferred address, or were instructed to relocate. In that
|
||||
// case we reserve wherever possible, but the start address needs to be encodable as narrow Klass
|
||||
|
||||
@ -138,3 +138,9 @@ ciKlass* ciInstance::java_lang_Class_klass() {
|
||||
assert(java_lang_Class::as_Klass(get_oop()) != nullptr, "klass is null");
|
||||
return CURRENT_ENV->get_metadata(java_lang_Class::as_Klass(get_oop()))->as_klass();
|
||||
}
|
||||
|
||||
char* ciInstance::java_lang_String_str(char* buf, size_t buflen) {
|
||||
VM_ENTRY_MARK;
|
||||
assert(get_oop()->is_a(vmClasses::String_klass()), "not a String");
|
||||
return java_lang_String::as_utf8_string(get_oop(), buf, buflen);
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user