mirror of
https://github.com/openjdk/jdk.git
synced 2026-02-10 18:38:27 +00:00
Merge remote-tracking branch 'origin/master' into _8366241_nmt_consolidate_structures
This commit is contained in:
commit
ec846aa4fe
@ -1859,8 +1859,6 @@ difference.</p>
|
||||
<h3 id="additional-undecided-features">Additional Undecided
|
||||
Features</h3>
|
||||
<ul>
|
||||
<li><p>Trailing return type syntax for functions (<a
|
||||
href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2541.htm">n2541</a>)</p></li>
|
||||
<li><p>Member initializers and aggregates (<a
|
||||
href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2013/n3653.html">n3653</a>)</p></li>
|
||||
<li><p>Rvalue references and move semantics</p></li>
|
||||
|
||||
@ -1853,9 +1853,6 @@ See Object Lifetime: C++17 6.8/8, C++20 6.7.3/8
|
||||
|
||||
### Additional Undecided Features
|
||||
|
||||
* Trailing return type syntax for functions
|
||||
([n2541](http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2541.htm))
|
||||
|
||||
* Member initializers and aggregates
|
||||
([n3653](http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2013/n3653.html))
|
||||
|
||||
|
||||
@ -114,7 +114,6 @@ ifeq ($(HSDIS_BACKEND), binutils)
|
||||
TOOLCHAIN_TYPE := gcc
|
||||
OPENJDK_TARGET_OS := linux
|
||||
OPENJDK_TARGET_OS_TYPE := unix
|
||||
CC_OUT_OPTION := -o$(SPACE)
|
||||
GENDEPS_FLAGS := -MMD -MF
|
||||
CFLAGS_DEBUG_SYMBOLS := -g
|
||||
DISABLED_WARNINGS :=
|
||||
|
||||
@ -63,7 +63,7 @@ TOOL_GENERATECURRENCYDATA = $(JAVA_SMALL) -cp $(BUILDTOOLS_OUTPUTDIR)/jdk_tools_
|
||||
TOOL_TZDB = $(JAVA_SMALL) -cp $(BUILDTOOLS_OUTPUTDIR)/jdk_tools_classes \
|
||||
build.tools.tzdb.TzdbZoneRulesCompiler
|
||||
|
||||
TOOL_BLOCKED_CERTS = $(JAVA_SMALL) -cp $(BUILDTOOLS_OUTPUTDIR)/jdk_tools_classes \
|
||||
TOOL_BLOCKED_CERTS = $(JAVA_SMALL) -Xlog:disable -cp $(BUILDTOOLS_OUTPUTDIR)/jdk_tools_classes \
|
||||
--add-exports java.base/sun.security.util=ALL-UNNAMED \
|
||||
build.tools.blockedcertsconverter.BlockedCertsConverter
|
||||
|
||||
|
||||
@ -597,10 +597,9 @@ AC_DEFUN([BOOTJDK_SETUP_BUILD_JDK],
|
||||
AC_ARG_WITH(build-jdk, [AS_HELP_STRING([--with-build-jdk],
|
||||
[path to JDK of same version as is being built@<:@the newly built JDK@:>@])])
|
||||
|
||||
CREATE_BUILDJDK=false
|
||||
EXTERNAL_BUILDJDK=false
|
||||
BUILD_JDK_FOUND="no"
|
||||
EXTERNAL_BUILDJDK_PATH=""
|
||||
if test "x$with_build_jdk" != "x"; then
|
||||
BUILD_JDK_FOUND=no
|
||||
BOOTJDK_CHECK_BUILD_JDK([
|
||||
if test "x$with_build_jdk" != x; then
|
||||
BUILD_JDK=$with_build_jdk
|
||||
@ -608,40 +607,15 @@ AC_DEFUN([BOOTJDK_SETUP_BUILD_JDK],
|
||||
AC_MSG_NOTICE([Found potential Build JDK using configure arguments])
|
||||
fi
|
||||
])
|
||||
EXTERNAL_BUILDJDK=true
|
||||
else
|
||||
if test "x$COMPILE_TYPE" = "xcross"; then
|
||||
BUILD_JDK="\$(BUILDJDK_OUTPUTDIR)/jdk"
|
||||
BUILD_JDK_FOUND=yes
|
||||
CREATE_BUILDJDK=true
|
||||
if test "x$BUILD_JDK_FOUND" != "xyes"; then
|
||||
AC_MSG_CHECKING([for Build JDK])
|
||||
AC_MSG_RESULT([yes, will build it for the host platform])
|
||||
else
|
||||
BUILD_JDK="\$(JDK_OUTPUTDIR)"
|
||||
BUILD_JDK_FOUND=yes
|
||||
AC_MSG_CHECKING([for Build JDK])
|
||||
AC_MSG_RESULT([yes, will use output dir])
|
||||
AC_MSG_RESULT([no])
|
||||
AC_MSG_ERROR([Could not find a suitable Build JDK])
|
||||
fi
|
||||
EXTERNAL_BUILDJDK_PATH="$BUILD_JDK"
|
||||
fi
|
||||
|
||||
# Since these tools do not yet exist, we cannot use UTIL_FIXUP_EXECUTABLE to
|
||||
# detect the need of fixpath
|
||||
JMOD="$BUILD_JDK/bin/jmod"
|
||||
UTIL_ADD_FIXPATH(JMOD)
|
||||
JLINK="$BUILD_JDK/bin/jlink"
|
||||
UTIL_ADD_FIXPATH(JLINK)
|
||||
AC_SUBST(JMOD)
|
||||
AC_SUBST(JLINK)
|
||||
|
||||
if test "x$BUILD_JDK_FOUND" != "xyes"; then
|
||||
AC_MSG_CHECKING([for Build JDK])
|
||||
AC_MSG_RESULT([no])
|
||||
AC_MSG_ERROR([Could not find a suitable Build JDK])
|
||||
fi
|
||||
|
||||
AC_SUBST(CREATE_BUILDJDK)
|
||||
AC_SUBST(BUILD_JDK)
|
||||
AC_SUBST(EXTERNAL_BUILDJDK)
|
||||
AC_SUBST(EXTERNAL_BUILDJDK_PATH)
|
||||
])
|
||||
|
||||
# The docs-reference JDK is used to run javadoc for the docs-reference targets.
|
||||
|
||||
@ -37,56 +37,25 @@ AC_DEFUN([FLAGS_SETUP_SHARED_LIBS],
|
||||
if test "x$TOOLCHAIN_TYPE" = xgcc; then
|
||||
# Default works for linux, might work on other platforms as well.
|
||||
SHARED_LIBRARY_FLAGS='-shared'
|
||||
# --disable-new-dtags forces use of RPATH instead of RUNPATH for rpaths.
|
||||
# This protects internal library dependencies within the JDK from being
|
||||
# overridden using LD_LIBRARY_PATH. See JDK-8326891 for more information.
|
||||
SET_EXECUTABLE_ORIGIN='-Wl,-rpath,\$$ORIGIN[$]1 -Wl,--disable-new-dtags'
|
||||
SET_SHARED_LIBRARY_ORIGIN="-Wl,-z,origin $SET_EXECUTABLE_ORIGIN"
|
||||
SET_SHARED_LIBRARY_NAME='-Wl,-soname=[$]1'
|
||||
|
||||
elif test "x$TOOLCHAIN_TYPE" = xclang; then
|
||||
if test "x$OPENJDK_TARGET_OS" = xmacosx; then
|
||||
# Linking is different on MacOSX
|
||||
SHARED_LIBRARY_FLAGS="-dynamiclib -compatibility_version 1.0.0 -current_version 1.0.0"
|
||||
SET_EXECUTABLE_ORIGIN='-Wl,-rpath,@loader_path$(or [$]1,/.)'
|
||||
SET_SHARED_LIBRARY_ORIGIN="$SET_EXECUTABLE_ORIGIN"
|
||||
SET_SHARED_LIBRARY_NAME='-Wl,-install_name,@rpath/[$]1'
|
||||
|
||||
elif test "x$OPENJDK_TARGET_OS" = xaix; then
|
||||
# Linking is different on aix
|
||||
SHARED_LIBRARY_FLAGS="-shared -Wl,-bM:SRE -Wl,-bnoentry"
|
||||
SET_EXECUTABLE_ORIGIN=""
|
||||
SET_SHARED_LIBRARY_ORIGIN=''
|
||||
SET_SHARED_LIBRARY_NAME=''
|
||||
|
||||
else
|
||||
# Default works for linux, might work on other platforms as well.
|
||||
SHARED_LIBRARY_FLAGS='-shared'
|
||||
SET_EXECUTABLE_ORIGIN='-Wl,-rpath,\$$ORIGIN[$]1'
|
||||
if test "x$OPENJDK_TARGET_OS" = xlinux; then
|
||||
SET_EXECUTABLE_ORIGIN="$SET_EXECUTABLE_ORIGIN -Wl,--disable-new-dtags"
|
||||
fi
|
||||
SET_SHARED_LIBRARY_NAME='-Wl,-soname=[$]1'
|
||||
|
||||
# arm specific settings
|
||||
if test "x$OPENJDK_TARGET_CPU" = "xarm"; then
|
||||
# '-Wl,-z,origin' isn't used on arm.
|
||||
SET_SHARED_LIBRARY_ORIGIN='-Wl,-rpath,\$$$$ORIGIN[$]1'
|
||||
else
|
||||
SET_SHARED_LIBRARY_ORIGIN="-Wl,-z,origin $SET_EXECUTABLE_ORIGIN"
|
||||
fi
|
||||
fi
|
||||
|
||||
elif test "x$TOOLCHAIN_TYPE" = xmicrosoft; then
|
||||
SHARED_LIBRARY_FLAGS="-dll"
|
||||
SET_EXECUTABLE_ORIGIN=''
|
||||
SET_SHARED_LIBRARY_ORIGIN=''
|
||||
SET_SHARED_LIBRARY_NAME=''
|
||||
fi
|
||||
|
||||
AC_SUBST(SET_EXECUTABLE_ORIGIN)
|
||||
AC_SUBST(SET_SHARED_LIBRARY_ORIGIN)
|
||||
AC_SUBST(SET_SHARED_LIBRARY_NAME)
|
||||
AC_SUBST(SHARED_LIBRARY_FLAGS)
|
||||
])
|
||||
|
||||
@ -934,48 +903,6 @@ AC_DEFUN([FLAGS_SETUP_CFLAGS_CPU_DEP],
|
||||
IF_FALSE: [$2FDLIBM_CFLAGS=""])
|
||||
fi
|
||||
AC_SUBST($2FDLIBM_CFLAGS)
|
||||
|
||||
# Check whether the compiler supports the Arm C Language Extensions (ACLE)
|
||||
# for SVE. Set SVE_CFLAGS to -march=armv8-a+sve if it does.
|
||||
# ACLE and this flag are required to build the aarch64 SVE related functions in
|
||||
# libvectormath. Apple Silicon does not support SVE; use macOS as a proxy for
|
||||
# that check.
|
||||
if test "x$OPENJDK_TARGET_CPU" = "xaarch64" && test "x$OPENJDK_TARGET_OS" = "xlinux"; then
|
||||
if test "x$TOOLCHAIN_TYPE" = xgcc || test "x$TOOLCHAIN_TYPE" = xclang; then
|
||||
AC_LANG_PUSH(C)
|
||||
OLD_CFLAGS="$CFLAGS"
|
||||
CFLAGS="$CFLAGS -march=armv8-a+sve"
|
||||
AC_MSG_CHECKING([if Arm SVE ACLE is supported])
|
||||
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([#include <arm_sve.h>],
|
||||
[
|
||||
svint32_t r = svdup_n_s32(1);
|
||||
return 0;
|
||||
])],
|
||||
[
|
||||
AC_MSG_RESULT([yes])
|
||||
$2SVE_CFLAGS="-march=armv8-a+sve"
|
||||
# Switching the initialization mode with gcc from 'pattern' to 'zero'
|
||||
# avoids the use of unsupported `__builtin_clear_padding` for variable
|
||||
# length aggregates
|
||||
if test "x$DEBUG_LEVEL" != xrelease && test "x$TOOLCHAIN_TYPE" = xgcc ; then
|
||||
INIT_ZERO_FLAG="-ftrivial-auto-var-init=zero"
|
||||
FLAGS_COMPILER_CHECK_ARGUMENTS(ARGUMENT: [$INIT_ZERO_FLAG],
|
||||
IF_TRUE: [
|
||||
$2SVE_CFLAGS="${$2SVE_CFLAGS} $INIT_ZERO_FLAG"
|
||||
]
|
||||
)
|
||||
fi
|
||||
],
|
||||
[
|
||||
AC_MSG_RESULT([no])
|
||||
$2SVE_CFLAGS=""
|
||||
]
|
||||
)
|
||||
CFLAGS="$OLD_CFLAGS"
|
||||
AC_LANG_POP(C)
|
||||
fi
|
||||
fi
|
||||
AC_SUBST($2SVE_CFLAGS)
|
||||
])
|
||||
|
||||
AC_DEFUN_ONCE([FLAGS_SETUP_BRANCH_PROTECTION],
|
||||
|
||||
@ -79,7 +79,7 @@ AC_DEFUN([FLAGS_SETUP_LDFLAGS_HELPER],
|
||||
fi
|
||||
if test "x$OPENJDK_TARGET_OS" = xaix; then
|
||||
BASIC_LDFLAGS="-Wl,-b64 -Wl,-brtl -Wl,-bnorwexec -Wl,-blibpath:/usr/lib:lib -Wl,-bnoexpall \
|
||||
-Wl,-bernotok -Wl,-bdatapsize:64k -Wl,-btextpsize:64k -Wl,-bstackpsize:64k"
|
||||
-Wl,-bernotok -Wl,-bcdtors:mbr::s -Wl,-bdatapsize:64k -Wl,-btextpsize:64k -Wl,-bstackpsize:64k"
|
||||
BASIC_LDFLAGS_JVM_ONLY="$BASIC_LDFLAGS_JVM_ONLY -Wl,-lC_r -Wl,-bbigtoc"
|
||||
fi
|
||||
|
||||
@ -98,7 +98,7 @@ AC_DEFUN([FLAGS_SETUP_LDFLAGS_HELPER],
|
||||
|
||||
# Setup OS-dependent LDFLAGS
|
||||
if test "x$OPENJDK_TARGET_OS" = xmacosx && test "x$TOOLCHAIN_TYPE" = xclang; then
|
||||
# FIXME: We should really generalize SET_SHARED_LIBRARY_ORIGIN instead.
|
||||
# FIXME: We should really generalize SetSharedLibraryOrigin instead.
|
||||
OS_LDFLAGS_JVM_ONLY="-Wl,-rpath,@loader_path/. -Wl,-rpath,@loader_path/.."
|
||||
OS_LDFLAGS="-mmacosx-version-min=$MACOSX_VERSION_MIN -Wl,-reproducible"
|
||||
fi
|
||||
|
||||
@ -107,6 +107,62 @@ AC_DEFUN([FLAGS_SETUP_NMFLAGS],
|
||||
AC_SUBST(NMFLAGS)
|
||||
])
|
||||
|
||||
# Check whether the compiler supports the Arm C Language Extensions (ACLE)
|
||||
# for SVE. Set SVE_CFLAGS to -march=armv8-a+sve if it does.
|
||||
# ACLE and this flag are required to build the aarch64 SVE related functions
|
||||
# in libvectormath.
|
||||
AC_DEFUN([FLAGS_SETUP_SVE],
|
||||
[
|
||||
AARCH64_SVE_AVAILABLE=false
|
||||
# Apple Silicon does not support SVE; use macOS as a proxy for that check.
|
||||
if test "x$OPENJDK_TARGET_CPU" = "xaarch64" && test "x$OPENJDK_TARGET_OS" = "xlinux"; then
|
||||
if test "x$TOOLCHAIN_TYPE" = xgcc || test "x$TOOLCHAIN_TYPE" = xclang; then
|
||||
# check the compiler and binutils support sve or not
|
||||
AC_MSG_CHECKING([if Arm SVE ACLE is supported])
|
||||
AC_LANG_PUSH([C])
|
||||
saved_cflags="$CFLAGS"
|
||||
CFLAGS="$CFLAGS -march=armv8-a+sve $CFLAGS_WARNINGS_ARE_ERRORS ARG_ARGUMENT"
|
||||
AC_COMPILE_IFELSE([AC_LANG_PROGRAM(
|
||||
[
|
||||
#include <arm_sve.h>
|
||||
svfloat64_t a() {}
|
||||
],
|
||||
[
|
||||
svint32_t r = svdup_n_s32(1)
|
||||
])],
|
||||
[
|
||||
AARCH64_SVE_AVAILABLE=true
|
||||
]
|
||||
)
|
||||
CFLAGS="$saved_cflags"
|
||||
AC_LANG_POP([C])
|
||||
AC_MSG_RESULT([$AARCH64_SVE_AVAILABLE])
|
||||
fi
|
||||
fi
|
||||
|
||||
UTIL_ARG_ENABLE(NAME: aarch64-sve, DEFAULT: auto,
|
||||
RESULT: AARCH64_SVE_ENABLED,
|
||||
DESC: [Use SVE when compiling libsleef],
|
||||
AVAILABLE: $AARCH64_SVE_AVAILABLE)
|
||||
SVE_CFLAGS=""
|
||||
if test "x$AARCH64_SVE_ENABLED" = xtrue; then
|
||||
SVE_CFLAGS="-march=armv8-a+sve"
|
||||
# Switching the initialization mode with gcc from 'pattern' to 'zero'
|
||||
# avoids the use of unsupported `__builtin_clear_padding` for variable
|
||||
# length aggregates
|
||||
if test "x$DEBUG_LEVEL" != xrelease && test "x$TOOLCHAIN_TYPE" = xgcc ; then
|
||||
AC_MSG_CHECKING([Switching the initialization mode with gcc from pattern to zero])
|
||||
INIT_ZERO_FLAG="-ftrivial-auto-var-init=zero"
|
||||
FLAGS_COMPILER_CHECK_ARGUMENTS(ARGUMENT: [$INIT_ZERO_FLAG],
|
||||
IF_TRUE: [
|
||||
SVE_CFLAGS="${SVE_CFLAGS} $INIT_ZERO_FLAG"
|
||||
]
|
||||
)
|
||||
fi
|
||||
fi
|
||||
AC_SUBST(SVE_CFLAGS)
|
||||
])
|
||||
|
||||
################################################################################
|
||||
# platform independent
|
||||
AC_DEFUN([FLAGS_SETUP_ASFLAGS],
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
#
|
||||
# Copyright (c) 2011, 2024, Oracle and/or its affiliates. All rights reserved.
|
||||
# Copyright (c) 2011, 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
|
||||
@ -319,16 +319,10 @@ AC_DEFUN_ONCE([FLAGS_PRE_TOOLCHAIN],
|
||||
AC_DEFUN([FLAGS_SETUP_TOOLCHAIN_CONTROL],
|
||||
[
|
||||
if test "x$TOOLCHAIN_TYPE" = xmicrosoft; then
|
||||
CC_OUT_OPTION=-Fo
|
||||
if test "x$OPENJDK_TARGET_CPU" != xaarch64; then
|
||||
AS_NON_ASM_EXTENSION_OPTION=-Ta
|
||||
fi
|
||||
else
|
||||
# The option used to specify the target .o,.a or .so file.
|
||||
# When compiling, how to specify the to be created object file.
|
||||
CC_OUT_OPTION='-o$(SPACE)'
|
||||
fi
|
||||
AC_SUBST(CC_OUT_OPTION)
|
||||
AC_SUBST(AS_NON_ASM_EXTENSION_OPTION)
|
||||
|
||||
# Generate make dependency files
|
||||
@ -374,6 +368,7 @@ AC_DEFUN([FLAGS_SETUP_FLAGS],
|
||||
FLAGS_SETUP_RCFLAGS
|
||||
FLAGS_SETUP_NMFLAGS
|
||||
|
||||
FLAGS_SETUP_SVE
|
||||
FLAGS_SETUP_ASFLAGS
|
||||
FLAGS_SETUP_ASFLAGS_CPU_DEP([TARGET])
|
||||
FLAGS_SETUP_ASFLAGS_CPU_DEP([BUILD], [OPENJDK_BUILD_])
|
||||
|
||||
@ -565,9 +565,14 @@ AC_DEFUN_ONCE([JDKOPT_SETUP_UNDEFINED_BEHAVIOR_SANITIZER],
|
||||
# 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.
|
||||
# In the ubsan case we have to link every binary with the C++-compiler as linker, because inherently
|
||||
# the C-Compiler and the C++-compiler used as linker provide a different set of ubsan exports.
|
||||
# Linking an executable with the C-compiler and one of its shared libraries with the C++-compiler
|
||||
# leeds to unresolved symbols.
|
||||
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"
|
||||
UBSAN_CFLAGS="$UBSAN_CFLAGS -DLLVM_SYMBOLIZER=$(dirname $(dirname $CC))/tools/ibm-llvm-symbolizer"
|
||||
UBSAN_LDFLAGS="$UBSAN_LDFLAGS -Wl,-bbigtoc"
|
||||
LD="$LDCXX"
|
||||
fi
|
||||
UTIL_ARG_ENABLE(NAME: ubsan, DEFAULT: false, RESULT: UBSAN_ENABLED,
|
||||
DESC: [enable UndefinedBehaviorSanitizer],
|
||||
|
||||
@ -28,7 +28,7 @@
|
||||
################################################################################
|
||||
|
||||
# Minimum supported versions
|
||||
JTREG_MINIMUM_VERSION=7.5.2
|
||||
JTREG_MINIMUM_VERSION=8
|
||||
GTEST_MINIMUM_VERSION=1.14.0
|
||||
|
||||
################################################################################
|
||||
|
||||
@ -136,12 +136,8 @@ AC_DEFUN_ONCE([LIB_SETUP_LIBRARIES],
|
||||
BASIC_JVM_LIBS="$BASIC_JVM_LIBS $LIBPTHREAD"
|
||||
fi
|
||||
|
||||
# librt for legacy clock_gettime
|
||||
# librt - for timers (timer_* functions)
|
||||
if test "x$OPENJDK_TARGET_OS" = xlinux; then
|
||||
# Hotspot needs to link librt to get the clock_* functions.
|
||||
# But once our supported minimum build and runtime platform
|
||||
# has glibc 2.17, this can be removed as the functions are
|
||||
# in libc.
|
||||
BASIC_JVM_LIBS="$BASIC_JVM_LIBS -lrt"
|
||||
fi
|
||||
|
||||
|
||||
@ -386,9 +386,22 @@ CAPSTONE_ARCH_AARCH64_NAME := @CAPSTONE_ARCH_AARCH64_NAME@
|
||||
# it in sync.
|
||||
BOOT_JDK := @BOOT_JDK@
|
||||
|
||||
BUILD_JDK := @BUILD_JDK@
|
||||
CREATE_BUILDJDK := @CREATE_BUILDJDK@
|
||||
EXTERNAL_BUILDJDK := @EXTERNAL_BUILDJDK@
|
||||
EXTERNAL_BUILDJDK_PATH := @EXTERNAL_BUILDJDK_PATH@
|
||||
|
||||
ifneq ($(EXTERNAL_BUILDJDK_PATH), )
|
||||
EXTERNAL_BUILDJDK := true
|
||||
CREATE_BUILDJDK := false
|
||||
BUILD_JDK := $(EXTERNAL_BUILDJDK_PATH)
|
||||
else
|
||||
EXTERNAL_BUILDJDK := false
|
||||
ifeq ($(COMPILE_TYPE), cross)
|
||||
CREATE_BUILDJDK := true
|
||||
BUILD_JDK := $(BUILDJDK_OUTPUTDIR)/jdk
|
||||
else
|
||||
CREATE_BUILDJDK := false
|
||||
BUILD_JDK := $(JDK_OUTPUTDIR)
|
||||
endif
|
||||
endif
|
||||
|
||||
# Whether the boot jdk jar supports --date=TIMESTAMP
|
||||
BOOT_JDK_JAR_SUPPORTS_DATE := @BOOT_JDK_JAR_SUPPORTS_DATE@
|
||||
@ -491,7 +504,6 @@ CXX_VERSION_NUMBER := @CXX_VERSION_NUMBER@
|
||||
# Legacy support
|
||||
HOTSPOT_TOOLCHAIN_TYPE := @HOTSPOT_TOOLCHAIN_TYPE@
|
||||
|
||||
CC_OUT_OPTION := @CC_OUT_OPTION@
|
||||
AS_NON_ASM_EXTENSION_OPTION := @AS_NON_ASM_EXTENSION_OPTION@
|
||||
|
||||
# Flags used for overriding the default opt setting for a C/C++ source file.
|
||||
@ -624,17 +636,8 @@ ASFLAGS_DEBUG_SYMBOLS := @ASFLAGS_DEBUG_SYMBOLS@
|
||||
# Compress (or not) jars
|
||||
COMPRESS_JARS := @COMPRESS_JARS@
|
||||
|
||||
# Options to linker to specify the library name.
|
||||
# (Note absence of := assignment, because we do not want to evaluate the macro body here)
|
||||
SET_SHARED_LIBRARY_NAME = @SET_SHARED_LIBRARY_NAME@
|
||||
|
||||
SHARED_LIBRARY_FLAGS := @SHARED_LIBRARY_FLAGS@
|
||||
|
||||
# Set origin using the linker, ie use the relative path to the dependent library to find the dependencies.
|
||||
# (Note absence of := assignment, because we do not want to evaluate the macro body here)
|
||||
SET_SHARED_LIBRARY_ORIGIN = @SET_SHARED_LIBRARY_ORIGIN@
|
||||
SET_EXECUTABLE_ORIGIN = @SET_EXECUTABLE_ORIGIN@
|
||||
|
||||
LIBRARY_PREFIX := @LIBRARY_PREFIX@
|
||||
SHARED_LIBRARY_SUFFIX := @SHARED_LIBRARY_SUFFIX@
|
||||
STATIC_LIBRARY_SUFFIX := @STATIC_LIBRARY_SUFFIX@
|
||||
@ -657,8 +660,8 @@ JAVA_CMD := @JAVA@
|
||||
JAVAC_CMD := @JAVAC@
|
||||
JAVADOC_CMD := @JAVADOC@
|
||||
JAR_CMD := @JAR@
|
||||
JLINK_CMD := @JLINK@
|
||||
JMOD_CMD := @JMOD@
|
||||
JLINK_CMD := @FIXPATH@ $(BUILD_JDK)/bin/jlink
|
||||
JMOD_CMD := @FIXPATH@ $(BUILD_JDK)/bin/jmod
|
||||
# These variables are meant to be used. They are defined with = instead of := to make
|
||||
# it possible to override only the *_CMD variables.
|
||||
JAVA = $(JAVA_CMD) $(JAVA_FLAGS_BIG) $(JAVA_FLAGS)
|
||||
|
||||
@ -148,9 +148,12 @@ define SetupExecuteBody
|
||||
$1_INFO := Running commands for $1
|
||||
endif
|
||||
|
||||
$1_VARDEPS := $$($1_COMMAND) $$($1_PRE_COMMAND) $$($1_POST_COMMAND)
|
||||
$1_VARDEPS_FILE := $$(call DependOnVariable, $1_VARDEPS, $$($1_BASE)_exec.vardeps)
|
||||
|
||||
ifneq ($$($1_PRE_COMMAND), )
|
||||
|
||||
$$($1_PRE_MARKER): $$($1_DEPS)
|
||||
$$($1_PRE_MARKER): $$($1_DEPS) $$($1_VARDEPS_FILE)
|
||||
ifneq ($$($1_WARN), )
|
||||
$$(call LogWarn, $$($1_WARN))
|
||||
endif
|
||||
@ -176,7 +179,7 @@ define SetupExecuteBody
|
||||
|
||||
$1 := $$($1_PRE_MARKER) $$($1_EXEC_RESULT)
|
||||
else
|
||||
$$($1_EXEC_RESULT): $$($1_DEPS)
|
||||
$$($1_EXEC_RESULT): $$($1_DEPS) $$($1_VARDEPS_FILE)
|
||||
ifneq ($$($1_WARN), )
|
||||
$$(call LogWarn, $$($1_WARN))
|
||||
endif
|
||||
|
||||
@ -30,6 +30,47 @@ ifeq ($(INCLUDE), true)
|
||||
|
||||
include NativeCompilation.gmk
|
||||
|
||||
ifeq ($(call isCompiler, gcc), true)
|
||||
# --disable-new-dtags forces use of RPATH instead of RUNPATH for rpaths.
|
||||
# This protects internal library dependencies within the JDK from being
|
||||
# overridden using LD_LIBRARY_PATH. See JDK-8326891 for more information.
|
||||
SetExecutableOrigin = \
|
||||
-Wl,-rpath,\$(DOLLAR)ORIGIN$1 -Wl,--disable-new-dtags
|
||||
SetSharedLibraryOrigin = \
|
||||
-Wl,-z,origin -Wl,-rpath,\$(DOLLAR)ORIGIN$1 -Wl,--disable-new-dtags
|
||||
else ifeq ($(call isCompiler, clang), true)
|
||||
ifeq ($(call isTargetOs, macosx), true)
|
||||
SetExecutableOrigin = \
|
||||
-Wl,-rpath,@loader_path$(or $1,/.)
|
||||
SetSharedLibraryOrigin = \
|
||||
-Wl,-rpath,@loader_path$(or $1,/.)
|
||||
else ifeq ($(call isTargetOs, aix), true)
|
||||
SetExecutableOrigin =
|
||||
SetSharedLibraryOrigin =
|
||||
else
|
||||
ifeq ($(call isTargetOs, linux), true)
|
||||
SetExecutableOrigin = \
|
||||
-Wl,-rpath,\$(DOLLAR)ORIGIN$1 -Wl,--disable-new-dtags
|
||||
else
|
||||
SetExecutableOrigin = \
|
||||
-Wl,-rpath,\$(DOLLAR)ORIGIN$1
|
||||
endif
|
||||
|
||||
ifeq ($(call isTargetOs, arm), true)
|
||||
SetSharedLibraryOrigin = \
|
||||
-Wl,-rpath,\$(DOLLAR)ORIGIN$1
|
||||
else
|
||||
SetSharedLibraryOrigin = \
|
||||
-Wl,-z,origin -Wl,-rpath,\$(DOLLAR)ORIGIN$1
|
||||
endif
|
||||
endif
|
||||
else ifeq ($(call isCompiler, microsoft), true)
|
||||
SetExecutableOrigin =
|
||||
SetSharedLibraryOrigin =
|
||||
else
|
||||
$(error Unknown toolchain)
|
||||
endif
|
||||
|
||||
FindSrcDirsForComponent += \
|
||||
$(call uniq, $(wildcard \
|
||||
$(TOPDIR)/src/$(strip $1)/$(OPENJDK_TARGET_OS)/native/$(strip $2) \
|
||||
@ -444,9 +485,9 @@ define SetupJdkNativeCompilationBody
|
||||
|
||||
ifneq ($$($1_LD_SET_ORIGIN), false)
|
||||
ifeq ($$($1_TYPE), EXECUTABLE)
|
||||
$1_LDFLAGS += $$(call SET_EXECUTABLE_ORIGIN)
|
||||
$1_LDFLAGS += $$(call SetExecutableOrigin)
|
||||
else
|
||||
$1_LDFLAGS += $$(call SET_SHARED_LIBRARY_ORIGIN)
|
||||
$1_LDFLAGS += $$(call SetSharedLibraryOrigin)
|
||||
endif
|
||||
endif
|
||||
# APPEND_LDFLAGS, if it exists, must be set after the origin flags
|
||||
|
||||
@ -156,8 +156,8 @@ define SetupBuildLauncherBody
|
||||
DISABLED_WARNINGS_gcc := unused-function unused-variable, \
|
||||
DISABLED_WARNINGS_clang := unused-function, \
|
||||
LDFLAGS := $$($1_LDFLAGS), \
|
||||
LDFLAGS_linux := $$(call SET_EXECUTABLE_ORIGIN,/../lib), \
|
||||
LDFLAGS_macosx := $$(call SET_EXECUTABLE_ORIGIN,/../lib), \
|
||||
LDFLAGS_linux := $$(call SetExecutableOrigin,/../lib), \
|
||||
LDFLAGS_macosx := $$(call SetExecutableOrigin,/../lib), \
|
||||
LDFLAGS_FILTER_OUT := $$($1_LDFLAGS_FILTER_OUT), \
|
||||
JDK_LIBS := $$($1_JDK_LIBS), \
|
||||
JDK_LIBS_windows := $$($1_JDK_LIBS_windows), \
|
||||
|
||||
@ -93,6 +93,14 @@ DEPENDENCY_TARGET_SED_PATTERN := \
|
||||
-e 's/$$$$/ :/' \
|
||||
#
|
||||
|
||||
################################################################################
|
||||
# Setup compiler-specific argument to specify output file
|
||||
ifeq ($(call isCompiler, microsoft), true)
|
||||
CC_OUT_OPTION := -Fo
|
||||
else
|
||||
CC_OUT_OPTION := -o$(SPACE)
|
||||
endif
|
||||
|
||||
################################################################################
|
||||
# Create the recipe needed to compile a single native source file.
|
||||
#
|
||||
@ -334,7 +342,7 @@ define CreateWindowsResourceFile
|
||||
$$(call LogInfo, Compiling resource $$(notdir $$($1_VERSIONINFO_RESOURCE)) (for $$($1_BASENAME)))
|
||||
$$(call MakeDir, $$(@D) $$($1_OBJECT_DIR))
|
||||
$$(call ExecuteWithLog, $$@, $$(call MakeCommandRelative, \
|
||||
$$($1_RC) $$($1_RCFLAGS) $$($1_SYSROOT_CFLAGS) $(CC_OUT_OPTION)$$@ \
|
||||
$$($1_RC) $$($1_RCFLAGS) $$($1_SYSROOT_CFLAGS) -Fo$$@ \
|
||||
$$($1_VERSIONINFO_RESOURCE) 2>&1 ))
|
||||
# Windows RC compiler does not support -showIncludes, so we mis-use CL
|
||||
# for this. Filter out RC specific arguments that are unknown to CL.
|
||||
@ -344,7 +352,7 @@ define CreateWindowsResourceFile
|
||||
$$(call ExecuteWithLog, $$($1_RES_DEPS_FILE)$(OBJ_SUFFIX), \
|
||||
$$($1_CC) $$(filter-out -l%, $$($1_RCFLAGS)) \
|
||||
$$($1_SYSROOT_CFLAGS) -showIncludes -nologo -TC \
|
||||
$(CC_OUT_OPTION)$$($1_RES_DEPS_FILE)$(OBJ_SUFFIX) -P -Fi$$($1_RES_DEPS_FILE).pp \
|
||||
-Fo$$($1_RES_DEPS_FILE)$(OBJ_SUFFIX) -P -Fi$$($1_RES_DEPS_FILE).pp \
|
||||
$$($1_VERSIONINFO_RESOURCE)) 2>&1 \
|
||||
| $(TR) -d '\r' | $(GREP) -v -e "^Note: including file:" \
|
||||
-e "^$$(notdir $$($1_VERSIONINFO_RESOURCE))$$$$" || test "$$$$?" = "1" ; \
|
||||
|
||||
@ -50,6 +50,26 @@ GetEntitlementsFile = \
|
||||
$(if $(wildcard $f), $f, $(DEFAULT_ENTITLEMENTS_FILE)) \
|
||||
)
|
||||
|
||||
ifeq ($(call isCompiler, gcc), true)
|
||||
SetSharedLibraryName = \
|
||||
-Wl,-soname=$1
|
||||
else ifeq ($(call isCompiler, clang), true)
|
||||
ifeq ($(call isTargetOs, macosx), true)
|
||||
SetSharedLibraryName = \
|
||||
-Wl,-install_name,@rpath/$1
|
||||
else ifeq ($(call isTargetOs, aix), true)
|
||||
SetSharedLibraryName =
|
||||
else
|
||||
# Default works for linux, might work on other platforms as well.
|
||||
SetSharedLibraryName = \
|
||||
-Wl,-soname=$1
|
||||
endif
|
||||
else ifeq ($(call isCompiler, microsoft), true)
|
||||
SetSharedLibraryName =
|
||||
else
|
||||
$(error Unknown toolchain)
|
||||
endif
|
||||
|
||||
################################################################################
|
||||
define SetupLinking
|
||||
# Unless specifically set, stripping should only happen if symbols are also
|
||||
@ -131,7 +151,7 @@ define CreateDynamicLibraryOrExecutable
|
||||
# A shared dynamic library or an executable binary has been specified
|
||||
ifeq ($$($1_TYPE), LIBRARY)
|
||||
# Generating a dynamic library.
|
||||
$1_EXTRA_LDFLAGS += $$(call SET_SHARED_LIBRARY_NAME,$$($1_BASENAME))
|
||||
$1_EXTRA_LDFLAGS += $$(call SetSharedLibraryName,$$($1_BASENAME))
|
||||
endif
|
||||
|
||||
ifeq ($(MACOSX_CODESIGN_MODE), hardened)
|
||||
|
||||
@ -26,7 +26,7 @@
|
||||
# Versions and download locations for dependencies used by GitHub Actions (GHA)
|
||||
|
||||
GTEST_VERSION=1.14.0
|
||||
JTREG_VERSION=7.5.2+1
|
||||
JTREG_VERSION=8+2
|
||||
|
||||
LINUX_X64_BOOT_JDK_EXT=tar.gz
|
||||
LINUX_X64_BOOT_JDK_URL=https://download.java.net/java/GA/jdk24/1f9ff9062db4449d8ca828c504ffae90/36/GPL/openjdk-24_linux-x64_bin.tar.gz
|
||||
|
||||
@ -1174,9 +1174,9 @@ var getJibProfilesDependencies = function (input, common) {
|
||||
jtreg: {
|
||||
server: "jpg",
|
||||
product: "jtreg",
|
||||
version: "7.5.2",
|
||||
build_number: "1",
|
||||
file: "bundles/jtreg-7.5.2+1.zip",
|
||||
version: "8",
|
||||
build_number: "2",
|
||||
file: "bundles/jtreg-8+2.zip",
|
||||
environment_name: "JT_HOME",
|
||||
environment_path: input.get("jtreg", "home_path") + "/bin",
|
||||
configure_args: "--with-jtreg=" + input.get("jtreg", "home_path"),
|
||||
|
||||
@ -152,7 +152,7 @@ $(eval $(call SetupJdkExecutable, BUILD_GTEST_LAUNCHER, \
|
||||
-I$(GTEST_FRAMEWORK_SRC)/googlemock \
|
||||
-I$(GTEST_FRAMEWORK_SRC)/googlemock/include, \
|
||||
LD_SET_ORIGIN := false, \
|
||||
LDFLAGS_unix := $(call SET_SHARED_LIBRARY_ORIGIN), \
|
||||
LDFLAGS_unix := $(call SetSharedLibraryOrigin), \
|
||||
JDK_LIBS := gtest:libjvm, \
|
||||
COPY_DEBUG_SYMBOLS := $(GTEST_COPY_DEBUG_SYMBOLS), \
|
||||
ZIP_EXTERNAL_DEBUG_SYMBOLS := false, \
|
||||
|
||||
@ -57,7 +57,7 @@ ifeq ($(call check-jvm-feature, zero), true)
|
||||
-DZERO_LIBARCH='"$(OPENJDK_TARGET_CPU_LEGACY_LIB)"' $(LIBFFI_CFLAGS)
|
||||
JVM_LIBS_FEATURES += $(LIBFFI_LIBS)
|
||||
ifeq ($(ENABLE_LIBFFI_BUNDLING), true)
|
||||
JVM_LDFLAGS_FEATURES += $(call SET_EXECUTABLE_ORIGIN,/..)
|
||||
JVM_LDFLAGS_FEATURES += $(call SetExecutableOrigin,/..)
|
||||
endif
|
||||
else
|
||||
JVM_EXCLUDE_PATTERNS += /zero/
|
||||
|
||||
@ -22,6 +22,7 @@
|
||||
// Java extension
|
||||
"jdk.project.jdkhome": "{{OUTPUTDIR}}/jdk",
|
||||
"jdk.java.onSave.organizeImports": false, // prevents unnecessary changes
|
||||
"jdk.serverVmOptions": ["-Xmx2G"], // prevent out of memory
|
||||
|
||||
// Additional conventions
|
||||
"files.associations": {
|
||||
|
||||
@ -33,7 +33,6 @@ include gensrc/GensrcBuffer.gmk
|
||||
include gensrc/GensrcCharacterData.gmk
|
||||
include gensrc/GensrcCharsetCoder.gmk
|
||||
include gensrc/GensrcCharsetMapping.gmk
|
||||
include gensrc/GensrcExceptions.gmk
|
||||
include gensrc/GensrcMisc.gmk
|
||||
include gensrc/GensrcModuleLoaderMap.gmk
|
||||
include gensrc/GensrcRegex.gmk
|
||||
|
||||
@ -154,6 +154,8 @@ endif
|
||||
|
||||
################################################################################
|
||||
## Build libsyslookup
|
||||
## The LIBDL dependency on Linux is needed to dynamically access libdl symbols,
|
||||
## which may be needed as part of resolving some standard symbols
|
||||
################################################################################
|
||||
|
||||
$(eval $(call SetupJdkLibrary, BUILD_LIBSYSLOOKUP, \
|
||||
@ -196,7 +198,7 @@ ifeq ($(call isTargetOs, linux)+$(call isTargetCpu, x86_64)+$(INCLUDE_COMPILER2)
|
||||
OPTIMIZATION := HIGH, \
|
||||
CXXFLAGS := -std=c++17, \
|
||||
DISABLED_WARNINGS_gcc := unused-variable, \
|
||||
LIBS_linux := $(LIBDL) $(LIBM), \
|
||||
LIBS_linux := $(LIBM), \
|
||||
))
|
||||
|
||||
TARGETS += $(BUILD_LIBSIMD_SORT)
|
||||
|
||||
@ -1,57 +0,0 @@
|
||||
#
|
||||
# Copyright (c) 2011, 2025, Oracle and/or its affiliates. All rights reserved.
|
||||
# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
#
|
||||
# This code is free software; you can redistribute it and/or modify it
|
||||
# under the terms of the GNU General Public License version 2 only, as
|
||||
# published by the Free Software Foundation. Oracle designates this
|
||||
# particular file as subject to the "Classpath" exception as provided
|
||||
# by Oracle in the LICENSE file that accompanied this code.
|
||||
#
|
||||
# This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
# version 2 for more details (a copy is included in the LICENSE file that
|
||||
# accompanied this code).
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License version
|
||||
# 2 along with this work; if not, write to the Free Software Foundation,
|
||||
# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
#
|
||||
# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
# or visit www.oracle.com if you need additional information or have any
|
||||
# questions.
|
||||
#
|
||||
|
||||
include MakeIncludeStart.gmk
|
||||
ifeq ($(INCLUDE), true)
|
||||
|
||||
################################################################################
|
||||
|
||||
GENSRC_EXCEPTIONS :=
|
||||
|
||||
GENSRC_EXCEPTIONS_DST := $(SUPPORT_OUTPUTDIR)/gensrc/java.base/java/nio
|
||||
|
||||
GENSRC_EXCEPTIONS_SRC := $(MODULE_SRC)/share/classes/java/nio
|
||||
GENSRC_EXCEPTIONS_CMD := $(TOPDIR)/make/scripts/genExceptions.sh
|
||||
|
||||
GENSRC_EXCEPTIONS_SRC_DIRS := . charset channels
|
||||
|
||||
$(GENSRC_EXCEPTIONS_DST)/_the.%.marker: $(GENSRC_EXCEPTIONS_SRC)/%/exceptions \
|
||||
$(GENSRC_EXCEPTIONS_CMD)
|
||||
$(call LogInfo, Generating exceptions java.nio $*)
|
||||
$(call MakeDir, $(@D)/$*)
|
||||
SCRIPTS="$(TOPDIR)/make/scripts" AWK="$(AWK)" SH="$(SH)" $(SH) \
|
||||
$(GENSRC_EXCEPTIONS_CMD) $< $(@D)/$* $(LOG_DEBUG)
|
||||
$(TOUCH) $@
|
||||
|
||||
GENSRC_EXCEPTIONS += $(foreach D, $(GENSRC_EXCEPTIONS_SRC_DIRS), $(GENSRC_EXCEPTIONS_DST)/_the.$(D).marker)
|
||||
|
||||
$(GENSRC_EXCEPTIONS): $(BUILD_TOOLS_JDK)
|
||||
|
||||
TARGETS += $(GENSRC_EXCEPTIONS)
|
||||
|
||||
################################################################################
|
||||
|
||||
endif # include guard
|
||||
include MakeIncludeEnd.gmk
|
||||
@ -51,7 +51,7 @@ $(eval $(call SetupJdkLibrary, BUILD_LIBMLIB_IMAGE, \
|
||||
$(LIBMLIB_IMAGE_CFLAGS), \
|
||||
DISABLED_WARNINGS_gcc := unused-function, \
|
||||
DISABLED_WARNINGS_clang_mlib_ImageCreate.c := unused-function, \
|
||||
LIBS_unix := $(LIBDL) $(LIBM), \
|
||||
LIBS_unix := $(LIBM), \
|
||||
))
|
||||
|
||||
TARGETS += $(BUILD_LIBMLIB_IMAGE)
|
||||
@ -264,7 +264,7 @@ ifeq ($(ENABLE_HEADLESS_ONLY), false)
|
||||
JDK_LIBS_macosx := libosxapp, \
|
||||
LIBS := $(GIFLIB_LIBS) $(LIBJPEG_LIBS) $(LIBZ_LIBS) $(PNG_LIBS) $(ICONV_LIBS), \
|
||||
LIBS_unix := $(LIBM) $(LIBPTHREAD), \
|
||||
LIBS_linux := $(LIBDL) $(X_LIBS) -lX11 -lXext, \
|
||||
LIBS_linux := $(X_LIBS) -lX11 -lXext, \
|
||||
LIBS_macosx := \
|
||||
-framework ApplicationServices \
|
||||
-framework Cocoa \
|
||||
|
||||
@ -43,8 +43,6 @@ $(eval $(call SetupJdkLibrary, BUILD_LIBINSTRUMENT, \
|
||||
JDK_LIBS := java.base:libjava java.base:libjli java.base:libjvm, \
|
||||
LIBS := $(ICONV_LIBS), \
|
||||
LIBS_unix := $(LIBZ_LIBS), \
|
||||
LIBS_linux := $(LIBDL), \
|
||||
LIBS_aix := $(LIBDL), \
|
||||
LIBS_macosx := \
|
||||
-framework ApplicationServices \
|
||||
-framework Cocoa \
|
||||
|
||||
@ -41,7 +41,7 @@ ifeq ($(call isTargetOs, linux), true)
|
||||
java.base:libnio \
|
||||
java.base:libnio/ch, \
|
||||
JDK_LIBS := java.base:libjava java.base:libnet, \
|
||||
LIBS_linux := $(LIBDL) $(LIBPTHREAD), \
|
||||
LIBS_linux := $(LIBDL), \
|
||||
))
|
||||
|
||||
TARGETS += $(BUILD_LIBSCTP)
|
||||
|
||||
@ -1,45 +0,0 @@
|
||||
#! /bin/sh
|
||||
#
|
||||
# Copyright (c) 2007, 2020, Oracle and/or its affiliates. All rights reserved.
|
||||
# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
#
|
||||
# This code is free software; you can redistribute it and/or modify it
|
||||
# under the terms of the GNU General Public License version 2 only, as
|
||||
# published by the Free Software Foundation. Oracle designates this
|
||||
# particular file as subject to the "Classpath" exception as provided
|
||||
# by Oracle in the LICENSE file that accompanied this code.
|
||||
#
|
||||
# This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
# version 2 for more details (a copy is included in the LICENSE file that
|
||||
# accompanied this code).
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License version
|
||||
# 2 along with this work; if not, write to the Free Software Foundation,
|
||||
# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
#
|
||||
# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
# or visit www.oracle.com if you need additional information or have any
|
||||
# questions.
|
||||
#
|
||||
|
||||
# Parse the first contiguous comment block in this script and generate
|
||||
# a java comment block. If this script is invoked with a copyright
|
||||
# year/year range, the java comment block will contain a Sun copyright.
|
||||
|
||||
COPYRIGHT_YEARS="$1"
|
||||
|
||||
cat <<__END__
|
||||
/*
|
||||
__END__
|
||||
|
||||
if [ "x$COPYRIGHT_YEARS" != x ]; then
|
||||
cat <<__END__
|
||||
* Copyright (c) $COPYRIGHT_YEARS Oracle and/or its affiliates. All rights reserved.
|
||||
__END__
|
||||
fi
|
||||
|
||||
$AWK ' /^#.*Copyright.*Oracle/ { next }
|
||||
/^#([^!]|$)/ { sub(/^#/, " *"); print }
|
||||
/^$/ { print " */"; exit } ' $0
|
||||
@ -1,116 +0,0 @@
|
||||
#! /bin/sh
|
||||
#
|
||||
# Copyright (c) 2000, 2025, Oracle and/or its affiliates. All rights reserved.
|
||||
# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
#
|
||||
# This code is free software; you can redistribute it and/or modify it
|
||||
# under the terms of the GNU General Public License version 2 only, as
|
||||
# published by the Free Software Foundation. Oracle designates this
|
||||
# particular file as subject to the "Classpath" exception as provided
|
||||
# by Oracle in the LICENSE file that accompanied this code.
|
||||
#
|
||||
# This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
# version 2 for more details (a copy is included in the LICENSE file that
|
||||
# accompanied this code).
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License version
|
||||
# 2 along with this work; if not, write to the Free Software Foundation,
|
||||
# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
#
|
||||
# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
# or visit www.oracle.com if you need additional information or have any
|
||||
# questions.
|
||||
#
|
||||
|
||||
# Generate exception classes
|
||||
|
||||
SPEC=$1
|
||||
DST=$2
|
||||
|
||||
gen() {
|
||||
ID=$1
|
||||
WHAT=$2
|
||||
SVUID=$3
|
||||
ARG_TYPE=$4
|
||||
ARG_ID=$5
|
||||
ARG_PROP=$6
|
||||
ARG_PHRASE=$7
|
||||
ARG_PARAM="$ARG_TYPE$ $ARG_ID"
|
||||
echo '-->' $DST/$ID.java
|
||||
out=$DST/${ID}.java
|
||||
|
||||
$SH ${SCRIPTS}/addNotices.sh "$COPYRIGHT_YEARS" > $out
|
||||
|
||||
cat >>$out <<__END__
|
||||
|
||||
// -- This file was mechanically generated: Do not edit! -- //
|
||||
|
||||
package $PACKAGE;
|
||||
|
||||
|
||||
/**$WHAT
|
||||
*
|
||||
* @since $SINCE
|
||||
*/
|
||||
|
||||
public `if [ ${ABSTRACT:-0} = 1 ];
|
||||
then echo 'abstract '; fi`class $ID
|
||||
extends ${SUPER}
|
||||
{
|
||||
|
||||
@java.io.Serial
|
||||
private static final long serialVersionUID = $SVUID;
|
||||
__END__
|
||||
|
||||
if [ $ARG_ID ]; then
|
||||
|
||||
cat >>$out <<__END__
|
||||
|
||||
/**
|
||||
* The $ARG_PHRASE.
|
||||
*
|
||||
* @serial
|
||||
*/
|
||||
private $ARG_TYPE $ARG_ID;
|
||||
|
||||
/**
|
||||
* Constructs an instance of this class.
|
||||
*
|
||||
* @param $ARG_ID
|
||||
* The $ARG_PHRASE
|
||||
*/
|
||||
public $ID($ARG_TYPE $ARG_ID) {
|
||||
super(String.valueOf($ARG_ID));
|
||||
this.$ARG_ID = $ARG_ID;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the $ARG_PHRASE.
|
||||
*
|
||||
* @return The $ARG_PHRASE
|
||||
*/
|
||||
public $ARG_TYPE get$ARG_PROP() {
|
||||
return $ARG_ID;
|
||||
}
|
||||
|
||||
}
|
||||
__END__
|
||||
|
||||
else
|
||||
|
||||
cat >>$out <<__END__
|
||||
|
||||
/**
|
||||
* Constructs an instance of this class.
|
||||
*/
|
||||
public $ID() { }
|
||||
|
||||
}
|
||||
__END__
|
||||
|
||||
fi
|
||||
}
|
||||
|
||||
. $SPEC
|
||||
@ -216,11 +216,6 @@ source %{
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
case Op_ExpandV:
|
||||
if (UseSVE < 2 || is_subword_type(bt)) {
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
case Op_VectorMaskToLong:
|
||||
if (UseSVE > 0 && vlen > 64) {
|
||||
return false;
|
||||
@ -7113,10 +7108,39 @@ instruct vcompressS(vReg dst, vReg src, pReg pg,
|
||||
ins_pipe(pipe_slow);
|
||||
%}
|
||||
|
||||
instruct vexpand(vReg dst, vReg src, pRegGov pg) %{
|
||||
instruct vexpand_neon(vReg dst, vReg src, vReg mask, vReg tmp1, vReg tmp2) %{
|
||||
predicate(UseSVE == 0);
|
||||
match(Set dst (ExpandV src mask));
|
||||
effect(TEMP_DEF dst, TEMP tmp1, TEMP tmp2);
|
||||
format %{ "vexpand_neon $dst, $src, $mask\t# KILL $tmp1, $tmp2" %}
|
||||
ins_encode %{
|
||||
BasicType bt = Matcher::vector_element_basic_type(this);
|
||||
int length_in_bytes = (int) Matcher::vector_length_in_bytes(this);
|
||||
__ vector_expand_neon($dst$$FloatRegister, $src$$FloatRegister, $mask$$FloatRegister,
|
||||
$tmp1$$FloatRegister, $tmp2$$FloatRegister, bt, length_in_bytes);
|
||||
%}
|
||||
ins_pipe(pipe_slow);
|
||||
%}
|
||||
|
||||
instruct vexpand_sve(vReg dst, vReg src, pRegGov pg, vReg tmp1, vReg tmp2) %{
|
||||
predicate(UseSVE == 1 || (UseSVE == 2 && type2aelembytes(Matcher::vector_element_basic_type(n)) < 4));
|
||||
match(Set dst (ExpandV src pg));
|
||||
effect(TEMP_DEF dst, TEMP tmp1, TEMP tmp2);
|
||||
format %{ "vexpand_sve $dst, $src, $pg\t# KILL $tmp1, $tmp2" %}
|
||||
ins_encode %{
|
||||
BasicType bt = Matcher::vector_element_basic_type(this);
|
||||
int length_in_bytes = (int) Matcher::vector_length_in_bytes(this);
|
||||
__ vector_expand_sve($dst$$FloatRegister, $src$$FloatRegister, $pg$$PRegister,
|
||||
$tmp1$$FloatRegister, $tmp2$$FloatRegister, bt, length_in_bytes);
|
||||
%}
|
||||
ins_pipe(pipe_slow);
|
||||
%}
|
||||
|
||||
instruct vexpand_sve2_SD(vReg dst, vReg src, pRegGov pg) %{
|
||||
predicate(UseSVE == 2 && type2aelembytes(Matcher::vector_element_basic_type(n)) >= 4);
|
||||
match(Set dst (ExpandV src pg));
|
||||
effect(TEMP_DEF dst);
|
||||
format %{ "vexpand $dst, $pg, $src" %}
|
||||
format %{ "vexpand_sve2_SD $dst, $src, $pg" %}
|
||||
ins_encode %{
|
||||
// Example input: src = 1 2 3 4 5 6 7 8
|
||||
// pg = 1 0 0 1 1 0 1 1
|
||||
@ -7127,7 +7151,6 @@ instruct vexpand(vReg dst, vReg src, pRegGov pg) %{
|
||||
// for TBL whose value is used to select the indexed element from src vector.
|
||||
|
||||
BasicType bt = Matcher::vector_element_basic_type(this);
|
||||
assert(UseSVE == 2 && !is_subword_type(bt), "unsupported");
|
||||
Assembler::SIMD_RegVariant size = __ elemType_to_regVariant(bt);
|
||||
// dst = 0 0 0 0 0 0 0 0
|
||||
__ sve_dup($dst$$FloatRegister, size, 0);
|
||||
|
||||
@ -206,11 +206,6 @@ source %{
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
case Op_ExpandV:
|
||||
if (UseSVE < 2 || is_subword_type(bt)) {
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
case Op_VectorMaskToLong:
|
||||
if (UseSVE > 0 && vlen > 64) {
|
||||
return false;
|
||||
@ -5101,10 +5096,39 @@ instruct vcompressS(vReg dst, vReg src, pReg pg,
|
||||
ins_pipe(pipe_slow);
|
||||
%}
|
||||
|
||||
instruct vexpand(vReg dst, vReg src, pRegGov pg) %{
|
||||
instruct vexpand_neon(vReg dst, vReg src, vReg mask, vReg tmp1, vReg tmp2) %{
|
||||
predicate(UseSVE == 0);
|
||||
match(Set dst (ExpandV src mask));
|
||||
effect(TEMP_DEF dst, TEMP tmp1, TEMP tmp2);
|
||||
format %{ "vexpand_neon $dst, $src, $mask\t# KILL $tmp1, $tmp2" %}
|
||||
ins_encode %{
|
||||
BasicType bt = Matcher::vector_element_basic_type(this);
|
||||
int length_in_bytes = (int) Matcher::vector_length_in_bytes(this);
|
||||
__ vector_expand_neon($dst$$FloatRegister, $src$$FloatRegister, $mask$$FloatRegister,
|
||||
$tmp1$$FloatRegister, $tmp2$$FloatRegister, bt, length_in_bytes);
|
||||
%}
|
||||
ins_pipe(pipe_slow);
|
||||
%}
|
||||
|
||||
instruct vexpand_sve(vReg dst, vReg src, pRegGov pg, vReg tmp1, vReg tmp2) %{
|
||||
predicate(UseSVE == 1 || (UseSVE == 2 && type2aelembytes(Matcher::vector_element_basic_type(n)) < 4));
|
||||
match(Set dst (ExpandV src pg));
|
||||
effect(TEMP_DEF dst, TEMP tmp1, TEMP tmp2);
|
||||
format %{ "vexpand_sve $dst, $src, $pg\t# KILL $tmp1, $tmp2" %}
|
||||
ins_encode %{
|
||||
BasicType bt = Matcher::vector_element_basic_type(this);
|
||||
int length_in_bytes = (int) Matcher::vector_length_in_bytes(this);
|
||||
__ vector_expand_sve($dst$$FloatRegister, $src$$FloatRegister, $pg$$PRegister,
|
||||
$tmp1$$FloatRegister, $tmp2$$FloatRegister, bt, length_in_bytes);
|
||||
%}
|
||||
ins_pipe(pipe_slow);
|
||||
%}
|
||||
|
||||
instruct vexpand_sve2_SD(vReg dst, vReg src, pRegGov pg) %{
|
||||
predicate(UseSVE == 2 && type2aelembytes(Matcher::vector_element_basic_type(n)) >= 4);
|
||||
match(Set dst (ExpandV src pg));
|
||||
effect(TEMP_DEF dst);
|
||||
format %{ "vexpand $dst, $pg, $src" %}
|
||||
format %{ "vexpand_sve2_SD $dst, $src, $pg" %}
|
||||
ins_encode %{
|
||||
// Example input: src = 1 2 3 4 5 6 7 8
|
||||
// pg = 1 0 0 1 1 0 1 1
|
||||
@ -5115,7 +5139,6 @@ instruct vexpand(vReg dst, vReg src, pRegGov pg) %{
|
||||
// for TBL whose value is used to select the indexed element from src vector.
|
||||
|
||||
BasicType bt = Matcher::vector_element_basic_type(this);
|
||||
assert(UseSVE == 2 && !is_subword_type(bt), "unsupported");
|
||||
Assembler::SIMD_RegVariant size = __ elemType_to_regVariant(bt);
|
||||
// dst = 0 0 0 0 0 0 0 0
|
||||
__ sve_dup($dst$$FloatRegister, size, 0);
|
||||
|
||||
@ -4068,6 +4068,13 @@ public:
|
||||
INSN(sve_brkb, 0b10); // Break before first true condition
|
||||
#undef INSN
|
||||
|
||||
// SVE move prefix (unpredicated)
|
||||
void sve_movprfx(FloatRegister Zd, FloatRegister Zn) {
|
||||
starti;
|
||||
f(0b00000100, 31, 24), f(0b00, 23, 22), f(0b1, 21), f(0b00000, 20, 16);
|
||||
f(0b101111, 15, 10), rf(Zn, 5), rf(Zd, 0);
|
||||
}
|
||||
|
||||
// Element count and increment scalar (SVE)
|
||||
#define INSN(NAME, TYPE) \
|
||||
void NAME(Register Xdn, unsigned imm4 = 1, int pattern = 0b11111) { \
|
||||
|
||||
@ -26,7 +26,7 @@
|
||||
#ifndef CPU_AARCH64_ASSEMBLER_AARCH64_INLINE_HPP
|
||||
#define CPU_AARCH64_ASSEMBLER_AARCH64_INLINE_HPP
|
||||
|
||||
#include "asm/assembler.inline.hpp"
|
||||
#include "asm/assembler.hpp"
|
||||
#include "asm/codeBuffer.hpp"
|
||||
#include "code/codeCache.hpp"
|
||||
|
||||
|
||||
@ -216,10 +216,10 @@ void MonitorEnterStub::emit_code(LIR_Assembler* ce) {
|
||||
|
||||
void MonitorExitStub::emit_code(LIR_Assembler* ce) {
|
||||
__ bind(_entry);
|
||||
if (_compute_lock) {
|
||||
// lock_reg was destroyed by fast unlocking attempt => recompute it
|
||||
ce->monitor_address(_monitor_ix, _lock_reg);
|
||||
}
|
||||
|
||||
// lock_reg was destroyed by fast unlocking attempt => recompute it
|
||||
ce->monitor_address(_monitor_ix, _lock_reg);
|
||||
|
||||
ce->store_parameter(_lock_reg->as_register(), 0);
|
||||
// note: non-blocking leaf routine => no call info needed
|
||||
StubId exit_id;
|
||||
|
||||
@ -409,7 +409,7 @@ int LIR_Assembler::emit_unwind_handler() {
|
||||
MonitorExitStub* stub = nullptr;
|
||||
if (method()->is_synchronized()) {
|
||||
monitor_address(0, FrameMap::r0_opr);
|
||||
stub = new MonitorExitStub(FrameMap::r0_opr, true, 0);
|
||||
stub = new MonitorExitStub(FrameMap::r0_opr, 0);
|
||||
__ unlock_object(r5, r4, r0, r6, *stub->entry());
|
||||
__ bind(*stub->continuation());
|
||||
}
|
||||
@ -2481,7 +2481,6 @@ void LIR_Assembler::emit_lock(LIR_OpLock* op) {
|
||||
Register lock = op->lock_opr()->as_register();
|
||||
Register temp = op->scratch_opr()->as_register();
|
||||
if (op->code() == lir_lock) {
|
||||
assert(BasicLock::displaced_header_offset_in_bytes() == 0, "lock_reg must point to the displaced header");
|
||||
// add debug info for NullPointerException only if one is possible
|
||||
int null_check_offset = __ lock_object(hdr, obj, lock, temp, *op->stub()->entry());
|
||||
if (op->info() != nullptr) {
|
||||
@ -2489,7 +2488,6 @@ void LIR_Assembler::emit_lock(LIR_OpLock* op) {
|
||||
}
|
||||
// done
|
||||
} else if (op->code() == lir_unlock) {
|
||||
assert(BasicLock::displaced_header_offset_in_bytes() == 0, "lock_reg must point to the displaced header");
|
||||
__ unlock_object(hdr, obj, lock, temp, *op->stub()->entry());
|
||||
} else {
|
||||
Unimplemented();
|
||||
|
||||
@ -59,28 +59,28 @@ void C1_MacroAssembler::float_cmp(bool is_float, int unordered_result,
|
||||
}
|
||||
}
|
||||
|
||||
int C1_MacroAssembler::lock_object(Register hdr, Register obj, Register disp_hdr, Register temp, Label& slow_case) {
|
||||
assert_different_registers(hdr, obj, disp_hdr, temp, rscratch2);
|
||||
int C1_MacroAssembler::lock_object(Register hdr, Register obj, Register basic_lock, Register temp, Label& slow_case) {
|
||||
assert_different_registers(hdr, obj, basic_lock, temp, rscratch2);
|
||||
int null_check_offset = -1;
|
||||
|
||||
verify_oop(obj);
|
||||
|
||||
// save object being locked into the BasicObjectLock
|
||||
str(obj, Address(disp_hdr, BasicObjectLock::obj_offset()));
|
||||
str(obj, Address(basic_lock, BasicObjectLock::obj_offset()));
|
||||
|
||||
null_check_offset = offset();
|
||||
|
||||
lightweight_lock(disp_hdr, obj, hdr, temp, rscratch2, slow_case);
|
||||
lightweight_lock(basic_lock, obj, hdr, temp, rscratch2, slow_case);
|
||||
|
||||
return null_check_offset;
|
||||
}
|
||||
|
||||
|
||||
void C1_MacroAssembler::unlock_object(Register hdr, Register obj, Register disp_hdr, Register temp, Label& slow_case) {
|
||||
assert_different_registers(hdr, obj, disp_hdr, temp, rscratch2);
|
||||
void C1_MacroAssembler::unlock_object(Register hdr, Register obj, Register basic_lock, Register temp, Label& slow_case) {
|
||||
assert_different_registers(hdr, obj, basic_lock, temp, rscratch2);
|
||||
|
||||
// load object
|
||||
ldr(obj, Address(disp_hdr, BasicObjectLock::obj_offset()));
|
||||
ldr(obj, Address(basic_lock, BasicObjectLock::obj_offset()));
|
||||
verify_oop(obj);
|
||||
|
||||
lightweight_unlock(obj, hdr, temp, rscratch2, slow_case);
|
||||
|
||||
@ -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.
|
||||
* Copyright (c) 2014, 2021, Red Hat Inc. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
@ -55,19 +55,19 @@ using MacroAssembler::null_check;
|
||||
Register result);
|
||||
|
||||
// locking
|
||||
// hdr : must be r0, contents destroyed
|
||||
// obj : must point to the object to lock, contents preserved
|
||||
// disp_hdr: must point to the displaced header location, contents preserved
|
||||
// temp : temporary register, must not be rscratch1 or rscratch2
|
||||
// hdr : must be r0, contents destroyed
|
||||
// obj : must point to the object to lock, contents preserved
|
||||
// basic_lock: must point to the basic lock, contents preserved
|
||||
// temp : temporary register, must not be rscratch1 or rscratch2
|
||||
// returns code offset at which to add null check debug information
|
||||
int lock_object (Register swap, Register obj, Register disp_hdr, Register temp, Label& slow_case);
|
||||
int lock_object (Register swap, Register obj, Register basic_lock, Register temp, Label& slow_case);
|
||||
|
||||
// unlocking
|
||||
// hdr : contents destroyed
|
||||
// obj : must point to the object to lock, contents preserved
|
||||
// disp_hdr: must be r0 & must point to the displaced header location, contents destroyed
|
||||
// temp : temporary register, must not be rscratch1 or rscratch2
|
||||
void unlock_object(Register swap, Register obj, Register lock, Register temp, Label& slow_case);
|
||||
// hdr : contents destroyed
|
||||
// obj : must point to the object to lock, contents preserved
|
||||
// basic_lock: must be r0 & must point to the basic lock, contents destroyed
|
||||
// temp : temporary register, must not be rscratch1 or rscratch2
|
||||
void unlock_object(Register swap, Register obj, Register basic_lock, Register temp, Label& slow_case);
|
||||
|
||||
void initialize_object(
|
||||
Register obj, // result: pointer to object after successful allocation
|
||||
|
||||
@ -2771,3 +2771,90 @@ void C2_MacroAssembler::select_from_two_vectors(FloatRegister dst, FloatRegister
|
||||
select_from_two_vectors_neon(dst, src1, src2, dst, tmp, vector_length_in_bytes);
|
||||
}
|
||||
}
|
||||
|
||||
// Vector expand implementation. Elements from the src vector are expanded into
|
||||
// the dst vector under the control of the vector mask.
|
||||
// Since there are no native instructions directly corresponding to expand before
|
||||
// SVE2p2, the following implementations mainly leverages the TBL instruction to
|
||||
// implement expand. To compute the index input for TBL, the prefix sum algorithm
|
||||
// (https://en.wikipedia.org/wiki/Prefix_sum) is used. The same algorithm is used
|
||||
// for NEON and SVE, but with different instructions where appropriate.
|
||||
|
||||
// Vector expand implementation for NEON.
|
||||
//
|
||||
// An example of 128-bit Byte vector:
|
||||
// Data direction: high <== low
|
||||
// Input:
|
||||
// src = g f e d c b a 9 8 7 6 5 4 3 2 1
|
||||
// mask = 0 0 -1 -1 0 0 -1 -1 0 0 -1 -1 0 0 -1 -1
|
||||
// Expected result:
|
||||
// dst = 0 0 8 7 0 0 6 5 0 0 4 3 0 0 2 1
|
||||
void C2_MacroAssembler::vector_expand_neon(FloatRegister dst, FloatRegister src, FloatRegister mask,
|
||||
FloatRegister tmp1, FloatRegister tmp2, BasicType bt,
|
||||
int vector_length_in_bytes) {
|
||||
assert(vector_length_in_bytes <= 16, "the vector length in bytes for NEON must be <= 16");
|
||||
assert_different_registers(dst, src, mask, tmp1, tmp2);
|
||||
// Since the TBL instruction only supports byte table, we need to
|
||||
// compute indices in byte type for all types.
|
||||
SIMD_Arrangement size = vector_length_in_bytes == 16 ? T16B : T8B;
|
||||
// tmp1 = 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
|
||||
dup(tmp1, size, zr);
|
||||
// dst = 0 0 1 1 0 0 1 1 0 0 1 1 0 0 1 1
|
||||
negr(dst, size, mask);
|
||||
// Calculate vector index for TBL with prefix sum algorithm.
|
||||
// dst = 8 8 8 7 6 6 6 5 4 4 4 3 2 2 2 1
|
||||
for (int i = 1; i < vector_length_in_bytes; i <<= 1) {
|
||||
ext(tmp2, size, tmp1, dst, vector_length_in_bytes - i);
|
||||
addv(dst, size, tmp2, dst);
|
||||
}
|
||||
// tmp2 = 0 0 -1 -1 0 0 -1 -1 0 0 -1 -1 0 0 -1 -1
|
||||
orr(tmp2, size, mask, mask);
|
||||
// tmp2 = 0 0 8 7 0 0 6 5 0 0 4 3 0 0 2 1
|
||||
bsl(tmp2, size, dst, tmp1);
|
||||
// tmp1 = 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
|
||||
movi(tmp1, size, 1);
|
||||
// dst = -1 -1 7 6 -1 -1 5 4 -1 -1 3 2 -1 -1 1 0
|
||||
subv(dst, size, tmp2, tmp1);
|
||||
// dst = 0 0 8 7 0 0 6 5 0 0 4 3 0 0 2 1
|
||||
tbl(dst, size, src, 1, dst);
|
||||
}
|
||||
|
||||
// Vector expand implementation for SVE.
|
||||
//
|
||||
// An example of 128-bit Short vector:
|
||||
// Data direction: high <== low
|
||||
// Input:
|
||||
// src = gf ed cb a9 87 65 43 21
|
||||
// pg = 00 01 00 01 00 01 00 01
|
||||
// Expected result:
|
||||
// dst = 00 87 00 65 00 43 00 21
|
||||
void C2_MacroAssembler::vector_expand_sve(FloatRegister dst, FloatRegister src, PRegister pg,
|
||||
FloatRegister tmp1, FloatRegister tmp2, BasicType bt,
|
||||
int vector_length_in_bytes) {
|
||||
assert(UseSVE > 0, "expand implementation only for SVE");
|
||||
assert_different_registers(dst, src, tmp1, tmp2);
|
||||
SIMD_RegVariant size = elemType_to_regVariant(bt);
|
||||
|
||||
// tmp1 = 00 00 00 00 00 00 00 00
|
||||
sve_dup(tmp1, size, 0);
|
||||
sve_movprfx(tmp2, tmp1);
|
||||
// tmp2 = 00 01 00 01 00 01 00 01
|
||||
sve_cpy(tmp2, size, pg, 1, true);
|
||||
// Calculate vector index for TBL with prefix sum algorithm.
|
||||
// tmp2 = 04 04 03 03 02 02 01 01
|
||||
for (int i = type2aelembytes(bt); i < vector_length_in_bytes; i <<= 1) {
|
||||
sve_movprfx(dst, tmp1);
|
||||
// The EXT instruction operates on the full-width sve register. The correct
|
||||
// index calculation method is:
|
||||
// vector_length_in_bytes - i + MaxVectorSize - vector_length_in_bytes =>
|
||||
// MaxVectorSize - i.
|
||||
sve_ext(dst, tmp2, MaxVectorSize - i);
|
||||
sve_add(tmp2, size, dst, tmp2);
|
||||
}
|
||||
// dst = 00 04 00 03 00 02 00 01
|
||||
sve_sel(dst, size, pg, tmp2, tmp1);
|
||||
// dst = -1 03 -1 02 -1 01 -1 00
|
||||
sve_sub(dst, size, 1);
|
||||
// dst = 00 87 00 65 00 43 00 21
|
||||
sve_tbl(dst, size, src, dst);
|
||||
}
|
||||
@ -204,4 +204,10 @@
|
||||
FloatRegister index, FloatRegister tmp, BasicType bt,
|
||||
unsigned vector_length_in_bytes);
|
||||
|
||||
void vector_expand_neon(FloatRegister dst, FloatRegister src, FloatRegister mask,
|
||||
FloatRegister tmp1, FloatRegister tmp2, BasicType bt,
|
||||
int vector_length_in_bytes);
|
||||
void vector_expand_sve(FloatRegister dst, FloatRegister src, PRegister pg,
|
||||
FloatRegister tmp1, FloatRegister tmp2, BasicType bt,
|
||||
int vector_length_in_bytes);
|
||||
#endif // CPU_AARCH64_C2_MACROASSEMBLER_AARCH64_HPP
|
||||
|
||||
@ -86,15 +86,48 @@ void G1BarrierSetAssembler::gen_write_ref_array_pre_barrier(MacroAssembler* masm
|
||||
}
|
||||
}
|
||||
|
||||
void G1BarrierSetAssembler::gen_write_ref_array_post_barrier(MacroAssembler* masm, DecoratorSet decorators,
|
||||
Register start, Register count, Register scratch, RegSet saved_regs) {
|
||||
__ push(saved_regs, sp);
|
||||
assert_different_registers(start, count, scratch);
|
||||
assert_different_registers(c_rarg0, count);
|
||||
__ mov(c_rarg0, start);
|
||||
__ mov(c_rarg1, count);
|
||||
__ call_VM_leaf(CAST_FROM_FN_PTR(address, G1BarrierSetRuntime::write_ref_array_post_entry), 2);
|
||||
__ pop(saved_regs, sp);
|
||||
void G1BarrierSetAssembler::gen_write_ref_array_post_barrier(MacroAssembler* masm,
|
||||
DecoratorSet decorators,
|
||||
Register start,
|
||||
Register count,
|
||||
Register scratch,
|
||||
RegSet saved_regs) {
|
||||
|
||||
Label done;
|
||||
Label loop;
|
||||
Label next;
|
||||
|
||||
__ cbz(count, done);
|
||||
|
||||
// Calculate the number of card marks to set. Since the object might start and
|
||||
// end within a card, we need to calculate this via the card table indexes of
|
||||
// the actual start and last addresses covered by the object.
|
||||
// Temporarily use the count register for the last element address.
|
||||
__ lea(count, Address(start, count, Address::lsl(LogBytesPerHeapOop))); // end = start + count << LogBytesPerHeapOop
|
||||
__ sub(count, count, BytesPerHeapOop); // Use last element address for end.
|
||||
|
||||
__ lsr(start, start, CardTable::card_shift());
|
||||
__ lsr(count, count, CardTable::card_shift());
|
||||
__ sub(count, count, start); // Number of bytes to mark - 1.
|
||||
|
||||
// Add card table base offset to start.
|
||||
__ ldr(scratch, Address(rthread, in_bytes(G1ThreadLocalData::card_table_base_offset())));
|
||||
__ add(start, start, scratch);
|
||||
|
||||
__ bind(loop);
|
||||
if (UseCondCardMark) {
|
||||
__ ldrb(scratch, Address(start, count));
|
||||
// Instead of loading clean_card_val and comparing, we exploit the fact that
|
||||
// the LSB of non-clean cards is always 0, and the LSB of clean cards 1.
|
||||
__ tbz(scratch, 0, next);
|
||||
}
|
||||
static_assert(G1CardTable::dirty_card_val() == 0, "must be to use zr");
|
||||
__ strb(zr, Address(start, count));
|
||||
__ bind(next);
|
||||
__ subs(count, count, 1);
|
||||
__ br(Assembler::GE, loop);
|
||||
|
||||
__ bind(done);
|
||||
}
|
||||
|
||||
static void generate_queue_test_and_insertion(MacroAssembler* masm, ByteSize index_offset, ByteSize buffer_offset, Label& runtime,
|
||||
@ -199,13 +232,17 @@ void G1BarrierSetAssembler::g1_write_barrier_pre(MacroAssembler* masm,
|
||||
|
||||
}
|
||||
|
||||
static void generate_post_barrier_fast_path(MacroAssembler* masm,
|
||||
const Register store_addr,
|
||||
const Register new_val,
|
||||
const Register tmp1,
|
||||
const Register tmp2,
|
||||
Label& done,
|
||||
bool new_val_may_be_null) {
|
||||
static void generate_post_barrier(MacroAssembler* masm,
|
||||
const Register store_addr,
|
||||
const Register new_val,
|
||||
const Register thread,
|
||||
const Register tmp1,
|
||||
const Register tmp2,
|
||||
Label& done,
|
||||
bool new_val_may_be_null) {
|
||||
assert(thread == rthread, "must be");
|
||||
assert_different_registers(store_addr, new_val, thread, tmp1, tmp2, noreg, rscratch1);
|
||||
|
||||
// Does store cross heap regions?
|
||||
__ eor(tmp1, store_addr, new_val); // tmp1 := store address ^ new value
|
||||
__ lsr(tmp1, tmp1, G1HeapRegion::LogOfHRGrainBytes); // tmp1 := ((store address ^ new value) >> LogOfHRGrainBytes)
|
||||
@ -214,33 +251,19 @@ static void generate_post_barrier_fast_path(MacroAssembler* masm,
|
||||
if (new_val_may_be_null) {
|
||||
__ cbz(new_val, done);
|
||||
}
|
||||
// Storing region crossing non-null, is card young?
|
||||
// Storing region crossing non-null.
|
||||
__ lsr(tmp1, store_addr, CardTable::card_shift()); // tmp1 := card address relative to card table base
|
||||
__ load_byte_map_base(tmp2); // tmp2 := card table base address
|
||||
__ add(tmp1, tmp1, tmp2); // tmp1 := card address
|
||||
__ ldrb(tmp2, Address(tmp1)); // tmp2 := card
|
||||
__ cmpw(tmp2, (int)G1CardTable::g1_young_card_val()); // tmp2 := card == young_card_val?
|
||||
}
|
||||
|
||||
static void generate_post_barrier_slow_path(MacroAssembler* masm,
|
||||
const Register thread,
|
||||
const Register tmp1,
|
||||
const Register tmp2,
|
||||
Label& done,
|
||||
Label& runtime) {
|
||||
__ membar(Assembler::StoreLoad); // StoreLoad membar
|
||||
__ ldrb(tmp2, Address(tmp1)); // tmp2 := card
|
||||
__ cbzw(tmp2, done);
|
||||
// Storing a region crossing, non-null oop, card is clean.
|
||||
// Dirty card and log.
|
||||
STATIC_ASSERT(CardTable::dirty_card_val() == 0);
|
||||
__ strb(zr, Address(tmp1)); // *(card address) := dirty_card_val
|
||||
generate_queue_test_and_insertion(masm,
|
||||
G1ThreadLocalData::dirty_card_queue_index_offset(),
|
||||
G1ThreadLocalData::dirty_card_queue_buffer_offset(),
|
||||
runtime,
|
||||
thread, tmp1, tmp2, rscratch1);
|
||||
__ b(done);
|
||||
Address card_table_addr(thread, in_bytes(G1ThreadLocalData::card_table_base_offset()));
|
||||
__ ldr(tmp2, card_table_addr); // tmp2 := card table base address
|
||||
if (UseCondCardMark) {
|
||||
__ ldrb(rscratch1, Address(tmp1, tmp2)); // rscratch1 := card
|
||||
// Instead of loading clean_card_val and comparing, we exploit the fact that
|
||||
// the LSB of non-clean cards is always 0, and the LSB of clean cards 1.
|
||||
__ tbz(rscratch1, 0, done);
|
||||
}
|
||||
static_assert(G1CardTable::dirty_card_val() == 0, "must be to use zr");
|
||||
__ strb(zr, Address(tmp1, tmp2)); // *(card address) := dirty_card_val
|
||||
}
|
||||
|
||||
void G1BarrierSetAssembler::g1_write_barrier_post(MacroAssembler* masm,
|
||||
@ -249,27 +272,8 @@ void G1BarrierSetAssembler::g1_write_barrier_post(MacroAssembler* masm,
|
||||
Register thread,
|
||||
Register tmp1,
|
||||
Register tmp2) {
|
||||
assert(thread == rthread, "must be");
|
||||
assert_different_registers(store_addr, new_val, thread, tmp1, tmp2,
|
||||
rscratch1);
|
||||
assert(store_addr != noreg && new_val != noreg && tmp1 != noreg
|
||||
&& tmp2 != noreg, "expecting a register");
|
||||
|
||||
Label done;
|
||||
Label runtime;
|
||||
|
||||
generate_post_barrier_fast_path(masm, store_addr, new_val, tmp1, tmp2, done, true /* new_val_may_be_null */);
|
||||
// If card is young, jump to done
|
||||
__ br(Assembler::EQ, done);
|
||||
generate_post_barrier_slow_path(masm, thread, tmp1, tmp2, done, runtime);
|
||||
|
||||
__ bind(runtime);
|
||||
// save the live input values
|
||||
RegSet saved = RegSet::of(store_addr);
|
||||
__ push(saved, sp);
|
||||
__ call_VM_leaf(CAST_FROM_FN_PTR(address, G1BarrierSetRuntime::write_ref_field_post_entry), tmp1, thread);
|
||||
__ pop(saved, sp);
|
||||
|
||||
generate_post_barrier(masm, store_addr, new_val, thread, tmp1, tmp2, done, false /* new_val_may_be_null */);
|
||||
__ bind(done);
|
||||
}
|
||||
|
||||
@ -329,38 +333,10 @@ void G1BarrierSetAssembler::g1_write_barrier_post_c2(MacroAssembler* masm,
|
||||
Register thread,
|
||||
Register tmp1,
|
||||
Register tmp2,
|
||||
G1PostBarrierStubC2* stub) {
|
||||
assert(thread == rthread, "must be");
|
||||
assert_different_registers(store_addr, new_val, thread, tmp1, tmp2,
|
||||
rscratch1);
|
||||
assert(store_addr != noreg && new_val != noreg && tmp1 != noreg
|
||||
&& tmp2 != noreg, "expecting a register");
|
||||
|
||||
stub->initialize_registers(thread, tmp1, tmp2);
|
||||
|
||||
bool new_val_may_be_null = (stub->barrier_data() & G1C2BarrierPostNotNull) == 0;
|
||||
generate_post_barrier_fast_path(masm, store_addr, new_val, tmp1, tmp2, *stub->continuation(), new_val_may_be_null);
|
||||
// If card is not young, jump to stub (slow path)
|
||||
__ br(Assembler::NE, *stub->entry());
|
||||
|
||||
__ bind(*stub->continuation());
|
||||
}
|
||||
|
||||
void G1BarrierSetAssembler::generate_c2_post_barrier_stub(MacroAssembler* masm,
|
||||
G1PostBarrierStubC2* stub) const {
|
||||
Assembler::InlineSkippedInstructionsCounter skip_counter(masm);
|
||||
Label runtime;
|
||||
Register thread = stub->thread();
|
||||
Register tmp1 = stub->tmp1(); // tmp1 holds the card address.
|
||||
Register tmp2 = stub->tmp2();
|
||||
assert(stub->tmp3() == noreg, "not needed in this platform");
|
||||
|
||||
__ bind(*stub->entry());
|
||||
generate_post_barrier_slow_path(masm, thread, tmp1, tmp2, *stub->continuation(), runtime);
|
||||
|
||||
__ bind(runtime);
|
||||
generate_c2_barrier_runtime_call(masm, stub, tmp1, CAST_FROM_FN_PTR(address, G1BarrierSetRuntime::write_ref_field_post_entry));
|
||||
__ b(*stub->continuation());
|
||||
bool new_val_may_be_null) {
|
||||
Label done;
|
||||
generate_post_barrier(masm, store_addr, new_val, thread, tmp1, tmp2, done, new_val_may_be_null);
|
||||
__ bind(done);
|
||||
}
|
||||
|
||||
#endif // COMPILER2
|
||||
@ -456,20 +432,19 @@ void G1BarrierSetAssembler::gen_pre_barrier_stub(LIR_Assembler* ce, G1PreBarrier
|
||||
__ b(*stub->continuation());
|
||||
}
|
||||
|
||||
void G1BarrierSetAssembler::gen_post_barrier_stub(LIR_Assembler* ce, G1PostBarrierStub* stub) {
|
||||
G1BarrierSetC1* bs = (G1BarrierSetC1*)BarrierSet::barrier_set()->barrier_set_c1();
|
||||
__ bind(*stub->entry());
|
||||
assert(stub->addr()->is_register(), "Precondition.");
|
||||
assert(stub->new_val()->is_register(), "Precondition.");
|
||||
Register new_val_reg = stub->new_val()->as_register();
|
||||
__ cbz(new_val_reg, *stub->continuation());
|
||||
ce->store_parameter(stub->addr()->as_pointer_register(), 0);
|
||||
__ far_call(RuntimeAddress(bs->post_barrier_c1_runtime_code_blob()->code_begin()));
|
||||
__ b(*stub->continuation());
|
||||
}
|
||||
|
||||
#undef __
|
||||
|
||||
void G1BarrierSetAssembler::g1_write_barrier_post_c1(MacroAssembler* masm,
|
||||
Register store_addr,
|
||||
Register new_val,
|
||||
Register thread,
|
||||
Register tmp1,
|
||||
Register tmp2) {
|
||||
Label done;
|
||||
generate_post_barrier(masm, store_addr, new_val, thread, tmp1, tmp2, done, true /* new_val_may_be_null */);
|
||||
masm->bind(done);
|
||||
}
|
||||
|
||||
#define __ sasm->
|
||||
|
||||
void G1BarrierSetAssembler::generate_c1_pre_barrier_runtime_stub(StubAssembler* sasm) {
|
||||
@ -521,74 +496,6 @@ void G1BarrierSetAssembler::generate_c1_pre_barrier_runtime_stub(StubAssembler*
|
||||
__ epilogue();
|
||||
}
|
||||
|
||||
void G1BarrierSetAssembler::generate_c1_post_barrier_runtime_stub(StubAssembler* sasm) {
|
||||
__ prologue("g1_post_barrier", false);
|
||||
|
||||
// arg0: store_address
|
||||
Address store_addr(rfp, 2*BytesPerWord);
|
||||
|
||||
BarrierSet* bs = BarrierSet::barrier_set();
|
||||
CardTableBarrierSet* ctbs = barrier_set_cast<CardTableBarrierSet>(bs);
|
||||
CardTable* ct = ctbs->card_table();
|
||||
|
||||
Label done;
|
||||
Label runtime;
|
||||
|
||||
// At this point we know new_value is non-null and the new_value crosses regions.
|
||||
// Must check to see if card is already dirty
|
||||
|
||||
const Register thread = rthread;
|
||||
|
||||
Address queue_index(thread, in_bytes(G1ThreadLocalData::dirty_card_queue_index_offset()));
|
||||
Address buffer(thread, in_bytes(G1ThreadLocalData::dirty_card_queue_buffer_offset()));
|
||||
|
||||
const Register card_offset = rscratch2;
|
||||
// LR is free here, so we can use it to hold the byte_map_base.
|
||||
const Register byte_map_base = lr;
|
||||
|
||||
assert_different_registers(card_offset, byte_map_base, rscratch1);
|
||||
|
||||
__ load_parameter(0, card_offset);
|
||||
__ lsr(card_offset, card_offset, CardTable::card_shift());
|
||||
__ load_byte_map_base(byte_map_base);
|
||||
__ ldrb(rscratch1, Address(byte_map_base, card_offset));
|
||||
__ cmpw(rscratch1, (int)G1CardTable::g1_young_card_val());
|
||||
__ br(Assembler::EQ, done);
|
||||
|
||||
assert((int)CardTable::dirty_card_val() == 0, "must be 0");
|
||||
|
||||
__ membar(Assembler::StoreLoad);
|
||||
__ ldrb(rscratch1, Address(byte_map_base, card_offset));
|
||||
__ cbzw(rscratch1, done);
|
||||
|
||||
// storing region crossing non-null, card is clean.
|
||||
// dirty card and log.
|
||||
__ strb(zr, Address(byte_map_base, card_offset));
|
||||
|
||||
// Convert card offset into an address in card_addr
|
||||
Register card_addr = card_offset;
|
||||
__ add(card_addr, byte_map_base, card_addr);
|
||||
|
||||
__ ldr(rscratch1, queue_index);
|
||||
__ cbz(rscratch1, runtime);
|
||||
__ sub(rscratch1, rscratch1, wordSize);
|
||||
__ str(rscratch1, queue_index);
|
||||
|
||||
// Reuse LR to hold buffer_addr
|
||||
const Register buffer_addr = lr;
|
||||
|
||||
__ ldr(buffer_addr, buffer);
|
||||
__ str(card_addr, Address(buffer_addr, rscratch1));
|
||||
__ b(done);
|
||||
|
||||
__ bind(runtime);
|
||||
__ push_call_clobbered_registers();
|
||||
__ call_VM_leaf(CAST_FROM_FN_PTR(address, G1BarrierSetRuntime::write_ref_field_post_entry), card_addr, thread);
|
||||
__ pop_call_clobbered_registers();
|
||||
__ bind(done);
|
||||
__ epilogue();
|
||||
}
|
||||
|
||||
#undef __
|
||||
|
||||
#endif // COMPILER1
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2018, 2024, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2018, 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
|
||||
@ -32,9 +32,7 @@
|
||||
class LIR_Assembler;
|
||||
class StubAssembler;
|
||||
class G1PreBarrierStub;
|
||||
class G1PostBarrierStub;
|
||||
class G1PreBarrierStubC2;
|
||||
class G1PostBarrierStubC2;
|
||||
|
||||
class G1BarrierSetAssembler: public ModRefBarrierSetAssembler {
|
||||
protected:
|
||||
@ -65,10 +63,15 @@ protected:
|
||||
public:
|
||||
#ifdef COMPILER1
|
||||
void gen_pre_barrier_stub(LIR_Assembler* ce, G1PreBarrierStub* stub);
|
||||
void gen_post_barrier_stub(LIR_Assembler* ce, G1PostBarrierStub* stub);
|
||||
|
||||
void generate_c1_pre_barrier_runtime_stub(StubAssembler* sasm);
|
||||
void generate_c1_post_barrier_runtime_stub(StubAssembler* sasm);
|
||||
|
||||
void g1_write_barrier_post_c1(MacroAssembler* masm,
|
||||
Register store_addr,
|
||||
Register new_val,
|
||||
Register thread,
|
||||
Register tmp1,
|
||||
Register tmp2);
|
||||
#endif
|
||||
|
||||
#ifdef COMPILER2
|
||||
@ -87,9 +90,7 @@ public:
|
||||
Register thread,
|
||||
Register tmp1,
|
||||
Register tmp2,
|
||||
G1PostBarrierStubC2* c2_stub);
|
||||
void generate_c2_post_barrier_stub(MacroAssembler* masm,
|
||||
G1PostBarrierStubC2* stub) const;
|
||||
bool new_val_may_be_null);
|
||||
#endif
|
||||
|
||||
void load_at(MacroAssembler* masm, DecoratorSet decorators, BasicType type,
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
//
|
||||
// Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved.
|
||||
// Copyright (c) 2024, 2025, Oracle and/or its affiliates. All rights reserved.
|
||||
// DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
//
|
||||
// This code is free software; you can redistribute it and/or modify it
|
||||
@ -62,13 +62,13 @@ static void write_barrier_post(MacroAssembler* masm,
|
||||
Register new_val,
|
||||
Register tmp1,
|
||||
Register tmp2) {
|
||||
if (!G1PostBarrierStubC2::needs_barrier(node)) {
|
||||
if (!G1BarrierStubC2::needs_post_barrier(node)) {
|
||||
return;
|
||||
}
|
||||
Assembler::InlineSkippedInstructionsCounter skip_counter(masm);
|
||||
G1BarrierSetAssembler* g1_asm = static_cast<G1BarrierSetAssembler*>(BarrierSet::barrier_set()->barrier_set_assembler());
|
||||
G1PostBarrierStubC2* const stub = G1PostBarrierStubC2::create(node);
|
||||
g1_asm->g1_write_barrier_post_c2(masm, store_addr, new_val, rthread, tmp1, tmp2, stub);
|
||||
bool new_val_may_be_null = G1BarrierStubC2::post_new_val_may_be_null(node);
|
||||
g1_asm->g1_write_barrier_post_c2(masm, store_addr, new_val, rthread, tmp1, tmp2, new_val_may_be_null);
|
||||
}
|
||||
|
||||
%}
|
||||
|
||||
@ -398,14 +398,18 @@ void BarrierSetAssembler::check_oop(MacroAssembler* masm, Register obj, Register
|
||||
OptoReg::Name BarrierSetAssembler::encode_float_vector_register_size(const Node* node, OptoReg::Name opto_reg) {
|
||||
switch (node->ideal_reg()) {
|
||||
case Op_RegF:
|
||||
case Op_RegI: // RA may place scalar values (Op_RegI/N/L/P) in FP registers when UseFPUForSpilling is enabled
|
||||
case Op_RegN:
|
||||
// No need to refine. The original encoding is already fine to distinguish.
|
||||
assert(opto_reg % 4 == 0, "Float register should only occupy a single slot");
|
||||
assert(opto_reg % 4 == 0, "32-bit register should only occupy a single slot");
|
||||
break;
|
||||
// Use different encoding values of the same fp/vector register to help distinguish different sizes.
|
||||
// Such as V16. The OptoReg::name and its corresponding slot value are
|
||||
// "V16": 64, "V16_H": 65, "V16_J": 66, "V16_K": 67.
|
||||
case Op_RegD:
|
||||
case Op_VecD:
|
||||
case Op_RegL:
|
||||
case Op_RegP:
|
||||
opto_reg &= ~3;
|
||||
opto_reg |= 1;
|
||||
break;
|
||||
|
||||
@ -275,7 +275,6 @@ public:
|
||||
Label* entry();
|
||||
};
|
||||
|
||||
|
||||
class ZStoreBarrierStubC2Aarch64 : public ZStoreBarrierStubC2 {
|
||||
private:
|
||||
bool _deferred_emit;
|
||||
|
||||
@ -239,7 +239,6 @@ instruct zCompareAndSwapPAcq(iRegINoSp res, indirect mem, iRegP oldval, iRegP ne
|
||||
ins_pipe(pipe_slow);
|
||||
%}
|
||||
|
||||
|
||||
instruct zCompareAndExchangeP(iRegPNoSp res, indirect mem, iRegP oldval, iRegP newval, iRegPNoSp oldval_tmp, iRegPNoSp newval_tmp, rFlagsReg cr) %{
|
||||
match(Set res (CompareAndExchangeP mem (Binary oldval newval)));
|
||||
predicate(UseZGC && !needs_acquiring_load_exclusive(n) && n->as_LoadStore()->barrier_data() != 0);
|
||||
|
||||
@ -1623,7 +1623,7 @@ public:
|
||||
FloatRegister p, FloatRegister z, FloatRegister t1);
|
||||
void ghash_reduce_wide(int index, FloatRegister result, FloatRegister lo, FloatRegister hi,
|
||||
FloatRegister p, FloatRegister z, FloatRegister t1);
|
||||
void ghash_processBlocks_wide(address p, Register state, Register subkeyH,
|
||||
void ghash_processBlocks_wide(Label& p, Register state, Register subkeyH,
|
||||
Register data, Register blocks, int unrolls);
|
||||
|
||||
|
||||
|
||||
@ -507,7 +507,7 @@ void MacroAssembler::ghash_modmul(FloatRegister result,
|
||||
//
|
||||
// Clobbers all vector registers.
|
||||
//
|
||||
void MacroAssembler::ghash_processBlocks_wide(address field_polynomial, Register state,
|
||||
void MacroAssembler::ghash_processBlocks_wide(Label& field_polynomial, Register state,
|
||||
Register subkeyH,
|
||||
Register data, Register blocks, int unrolls) {
|
||||
int register_stride = 7;
|
||||
@ -531,7 +531,10 @@ void MacroAssembler::ghash_processBlocks_wide(address field_polynomial, Register
|
||||
FloatRegister p = v31;
|
||||
eor(vzr, T16B, vzr, vzr); // zero register
|
||||
|
||||
ldrq(p, field_polynomial); // The field polynomial
|
||||
// load polynomial via label which must identify local data in the
|
||||
// same code stub
|
||||
adr(rscratch1, field_polynomial);
|
||||
ldrq(p, rscratch1); // The field polynomial
|
||||
|
||||
ldrq(v0, Address(state));
|
||||
ldrq(Hprime, Address(subkeyH));
|
||||
|
||||
@ -683,12 +683,12 @@ void SharedRuntime::generate_i2c2i_adapters(MacroAssembler *masm,
|
||||
int comp_args_on_stack,
|
||||
const BasicType *sig_bt,
|
||||
const VMRegPair *regs,
|
||||
AdapterHandlerEntry* handler) {
|
||||
address i2c_entry = __ pc();
|
||||
address entry_address[AdapterBlob::ENTRY_COUNT]) {
|
||||
entry_address[AdapterBlob::I2C] = __ pc();
|
||||
|
||||
gen_i2c_adapter(masm, total_args_passed, comp_args_on_stack, sig_bt, regs);
|
||||
|
||||
address c2i_unverified_entry = __ pc();
|
||||
entry_address[AdapterBlob::C2I_Unverified] = __ pc();
|
||||
Label skip_fixup;
|
||||
|
||||
Register data = rscratch2;
|
||||
@ -718,10 +718,10 @@ void SharedRuntime::generate_i2c2i_adapters(MacroAssembler *masm,
|
||||
__ block_comment("} c2i_unverified_entry");
|
||||
}
|
||||
|
||||
address c2i_entry = __ pc();
|
||||
entry_address[AdapterBlob::C2I] = __ pc();
|
||||
|
||||
// Class initialization barrier for static methods
|
||||
address c2i_no_clinit_check_entry = nullptr;
|
||||
entry_address[AdapterBlob::C2I_No_Clinit_Check] = nullptr;
|
||||
if (VM_Version::supports_fast_class_init_checks()) {
|
||||
Label L_skip_barrier;
|
||||
|
||||
@ -736,15 +736,13 @@ void SharedRuntime::generate_i2c2i_adapters(MacroAssembler *masm,
|
||||
__ far_jump(RuntimeAddress(SharedRuntime::get_handle_wrong_method_stub()));
|
||||
|
||||
__ bind(L_skip_barrier);
|
||||
c2i_no_clinit_check_entry = __ pc();
|
||||
entry_address[AdapterBlob::C2I_No_Clinit_Check] = __ pc();
|
||||
}
|
||||
|
||||
BarrierSetAssembler* bs = BarrierSet::barrier_set()->barrier_set_assembler();
|
||||
bs->c2i_entry_barrier(masm);
|
||||
|
||||
gen_c2i_adapter(masm, total_args_passed, comp_args_on_stack, sig_bt, regs, skip_fixup);
|
||||
|
||||
handler->set_entry_points(i2c_entry, c2i_entry, c2i_unverified_entry, c2i_no_clinit_check_entry);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -1763,9 +1761,6 @@ nmethod* SharedRuntime::generate_native_wrapper(MacroAssembler* masm,
|
||||
Label lock_done;
|
||||
|
||||
if (method->is_synchronized()) {
|
||||
Label count;
|
||||
const int mark_word_offset = BasicLock::displaced_header_offset_in_bytes();
|
||||
|
||||
// Get the handle (the 2nd argument)
|
||||
__ mov(oop_handle_reg, c_rarg1);
|
||||
|
||||
|
||||
@ -802,7 +802,7 @@ class StubGenerator: public StubCodeGenerator {
|
||||
//
|
||||
// s and d are adjusted to point to the remaining words to copy
|
||||
//
|
||||
void generate_copy_longs(StubId stub_id, DecoratorSet decorators, Label &start, Register s, Register d, Register count) {
|
||||
address generate_copy_longs(StubId stub_id, DecoratorSet decorators, Register s, Register d, Register count) {
|
||||
BasicType type;
|
||||
copy_direction direction;
|
||||
|
||||
@ -854,7 +854,7 @@ class StubGenerator: public StubCodeGenerator {
|
||||
|
||||
StubCodeMark mark(this, stub_id);
|
||||
|
||||
__ bind(start);
|
||||
address start = __ pc();
|
||||
|
||||
Label unaligned_copy_long;
|
||||
if (AvoidUnalignedAccesses) {
|
||||
@ -894,9 +894,9 @@ class StubGenerator: public StubCodeGenerator {
|
||||
int prefetch = PrefetchCopyIntervalInBytes;
|
||||
bool use_stride = false;
|
||||
if (direction == copy_backwards) {
|
||||
use_stride = prefetch > 256;
|
||||
prefetch = -prefetch;
|
||||
if (use_stride) __ mov(stride, prefetch);
|
||||
use_stride = prefetch > 256;
|
||||
prefetch = -prefetch;
|
||||
if (use_stride) __ mov(stride, prefetch);
|
||||
}
|
||||
|
||||
__ bind(again);
|
||||
@ -1026,9 +1026,9 @@ class StubGenerator: public StubCodeGenerator {
|
||||
int prefetch = PrefetchCopyIntervalInBytes;
|
||||
bool use_stride = false;
|
||||
if (direction == copy_backwards) {
|
||||
use_stride = prefetch > 256;
|
||||
prefetch = -prefetch;
|
||||
if (use_stride) __ mov(stride, prefetch);
|
||||
use_stride = prefetch > 256;
|
||||
prefetch = -prefetch;
|
||||
if (use_stride) __ mov(stride, prefetch);
|
||||
}
|
||||
|
||||
__ bind(again);
|
||||
@ -1037,15 +1037,15 @@ class StubGenerator: public StubCodeGenerator {
|
||||
__ prfm(use_stride ? Address(s, stride) : Address(s, prefetch), PLDL1KEEP);
|
||||
|
||||
if (direction == copy_forwards) {
|
||||
// allowing for the offset of -8 the store instructions place
|
||||
// registers into the target 64 bit block at the following
|
||||
// offsets
|
||||
//
|
||||
// t0 at offset 0
|
||||
// t1 at offset 8, t2 at offset 16
|
||||
// t3 at offset 24, t4 at offset 32
|
||||
// t5 at offset 40, t6 at offset 48
|
||||
// t7 at offset 56
|
||||
// allowing for the offset of -8 the store instructions place
|
||||
// registers into the target 64 bit block at the following
|
||||
// offsets
|
||||
//
|
||||
// t0 at offset 0
|
||||
// t1 at offset 8, t2 at offset 16
|
||||
// t3 at offset 24, t4 at offset 32
|
||||
// t5 at offset 40, t6 at offset 48
|
||||
// t7 at offset 56
|
||||
|
||||
bs.copy_store_at_8(Address(d, 1 * unit), t0);
|
||||
bs.copy_store_at_16(Address(d, 2 * unit), t1, t2);
|
||||
@ -1057,18 +1057,18 @@ class StubGenerator: public StubCodeGenerator {
|
||||
bs.copy_store_at_8(Address(__ pre(d, 8 * unit)), t7);
|
||||
bs.copy_load_at_16(t6, t7, Address(__ pre(s, 8 * unit)));
|
||||
} else {
|
||||
// d was not offset when we started so the registers are
|
||||
// written into the 64 bit block preceding d with the following
|
||||
// offsets
|
||||
//
|
||||
// t1 at offset -8
|
||||
// t3 at offset -24, t0 at offset -16
|
||||
// t5 at offset -48, t2 at offset -32
|
||||
// t7 at offset -56, t4 at offset -48
|
||||
// t6 at offset -64
|
||||
//
|
||||
// note that this matches the offsets previously noted for the
|
||||
// loads
|
||||
// d was not offset when we started so the registers are
|
||||
// written into the 64 bit block preceding d with the following
|
||||
// offsets
|
||||
//
|
||||
// t1 at offset -8
|
||||
// t3 at offset -24, t0 at offset -16
|
||||
// t5 at offset -48, t2 at offset -32
|
||||
// t7 at offset -56, t4 at offset -48
|
||||
// t6 at offset -64
|
||||
//
|
||||
// note that this matches the offsets previously noted for the
|
||||
// loads
|
||||
|
||||
bs.copy_store_at_8(Address(d, 1 * unit), t1);
|
||||
bs.copy_store_at_16(Address(d, 3 * unit), t3, t0);
|
||||
@ -1109,10 +1109,10 @@ class StubGenerator: public StubCodeGenerator {
|
||||
{
|
||||
Label L1, L2;
|
||||
__ tbz(count, exact_log2(4), L1);
|
||||
// this is the same as above but copying only 4 longs hence
|
||||
// with only one intervening stp between the str instructions
|
||||
// but note that the offsets and registers still follow the
|
||||
// same pattern
|
||||
// this is the same as above but copying only 4 longs hence
|
||||
// with only one intervening stp between the str instructions
|
||||
// but note that the offsets and registers still follow the
|
||||
// same pattern
|
||||
bs.copy_load_at_16(t0, t1, Address(s, 2 * unit));
|
||||
bs.copy_load_at_16(t2, t3, Address(__ pre(s, 4 * unit)));
|
||||
if (direction == copy_forwards) {
|
||||
@ -1127,10 +1127,10 @@ class StubGenerator: public StubCodeGenerator {
|
||||
__ bind(L1);
|
||||
|
||||
__ tbz(count, 1, L2);
|
||||
// this is the same as above but copying only 2 longs hence
|
||||
// there is no intervening stp between the str instructions
|
||||
// but note that the offset and register patterns are still
|
||||
// the same
|
||||
// this is the same as above but copying only 2 longs hence
|
||||
// there is no intervening stp between the str instructions
|
||||
// but note that the offset and register patterns are still
|
||||
// the same
|
||||
bs.copy_load_at_16(t0, t1, Address(__ pre(s, 2 * unit)));
|
||||
if (direction == copy_forwards) {
|
||||
bs.copy_store_at_8(Address(d, 1 * unit), t0);
|
||||
@ -1141,18 +1141,20 @@ class StubGenerator: public StubCodeGenerator {
|
||||
}
|
||||
__ bind(L2);
|
||||
|
||||
// for forwards copy we need to re-adjust the offsets we
|
||||
// applied so that s and d are follow the last words written
|
||||
// for forwards copy we need to re-adjust the offsets we
|
||||
// applied so that s and d are follow the last words written
|
||||
|
||||
if (direction == copy_forwards) {
|
||||
__ add(s, s, 16);
|
||||
__ add(d, d, 8);
|
||||
}
|
||||
if (direction == copy_forwards) {
|
||||
__ add(s, s, 16);
|
||||
__ add(d, d, 8);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
__ ret(lr);
|
||||
}
|
||||
}
|
||||
|
||||
return start;
|
||||
}
|
||||
|
||||
// Small copy: less than 16 bytes.
|
||||
@ -1206,10 +1208,6 @@ class StubGenerator: public StubCodeGenerator {
|
||||
}
|
||||
}
|
||||
|
||||
Label copy_f, copy_b;
|
||||
Label copy_obj_f, copy_obj_b;
|
||||
Label copy_obj_uninit_f, copy_obj_uninit_b;
|
||||
|
||||
// All-singing all-dancing memory copy.
|
||||
//
|
||||
// Copy count units of memory from s to d. The size of a unit is
|
||||
@ -1447,19 +1445,19 @@ class StubGenerator: public StubCodeGenerator {
|
||||
}
|
||||
if (direction == copy_forwards) {
|
||||
if (type != T_OBJECT) {
|
||||
__ bl(copy_f);
|
||||
__ bl(StubRoutines::aarch64::copy_byte_f());
|
||||
} else if ((decorators & IS_DEST_UNINITIALIZED) != 0) {
|
||||
__ bl(copy_obj_uninit_f);
|
||||
__ bl(StubRoutines::aarch64::copy_oop_uninit_f());
|
||||
} else {
|
||||
__ bl(copy_obj_f);
|
||||
__ bl(StubRoutines::aarch64::copy_oop_f());
|
||||
}
|
||||
} else {
|
||||
if (type != T_OBJECT) {
|
||||
__ bl(copy_b);
|
||||
__ bl(StubRoutines::aarch64::copy_byte_b());
|
||||
} else if ((decorators & IS_DEST_UNINITIALIZED) != 0) {
|
||||
__ bl(copy_obj_uninit_b);
|
||||
__ bl(StubRoutines::aarch64::copy_oop_uninit_b());
|
||||
} else {
|
||||
__ bl(copy_obj_b);
|
||||
__ bl(StubRoutines::aarch64::copy_oop_b());
|
||||
}
|
||||
}
|
||||
|
||||
@ -1522,11 +1520,11 @@ class StubGenerator: public StubCodeGenerator {
|
||||
// the hardware handle it. The two dwords within qwords that span
|
||||
// cache line boundaries will still be loaded and stored atomically.
|
||||
//
|
||||
// Side Effects: entry is set to the (post push) entry point so it
|
||||
// can be used by the corresponding conjoint copy
|
||||
// method
|
||||
// Side Effects: nopush_entry is set to the (post push) entry point
|
||||
// so it can be used by the corresponding conjoint
|
||||
// copy method
|
||||
//
|
||||
address generate_disjoint_copy(StubId stub_id, address *entry) {
|
||||
address generate_disjoint_copy(StubId stub_id, address *nopush_entry) {
|
||||
Register s = c_rarg0, d = c_rarg1, count = c_rarg2;
|
||||
RegSet saved_reg = RegSet::of(s, d, count);
|
||||
int size;
|
||||
@ -1615,8 +1613,8 @@ class StubGenerator: public StubCodeGenerator {
|
||||
address start = __ pc();
|
||||
__ enter();
|
||||
|
||||
if (entry != nullptr) {
|
||||
*entry = __ pc();
|
||||
if (nopush_entry != nullptr) {
|
||||
*nopush_entry = __ pc();
|
||||
// caller can pass a 64-bit byte count here (from Unsafe.copyMemory)
|
||||
BLOCK_COMMENT("Entry:");
|
||||
}
|
||||
@ -1679,10 +1677,10 @@ class StubGenerator: public StubCodeGenerator {
|
||||
// cache line boundaries will still be loaded and stored atomically.
|
||||
//
|
||||
// Side Effects:
|
||||
// entry is set to the no-overlap entry point so it can be used by
|
||||
// some other conjoint copy method
|
||||
// nopush_entry is set to the no-overlap entry point so it can be
|
||||
// used by some other conjoint copy method
|
||||
//
|
||||
address generate_conjoint_copy(StubId stub_id, address nooverlap_target, address *entry) {
|
||||
address generate_conjoint_copy(StubId stub_id, address nooverlap_target, address *nopush_entry) {
|
||||
Register s = c_rarg0, d = c_rarg1, count = c_rarg2;
|
||||
RegSet saved_regs = RegSet::of(s, d, count);
|
||||
int size;
|
||||
@ -1769,16 +1767,19 @@ class StubGenerator: public StubCodeGenerator {
|
||||
address start = __ pc();
|
||||
__ enter();
|
||||
|
||||
if (entry != nullptr) {
|
||||
*entry = __ pc();
|
||||
if (nopush_entry != nullptr) {
|
||||
*nopush_entry = __ pc();
|
||||
// caller can pass a 64-bit byte count here (from Unsafe.copyMemory)
|
||||
BLOCK_COMMENT("Entry:");
|
||||
}
|
||||
|
||||
// use fwd copy when (d-s) above_equal (count*size)
|
||||
Label L_overlapping;
|
||||
__ sub(rscratch1, d, s);
|
||||
__ cmp(rscratch1, count, Assembler::LSL, exact_log2(size));
|
||||
__ br(Assembler::HS, nooverlap_target);
|
||||
__ br(Assembler::LO, L_overlapping);
|
||||
__ b(RuntimeAddress(nooverlap_target));
|
||||
__ bind(L_overlapping);
|
||||
|
||||
DecoratorSet decorators = IN_HEAP | IS_ARRAY;
|
||||
if (dest_uninitialized) {
|
||||
@ -1850,7 +1851,7 @@ class StubGenerator: public StubCodeGenerator {
|
||||
// r0 == 0 - success
|
||||
// r0 == -1^K - failure, where K is partial transfer count
|
||||
//
|
||||
address generate_checkcast_copy(StubId stub_id, address *entry) {
|
||||
address generate_checkcast_copy(StubId stub_id, address *nopush_entry) {
|
||||
bool dest_uninitialized;
|
||||
switch (stub_id) {
|
||||
case StubId::stubgen_checkcast_arraycopy_id:
|
||||
@ -1911,8 +1912,8 @@ class StubGenerator: public StubCodeGenerator {
|
||||
#endif //ASSERT
|
||||
|
||||
// Caller of this entry point must set up the argument registers.
|
||||
if (entry != nullptr) {
|
||||
*entry = __ pc();
|
||||
if (nopush_entry != nullptr) {
|
||||
*nopush_entry = __ pc();
|
||||
BLOCK_COMMENT("Entry:");
|
||||
}
|
||||
|
||||
@ -2724,13 +2725,21 @@ class StubGenerator: public StubCodeGenerator {
|
||||
}
|
||||
|
||||
void generate_arraycopy_stubs() {
|
||||
address entry;
|
||||
address entry_jbyte_arraycopy;
|
||||
address entry_jshort_arraycopy;
|
||||
address entry_jint_arraycopy;
|
||||
address entry_oop_arraycopy;
|
||||
address entry_jlong_arraycopy;
|
||||
address entry_checkcast_arraycopy;
|
||||
// Some copy stubs publish a normal entry and then a 2nd 'fallback'
|
||||
// entry immediately following their stack push. This can be used
|
||||
// as a post-push branch target for compatible stubs when they
|
||||
// identify a special case that can be handled by the fallback
|
||||
// stub e.g a disjoint copy stub may be use as a special case
|
||||
// fallback for its compatible conjoint copy stub.
|
||||
//
|
||||
// A no push entry is always returned in the following local and
|
||||
// then published by assigning to the appropriate entry field in
|
||||
// class StubRoutines. The entry value is then passed to the
|
||||
// generator for the compatible stub. That means the entry must be
|
||||
// listed when saving to/restoring from the AOT cache, ensuring
|
||||
// that the inter-stub jumps are noted at AOT-cache save and
|
||||
// relocated at AOT cache load.
|
||||
address nopush_entry;
|
||||
|
||||
// generate the common exit first so later stubs can rely on it if
|
||||
// they want an UnsafeMemoryAccess exit non-local to the stub
|
||||
@ -2738,83 +2747,123 @@ class StubGenerator: public StubCodeGenerator {
|
||||
// register the stub as the default exit with class UnsafeMemoryAccess
|
||||
UnsafeMemoryAccess::set_common_exit_stub_pc(StubRoutines::_unsafecopy_common_exit);
|
||||
|
||||
generate_copy_longs(StubId::stubgen_copy_byte_f_id, IN_HEAP | IS_ARRAY, copy_f, r0, r1, r15);
|
||||
generate_copy_longs(StubId::stubgen_copy_byte_b_id, IN_HEAP | IS_ARRAY, copy_b, r0, r1, r15);
|
||||
// generate and publish arch64-specific bulk copy routines first
|
||||
// so we can call them from other copy stubs
|
||||
StubRoutines::aarch64::_copy_byte_f = generate_copy_longs(StubId::stubgen_copy_byte_f_id, IN_HEAP | IS_ARRAY, r0, r1, r15);
|
||||
StubRoutines::aarch64::_copy_byte_b = generate_copy_longs(StubId::stubgen_copy_byte_b_id, IN_HEAP | IS_ARRAY, r0, r1, r15);
|
||||
|
||||
generate_copy_longs(StubId::stubgen_copy_oop_f_id, IN_HEAP | IS_ARRAY, copy_obj_f, r0, r1, r15);
|
||||
generate_copy_longs(StubId::stubgen_copy_oop_b_id, IN_HEAP | IS_ARRAY, copy_obj_b, r0, r1, r15);
|
||||
StubRoutines::aarch64::_copy_oop_f = generate_copy_longs(StubId::stubgen_copy_oop_f_id, IN_HEAP | IS_ARRAY, r0, r1, r15);
|
||||
StubRoutines::aarch64::_copy_oop_b = generate_copy_longs(StubId::stubgen_copy_oop_b_id, IN_HEAP | IS_ARRAY, r0, r1, r15);
|
||||
|
||||
generate_copy_longs(StubId::stubgen_copy_oop_uninit_f_id, IN_HEAP | IS_ARRAY | IS_DEST_UNINITIALIZED, copy_obj_uninit_f, r0, r1, r15);
|
||||
generate_copy_longs(StubId::stubgen_copy_oop_uninit_b_id, IN_HEAP | IS_ARRAY | IS_DEST_UNINITIALIZED, copy_obj_uninit_b, r0, r1, r15);
|
||||
StubRoutines::aarch64::_copy_oop_uninit_f = generate_copy_longs(StubId::stubgen_copy_oop_uninit_f_id, IN_HEAP | IS_ARRAY | IS_DEST_UNINITIALIZED, r0, r1, r15);
|
||||
StubRoutines::aarch64::_copy_oop_uninit_b = generate_copy_longs(StubId::stubgen_copy_oop_uninit_b_id, IN_HEAP | IS_ARRAY | IS_DEST_UNINITIALIZED, r0, r1, r15);
|
||||
|
||||
StubRoutines::aarch64::_zero_blocks = generate_zero_blocks();
|
||||
|
||||
//*** jbyte
|
||||
// Always need aligned and unaligned versions
|
||||
StubRoutines::_jbyte_disjoint_arraycopy = generate_disjoint_copy(StubId::stubgen_jbyte_disjoint_arraycopy_id, &entry);
|
||||
StubRoutines::_jbyte_arraycopy = generate_conjoint_copy(StubId::stubgen_jbyte_arraycopy_id, entry, &entry_jbyte_arraycopy);
|
||||
StubRoutines::_arrayof_jbyte_disjoint_arraycopy = generate_disjoint_copy(StubId::stubgen_arrayof_jbyte_disjoint_arraycopy_id, &entry);
|
||||
StubRoutines::_arrayof_jbyte_arraycopy = generate_conjoint_copy(StubId::stubgen_arrayof_jbyte_arraycopy_id, entry, nullptr);
|
||||
StubRoutines::_jbyte_disjoint_arraycopy = generate_disjoint_copy(StubId::stubgen_jbyte_disjoint_arraycopy_id, &nopush_entry);
|
||||
// disjoint nopush entry is needed by conjoint copy
|
||||
StubRoutines::_jbyte_disjoint_arraycopy_nopush = nopush_entry;
|
||||
StubRoutines::_jbyte_arraycopy = generate_conjoint_copy(StubId::stubgen_jbyte_arraycopy_id, StubRoutines::_jbyte_disjoint_arraycopy_nopush, &nopush_entry);
|
||||
// conjoint nopush entry is needed by generic/unsafe copy
|
||||
StubRoutines::_jbyte_arraycopy_nopush = nopush_entry;
|
||||
StubRoutines::_arrayof_jbyte_disjoint_arraycopy = generate_disjoint_copy(StubId::stubgen_arrayof_jbyte_disjoint_arraycopy_id, &nopush_entry);
|
||||
// disjoint arrayof nopush entry is needed by conjoint copy
|
||||
StubRoutines::_arrayof_jbyte_disjoint_arraycopy_nopush = nopush_entry;
|
||||
StubRoutines::_arrayof_jbyte_arraycopy = generate_conjoint_copy(StubId::stubgen_arrayof_jbyte_arraycopy_id, StubRoutines::_arrayof_jbyte_disjoint_arraycopy_nopush, nullptr);
|
||||
|
||||
//*** jshort
|
||||
// Always need aligned and unaligned versions
|
||||
StubRoutines::_jshort_disjoint_arraycopy = generate_disjoint_copy(StubId::stubgen_jshort_disjoint_arraycopy_id, &entry);
|
||||
StubRoutines::_jshort_arraycopy = generate_conjoint_copy(StubId::stubgen_jshort_arraycopy_id, entry, &entry_jshort_arraycopy);
|
||||
StubRoutines::_arrayof_jshort_disjoint_arraycopy = generate_disjoint_copy(StubId::stubgen_arrayof_jshort_disjoint_arraycopy_id, &entry);
|
||||
StubRoutines::_arrayof_jshort_arraycopy = generate_conjoint_copy(StubId::stubgen_arrayof_jshort_arraycopy_id, entry, nullptr);
|
||||
StubRoutines::_jshort_disjoint_arraycopy = generate_disjoint_copy(StubId::stubgen_jshort_disjoint_arraycopy_id, &nopush_entry);
|
||||
// disjoint nopush entry is needed by conjoint copy
|
||||
StubRoutines::_jshort_disjoint_arraycopy_nopush = nopush_entry;
|
||||
StubRoutines::_jshort_arraycopy = generate_conjoint_copy(StubId::stubgen_jshort_arraycopy_id, StubRoutines::_jshort_disjoint_arraycopy_nopush, &nopush_entry);
|
||||
// conjoint nopush entry is used by generic/unsafe copy
|
||||
StubRoutines::_jshort_arraycopy_nopush = nopush_entry;
|
||||
StubRoutines::_arrayof_jshort_disjoint_arraycopy = generate_disjoint_copy(StubId::stubgen_arrayof_jshort_disjoint_arraycopy_id, &nopush_entry);
|
||||
// disjoint arrayof nopush entry is needed by conjoint copy
|
||||
StubRoutines::_arrayof_jshort_disjoint_arraycopy_nopush = nopush_entry;
|
||||
StubRoutines::_arrayof_jshort_arraycopy = generate_conjoint_copy(StubId::stubgen_arrayof_jshort_arraycopy_id, StubRoutines::_arrayof_jshort_disjoint_arraycopy_nopush, nullptr);
|
||||
|
||||
//*** jint
|
||||
// Aligned versions
|
||||
StubRoutines::_arrayof_jint_disjoint_arraycopy = generate_disjoint_copy(StubId::stubgen_arrayof_jint_disjoint_arraycopy_id, &entry);
|
||||
StubRoutines::_arrayof_jint_arraycopy = generate_conjoint_copy(StubId::stubgen_arrayof_jint_arraycopy_id, entry, &entry_jint_arraycopy);
|
||||
StubRoutines::_arrayof_jint_disjoint_arraycopy = generate_disjoint_copy(StubId::stubgen_arrayof_jint_disjoint_arraycopy_id, &nopush_entry);
|
||||
// disjoint arrayof nopush entry is needed by conjoint copy
|
||||
StubRoutines::_arrayof_jint_disjoint_arraycopy_nopush = nopush_entry;
|
||||
StubRoutines::_arrayof_jint_arraycopy = generate_conjoint_copy(StubId::stubgen_arrayof_jint_arraycopy_id, StubRoutines::_arrayof_jint_disjoint_arraycopy_nopush, nullptr);
|
||||
// In 64 bit we need both aligned and unaligned versions of jint arraycopy.
|
||||
// entry_jint_arraycopy always points to the unaligned version
|
||||
StubRoutines::_jint_disjoint_arraycopy = generate_disjoint_copy(StubId::stubgen_jint_disjoint_arraycopy_id, &entry);
|
||||
StubRoutines::_jint_arraycopy = generate_conjoint_copy(StubId::stubgen_jint_arraycopy_id, entry, &entry_jint_arraycopy);
|
||||
// jint_arraycopy_nopush always points to the unaligned version
|
||||
StubRoutines::_jint_disjoint_arraycopy = generate_disjoint_copy(StubId::stubgen_jint_disjoint_arraycopy_id, &nopush_entry);
|
||||
// disjoint nopush entry is needed by conjoint copy
|
||||
StubRoutines::_jint_disjoint_arraycopy_nopush = nopush_entry;
|
||||
StubRoutines::_jint_arraycopy = generate_conjoint_copy(StubId::stubgen_jint_arraycopy_id, StubRoutines::_jint_disjoint_arraycopy_nopush, &nopush_entry);
|
||||
// conjoint nopush entry is needed by generic/unsafe copy
|
||||
StubRoutines::_jint_arraycopy_nopush = nopush_entry;
|
||||
|
||||
//*** jlong
|
||||
// It is always aligned
|
||||
StubRoutines::_arrayof_jlong_disjoint_arraycopy = generate_disjoint_copy(StubId::stubgen_arrayof_jlong_disjoint_arraycopy_id, &entry);
|
||||
StubRoutines::_arrayof_jlong_arraycopy = generate_conjoint_copy(StubId::stubgen_arrayof_jlong_arraycopy_id, entry, &entry_jlong_arraycopy);
|
||||
StubRoutines::_arrayof_jlong_disjoint_arraycopy = generate_disjoint_copy(StubId::stubgen_arrayof_jlong_disjoint_arraycopy_id, &nopush_entry);
|
||||
// disjoint arrayof nopush entry is needed by conjoint copy
|
||||
StubRoutines::_arrayof_jlong_disjoint_arraycopy_nopush = nopush_entry;
|
||||
StubRoutines::_arrayof_jlong_arraycopy = generate_conjoint_copy(StubId::stubgen_arrayof_jlong_arraycopy_id, StubRoutines::_arrayof_jlong_disjoint_arraycopy_nopush, &nopush_entry);
|
||||
// conjoint nopush entry is needed by generic/unsafe copy
|
||||
StubRoutines::_jlong_arraycopy_nopush = nopush_entry;
|
||||
// disjoint normal/nopush and conjoint normal entries are not
|
||||
// generated since the arrayof versions are the same
|
||||
StubRoutines::_jlong_disjoint_arraycopy = StubRoutines::_arrayof_jlong_disjoint_arraycopy;
|
||||
StubRoutines::_jlong_disjoint_arraycopy_nopush = StubRoutines::_arrayof_jlong_disjoint_arraycopy_nopush;
|
||||
StubRoutines::_jlong_arraycopy = StubRoutines::_arrayof_jlong_arraycopy;
|
||||
|
||||
//*** oops
|
||||
{
|
||||
// With compressed oops we need unaligned versions; notice that
|
||||
// we overwrite entry_oop_arraycopy.
|
||||
bool aligned = !UseCompressedOops;
|
||||
|
||||
StubRoutines::_arrayof_oop_disjoint_arraycopy
|
||||
= generate_disjoint_copy(StubId::stubgen_arrayof_oop_disjoint_arraycopy_id, &entry);
|
||||
= generate_disjoint_copy(StubId::stubgen_arrayof_oop_disjoint_arraycopy_id, &nopush_entry);
|
||||
// disjoint arrayof nopush entry is needed by conjoint copy
|
||||
StubRoutines::_arrayof_oop_disjoint_arraycopy_nopush = nopush_entry;
|
||||
StubRoutines::_arrayof_oop_arraycopy
|
||||
= generate_conjoint_copy(StubId::stubgen_arrayof_oop_arraycopy_id, entry, &entry_oop_arraycopy);
|
||||
= generate_conjoint_copy(StubId::stubgen_arrayof_oop_arraycopy_id, StubRoutines::_arrayof_oop_disjoint_arraycopy_nopush, &nopush_entry);
|
||||
// conjoint arrayof nopush entry is needed by generic/unsafe copy
|
||||
StubRoutines::_oop_arraycopy_nopush = nopush_entry;
|
||||
// Aligned versions without pre-barriers
|
||||
StubRoutines::_arrayof_oop_disjoint_arraycopy_uninit
|
||||
= generate_disjoint_copy(StubId::stubgen_arrayof_oop_disjoint_arraycopy_uninit_id, &entry);
|
||||
= generate_disjoint_copy(StubId::stubgen_arrayof_oop_disjoint_arraycopy_uninit_id, &nopush_entry);
|
||||
// disjoint arrayof+uninit nopush entry is needed by conjoint copy
|
||||
StubRoutines::_arrayof_oop_disjoint_arraycopy_uninit_nopush = nopush_entry;
|
||||
// note that we don't need a returned nopush entry because the
|
||||
// generic/unsafe copy does not cater for uninit arrays.
|
||||
StubRoutines::_arrayof_oop_arraycopy_uninit
|
||||
= generate_conjoint_copy(StubId::stubgen_arrayof_oop_arraycopy_uninit_id, entry, nullptr);
|
||||
= generate_conjoint_copy(StubId::stubgen_arrayof_oop_arraycopy_uninit_id, StubRoutines::_arrayof_oop_disjoint_arraycopy_uninit_nopush, nullptr);
|
||||
}
|
||||
|
||||
// for oop copies reuse arrayof entries for non-arrayof cases
|
||||
StubRoutines::_oop_disjoint_arraycopy = StubRoutines::_arrayof_oop_disjoint_arraycopy;
|
||||
StubRoutines::_oop_disjoint_arraycopy_nopush = StubRoutines::_arrayof_oop_disjoint_arraycopy_nopush;
|
||||
StubRoutines::_oop_arraycopy = StubRoutines::_arrayof_oop_arraycopy;
|
||||
StubRoutines::_oop_disjoint_arraycopy_uninit = StubRoutines::_arrayof_oop_disjoint_arraycopy_uninit;
|
||||
StubRoutines::_oop_disjoint_arraycopy_uninit_nopush = StubRoutines::_arrayof_oop_disjoint_arraycopy_uninit_nopush;
|
||||
StubRoutines::_oop_arraycopy_uninit = StubRoutines::_arrayof_oop_arraycopy_uninit;
|
||||
|
||||
StubRoutines::_checkcast_arraycopy = generate_checkcast_copy(StubId::stubgen_checkcast_arraycopy_id, &entry_checkcast_arraycopy);
|
||||
StubRoutines::_checkcast_arraycopy = generate_checkcast_copy(StubId::stubgen_checkcast_arraycopy_id, &nopush_entry);
|
||||
// checkcast nopush entry is needed by generic copy
|
||||
StubRoutines::_checkcast_arraycopy_nopush = nopush_entry;
|
||||
// note that we don't need a returned nopush entry because the
|
||||
// generic copy does not cater for uninit arrays.
|
||||
StubRoutines::_checkcast_arraycopy_uninit = generate_checkcast_copy(StubId::stubgen_checkcast_arraycopy_uninit_id, nullptr);
|
||||
|
||||
StubRoutines::_unsafe_arraycopy = generate_unsafe_copy(entry_jbyte_arraycopy,
|
||||
entry_jshort_arraycopy,
|
||||
entry_jint_arraycopy,
|
||||
entry_jlong_arraycopy);
|
||||
// unsafe arraycopy may fallback on conjoint stubs
|
||||
StubRoutines::_unsafe_arraycopy = generate_unsafe_copy(StubRoutines::_jbyte_arraycopy_nopush,
|
||||
StubRoutines::_jshort_arraycopy_nopush,
|
||||
StubRoutines::_jint_arraycopy_nopush,
|
||||
StubRoutines::_jlong_arraycopy_nopush);
|
||||
|
||||
StubRoutines::_generic_arraycopy = generate_generic_copy(entry_jbyte_arraycopy,
|
||||
entry_jshort_arraycopy,
|
||||
entry_jint_arraycopy,
|
||||
entry_oop_arraycopy,
|
||||
entry_jlong_arraycopy,
|
||||
entry_checkcast_arraycopy);
|
||||
// generic arraycopy may fallback on conjoint stubs
|
||||
StubRoutines::_generic_arraycopy = generate_generic_copy(StubRoutines::_jbyte_arraycopy_nopush,
|
||||
StubRoutines::_jshort_arraycopy_nopush,
|
||||
StubRoutines::_jint_arraycopy_nopush,
|
||||
StubRoutines::_oop_arraycopy_nopush,
|
||||
StubRoutines::_jlong_arraycopy_nopush,
|
||||
StubRoutines::_checkcast_arraycopy_nopush);
|
||||
|
||||
StubRoutines::_jbyte_fill = generate_fill(StubId::stubgen_jbyte_fill_id);
|
||||
StubRoutines::_jshort_fill = generate_fill(StubId::stubgen_jshort_fill_id);
|
||||
@ -3402,14 +3451,9 @@ class StubGenerator: public StubCodeGenerator {
|
||||
// counter = c_rarg7 - 16 bytes of CTR
|
||||
// return - number of processed bytes
|
||||
address generate_galoisCounterMode_AESCrypt() {
|
||||
address ghash_polynomial = __ pc();
|
||||
__ emit_int64(0x87); // The low-order bits of the field
|
||||
// polynomial (i.e. p = z^7+z^2+z+1)
|
||||
// repeated in the low and high parts of a
|
||||
// 128-bit vector
|
||||
__ emit_int64(0x87);
|
||||
Label ghash_polynomial; // local data generated after code
|
||||
|
||||
__ align(CodeEntryAlignment);
|
||||
__ align(CodeEntryAlignment);
|
||||
StubId stub_id = StubId::stubgen_galoisCounterMode_AESCrypt_id;
|
||||
StubCodeMark mark(this, stub_id);
|
||||
address start = __ pc();
|
||||
@ -3514,7 +3558,17 @@ class StubGenerator: public StubCodeGenerator {
|
||||
|
||||
__ leave(); // required for proper stackwalking of RuntimeStub frame
|
||||
__ ret(lr);
|
||||
return start;
|
||||
|
||||
// bind label and generate polynomial data
|
||||
__ align(wordSize * 2);
|
||||
__ bind(ghash_polynomial);
|
||||
__ emit_int64(0x87); // The low-order bits of the field
|
||||
// polynomial (i.e. p = z^7+z^2+z+1)
|
||||
// repeated in the low and high parts of a
|
||||
// 128-bit vector
|
||||
__ emit_int64(0x87);
|
||||
|
||||
return start;
|
||||
}
|
||||
|
||||
class Cached64Bytes {
|
||||
@ -4559,16 +4613,6 @@ class StubGenerator: public StubCodeGenerator {
|
||||
// by the second lane from all vectors and so on.
|
||||
address generate_chacha20Block_blockpar() {
|
||||
Label L_twoRounds, L_cc20_const;
|
||||
// The constant data is broken into two 128-bit segments to be loaded
|
||||
// onto FloatRegisters. The first 128 bits are a counter add overlay
|
||||
// that adds +0/+1/+2/+3 to the vector holding replicated state[12].
|
||||
// The second 128-bits is a table constant used for 8-bit left rotations.
|
||||
__ BIND(L_cc20_const);
|
||||
__ emit_int64(0x0000000100000000UL);
|
||||
__ emit_int64(0x0000000300000002UL);
|
||||
__ emit_int64(0x0605040702010003UL);
|
||||
__ emit_int64(0x0E0D0C0F0A09080BUL);
|
||||
|
||||
__ align(CodeEntryAlignment);
|
||||
StubId stub_id = StubId::stubgen_chacha20Block_id;
|
||||
StubCodeMark mark(this, stub_id);
|
||||
@ -4716,6 +4760,17 @@ class StubGenerator: public StubCodeGenerator {
|
||||
__ leave();
|
||||
__ ret(lr);
|
||||
|
||||
// bind label and generate local constant data used by this stub
|
||||
// The constant data is broken into two 128-bit segments to be loaded
|
||||
// onto FloatRegisters. The first 128 bits are a counter add overlay
|
||||
// that adds +0/+1/+2/+3 to the vector holding replicated state[12].
|
||||
// The second 128-bits is a table constant used for 8-bit left rotations.
|
||||
__ BIND(L_cc20_const);
|
||||
__ emit_int64(0x0000000100000000UL);
|
||||
__ emit_int64(0x0000000300000002UL);
|
||||
__ emit_int64(0x0605040702010003UL);
|
||||
__ emit_int64(0x0E0D0C0F0A09080BUL);
|
||||
|
||||
return start;
|
||||
}
|
||||
|
||||
@ -6036,10 +6091,6 @@ class StubGenerator: public StubCodeGenerator {
|
||||
address generate_kyber12To16() {
|
||||
Label L_F00, L_loop, L_end;
|
||||
|
||||
__ BIND(L_F00);
|
||||
__ emit_int64(0x0f000f000f000f00);
|
||||
__ emit_int64(0x0f000f000f000f00);
|
||||
|
||||
__ align(CodeEntryAlignment);
|
||||
StubId stub_id = StubId::stubgen_kyber12To16_id;
|
||||
StubCodeMark mark(this, stub_id);
|
||||
@ -6233,6 +6284,11 @@ class StubGenerator: public StubCodeGenerator {
|
||||
__ mov(r0, zr); // return 0
|
||||
__ ret(lr);
|
||||
|
||||
// bind label and generate constant data used by this stub
|
||||
__ BIND(L_F00);
|
||||
__ emit_int64(0x0f000f000f000f00);
|
||||
__ emit_int64(0x0f000f000f000f00);
|
||||
|
||||
return start;
|
||||
}
|
||||
|
||||
@ -9642,14 +9698,7 @@ class StubGenerator: public StubCodeGenerator {
|
||||
|
||||
StubId stub_id = StubId::stubgen_ghash_processBlocks_id;
|
||||
StubCodeMark mark(this, stub_id);
|
||||
__ align(wordSize * 2);
|
||||
address p = __ pc();
|
||||
__ emit_int64(0x87); // The low-order bits of the field
|
||||
// polynomial (i.e. p = z^7+z^2+z+1)
|
||||
// repeated in the low and high parts of a
|
||||
// 128-bit vector
|
||||
__ emit_int64(0x87);
|
||||
|
||||
Label polynomial; // local data generated at end of stub
|
||||
__ align(CodeEntryAlignment);
|
||||
address start = __ pc();
|
||||
|
||||
@ -9661,7 +9710,8 @@ class StubGenerator: public StubCodeGenerator {
|
||||
FloatRegister vzr = v30;
|
||||
__ eor(vzr, __ T16B, vzr, vzr); // zero register
|
||||
|
||||
__ ldrq(v24, p); // The field polynomial
|
||||
__ adr(rscratch1, polynomial);
|
||||
__ ldrq(v24, rscratch1); // The field polynomial
|
||||
|
||||
__ ldrq(v0, Address(state));
|
||||
__ ldrq(v1, Address(subkeyH));
|
||||
@ -9701,6 +9751,15 @@ class StubGenerator: public StubCodeGenerator {
|
||||
__ st1(v0, __ T16B, state);
|
||||
__ ret(lr);
|
||||
|
||||
// bind label and generate local polynomial data
|
||||
__ align(wordSize * 2);
|
||||
__ bind(polynomial);
|
||||
__ emit_int64(0x87); // The low-order bits of the field
|
||||
// polynomial (i.e. p = z^7+z^2+z+1)
|
||||
// repeated in the low and high parts of a
|
||||
// 128-bit vector
|
||||
__ emit_int64(0x87);
|
||||
|
||||
return start;
|
||||
}
|
||||
|
||||
@ -9709,14 +9768,7 @@ class StubGenerator: public StubCodeGenerator {
|
||||
|
||||
StubId stub_id = StubId::stubgen_ghash_processBlocks_wide_id;
|
||||
StubCodeMark mark(this, stub_id);
|
||||
__ align(wordSize * 2);
|
||||
address p = __ pc();
|
||||
__ emit_int64(0x87); // The low-order bits of the field
|
||||
// polynomial (i.e. p = z^7+z^2+z+1)
|
||||
// repeated in the low and high parts of a
|
||||
// 128-bit vector
|
||||
__ emit_int64(0x87);
|
||||
|
||||
Label polynomial; // local data generated after stub
|
||||
__ align(CodeEntryAlignment);
|
||||
address start = __ pc();
|
||||
|
||||
@ -9738,7 +9790,7 @@ class StubGenerator: public StubCodeGenerator {
|
||||
__ st1(v8, v9, v10, v11, __ T16B, Address(sp));
|
||||
}
|
||||
|
||||
__ ghash_processBlocks_wide(p, state, subkeyH, data, blocks, unroll);
|
||||
__ ghash_processBlocks_wide(polynomial, state, subkeyH, data, blocks, unroll);
|
||||
|
||||
if (unroll > 1) {
|
||||
// And restore state
|
||||
@ -9751,7 +9803,17 @@ class StubGenerator: public StubCodeGenerator {
|
||||
|
||||
__ ret(lr);
|
||||
|
||||
// bind label and generate polynomial data
|
||||
__ align(wordSize * 2);
|
||||
__ bind(polynomial);
|
||||
__ emit_int64(0x87); // The low-order bits of the field
|
||||
// polynomial (i.e. p = z^7+z^2+z+1)
|
||||
// repeated in the low and high parts of a
|
||||
// 128-bit vector
|
||||
__ emit_int64(0x87);
|
||||
|
||||
return start;
|
||||
|
||||
}
|
||||
|
||||
void generate_base64_encode_simdround(Register src, Register dst,
|
||||
|
||||
@ -200,9 +200,10 @@ void MonitorEnterStub::emit_code(LIR_Assembler* ce) {
|
||||
|
||||
void MonitorExitStub::emit_code(LIR_Assembler* ce) {
|
||||
__ bind(_entry);
|
||||
if (_compute_lock) {
|
||||
ce->monitor_address(_monitor_ix, _lock_reg);
|
||||
}
|
||||
|
||||
// lock_reg was destroyed by fast unlocking attempt => recompute it
|
||||
ce->monitor_address(_monitor_ix, _lock_reg);
|
||||
|
||||
const Register lock_reg = _lock_reg->as_pointer_register();
|
||||
|
||||
ce->verify_reserved_argument_area_size(1);
|
||||
|
||||
@ -245,7 +245,7 @@ int LIR_Assembler::emit_unwind_handler() {
|
||||
MonitorExitStub* stub = nullptr;
|
||||
if (method()->is_synchronized()) {
|
||||
monitor_address(0, FrameMap::R0_opr);
|
||||
stub = new MonitorExitStub(FrameMap::R0_opr, true, 0);
|
||||
stub = new MonitorExitStub(FrameMap::R0_opr, 0);
|
||||
__ unlock_object(R2, R1, R0, *stub->entry());
|
||||
__ bind(*stub->continuation());
|
||||
}
|
||||
@ -2427,7 +2427,6 @@ void LIR_Assembler::emit_lock(LIR_OpLock* op) {
|
||||
Register lock = op->lock_opr()->as_pointer_register();
|
||||
|
||||
if (op->code() == lir_lock) {
|
||||
assert(BasicLock::displaced_header_offset_in_bytes() == 0, "lock_reg must point to the displaced header");
|
||||
int null_check_offset = __ lock_object(hdr, obj, lock, *op->stub()->entry());
|
||||
if (op->info() != nullptr) {
|
||||
add_debug_info_for_null_check(null_check_offset, op->info());
|
||||
|
||||
@ -176,17 +176,17 @@ void C1_MacroAssembler::allocate_array(Register obj, Register len,
|
||||
initialize_object(obj, tmp1, klass, len, tmp2, tmp3, header_size_in_bytes, -1, /* is_tlab_allocated */ UseTLAB);
|
||||
}
|
||||
|
||||
int C1_MacroAssembler::lock_object(Register hdr, Register obj, Register disp_hdr, Label& slow_case) {
|
||||
int C1_MacroAssembler::lock_object(Register hdr, Register obj, Register basic_lock, Label& slow_case) {
|
||||
int null_check_offset = 0;
|
||||
|
||||
const Register tmp2 = Rtemp; // Rtemp should be free at c1 LIR level
|
||||
assert_different_registers(hdr, obj, disp_hdr, tmp2);
|
||||
assert_different_registers(hdr, obj, basic_lock, tmp2);
|
||||
|
||||
assert(BasicObjectLock::lock_offset() == 0, "adjust this code");
|
||||
assert(oopDesc::mark_offset_in_bytes() == 0, "Required by atomic instructions");
|
||||
|
||||
// save object being locked into the BasicObjectLock
|
||||
str(obj, Address(disp_hdr, BasicObjectLock::obj_offset()));
|
||||
str(obj, Address(basic_lock, BasicObjectLock::obj_offset()));
|
||||
|
||||
null_check_offset = offset();
|
||||
|
||||
@ -197,26 +197,26 @@ int C1_MacroAssembler::lock_object(Register hdr, Register obj, Register disp_hdr
|
||||
b(slow_case, ne);
|
||||
}
|
||||
|
||||
Register t1 = disp_hdr; // Needs saving, probably
|
||||
Register t2 = hdr; // blow
|
||||
Register t3 = Rtemp; // blow
|
||||
Register t1 = basic_lock; // Needs saving, probably
|
||||
Register t2 = hdr; // blow
|
||||
Register t3 = Rtemp; // blow
|
||||
|
||||
lightweight_lock(obj, t1, t2, t3, 1 /* savemask - save t1 */, slow_case);
|
||||
// Success: fall through
|
||||
return null_check_offset;
|
||||
}
|
||||
|
||||
void C1_MacroAssembler::unlock_object(Register hdr, Register obj, Register disp_hdr, Label& slow_case) {
|
||||
assert_different_registers(hdr, obj, disp_hdr, Rtemp);
|
||||
void C1_MacroAssembler::unlock_object(Register hdr, Register obj, Register basic_lock, Label& slow_case) {
|
||||
assert_different_registers(hdr, obj, basic_lock, Rtemp);
|
||||
|
||||
assert(BasicObjectLock::lock_offset() == 0, "adjust this code");
|
||||
assert(oopDesc::mark_offset_in_bytes() == 0, "Required by atomic instructions");
|
||||
|
||||
ldr(obj, Address(disp_hdr, BasicObjectLock::obj_offset()));
|
||||
ldr(obj, Address(basic_lock, BasicObjectLock::obj_offset()));
|
||||
|
||||
Register t1 = disp_hdr; // Needs saving, probably
|
||||
Register t2 = hdr; // blow
|
||||
Register t3 = Rtemp; // blow
|
||||
Register t1 = basic_lock; // Needs saving, probably
|
||||
Register t2 = hdr; // blow
|
||||
Register t3 = Rtemp; // blow
|
||||
|
||||
lightweight_unlock(obj, t1, t2, t3, 1 /* savemask - save t1 */, slow_case);
|
||||
// Success: fall through
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2008, 2023, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2008, 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
|
||||
@ -59,9 +59,9 @@
|
||||
max_array_allocation_length = 0x01000000
|
||||
};
|
||||
|
||||
int lock_object(Register hdr, Register obj, Register disp_hdr, Label& slow_case);
|
||||
int lock_object(Register hdr, Register obj, Register basic_lock, Label& slow_case);
|
||||
|
||||
void unlock_object(Register hdr, Register obj, Register disp_hdr, Label& slow_case);
|
||||
void unlock_object(Register hdr, Register obj, Register basic_lock, Label& slow_case);
|
||||
|
||||
// This platform only uses signal-based null checks. The Label is not needed.
|
||||
void null_check(Register r, Label *Lnull = nullptr) { MacroAssembler::null_check(r); }
|
||||
|
||||
@ -198,15 +198,18 @@ void G1BarrierSetAssembler::g1_write_barrier_pre(MacroAssembler* masm,
|
||||
__ bind(done);
|
||||
}
|
||||
|
||||
static void generate_post_barrier_fast_path(MacroAssembler* masm,
|
||||
const Register store_addr,
|
||||
const Register new_val,
|
||||
const Register tmp1,
|
||||
const Register tmp2,
|
||||
Label& done,
|
||||
bool new_val_may_be_null) {
|
||||
// Does store cross heap regions?
|
||||
static void generate_post_barrier(MacroAssembler* masm,
|
||||
const Register store_addr,
|
||||
const Register new_val,
|
||||
const Register thread,
|
||||
const Register tmp1,
|
||||
const Register tmp2,
|
||||
Label& done,
|
||||
bool new_val_may_be_null) {
|
||||
assert(thread == Rthread, "must be");
|
||||
assert_different_registers(store_addr, new_val, thread, tmp1, tmp2, noreg);
|
||||
|
||||
// Does store cross heap regions?
|
||||
__ eor(tmp1, store_addr, new_val);
|
||||
__ movs(tmp1, AsmOperand(tmp1, lsr, G1HeapRegion::LogOfHRGrainBytes));
|
||||
__ b(done, eq);
|
||||
@ -215,76 +218,34 @@ static void generate_post_barrier_fast_path(MacroAssembler* masm,
|
||||
if (new_val_may_be_null) {
|
||||
__ cbz(new_val, done);
|
||||
}
|
||||
// storing region crossing non-null, is card already dirty?
|
||||
const Register card_addr = tmp1;
|
||||
|
||||
CardTableBarrierSet* ct = barrier_set_cast<CardTableBarrierSet>(BarrierSet::barrier_set());
|
||||
__ mov_address(tmp2, (address)ct->card_table()->byte_map_base());
|
||||
__ add(card_addr, tmp2, AsmOperand(store_addr, lsr, CardTable::card_shift()));
|
||||
// storing region crossing non-null, is card already non-clean?
|
||||
Address card_table_addr(thread, in_bytes(G1ThreadLocalData::card_table_base_offset()));
|
||||
__ ldr(tmp2, card_table_addr);
|
||||
__ add(tmp1, tmp2, AsmOperand(store_addr, lsr, CardTable::card_shift()));
|
||||
|
||||
__ ldrb(tmp2, Address(card_addr));
|
||||
__ cmp(tmp2, (int)G1CardTable::g1_young_card_val());
|
||||
if (UseCondCardMark) {
|
||||
__ ldrb(tmp2, Address(tmp1));
|
||||
// Instead of loading clean_card_val and comparing, we exploit the fact that
|
||||
// the LSB of non-clean cards is always 0, and the LSB of clean cards 1.
|
||||
__ tbz(tmp2, 0, done);
|
||||
}
|
||||
|
||||
static_assert(G1CardTable::dirty_card_val() == 0, "must be to use zero_register()");
|
||||
__ zero_register(tmp2);
|
||||
__ strb(tmp2, Address(tmp1)); // *(card address) := dirty_card_val
|
||||
}
|
||||
|
||||
static void generate_post_barrier_slow_path(MacroAssembler* masm,
|
||||
const Register thread,
|
||||
const Register tmp1,
|
||||
const Register tmp2,
|
||||
const Register tmp3,
|
||||
Label& done,
|
||||
Label& runtime) {
|
||||
__ membar(MacroAssembler::Membar_mask_bits(MacroAssembler::StoreLoad), tmp2);
|
||||
assert(CardTable::dirty_card_val() == 0, "adjust this code");
|
||||
// card_addr is loaded by generate_post_barrier_fast_path
|
||||
const Register card_addr = tmp1;
|
||||
__ ldrb(tmp2, Address(card_addr));
|
||||
__ cbz(tmp2, done);
|
||||
|
||||
// storing a region crossing, non-null oop, card is clean.
|
||||
// dirty card and log.
|
||||
|
||||
__ strb(__ zero_register(tmp2), Address(card_addr));
|
||||
generate_queue_test_and_insertion(masm,
|
||||
G1ThreadLocalData::dirty_card_queue_index_offset(),
|
||||
G1ThreadLocalData::dirty_card_queue_buffer_offset(),
|
||||
runtime,
|
||||
thread, card_addr, tmp2, tmp3);
|
||||
__ b(done);
|
||||
}
|
||||
|
||||
|
||||
// G1 post-barrier.
|
||||
// Blows all volatile registers R0-R3, LR).
|
||||
void G1BarrierSetAssembler::g1_write_barrier_post(MacroAssembler* masm,
|
||||
Register store_addr,
|
||||
Register new_val,
|
||||
Register tmp1,
|
||||
Register tmp2,
|
||||
Register tmp3) {
|
||||
Register store_addr,
|
||||
Register new_val,
|
||||
Register tmp1,
|
||||
Register tmp2,
|
||||
Register tmp3) {
|
||||
Label done;
|
||||
Label runtime;
|
||||
|
||||
generate_post_barrier_fast_path(masm, store_addr, new_val, tmp1, tmp2, done, true /* new_val_may_be_null */);
|
||||
// If card is young, jump to done
|
||||
// card_addr and card are loaded by generate_post_barrier_fast_path
|
||||
const Register card = tmp2;
|
||||
const Register card_addr = tmp1;
|
||||
__ b(done, eq);
|
||||
generate_post_barrier_slow_path(masm, Rthread, card_addr, tmp2, tmp3, done, runtime);
|
||||
|
||||
__ bind(runtime);
|
||||
|
||||
RegisterSet set = RegisterSet(store_addr) | RegisterSet(R0, R3) | RegisterSet(R12);
|
||||
__ push(set);
|
||||
|
||||
if (card_addr != R0) {
|
||||
__ mov(R0, card_addr);
|
||||
}
|
||||
__ mov(R1, Rthread);
|
||||
__ call_VM_leaf(CAST_FROM_FN_PTR(address, G1BarrierSetRuntime::write_ref_field_post_entry), R0, R1);
|
||||
|
||||
__ pop(set);
|
||||
|
||||
generate_post_barrier(masm, store_addr, new_val, Rthread, tmp1, tmp2, done, true /* new_val_may_be_null */);
|
||||
__ bind(done);
|
||||
}
|
||||
|
||||
@ -344,35 +305,10 @@ void G1BarrierSetAssembler::g1_write_barrier_post_c2(MacroAssembler* masm,
|
||||
Register tmp1,
|
||||
Register tmp2,
|
||||
Register tmp3,
|
||||
G1PostBarrierStubC2* stub) {
|
||||
assert(thread == Rthread, "must be");
|
||||
assert_different_registers(store_addr, new_val, thread, tmp1, tmp2, noreg);
|
||||
|
||||
stub->initialize_registers(thread, tmp1, tmp2, tmp3);
|
||||
|
||||
bool new_val_may_be_null = (stub->barrier_data() & G1C2BarrierPostNotNull) == 0;
|
||||
generate_post_barrier_fast_path(masm, store_addr, new_val, tmp1, tmp2, *stub->continuation(), new_val_may_be_null);
|
||||
// If card is not young, jump to stub (slow path)
|
||||
__ b(*stub->entry(), ne);
|
||||
|
||||
__ bind(*stub->continuation());
|
||||
}
|
||||
|
||||
void G1BarrierSetAssembler::generate_c2_post_barrier_stub(MacroAssembler* masm,
|
||||
G1PostBarrierStubC2* stub) const {
|
||||
Assembler::InlineSkippedInstructionsCounter skip_counter(masm);
|
||||
Label runtime;
|
||||
Register thread = stub->thread();
|
||||
Register tmp1 = stub->tmp1(); // tmp1 holds the card address.
|
||||
Register tmp2 = stub->tmp2();
|
||||
Register tmp3 = stub->tmp3();
|
||||
|
||||
__ bind(*stub->entry());
|
||||
generate_post_barrier_slow_path(masm, thread, tmp1, tmp2, tmp3, *stub->continuation(), runtime);
|
||||
|
||||
__ bind(runtime);
|
||||
generate_c2_barrier_runtime_call(masm, stub, tmp1, CAST_FROM_FN_PTR(address, G1BarrierSetRuntime::write_ref_field_post_entry), tmp2);
|
||||
__ b(*stub->continuation());
|
||||
bool new_val_may_be_null) {
|
||||
Label done;
|
||||
generate_post_barrier(masm, store_addr, new_val, thread, tmp1, tmp2, done, new_val_may_be_null);
|
||||
__ bind(done);
|
||||
}
|
||||
|
||||
#endif // COMPILER2
|
||||
@ -463,20 +399,19 @@ void G1BarrierSetAssembler::gen_pre_barrier_stub(LIR_Assembler* ce, G1PreBarrier
|
||||
__ b(*stub->continuation());
|
||||
}
|
||||
|
||||
void G1BarrierSetAssembler::gen_post_barrier_stub(LIR_Assembler* ce, G1PostBarrierStub* stub) {
|
||||
G1BarrierSetC1* bs = (G1BarrierSetC1*)BarrierSet::barrier_set()->barrier_set_c1();
|
||||
__ bind(*stub->entry());
|
||||
assert(stub->addr()->is_register(), "Precondition.");
|
||||
assert(stub->new_val()->is_register(), "Precondition.");
|
||||
Register new_val_reg = stub->new_val()->as_register();
|
||||
__ cbz(new_val_reg, *stub->continuation());
|
||||
ce->verify_reserved_argument_area_size(1);
|
||||
__ str(stub->addr()->as_pointer_register(), Address(SP));
|
||||
__ call(bs->post_barrier_c1_runtime_code_blob()->code_begin(), relocInfo::runtime_call_type);
|
||||
__ b(*stub->continuation());
|
||||
#undef __
|
||||
|
||||
void G1BarrierSetAssembler::g1_write_barrier_post_c1(MacroAssembler* masm,
|
||||
Register store_addr,
|
||||
Register new_val,
|
||||
Register thread,
|
||||
Register tmp1,
|
||||
Register tmp2) {
|
||||
Label done;
|
||||
generate_post_barrier(masm, store_addr, new_val, thread, tmp1, tmp2, done, true /* new_val_may_be_null */);
|
||||
masm->bind(done);
|
||||
}
|
||||
|
||||
#undef __
|
||||
#define __ sasm->
|
||||
|
||||
void G1BarrierSetAssembler::generate_c1_pre_barrier_runtime_stub(StubAssembler* sasm) {
|
||||
@ -536,102 +471,6 @@ void G1BarrierSetAssembler::generate_c1_pre_barrier_runtime_stub(StubAssembler*
|
||||
__ b(done);
|
||||
}
|
||||
|
||||
void G1BarrierSetAssembler::generate_c1_post_barrier_runtime_stub(StubAssembler* sasm) {
|
||||
// Input:
|
||||
// - store_addr, pushed on the stack
|
||||
|
||||
__ set_info("g1_post_barrier_slow_id", false);
|
||||
|
||||
Label done;
|
||||
Label recheck;
|
||||
Label runtime;
|
||||
|
||||
Address queue_index(Rthread, in_bytes(G1ThreadLocalData::dirty_card_queue_index_offset()));
|
||||
Address buffer(Rthread, in_bytes(G1ThreadLocalData::dirty_card_queue_buffer_offset()));
|
||||
|
||||
AddressLiteral cardtable(ci_card_table_address_as<address>(), relocInfo::none);
|
||||
|
||||
// save at least the registers that need saving if the runtime is called
|
||||
const RegisterSet saved_regs = RegisterSet(R0,R3) | RegisterSet(R12) | RegisterSet(LR);
|
||||
const int nb_saved_regs = 6;
|
||||
assert(nb_saved_regs == saved_regs.size(), "fix nb_saved_regs");
|
||||
__ push(saved_regs);
|
||||
|
||||
const Register r_card_addr_0 = R0; // must be R0 for the slow case
|
||||
const Register r_obj_0 = R0;
|
||||
const Register r_card_base_1 = R1;
|
||||
const Register r_tmp2 = R2;
|
||||
const Register r_index_2 = R2;
|
||||
const Register r_buffer_3 = R3;
|
||||
const Register tmp1 = Rtemp;
|
||||
|
||||
__ ldr(r_obj_0, Address(SP, nb_saved_regs*wordSize));
|
||||
// Note: there is a comment in x86 code about not using
|
||||
// ExternalAddress / lea, due to relocation not working
|
||||
// properly for that address. Should be OK for arm, where we
|
||||
// explicitly specify that 'cardtable' has a relocInfo::none
|
||||
// type.
|
||||
__ lea(r_card_base_1, cardtable);
|
||||
__ add(r_card_addr_0, r_card_base_1, AsmOperand(r_obj_0, lsr, CardTable::card_shift()));
|
||||
|
||||
// first quick check without barrier
|
||||
__ ldrb(r_tmp2, Address(r_card_addr_0));
|
||||
|
||||
__ cmp(r_tmp2, (int)G1CardTable::g1_young_card_val());
|
||||
__ b(recheck, ne);
|
||||
|
||||
__ bind(done);
|
||||
|
||||
__ pop(saved_regs);
|
||||
|
||||
__ ret();
|
||||
|
||||
__ bind(recheck);
|
||||
|
||||
__ membar(MacroAssembler::Membar_mask_bits(MacroAssembler::StoreLoad), tmp1);
|
||||
|
||||
// reload card state after the barrier that ensures the stored oop was visible
|
||||
__ ldrb(r_tmp2, Address(r_card_addr_0));
|
||||
|
||||
assert(CardTable::dirty_card_val() == 0, "adjust this code");
|
||||
__ cbz(r_tmp2, done);
|
||||
|
||||
// storing region crossing non-null, card is clean.
|
||||
// dirty card and log.
|
||||
|
||||
assert(0 == (int)CardTable::dirty_card_val(), "adjust this code");
|
||||
if ((ci_card_table_address_as<intptr_t>() & 0xff) == 0) {
|
||||
// Card table is aligned so the lowest byte of the table address base is zero.
|
||||
__ strb(r_card_base_1, Address(r_card_addr_0));
|
||||
} else {
|
||||
__ strb(__ zero_register(r_tmp2), Address(r_card_addr_0));
|
||||
}
|
||||
|
||||
__ ldr(r_index_2, queue_index);
|
||||
__ ldr(r_buffer_3, buffer);
|
||||
|
||||
__ subs(r_index_2, r_index_2, wordSize);
|
||||
__ b(runtime, lt); // go to runtime if now negative
|
||||
|
||||
__ str(r_index_2, queue_index);
|
||||
|
||||
__ str(r_card_addr_0, Address(r_buffer_3, r_index_2));
|
||||
|
||||
__ b(done);
|
||||
|
||||
__ bind(runtime);
|
||||
|
||||
__ save_live_registers();
|
||||
|
||||
assert(r_card_addr_0 == c_rarg0, "card_addr should be in R0");
|
||||
__ mov(c_rarg1, Rthread);
|
||||
__ call_VM_leaf(CAST_FROM_FN_PTR(address, G1BarrierSetRuntime::write_ref_field_post_entry), c_rarg0, c_rarg1);
|
||||
|
||||
__ restore_live_registers_without_return();
|
||||
|
||||
__ b(done);
|
||||
}
|
||||
|
||||
#undef __
|
||||
|
||||
#endif // COMPILER1
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2018, 2024, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2018, 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
|
||||
@ -32,9 +32,7 @@
|
||||
class LIR_Assembler;
|
||||
class StubAssembler;
|
||||
class G1PreBarrierStub;
|
||||
class G1PostBarrierStub;
|
||||
class G1PreBarrierStubC2;
|
||||
class G1PostBarrierStubC2;
|
||||
|
||||
class G1BarrierSetAssembler: public ModRefBarrierSetAssembler {
|
||||
protected:
|
||||
@ -66,10 +64,15 @@ public:
|
||||
#ifdef COMPILER1
|
||||
public:
|
||||
void gen_pre_barrier_stub(LIR_Assembler* ce, G1PreBarrierStub* stub);
|
||||
void gen_post_barrier_stub(LIR_Assembler* ce, G1PostBarrierStub* stub);
|
||||
|
||||
void generate_c1_pre_barrier_runtime_stub(StubAssembler* sasm);
|
||||
void generate_c1_post_barrier_runtime_stub(StubAssembler* sasm);
|
||||
|
||||
void g1_write_barrier_post_c1(MacroAssembler* masm,
|
||||
Register store_addr,
|
||||
Register new_val,
|
||||
Register thread,
|
||||
Register tmp1,
|
||||
Register tmp2);
|
||||
#endif
|
||||
|
||||
#ifdef COMPILER2
|
||||
@ -89,9 +92,7 @@ public:
|
||||
Register tmp1,
|
||||
Register tmp2,
|
||||
Register tmp3,
|
||||
G1PostBarrierStubC2* c2_stub);
|
||||
void generate_c2_post_barrier_stub(MacroAssembler* masm,
|
||||
G1PostBarrierStubC2* stub) const;
|
||||
bool new_val_may_be_null);
|
||||
#endif
|
||||
|
||||
};
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
//
|
||||
// Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved.
|
||||
// Copyright (c) 2024, 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
|
||||
@ -63,13 +63,13 @@ static void write_barrier_post(MacroAssembler* masm,
|
||||
Register tmp1,
|
||||
Register tmp2,
|
||||
Register tmp3) {
|
||||
if (!G1PostBarrierStubC2::needs_barrier(node)) {
|
||||
if (!G1BarrierStubC2::needs_post_barrier(node)) {
|
||||
return;
|
||||
}
|
||||
Assembler::InlineSkippedInstructionsCounter skip_counter(masm);
|
||||
G1BarrierSetAssembler* g1_asm = static_cast<G1BarrierSetAssembler*>(BarrierSet::barrier_set()->barrier_set_assembler());
|
||||
G1PostBarrierStubC2* const stub = G1PostBarrierStubC2::create(node);
|
||||
g1_asm->g1_write_barrier_post_c2(masm, store_addr, new_val, Rthread, tmp1, tmp2, tmp3, stub);
|
||||
bool new_val_may_be_null = G1BarrierStubC2::post_new_val_may_be_null(node);
|
||||
g1_asm->g1_write_barrier_post_c2(masm, store_addr, new_val, Rthread, tmp1, tmp2, tmp3, new_val_may_be_null);
|
||||
}
|
||||
|
||||
%}
|
||||
|
||||
@ -617,11 +617,11 @@ void SharedRuntime::generate_i2c2i_adapters(MacroAssembler *masm,
|
||||
int comp_args_on_stack,
|
||||
const BasicType *sig_bt,
|
||||
const VMRegPair *regs,
|
||||
AdapterHandlerEntry* handler) {
|
||||
address i2c_entry = __ pc();
|
||||
address entry_address[AdapterBlob::ENTRY_COUNT]) {
|
||||
entry_address[AdapterBlob::I2C] = __ pc();
|
||||
gen_i2c_adapter(masm, total_args_passed, comp_args_on_stack, sig_bt, regs);
|
||||
|
||||
address c2i_unverified_entry = __ pc();
|
||||
entry_address[AdapterBlob::C2I_Unverified] = __ pc();
|
||||
Label skip_fixup;
|
||||
const Register receiver = R0;
|
||||
const Register holder_klass = Rtemp; // XXX should be OK for C2 but not 100% sure
|
||||
@ -634,10 +634,9 @@ void SharedRuntime::generate_i2c2i_adapters(MacroAssembler *masm,
|
||||
__ b(skip_fixup, eq);
|
||||
__ jump(SharedRuntime::get_ic_miss_stub(), relocInfo::runtime_call_type, noreg, ne);
|
||||
|
||||
address c2i_entry = __ pc();
|
||||
entry_address[AdapterBlob::C2I] = __ pc();
|
||||
entry_address[AdapterBlob::C2I_No_Clinit_Check] = nullptr;
|
||||
gen_c2i_adapter(masm, total_args_passed, comp_args_on_stack, sig_bt, regs, skip_fixup);
|
||||
|
||||
handler->set_entry_points(i2c_entry, c2i_entry, c2i_unverified_entry, nullptr);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -1129,7 +1128,7 @@ nmethod* SharedRuntime::generate_native_wrapper(MacroAssembler* masm,
|
||||
|
||||
const Register sync_handle = R5;
|
||||
const Register sync_obj = R6;
|
||||
const Register disp_hdr = altFP_7_11;
|
||||
const Register basic_lock = altFP_7_11;
|
||||
const Register tmp = R8;
|
||||
|
||||
Label slow_lock, lock_done, fast_lock;
|
||||
@ -1140,7 +1139,7 @@ nmethod* SharedRuntime::generate_native_wrapper(MacroAssembler* masm,
|
||||
__ mov(sync_handle, R1);
|
||||
|
||||
log_trace(fastlock)("SharedRuntime lock fast");
|
||||
__ lightweight_lock(sync_obj /* object */, disp_hdr /* t1 */, tmp /* t2 */, Rtemp /* t3 */,
|
||||
__ lightweight_lock(sync_obj /* object */, basic_lock /* t1 */, tmp /* t2 */, Rtemp /* t3 */,
|
||||
0x7 /* savemask */, slow_lock);
|
||||
// Fall through to lock_done
|
||||
__ bind(lock_done);
|
||||
@ -1255,7 +1254,7 @@ nmethod* SharedRuntime::generate_native_wrapper(MacroAssembler* masm,
|
||||
|
||||
// last_Java_frame is already set, so do call_VM manually; no exception can occur
|
||||
__ mov(R0, sync_obj);
|
||||
__ mov(R1, disp_hdr);
|
||||
__ mov(R1, basic_lock);
|
||||
__ mov(R2, Rthread);
|
||||
__ call(CAST_FROM_FN_PTR(address, SharedRuntime::complete_monitor_locking_C));
|
||||
|
||||
@ -1270,12 +1269,12 @@ nmethod* SharedRuntime::generate_native_wrapper(MacroAssembler* masm,
|
||||
|
||||
// Clear pending exception before reentering VM.
|
||||
// Can store the oop in register since it is a leaf call.
|
||||
assert_different_registers(Rtmp_save1, sync_obj, disp_hdr);
|
||||
assert_different_registers(Rtmp_save1, sync_obj, basic_lock);
|
||||
__ ldr(Rtmp_save1, Address(Rthread, Thread::pending_exception_offset()));
|
||||
Register zero = __ zero_register(Rtemp);
|
||||
__ str(zero, Address(Rthread, Thread::pending_exception_offset()));
|
||||
__ mov(R0, sync_obj);
|
||||
__ mov(R1, disp_hdr);
|
||||
__ mov(R1, basic_lock);
|
||||
__ mov(R2, Rthread);
|
||||
__ call(CAST_FROM_FN_PTR(address, SharedRuntime::complete_monitor_unlocking_C));
|
||||
__ str(Rtmp_save1, Address(Rthread, Thread::pending_exception_offset()));
|
||||
|
||||
@ -3011,6 +3011,10 @@ class StubGenerator: public StubCodeGenerator {
|
||||
// Note: the disjoint stubs must be generated first, some of
|
||||
// the conjoint stubs use them.
|
||||
|
||||
// Note: chaining of stubs does not rely on branching to an
|
||||
// auxiliary post-push entry because none of the stubs
|
||||
// push/pop a frame.
|
||||
|
||||
// these need always status in case they are called from generic_arraycopy
|
||||
StubRoutines::_jbyte_disjoint_arraycopy = generate_primitive_copy(StubId::stubgen_jbyte_disjoint_arraycopy_id);
|
||||
StubRoutines::_jshort_disjoint_arraycopy = generate_primitive_copy(StubId::stubgen_jshort_disjoint_arraycopy_id);
|
||||
@ -3024,6 +3028,7 @@ class StubGenerator: public StubCodeGenerator {
|
||||
StubRoutines::_arrayof_jlong_disjoint_arraycopy = generate_primitive_copy(StubId::stubgen_arrayof_jlong_disjoint_arraycopy_id);
|
||||
StubRoutines::_arrayof_oop_disjoint_arraycopy = generate_oop_copy (StubId::stubgen_arrayof_oop_disjoint_arraycopy_id);
|
||||
|
||||
// disjoint copy entry is needed by conjoint copy
|
||||
// these need always status in case they are called from generic_arraycopy
|
||||
StubRoutines::_jbyte_arraycopy = generate_primitive_copy(StubId::stubgen_jbyte_arraycopy_id, StubRoutines::_jbyte_disjoint_arraycopy);
|
||||
StubRoutines::_jshort_arraycopy = generate_primitive_copy(StubId::stubgen_jshort_arraycopy_id, StubRoutines::_jshort_disjoint_arraycopy);
|
||||
|
||||
@ -26,7 +26,7 @@
|
||||
#ifndef CPU_PPC_ASSEMBLER_PPC_INLINE_HPP
|
||||
#define CPU_PPC_ASSEMBLER_PPC_INLINE_HPP
|
||||
|
||||
#include "asm/assembler.inline.hpp"
|
||||
#include "asm/assembler.hpp"
|
||||
#include "asm/codeBuffer.hpp"
|
||||
#include "code/codeCache.hpp"
|
||||
#include "runtime/vm_version.hpp"
|
||||
|
||||
@ -268,9 +268,10 @@ void MonitorEnterStub::emit_code(LIR_Assembler* ce) {
|
||||
|
||||
void MonitorExitStub::emit_code(LIR_Assembler* ce) {
|
||||
__ bind(_entry);
|
||||
if (_compute_lock) {
|
||||
ce->monitor_address(_monitor_ix, _lock_reg);
|
||||
}
|
||||
|
||||
// lock_reg was destroyed by fast unlocking attempt => recompute it
|
||||
ce->monitor_address(_monitor_ix, _lock_reg);
|
||||
|
||||
address stub = Runtime1::entry_for(ce->compilation()->has_fpu_code() ? StubId::c1_monitorexit_id : StubId::c1_monitorexit_nofpu_id);
|
||||
//__ load_const_optimized(R0, stub);
|
||||
__ add_const_optimized(R0, R29_TOC, MacroAssembler::offset_to_global_toc(stub));
|
||||
|
||||
@ -227,7 +227,7 @@ int LIR_Assembler::emit_unwind_handler() {
|
||||
MonitorExitStub* stub = nullptr;
|
||||
if (method()->is_synchronized()) {
|
||||
monitor_address(0, FrameMap::R4_opr);
|
||||
stub = new MonitorExitStub(FrameMap::R4_opr, true, 0);
|
||||
stub = new MonitorExitStub(FrameMap::R4_opr, 0);
|
||||
__ unlock_object(R5, R6, R4, *stub->entry());
|
||||
__ bind(*stub->continuation());
|
||||
}
|
||||
@ -2614,7 +2614,6 @@ void LIR_Assembler::emit_lock(LIR_OpLock* op) {
|
||||
// Obj may not be an oop.
|
||||
if (op->code() == lir_lock) {
|
||||
MonitorEnterStub* stub = (MonitorEnterStub*)op->stub();
|
||||
assert(BasicLock::displaced_header_offset_in_bytes() == 0, "lock_reg must point to the displaced header");
|
||||
// Add debug info for NullPointerException only if one is possible.
|
||||
if (op->info() != nullptr) {
|
||||
if (!os::zero_page_read_protected() || !ImplicitNullChecks) {
|
||||
@ -2626,7 +2625,6 @@ void LIR_Assembler::emit_lock(LIR_OpLock* op) {
|
||||
__ lock_object(hdr, obj, lock, op->scratch_opr()->as_register(), *op->stub()->entry());
|
||||
} else {
|
||||
assert (op->code() == lir_unlock, "Invalid code, expected lir_unlock");
|
||||
assert(BasicLock::displaced_header_offset_in_bytes() == 0, "lock_reg must point to the displaced header");
|
||||
__ unlock_object(hdr, obj, lock, *op->stub()->entry());
|
||||
}
|
||||
__ bind(*op->stub()->continuation());
|
||||
|
||||
@ -28,7 +28,6 @@
|
||||
#include "gc/g1/g1BarrierSetAssembler.hpp"
|
||||
#include "gc/g1/g1BarrierSetRuntime.hpp"
|
||||
#include "gc/g1/g1CardTable.hpp"
|
||||
#include "gc/g1/g1DirtyCardQueue.hpp"
|
||||
#include "gc/g1/g1HeapRegion.hpp"
|
||||
#include "gc/g1/g1SATBMarkQueueSet.hpp"
|
||||
#include "gc/g1/g1ThreadLocalData.hpp"
|
||||
@ -230,78 +229,52 @@ void G1BarrierSetAssembler::g1_write_barrier_pre(MacroAssembler* masm, Decorator
|
||||
__ bind(filtered);
|
||||
}
|
||||
|
||||
static void generate_region_crossing_test(MacroAssembler* masm, const Register store_addr, const Register new_val) {
|
||||
__ xorr(R0, store_addr, new_val); // tmp1 := store address ^ new value
|
||||
__ srdi_(R0, R0, G1HeapRegion::LogOfHRGrainBytes); // tmp1 := ((store address ^ new value) >> LogOfHRGrainBytes)
|
||||
}
|
||||
static void generate_post_barrier(MacroAssembler* masm,
|
||||
const Register store_addr,
|
||||
const Register new_val,
|
||||
const Register thread,
|
||||
const Register tmp1,
|
||||
const Register tmp2,
|
||||
Label& done,
|
||||
bool new_val_may_be_null) {
|
||||
assert_different_registers(store_addr, new_val, tmp1, R0);
|
||||
assert_different_registers(store_addr, tmp1, tmp2, R0);
|
||||
|
||||
static Address generate_card_young_test(MacroAssembler* masm, const Register store_addr, const Register tmp1, const Register tmp2) {
|
||||
CardTableBarrierSet* ct = barrier_set_cast<CardTableBarrierSet>(BarrierSet::barrier_set());
|
||||
__ load_const_optimized(tmp1, (address)(ct->card_table()->byte_map_base()), tmp2);
|
||||
__ srdi(tmp2, store_addr, CardTable::card_shift()); // tmp1 := card address relative to card table base
|
||||
__ lbzx(R0, tmp1, tmp2); // tmp1 := card address
|
||||
__ cmpwi(CR0, R0, (int)G1CardTable::g1_young_card_val());
|
||||
return Address(tmp1, tmp2); // return card address
|
||||
}
|
||||
__ xorr(R0, store_addr, new_val); // R0 := store address ^ new value
|
||||
__ srdi_(R0, R0, G1HeapRegion::LogOfHRGrainBytes); // R0 := ((store address ^ new value) >> LogOfHRGrainBytes)
|
||||
__ beq(CR0, done);
|
||||
|
||||
static void generate_card_dirty_test(MacroAssembler* masm, Address card_addr) {
|
||||
__ membar(Assembler::StoreLoad); // Must reload after StoreLoad membar due to concurrent refinement
|
||||
__ lbzx(R0, card_addr.base(), card_addr.index()); // tmp2 := card
|
||||
__ cmpwi(CR0, R0, (int)G1CardTable::dirty_card_val()); // tmp2 := card == dirty_card_val?
|
||||
// Crosses regions, storing null?
|
||||
if (!new_val_may_be_null) {
|
||||
#ifdef ASSERT
|
||||
__ cmpdi(CR0, new_val, 0);
|
||||
__ asm_assert_ne("null oop not allowed (G1 post)"); // Checked by caller.
|
||||
#endif
|
||||
} else {
|
||||
__ cmpdi(CR0, new_val, 0);
|
||||
__ beq(CR0, done);
|
||||
}
|
||||
|
||||
__ ld(tmp1, G1ThreadLocalData::card_table_base_offset(), thread);
|
||||
__ srdi(tmp2, store_addr, CardTable::card_shift()); // tmp2 := card address relative to card table base
|
||||
if (UseCondCardMark) {
|
||||
__ lbzx(R0, tmp1, tmp2);
|
||||
__ cmpwi(CR0, R0, (int)G1CardTable::clean_card_val());
|
||||
__ bne(CR0, done);
|
||||
}
|
||||
|
||||
__ li(R0, G1CardTable::dirty_card_val());
|
||||
__ stbx(R0, tmp1, tmp2);
|
||||
}
|
||||
|
||||
void G1BarrierSetAssembler::g1_write_barrier_post(MacroAssembler* masm, DecoratorSet decorators,
|
||||
Register store_addr, Register new_val,
|
||||
Register tmp1, Register tmp2, Register tmp3,
|
||||
MacroAssembler::PreservationLevel preservation_level) {
|
||||
Register tmp1, Register tmp2) {
|
||||
bool not_null = (decorators & IS_NOT_NULL) != 0;
|
||||
|
||||
Label runtime, filtered;
|
||||
assert_different_registers(store_addr, new_val, tmp1, tmp2);
|
||||
|
||||
CardTableBarrierSet* ct = barrier_set_cast<CardTableBarrierSet>(BarrierSet::barrier_set());
|
||||
|
||||
generate_region_crossing_test(masm, store_addr, new_val);
|
||||
__ beq(CR0, filtered);
|
||||
|
||||
// Crosses regions, storing null?
|
||||
if (not_null) {
|
||||
#ifdef ASSERT
|
||||
__ cmpdi(CR0, new_val, 0);
|
||||
__ asm_assert_ne("null oop not allowed (G1 post)"); // Checked by caller.
|
||||
#endif
|
||||
} else {
|
||||
__ cmpdi(CR0, new_val, 0);
|
||||
__ beq(CR0, filtered);
|
||||
}
|
||||
|
||||
Address card_addr = generate_card_young_test(masm, store_addr, tmp1, tmp2);
|
||||
__ beq(CR0, filtered);
|
||||
|
||||
generate_card_dirty_test(masm, card_addr);
|
||||
__ beq(CR0, filtered);
|
||||
|
||||
__ li(R0, (int)G1CardTable::dirty_card_val());
|
||||
__ stbx(R0, card_addr.base(), card_addr.index()); // *(card address) := dirty_card_val
|
||||
|
||||
Register Rcard_addr = tmp3;
|
||||
__ add(Rcard_addr, card_addr.base(), card_addr.index()); // This is the address which needs to get enqueued.
|
||||
|
||||
generate_queue_insertion(masm,
|
||||
G1ThreadLocalData::dirty_card_queue_index_offset(),
|
||||
G1ThreadLocalData::dirty_card_queue_buffer_offset(),
|
||||
runtime, Rcard_addr, tmp1);
|
||||
__ b(filtered);
|
||||
|
||||
__ bind(runtime);
|
||||
|
||||
assert(preservation_level == MacroAssembler::PRESERVATION_NONE,
|
||||
"g1_write_barrier_post doesn't support preservation levels higher than PRESERVATION_NONE");
|
||||
|
||||
// Save the live input values.
|
||||
__ call_VM_leaf(CAST_FROM_FN_PTR(address, G1BarrierSetRuntime::write_ref_field_post_entry), Rcard_addr, R16_thread);
|
||||
|
||||
__ bind(filtered);
|
||||
Label done;
|
||||
generate_post_barrier(masm, store_addr, new_val, R16_thread, tmp1, tmp2, done, !not_null);
|
||||
__ bind(done);
|
||||
}
|
||||
|
||||
void G1BarrierSetAssembler::oop_store_at(MacroAssembler* masm, DecoratorSet decorators, BasicType type,
|
||||
@ -333,8 +306,7 @@ void G1BarrierSetAssembler::oop_store_at(MacroAssembler* masm, DecoratorSet deco
|
||||
}
|
||||
g1_write_barrier_post(masm, decorators,
|
||||
base, val,
|
||||
tmp1, tmp2, tmp3,
|
||||
preservation_level);
|
||||
tmp1, tmp2);
|
||||
}
|
||||
}
|
||||
|
||||
@ -457,70 +429,29 @@ void G1BarrierSetAssembler::g1_write_barrier_post_c2(MacroAssembler* masm,
|
||||
Register new_val,
|
||||
Register tmp1,
|
||||
Register tmp2,
|
||||
G1PostBarrierStubC2* stub,
|
||||
bool new_val_may_be_null,
|
||||
bool decode_new_val) {
|
||||
assert_different_registers(store_addr, new_val, tmp1, R0);
|
||||
assert_different_registers(store_addr, tmp1, tmp2, R0);
|
||||
|
||||
stub->initialize_registers(R16_thread, tmp1, tmp2);
|
||||
Label done;
|
||||
|
||||
bool null_check_required = (stub->barrier_data() & G1C2BarrierPostNotNull) == 0;
|
||||
Register new_val_decoded = new_val;
|
||||
|
||||
if (decode_new_val) {
|
||||
assert(UseCompressedOops, "or should not be here");
|
||||
if (null_check_required && CompressedOops::base() != nullptr) {
|
||||
if (new_val_may_be_null && CompressedOops::base() != nullptr) {
|
||||
// We prefer doing the null check after the region crossing check.
|
||||
// Only compressed oop modes with base != null require a null check here.
|
||||
__ cmpwi(CR0, new_val, 0);
|
||||
__ beq(CR0, *stub->continuation());
|
||||
null_check_required = false;
|
||||
__ beq(CR0, done);
|
||||
new_val_may_be_null = false;
|
||||
}
|
||||
new_val_decoded = __ decode_heap_oop_not_null(tmp2, new_val);
|
||||
}
|
||||
|
||||
generate_region_crossing_test(masm, store_addr, new_val_decoded);
|
||||
__ beq(CR0, *stub->continuation());
|
||||
|
||||
// crosses regions, storing null?
|
||||
if (null_check_required) {
|
||||
__ cmpdi(CR0, new_val_decoded, 0);
|
||||
__ beq(CR0, *stub->continuation());
|
||||
}
|
||||
|
||||
Address card_addr = generate_card_young_test(masm, store_addr, tmp1, tmp2);
|
||||
assert(card_addr.base() == tmp1 && card_addr.index() == tmp2, "needed by post barrier stub");
|
||||
__ bc_far_optimized(Assembler::bcondCRbiIs0, __ bi0(CR0, Assembler::equal), *stub->entry());
|
||||
|
||||
__ bind(*stub->continuation());
|
||||
}
|
||||
|
||||
void G1BarrierSetAssembler::generate_c2_post_barrier_stub(MacroAssembler* masm,
|
||||
G1PostBarrierStubC2* stub) const {
|
||||
Assembler::InlineSkippedInstructionsCounter skip_counter(masm);
|
||||
Label runtime;
|
||||
Address card_addr(stub->tmp1(), stub->tmp2()); // See above.
|
||||
|
||||
__ bind(*stub->entry());
|
||||
|
||||
generate_card_dirty_test(masm, card_addr);
|
||||
__ bc_far_optimized(Assembler::bcondCRbiIs1, __ bi0(CR0, Assembler::equal), *stub->continuation());
|
||||
|
||||
__ li(R0, (int)G1CardTable::dirty_card_val());
|
||||
__ stbx(R0, card_addr.base(), card_addr.index()); // *(card address) := dirty_card_val
|
||||
|
||||
Register Rcard_addr = stub->tmp1();
|
||||
__ add(Rcard_addr, card_addr.base(), card_addr.index()); // This is the address which needs to get enqueued.
|
||||
|
||||
generate_queue_insertion(masm,
|
||||
G1ThreadLocalData::dirty_card_queue_index_offset(),
|
||||
G1ThreadLocalData::dirty_card_queue_buffer_offset(),
|
||||
runtime, Rcard_addr, stub->tmp2());
|
||||
__ b(*stub->continuation());
|
||||
|
||||
__ bind(runtime);
|
||||
generate_c2_barrier_runtime_call(masm, stub, Rcard_addr, CAST_FROM_FN_PTR(address, G1BarrierSetRuntime::write_ref_field_post_entry));
|
||||
__ b(*stub->continuation());
|
||||
generate_post_barrier(masm, store_addr, new_val_decoded, R16_thread, tmp1, tmp2, done, new_val_may_be_null);
|
||||
__ bind(done);
|
||||
}
|
||||
|
||||
#endif // COMPILER2
|
||||
@ -558,28 +489,19 @@ void G1BarrierSetAssembler::gen_pre_barrier_stub(LIR_Assembler* ce, G1PreBarrier
|
||||
__ b(*stub->continuation());
|
||||
}
|
||||
|
||||
void G1BarrierSetAssembler::gen_post_barrier_stub(LIR_Assembler* ce, G1PostBarrierStub* stub) {
|
||||
G1BarrierSetC1* bs = (G1BarrierSetC1*)BarrierSet::barrier_set()->barrier_set_c1();
|
||||
__ bind(*stub->entry());
|
||||
#undef __
|
||||
|
||||
assert(stub->addr()->is_register(), "Precondition.");
|
||||
assert(stub->new_val()->is_register(), "Precondition.");
|
||||
Register addr_reg = stub->addr()->as_pointer_register();
|
||||
Register new_val_reg = stub->new_val()->as_register();
|
||||
|
||||
__ cmpdi(CR0, new_val_reg, 0);
|
||||
__ bc_far_optimized(Assembler::bcondCRbiIs1, __ bi0(CR0, Assembler::equal), *stub->continuation());
|
||||
|
||||
address c_code = bs->post_barrier_c1_runtime_code_blob()->code_begin();
|
||||
//__ load_const_optimized(R0, c_code);
|
||||
__ add_const_optimized(R0, R29_TOC, MacroAssembler::offset_to_global_toc(c_code));
|
||||
__ mtctr(R0);
|
||||
__ mr(R0, addr_reg); // Pass addr in R0.
|
||||
__ bctrl();
|
||||
__ b(*stub->continuation());
|
||||
void G1BarrierSetAssembler::g1_write_barrier_post_c1(MacroAssembler* masm,
|
||||
Register store_addr,
|
||||
Register new_val,
|
||||
Register thread,
|
||||
Register tmp1,
|
||||
Register tmp2) {
|
||||
Label done;
|
||||
generate_post_barrier(masm, store_addr, new_val, thread, tmp1, tmp2, done, true /* new_val_may_be_null */);
|
||||
masm->bind(done);
|
||||
}
|
||||
|
||||
#undef __
|
||||
#define __ sasm->
|
||||
|
||||
void G1BarrierSetAssembler::generate_c1_pre_barrier_runtime_stub(StubAssembler* sasm) {
|
||||
@ -642,86 +564,6 @@ void G1BarrierSetAssembler::generate_c1_pre_barrier_runtime_stub(StubAssembler*
|
||||
__ b(restart);
|
||||
}
|
||||
|
||||
void G1BarrierSetAssembler::generate_c1_post_barrier_runtime_stub(StubAssembler* sasm) {
|
||||
G1BarrierSet* bs = barrier_set_cast<G1BarrierSet>(BarrierSet::barrier_set());
|
||||
|
||||
__ set_info("g1_post_barrier_slow_id", false);
|
||||
|
||||
// Using stack slots: spill addr, spill tmp2
|
||||
const int stack_slots = 2;
|
||||
Register tmp = R0;
|
||||
Register addr = R14;
|
||||
Register tmp2 = R15;
|
||||
CardTable::CardValue* byte_map_base = bs->card_table()->byte_map_base();
|
||||
|
||||
Label restart, refill, ret;
|
||||
|
||||
// Spill
|
||||
__ std(addr, -8, R1_SP);
|
||||
__ std(tmp2, -16, R1_SP);
|
||||
|
||||
__ srdi(addr, R0, CardTable::card_shift()); // Addr is passed in R0.
|
||||
__ load_const_optimized(/*cardtable*/ tmp2, byte_map_base, tmp);
|
||||
__ add(addr, tmp2, addr);
|
||||
__ lbz(tmp, 0, addr); // tmp := [addr + cardtable]
|
||||
|
||||
// Return if young card.
|
||||
__ cmpwi(CR0, tmp, G1CardTable::g1_young_card_val());
|
||||
__ beq(CR0, ret);
|
||||
|
||||
// Return if sequential consistent value is already dirty.
|
||||
__ membar(Assembler::StoreLoad);
|
||||
__ lbz(tmp, 0, addr); // tmp := [addr + cardtable]
|
||||
|
||||
__ cmpwi(CR0, tmp, G1CardTable::dirty_card_val());
|
||||
__ beq(CR0, ret);
|
||||
|
||||
// Not dirty.
|
||||
|
||||
// First, dirty it.
|
||||
__ li(tmp, G1CardTable::dirty_card_val());
|
||||
__ stb(tmp, 0, addr);
|
||||
|
||||
int dirty_card_q_index_byte_offset = in_bytes(G1ThreadLocalData::dirty_card_queue_index_offset());
|
||||
int dirty_card_q_buf_byte_offset = in_bytes(G1ThreadLocalData::dirty_card_queue_buffer_offset());
|
||||
|
||||
__ bind(restart);
|
||||
|
||||
// Get the index into the update buffer. G1DirtyCardQueue::_index is
|
||||
// a size_t so ld_ptr is appropriate here.
|
||||
__ ld(tmp2, dirty_card_q_index_byte_offset, R16_thread);
|
||||
|
||||
// index == 0?
|
||||
__ cmpdi(CR0, tmp2, 0);
|
||||
__ beq(CR0, refill);
|
||||
|
||||
__ ld(tmp, dirty_card_q_buf_byte_offset, R16_thread);
|
||||
__ addi(tmp2, tmp2, -oopSize);
|
||||
|
||||
__ std(tmp2, dirty_card_q_index_byte_offset, R16_thread);
|
||||
__ add(tmp2, tmp, tmp2);
|
||||
__ std(addr, 0, tmp2); // [_buf + index] := <address_of_card>
|
||||
|
||||
// Restore temp registers and return-from-leaf.
|
||||
__ bind(ret);
|
||||
__ ld(tmp2, -16, R1_SP);
|
||||
__ ld(addr, -8, R1_SP);
|
||||
__ blr();
|
||||
|
||||
__ bind(refill);
|
||||
const int nbytes_save = (MacroAssembler::num_volatile_regs + stack_slots) * BytesPerWord;
|
||||
__ save_volatile_gprs(R1_SP, -nbytes_save); // except R0
|
||||
__ mflr(R0);
|
||||
__ std(R0, _abi0(lr), R1_SP);
|
||||
__ push_frame_reg_args(nbytes_save, R0); // dummy frame for C call
|
||||
__ call_VM_leaf(CAST_FROM_FN_PTR(address, G1DirtyCardQueueSet::handle_zero_index_for_thread), R16_thread);
|
||||
__ pop_frame();
|
||||
__ ld(R0, _abi0(lr), R1_SP);
|
||||
__ mtlr(R0);
|
||||
__ restore_volatile_gprs(R1_SP, -nbytes_save); // except R0
|
||||
__ b(restart);
|
||||
}
|
||||
|
||||
#undef __
|
||||
|
||||
#endif // COMPILER1
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2018, 2024, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2018, 2025, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2018, 2021 SAP SE. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
@ -37,9 +37,7 @@
|
||||
class LIR_Assembler;
|
||||
class StubAssembler;
|
||||
class G1PreBarrierStub;
|
||||
class G1PostBarrierStub;
|
||||
class G1PreBarrierStubC2;
|
||||
class G1PostBarrierStubC2;
|
||||
|
||||
class G1BarrierSetAssembler: public ModRefBarrierSetAssembler {
|
||||
protected:
|
||||
@ -56,8 +54,7 @@ protected:
|
||||
MacroAssembler::PreservationLevel preservation_level);
|
||||
void g1_write_barrier_post(MacroAssembler* masm, DecoratorSet decorators,
|
||||
Register store_addr, Register new_val,
|
||||
Register tmp1, Register tmp2, Register tmp3,
|
||||
MacroAssembler::PreservationLevel preservation_level);
|
||||
Register tmp1, Register tmp2);
|
||||
|
||||
virtual void oop_store_at(MacroAssembler* masm, DecoratorSet decorators, BasicType type,
|
||||
Register base, RegisterOrConstant ind_or_offs, Register val,
|
||||
@ -79,17 +76,21 @@ public:
|
||||
Register new_val,
|
||||
Register tmp1,
|
||||
Register tmp2,
|
||||
G1PostBarrierStubC2* c2_stub,
|
||||
bool new_val_may_be_null,
|
||||
bool decode_new_val);
|
||||
void generate_c2_post_barrier_stub(MacroAssembler* masm,
|
||||
G1PostBarrierStubC2* stub) const;
|
||||
#endif
|
||||
#ifdef COMPILER1
|
||||
void gen_pre_barrier_stub(LIR_Assembler* ce, G1PreBarrierStub* stub);
|
||||
void gen_post_barrier_stub(LIR_Assembler* ce, G1PostBarrierStub* stub);
|
||||
|
||||
void generate_c1_pre_barrier_runtime_stub(StubAssembler* sasm);
|
||||
void generate_c1_post_barrier_runtime_stub(StubAssembler* sasm);
|
||||
|
||||
void g1_write_barrier_post_c1(MacroAssembler* masm,
|
||||
Register store_addr,
|
||||
Register new_val,
|
||||
Register thread,
|
||||
Register tmp1,
|
||||
Register tmp2);
|
||||
|
||||
#endif
|
||||
|
||||
virtual void load_at(MacroAssembler* masm, DecoratorSet decorators, BasicType type,
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
//
|
||||
// Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved.
|
||||
// Copyright (c) 2024, 2025, Oracle and/or its affiliates. All rights reserved.
|
||||
// Copyright (c) 2025 SAP SE. All rights reserved.
|
||||
// DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
//
|
||||
@ -64,13 +64,13 @@ static void post_write_barrier(MacroAssembler* masm,
|
||||
Register tmp1,
|
||||
Register tmp2,
|
||||
bool decode_new_val = false) {
|
||||
if (!G1PostBarrierStubC2::needs_barrier(node)) {
|
||||
if (!G1BarrierStubC2::needs_post_barrier(node)) {
|
||||
return;
|
||||
}
|
||||
Assembler::InlineSkippedInstructionsCounter skip_counter(masm);
|
||||
G1BarrierSetAssembler* g1_asm = static_cast<G1BarrierSetAssembler*>(BarrierSet::barrier_set()->barrier_set_assembler());
|
||||
G1PostBarrierStubC2* const stub = G1PostBarrierStubC2::create(node);
|
||||
g1_asm->g1_write_barrier_post_c2(masm, store_addr, new_val, tmp1, tmp2, stub, decode_new_val);
|
||||
bool new_val_may_be_null = G1BarrierStubC2::post_new_val_may_be_null(node);
|
||||
g1_asm->g1_write_barrier_post_c2(masm, store_addr, new_val, tmp1, tmp2, new_val_may_be_null, decode_new_val);
|
||||
}
|
||||
|
||||
%}
|
||||
|
||||
@ -114,7 +114,6 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
void ZBarrierSetAssembler::load_at(MacroAssembler* masm, DecoratorSet decorators, BasicType type,
|
||||
Register base, RegisterOrConstant ind_or_offs, Register dst,
|
||||
Register tmp1, Register tmp2,
|
||||
@ -561,7 +560,6 @@ void ZBarrierSetAssembler::generate_conjoint_oop_copy(MacroAssembler* masm, bool
|
||||
copy_store_at_slow(masm, R4_ARG2, tmp, store_bad, store_good, dest_uninitialized);
|
||||
}
|
||||
|
||||
|
||||
// Verify a colored pointer.
|
||||
void ZBarrierSetAssembler::check_oop(MacroAssembler *masm, Register obj, const char* msg) {
|
||||
if (!VerifyOops) {
|
||||
@ -583,7 +581,6 @@ void ZBarrierSetAssembler::check_oop(MacroAssembler *masm, Register obj, const c
|
||||
__ bind(done);
|
||||
}
|
||||
|
||||
|
||||
void ZBarrierSetAssembler::try_resolve_jobject_in_native(MacroAssembler* masm, Register dst, Register jni_env,
|
||||
Register obj, Register tmp, Label& slowpath) {
|
||||
__ block_comment("try_resolve_jobject_in_native (zgc) {");
|
||||
|
||||
@ -1199,16 +1199,11 @@ void SharedRuntime::generate_i2c2i_adapters(MacroAssembler *masm,
|
||||
int comp_args_on_stack,
|
||||
const BasicType *sig_bt,
|
||||
const VMRegPair *regs,
|
||||
AdapterHandlerEntry* handler) {
|
||||
address i2c_entry;
|
||||
address c2i_unverified_entry;
|
||||
address c2i_entry;
|
||||
|
||||
|
||||
address entry_address[AdapterBlob::ENTRY_COUNT]) {
|
||||
// entry: i2c
|
||||
|
||||
__ align(CodeEntryAlignment);
|
||||
i2c_entry = __ pc();
|
||||
entry_address[AdapterBlob::I2C] = __ pc();
|
||||
gen_i2c_adapter(masm, total_args_passed, comp_args_on_stack, sig_bt, regs);
|
||||
|
||||
|
||||
@ -1216,7 +1211,7 @@ void SharedRuntime::generate_i2c2i_adapters(MacroAssembler *masm,
|
||||
|
||||
__ align(CodeEntryAlignment);
|
||||
BLOCK_COMMENT("c2i unverified entry");
|
||||
c2i_unverified_entry = __ pc();
|
||||
entry_address[AdapterBlob::C2I_Unverified] = __ pc();
|
||||
|
||||
// inline_cache contains a CompiledICData
|
||||
const Register ic = R19_inline_cache_reg;
|
||||
@ -1244,10 +1239,10 @@ void SharedRuntime::generate_i2c2i_adapters(MacroAssembler *masm,
|
||||
|
||||
// entry: c2i
|
||||
|
||||
c2i_entry = __ pc();
|
||||
entry_address[AdapterBlob::C2I] = __ pc();
|
||||
|
||||
// Class initialization barrier for static methods
|
||||
address c2i_no_clinit_check_entry = nullptr;
|
||||
entry_address[AdapterBlob::C2I_No_Clinit_Check] = nullptr;
|
||||
if (VM_Version::supports_fast_class_init_checks()) {
|
||||
Label L_skip_barrier;
|
||||
|
||||
@ -1266,15 +1261,13 @@ void SharedRuntime::generate_i2c2i_adapters(MacroAssembler *masm,
|
||||
__ bctr();
|
||||
|
||||
__ bind(L_skip_barrier);
|
||||
c2i_no_clinit_check_entry = __ pc();
|
||||
entry_address[AdapterBlob::C2I_No_Clinit_Check] = __ pc();
|
||||
}
|
||||
|
||||
BarrierSetAssembler* bs = BarrierSet::barrier_set()->barrier_set_assembler();
|
||||
bs->c2i_entry_barrier(masm, /* tmp register*/ ic_klass, /* tmp register*/ receiver_klass, /* tmp register*/ code);
|
||||
|
||||
gen_c2i_adapter(masm, total_args_passed, comp_args_on_stack, sig_bt, regs, call_interpreter, ientry);
|
||||
|
||||
handler->set_entry_points(i2c_entry, c2i_entry, c2i_unverified_entry, c2i_no_clinit_check_entry);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@ -3277,8 +3277,12 @@ class StubGenerator: public StubCodeGenerator {
|
||||
// register the stub as the default exit with class UnsafeMemoryAccess
|
||||
UnsafeMemoryAccess::set_common_exit_stub_pc(StubRoutines::_unsafecopy_common_exit);
|
||||
|
||||
// Note: the disjoint stubs must be generated first, some of
|
||||
// the conjoint stubs use them.
|
||||
// Note: the disjoint stubs must be generated first, some of the
|
||||
// conjoint stubs use them.
|
||||
|
||||
// Note: chaining of stubs does not rely on branching to an
|
||||
// auxiliary post-push entry because none of the stubs
|
||||
// push/pop a frame.
|
||||
|
||||
// non-aligned disjoint versions
|
||||
StubRoutines::_jbyte_disjoint_arraycopy = generate_disjoint_byte_copy(StubId::stubgen_jbyte_disjoint_arraycopy_id);
|
||||
|
||||
@ -27,7 +27,7 @@
|
||||
#ifndef CPU_RISCV_ASSEMBLER_RISCV_INLINE_HPP
|
||||
#define CPU_RISCV_ASSEMBLER_RISCV_INLINE_HPP
|
||||
|
||||
#include "asm/assembler.inline.hpp"
|
||||
#include "asm/assembler.hpp"
|
||||
#include "asm/codeBuffer.hpp"
|
||||
#include "code/codeCache.hpp"
|
||||
|
||||
|
||||
@ -204,10 +204,10 @@ void MonitorEnterStub::emit_code(LIR_Assembler* ce) {
|
||||
|
||||
void MonitorExitStub::emit_code(LIR_Assembler* ce) {
|
||||
__ bind(_entry);
|
||||
if (_compute_lock) {
|
||||
// lock_reg was destroyed by fast unlocking attempt => recompute it
|
||||
ce->monitor_address(_monitor_ix, _lock_reg);
|
||||
}
|
||||
|
||||
// lock_reg was destroyed by fast unlocking attempt => recompute it
|
||||
ce->monitor_address(_monitor_ix, _lock_reg);
|
||||
|
||||
ce->store_parameter(_lock_reg->as_register(), 0);
|
||||
// note: non-blocking leaf routine => no call info needed
|
||||
StubId exit_id;
|
||||
|
||||
@ -338,7 +338,7 @@ int LIR_Assembler::emit_unwind_handler() {
|
||||
MonitorExitStub* stub = nullptr;
|
||||
if (method()->is_synchronized()) {
|
||||
monitor_address(0, FrameMap::r10_opr);
|
||||
stub = new MonitorExitStub(FrameMap::r10_opr, true, 0);
|
||||
stub = new MonitorExitStub(FrameMap::r10_opr, 0);
|
||||
__ unlock_object(x15, x14, x10, x16, *stub->entry());
|
||||
__ bind(*stub->continuation());
|
||||
}
|
||||
@ -1494,14 +1494,12 @@ void LIR_Assembler::emit_lock(LIR_OpLock* op) {
|
||||
Register lock = op->lock_opr()->as_register();
|
||||
Register temp = op->scratch_opr()->as_register();
|
||||
if (op->code() == lir_lock) {
|
||||
assert(BasicLock::displaced_header_offset_in_bytes() == 0, "lock_reg must point to the displaced header");
|
||||
// add debug info for NullPointerException only if one is possible
|
||||
int null_check_offset = __ lock_object(hdr, obj, lock, temp, *op->stub()->entry());
|
||||
if (op->info() != nullptr) {
|
||||
add_debug_info_for_null_check(null_check_offset, op->info());
|
||||
}
|
||||
} else if (op->code() == lir_unlock) {
|
||||
assert(BasicLock::displaced_header_offset_in_bytes() == 0, "lock_reg must point to the displaced header");
|
||||
__ unlock_object(hdr, obj, lock, temp, *op->stub()->entry());
|
||||
} else {
|
||||
Unimplemented();
|
||||
|
||||
@ -48,27 +48,27 @@ void C1_MacroAssembler::float_cmp(bool is_float, int unordered_result,
|
||||
}
|
||||
}
|
||||
|
||||
int C1_MacroAssembler::lock_object(Register hdr, Register obj, Register disp_hdr, Register temp, Label& slow_case) {
|
||||
assert_different_registers(hdr, obj, disp_hdr, temp, t0, t1);
|
||||
int C1_MacroAssembler::lock_object(Register hdr, Register obj, Register basic_lock, Register temp, Label& slow_case) {
|
||||
assert_different_registers(hdr, obj, basic_lock, temp, t0, t1);
|
||||
int null_check_offset = -1;
|
||||
|
||||
verify_oop(obj);
|
||||
|
||||
// save object being locked into the BasicObjectLock
|
||||
sd(obj, Address(disp_hdr, BasicObjectLock::obj_offset()));
|
||||
sd(obj, Address(basic_lock, BasicObjectLock::obj_offset()));
|
||||
|
||||
null_check_offset = offset();
|
||||
|
||||
lightweight_lock(disp_hdr, obj, hdr, temp, t1, slow_case);
|
||||
lightweight_lock(basic_lock, obj, hdr, temp, t1, slow_case);
|
||||
|
||||
return null_check_offset;
|
||||
}
|
||||
|
||||
void C1_MacroAssembler::unlock_object(Register hdr, Register obj, Register disp_hdr, Register temp, Label& slow_case) {
|
||||
assert_different_registers(hdr, obj, disp_hdr, temp, t0, t1);
|
||||
void C1_MacroAssembler::unlock_object(Register hdr, Register obj, Register basic_lock, Register temp, Label& slow_case) {
|
||||
assert_different_registers(hdr, obj, basic_lock, temp, t0, t1);
|
||||
|
||||
// load object
|
||||
ld(obj, Address(disp_hdr, BasicObjectLock::obj_offset()));
|
||||
ld(obj, Address(basic_lock, BasicObjectLock::obj_offset()));
|
||||
verify_oop(obj);
|
||||
|
||||
lightweight_unlock(obj, hdr, temp, t1, slow_case);
|
||||
|
||||
@ -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.
|
||||
* Copyright (c) 2014, 2015, Red Hat Inc. All rights reserved.
|
||||
* Copyright (c) 2020, 2022, Huawei Technologies Co., Ltd. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
@ -56,19 +56,19 @@ using MacroAssembler::null_check;
|
||||
Register result);
|
||||
|
||||
// locking
|
||||
// hdr : must be x10, contents destroyed
|
||||
// obj : must point to the object to lock, contents preserved
|
||||
// disp_hdr: must point to the displaced header location, contents preserved
|
||||
// temp : temporary register, must not be scratch register t0 or t1
|
||||
// hdr : must be x10, contents destroyed
|
||||
// obj : must point to the object to lock, contents preserved
|
||||
// basic_lock: must point to the basic_lock, contents preserved
|
||||
// temp : temporary register, must not be scratch register t0 or t1
|
||||
// returns code offset at which to add null check debug information
|
||||
int lock_object(Register swap, Register obj, Register disp_hdr, Register temp, Label& slow_case);
|
||||
int lock_object(Register swap, Register obj, Register basic_lock, Register temp, Label& slow_case);
|
||||
|
||||
// unlocking
|
||||
// hdr : contents destroyed
|
||||
// obj : must point to the object to lock, contents preserved
|
||||
// disp_hdr: must be x10 & must point to the displaced header location, contents destroyed
|
||||
// temp : temporary register, must not be scratch register t0 or t1
|
||||
void unlock_object(Register swap, Register obj, Register lock, Register temp, Label& slow_case);
|
||||
// hdr : contents destroyed
|
||||
// obj : must point to the object to lock, contents preserved
|
||||
// basic_lock: must be x10 & must point to the basic lock, contents destroyed
|
||||
// temp : temporary register, must not be scratch register t0 or t1
|
||||
void unlock_object(Register swap, Register obj, Register basic_lock, Register temp, Label& slow_case);
|
||||
|
||||
void initialize_object(
|
||||
Register obj, // result: pointer to object after successful allocation
|
||||
|
||||
@ -87,15 +87,54 @@ void G1BarrierSetAssembler::gen_write_ref_array_pre_barrier(MacroAssembler* masm
|
||||
}
|
||||
}
|
||||
|
||||
void G1BarrierSetAssembler::gen_write_ref_array_post_barrier(MacroAssembler* masm, DecoratorSet decorators,
|
||||
Register start, Register count, Register tmp, RegSet saved_regs) {
|
||||
__ push_reg(saved_regs, sp);
|
||||
void G1BarrierSetAssembler::gen_write_ref_array_post_barrier(MacroAssembler* masm,
|
||||
DecoratorSet decorators,
|
||||
Register start,
|
||||
Register count,
|
||||
Register tmp,
|
||||
RegSet saved_regs) {
|
||||
assert_different_registers(start, count, tmp);
|
||||
assert_different_registers(c_rarg0, count);
|
||||
__ mv(c_rarg0, start);
|
||||
__ mv(c_rarg1, count);
|
||||
__ call_VM_leaf(CAST_FROM_FN_PTR(address, G1BarrierSetRuntime::write_ref_array_post_entry), 2);
|
||||
__ pop_reg(saved_regs, sp);
|
||||
|
||||
Label loop, next, done;
|
||||
|
||||
// Zero count? Nothing to do.
|
||||
__ beqz(count, done);
|
||||
|
||||
// Calculate the number of card marks to set. Since the object might start and
|
||||
// end within a card, we need to calculate this via the card table indexes of
|
||||
// the actual start and last addresses covered by the object.
|
||||
// Temporarily use the count register for the last element address.
|
||||
__ shadd(count, count, start, tmp, LogBytesPerHeapOop); // end = start + count << LogBytesPerHeapOop
|
||||
__ subi(count, count, BytesPerHeapOop); // Use last element address for end.
|
||||
|
||||
__ srli(start, start, CardTable::card_shift());
|
||||
__ srli(count, count, CardTable::card_shift());
|
||||
__ sub(count, count, start); // Number of bytes to mark - 1.
|
||||
|
||||
// Add card table base offset to start.
|
||||
Address card_table_address(xthread, G1ThreadLocalData::card_table_base_offset());
|
||||
__ ld(tmp, card_table_address);
|
||||
__ add(start, start, tmp);
|
||||
|
||||
__ bind(loop);
|
||||
if (UseCondCardMark) {
|
||||
__ add(tmp, start, count);
|
||||
__ lbu(tmp, Address(tmp, 0));
|
||||
static_assert((uint)G1CardTable::clean_card_val() == 0xff, "must be");
|
||||
__ subi(tmp, tmp, G1CardTable::clean_card_val()); // Convert to clean_card_value() to a comparison
|
||||
// against zero to avoid use of an extra temp.
|
||||
__ bnez(tmp, next);
|
||||
}
|
||||
|
||||
__ add(tmp, start, count);
|
||||
static_assert(G1CardTable::dirty_card_val() == 0, "must be to use zr");
|
||||
__ sb(zr, Address(tmp, 0));
|
||||
|
||||
__ bind(next);
|
||||
__ subi(count, count, 1);
|
||||
__ bgez(count, loop);
|
||||
|
||||
__ bind(done);
|
||||
}
|
||||
|
||||
static void generate_queue_test_and_insertion(MacroAssembler* masm, ByteSize index_offset, ByteSize buffer_offset, Label& runtime,
|
||||
@ -189,47 +228,40 @@ void G1BarrierSetAssembler::g1_write_barrier_pre(MacroAssembler* masm,
|
||||
|
||||
}
|
||||
|
||||
static void generate_post_barrier_fast_path(MacroAssembler* masm,
|
||||
const Register store_addr,
|
||||
const Register new_val,
|
||||
const Register tmp1,
|
||||
const Register tmp2,
|
||||
Label& done,
|
||||
bool new_val_may_be_null) {
|
||||
static void generate_post_barrier(MacroAssembler* masm,
|
||||
const Register store_addr,
|
||||
const Register new_val,
|
||||
const Register thread,
|
||||
const Register tmp1,
|
||||
const Register tmp2,
|
||||
Label& done,
|
||||
bool new_val_may_be_null) {
|
||||
assert(thread == xthread, "must be");
|
||||
assert_different_registers(store_addr, new_val, thread, tmp1, tmp2, noreg);
|
||||
// Does store cross heap regions?
|
||||
__ xorr(tmp1, store_addr, new_val); // tmp1 := store address ^ new value
|
||||
__ srli(tmp1, tmp1, G1HeapRegion::LogOfHRGrainBytes); // tmp1 := ((store address ^ new value) >> LogOfHRGrainBytes)
|
||||
__ beqz(tmp1, done);
|
||||
|
||||
// Crosses regions, storing null?
|
||||
if (new_val_may_be_null) {
|
||||
__ beqz(new_val, done);
|
||||
}
|
||||
// Storing region crossing non-null, is card young?
|
||||
// Storing region crossing non-null, is card clean?
|
||||
__ srli(tmp1, store_addr, CardTable::card_shift()); // tmp1 := card address relative to card table base
|
||||
__ load_byte_map_base(tmp2); // tmp2 := card table base address
|
||||
__ add(tmp1, tmp1, tmp2); // tmp1 := card address
|
||||
__ lbu(tmp2, Address(tmp1)); // tmp2 := card
|
||||
}
|
||||
|
||||
static void generate_post_barrier_slow_path(MacroAssembler* masm,
|
||||
const Register thread,
|
||||
const Register tmp1,
|
||||
const Register tmp2,
|
||||
Label& done,
|
||||
Label& runtime) {
|
||||
__ membar(MacroAssembler::StoreLoad); // StoreLoad membar
|
||||
__ lbu(tmp2, Address(tmp1)); // tmp2 := card
|
||||
__ beqz(tmp2, done, true);
|
||||
// Storing a region crossing, non-null oop, card is clean.
|
||||
// Dirty card and log.
|
||||
STATIC_ASSERT(CardTable::dirty_card_val() == 0);
|
||||
__ sb(zr, Address(tmp1)); // *(card address) := dirty_card_val
|
||||
generate_queue_test_and_insertion(masm,
|
||||
G1ThreadLocalData::dirty_card_queue_index_offset(),
|
||||
G1ThreadLocalData::dirty_card_queue_buffer_offset(),
|
||||
runtime,
|
||||
thread, tmp1, tmp2, t0);
|
||||
__ j(done);
|
||||
Address card_table_address(xthread, G1ThreadLocalData::card_table_base_offset());
|
||||
__ ld(tmp2, card_table_address); // tmp2 := card table base address
|
||||
__ add(tmp1, tmp1, tmp2); // tmp1 := card address
|
||||
if (UseCondCardMark) {
|
||||
static_assert((uint)G1CardTable::clean_card_val() == 0xff, "must be");
|
||||
__ lbu(tmp2, Address(tmp1, 0)); // tmp2 := card
|
||||
__ subi(tmp2, tmp2, G1CardTable::clean_card_val()); // Convert to clean_card_value() to a comparison
|
||||
// against zero to avoid use of an extra temp.
|
||||
__ bnez(tmp2, done);
|
||||
}
|
||||
static_assert((uint)G1CardTable::dirty_card_val() == 0, "must be to use zr");
|
||||
__ sb(zr, Address(tmp1, 0));
|
||||
}
|
||||
|
||||
void G1BarrierSetAssembler::g1_write_barrier_post(MacroAssembler* masm,
|
||||
@ -238,27 +270,8 @@ void G1BarrierSetAssembler::g1_write_barrier_post(MacroAssembler* masm,
|
||||
Register thread,
|
||||
Register tmp1,
|
||||
Register tmp2) {
|
||||
assert(thread == xthread, "must be");
|
||||
assert_different_registers(store_addr, new_val, thread, tmp1, tmp2, t0);
|
||||
assert(store_addr != noreg && new_val != noreg && tmp1 != noreg && tmp2 != noreg,
|
||||
"expecting a register");
|
||||
|
||||
Label done;
|
||||
Label runtime;
|
||||
|
||||
generate_post_barrier_fast_path(masm, store_addr, new_val, tmp1, tmp2, done, true /* new_val_may_be_null */);
|
||||
// If card is young, jump to done (tmp2 holds the card value)
|
||||
__ mv(t0, (int)G1CardTable::g1_young_card_val());
|
||||
__ beq(tmp2, t0, done); // card == young_card_val?
|
||||
generate_post_barrier_slow_path(masm, thread, tmp1, tmp2, done, runtime);
|
||||
|
||||
__ bind(runtime);
|
||||
// save the live input values
|
||||
RegSet saved = RegSet::of(store_addr);
|
||||
__ push_reg(saved, sp);
|
||||
__ call_VM_leaf(CAST_FROM_FN_PTR(address, G1BarrierSetRuntime::write_ref_field_post_entry), tmp1, thread);
|
||||
__ pop_reg(saved, sp);
|
||||
|
||||
generate_post_barrier(masm, store_addr, new_val, thread, tmp1, tmp2, done, true /* new_val_may_be_null */);
|
||||
__ bind(done);
|
||||
}
|
||||
|
||||
@ -318,37 +331,10 @@ void G1BarrierSetAssembler::g1_write_barrier_post_c2(MacroAssembler* masm,
|
||||
Register thread,
|
||||
Register tmp1,
|
||||
Register tmp2,
|
||||
G1PostBarrierStubC2* stub) {
|
||||
assert(thread == xthread, "must be");
|
||||
assert_different_registers(store_addr, new_val, thread, tmp1, tmp2, t0);
|
||||
assert(store_addr != noreg && new_val != noreg && tmp1 != noreg && tmp2 != noreg,
|
||||
"expecting a register");
|
||||
|
||||
stub->initialize_registers(thread, tmp1, tmp2);
|
||||
|
||||
bool new_val_may_be_null = (stub->barrier_data() & G1C2BarrierPostNotNull) == 0;
|
||||
generate_post_barrier_fast_path(masm, store_addr, new_val, tmp1, tmp2, *stub->continuation(), new_val_may_be_null);
|
||||
// If card is not young, jump to stub (slow path) (tmp2 holds the card value)
|
||||
__ mv(t0, (int)G1CardTable::g1_young_card_val());
|
||||
__ bne(tmp2, t0, *stub->entry(), true);
|
||||
|
||||
__ bind(*stub->continuation());
|
||||
}
|
||||
|
||||
void G1BarrierSetAssembler::generate_c2_post_barrier_stub(MacroAssembler* masm,
|
||||
G1PostBarrierStubC2* stub) const {
|
||||
Assembler::InlineSkippedInstructionsCounter skip_counter(masm);
|
||||
Label runtime;
|
||||
Register thread = stub->thread();
|
||||
Register tmp1 = stub->tmp1(); // tmp1 holds the card address.
|
||||
Register tmp2 = stub->tmp2();
|
||||
|
||||
__ bind(*stub->entry());
|
||||
generate_post_barrier_slow_path(masm, thread, tmp1, tmp2, *stub->continuation(), runtime);
|
||||
|
||||
__ bind(runtime);
|
||||
generate_c2_barrier_runtime_call(masm, stub, tmp1, CAST_FROM_FN_PTR(address, G1BarrierSetRuntime::write_ref_field_post_entry));
|
||||
__ j(*stub->continuation());
|
||||
bool new_val_may_be_null) {
|
||||
Label done;
|
||||
generate_post_barrier(masm, store_addr, new_val, thread, tmp1, tmp2, done, new_val_may_be_null);
|
||||
__ bind(done);
|
||||
}
|
||||
|
||||
#endif // COMPILER2
|
||||
@ -443,20 +429,19 @@ void G1BarrierSetAssembler::gen_pre_barrier_stub(LIR_Assembler* ce, G1PreBarrier
|
||||
__ j(*stub->continuation());
|
||||
}
|
||||
|
||||
void G1BarrierSetAssembler::gen_post_barrier_stub(LIR_Assembler* ce, G1PostBarrierStub* stub) {
|
||||
G1BarrierSetC1* bs = (G1BarrierSetC1*)BarrierSet::barrier_set()->barrier_set_c1();
|
||||
__ bind(*stub->entry());
|
||||
assert(stub->addr()->is_register(), "Precondition");
|
||||
assert(stub->new_val()->is_register(), "Precondition");
|
||||
Register new_val_reg = stub->new_val()->as_register();
|
||||
__ beqz(new_val_reg, *stub->continuation(), /* is_far */ true);
|
||||
ce->store_parameter(stub->addr()->as_pointer_register(), 0);
|
||||
__ far_call(RuntimeAddress(bs->post_barrier_c1_runtime_code_blob()->code_begin()));
|
||||
__ j(*stub->continuation());
|
||||
}
|
||||
|
||||
#undef __
|
||||
|
||||
void G1BarrierSetAssembler::g1_write_barrier_post_c1(MacroAssembler* masm,
|
||||
Register store_addr,
|
||||
Register new_val,
|
||||
Register thread,
|
||||
Register tmp1,
|
||||
Register tmp2) {
|
||||
Label done;
|
||||
generate_post_barrier(masm, store_addr, new_val, thread, tmp1, tmp2, done, true /* new_val_may_be_null */);
|
||||
masm->bind(done);
|
||||
}
|
||||
|
||||
#define __ sasm->
|
||||
|
||||
void G1BarrierSetAssembler::generate_c1_pre_barrier_runtime_stub(StubAssembler* sasm) {
|
||||
@ -507,74 +492,6 @@ void G1BarrierSetAssembler::generate_c1_pre_barrier_runtime_stub(StubAssembler*
|
||||
__ epilogue();
|
||||
}
|
||||
|
||||
void G1BarrierSetAssembler::generate_c1_post_barrier_runtime_stub(StubAssembler* sasm) {
|
||||
__ prologue("g1_post_barrier", false);
|
||||
|
||||
// arg0 : store_address
|
||||
Address store_addr(fp, 2 * BytesPerWord); // 2 BytesPerWord from fp
|
||||
|
||||
BarrierSet* bs = BarrierSet::barrier_set();
|
||||
CardTableBarrierSet* ctbs = barrier_set_cast<CardTableBarrierSet>(bs);
|
||||
|
||||
Label done;
|
||||
Label runtime;
|
||||
|
||||
// At this point we know new_value is non-null and the new_value crosses regions.
|
||||
// Must check to see if card is already dirty
|
||||
const Register thread = xthread;
|
||||
|
||||
Address queue_index(thread, in_bytes(G1ThreadLocalData::dirty_card_queue_index_offset()));
|
||||
Address buffer(thread, in_bytes(G1ThreadLocalData::dirty_card_queue_buffer_offset()));
|
||||
|
||||
const Register card_offset = t1;
|
||||
// RA is free here, so we can use it to hold the byte_map_base.
|
||||
const Register byte_map_base = ra;
|
||||
|
||||
assert_different_registers(card_offset, byte_map_base, t0);
|
||||
|
||||
__ load_parameter(0, card_offset);
|
||||
__ srli(card_offset, card_offset, CardTable::card_shift());
|
||||
__ load_byte_map_base(byte_map_base);
|
||||
|
||||
// Convert card offset into an address in card_addr
|
||||
Register card_addr = card_offset;
|
||||
__ add(card_addr, byte_map_base, card_addr);
|
||||
|
||||
__ lbu(t0, Address(card_addr, 0));
|
||||
__ sub(t0, t0, (int)G1CardTable::g1_young_card_val());
|
||||
__ beqz(t0, done);
|
||||
|
||||
assert((int)CardTable::dirty_card_val() == 0, "must be 0");
|
||||
|
||||
__ membar(MacroAssembler::StoreLoad);
|
||||
__ lbu(t0, Address(card_addr, 0));
|
||||
__ beqz(t0, done);
|
||||
|
||||
// storing region crossing non-null, card is clean.
|
||||
// dirty card and log.
|
||||
__ sb(zr, Address(card_addr, 0));
|
||||
|
||||
__ ld(t0, queue_index);
|
||||
__ beqz(t0, runtime);
|
||||
__ subi(t0, t0, wordSize);
|
||||
__ sd(t0, queue_index);
|
||||
|
||||
// Reuse RA to hold buffer_addr
|
||||
const Register buffer_addr = ra;
|
||||
|
||||
__ ld(buffer_addr, buffer);
|
||||
__ add(t0, buffer_addr, t0);
|
||||
__ sd(card_addr, Address(t0, 0));
|
||||
__ j(done);
|
||||
|
||||
__ bind(runtime);
|
||||
__ push_call_clobbered_registers();
|
||||
__ call_VM_leaf(CAST_FROM_FN_PTR(address, G1BarrierSetRuntime::write_ref_field_post_entry), card_addr, thread);
|
||||
__ pop_call_clobbered_registers();
|
||||
__ bind(done);
|
||||
__ epilogue();
|
||||
}
|
||||
|
||||
#undef __
|
||||
|
||||
#endif // COMPILER1
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2018, 2024, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2018, 2025, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2020, 2024, Huawei Technologies Co., Ltd. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
@ -35,9 +35,7 @@ class LIR_Assembler;
|
||||
#endif
|
||||
class StubAssembler;
|
||||
class G1PreBarrierStub;
|
||||
class G1PostBarrierStub;
|
||||
class G1PreBarrierStubC2;
|
||||
class G1PostBarrierStubC2;
|
||||
|
||||
class G1BarrierSetAssembler: public ModRefBarrierSetAssembler {
|
||||
protected:
|
||||
@ -68,10 +66,16 @@ protected:
|
||||
public:
|
||||
#ifdef COMPILER1
|
||||
void gen_pre_barrier_stub(LIR_Assembler* ce, G1PreBarrierStub* stub);
|
||||
void gen_post_barrier_stub(LIR_Assembler* ce, G1PostBarrierStub* stub);
|
||||
|
||||
void generate_c1_pre_barrier_runtime_stub(StubAssembler* sasm);
|
||||
void generate_c1_post_barrier_runtime_stub(StubAssembler* sasm);
|
||||
|
||||
void g1_write_barrier_post_c1(MacroAssembler* masm,
|
||||
Register store_addr,
|
||||
Register new_val,
|
||||
Register thread,
|
||||
Register tmp1,
|
||||
Register tmp2);
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef COMPILER2
|
||||
@ -90,9 +94,7 @@ public:
|
||||
Register thread,
|
||||
Register tmp1,
|
||||
Register tmp2,
|
||||
G1PostBarrierStubC2* c2_stub);
|
||||
void generate_c2_post_barrier_stub(MacroAssembler* masm,
|
||||
G1PostBarrierStubC2* stub) const;
|
||||
bool new_val_may_be_null);
|
||||
#endif
|
||||
|
||||
void load_at(MacroAssembler* masm, DecoratorSet decorators, BasicType type,
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
//
|
||||
// Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved.
|
||||
// Copyright (c) 2024, 2025, Oracle and/or its affiliates. All rights reserved.
|
||||
// Copyright (c) 2024, Huawei Technologies Co., Ltd. All rights reserved.
|
||||
// DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
//
|
||||
@ -63,13 +63,13 @@ static void write_barrier_post(MacroAssembler* masm,
|
||||
Register new_val,
|
||||
Register tmp1,
|
||||
Register tmp2) {
|
||||
if (!G1PostBarrierStubC2::needs_barrier(node)) {
|
||||
if (!G1BarrierStubC2::needs_post_barrier(node)) {
|
||||
return;
|
||||
}
|
||||
Assembler::InlineSkippedInstructionsCounter skip_counter(masm);
|
||||
G1BarrierSetAssembler* g1_asm = static_cast<G1BarrierSetAssembler*>(BarrierSet::barrier_set()->barrier_set_assembler());
|
||||
G1PostBarrierStubC2* const stub = G1PostBarrierStubC2::create(node);
|
||||
g1_asm->g1_write_barrier_post_c2(masm, store_addr, new_val, xthread, tmp1, tmp2, stub);
|
||||
bool new_val_may_be_null = G1BarrierStubC2::post_new_val_may_be_null(node);
|
||||
g1_asm->g1_write_barrier_post_c2(masm, store_addr, new_val, xthread, tmp1, tmp2, new_val_may_be_null);
|
||||
}
|
||||
|
||||
%}
|
||||
|
||||
@ -602,11 +602,11 @@ void SharedRuntime::generate_i2c2i_adapters(MacroAssembler *masm,
|
||||
int comp_args_on_stack,
|
||||
const BasicType *sig_bt,
|
||||
const VMRegPair *regs,
|
||||
AdapterHandlerEntry* handler) {
|
||||
address i2c_entry = __ pc();
|
||||
address entry_address[AdapterBlob::ENTRY_COUNT]) {
|
||||
entry_address[AdapterBlob::I2C] = __ pc();
|
||||
gen_i2c_adapter(masm, total_args_passed, comp_args_on_stack, sig_bt, regs);
|
||||
|
||||
address c2i_unverified_entry = __ pc();
|
||||
entry_address[AdapterBlob::C2I_Unverified] = __ pc();
|
||||
Label skip_fixup;
|
||||
|
||||
const Register receiver = j_rarg0;
|
||||
@ -633,10 +633,10 @@ void SharedRuntime::generate_i2c2i_adapters(MacroAssembler *masm,
|
||||
__ block_comment("} c2i_unverified_entry");
|
||||
}
|
||||
|
||||
address c2i_entry = __ pc();
|
||||
entry_address[AdapterBlob::C2I] = __ pc();
|
||||
|
||||
// Class initialization barrier for static methods
|
||||
address c2i_no_clinit_check_entry = nullptr;
|
||||
entry_address[AdapterBlob::C2I_No_Clinit_Check] = nullptr;
|
||||
if (VM_Version::supports_fast_class_init_checks()) {
|
||||
Label L_skip_barrier;
|
||||
|
||||
@ -651,15 +651,13 @@ void SharedRuntime::generate_i2c2i_adapters(MacroAssembler *masm,
|
||||
__ far_jump(RuntimeAddress(SharedRuntime::get_handle_wrong_method_stub()));
|
||||
|
||||
__ bind(L_skip_barrier);
|
||||
c2i_no_clinit_check_entry = __ pc();
|
||||
entry_address[AdapterBlob::C2I_No_Clinit_Check] = __ pc();
|
||||
}
|
||||
|
||||
BarrierSetAssembler* bs = BarrierSet::barrier_set()->barrier_set_assembler();
|
||||
bs->c2i_entry_barrier(masm);
|
||||
|
||||
gen_c2i_adapter(masm, total_args_passed, comp_args_on_stack, sig_bt, regs, skip_fixup);
|
||||
|
||||
handler->set_entry_points(i2c_entry, c2i_entry, c2i_unverified_entry, c2i_no_clinit_check_entry);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -1679,8 +1677,6 @@ nmethod* SharedRuntime::generate_native_wrapper(MacroAssembler* masm,
|
||||
Label lock_done;
|
||||
|
||||
if (method->is_synchronized()) {
|
||||
const int mark_word_offset = BasicLock::displaced_header_offset_in_bytes();
|
||||
|
||||
// Get the handle (the 2nd argument)
|
||||
__ mv(oop_handle_reg, c_rarg1);
|
||||
|
||||
|
||||
@ -732,8 +732,7 @@ class StubGenerator: public StubCodeGenerator {
|
||||
//
|
||||
// s and d are adjusted to point to the remaining words to copy
|
||||
//
|
||||
void generate_copy_longs(StubId stub_id, Label &start,
|
||||
Register s, Register d, Register count) {
|
||||
address generate_copy_longs(StubId stub_id, Register s, Register d, Register count) {
|
||||
BasicType type;
|
||||
copy_direction direction;
|
||||
switch (stub_id) {
|
||||
@ -763,7 +762,7 @@ class StubGenerator: public StubCodeGenerator {
|
||||
Label again, drain;
|
||||
StubCodeMark mark(this, stub_id);
|
||||
__ align(CodeEntryAlignment);
|
||||
__ bind(start);
|
||||
address start = __ pc();
|
||||
|
||||
if (direction == copy_forwards) {
|
||||
__ sub(s, s, bias);
|
||||
@ -879,9 +878,9 @@ class StubGenerator: public StubCodeGenerator {
|
||||
}
|
||||
|
||||
__ ret();
|
||||
}
|
||||
|
||||
Label copy_f, copy_b;
|
||||
return start;
|
||||
}
|
||||
|
||||
typedef void (MacroAssembler::*copy_insn)(Register Rd, const Address &adr, Register temp);
|
||||
|
||||
@ -1099,8 +1098,8 @@ class StubGenerator: public StubCodeGenerator {
|
||||
// stub_id - is used to name the stub and identify all details of
|
||||
// how to perform the copy.
|
||||
//
|
||||
// entry - is assigned to the stub's post push entry point unless
|
||||
// it is null
|
||||
// nopush_entry - is assigned to the stub's post push entry point
|
||||
// unless it is null
|
||||
//
|
||||
// Inputs:
|
||||
// c_rarg0 - source array address
|
||||
@ -1111,11 +1110,11 @@ class StubGenerator: public StubCodeGenerator {
|
||||
// the hardware handle it. The two dwords within qwords that span
|
||||
// cache line boundaries will still be loaded and stored atomically.
|
||||
//
|
||||
// Side Effects: entry is set to the (post push) entry point so it
|
||||
// can be used by the corresponding conjoint copy
|
||||
// method
|
||||
// Side Effects: nopush_entry is set to the (post push) entry point
|
||||
// so it can be used by the corresponding conjoint
|
||||
// copy method
|
||||
//
|
||||
address generate_disjoint_copy(StubId stub_id, address* entry) {
|
||||
address generate_disjoint_copy(StubId stub_id, address* nopush_entry) {
|
||||
size_t size;
|
||||
bool aligned;
|
||||
bool is_oop;
|
||||
@ -1204,8 +1203,8 @@ class StubGenerator: public StubCodeGenerator {
|
||||
address start = __ pc();
|
||||
__ enter();
|
||||
|
||||
if (entry != nullptr) {
|
||||
*entry = __ pc();
|
||||
if (nopush_entry != nullptr) {
|
||||
*nopush_entry = __ pc();
|
||||
// caller can pass a 64-bit byte count here (from Unsafe.copyMemory)
|
||||
BLOCK_COMMENT("Entry:");
|
||||
}
|
||||
@ -1256,8 +1255,8 @@ class StubGenerator: public StubCodeGenerator {
|
||||
// corresponding disjoint copy routine which can be
|
||||
// jumped to if the ranges do not actually overlap
|
||||
//
|
||||
// entry - is assigned to the stub's post push entry point unless
|
||||
// it is null
|
||||
// nopush_entry - is assigned to the stub's post push entry point
|
||||
// unless it is null
|
||||
//
|
||||
// Inputs:
|
||||
// c_rarg0 - source array address
|
||||
@ -1269,10 +1268,10 @@ class StubGenerator: public StubCodeGenerator {
|
||||
// cache line boundaries will still be loaded and stored atomically.
|
||||
//
|
||||
// Side Effects:
|
||||
// entry is set to the no-overlap entry point so it can be used by
|
||||
// some other conjoint copy method
|
||||
// nopush_entry is set to the no-overlap entry point so it can be
|
||||
// used by some other conjoint copy method
|
||||
//
|
||||
address generate_conjoint_copy(StubId stub_id, address nooverlap_target, address *entry) {
|
||||
address generate_conjoint_copy(StubId stub_id, address nooverlap_target, address *nopush_entry) {
|
||||
const Register s = c_rarg0, d = c_rarg1, count = c_rarg2;
|
||||
RegSet saved_regs = RegSet::of(s, d, count);
|
||||
int size;
|
||||
@ -1359,8 +1358,8 @@ class StubGenerator: public StubCodeGenerator {
|
||||
address start = __ pc();
|
||||
__ enter();
|
||||
|
||||
if (entry != nullptr) {
|
||||
*entry = __ pc();
|
||||
if (nopush_entry != nullptr) {
|
||||
*nopush_entry = __ pc();
|
||||
// caller can pass a 64-bit byte count here (from Unsafe.copyMemory)
|
||||
BLOCK_COMMENT("Entry:");
|
||||
}
|
||||
@ -1370,7 +1369,7 @@ class StubGenerator: public StubCodeGenerator {
|
||||
__ slli(t1, count, exact_log2(size));
|
||||
Label L_continue;
|
||||
__ bltu(t0, t1, L_continue);
|
||||
__ j(nooverlap_target);
|
||||
__ j(RuntimeAddress(nooverlap_target));
|
||||
__ bind(L_continue);
|
||||
|
||||
DecoratorSet decorators = IN_HEAP | IS_ARRAY;
|
||||
@ -1445,7 +1444,7 @@ class StubGenerator: public StubCodeGenerator {
|
||||
// x10 == 0 - success
|
||||
// x10 == -1^K - failure, where K is partial transfer count
|
||||
//
|
||||
address generate_checkcast_copy(StubId stub_id, address* entry) {
|
||||
address generate_checkcast_copy(StubId stub_id, address* nopush_entry) {
|
||||
bool dest_uninitialized;
|
||||
switch (stub_id) {
|
||||
case StubId::stubgen_checkcast_arraycopy_id:
|
||||
@ -1496,8 +1495,8 @@ class StubGenerator: public StubCodeGenerator {
|
||||
__ enter(); // required for proper stackwalking of RuntimeStub frame
|
||||
|
||||
// Caller of this entry point must set up the argument registers.
|
||||
if (entry != nullptr) {
|
||||
*entry = __ pc();
|
||||
if (nopush_entry != nullptr) {
|
||||
*nopush_entry = __ pc();
|
||||
BLOCK_COMMENT("Entry:");
|
||||
}
|
||||
|
||||
@ -2294,13 +2293,21 @@ class StubGenerator: public StubCodeGenerator {
|
||||
}
|
||||
|
||||
void generate_arraycopy_stubs() {
|
||||
address entry = nullptr;
|
||||
address entry_jbyte_arraycopy = nullptr;
|
||||
address entry_jshort_arraycopy = nullptr;
|
||||
address entry_jint_arraycopy = nullptr;
|
||||
address entry_oop_arraycopy = nullptr;
|
||||
address entry_jlong_arraycopy = nullptr;
|
||||
address entry_checkcast_arraycopy = nullptr;
|
||||
// Some copy stubs publish a normal entry and then a 2nd 'fallback'
|
||||
// entry immediately following their stack push. This can be used
|
||||
// as a post-push branch target for compatible stubs when they
|
||||
// identify a special case that can be handled by the fallback
|
||||
// stub e.g a disjoint copy stub may be use as a special case
|
||||
// fallback for its compatible conjoint copy stub.
|
||||
//
|
||||
// A no push entry is always returned in the following local and
|
||||
// then published by assigning to the appropriate entry field in
|
||||
// class StubRoutines. The entry value is then passed to the
|
||||
// generator for the compatible stub. That means the entry must be
|
||||
// listed when saving to/restoring from the AOT cache, ensuring
|
||||
// that the inter-stub jumps are noted at AOT-cache save and
|
||||
// relocated at AOT cache load.
|
||||
address nopush_entry = nullptr;
|
||||
|
||||
// generate the common exit first so later stubs can rely on it if
|
||||
// they want an UnsafeMemoryAccess exit non-local to the stub
|
||||
@ -2308,72 +2315,117 @@ class StubGenerator: public StubCodeGenerator {
|
||||
// register the stub as the default exit with class UnsafeMemoryAccess
|
||||
UnsafeMemoryAccess::set_common_exit_stub_pc(StubRoutines::_unsafecopy_common_exit);
|
||||
|
||||
generate_copy_longs(StubId::stubgen_copy_byte_f_id, copy_f, c_rarg0, c_rarg1, t1);
|
||||
generate_copy_longs(StubId::stubgen_copy_byte_b_id, copy_b, c_rarg0, c_rarg1, t1);
|
||||
// generate and publish riscv-specific bulk copy routines first
|
||||
// so we can call them from other copy stubs
|
||||
StubRoutines::riscv::_copy_byte_f = generate_copy_longs(StubId::stubgen_copy_byte_f_id, c_rarg0, c_rarg1, t1);
|
||||
StubRoutines::riscv::_copy_byte_b = generate_copy_longs(StubId::stubgen_copy_byte_b_id, c_rarg0, c_rarg1, t1);
|
||||
|
||||
StubRoutines::riscv::_zero_blocks = generate_zero_blocks();
|
||||
|
||||
//*** jbyte
|
||||
// Always need aligned and unaligned versions
|
||||
StubRoutines::_jbyte_disjoint_arraycopy = generate_disjoint_copy(StubId::stubgen_jbyte_disjoint_arraycopy_id, &entry);
|
||||
StubRoutines::_jbyte_arraycopy = generate_conjoint_copy(StubId::stubgen_jbyte_arraycopy_id, entry, &entry_jbyte_arraycopy);
|
||||
StubRoutines::_arrayof_jbyte_disjoint_arraycopy = generate_disjoint_copy(StubId::stubgen_arrayof_jbyte_disjoint_arraycopy_id, &entry);
|
||||
StubRoutines::_arrayof_jbyte_arraycopy = generate_conjoint_copy(StubId::stubgen_arrayof_jbyte_arraycopy_id, entry, nullptr);
|
||||
StubRoutines::_jbyte_disjoint_arraycopy = generate_disjoint_copy(StubId::stubgen_jbyte_disjoint_arraycopy_id, &nopush_entry);
|
||||
// disjoint nopush entry is needed by conjoint copy
|
||||
StubRoutines::_jbyte_disjoint_arraycopy_nopush = nopush_entry;
|
||||
StubRoutines::_jbyte_arraycopy = generate_conjoint_copy(StubId::stubgen_jbyte_arraycopy_id, StubRoutines::_jbyte_disjoint_arraycopy_nopush, &nopush_entry);
|
||||
// conjoint nopush entry is needed by generic/unsafe copy
|
||||
StubRoutines::_jbyte_arraycopy_nopush = nopush_entry;
|
||||
StubRoutines::_arrayof_jbyte_disjoint_arraycopy = generate_disjoint_copy(StubId::stubgen_arrayof_jbyte_disjoint_arraycopy_id, &nopush_entry);
|
||||
// disjoint arrayof nopush entry is needed by conjoint copy
|
||||
StubRoutines::_arrayof_jbyte_disjoint_arraycopy_nopush = nopush_entry;
|
||||
StubRoutines::_arrayof_jbyte_arraycopy = generate_conjoint_copy(StubId::stubgen_arrayof_jbyte_arraycopy_id, StubRoutines::_arrayof_jbyte_disjoint_arraycopy_nopush, nullptr);
|
||||
|
||||
//*** jshort
|
||||
// Always need aligned and unaligned versions
|
||||
StubRoutines::_jshort_disjoint_arraycopy = generate_disjoint_copy(StubId::stubgen_jshort_disjoint_arraycopy_id, &entry);
|
||||
StubRoutines::_jshort_arraycopy = generate_conjoint_copy(StubId::stubgen_jshort_arraycopy_id, entry, &entry_jshort_arraycopy);
|
||||
StubRoutines::_arrayof_jshort_disjoint_arraycopy = generate_disjoint_copy(StubId::stubgen_arrayof_jshort_disjoint_arraycopy_id, &entry);
|
||||
StubRoutines::_arrayof_jshort_arraycopy = generate_conjoint_copy(StubId::stubgen_arrayof_jshort_arraycopy_id, entry, nullptr);
|
||||
StubRoutines::_jshort_disjoint_arraycopy = generate_disjoint_copy(StubId::stubgen_jshort_disjoint_arraycopy_id, &nopush_entry);
|
||||
// disjoint nopush entry is needed by conjoint copy
|
||||
StubRoutines::_jshort_disjoint_arraycopy_nopush = nopush_entry;
|
||||
StubRoutines::_jshort_arraycopy = generate_conjoint_copy(StubId::stubgen_jshort_arraycopy_id, StubRoutines::_jshort_disjoint_arraycopy_nopush, &nopush_entry);
|
||||
// conjoint nopush entry is used by generic/unsafe copy
|
||||
StubRoutines::_jshort_arraycopy_nopush = nopush_entry;
|
||||
StubRoutines::_arrayof_jshort_disjoint_arraycopy = generate_disjoint_copy(StubId::stubgen_arrayof_jshort_disjoint_arraycopy_id, &nopush_entry);
|
||||
// disjoint arrayof nopush entry is needed by conjoint copy
|
||||
StubRoutines::_arrayof_jshort_disjoint_arraycopy_nopush = nopush_entry;
|
||||
StubRoutines::_arrayof_jshort_arraycopy = generate_conjoint_copy(StubId::stubgen_arrayof_jshort_arraycopy_id, StubRoutines::_arrayof_jshort_disjoint_arraycopy_nopush, nullptr);
|
||||
|
||||
//*** jint
|
||||
// Aligned versions
|
||||
StubRoutines::_arrayof_jint_disjoint_arraycopy = generate_disjoint_copy(StubId::stubgen_arrayof_jint_disjoint_arraycopy_id, &entry);
|
||||
StubRoutines::_arrayof_jint_arraycopy = generate_conjoint_copy(StubId::stubgen_arrayof_jint_arraycopy_id, entry, &entry_jint_arraycopy);
|
||||
StubRoutines::_arrayof_jint_disjoint_arraycopy = generate_disjoint_copy(StubId::stubgen_arrayof_jint_disjoint_arraycopy_id, &nopush_entry);
|
||||
// disjoint arrayof nopush entry is needed by conjoint copy
|
||||
StubRoutines::_arrayof_jint_disjoint_arraycopy_nopush = nopush_entry;
|
||||
StubRoutines::_arrayof_jint_arraycopy = generate_conjoint_copy(StubId::stubgen_arrayof_jint_arraycopy_id, StubRoutines::_arrayof_jint_disjoint_arraycopy_nopush, nullptr);
|
||||
// In 64 bit we need both aligned and unaligned versions of jint arraycopy.
|
||||
// entry_jint_arraycopy always points to the unaligned version
|
||||
StubRoutines::_jint_disjoint_arraycopy = generate_disjoint_copy(StubId::stubgen_jint_disjoint_arraycopy_id, &entry);
|
||||
StubRoutines::_jint_arraycopy = generate_conjoint_copy(StubId::stubgen_jint_arraycopy_id, entry, &entry_jint_arraycopy);
|
||||
StubRoutines::_jint_disjoint_arraycopy = generate_disjoint_copy(StubId::stubgen_jint_disjoint_arraycopy_id, &nopush_entry);
|
||||
// disjoint nopush entry is needed by conjoint copy
|
||||
StubRoutines::_jint_disjoint_arraycopy_nopush = nopush_entry;
|
||||
StubRoutines::_jint_arraycopy = generate_conjoint_copy(StubId::stubgen_jint_arraycopy_id, StubRoutines::_jint_disjoint_arraycopy_nopush, &nopush_entry);
|
||||
// conjoint nopush entry is needed by generic/unsafe copy
|
||||
StubRoutines::_jint_arraycopy_nopush = nopush_entry;
|
||||
|
||||
//*** jlong
|
||||
// It is always aligned
|
||||
StubRoutines::_arrayof_jlong_disjoint_arraycopy = generate_disjoint_copy(StubId::stubgen_arrayof_jlong_disjoint_arraycopy_id, &entry);
|
||||
StubRoutines::_arrayof_jlong_arraycopy = generate_conjoint_copy(StubId::stubgen_arrayof_jlong_arraycopy_id, entry, &entry_jlong_arraycopy);
|
||||
StubRoutines::_arrayof_jlong_disjoint_arraycopy = generate_disjoint_copy(StubId::stubgen_arrayof_jlong_disjoint_arraycopy_id, &nopush_entry);
|
||||
// disjoint arrayof nopush entry is needed by conjoint copy
|
||||
StubRoutines::_arrayof_jlong_disjoint_arraycopy_nopush = nopush_entry;
|
||||
StubRoutines::_arrayof_jlong_arraycopy = generate_conjoint_copy(StubId::stubgen_arrayof_jlong_arraycopy_id, StubRoutines::_arrayof_jlong_disjoint_arraycopy_nopush, &nopush_entry);
|
||||
// conjoint nopush entry is needed by generic/unsafe copy
|
||||
StubRoutines::_jlong_arraycopy_nopush = nopush_entry;
|
||||
// disjoint normal/nopush and conjoint normal entries are not
|
||||
// generated since the arrayof versions are the same
|
||||
StubRoutines::_jlong_disjoint_arraycopy = StubRoutines::_arrayof_jlong_disjoint_arraycopy;
|
||||
StubRoutines::_jlong_disjoint_arraycopy_nopush = StubRoutines::_arrayof_jlong_disjoint_arraycopy_nopush;
|
||||
StubRoutines::_jlong_arraycopy = StubRoutines::_arrayof_jlong_arraycopy;
|
||||
|
||||
//*** oops
|
||||
StubRoutines::_arrayof_oop_disjoint_arraycopy
|
||||
= generate_disjoint_copy(StubId::stubgen_arrayof_oop_disjoint_arraycopy_id, &entry);
|
||||
= generate_disjoint_copy(StubId::stubgen_arrayof_oop_disjoint_arraycopy_id, &nopush_entry);
|
||||
// disjoint arrayof nopush entry is needed by conjoint copy
|
||||
StubRoutines::_arrayof_oop_disjoint_arraycopy_nopush = nopush_entry;
|
||||
StubRoutines::_arrayof_oop_arraycopy
|
||||
= generate_conjoint_copy(StubId::stubgen_arrayof_oop_arraycopy_id, entry, &entry_oop_arraycopy);
|
||||
= generate_conjoint_copy(StubId::stubgen_arrayof_oop_arraycopy_id, StubRoutines::_arrayof_oop_disjoint_arraycopy_nopush, &nopush_entry);
|
||||
// conjoint arrayof nopush entry is needed by generic/unsafe copy
|
||||
StubRoutines::_oop_arraycopy_nopush = nopush_entry;
|
||||
// Aligned versions without pre-barriers
|
||||
StubRoutines::_arrayof_oop_disjoint_arraycopy_uninit
|
||||
= generate_disjoint_copy(StubId::stubgen_arrayof_oop_disjoint_arraycopy_uninit_id, &entry);
|
||||
StubRoutines::_arrayof_oop_arraycopy_uninit
|
||||
= generate_conjoint_copy(StubId::stubgen_arrayof_oop_arraycopy_uninit_id, entry, nullptr);
|
||||
= generate_disjoint_copy(StubId::stubgen_arrayof_oop_disjoint_arraycopy_uninit_id, &nopush_entry);
|
||||
// disjoint arrayof+uninit nopush entry is needed by conjoint copy
|
||||
StubRoutines::_arrayof_oop_disjoint_arraycopy_uninit_nopush = nopush_entry;
|
||||
|
||||
// note that we don't need a returned nopush entry because the
|
||||
// generic/unsafe copy does not cater for uninit arrays.
|
||||
StubRoutines::_arrayof_oop_arraycopy_uninit
|
||||
= generate_conjoint_copy(StubId::stubgen_arrayof_oop_arraycopy_uninit_id, StubRoutines::_arrayof_oop_disjoint_arraycopy_uninit_nopush, nullptr);
|
||||
|
||||
// for oop copies reuse arrayof entries for non-arrayof cases
|
||||
StubRoutines::_oop_disjoint_arraycopy = StubRoutines::_arrayof_oop_disjoint_arraycopy;
|
||||
StubRoutines::_oop_disjoint_arraycopy_nopush = StubRoutines::_arrayof_oop_disjoint_arraycopy_nopush;
|
||||
StubRoutines::_oop_arraycopy = StubRoutines::_arrayof_oop_arraycopy;
|
||||
StubRoutines::_oop_disjoint_arraycopy_uninit = StubRoutines::_arrayof_oop_disjoint_arraycopy_uninit;
|
||||
StubRoutines::_oop_disjoint_arraycopy_uninit_nopush = StubRoutines::_arrayof_oop_disjoint_arraycopy_uninit_nopush;
|
||||
StubRoutines::_oop_arraycopy_uninit = StubRoutines::_arrayof_oop_arraycopy_uninit;
|
||||
|
||||
StubRoutines::_checkcast_arraycopy = generate_checkcast_copy(StubId::stubgen_checkcast_arraycopy_id, &entry_checkcast_arraycopy);
|
||||
StubRoutines::_checkcast_arraycopy = generate_checkcast_copy(StubId::stubgen_checkcast_arraycopy_id, &nopush_entry);
|
||||
// checkcast nopush entry is needed by generic copy
|
||||
StubRoutines::_checkcast_arraycopy_nopush = nopush_entry;
|
||||
// note that we don't need a returned nopush entry because the
|
||||
// generic copy does not cater for uninit arrays.
|
||||
StubRoutines::_checkcast_arraycopy_uninit = generate_checkcast_copy(StubId::stubgen_checkcast_arraycopy_uninit_id, nullptr);
|
||||
|
||||
|
||||
StubRoutines::_unsafe_arraycopy = generate_unsafe_copy(entry_jbyte_arraycopy,
|
||||
entry_jshort_arraycopy,
|
||||
entry_jint_arraycopy,
|
||||
entry_jlong_arraycopy);
|
||||
// unsafe arraycopy may fallback on conjoint stubs
|
||||
StubRoutines::_unsafe_arraycopy = generate_unsafe_copy(StubRoutines::_jbyte_arraycopy_nopush,
|
||||
StubRoutines::_jshort_arraycopy_nopush,
|
||||
StubRoutines::_jint_arraycopy_nopush,
|
||||
StubRoutines::_jlong_arraycopy_nopush);
|
||||
|
||||
StubRoutines::_generic_arraycopy = generate_generic_copy(entry_jbyte_arraycopy,
|
||||
entry_jshort_arraycopy,
|
||||
entry_jint_arraycopy,
|
||||
entry_oop_arraycopy,
|
||||
entry_jlong_arraycopy,
|
||||
entry_checkcast_arraycopy);
|
||||
// generic arraycopy may fallback on conjoint stubs
|
||||
StubRoutines::_generic_arraycopy = generate_generic_copy(StubRoutines::_jbyte_arraycopy_nopush,
|
||||
StubRoutines::_jshort_arraycopy_nopush,
|
||||
StubRoutines::_jint_arraycopy_nopush,
|
||||
StubRoutines::_oop_arraycopy_nopush,
|
||||
StubRoutines::_jlong_arraycopy_nopush,
|
||||
StubRoutines::_checkcast_arraycopy_nopush);
|
||||
|
||||
StubRoutines::_jbyte_fill = generate_fill(StubId::stubgen_jbyte_fill_id);
|
||||
StubRoutines::_jshort_fill = generate_fill(StubId::stubgen_jshort_fill_id);
|
||||
|
||||
@ -35,15 +35,28 @@
|
||||
|
||||
uint32_t VM_Version::_initial_vector_length = 0;
|
||||
|
||||
#define DEF_RV_FEATURE(NAME, PRETTY, BIT, FSTRING, FLAGF) \
|
||||
VM_Version::NAME##RVFeatureValue VM_Version::NAME(PRETTY, BIT, FSTRING);
|
||||
RV_FEATURE_FLAGS(DEF_RV_FEATURE)
|
||||
#define DEF_RV_EXT_FEATURE(NAME, PRETTY, LINUX_BIT, FSTRING, FLAGF) \
|
||||
VM_Version::NAME##RVExtFeatureValue VM_Version::NAME;
|
||||
RV_EXT_FEATURE_FLAGS(DEF_RV_EXT_FEATURE)
|
||||
#undef DEF_RV_EXT_FEATURE
|
||||
|
||||
#define ADD_RV_FEATURE_IN_LIST(NAME, PRETTY, BIT, FSTRING, FLAGF) \
|
||||
&VM_Version::NAME,
|
||||
VM_Version::RVFeatureValue* VM_Version::_feature_list[] = {
|
||||
RV_FEATURE_FLAGS(ADD_RV_FEATURE_IN_LIST)
|
||||
#define DEF_RV_NON_EXT_FEATURE(NAME, PRETTY, LINUX_BIT, FSTRING, FLAGF) \
|
||||
VM_Version::NAME##RVNonExtFeatureValue VM_Version::NAME;
|
||||
RV_NON_EXT_FEATURE_FLAGS(DEF_RV_NON_EXT_FEATURE)
|
||||
#undef DEF_RV_NON_EXT_FEATURE
|
||||
|
||||
#define ADD_RV_EXT_FEATURE_IN_LIST(NAME, PRETTY, LINUX_BIT, FSTRING, FLAGF) \
|
||||
&VM_Version::NAME,
|
||||
#define ADD_RV_NON_EXT_FEATURE_IN_LIST(NAME, PRETTY, LINUX_BIT, FSTRING, FLAGF) \
|
||||
&VM_Version::NAME,
|
||||
VM_Version::RVFeatureValue* VM_Version::_feature_list[] = {
|
||||
RV_EXT_FEATURE_FLAGS(ADD_RV_EXT_FEATURE_IN_LIST)
|
||||
RV_NON_EXT_FEATURE_FLAGS(ADD_RV_NON_EXT_FEATURE_IN_LIST)
|
||||
nullptr};
|
||||
#undef ADD_RV_NON_EXT_FEATURE_IN_LIST
|
||||
#undef ADD_RV_EXT_FEATURE_IN_LIST
|
||||
|
||||
VM_Version::RVExtFeatures* VM_Version::_rv_ext_features = new VM_Version::RVExtFeatures();
|
||||
|
||||
void VM_Version::useRVA20U64Profile() {
|
||||
RV_USE_RVA20U64;
|
||||
@ -477,10 +490,6 @@ void VM_Version::c2_initialize() {
|
||||
warning("AES/CTR intrinsics are not available on this CPU");
|
||||
FLAG_SET_DEFAULT(UseAESCTRIntrinsics, false);
|
||||
}
|
||||
|
||||
if (FLAG_IS_DEFAULT(AlignVector)) {
|
||||
FLAG_SET_DEFAULT(AlignVector, AvoidUnalignedAccesses);
|
||||
}
|
||||
}
|
||||
|
||||
#endif // COMPILER2
|
||||
|
||||
@ -46,30 +46,29 @@ class VM_Version : public Abstract_VM_Version {
|
||||
RIVOS = 0x6cf, // JEDEC: 0x4f, Bank: 14
|
||||
};
|
||||
|
||||
class RVExtFeatures;
|
||||
|
||||
class RVFeatureValue {
|
||||
const char* const _pretty;
|
||||
const bool _feature_string;
|
||||
const uint64_t _feature_bit;
|
||||
bool _enabled;
|
||||
const uint64_t _linux_feature_bit;
|
||||
int64_t _value;
|
||||
public:
|
||||
RVFeatureValue(const char* pretty, int bit_num, bool fstring) :
|
||||
_pretty(pretty), _feature_string(fstring), _feature_bit(nth_bit(bit_num)),
|
||||
_enabled(false), _value(-1) {
|
||||
RVFeatureValue(const char* pretty, int linux_bit_num, bool fstring) :
|
||||
_pretty(pretty), _feature_string(fstring), _linux_feature_bit(nth_bit(linux_bit_num)),
|
||||
_value(-1) {
|
||||
}
|
||||
void enable_feature(int64_t value = 0) {
|
||||
_enabled = true;
|
||||
virtual void enable_feature(int64_t value = 0) {
|
||||
_value = value;
|
||||
}
|
||||
void disable_feature() {
|
||||
_enabled = false;
|
||||
virtual void disable_feature() {
|
||||
_value = -1;
|
||||
}
|
||||
const char* pretty() { return _pretty; }
|
||||
uint64_t feature_bit() { return _feature_bit; }
|
||||
uint64_t feature_bit() { return _linux_feature_bit; }
|
||||
bool feature_string() { return _feature_string; }
|
||||
bool enabled() { return _enabled; }
|
||||
int64_t value() { return _value; }
|
||||
virtual bool enabled() = 0;
|
||||
virtual void update_flag() = 0;
|
||||
};
|
||||
|
||||
@ -111,6 +110,45 @@ class VM_Version : public Abstract_VM_Version {
|
||||
#define NO_UPDATE_DEFAULT \
|
||||
void update_flag() {} \
|
||||
|
||||
|
||||
class RVExtFeatureValue : public RVFeatureValue {
|
||||
const uint32_t _cpu_feature_index;
|
||||
public:
|
||||
RVExtFeatureValue(const char* pretty, int linux_bit_num, uint32_t cpu_feature_index, bool fstring) :
|
||||
RVFeatureValue(pretty, linux_bit_num, fstring),
|
||||
_cpu_feature_index(cpu_feature_index) {
|
||||
}
|
||||
bool enabled() {
|
||||
return RVExtFeatures::current()->support_feature(_cpu_feature_index);
|
||||
}
|
||||
void enable_feature(int64_t value = 0) {
|
||||
RVFeatureValue::enable_feature(value);
|
||||
RVExtFeatures::current()->set_feature(_cpu_feature_index);
|
||||
}
|
||||
void disable_feature() {
|
||||
RVFeatureValue::disable_feature();
|
||||
RVExtFeatures::current()->clear_feature(_cpu_feature_index);
|
||||
}
|
||||
};
|
||||
|
||||
class RVNonExtFeatureValue : public RVFeatureValue {
|
||||
bool _enabled;
|
||||
public:
|
||||
RVNonExtFeatureValue(const char* pretty, int linux_bit_num, bool fstring) :
|
||||
RVFeatureValue(pretty, linux_bit_num, fstring),
|
||||
_enabled(false) {
|
||||
}
|
||||
bool enabled() { return _enabled; }
|
||||
void enable_feature(int64_t value = 0) {
|
||||
RVFeatureValue::enable_feature(value);
|
||||
_enabled = true;
|
||||
}
|
||||
void disable_feature() {
|
||||
RVFeatureValue::disable_feature();
|
||||
_enabled = false;
|
||||
}
|
||||
};
|
||||
|
||||
// Frozen standard extensions
|
||||
// I RV64I
|
||||
// M Integer Multiplication and Division
|
||||
@ -161,58 +199,140 @@ class VM_Version : public Abstract_VM_Version {
|
||||
#define RV_NO_FLAG_BIT (BitsPerWord+1) // nth_bit will return 0 on values larger than BitsPerWord
|
||||
|
||||
// Note: the order matters, depender should be after their dependee. E.g. ext_V before ext_Zvbb.
|
||||
// declaration name , extension name, bit pos ,in str, mapped flag)
|
||||
#define RV_FEATURE_FLAGS(decl) \
|
||||
decl(ext_I , "i" , ('I' - 'A'), true , NO_UPDATE_DEFAULT) \
|
||||
decl(ext_M , "m" , ('M' - 'A'), true , NO_UPDATE_DEFAULT) \
|
||||
decl(ext_A , "a" , ('A' - 'A'), true , NO_UPDATE_DEFAULT) \
|
||||
decl(ext_F , "f" , ('F' - 'A'), true , NO_UPDATE_DEFAULT) \
|
||||
decl(ext_D , "d" , ('D' - 'A'), true , NO_UPDATE_DEFAULT) \
|
||||
decl(ext_C , "c" , ('C' - 'A'), true , UPDATE_DEFAULT(UseRVC)) \
|
||||
decl(ext_Q , "q" , ('Q' - 'A'), true , NO_UPDATE_DEFAULT) \
|
||||
decl(ext_H , "h" , ('H' - 'A'), true , NO_UPDATE_DEFAULT) \
|
||||
decl(ext_V , "v" , ('V' - 'A'), true , UPDATE_DEFAULT(UseRVV)) \
|
||||
decl(ext_Zicbom , "Zicbom" , RV_NO_FLAG_BIT, true , UPDATE_DEFAULT(UseZicbom)) \
|
||||
decl(ext_Zicboz , "Zicboz" , RV_NO_FLAG_BIT, true , UPDATE_DEFAULT(UseZicboz)) \
|
||||
decl(ext_Zicbop , "Zicbop" , RV_NO_FLAG_BIT, true , UPDATE_DEFAULT(UseZicbop)) \
|
||||
decl(ext_Zba , "Zba" , RV_NO_FLAG_BIT, true , UPDATE_DEFAULT(UseZba)) \
|
||||
decl(ext_Zbb , "Zbb" , RV_NO_FLAG_BIT, true , UPDATE_DEFAULT(UseZbb)) \
|
||||
decl(ext_Zbc , "Zbc" , RV_NO_FLAG_BIT, true , NO_UPDATE_DEFAULT) \
|
||||
decl(ext_Zbs , "Zbs" , RV_NO_FLAG_BIT, true , UPDATE_DEFAULT(UseZbs)) \
|
||||
decl(ext_Zbkb , "Zbkb" , RV_NO_FLAG_BIT, true , UPDATE_DEFAULT(UseZbkb)) \
|
||||
decl(ext_Zcb , "Zcb" , RV_NO_FLAG_BIT, true , UPDATE_DEFAULT(UseZcb)) \
|
||||
decl(ext_Zfa , "Zfa" , RV_NO_FLAG_BIT, true , UPDATE_DEFAULT(UseZfa)) \
|
||||
decl(ext_Zfh , "Zfh" , RV_NO_FLAG_BIT, true , UPDATE_DEFAULT(UseZfh)) \
|
||||
decl(ext_Zfhmin , "Zfhmin" , RV_NO_FLAG_BIT, true , UPDATE_DEFAULT(UseZfhmin)) \
|
||||
decl(ext_Zicsr , "Zicsr" , RV_NO_FLAG_BIT, true , NO_UPDATE_DEFAULT) \
|
||||
decl(ext_Zicntr , "Zicntr" , RV_NO_FLAG_BIT, true , NO_UPDATE_DEFAULT) \
|
||||
decl(ext_Zifencei , "Zifencei" , RV_NO_FLAG_BIT, true , NO_UPDATE_DEFAULT) \
|
||||
decl(ext_Zic64b , "Zic64b" , RV_NO_FLAG_BIT, true , UPDATE_DEFAULT(UseZic64b)) \
|
||||
decl(ext_Ztso , "Ztso" , RV_NO_FLAG_BIT, true , UPDATE_DEFAULT(UseZtso)) \
|
||||
decl(ext_Zihintpause , "Zihintpause" , RV_NO_FLAG_BIT, true , UPDATE_DEFAULT(UseZihintpause)) \
|
||||
decl(ext_Zacas , "Zacas" , RV_NO_FLAG_BIT, true , UPDATE_DEFAULT(UseZacas)) \
|
||||
decl(ext_Zvbb , "Zvbb" , RV_NO_FLAG_BIT, true , UPDATE_DEFAULT_DEP(UseZvbb, ext_V)) \
|
||||
decl(ext_Zvbc , "Zvbc" , RV_NO_FLAG_BIT, true , UPDATE_DEFAULT_DEP(UseZvbc, ext_V)) \
|
||||
decl(ext_Zvfh , "Zvfh" , RV_NO_FLAG_BIT, true , UPDATE_DEFAULT_DEP(UseZvfh, ext_V)) \
|
||||
decl(ext_Zvkn , "Zvkn" , RV_NO_FLAG_BIT, true , UPDATE_DEFAULT_DEP(UseZvkn, ext_V)) \
|
||||
decl(ext_Zicond , "Zicond" , RV_NO_FLAG_BIT, true , UPDATE_DEFAULT(UseZicond)) \
|
||||
decl(mvendorid , "VendorId" , RV_NO_FLAG_BIT, false, NO_UPDATE_DEFAULT) \
|
||||
decl(marchid , "ArchId" , RV_NO_FLAG_BIT, false, NO_UPDATE_DEFAULT) \
|
||||
decl(mimpid , "ImpId" , RV_NO_FLAG_BIT, false, NO_UPDATE_DEFAULT) \
|
||||
decl(unaligned_access , "Unaligned" , RV_NO_FLAG_BIT, false, NO_UPDATE_DEFAULT) \
|
||||
decl(satp_mode , "SATP" , RV_NO_FLAG_BIT, false, NO_UPDATE_DEFAULT) \
|
||||
decl(zicboz_block_size, "ZicbozBlockSize", RV_NO_FLAG_BIT, false, NO_UPDATE_DEFAULT) \
|
||||
//
|
||||
// Fields description in `decl`:
|
||||
// declaration name, extension name, bit value from linux, feature string?, mapped flag)
|
||||
#define RV_EXT_FEATURE_FLAGS(decl) \
|
||||
decl(ext_I , i , ('I' - 'A'), true , NO_UPDATE_DEFAULT) \
|
||||
decl(ext_M , m , ('M' - 'A'), true , NO_UPDATE_DEFAULT) \
|
||||
decl(ext_A , a , ('A' - 'A'), true , NO_UPDATE_DEFAULT) \
|
||||
decl(ext_F , f , ('F' - 'A'), true , NO_UPDATE_DEFAULT) \
|
||||
decl(ext_D , d , ('D' - 'A'), true , NO_UPDATE_DEFAULT) \
|
||||
decl(ext_C , c , ('C' - 'A'), true , UPDATE_DEFAULT(UseRVC)) \
|
||||
decl(ext_Q , q , ('Q' - 'A'), true , NO_UPDATE_DEFAULT) \
|
||||
decl(ext_H , h , ('H' - 'A'), true , NO_UPDATE_DEFAULT) \
|
||||
decl(ext_V , v , ('V' - 'A'), true , UPDATE_DEFAULT(UseRVV)) \
|
||||
decl(ext_Zicbom , Zicbom , RV_NO_FLAG_BIT, true , UPDATE_DEFAULT(UseZicbom)) \
|
||||
decl(ext_Zicboz , Zicboz , RV_NO_FLAG_BIT, true , UPDATE_DEFAULT(UseZicboz)) \
|
||||
decl(ext_Zicbop , Zicbop , RV_NO_FLAG_BIT, true , UPDATE_DEFAULT(UseZicbop)) \
|
||||
decl(ext_Zba , Zba , RV_NO_FLAG_BIT, true , UPDATE_DEFAULT(UseZba)) \
|
||||
decl(ext_Zbb , Zbb , RV_NO_FLAG_BIT, true , UPDATE_DEFAULT(UseZbb)) \
|
||||
decl(ext_Zbc , Zbc , RV_NO_FLAG_BIT, true , NO_UPDATE_DEFAULT) \
|
||||
decl(ext_Zbs , Zbs , RV_NO_FLAG_BIT, true , UPDATE_DEFAULT(UseZbs)) \
|
||||
decl(ext_Zbkb , Zbkb , RV_NO_FLAG_BIT, true , UPDATE_DEFAULT(UseZbkb)) \
|
||||
decl(ext_Zcb , Zcb , RV_NO_FLAG_BIT, true , UPDATE_DEFAULT(UseZcb)) \
|
||||
decl(ext_Zfa , Zfa , RV_NO_FLAG_BIT, true , UPDATE_DEFAULT(UseZfa)) \
|
||||
decl(ext_Zfh , Zfh , RV_NO_FLAG_BIT, true , UPDATE_DEFAULT(UseZfh)) \
|
||||
decl(ext_Zfhmin , Zfhmin , RV_NO_FLAG_BIT, true , UPDATE_DEFAULT(UseZfhmin)) \
|
||||
decl(ext_Zicsr , Zicsr , RV_NO_FLAG_BIT, true , NO_UPDATE_DEFAULT) \
|
||||
decl(ext_Zicntr , Zicntr , RV_NO_FLAG_BIT, true , NO_UPDATE_DEFAULT) \
|
||||
decl(ext_Zifencei , Zifencei , RV_NO_FLAG_BIT, true , NO_UPDATE_DEFAULT) \
|
||||
decl(ext_Zic64b , Zic64b , RV_NO_FLAG_BIT, true , UPDATE_DEFAULT(UseZic64b)) \
|
||||
decl(ext_Ztso , Ztso , RV_NO_FLAG_BIT, true , UPDATE_DEFAULT(UseZtso)) \
|
||||
decl(ext_Zihintpause , Zihintpause , RV_NO_FLAG_BIT, true , UPDATE_DEFAULT(UseZihintpause)) \
|
||||
decl(ext_Zacas , Zacas , RV_NO_FLAG_BIT, true , UPDATE_DEFAULT(UseZacas)) \
|
||||
decl(ext_Zvbb , Zvbb , RV_NO_FLAG_BIT, true , UPDATE_DEFAULT_DEP(UseZvbb, ext_V)) \
|
||||
decl(ext_Zvbc , Zvbc , RV_NO_FLAG_BIT, true , UPDATE_DEFAULT_DEP(UseZvbc, ext_V)) \
|
||||
decl(ext_Zvfh , Zvfh , RV_NO_FLAG_BIT, true , UPDATE_DEFAULT_DEP(UseZvfh, ext_V)) \
|
||||
decl(ext_Zvkn , Zvkn , RV_NO_FLAG_BIT, true , UPDATE_DEFAULT_DEP(UseZvkn, ext_V)) \
|
||||
decl(ext_Zicond , Zicond , RV_NO_FLAG_BIT, true , UPDATE_DEFAULT(UseZicond)) \
|
||||
|
||||
#define DECLARE_RV_FEATURE(NAME, PRETTY, BIT, FSTRING, FLAGF) \
|
||||
struct NAME##RVFeatureValue : public RVFeatureValue { \
|
||||
NAME##RVFeatureValue(const char* pretty, int bit, bool fstring) : \
|
||||
RVFeatureValue(pretty, bit, fstring) {} \
|
||||
FLAGF; \
|
||||
}; \
|
||||
static NAME##RVFeatureValue NAME; \
|
||||
#define DECLARE_RV_EXT_FEATURE(NAME, PRETTY, LINUX_BIT, FSTRING, FLAGF) \
|
||||
struct NAME##RVExtFeatureValue : public RVExtFeatureValue { \
|
||||
NAME##RVExtFeatureValue() : \
|
||||
RVExtFeatureValue(#PRETTY, LINUX_BIT, RVExtFeatures::CPU_##NAME, FSTRING) {} \
|
||||
FLAGF; \
|
||||
}; \
|
||||
static NAME##RVExtFeatureValue NAME; \
|
||||
|
||||
RV_FEATURE_FLAGS(DECLARE_RV_FEATURE)
|
||||
#undef DECLARE_RV_FEATURE
|
||||
RV_EXT_FEATURE_FLAGS(DECLARE_RV_EXT_FEATURE)
|
||||
#undef DECLARE_RV_EXT_FEATURE
|
||||
|
||||
// Non-extension features
|
||||
//
|
||||
#define RV_NON_EXT_FEATURE_FLAGS(decl) \
|
||||
decl(unaligned_access , Unaligned , RV_NO_FLAG_BIT, false, NO_UPDATE_DEFAULT) \
|
||||
decl(mvendorid , VendorId , RV_NO_FLAG_BIT, false, NO_UPDATE_DEFAULT) \
|
||||
decl(marchid , ArchId , RV_NO_FLAG_BIT, false, NO_UPDATE_DEFAULT) \
|
||||
decl(mimpid , ImpId , RV_NO_FLAG_BIT, false, NO_UPDATE_DEFAULT) \
|
||||
decl(satp_mode , SATP , RV_NO_FLAG_BIT, false, NO_UPDATE_DEFAULT) \
|
||||
decl(zicboz_block_size, ZicbozBlockSize , RV_NO_FLAG_BIT, false, NO_UPDATE_DEFAULT) \
|
||||
|
||||
#define DECLARE_RV_NON_EXT_FEATURE(NAME, PRETTY, LINUX_BIT, FSTRING, FLAGF) \
|
||||
struct NAME##RVNonExtFeatureValue : public RVNonExtFeatureValue { \
|
||||
NAME##RVNonExtFeatureValue() : \
|
||||
RVNonExtFeatureValue(#PRETTY, LINUX_BIT, FSTRING) {} \
|
||||
FLAGF; \
|
||||
}; \
|
||||
static NAME##RVNonExtFeatureValue NAME; \
|
||||
|
||||
RV_NON_EXT_FEATURE_FLAGS(DECLARE_RV_NON_EXT_FEATURE)
|
||||
#undef DECLARE_RV_NON_EXT_FEATURE
|
||||
|
||||
private:
|
||||
// Utility for AOT CPU feature store/check.
|
||||
class RVExtFeatures : public CHeapObj<mtCode> {
|
||||
public:
|
||||
enum RVFeatureIndex {
|
||||
#define DECLARE_RV_FEATURE_ENUM(NAME, PRETTY, LINUX_BIT, FSTRING, FLAGF) CPU_##NAME,
|
||||
|
||||
RV_EXT_FEATURE_FLAGS(DECLARE_RV_FEATURE_ENUM)
|
||||
MAX_CPU_FEATURE_INDEX
|
||||
#undef DECLARE_RV_FEATURE_ENUM
|
||||
};
|
||||
private:
|
||||
uint64_t _features_bitmap[(MAX_CPU_FEATURE_INDEX / BitsPerLong) + 1];
|
||||
STATIC_ASSERT(sizeof(_features_bitmap) * BitsPerByte >= MAX_CPU_FEATURE_INDEX);
|
||||
|
||||
// Number of 8-byte elements in _features_bitmap.
|
||||
constexpr static int element_count() {
|
||||
return sizeof(_features_bitmap) / sizeof(uint64_t);
|
||||
}
|
||||
|
||||
static int element_index(RVFeatureIndex feature) {
|
||||
int idx = feature / BitsPerLong;
|
||||
assert(idx < element_count(), "Features array index out of bounds");
|
||||
return idx;
|
||||
}
|
||||
|
||||
static uint64_t feature_bit(RVFeatureIndex feature) {
|
||||
return (1ULL << (feature % BitsPerLong));
|
||||
}
|
||||
|
||||
static RVFeatureIndex convert(uint32_t index) {
|
||||
assert(index < MAX_CPU_FEATURE_INDEX, "must");
|
||||
return (RVFeatureIndex)index;
|
||||
}
|
||||
|
||||
public:
|
||||
static RVExtFeatures* current() {
|
||||
return _rv_ext_features;
|
||||
}
|
||||
|
||||
RVExtFeatures() {
|
||||
for (int i = 0; i < element_count(); i++) {
|
||||
_features_bitmap[i] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void set_feature(uint32_t feature) {
|
||||
RVFeatureIndex f = convert(feature);
|
||||
int idx = element_index(f);
|
||||
_features_bitmap[idx] |= feature_bit(f);
|
||||
}
|
||||
|
||||
void clear_feature(uint32_t feature) {
|
||||
RVFeatureIndex f = convert(feature);
|
||||
int idx = element_index(f);
|
||||
_features_bitmap[idx] &= ~feature_bit(f);
|
||||
}
|
||||
|
||||
bool support_feature(uint32_t feature) {
|
||||
RVFeatureIndex f = convert(feature);
|
||||
int idx = element_index(f);
|
||||
return (_features_bitmap[idx] & feature_bit(f)) != 0;
|
||||
}
|
||||
};
|
||||
|
||||
// enable extensions based on profile, current supported profiles:
|
||||
// RVA20U64
|
||||
@ -286,6 +406,7 @@ class VM_Version : public Abstract_VM_Version {
|
||||
|
||||
// Null terminated list
|
||||
static RVFeatureValue* _feature_list[];
|
||||
static RVExtFeatures* _rv_ext_features;
|
||||
|
||||
// Enables features in _feature_list
|
||||
static void setup_cpu_available_features();
|
||||
|
||||
@ -26,7 +26,7 @@
|
||||
#ifndef CPU_S390_ASSEMBLER_S390_INLINE_HPP
|
||||
#define CPU_S390_ASSEMBLER_S390_INLINE_HPP
|
||||
|
||||
#include "asm/assembler.inline.hpp"
|
||||
#include "asm/assembler.hpp"
|
||||
#include "asm/codeBuffer.hpp"
|
||||
#include "code/codeCache.hpp"
|
||||
|
||||
|
||||
@ -234,12 +234,10 @@ void MonitorEnterStub::emit_code(LIR_Assembler* ce) {
|
||||
void MonitorExitStub::emit_code(LIR_Assembler* ce) {
|
||||
__ bind(_entry);
|
||||
// Move address of the BasicObjectLock into Z_R1_scratch.
|
||||
if (_compute_lock) {
|
||||
// Lock_reg was destroyed by fast unlocking attempt => recompute it.
|
||||
ce->monitor_address(_monitor_ix, FrameMap::as_opr(Z_R1_scratch));
|
||||
} else {
|
||||
__ lgr_if_needed(Z_R1_scratch, _lock_reg->as_register());
|
||||
}
|
||||
|
||||
// Lock_reg was destroyed by fast unlocking attempt => recompute it.
|
||||
ce->monitor_address(_monitor_ix, FrameMap::as_opr(Z_R1_scratch));
|
||||
|
||||
// Note: non-blocking leaf routine => no call info needed.
|
||||
StubId exit_id;
|
||||
if (ce->compilation()->has_fpu_code()) {
|
||||
|
||||
@ -228,7 +228,7 @@ int LIR_Assembler::emit_unwind_handler() {
|
||||
// StubId::c1_monitorexit_id expects lock address in Z_R1_scratch.
|
||||
LIR_Opr lock = FrameMap::as_opr(Z_R1_scratch);
|
||||
monitor_address(0, lock);
|
||||
stub = new MonitorExitStub(lock, true, 0);
|
||||
stub = new MonitorExitStub(lock, 0);
|
||||
__ unlock_object(Rtmp1, Rtmp2, lock->as_register(), *stub->entry());
|
||||
__ bind(*stub->continuation());
|
||||
}
|
||||
@ -2711,7 +2711,6 @@ void LIR_Assembler::emit_lock(LIR_OpLock* op) {
|
||||
Register hdr = op->hdr_opr()->as_register();
|
||||
Register lock = op->lock_opr()->as_register();
|
||||
if (op->code() == lir_lock) {
|
||||
assert(BasicLock::displaced_header_offset_in_bytes() == 0, "lock_reg must point to the displaced header");
|
||||
// Add debug info for NullPointerException only if one is possible.
|
||||
if (op->info() != nullptr) {
|
||||
add_debug_info_for_null_check_here(op->info());
|
||||
@ -2719,7 +2718,6 @@ void LIR_Assembler::emit_lock(LIR_OpLock* op) {
|
||||
__ lock_object(hdr, obj, lock, *op->stub()->entry());
|
||||
// done
|
||||
} else if (op->code() == lir_unlock) {
|
||||
assert(BasicLock::displaced_header_offset_in_bytes() == 0, "lock_reg must point to the displaced header");
|
||||
__ unlock_object(hdr, obj, lock, *op->stub()->entry());
|
||||
} else {
|
||||
ShouldNotReachHere();
|
||||
|
||||
@ -45,8 +45,7 @@ define_pd_global(intx, CompileThreshold, 10000);
|
||||
define_pd_global(intx, OnStackReplacePercentage, 140);
|
||||
define_pd_global(intx, ConditionalMoveLimit, 4);
|
||||
define_pd_global(intx, FreqInlineSize, 175);
|
||||
// 10 prevents spill-split-recycle sanity check in JVM2008.xml.transform.
|
||||
define_pd_global(intx, InteriorEntryAlignment, 2);
|
||||
define_pd_global(intx, InteriorEntryAlignment, 4);
|
||||
define_pd_global(size_t, NewSizeThreadIncrease, ScaleForWordSize(4*K));
|
||||
define_pd_global(intx, RegisterCostAreaRatio, 12000);
|
||||
define_pd_global(intx, LoopUnrollLimit, 60);
|
||||
|
||||
@ -28,7 +28,6 @@
|
||||
#include "gc/g1/g1BarrierSetAssembler.hpp"
|
||||
#include "gc/g1/g1BarrierSetRuntime.hpp"
|
||||
#include "gc/g1/g1CardTable.hpp"
|
||||
#include "gc/g1/g1DirtyCardQueue.hpp"
|
||||
#include "gc/g1/g1HeapRegion.hpp"
|
||||
#include "gc/g1/g1SATBMarkQueueSet.hpp"
|
||||
#include "gc/g1/g1ThreadLocalData.hpp"
|
||||
@ -205,104 +204,71 @@ void G1BarrierSetAssembler::generate_c2_pre_barrier_stub(MacroAssembler* masm,
|
||||
BLOCK_COMMENT("} generate_c2_pre_barrier_stub");
|
||||
}
|
||||
|
||||
static void generate_post_barrier(MacroAssembler* masm,
|
||||
const Register store_addr,
|
||||
const Register new_val,
|
||||
const Register thread,
|
||||
const Register tmp1,
|
||||
const Register tmp2,
|
||||
Label& done,
|
||||
bool new_val_may_be_null) {
|
||||
|
||||
__ block_comment("generate_post_barrier {");
|
||||
|
||||
assert(thread == Z_thread, "must be");
|
||||
assert_different_registers(store_addr, new_val, thread, tmp1, tmp2, noreg);
|
||||
|
||||
// Does store cross heap regions?
|
||||
if (VM_Version::has_DistinctOpnds()) {
|
||||
__ z_xgrk(tmp1, store_addr, new_val); // tmp1 := store address ^ new value
|
||||
} else {
|
||||
__ z_lgr(tmp1, store_addr);
|
||||
__ z_xgr(tmp1, new_val);
|
||||
}
|
||||
__ z_srag(tmp1, tmp1, G1HeapRegion::LogOfHRGrainBytes); // tmp1 := ((store address ^ new value) >> LogOfHRGrainBytes)
|
||||
__ branch_optimized(Assembler::bcondEqual, done);
|
||||
|
||||
// Crosses regions, storing null?
|
||||
if (new_val_may_be_null) {
|
||||
__ z_ltgr(new_val, new_val);
|
||||
__ z_bre(done);
|
||||
} else {
|
||||
#ifdef ASSERT
|
||||
__ z_ltgr(new_val, new_val);
|
||||
__ asm_assert(Assembler::bcondNotZero, "null oop not allowed (G1 post)", 0x322); // Checked by caller.
|
||||
#endif
|
||||
}
|
||||
|
||||
__ z_srag(tmp1, store_addr, CardTable::card_shift());
|
||||
|
||||
Address card_table_addr(thread, in_bytes(G1ThreadLocalData::card_table_base_offset()));
|
||||
__ z_alg(tmp1, card_table_addr); // tmp1 := card address
|
||||
|
||||
if(UseCondCardMark) {
|
||||
__ z_cli(0, tmp1, G1CardTable::clean_card_val());
|
||||
__ branch_optimized(Assembler::bcondNotEqual, done);
|
||||
}
|
||||
|
||||
static_assert(G1CardTable::dirty_card_val() == 0, "must be to use z_mvi");
|
||||
__ z_mvi(0, tmp1, G1CardTable::dirty_card_val()); // *(card address) := dirty_card_val
|
||||
|
||||
__ block_comment("} generate_post_barrier");
|
||||
}
|
||||
|
||||
void G1BarrierSetAssembler::g1_write_barrier_post_c2(MacroAssembler* masm,
|
||||
Register store_addr,
|
||||
Register new_val,
|
||||
Register thread,
|
||||
Register tmp1,
|
||||
Register tmp2,
|
||||
G1PostBarrierStubC2* stub) {
|
||||
bool new_val_may_be_null) {
|
||||
BLOCK_COMMENT("g1_write_barrier_post_c2 {");
|
||||
|
||||
assert(thread == Z_thread, "must be");
|
||||
assert_different_registers(store_addr, new_val, thread, tmp1, tmp2, Z_R1_scratch);
|
||||
|
||||
assert(store_addr != noreg && new_val != noreg && tmp1 != noreg && tmp2 != noreg, "expecting a register");
|
||||
|
||||
stub->initialize_registers(thread, tmp1, tmp2);
|
||||
|
||||
BLOCK_COMMENT("generate_region_crossing_test {");
|
||||
if (VM_Version::has_DistinctOpnds()) {
|
||||
__ z_xgrk(tmp1, store_addr, new_val);
|
||||
} else {
|
||||
__ z_lgr(tmp1, store_addr);
|
||||
__ z_xgr(tmp1, new_val);
|
||||
}
|
||||
__ z_srag(tmp1, tmp1, G1HeapRegion::LogOfHRGrainBytes);
|
||||
__ branch_optimized(Assembler::bcondEqual, *stub->continuation());
|
||||
BLOCK_COMMENT("} generate_region_crossing_test");
|
||||
|
||||
// crosses regions, storing null?
|
||||
if ((stub->barrier_data() & G1C2BarrierPostNotNull) == 0) {
|
||||
__ z_ltgr(new_val, new_val);
|
||||
__ branch_optimized(Assembler::bcondEqual, *stub->continuation());
|
||||
}
|
||||
|
||||
BLOCK_COMMENT("generate_card_young_test {");
|
||||
CardTableBarrierSet* ct = barrier_set_cast<CardTableBarrierSet>(BarrierSet::barrier_set());
|
||||
// calculate address of card
|
||||
__ load_const_optimized(tmp2, (address)ct->card_table()->byte_map_base()); // Card table base.
|
||||
__ z_srlg(tmp1, store_addr, CardTable::card_shift()); // Index into card table.
|
||||
__ z_algr(tmp1, tmp2); // Explicit calculation needed for cli.
|
||||
|
||||
// Filter young.
|
||||
__ z_cli(0, tmp1, G1CardTable::g1_young_card_val());
|
||||
|
||||
BLOCK_COMMENT("} generate_card_young_test");
|
||||
|
||||
// From here on, tmp1 holds the card address.
|
||||
__ branch_optimized(Assembler::bcondNotEqual, *stub->entry());
|
||||
|
||||
__ bind(*stub->continuation());
|
||||
|
||||
Label done;
|
||||
generate_post_barrier(masm, store_addr, new_val, thread, tmp1, tmp2, done, new_val_may_be_null);
|
||||
__ bind(done);
|
||||
BLOCK_COMMENT("} g1_write_barrier_post_c2");
|
||||
}
|
||||
|
||||
void G1BarrierSetAssembler::generate_c2_post_barrier_stub(MacroAssembler* masm,
|
||||
G1PostBarrierStubC2* stub) const {
|
||||
|
||||
BLOCK_COMMENT("generate_c2_post_barrier_stub {");
|
||||
|
||||
Assembler::InlineSkippedInstructionsCounter skip_counter(masm);
|
||||
Label runtime;
|
||||
|
||||
Register thread = stub->thread();
|
||||
Register tmp1 = stub->tmp1(); // tmp1 holds the card address.
|
||||
Register tmp2 = stub->tmp2();
|
||||
Register Rcard_addr = tmp1;
|
||||
|
||||
__ bind(*stub->entry());
|
||||
|
||||
BLOCK_COMMENT("generate_card_clean_test {");
|
||||
__ z_sync(); // Required to support concurrent cleaning.
|
||||
__ z_cli(0, Rcard_addr, 0); // Reload after membar.
|
||||
__ branch_optimized(Assembler::bcondEqual, *stub->continuation());
|
||||
BLOCK_COMMENT("} generate_card_clean_test");
|
||||
|
||||
BLOCK_COMMENT("generate_dirty_card {");
|
||||
// Storing a region crossing, non-null oop, card is clean.
|
||||
// Dirty card and log.
|
||||
STATIC_ASSERT(CardTable::dirty_card_val() == 0);
|
||||
__ z_mvi(0, Rcard_addr, CardTable::dirty_card_val());
|
||||
BLOCK_COMMENT("} generate_dirty_card");
|
||||
|
||||
generate_queue_test_and_insertion(masm,
|
||||
G1ThreadLocalData::dirty_card_queue_index_offset(),
|
||||
G1ThreadLocalData::dirty_card_queue_buffer_offset(),
|
||||
runtime,
|
||||
Z_thread, tmp1, tmp2);
|
||||
|
||||
__ branch_optimized(Assembler::bcondAlways, *stub->continuation());
|
||||
|
||||
__ bind(runtime);
|
||||
|
||||
generate_c2_barrier_runtime_call(masm, stub, tmp1, CAST_FROM_FN_PTR(address, G1BarrierSetRuntime::write_ref_field_post_entry));
|
||||
|
||||
__ branch_optimized(Assembler::bcondAlways, *stub->continuation());
|
||||
|
||||
BLOCK_COMMENT("} generate_c2_post_barrier_stub");
|
||||
}
|
||||
|
||||
#endif //COMPILER2
|
||||
|
||||
void G1BarrierSetAssembler::load_at(MacroAssembler* masm, DecoratorSet decorators, BasicType type,
|
||||
@ -451,99 +417,9 @@ void G1BarrierSetAssembler::g1_write_barrier_post(MacroAssembler* masm, Decorato
|
||||
Register Rtmp1, Register Rtmp2, Register Rtmp3) {
|
||||
bool not_null = (decorators & IS_NOT_NULL) != 0;
|
||||
|
||||
assert_different_registers(Rstore_addr, Rnew_val, Rtmp1, Rtmp2); // Most probably, Rnew_val == Rtmp3.
|
||||
|
||||
Label callRuntime, filtered;
|
||||
|
||||
CardTableBarrierSet* ct = barrier_set_cast<CardTableBarrierSet>(BarrierSet::barrier_set());
|
||||
|
||||
BLOCK_COMMENT("g1_write_barrier_post {");
|
||||
|
||||
// Does store cross heap regions?
|
||||
// It does if the two addresses specify different grain addresses.
|
||||
if (VM_Version::has_DistinctOpnds()) {
|
||||
__ z_xgrk(Rtmp1, Rstore_addr, Rnew_val);
|
||||
} else {
|
||||
__ z_lgr(Rtmp1, Rstore_addr);
|
||||
__ z_xgr(Rtmp1, Rnew_val);
|
||||
}
|
||||
__ z_srag(Rtmp1, Rtmp1, G1HeapRegion::LogOfHRGrainBytes);
|
||||
__ z_bre(filtered);
|
||||
|
||||
// Crosses regions, storing null?
|
||||
if (not_null) {
|
||||
#ifdef ASSERT
|
||||
__ z_ltgr(Rnew_val, Rnew_val);
|
||||
__ asm_assert(Assembler::bcondNotZero, "null oop not allowed (G1 post)", 0x322); // Checked by caller.
|
||||
#endif
|
||||
} else {
|
||||
__ z_ltgr(Rnew_val, Rnew_val);
|
||||
__ z_bre(filtered);
|
||||
}
|
||||
|
||||
Rnew_val = noreg; // end of lifetime
|
||||
|
||||
// Storing region crossing non-null, is card already dirty?
|
||||
assert_different_registers(Rtmp1, Rtmp2, Rtmp3);
|
||||
// Make sure not to use Z_R0 for any of these registers.
|
||||
Register Rcard_addr = (Rtmp1 != Z_R0_scratch) ? Rtmp1 : Rtmp3;
|
||||
Register Rbase = (Rtmp2 != Z_R0_scratch) ? Rtmp2 : Rtmp3;
|
||||
|
||||
// calculate address of card
|
||||
__ load_const_optimized(Rbase, (address)ct->card_table()->byte_map_base()); // Card table base.
|
||||
__ z_srlg(Rcard_addr, Rstore_addr, CardTable::card_shift()); // Index into card table.
|
||||
__ z_algr(Rcard_addr, Rbase); // Explicit calculation needed for cli.
|
||||
Rbase = noreg; // end of lifetime
|
||||
|
||||
// Filter young.
|
||||
__ z_cli(0, Rcard_addr, G1CardTable::g1_young_card_val());
|
||||
__ z_bre(filtered);
|
||||
|
||||
// Check the card value. If dirty, we're done.
|
||||
// This also avoids false sharing of the (already dirty) card.
|
||||
__ z_sync(); // Required to support concurrent cleaning.
|
||||
__ z_cli(0, Rcard_addr, G1CardTable::dirty_card_val()); // Reload after membar.
|
||||
__ z_bre(filtered);
|
||||
|
||||
// Storing a region crossing, non-null oop, card is clean.
|
||||
// Dirty card and log.
|
||||
__ z_mvi(0, Rcard_addr, G1CardTable::dirty_card_val());
|
||||
|
||||
Register Rcard_addr_x = Rcard_addr;
|
||||
Register Rqueue_index = (Rtmp2 != Z_R0_scratch) ? Rtmp2 : Rtmp1;
|
||||
if (Rcard_addr == Rqueue_index) {
|
||||
Rcard_addr_x = Z_R0_scratch; // Register shortage. We have to use Z_R0.
|
||||
}
|
||||
__ lgr_if_needed(Rcard_addr_x, Rcard_addr);
|
||||
|
||||
generate_queue_test_and_insertion(masm,
|
||||
G1ThreadLocalData::dirty_card_queue_index_offset(),
|
||||
G1ThreadLocalData::dirty_card_queue_buffer_offset(),
|
||||
callRuntime,
|
||||
Z_thread, Rcard_addr_x, Rqueue_index);
|
||||
__ z_bru(filtered);
|
||||
|
||||
__ bind(callRuntime);
|
||||
|
||||
// TODO: do we need a frame? Introduced to be on the safe side.
|
||||
bool needs_frame = true;
|
||||
__ lgr_if_needed(Rcard_addr, Rcard_addr_x); // copy back asap. push_frame will destroy Z_R0_scratch!
|
||||
|
||||
// VM call need frame to access(write) O register.
|
||||
if (needs_frame) {
|
||||
__ save_return_pc();
|
||||
__ push_frame_abi160(0); // Will use Z_R0 as tmp on old CPUs.
|
||||
}
|
||||
|
||||
// Save the live input values.
|
||||
__ call_VM_leaf(CAST_FROM_FN_PTR(address, G1BarrierSetRuntime::write_ref_field_post_entry), Rcard_addr, Z_thread);
|
||||
|
||||
if (needs_frame) {
|
||||
__ pop_frame();
|
||||
__ restore_return_pc();
|
||||
}
|
||||
|
||||
__ bind(filtered);
|
||||
Label done;
|
||||
generate_post_barrier(masm, Rstore_addr, Rnew_val, Z_thread, Rtmp1, Rtmp2, done, !not_null);
|
||||
__ bind(done);
|
||||
|
||||
BLOCK_COMMENT("} g1_write_barrier_post");
|
||||
}
|
||||
@ -615,22 +491,19 @@ void G1BarrierSetAssembler::gen_pre_barrier_stub(LIR_Assembler* ce, G1PreBarrier
|
||||
__ branch_optimized(Assembler::bcondAlways, *stub->continuation());
|
||||
}
|
||||
|
||||
void G1BarrierSetAssembler::gen_post_barrier_stub(LIR_Assembler* ce, G1PostBarrierStub* stub) {
|
||||
G1BarrierSetC1* bs = (G1BarrierSetC1*)BarrierSet::barrier_set()->barrier_set_c1();
|
||||
__ bind(*stub->entry());
|
||||
ce->check_reserved_argument_area(16); // RT stub needs 2 spill slots.
|
||||
assert(stub->addr()->is_register(), "Precondition.");
|
||||
assert(stub->new_val()->is_register(), "Precondition.");
|
||||
Register new_val_reg = stub->new_val()->as_register();
|
||||
__ z_ltgr(new_val_reg, new_val_reg);
|
||||
__ branch_optimized(Assembler::bcondZero, *stub->continuation());
|
||||
__ z_lgr(Z_R1_scratch, stub->addr()->as_pointer_register());
|
||||
ce->emit_call_c(bs->post_barrier_c1_runtime_code_blob()->code_begin());
|
||||
__ branch_optimized(Assembler::bcondAlways, *stub->continuation());
|
||||
}
|
||||
|
||||
#undef __
|
||||
|
||||
void G1BarrierSetAssembler::g1_write_barrier_post_c1(MacroAssembler* masm,
|
||||
Register store_addr,
|
||||
Register new_val,
|
||||
Register thread,
|
||||
Register tmp1,
|
||||
Register tmp2) {
|
||||
Label done;
|
||||
generate_post_barrier(masm, store_addr, new_val, thread, tmp1, tmp2, done, true /* new_val_may_be_null */);
|
||||
masm->bind(done);
|
||||
}
|
||||
|
||||
#define __ sasm->
|
||||
|
||||
static OopMap* save_volatile_registers(StubAssembler* sasm, Register return_pc = Z_R14) {
|
||||
@ -705,92 +578,6 @@ void G1BarrierSetAssembler::generate_c1_pre_barrier_runtime_stub(StubAssembler*
|
||||
__ z_bru(restart);
|
||||
}
|
||||
|
||||
void G1BarrierSetAssembler::generate_c1_post_barrier_runtime_stub(StubAssembler* sasm) {
|
||||
// Z_R1_scratch: oop address, address of updated memory slot
|
||||
|
||||
BarrierSet* bs = BarrierSet::barrier_set();
|
||||
__ set_info("g1_post_barrier_slow_id", false);
|
||||
|
||||
Register addr_oop = Z_R1_scratch;
|
||||
Register addr_card = Z_R1_scratch;
|
||||
Register r1 = Z_R6; // Must be saved/restored.
|
||||
Register r2 = Z_R7; // Must be saved/restored.
|
||||
Register cardtable = r1; // Must be non-volatile, because it is used to save addr_card.
|
||||
CardTableBarrierSet* ctbs = barrier_set_cast<CardTableBarrierSet>(bs);
|
||||
CardTable* ct = ctbs->card_table();
|
||||
CardTable::CardValue* byte_map_base = ct->byte_map_base();
|
||||
|
||||
// Save registers used below (see assertion in G1PreBarrierStub::emit_code()).
|
||||
__ z_stg(r1, 0*BytesPerWord + FrameMap::first_available_sp_in_frame, Z_SP);
|
||||
|
||||
Label not_already_dirty, restart, refill, young_card;
|
||||
|
||||
// Calculate address of card corresponding to the updated oop slot.
|
||||
AddressLiteral rs(byte_map_base);
|
||||
__ z_srlg(addr_card, addr_oop, CardTable::card_shift());
|
||||
addr_oop = noreg; // dead now
|
||||
__ load_const_optimized(cardtable, rs); // cardtable := <card table base>
|
||||
__ z_agr(addr_card, cardtable); // addr_card := addr_oop>>card_shift + cardtable
|
||||
|
||||
__ z_cli(0, addr_card, (int)G1CardTable::g1_young_card_val());
|
||||
__ z_bre(young_card);
|
||||
|
||||
__ z_sync(); // Required to support concurrent cleaning.
|
||||
|
||||
__ z_cli(0, addr_card, (int)CardTable::dirty_card_val());
|
||||
__ z_brne(not_already_dirty);
|
||||
|
||||
__ bind(young_card);
|
||||
// We didn't take the branch, so we're already dirty: restore
|
||||
// used registers and return.
|
||||
__ z_lg(r1, 0*BytesPerWord + FrameMap::first_available_sp_in_frame, Z_SP);
|
||||
__ z_br(Z_R14);
|
||||
|
||||
// Not dirty.
|
||||
__ bind(not_already_dirty);
|
||||
|
||||
// First, dirty it: [addr_card] := 0
|
||||
__ z_mvi(0, addr_card, CardTable::dirty_card_val());
|
||||
|
||||
Register idx = cardtable; // Must be non-volatile, because it is used to save addr_card.
|
||||
Register buf = r2;
|
||||
cardtable = noreg; // now dead
|
||||
|
||||
// Save registers used below (see assertion in G1PreBarrierStub::emit_code()).
|
||||
__ z_stg(r2, 1*BytesPerWord + FrameMap::first_available_sp_in_frame, Z_SP);
|
||||
|
||||
ByteSize dirty_card_q_index_byte_offset = G1ThreadLocalData::dirty_card_queue_index_offset();
|
||||
ByteSize dirty_card_q_buf_byte_offset = G1ThreadLocalData::dirty_card_queue_buffer_offset();
|
||||
|
||||
__ bind(restart);
|
||||
|
||||
// Get the index into the update buffer. G1DirtyCardQueue::_index is
|
||||
// a size_t so z_ltg is appropriate here.
|
||||
__ z_ltg(idx, Address(Z_thread, dirty_card_q_index_byte_offset));
|
||||
|
||||
// index == 0?
|
||||
__ z_brz(refill);
|
||||
|
||||
__ z_lg(buf, Address(Z_thread, dirty_card_q_buf_byte_offset));
|
||||
__ add2reg(idx, -oopSize);
|
||||
|
||||
__ z_stg(addr_card, 0, idx, buf); // [_buf + index] := <address_of_card>
|
||||
__ z_stg(idx, Address(Z_thread, dirty_card_q_index_byte_offset));
|
||||
// Restore killed registers and return.
|
||||
__ z_lg(r1, 0*BytesPerWord + FrameMap::first_available_sp_in_frame, Z_SP);
|
||||
__ z_lg(r2, 1*BytesPerWord + FrameMap::first_available_sp_in_frame, Z_SP);
|
||||
__ z_br(Z_R14);
|
||||
|
||||
__ bind(refill);
|
||||
save_volatile_registers(sasm);
|
||||
__ z_lgr(idx, addr_card); // Save addr_card, tmp3 must be non-volatile.
|
||||
__ call_VM_leaf(CAST_FROM_FN_PTR(address, G1DirtyCardQueueSet::handle_zero_index_for_thread),
|
||||
Z_thread);
|
||||
__ z_lgr(addr_card, idx);
|
||||
restore_volatile_registers(sasm); // Restore addr_card.
|
||||
__ z_bru(restart);
|
||||
}
|
||||
|
||||
#undef __
|
||||
|
||||
#endif // COMPILER1
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2018, 2024, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2018, 2025, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2018, 2024 SAP SE. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
@ -33,9 +33,7 @@
|
||||
class LIR_Assembler;
|
||||
class StubAssembler;
|
||||
class G1PreBarrierStub;
|
||||
class G1PostBarrierStub;
|
||||
class G1PreBarrierStubC2;
|
||||
class G1PostBarrierStubC2;
|
||||
|
||||
class G1BarrierSetAssembler: public ModRefBarrierSetAssembler {
|
||||
protected:
|
||||
@ -60,10 +58,16 @@ class G1BarrierSetAssembler: public ModRefBarrierSetAssembler {
|
||||
public:
|
||||
#ifdef COMPILER1
|
||||
void gen_pre_barrier_stub(LIR_Assembler* ce, G1PreBarrierStub* stub);
|
||||
void gen_post_barrier_stub(LIR_Assembler* ce, G1PostBarrierStub* stub);
|
||||
|
||||
void generate_c1_pre_barrier_runtime_stub(StubAssembler* sasm);
|
||||
void generate_c1_post_barrier_runtime_stub(StubAssembler* sasm);
|
||||
|
||||
void g1_write_barrier_post_c1(MacroAssembler* masm,
|
||||
Register store_addr,
|
||||
Register new_val,
|
||||
Register thread,
|
||||
Register tmp1,
|
||||
Register tmp2);
|
||||
|
||||
#endif // COMPILER1
|
||||
|
||||
#ifdef COMPILER2
|
||||
@ -81,9 +85,7 @@ class G1BarrierSetAssembler: public ModRefBarrierSetAssembler {
|
||||
Register thread,
|
||||
Register tmp1,
|
||||
Register tmp2,
|
||||
G1PostBarrierStubC2* c2_stub);
|
||||
void generate_c2_post_barrier_stub(MacroAssembler* masm,
|
||||
G1PostBarrierStubC2* stub) const;
|
||||
bool new_val_may_be_null);
|
||||
#endif // COMPILER2
|
||||
|
||||
virtual void load_at(MacroAssembler* masm, DecoratorSet decorators, BasicType type,
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
//
|
||||
// Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved.
|
||||
// Copyright (c) 2024, 2025, Oracle and/or its affiliates. All rights reserved.
|
||||
// Copyright 2024 IBM Corporation. All rights reserved.
|
||||
// DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
//
|
||||
@ -62,13 +62,13 @@ static void write_barrier_post(MacroAssembler* masm,
|
||||
Register new_val,
|
||||
Register tmp1,
|
||||
Register tmp2) {
|
||||
if (!G1PostBarrierStubC2::needs_barrier(node)) {
|
||||
if (!G1BarrierStubC2::needs_post_barrier(node)) {
|
||||
return;
|
||||
}
|
||||
Assembler::InlineSkippedInstructionsCounter skip_counter(masm);
|
||||
G1BarrierSetAssembler* g1_asm = static_cast<G1BarrierSetAssembler*>(BarrierSet::barrier_set()->barrier_set_assembler());
|
||||
G1PostBarrierStubC2* const stub = G1PostBarrierStubC2::create(node);
|
||||
g1_asm->g1_write_barrier_post_c2(masm, store_addr, new_val, Z_thread, tmp1, tmp2, stub);
|
||||
bool new_val_may_be_null = G1BarrierStubC2::post_new_val_may_be_null(node);
|
||||
g1_asm->g1_write_barrier_post_c2(masm, store_addr, new_val, Z_thread, tmp1, tmp2, new_val_may_be_null);
|
||||
}
|
||||
|
||||
%} // source
|
||||
|
||||
@ -171,6 +171,7 @@ void BarrierSetAssembler::try_resolve_jobject_in_native(MacroAssembler* masm, Re
|
||||
|
||||
void BarrierSetAssembler::nmethod_entry_barrier(MacroAssembler* masm) {
|
||||
BarrierSetNMethod* bs_nm = BarrierSet::barrier_set()->barrier_set_nmethod();
|
||||
__ align(4, __ offset() + OFFSET_TO_PATCHABLE_DATA); // must align the following block which requires atomic updates
|
||||
__ block_comment("nmethod_entry_barrier (nmethod_entry_barrier) {");
|
||||
|
||||
// Load jump addr:
|
||||
|
||||
@ -66,6 +66,14 @@ public:
|
||||
OptoReg::Name refine_register(const Node* node,
|
||||
OptoReg::Name opto_reg) const;
|
||||
#endif // COMPILER2
|
||||
|
||||
static const int OFFSET_TO_PATCHABLE_DATA_INSTRUCTION = 6 + 6 + 6; // iihf(6) + iilf(6) + lg(6)
|
||||
static const int BARRIER_TOTAL_LENGTH = OFFSET_TO_PATCHABLE_DATA_INSTRUCTION + 6 + 6 + 2; // cfi(6) + larl(6) + bcr(2)
|
||||
|
||||
// first 2 bytes are for cfi instruction opcode and next 4 bytes will be the value/data to be patched,
|
||||
// so we are skipping first 2 bytes and returning the address of value/data field
|
||||
static const int OFFSET_TO_PATCHABLE_DATA = 6 + 6 + 6 + 2; // iihf(6) + iilf(6) + lg(6) + CFI_OPCODE(2)
|
||||
|
||||
};
|
||||
|
||||
#ifdef COMPILER2
|
||||
|
||||
@ -26,26 +26,32 @@
|
||||
#include "code/codeBlob.hpp"
|
||||
#include "code/nativeInst.hpp"
|
||||
#include "code/nmethod.hpp"
|
||||
#include "gc/shared/barrierSetAssembler.hpp"
|
||||
#include "gc/shared/barrierSetNMethod.hpp"
|
||||
#include "utilities/debug.hpp"
|
||||
|
||||
class NativeMethodBarrier: public NativeInstruction {
|
||||
private:
|
||||
static const int PATCHABLE_INSTRUCTION_OFFSET = 3*6; // bytes
|
||||
|
||||
address get_barrier_start_address() const {
|
||||
return NativeInstruction::addr_at(0);
|
||||
}
|
||||
|
||||
address get_patchable_data_address() const {
|
||||
address inst_addr = get_barrier_start_address() + PATCHABLE_INSTRUCTION_OFFSET;
|
||||
address start_address = get_barrier_start_address();
|
||||
#ifdef ASSERT
|
||||
address inst_addr = start_address + BarrierSetAssembler::OFFSET_TO_PATCHABLE_DATA_INSTRUCTION;
|
||||
|
||||
DEBUG_ONLY(Assembler::is_z_cfi(*((long*)inst_addr)));
|
||||
return inst_addr + 2;
|
||||
unsigned long instr = 0;
|
||||
Assembler::get_instruction(inst_addr, &instr);
|
||||
assert(Assembler::is_z_cfi(instr), "sanity check");
|
||||
#endif // ASSERT
|
||||
|
||||
return start_address + BarrierSetAssembler::OFFSET_TO_PATCHABLE_DATA;
|
||||
}
|
||||
|
||||
public:
|
||||
static const int BARRIER_TOTAL_LENGTH = PATCHABLE_INSTRUCTION_OFFSET + 2*6 + 2; // bytes
|
||||
static const int BARRIER_TOTAL_LENGTH = BarrierSetAssembler::BARRIER_TOTAL_LENGTH;
|
||||
|
||||
int get_guard_value() const {
|
||||
address data_addr = get_patchable_data_address();
|
||||
@ -77,23 +83,30 @@ class NativeMethodBarrier: public NativeInstruction {
|
||||
|
||||
#ifdef ASSERT
|
||||
void verify() const {
|
||||
unsigned long instr = 0;
|
||||
int offset = 0; // bytes
|
||||
const address start = get_barrier_start_address();
|
||||
|
||||
MacroAssembler::is_load_const(/* address */ start + offset); // two instructions
|
||||
assert(MacroAssembler::is_load_const(/* address */ start + offset), "sanity check"); // two instructions
|
||||
offset += Assembler::instr_len(&start[offset]);
|
||||
offset += Assembler::instr_len(&start[offset]);
|
||||
|
||||
Assembler::is_z_lg(*((long*)(start + offset)));
|
||||
Assembler::get_instruction(start + offset, &instr);
|
||||
assert(Assembler::is_z_lg(instr), "sanity check");
|
||||
offset += Assembler::instr_len(&start[offset]);
|
||||
|
||||
Assembler::is_z_cfi(*((long*)(start + offset)));
|
||||
// it will be assignment operation, So it doesn't matter what value is already present in instr
|
||||
// hence, no need to 0 it out.
|
||||
Assembler::get_instruction(start + offset, &instr);
|
||||
assert(Assembler::is_z_cfi(instr), "sanity check");
|
||||
offset += Assembler::instr_len(&start[offset]);
|
||||
|
||||
Assembler::is_z_larl(*((long*)(start + offset)));
|
||||
Assembler::get_instruction(start + offset, &instr);
|
||||
assert(Assembler::is_z_larl(instr), "sanity check");
|
||||
offset += Assembler::instr_len(&start[offset]);
|
||||
|
||||
Assembler::is_z_bcr(*((long*)(start + offset)));
|
||||
Assembler::get_instruction(start + offset, &instr);
|
||||
assert(Assembler::is_z_bcr(instr), "sanity check");
|
||||
offset += Assembler::instr_len(&start[offset]);
|
||||
|
||||
assert(offset == BARRIER_TOTAL_LENGTH, "check offset == barrier length constant");
|
||||
|
||||
@ -1947,6 +1947,7 @@ bool Matcher::is_spillable_arg(int reg) {
|
||||
uint Matcher::int_pressure_limit()
|
||||
{
|
||||
// Medium size register set, 6 special purpose regs, 3 SOE regs.
|
||||
// 10 prevents spill-split-recycle sanity check in JVM2008.xml.transform.
|
||||
return (INTPRESSURE == -1) ? 10 : INTPRESSURE;
|
||||
}
|
||||
|
||||
|
||||
@ -2347,13 +2347,11 @@ void SharedRuntime::generate_i2c2i_adapters(MacroAssembler *masm,
|
||||
int comp_args_on_stack,
|
||||
const BasicType *sig_bt,
|
||||
const VMRegPair *regs,
|
||||
AdapterHandlerEntry* handler) {
|
||||
address entry_address[AdapterBlob::ENTRY_COUNT]) {
|
||||
__ align(CodeEntryAlignment);
|
||||
address i2c_entry = __ pc();
|
||||
entry_address[AdapterBlob::I2C] = __ pc();
|
||||
gen_i2c_adapter(masm, total_args_passed, comp_args_on_stack, sig_bt, regs);
|
||||
|
||||
address c2i_unverified_entry;
|
||||
|
||||
Label skip_fixup;
|
||||
{
|
||||
Label ic_miss;
|
||||
@ -2363,7 +2361,7 @@ void SharedRuntime::generate_i2c2i_adapters(MacroAssembler *masm,
|
||||
|
||||
// Unverified Entry Point UEP
|
||||
__ align(CodeEntryAlignment);
|
||||
c2i_unverified_entry = __ pc();
|
||||
entry_address[AdapterBlob::C2I_Unverified] = __ pc();
|
||||
|
||||
__ ic_check(2);
|
||||
__ z_lg(Z_method, Address(Z_inline_cache, CompiledICData::speculated_method_offset()));
|
||||
@ -2376,10 +2374,10 @@ void SharedRuntime::generate_i2c2i_adapters(MacroAssembler *masm,
|
||||
// Fallthru to VEP. Duplicate LTG, but saved taken branch.
|
||||
}
|
||||
|
||||
address c2i_entry = __ pc();
|
||||
entry_address[AdapterBlob::C2I] = __ pc();
|
||||
|
||||
// Class initialization barrier for static methods
|
||||
address c2i_no_clinit_check_entry = nullptr;
|
||||
entry_address[AdapterBlob::C2I_No_Clinit_Check] = nullptr;
|
||||
if (VM_Version::supports_fast_class_init_checks()) {
|
||||
Label L_skip_barrier;
|
||||
|
||||
@ -2396,12 +2394,10 @@ void SharedRuntime::generate_i2c2i_adapters(MacroAssembler *masm,
|
||||
__ z_br(klass);
|
||||
|
||||
__ bind(L_skip_barrier);
|
||||
c2i_no_clinit_check_entry = __ pc();
|
||||
entry_address[AdapterBlob::C2I_No_Clinit_Check] = __ pc();
|
||||
}
|
||||
|
||||
gen_c2i_adapter(masm, total_args_passed, comp_args_on_stack, sig_bt, regs, skip_fixup);
|
||||
|
||||
handler->set_entry_points(i2c_entry, c2i_entry, c2i_unverified_entry, c2i_no_clinit_check_entry);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@ -1398,11 +1398,7 @@ void Assembler::addl(Address dst, Register src) {
|
||||
|
||||
void Assembler::eaddl(Register dst, Address src1, Register src2, bool no_flags) {
|
||||
InstructionMark im(this);
|
||||
InstructionAttr attributes(AVX_128bit, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false);
|
||||
attributes.set_address_attributes(/* tuple_type */ EVEX_NOSCALE, /* input_size_in_bits */ EVEX_32bit);
|
||||
eevex_prefix_ndd(src1, dst->encoding(), src2->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F_3C /* MAP4 */, &attributes, no_flags);
|
||||
emit_int8(0x01);
|
||||
emit_operand(src2, src1, 0);
|
||||
emit_eevex_or_demote(dst, src1, src2, VEX_SIMD_NONE, VEX_OPCODE_0F_3C /* MAP4 */, EVEX_32bit, 0x01, no_flags, false /* is_map1 */, true /* is_commutative */);
|
||||
}
|
||||
|
||||
void Assembler::addl(Register dst, int32_t imm32) {
|
||||
@ -1432,11 +1428,7 @@ void Assembler::addl(Register dst, Register src) {
|
||||
}
|
||||
|
||||
void Assembler::eaddl(Register dst, Register src1, Register src2, bool no_flags) {
|
||||
InstructionAttr attributes(AVX_128bit, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false);
|
||||
// NDD shares its encoding bits with NDS bits for regular EVEX instruction.
|
||||
// Therefore, DST is passed as the second argument to minimize changes in the leaf level routine.
|
||||
(void)emit_eevex_prefix_or_demote_ndd(src1->encoding(), dst->encoding(), src2->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F_3C /* MAP4 */, &attributes, no_flags);
|
||||
emit_arith(0x03, 0xC0, src1, src2);
|
||||
emit_eevex_prefix_or_demote_arith_ndd(dst, src1, src2, VEX_SIMD_NONE, VEX_OPCODE_0F_3C /* MAP4 */, EVEX_32bit, 0x03, 0xC0, no_flags, true /* is_commutative */);
|
||||
}
|
||||
|
||||
void Assembler::addr_nop_4() {
|
||||
@ -1657,17 +1649,18 @@ void Assembler::eandl(Register dst, Register src1, Address src2, bool no_flags)
|
||||
emit_eevex_or_demote(dst, src1, src2, VEX_SIMD_NONE, VEX_OPCODE_0F_3C /* MAP4 */, EVEX_32bit, 0x23, no_flags);
|
||||
}
|
||||
|
||||
void Assembler::eandl(Register dst, Address src1, Register src2, bool no_flags) {
|
||||
InstructionMark im(this);
|
||||
emit_eevex_or_demote(dst, src1, src2, VEX_SIMD_NONE, VEX_OPCODE_0F_3C /* MAP4 */, EVEX_32bit, 0x21, no_flags, false /* is_map1 */, true /* is_commutative */);
|
||||
}
|
||||
|
||||
void Assembler::andl(Register dst, Register src) {
|
||||
(void) prefix_and_encode(dst->encoding(), src->encoding());
|
||||
emit_arith(0x23, 0xC0, dst, src);
|
||||
}
|
||||
|
||||
void Assembler::eandl(Register dst, Register src1, Register src2, bool no_flags) {
|
||||
InstructionAttr attributes(AVX_128bit, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false);
|
||||
// NDD shares its encoding bits with NDS bits for regular EVEX instruction.
|
||||
// Therefore, DST is passed as the second argument to minimize changes in the leaf level routine.
|
||||
(void) emit_eevex_prefix_or_demote_ndd(src1->encoding(), dst->encoding(), src2->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F_3C /* MAP4 */, &attributes, no_flags);
|
||||
emit_arith(0x23, 0xC0, src1, src2);
|
||||
emit_eevex_prefix_or_demote_arith_ndd(dst, src1, src2, VEX_SIMD_NONE, VEX_OPCODE_0F_3C /* MAP4 */, EVEX_32bit, 0x23, 0xC0, no_flags, true /* is_commutative */);
|
||||
}
|
||||
|
||||
void Assembler::andnl(Register dst, Register src1, Register src2) {
|
||||
@ -2232,6 +2225,44 @@ void Assembler::cvttss2sil(Register dst, XMMRegister src) {
|
||||
emit_int16(0x2C, (0xC0 | encode));
|
||||
}
|
||||
|
||||
void Assembler::evcvttss2sisl(Register dst, XMMRegister src) {
|
||||
assert(VM_Version::supports_avx10_2(), "");
|
||||
InstructionAttr attributes(AVX_128bit, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false);
|
||||
attributes.set_is_evex_instruction();
|
||||
int encode = vex_prefix_and_encode(dst->encoding(), 0, src->encoding(), VEX_SIMD_F3, VEX_OPCODE_MAP5, &attributes);
|
||||
emit_int16(0x6D, (0xC0 | encode));
|
||||
}
|
||||
|
||||
void Assembler::evcvttss2sisl(Register dst, Address src) {
|
||||
assert(VM_Version::supports_avx10_2(), "");
|
||||
InstructionMark im(this);
|
||||
InstructionAttr attributes(AVX_128bit, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false);
|
||||
attributes.set_address_attributes(/* tuple_type */ EVEX_T1S, /* input_size_in_bits */ EVEX_32bit);
|
||||
attributes.set_is_evex_instruction();
|
||||
vex_prefix(src, 0, dst->encoding(), VEX_SIMD_F3, VEX_OPCODE_MAP5, &attributes);
|
||||
emit_int8((unsigned char)0x6D);
|
||||
emit_operand(dst, src, 0);
|
||||
}
|
||||
|
||||
void Assembler::evcvttss2sisq(Register dst, XMMRegister src) {
|
||||
assert(VM_Version::supports_avx10_2(), "");
|
||||
InstructionAttr attributes(AVX_128bit, /* vex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false);
|
||||
attributes.set_is_evex_instruction();
|
||||
int encode = vex_prefix_and_encode(dst->encoding(), 0, src->encoding(), VEX_SIMD_F3, VEX_OPCODE_MAP5, &attributes);
|
||||
emit_int16(0x6D, (0xC0 | encode));
|
||||
}
|
||||
|
||||
void Assembler::evcvttss2sisq(Register dst, Address src) {
|
||||
assert(VM_Version::supports_avx10_2(), "");
|
||||
InstructionMark im(this);
|
||||
InstructionAttr attributes(AVX_128bit, /* vex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false);
|
||||
attributes.set_address_attributes(/* tuple_type */ EVEX_T1S, /* input_size_in_bits */ EVEX_32bit);
|
||||
attributes.set_is_evex_instruction();
|
||||
vex_prefix(src, 0, dst->encoding(), VEX_SIMD_F3, VEX_OPCODE_MAP5, &attributes);
|
||||
emit_int8((unsigned char)0x6D);
|
||||
emit_operand(dst, src, 0);
|
||||
}
|
||||
|
||||
void Assembler::cvttpd2dq(XMMRegister dst, XMMRegister src) {
|
||||
int vector_len = VM_Version::supports_avx512novl() ? AVX_512bit : AVX_128bit;
|
||||
InstructionAttr attributes(vector_len, /* rex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ true);
|
||||
@ -2317,6 +2348,25 @@ void Assembler::vcvttps2dq(XMMRegister dst, XMMRegister src, int vector_len) {
|
||||
emit_int16(0x5B, (0xC0 | encode));
|
||||
}
|
||||
|
||||
void Assembler::evcvttps2dqs(XMMRegister dst, XMMRegister src, int vector_len) {
|
||||
assert(VM_Version::supports_avx10_2(), "");
|
||||
InstructionAttr attributes(vector_len, /* rex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ true);
|
||||
attributes.set_is_evex_instruction();
|
||||
int encode = vex_prefix_and_encode(dst->encoding(), 0, src->encoding(), VEX_SIMD_NONE, VEX_OPCODE_MAP5, &attributes);
|
||||
emit_int16(0x6D, (0xC0 | encode));
|
||||
}
|
||||
|
||||
void Assembler::evcvttps2dqs(XMMRegister dst, Address src, int vector_len) {
|
||||
assert(VM_Version::supports_avx10_2(), "");
|
||||
InstructionMark im(this);
|
||||
InstructionAttr attributes(vector_len, /* rex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ true);
|
||||
attributes.set_address_attributes(/* tuple_type */ EVEX_FV, /* input_size_in_bits */ EVEX_32bit);
|
||||
attributes.set_is_evex_instruction();
|
||||
vex_prefix(src, 0, dst->encoding(), VEX_SIMD_NONE, VEX_OPCODE_MAP5, &attributes);
|
||||
emit_int8((unsigned char)0x6D);
|
||||
emit_operand(dst, src, 0);
|
||||
}
|
||||
|
||||
void Assembler::vcvttpd2dq(XMMRegister dst, XMMRegister src, int vector_len) {
|
||||
assert(vector_len <= AVX_256bit ? VM_Version::supports_avx() : VM_Version::supports_evex(), "");
|
||||
InstructionAttr attributes(vector_len, /* rex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ true);
|
||||
@ -2324,6 +2374,25 @@ void Assembler::vcvttpd2dq(XMMRegister dst, XMMRegister src, int vector_len) {
|
||||
emit_int16((unsigned char)0xE6, (0xC0 | encode));
|
||||
}
|
||||
|
||||
void Assembler::evcvttpd2dqs(XMMRegister dst, XMMRegister src, int vector_len) {
|
||||
assert(VM_Version::supports_avx10_2(), "");
|
||||
InstructionAttr attributes(vector_len, /* rex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ true);
|
||||
attributes.set_is_evex_instruction();
|
||||
int encode = vex_prefix_and_encode(dst->encoding(), 0, src->encoding(), VEX_SIMD_NONE, VEX_OPCODE_MAP5, &attributes);
|
||||
emit_int16(0x6D, (0xC0 | encode));
|
||||
}
|
||||
|
||||
void Assembler::evcvttpd2dqs(XMMRegister dst, Address src, int vector_len) {
|
||||
assert(VM_Version::supports_avx10_2(), "");
|
||||
InstructionMark im(this);
|
||||
InstructionAttr attributes(vector_len, /* rex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ true);
|
||||
attributes.set_address_attributes(/* tuple_type */ EVEX_FV, /* input_size_in_bits */ EVEX_64bit);
|
||||
attributes.set_is_evex_instruction();
|
||||
vex_prefix(src, 0, dst->encoding(), VEX_SIMD_NONE, VEX_OPCODE_MAP5, &attributes);
|
||||
emit_int8((unsigned char)0x6D);
|
||||
emit_operand(dst, src, 0);
|
||||
}
|
||||
|
||||
void Assembler::vcvtps2dq(XMMRegister dst, XMMRegister src, int vector_len) {
|
||||
assert(vector_len <= AVX_256bit ? VM_Version::supports_avx() : VM_Version::supports_evex(), "");
|
||||
InstructionAttr attributes(vector_len, /* rex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ true);
|
||||
@ -2339,6 +2408,25 @@ void Assembler::evcvttps2qq(XMMRegister dst, XMMRegister src, int vector_len) {
|
||||
emit_int16(0x7A, (0xC0 | encode));
|
||||
}
|
||||
|
||||
void Assembler::evcvttps2qqs(XMMRegister dst, XMMRegister src, int vector_len) {
|
||||
assert(VM_Version::supports_avx10_2(), "");
|
||||
InstructionAttr attributes(vector_len, /* rex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ true);
|
||||
attributes.set_is_evex_instruction();
|
||||
int encode = vex_prefix_and_encode(dst->encoding(), 0, src->encoding(), VEX_SIMD_66, VEX_OPCODE_MAP5, &attributes);
|
||||
emit_int16(0x6D, (0xC0 | encode));
|
||||
}
|
||||
|
||||
void Assembler::evcvttps2qqs(XMMRegister dst, Address src, int vector_len) {
|
||||
assert(VM_Version::supports_avx10_2(), "");
|
||||
InstructionMark im(this);
|
||||
InstructionAttr attributes(vector_len, /* rex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ true);
|
||||
attributes.set_address_attributes(/* tuple_type */ EVEX_HV, /* input_size_in_bits */ EVEX_32bit);
|
||||
attributes.set_is_evex_instruction();
|
||||
vex_prefix(src, 0, dst->encoding(), VEX_SIMD_66, VEX_OPCODE_MAP5, &attributes);
|
||||
emit_int8((unsigned char)0x6D);
|
||||
emit_operand(dst, src, 0);
|
||||
}
|
||||
|
||||
void Assembler::evcvtpd2qq(XMMRegister dst, XMMRegister src, int vector_len) {
|
||||
assert(VM_Version::supports_avx512dq(), "");
|
||||
InstructionAttr attributes(vector_len, /* rex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ true);
|
||||
@ -2363,6 +2451,25 @@ void Assembler::evcvttpd2qq(XMMRegister dst, XMMRegister src, int vector_len) {
|
||||
emit_int16(0x7A, (0xC0 | encode));
|
||||
}
|
||||
|
||||
void Assembler::evcvttpd2qqs(XMMRegister dst, XMMRegister src, int vector_len) {
|
||||
assert(VM_Version::supports_avx10_2(), "");
|
||||
InstructionAttr attributes(vector_len, /* rex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ true);
|
||||
attributes.set_is_evex_instruction();
|
||||
int encode = vex_prefix_and_encode(dst->encoding(), 0, src->encoding(), VEX_SIMD_66, VEX_OPCODE_MAP5, &attributes);
|
||||
emit_int16(0x6D, (0xC0 | encode));
|
||||
}
|
||||
|
||||
void Assembler::evcvttpd2qqs(XMMRegister dst, Address src, int vector_len) {
|
||||
assert(VM_Version::supports_avx10_2(), "");
|
||||
InstructionMark im(this);
|
||||
InstructionAttr attributes(vector_len, /* rex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ true);
|
||||
attributes.set_address_attributes(/* tuple_type */ EVEX_FV, /* input_size_in_bits */ EVEX_64bit);
|
||||
attributes.set_is_evex_instruction();
|
||||
vex_prefix(src, 0, dst->encoding(), VEX_SIMD_66, VEX_OPCODE_MAP5, &attributes);
|
||||
emit_int8((unsigned char)0x6D);
|
||||
emit_operand(dst, src, 0);
|
||||
}
|
||||
|
||||
void Assembler::evcvtqq2pd(XMMRegister dst, XMMRegister src, int vector_len) {
|
||||
assert(VM_Version::supports_avx512dq(), "");
|
||||
InstructionAttr attributes(vector_len, /* rex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ true);
|
||||
@ -2519,7 +2626,7 @@ void Assembler::imull(Register dst, Register src) {
|
||||
}
|
||||
|
||||
void Assembler::eimull(Register dst, Register src1, Register src2, bool no_flags) {
|
||||
emit_eevex_or_demote(dst->encoding(), src1->encoding(), src2->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F_3C /* MAP4 */, EVEX_32bit, 0xAF, no_flags, true /* is_map1 */, true /* swap */);
|
||||
emit_eevex_or_demote(dst->encoding(), src1->encoding(), src2->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F_3C /* MAP4 */, EVEX_32bit, 0xAF, no_flags, true /* is_map1 */, true /* swap */, true /* is_commutative */);
|
||||
}
|
||||
|
||||
void Assembler::imull(Register dst, Address src, int32_t value) {
|
||||
@ -4419,11 +4526,7 @@ void Assembler::enotl(Register dst, Register src) {
|
||||
}
|
||||
|
||||
void Assembler::eorw(Register dst, Register src1, Register src2, bool no_flags) {
|
||||
InstructionAttr attributes(AVX_128bit, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false);
|
||||
// NDD shares its encoding bits with NDS bits for regular EVEX instruction.
|
||||
// Therefore, DST is passed as the second argument to minimize changes in the leaf level routine.
|
||||
(void) emit_eevex_prefix_or_demote_ndd(src1->encoding(), dst->encoding(), src2->encoding(), VEX_SIMD_66, VEX_OPCODE_0F_3C /* MAP4 */, &attributes, no_flags);
|
||||
emit_arith(0x0B, 0xC0, src1, src2);
|
||||
emit_eevex_prefix_or_demote_arith_ndd(dst, src1, src2, VEX_SIMD_66, VEX_OPCODE_0F_3C /* MAP4 */, EVEX_16bit, 0x0B, 0xC0, no_flags, true /* is_commutative */);
|
||||
}
|
||||
|
||||
void Assembler::orl(Address dst, int32_t imm32) {
|
||||
@ -4467,11 +4570,7 @@ void Assembler::orl(Register dst, Register src) {
|
||||
}
|
||||
|
||||
void Assembler::eorl(Register dst, Register src1, Register src2, bool no_flags) {
|
||||
InstructionAttr attributes(AVX_128bit, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false);
|
||||
// NDD shares its encoding bits with NDS bits for regular EVEX instruction.
|
||||
// Therefore, DST is passed as the second argument to minimize changes in the leaf level routine.
|
||||
(void) emit_eevex_prefix_or_demote_ndd(src1->encoding(), dst->encoding(), src2->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F_3C /* MAP4 */, &attributes, no_flags);
|
||||
emit_arith(0x0B, 0xC0, src1, src2);
|
||||
emit_eevex_prefix_or_demote_arith_ndd(dst, src1, src2, VEX_SIMD_NONE, VEX_OPCODE_0F_3C /* MAP4 */, EVEX_32bit, 0x0B, 0xC0, no_flags, true /* is_commutative */);
|
||||
}
|
||||
|
||||
void Assembler::orl(Address dst, Register src) {
|
||||
@ -4483,11 +4582,7 @@ void Assembler::orl(Address dst, Register src) {
|
||||
|
||||
void Assembler::eorl(Register dst, Address src1, Register src2, bool no_flags) {
|
||||
InstructionMark im(this);
|
||||
InstructionAttr attributes(AVX_128bit, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false);
|
||||
attributes.set_address_attributes(/* tuple_type */ EVEX_NOSCALE, /* input_size_in_bits */ EVEX_32bit);
|
||||
eevex_prefix_ndd(src1, dst->encoding(), src2->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F_3C /* MAP4 */, &attributes, no_flags);
|
||||
emit_int8(0x09);
|
||||
emit_operand(src2, src1, 0);
|
||||
emit_eevex_or_demote(dst, src1, src2, VEX_SIMD_NONE, VEX_OPCODE_0F_3C /* MAP4 */, EVEX_32bit, 0x09, no_flags, false /* is_map1 */, true /* is_commutative */);
|
||||
}
|
||||
|
||||
void Assembler::orb(Address dst, int imm8) {
|
||||
@ -4517,11 +4612,7 @@ void Assembler::orb(Address dst, Register src) {
|
||||
|
||||
void Assembler::eorb(Register dst, Address src1, Register src2, bool no_flags) {
|
||||
InstructionMark im(this);
|
||||
InstructionAttr attributes(AVX_128bit, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false);
|
||||
attributes.set_address_attributes(/* tuple_type */ EVEX_NOSCALE, /* input_size_in_bits */ EVEX_8bit);
|
||||
eevex_prefix_ndd(src1, dst->encoding(), src2->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F_3C /* MAP4 */, &attributes, no_flags);
|
||||
emit_int8(0x08);
|
||||
emit_operand(src2, src1, 0);
|
||||
emit_eevex_or_demote(dst, src1, src2, VEX_SIMD_NONE, VEX_OPCODE_0F_3C /* MAP4 */, EVEX_8bit, 0x08, no_flags, false /* is_map1 */, true /* is_commutative */);
|
||||
}
|
||||
|
||||
void Assembler::packsswb(XMMRegister dst, XMMRegister src) {
|
||||
@ -7323,11 +7414,7 @@ void Assembler::xorl(Register dst, Register src) {
|
||||
}
|
||||
|
||||
void Assembler::exorl(Register dst, Register src1, Register src2, bool no_flags) {
|
||||
InstructionAttr attributes(AVX_128bit, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false);
|
||||
// NDD shares its encoding bits with NDS bits for regular EVEX instruction.
|
||||
// Therefore, DST is passed as the second argument to minimize changes in the leaf level routine.
|
||||
(void) emit_eevex_prefix_or_demote_ndd(src1->encoding(), dst->encoding(), src2->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F_3C /* MAP4 */, &attributes, no_flags);
|
||||
emit_arith(0x33, 0xC0, src1, src2);
|
||||
emit_eevex_prefix_or_demote_arith_ndd(dst, src1, src2, VEX_SIMD_NONE, VEX_OPCODE_0F_3C /* MAP4 */, EVEX_32bit, 0x33, 0xC0, no_flags, true /* is_commutative */);
|
||||
}
|
||||
|
||||
void Assembler::xorl(Address dst, Register src) {
|
||||
@ -7339,11 +7426,7 @@ void Assembler::xorl(Address dst, Register src) {
|
||||
|
||||
void Assembler::exorl(Register dst, Address src1, Register src2, bool no_flags) {
|
||||
InstructionMark im(this);
|
||||
InstructionAttr attributes(AVX_128bit, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false);
|
||||
attributes.set_address_attributes(/* tuple_type */ EVEX_NOSCALE, /* input_size_in_bits */ EVEX_32bit);
|
||||
eevex_prefix_ndd(src1, dst->encoding(), src2->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F_3C /* MAP4 */, &attributes, no_flags);
|
||||
emit_int8(0x31);
|
||||
emit_operand(src2, src1, 0);
|
||||
emit_eevex_or_demote(dst, src1, src2, VEX_SIMD_NONE, VEX_OPCODE_0F_3C /* MAP4 */, EVEX_32bit, 0x31, no_flags, false /* is_map1 */, true /* is_commutative */);
|
||||
}
|
||||
|
||||
void Assembler::xorb(Register dst, Address src) {
|
||||
@ -7367,11 +7450,7 @@ void Assembler::xorb(Address dst, Register src) {
|
||||
|
||||
void Assembler::exorb(Register dst, Address src1, Register src2, bool no_flags) {
|
||||
InstructionMark im(this);
|
||||
InstructionAttr attributes(AVX_128bit, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false);
|
||||
attributes.set_address_attributes(/* tuple_type */ EVEX_NOSCALE, /* input_size_in_bits */ EVEX_8bit);
|
||||
eevex_prefix_ndd(src1, dst->encoding(), src2->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F_3C /* MAP4 */, &attributes, no_flags);
|
||||
emit_int8(0x30);
|
||||
emit_operand(src2, src1, 0);
|
||||
emit_eevex_or_demote(dst, src1, src2, VEX_SIMD_NONE, VEX_OPCODE_0F_3C /* MAP4 */, EVEX_8bit, 0x30, no_flags, false /* is_map1 */, true /* is_commutative */);
|
||||
}
|
||||
|
||||
void Assembler::xorw(Register dst, Address src) {
|
||||
@ -12955,6 +13034,31 @@ void Assembler::eevex_prefix_ndd(Address adr, int ndd_enc, int xreg_enc, VexSimd
|
||||
vex_prefix(adr, ndd_enc, xreg_enc, pre, opc, attributes, /* nds_is_ndd */ true, no_flags);
|
||||
}
|
||||
|
||||
void Assembler::emit_eevex_or_demote(Register dst, Address src1, Register src2, VexSimdPrefix pre, VexOpcode opc,
|
||||
int size, int opcode_byte, bool no_flags, bool is_map1, bool is_commutative) {
|
||||
if (is_commutative && is_demotable(no_flags, dst->encoding(), src2->encoding())) {
|
||||
// Opcode byte adjustment due to mismatch between NDD and equivalent demotable variant
|
||||
opcode_byte += 2;
|
||||
if (size == EVEX_64bit) {
|
||||
emit_prefix_and_int8(get_prefixq(src1, dst, is_map1), opcode_byte);
|
||||
} else {
|
||||
// For 32-bit, 16-bit and 8-bit
|
||||
if (size == EVEX_16bit) {
|
||||
emit_int8(0x66);
|
||||
}
|
||||
prefix(src1, dst, false, is_map1);
|
||||
emit_int8(opcode_byte);
|
||||
}
|
||||
} else {
|
||||
bool vex_w = (size == EVEX_64bit) ? true : false;
|
||||
InstructionAttr attributes(AVX_128bit, vex_w, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false);
|
||||
attributes.set_address_attributes(/* tuple_type */ EVEX_NOSCALE, size);
|
||||
eevex_prefix_ndd(src1, dst->encoding(), src2->encoding(), pre, opc, &attributes, no_flags);
|
||||
emit_int8(opcode_byte);
|
||||
}
|
||||
emit_operand(src2, src1, 0);
|
||||
}
|
||||
|
||||
void Assembler::emit_eevex_or_demote(Register dst, Register src1, Address src2, VexSimdPrefix pre, VexOpcode opc,
|
||||
int size, int opcode_byte, bool no_flags, bool is_map1) {
|
||||
if (is_demotable(no_flags, dst->encoding(), src1->encoding())) {
|
||||
@ -13055,18 +13159,20 @@ void Assembler::emit_eevex_or_demote(int dst_enc, int nds_enc, int src_enc, int8
|
||||
}
|
||||
|
||||
void Assembler::emit_eevex_or_demote(int dst_enc, int nds_enc, int src_enc, VexSimdPrefix pre, VexOpcode opc,
|
||||
int size, int opcode_byte, bool no_flags, bool is_map1, bool swap) {
|
||||
int size, int opcode_byte, bool no_flags, bool is_map1, bool swap, bool is_commutative) {
|
||||
int encode;
|
||||
bool is_prefixq = (size == EVEX_64bit) ? true : false;
|
||||
if (is_demotable(no_flags, dst_enc, nds_enc)) {
|
||||
bool first_operand_demotable = is_demotable(no_flags, dst_enc, nds_enc);
|
||||
bool second_operand_demotable = is_commutative && is_demotable(no_flags, dst_enc, src_enc);
|
||||
if (first_operand_demotable || second_operand_demotable) {
|
||||
if (size == EVEX_16bit) {
|
||||
emit_int8(0x66);
|
||||
}
|
||||
|
||||
int src = first_operand_demotable ? src_enc : nds_enc;
|
||||
if (swap) {
|
||||
encode = is_prefixq ? prefixq_and_encode(dst_enc, src_enc, is_map1) : prefix_and_encode(dst_enc, src_enc, is_map1);
|
||||
encode = is_prefixq ? prefixq_and_encode(dst_enc, src, is_map1) : prefix_and_encode(dst_enc, src, is_map1);
|
||||
} else {
|
||||
encode = is_prefixq ? prefixq_and_encode(src_enc, dst_enc, is_map1) : prefix_and_encode(src_enc, dst_enc, is_map1);
|
||||
encode = is_prefixq ? prefixq_and_encode(src, dst_enc, is_map1) : prefix_and_encode(src, dst_enc, is_map1);
|
||||
}
|
||||
emit_opcode_prefix_and_encoding((unsigned char)opcode_byte, 0xC0, encode);
|
||||
} else {
|
||||
@ -13114,6 +13220,26 @@ int Assembler::eevex_prefix_and_encode_nf(int dst_enc, int nds_enc, int src_enc,
|
||||
return vex_prefix_and_encode(dst_enc, nds_enc, src_enc, pre, opc, attributes, /* src_is_gpr */ true, /* nds_is_ndd */ false, no_flags);
|
||||
}
|
||||
|
||||
void Assembler::emit_eevex_prefix_or_demote_arith_ndd(Register dst, Register src1, Register src2, VexSimdPrefix pre, VexOpcode opc,
|
||||
int size, int op1, int op2, bool no_flags, bool is_commutative) {
|
||||
bool demotable = is_demotable(no_flags, dst->encoding(), src1->encoding());
|
||||
if (!demotable && is_commutative) {
|
||||
if (is_demotable(no_flags, dst->encoding(), src2->encoding())) {
|
||||
// swap src1 and src2
|
||||
Register tmp = src1;
|
||||
src1 = src2;
|
||||
src2 = tmp;
|
||||
}
|
||||
}
|
||||
bool vex_w = (size == EVEX_64bit) ? true : false;
|
||||
bool use_prefixq = vex_w;
|
||||
InstructionAttr attributes(AVX_128bit, vex_w, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false);
|
||||
// NDD shares its encoding bits with NDS bits for regular EVEX instruction.
|
||||
// Therefore, DST is passed as the second argument to minimize changes in the leaf level routine.
|
||||
(void)emit_eevex_prefix_or_demote_ndd(src1->encoding(), dst->encoding(), src2->encoding(), pre, opc, &attributes, no_flags, use_prefixq);
|
||||
emit_arith(op1, op2, src1, src2);
|
||||
}
|
||||
|
||||
void Assembler::emit_eevex_prefix_or_demote_arith_ndd(Register dst, Register nds, int32_t imm32, VexSimdPrefix pre, VexOpcode opc,
|
||||
int size, int op1, int op2, bool no_flags) {
|
||||
int dst_enc = dst->encoding();
|
||||
@ -13124,7 +13250,6 @@ void Assembler::emit_eevex_prefix_or_demote_arith_ndd(Register dst, Register nds
|
||||
} else {
|
||||
bool vex_w = (size == EVEX_64bit) ? true : false;
|
||||
InstructionAttr attributes(AVX_128bit, vex_w, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false);
|
||||
//attributes.set_address_attributes(/* tuple_type */ EVEX_NOSCALE, size);
|
||||
attributes.set_is_evex_instruction();
|
||||
vex_prefix_and_encode(0, dst_enc, nds_enc, pre, opc, &attributes, /* src_is_gpr */ true, /* nds_is_ndd */ true, no_flags);
|
||||
|
||||
@ -13769,7 +13894,7 @@ void Assembler::pdepq(Register dst, Register src1, Address src2) {
|
||||
|
||||
void Assembler::sarxl(Register dst, Register src1, Register src2) {
|
||||
assert(VM_Version::supports_bmi2(), "");
|
||||
InstructionAttr attributes(AVX_128bit, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ true);
|
||||
InstructionAttr attributes(AVX_128bit, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false);
|
||||
int encode = vex_prefix_and_encode(dst->encoding(), src2->encoding(), src1->encoding(), VEX_SIMD_F3, VEX_OPCODE_0F_38, &attributes, true);
|
||||
emit_int16((unsigned char)0xF7, (0xC0 | encode));
|
||||
}
|
||||
@ -13777,7 +13902,7 @@ void Assembler::sarxl(Register dst, Register src1, Register src2) {
|
||||
void Assembler::sarxl(Register dst, Address src1, Register src2) {
|
||||
assert(VM_Version::supports_bmi2(), "");
|
||||
InstructionMark im(this);
|
||||
InstructionAttr attributes(AVX_128bit, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ true);
|
||||
InstructionAttr attributes(AVX_128bit, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false);
|
||||
attributes.set_address_attributes(/* tuple_type */ EVEX_NOSCALE, /* input_size_in_bits */ EVEX_32bit);
|
||||
vex_prefix(src1, src2->encoding(), dst->encoding(), VEX_SIMD_F3, VEX_OPCODE_0F_38, &attributes);
|
||||
emit_int8((unsigned char)0xF7);
|
||||
@ -13786,7 +13911,7 @@ void Assembler::sarxl(Register dst, Address src1, Register src2) {
|
||||
|
||||
void Assembler::sarxq(Register dst, Register src1, Register src2) {
|
||||
assert(VM_Version::supports_bmi2(), "");
|
||||
InstructionAttr attributes(AVX_128bit, /* vex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ true);
|
||||
InstructionAttr attributes(AVX_128bit, /* vex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false);
|
||||
int encode = vex_prefix_and_encode(dst->encoding(), src2->encoding(), src1->encoding(), VEX_SIMD_F3, VEX_OPCODE_0F_38, &attributes, true);
|
||||
emit_int16((unsigned char)0xF7, (0xC0 | encode));
|
||||
}
|
||||
@ -13794,7 +13919,7 @@ void Assembler::sarxq(Register dst, Register src1, Register src2) {
|
||||
void Assembler::sarxq(Register dst, Address src1, Register src2) {
|
||||
assert(VM_Version::supports_bmi2(), "");
|
||||
InstructionMark im(this);
|
||||
InstructionAttr attributes(AVX_128bit, /* vex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ true);
|
||||
InstructionAttr attributes(AVX_128bit, /* vex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false);
|
||||
attributes.set_address_attributes(/* tuple_type */ EVEX_NOSCALE, /* input_size_in_bits */ EVEX_64bit);
|
||||
vex_prefix(src1, src2->encoding(), dst->encoding(), VEX_SIMD_F3, VEX_OPCODE_0F_38, &attributes);
|
||||
emit_int8((unsigned char)0xF7);
|
||||
@ -13803,7 +13928,7 @@ void Assembler::sarxq(Register dst, Address src1, Register src2) {
|
||||
|
||||
void Assembler::shlxl(Register dst, Register src1, Register src2) {
|
||||
assert(VM_Version::supports_bmi2(), "");
|
||||
InstructionAttr attributes(AVX_128bit, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ true);
|
||||
InstructionAttr attributes(AVX_128bit, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false);
|
||||
int encode = vex_prefix_and_encode(dst->encoding(), src2->encoding(), src1->encoding(), VEX_SIMD_66, VEX_OPCODE_0F_38, &attributes, true);
|
||||
emit_int16((unsigned char)0xF7, (0xC0 | encode));
|
||||
}
|
||||
@ -13811,7 +13936,7 @@ void Assembler::shlxl(Register dst, Register src1, Register src2) {
|
||||
void Assembler::shlxl(Register dst, Address src1, Register src2) {
|
||||
assert(VM_Version::supports_bmi2(), "");
|
||||
InstructionMark im(this);
|
||||
InstructionAttr attributes(AVX_128bit, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ true);
|
||||
InstructionAttr attributes(AVX_128bit, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false);
|
||||
attributes.set_address_attributes(/* tuple_type */ EVEX_NOSCALE, /* input_size_in_bits */ EVEX_32bit);
|
||||
vex_prefix(src1, src2->encoding(), dst->encoding(), VEX_SIMD_66, VEX_OPCODE_0F_38, &attributes);
|
||||
emit_int8((unsigned char)0xF7);
|
||||
@ -13820,7 +13945,7 @@ void Assembler::shlxl(Register dst, Address src1, Register src2) {
|
||||
|
||||
void Assembler::shlxq(Register dst, Register src1, Register src2) {
|
||||
assert(VM_Version::supports_bmi2(), "");
|
||||
InstructionAttr attributes(AVX_128bit, /* vex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ true);
|
||||
InstructionAttr attributes(AVX_128bit, /* vex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false);
|
||||
int encode = vex_prefix_and_encode(dst->encoding(), src2->encoding(), src1->encoding(), VEX_SIMD_66, VEX_OPCODE_0F_38, &attributes, true);
|
||||
emit_int16((unsigned char)0xF7, (0xC0 | encode));
|
||||
}
|
||||
@ -13828,7 +13953,7 @@ void Assembler::shlxq(Register dst, Register src1, Register src2) {
|
||||
void Assembler::shlxq(Register dst, Address src1, Register src2) {
|
||||
assert(VM_Version::supports_bmi2(), "");
|
||||
InstructionMark im(this);
|
||||
InstructionAttr attributes(AVX_128bit, /* vex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ true);
|
||||
InstructionAttr attributes(AVX_128bit, /* vex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false);
|
||||
attributes.set_address_attributes(/* tuple_type */ EVEX_NOSCALE, /* input_size_in_bits */ EVEX_64bit);
|
||||
vex_prefix(src1, src2->encoding(), dst->encoding(), VEX_SIMD_66, VEX_OPCODE_0F_38, &attributes);
|
||||
emit_int8((unsigned char)0xF7);
|
||||
@ -13837,7 +13962,7 @@ void Assembler::shlxq(Register dst, Address src1, Register src2) {
|
||||
|
||||
void Assembler::shrxl(Register dst, Register src1, Register src2) {
|
||||
assert(VM_Version::supports_bmi2(), "");
|
||||
InstructionAttr attributes(AVX_128bit, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ true);
|
||||
InstructionAttr attributes(AVX_128bit, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false);
|
||||
int encode = vex_prefix_and_encode(dst->encoding(), src2->encoding(), src1->encoding(), VEX_SIMD_F2, VEX_OPCODE_0F_38, &attributes, true);
|
||||
emit_int16((unsigned char)0xF7, (0xC0 | encode));
|
||||
}
|
||||
@ -13845,7 +13970,7 @@ void Assembler::shrxl(Register dst, Register src1, Register src2) {
|
||||
void Assembler::shrxl(Register dst, Address src1, Register src2) {
|
||||
assert(VM_Version::supports_bmi2(), "");
|
||||
InstructionMark im(this);
|
||||
InstructionAttr attributes(AVX_128bit, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ true);
|
||||
InstructionAttr attributes(AVX_128bit, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false);
|
||||
attributes.set_address_attributes(/* tuple_type */ EVEX_NOSCALE, /* input_size_in_bits */ EVEX_32bit);
|
||||
vex_prefix(src1, src2->encoding(), dst->encoding(), VEX_SIMD_F2, VEX_OPCODE_0F_38, &attributes);
|
||||
emit_int8((unsigned char)0xF7);
|
||||
@ -13854,7 +13979,7 @@ void Assembler::shrxl(Register dst, Address src1, Register src2) {
|
||||
|
||||
void Assembler::shrxq(Register dst, Register src1, Register src2) {
|
||||
assert(VM_Version::supports_bmi2(), "");
|
||||
InstructionAttr attributes(AVX_128bit, /* vex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ true);
|
||||
InstructionAttr attributes(AVX_128bit, /* vex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false);
|
||||
int encode = vex_prefix_and_encode(dst->encoding(), src2->encoding(), src1->encoding(), VEX_SIMD_F2, VEX_OPCODE_0F_38, &attributes, true);
|
||||
emit_int16((unsigned char)0xF7, (0xC0 | encode));
|
||||
}
|
||||
@ -13862,7 +13987,7 @@ void Assembler::shrxq(Register dst, Register src1, Register src2) {
|
||||
void Assembler::shrxq(Register dst, Address src1, Register src2) {
|
||||
assert(VM_Version::supports_bmi2(), "");
|
||||
InstructionMark im(this);
|
||||
InstructionAttr attributes(AVX_128bit, /* vex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ true);
|
||||
InstructionAttr attributes(AVX_128bit, /* vex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false);
|
||||
attributes.set_address_attributes(/* tuple_type */ EVEX_NOSCALE, /* input_size_in_bits */ EVEX_64bit);
|
||||
vex_prefix(src1, src2->encoding(), dst->encoding(), VEX_SIMD_F2, VEX_OPCODE_0F_38, &attributes);
|
||||
emit_int8((unsigned char)0xF7);
|
||||
@ -14623,11 +14748,7 @@ void Assembler::addq(Address dst, Register src) {
|
||||
|
||||
void Assembler::eaddq(Register dst, Address src1, Register src2, bool no_flags) {
|
||||
InstructionMark im(this);
|
||||
InstructionAttr attributes(AVX_128bit, /* vex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false);
|
||||
attributes.set_address_attributes(/* tuple_type */ EVEX_NOSCALE, /* input_size_in_bits */ EVEX_64bit);
|
||||
eevex_prefix_ndd(src1, dst->encoding(), src2->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F_3C /* MAP4 */, &attributes, no_flags);
|
||||
emit_int8(0x01);
|
||||
emit_operand(src2, src1, 0);
|
||||
emit_eevex_or_demote(dst, src1, src2, VEX_SIMD_NONE, VEX_OPCODE_0F_3C /* MAP4 */, EVEX_64bit, 0x01, no_flags, false /* is_map1 */, true /* is_commutative */);
|
||||
}
|
||||
|
||||
void Assembler::addq(Register dst, int32_t imm32) {
|
||||
@ -14656,11 +14777,7 @@ void Assembler::addq(Register dst, Register src) {
|
||||
}
|
||||
|
||||
void Assembler::eaddq(Register dst, Register src1, Register src2, bool no_flags) {
|
||||
InstructionAttr attributes(AVX_128bit, /* vex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false);
|
||||
// NDD shares its encoding bits with NDS bits for regular EVEX instruction.
|
||||
// Therefore, DST is passed as the second argument to minimize changes in the leaf level routine.
|
||||
(void) emit_eevex_prefix_or_demote_ndd(src1->encoding(), dst->encoding(), src2->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F_3C /* MAP4 */, &attributes, no_flags, true /* use_prefixq */);
|
||||
emit_arith(0x03, 0xC0, src1, src2);
|
||||
emit_eevex_prefix_or_demote_arith_ndd(dst, src1, src2, VEX_SIMD_NONE, VEX_OPCODE_0F_3C /* MAP4 */, EVEX_64bit, 0x03, 0xC0, no_flags, true /* is_commutative */);
|
||||
}
|
||||
|
||||
void Assembler::adcxq(Register dst, Register src) {
|
||||
@ -14753,11 +14870,7 @@ void Assembler::andq(Register dst, Register src) {
|
||||
}
|
||||
|
||||
void Assembler::eandq(Register dst, Register src1, Register src2, bool no_flags) {
|
||||
InstructionAttr attributes(AVX_128bit, /* vex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false);
|
||||
// NDD shares its encoding bits with NDS bits for regular EVEX instruction.
|
||||
// Therefore, DST is passed as the second argument to minimize changes in the leaf level routine.
|
||||
(void) emit_eevex_prefix_or_demote_ndd(src1->encoding(), dst->encoding(), src2->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F_3C /* MAP4 */, &attributes, no_flags, true /* use_prefixq */);
|
||||
emit_arith(0x23, 0xC0, src1, src2);
|
||||
emit_eevex_prefix_or_demote_arith_ndd(dst, src1, src2, VEX_SIMD_NONE, VEX_OPCODE_0F_3C /* MAP4 */, EVEX_64bit, 0x23, 0xC0, no_flags, true /* is_commutative */);
|
||||
}
|
||||
|
||||
void Assembler::andq(Address dst, Register src) {
|
||||
@ -14768,11 +14881,7 @@ void Assembler::andq(Address dst, Register src) {
|
||||
|
||||
void Assembler::eandq(Register dst, Address src1, Register src2, bool no_flags) {
|
||||
InstructionMark im(this);
|
||||
InstructionAttr attributes(AVX_128bit, /* vex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false);
|
||||
attributes.set_address_attributes(/* tuple_type */ EVEX_NOSCALE, /* input_size_in_bits */ EVEX_64bit);
|
||||
eevex_prefix_ndd(src1, dst->encoding(), src2->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F_3C /* MAP4 */, &attributes, no_flags);
|
||||
emit_int8(0x21);
|
||||
emit_operand(src2, src1, 0);
|
||||
emit_eevex_or_demote(dst, src1, src2, VEX_SIMD_NONE, VEX_OPCODE_0F_3C /* MAP4 */, EVEX_64bit, 0x21, no_flags, false /* is_map1 */, true /* is_commutative */);
|
||||
}
|
||||
|
||||
void Assembler::andnq(Register dst, Register src1, Register src2) {
|
||||
@ -14993,6 +15102,44 @@ void Assembler::cvttsd2siq(Register dst, Address src) {
|
||||
emit_operand(dst, src, 0);
|
||||
}
|
||||
|
||||
void Assembler::evcvttsd2sisl(Register dst, XMMRegister src) {
|
||||
assert(VM_Version::supports_avx10_2(), "");
|
||||
InstructionAttr attributes(AVX_128bit, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false);
|
||||
attributes.set_is_evex_instruction();
|
||||
int encode = vex_prefix_and_encode(dst->encoding(), 0, src->encoding(), VEX_SIMD_F2, VEX_OPCODE_MAP5, &attributes);
|
||||
emit_int16(0x6D, (0xC0 | encode));
|
||||
}
|
||||
|
||||
void Assembler::evcvttsd2sisl(Register dst, Address src) {
|
||||
assert(VM_Version::supports_avx10_2(), "");
|
||||
InstructionMark im(this);
|
||||
InstructionAttr attributes(AVX_128bit, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false);
|
||||
attributes.set_address_attributes(/* tuple_type */ EVEX_T1S, /* input_size_in_bits */ EVEX_64bit);
|
||||
attributes.set_is_evex_instruction();
|
||||
vex_prefix(src, 0, dst->encoding(), VEX_SIMD_F2, VEX_OPCODE_MAP5, &attributes);
|
||||
emit_int8((unsigned char)0x6D);
|
||||
emit_operand(dst, src, 0);
|
||||
}
|
||||
|
||||
void Assembler::evcvttsd2sisq(Register dst, XMMRegister src) {
|
||||
assert(VM_Version::supports_avx10_2(), "");
|
||||
InstructionAttr attributes(AVX_128bit, /* vex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false);
|
||||
attributes.set_is_evex_instruction();
|
||||
int encode = vex_prefix_and_encode(dst->encoding(), 0, src->encoding(), VEX_SIMD_F2, VEX_OPCODE_MAP5, &attributes);
|
||||
emit_int16(0x6D, (0xC0 | encode));
|
||||
}
|
||||
|
||||
void Assembler::evcvttsd2sisq(Register dst, Address src) {
|
||||
assert(VM_Version::supports_avx10_2(), "");
|
||||
InstructionMark im(this);
|
||||
InstructionAttr attributes(AVX_128bit, /* vex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false);
|
||||
attributes.set_address_attributes(/* tuple_type */ EVEX_T1S, /* input_size_in_bits */ EVEX_64bit);
|
||||
attributes.set_is_evex_instruction();
|
||||
vex_prefix(src, 0, dst->encoding(), VEX_SIMD_F2, VEX_OPCODE_MAP5, &attributes);
|
||||
emit_int8((unsigned char)0x6D);
|
||||
emit_operand(dst, src, 0);
|
||||
}
|
||||
|
||||
void Assembler::cvttsd2siq(Register dst, XMMRegister src) {
|
||||
InstructionAttr attributes(AVX_128bit, /* rex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false);
|
||||
int encode = simd_prefix_and_encode(as_XMMRegister(dst->encoding()), xnoreg, src, VEX_SIMD_F2, VEX_OPCODE_0F, &attributes);
|
||||
@ -15118,7 +15265,7 @@ void Assembler::eimulq(Register dst, Register src, bool no_flags) {
|
||||
}
|
||||
|
||||
void Assembler::eimulq(Register dst, Register src1, Register src2, bool no_flags) {
|
||||
emit_eevex_or_demote(dst->encoding(), src1->encoding(), src2->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F_3C /* MAP4 */, EVEX_64bit, 0xAF, no_flags, true /* is_map1 */, true /* swap */);
|
||||
emit_eevex_or_demote(dst->encoding(), src1->encoding(), src2->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F_3C /* MAP4 */, EVEX_64bit, 0xAF, no_flags, true /* is_map1 */, true /* swap */, true /* is_commutative */);
|
||||
}
|
||||
|
||||
void Assembler::imulq(Register src) {
|
||||
@ -15580,11 +15727,7 @@ void Assembler::orq(Address dst, Register src) {
|
||||
|
||||
void Assembler::eorq(Register dst, Address src1, Register src2, bool no_flags) {
|
||||
InstructionMark im(this);
|
||||
InstructionAttr attributes(AVX_128bit, /* vex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false);
|
||||
attributes.set_address_attributes(/* tuple_type */ EVEX_NOSCALE, /* input_size_in_bits */ EVEX_64bit);
|
||||
eevex_prefix_ndd(src1, dst->encoding(), src2->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F_3C /* MAP4 */, &attributes, no_flags);
|
||||
emit_int8(0x09);
|
||||
emit_operand(src2, src1, 0);
|
||||
emit_eevex_or_demote(dst, src1, src2, VEX_SIMD_NONE, VEX_OPCODE_0F_3C /* MAP4 */, EVEX_64bit, 0x09, no_flags, false /* is_map1 */, true /* is_commutative */);
|
||||
}
|
||||
|
||||
void Assembler::orq(Register dst, int32_t imm32) {
|
||||
@ -15624,13 +15767,8 @@ void Assembler::orq(Register dst, Register src) {
|
||||
}
|
||||
|
||||
void Assembler::eorq(Register dst, Register src1, Register src2, bool no_flags) {
|
||||
InstructionAttr attributes(AVX_128bit, /* vex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false);
|
||||
// NDD shares its encoding bits with NDS bits for regular EVEX instruction.
|
||||
// Therefore, DST is passed as the second argument to minimize changes in the leaf level routine.
|
||||
(void) emit_eevex_prefix_or_demote_ndd(src1->encoding(), dst->encoding(), src2->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F_3C /* MAP4 */, &attributes, no_flags, true /* use_prefixq */);
|
||||
emit_arith(0x0B, 0xC0, src1, src2);
|
||||
emit_eevex_prefix_or_demote_arith_ndd(dst, src1, src2, VEX_SIMD_NONE, VEX_OPCODE_0F_3C /* MAP4 */, EVEX_64bit, 0x0B, 0xC0, no_flags, true /* is_commutative */);
|
||||
}
|
||||
|
||||
void Assembler::popcntq(Register dst, Address src) {
|
||||
assert(VM_Version::supports_popcnt(), "must support");
|
||||
InstructionMark im(this);
|
||||
@ -16372,11 +16510,7 @@ void Assembler::xorq(Register dst, Register src) {
|
||||
}
|
||||
|
||||
void Assembler::exorq(Register dst, Register src1, Register src2, bool no_flags) {
|
||||
InstructionAttr attributes(AVX_128bit, /* vex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false);
|
||||
// NDD shares its encoding bits with NDS bits for regular EVEX instruction.
|
||||
// Therefore, DST is passed as the second argument to minimize changes in the leaf level routine.
|
||||
(void) emit_eevex_prefix_or_demote_ndd(src1->encoding(), dst->encoding(), src2->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F_3C /* MAP4 */, &attributes, no_flags, true /* use_prefixq */);
|
||||
emit_arith(0x33, 0xC0, src1, src2);
|
||||
emit_eevex_prefix_or_demote_arith_ndd(dst, src1, src2, VEX_SIMD_NONE, VEX_OPCODE_0F_3C /* MAP4 */, EVEX_64bit, 0x33, 0xC0, no_flags, true /* is_commutative */);
|
||||
}
|
||||
|
||||
void Assembler::xorq(Register dst, Address src) {
|
||||
@ -16430,11 +16564,7 @@ void Assembler::esetzucc(Condition cc, Register dst) {
|
||||
|
||||
void Assembler::exorq(Register dst, Address src1, Register src2, bool no_flags) {
|
||||
InstructionMark im(this);
|
||||
InstructionAttr attributes(AVX_128bit, /* vex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false);
|
||||
attributes.set_address_attributes(/* tuple_type */ EVEX_NOSCALE, /* input_size_in_bits */ EVEX_64bit);
|
||||
eevex_prefix_ndd(src1, dst->encoding(), src2->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F_3C /* MAP4 */, &attributes, no_flags);
|
||||
emit_int8(0x31);
|
||||
emit_operand(src2, src1, 0);
|
||||
emit_eevex_or_demote(dst, src1, src2, VEX_SIMD_NONE, VEX_OPCODE_0F_3C /* MAP4 */, EVEX_64bit, 0x31, no_flags, false /* is_map1 */, true /* is_commutative */);
|
||||
}
|
||||
|
||||
void InstructionAttr::set_address_attributes(int tuple_type, int input_size_in_bits) {
|
||||
|
||||
@ -807,14 +807,20 @@ private:
|
||||
int emit_eevex_prefix_or_demote_ndd(int dst_enc, int nds_enc, VexSimdPrefix pre, VexOpcode opc,
|
||||
InstructionAttr *attributes, bool no_flags = false, bool use_prefixq = false);
|
||||
|
||||
void emit_eevex_prefix_or_demote_arith_ndd(Register dst, Register src1, Register src2, VexSimdPrefix pre, VexOpcode opc,
|
||||
int size, int op1, int op2, bool no_flags = false, bool is_commutative = false);
|
||||
|
||||
void emit_eevex_prefix_or_demote_arith_ndd(Register dst, Register nds, int32_t imm32, VexSimdPrefix pre, VexOpcode opc,
|
||||
int size, int op1, int op2, bool no_flags);
|
||||
|
||||
void emit_eevex_or_demote(Register dst, Register src1, Address src2, VexSimdPrefix pre, VexOpcode opc,
|
||||
int size, int opcode_byte, bool no_flags = false, bool is_map1 = false);
|
||||
|
||||
void emit_eevex_or_demote(Register dst, Address src1, Register src2, VexSimdPrefix pre, VexOpcode opc,
|
||||
int size, int opcode_byte, bool no_flags = false, bool is_map1 = false, bool is_commutative = false);
|
||||
|
||||
void emit_eevex_or_demote(int dst_enc, int nds_enc, int src_enc, VexSimdPrefix pre, VexOpcode opc,
|
||||
int size, int opcode_byte, bool no_flags, bool is_map1 = false, bool swap = false);
|
||||
int size, int opcode_byte, bool no_flags, bool is_map1 = false, bool swap = false, bool is_commutative = false);
|
||||
|
||||
void emit_eevex_or_demote(int dst_enc, int nds_enc, int src_enc, int8_t imm8, VexSimdPrefix pre, VexOpcode opc,
|
||||
int size, int opcode_byte, bool no_flags, bool is_map1 = false);
|
||||
@ -1149,6 +1155,7 @@ private:
|
||||
void eandl(Register dst, Register src, int32_t imm32, bool no_flags);
|
||||
void andl(Register dst, Address src);
|
||||
void eandl(Register dst, Register src1, Address src2, bool no_flags);
|
||||
void eandl(Register dst, Address src1, Register src2, bool no_flags);
|
||||
void andl(Register dst, Register src);
|
||||
void eandl(Register dst, Register src1, Register src2, bool no_flags);
|
||||
void andl(Address dst, Register src);
|
||||
@ -1309,11 +1316,19 @@ private:
|
||||
void cvttsd2sil(Register dst, XMMRegister src);
|
||||
void cvttsd2siq(Register dst, Address src);
|
||||
void cvttsd2siq(Register dst, XMMRegister src);
|
||||
void evcvttsd2sisl(Register dst, XMMRegister src);
|
||||
void evcvttsd2sisl(Register dst, Address src);
|
||||
void evcvttsd2sisq(Register dst, XMMRegister src);
|
||||
void evcvttsd2sisq(Register dst, Address src);
|
||||
|
||||
// Convert with Truncation Scalar Single-Precision Floating-Point Value to Doubleword Integer
|
||||
void cvttss2sil(Register dst, XMMRegister src);
|
||||
void cvttss2siq(Register dst, XMMRegister src);
|
||||
void cvtss2sil(Register dst, XMMRegister src);
|
||||
void evcvttss2sisl(Register dst, XMMRegister src);
|
||||
void evcvttss2sisl(Register dst, Address src);
|
||||
void evcvttss2sisq(Register dst, XMMRegister src);
|
||||
void evcvttss2sisq(Register dst, Address src);
|
||||
|
||||
// Convert vector double to int
|
||||
void cvttpd2dq(XMMRegister dst, XMMRegister src);
|
||||
@ -1325,7 +1340,11 @@ private:
|
||||
// Convert vector float to int/long
|
||||
void vcvtps2dq(XMMRegister dst, XMMRegister src, int vector_len);
|
||||
void vcvttps2dq(XMMRegister dst, XMMRegister src, int vector_len);
|
||||
void evcvttps2dqs(XMMRegister dst, XMMRegister src, int vector_len);
|
||||
void evcvttps2dqs(XMMRegister dst, Address src, int vector_len);
|
||||
void evcvttps2qq(XMMRegister dst, XMMRegister src, int vector_len);
|
||||
void evcvttps2qqs(XMMRegister dst, XMMRegister src, int vector_len);
|
||||
void evcvttps2qqs(XMMRegister dst, Address src, int vector_len);
|
||||
|
||||
// Convert vector long to vector FP
|
||||
void evcvtqq2ps(XMMRegister dst, XMMRegister src, int vector_len);
|
||||
@ -1334,9 +1353,13 @@ private:
|
||||
// Convert vector double to long
|
||||
void evcvtpd2qq(XMMRegister dst, XMMRegister src, int vector_len);
|
||||
void evcvttpd2qq(XMMRegister dst, XMMRegister src, int vector_len);
|
||||
void evcvttpd2qqs(XMMRegister dst, XMMRegister src, int vector_len);
|
||||
void evcvttpd2qqs(XMMRegister dst, Address src, int vector_len);
|
||||
|
||||
// Convert vector double to int
|
||||
void vcvttpd2dq(XMMRegister dst, XMMRegister src, int vector_len);
|
||||
void evcvttpd2dqs(XMMRegister dst, XMMRegister src, int vector_len);
|
||||
void evcvttpd2dqs(XMMRegister dst, Address src, int vector_len);
|
||||
|
||||
// Evex casts with truncation
|
||||
void evpmovwb(XMMRegister dst, XMMRegister src, int vector_len);
|
||||
|
||||
@ -207,10 +207,10 @@ void MonitorEnterStub::emit_code(LIR_Assembler* ce) {
|
||||
|
||||
void MonitorExitStub::emit_code(LIR_Assembler* ce) {
|
||||
__ bind(_entry);
|
||||
if (_compute_lock) {
|
||||
// lock_reg was destroyed by fast unlocking attempt => recompute it
|
||||
ce->monitor_address(_monitor_ix, _lock_reg);
|
||||
}
|
||||
|
||||
// lock_reg was destroyed by fast unlocking attempt => recompute it
|
||||
ce->monitor_address(_monitor_ix, _lock_reg);
|
||||
|
||||
ce->store_parameter(_lock_reg->as_register(), 0);
|
||||
// note: non-blocking leaf routine => no call info needed
|
||||
StubId exit_id;
|
||||
|
||||
@ -412,7 +412,7 @@ int LIR_Assembler::emit_unwind_handler() {
|
||||
MonitorExitStub* stub = nullptr;
|
||||
if (method()->is_synchronized()) {
|
||||
monitor_address(0, FrameMap::rax_opr);
|
||||
stub = new MonitorExitStub(FrameMap::rax_opr, true, 0);
|
||||
stub = new MonitorExitStub(FrameMap::rax_opr, 0);
|
||||
__ unlock_object(rdi, rsi, rax, *stub->entry());
|
||||
__ bind(*stub->continuation());
|
||||
}
|
||||
@ -2730,7 +2730,6 @@ void LIR_Assembler::emit_lock(LIR_OpLock* op) {
|
||||
Register hdr = op->hdr_opr()->as_register();
|
||||
Register lock = op->lock_opr()->as_register();
|
||||
if (op->code() == lir_lock) {
|
||||
assert(BasicLock::displaced_header_offset_in_bytes() == 0, "lock_reg must point to the displaced header");
|
||||
Register tmp = op->scratch_opr()->as_register();
|
||||
// add debug info for NullPointerException only if one is possible
|
||||
int null_check_offset = __ lock_object(hdr, obj, lock, tmp, *op->stub()->entry());
|
||||
@ -2739,7 +2738,6 @@ void LIR_Assembler::emit_lock(LIR_OpLock* op) {
|
||||
}
|
||||
// done
|
||||
} else if (op->code() == lir_unlock) {
|
||||
assert(BasicLock::displaced_header_offset_in_bytes() == 0, "lock_reg must point to the displaced header");
|
||||
__ unlock_object(hdr, obj, lock, *op->stub()->entry());
|
||||
} else {
|
||||
Unimplemented();
|
||||
|
||||
@ -41,32 +41,32 @@
|
||||
#include "utilities/checkedCast.hpp"
|
||||
#include "utilities/globalDefinitions.hpp"
|
||||
|
||||
int C1_MacroAssembler::lock_object(Register hdr, Register obj, Register disp_hdr, Register tmp, Label& slow_case) {
|
||||
int C1_MacroAssembler::lock_object(Register hdr, Register obj, Register basic_lock, Register tmp, Label& slow_case) {
|
||||
assert(hdr == rax, "hdr must be rax, for the cmpxchg instruction");
|
||||
assert_different_registers(hdr, obj, disp_hdr, tmp);
|
||||
assert_different_registers(hdr, obj, basic_lock, tmp);
|
||||
int null_check_offset = -1;
|
||||
|
||||
verify_oop(obj);
|
||||
|
||||
// save object being locked into the BasicObjectLock
|
||||
movptr(Address(disp_hdr, BasicObjectLock::obj_offset()), obj);
|
||||
movptr(Address(basic_lock, BasicObjectLock::obj_offset()), obj);
|
||||
|
||||
null_check_offset = offset();
|
||||
|
||||
lightweight_lock(disp_hdr, obj, hdr, tmp, slow_case);
|
||||
lightweight_lock(basic_lock, obj, hdr, tmp, slow_case);
|
||||
|
||||
return null_check_offset;
|
||||
}
|
||||
|
||||
void C1_MacroAssembler::unlock_object(Register hdr, Register obj, Register disp_hdr, Label& slow_case) {
|
||||
assert(disp_hdr == rax, "disp_hdr must be rax, for the cmpxchg instruction");
|
||||
assert(hdr != obj && hdr != disp_hdr && obj != disp_hdr, "registers must be different");
|
||||
void C1_MacroAssembler::unlock_object(Register hdr, Register obj, Register basic_lock, Label& slow_case) {
|
||||
assert(basic_lock == rax, "basic_lock must be rax, for the cmpxchg instruction");
|
||||
assert(hdr != obj && hdr != basic_lock && obj != basic_lock, "registers must be different");
|
||||
|
||||
// load object
|
||||
movptr(obj, Address(disp_hdr, BasicObjectLock::obj_offset()));
|
||||
movptr(obj, Address(basic_lock, BasicObjectLock::obj_offset()));
|
||||
verify_oop(obj);
|
||||
|
||||
lightweight_unlock(obj, disp_hdr, hdr, slow_case);
|
||||
lightweight_unlock(obj, rax, hdr, slow_case);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@ -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
|
||||
@ -46,17 +46,17 @@
|
||||
void initialize_body(Register obj, Register len_in_bytes, int hdr_size_in_bytes, Register t1);
|
||||
|
||||
// locking
|
||||
// hdr : must be rax, contents destroyed
|
||||
// obj : must point to the object to lock, contents preserved
|
||||
// disp_hdr: must point to the displaced header location, contents preserved
|
||||
// hdr : must be rax, contents destroyed
|
||||
// obj : must point to the object to lock, contents preserved
|
||||
// basic_lock: must point to the basic lock, contents preserved
|
||||
// returns code offset at which to add null check debug information
|
||||
int lock_object (Register swap, Register obj, Register disp_hdr, Register tmp, Label& slow_case);
|
||||
int lock_object (Register swap, Register obj, Register basic_lock, Register tmp, Label& slow_case);
|
||||
|
||||
// unlocking
|
||||
// hdr : contents destroyed
|
||||
// obj : must point to the object to lock, contents preserved
|
||||
// disp_hdr: must be eax & must point to the displaced header location, contents destroyed
|
||||
void unlock_object(Register swap, Register obj, Register lock, Label& slow_case);
|
||||
// hdr : contents destroyed
|
||||
// obj : must point to the object to lock, contents preserved
|
||||
// basic_lock: must be eax & must point to the basic lock, contents destroyed
|
||||
void unlock_object(Register swap, Register obj, Register basic_lock, Label& slow_case);
|
||||
|
||||
void initialize_object(
|
||||
Register obj, // result: pointer to object after successful allocation
|
||||
|
||||
@ -5053,12 +5053,12 @@ void C2_MacroAssembler::vector_cast_int_to_subword(BasicType to_elem_bt, XMMRegi
|
||||
}
|
||||
vpackuswb(dst, dst, zero, vec_enc);
|
||||
break;
|
||||
default: assert(false, "%s", type2name(to_elem_bt));
|
||||
default: assert(false, "Unexpected basic type for target of vector cast int to subword: %s", type2name(to_elem_bt));
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Algorithm for vector D2L and F2I conversions:-
|
||||
* Algorithm for vector D2L and F2I conversions (AVX 10.2 unsupported):-
|
||||
* a) Perform vector D2L/F2I cast.
|
||||
* b) Choose fast path if none of the result vector lane contains 0x80000000 value.
|
||||
* It signifies that source value could be any of the special floating point
|
||||
@ -5096,7 +5096,7 @@ void C2_MacroAssembler::vector_castF2X_evex(BasicType to_elem_bt, XMMRegister ds
|
||||
case T_BYTE:
|
||||
evpmovdb(dst, dst, vec_enc);
|
||||
break;
|
||||
default: assert(false, "%s", type2name(to_elem_bt));
|
||||
default: assert(false, "Unexpected basic type for target of vector castF2X EVEX: %s", type2name(to_elem_bt));
|
||||
}
|
||||
}
|
||||
|
||||
@ -5143,7 +5143,7 @@ void C2_MacroAssembler::vector_castD2X_evex(BasicType to_elem_bt, XMMRegister ds
|
||||
evpmovsqd(dst, dst, vec_enc);
|
||||
evpmovdb(dst, dst, vec_enc);
|
||||
break;
|
||||
default: assert(false, "%s", type2name(to_elem_bt));
|
||||
default: assert(false, "Unexpected basic type for target of vector castD2X AVX512DQ EVEX: %s", type2name(to_elem_bt));
|
||||
}
|
||||
} else {
|
||||
assert(type2aelembytes(to_elem_bt) <= 4, "");
|
||||
@ -5158,11 +5158,91 @@ void C2_MacroAssembler::vector_castD2X_evex(BasicType to_elem_bt, XMMRegister ds
|
||||
case T_BYTE:
|
||||
evpmovdb(dst, dst, vec_enc);
|
||||
break;
|
||||
default: assert(false, "%s", type2name(to_elem_bt));
|
||||
default: assert(false, "Unexpected basic type for target of vector castD2X EVEX: %s", type2name(to_elem_bt));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void C2_MacroAssembler::vector_castF2X_avx10(BasicType to_elem_bt, XMMRegister dst, XMMRegister src, int vec_enc) {
|
||||
switch(to_elem_bt) {
|
||||
case T_LONG:
|
||||
evcvttps2qqs(dst, src, vec_enc);
|
||||
break;
|
||||
case T_INT:
|
||||
evcvttps2dqs(dst, src, vec_enc);
|
||||
break;
|
||||
case T_SHORT:
|
||||
evcvttps2dqs(dst, src, vec_enc);
|
||||
evpmovdw(dst, dst, vec_enc);
|
||||
break;
|
||||
case T_BYTE:
|
||||
evcvttps2dqs(dst, src, vec_enc);
|
||||
evpmovdb(dst, dst, vec_enc);
|
||||
break;
|
||||
default: assert(false, "Unexpected basic type for target of vector castF2X AVX10 (reg src): %s", type2name(to_elem_bt));
|
||||
}
|
||||
}
|
||||
|
||||
void C2_MacroAssembler::vector_castF2X_avx10(BasicType to_elem_bt, XMMRegister dst, Address src, int vec_enc) {
|
||||
switch(to_elem_bt) {
|
||||
case T_LONG:
|
||||
evcvttps2qqs(dst, src, vec_enc);
|
||||
break;
|
||||
case T_INT:
|
||||
evcvttps2dqs(dst, src, vec_enc);
|
||||
break;
|
||||
case T_SHORT:
|
||||
evcvttps2dqs(dst, src, vec_enc);
|
||||
evpmovdw(dst, dst, vec_enc);
|
||||
break;
|
||||
case T_BYTE:
|
||||
evcvttps2dqs(dst, src, vec_enc);
|
||||
evpmovdb(dst, dst, vec_enc);
|
||||
break;
|
||||
default: assert(false, "Unexpected basic type for target of vector castF2X AVX10 (mem src): %s", type2name(to_elem_bt));
|
||||
}
|
||||
}
|
||||
|
||||
void C2_MacroAssembler::vector_castD2X_avx10(BasicType to_elem_bt, XMMRegister dst, XMMRegister src, int vec_enc) {
|
||||
switch(to_elem_bt) {
|
||||
case T_LONG:
|
||||
evcvttpd2qqs(dst, src, vec_enc);
|
||||
break;
|
||||
case T_INT:
|
||||
evcvttpd2dqs(dst, src, vec_enc);
|
||||
break;
|
||||
case T_SHORT:
|
||||
evcvttpd2dqs(dst, src, vec_enc);
|
||||
evpmovdw(dst, dst, vec_enc);
|
||||
break;
|
||||
case T_BYTE:
|
||||
evcvttpd2dqs(dst, src, vec_enc);
|
||||
evpmovdb(dst, dst, vec_enc);
|
||||
break;
|
||||
default: assert(false, "Unexpected basic type for target of vector castD2X AVX10 (reg src): %s", type2name(to_elem_bt));
|
||||
}
|
||||
}
|
||||
|
||||
void C2_MacroAssembler::vector_castD2X_avx10(BasicType to_elem_bt, XMMRegister dst, Address src, int vec_enc) {
|
||||
switch(to_elem_bt) {
|
||||
case T_LONG:
|
||||
evcvttpd2qqs(dst, src, vec_enc);
|
||||
break;
|
||||
case T_INT:
|
||||
evcvttpd2dqs(dst, src, vec_enc);
|
||||
break;
|
||||
case T_SHORT:
|
||||
evcvttpd2dqs(dst, src, vec_enc);
|
||||
evpmovdw(dst, dst, vec_enc);
|
||||
break;
|
||||
case T_BYTE:
|
||||
evcvttpd2dqs(dst, src, vec_enc);
|
||||
evpmovdb(dst, dst, vec_enc);
|
||||
break;
|
||||
default: assert(false, "Unexpected basic type for target of vector castD2X AVX10 (mem src): %s", type2name(to_elem_bt));
|
||||
}
|
||||
}
|
||||
|
||||
void C2_MacroAssembler::vector_round_double_evex(XMMRegister dst, XMMRegister src,
|
||||
AddressLiteral double_sign_flip, AddressLiteral new_mxcsr, int vec_enc,
|
||||
Register tmp, XMMRegister xtmp1, XMMRegister xtmp2, KRegister ktmp1, KRegister ktmp2) {
|
||||
|
||||
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