Merge remote-tracking branch 'origin/master' into JDK-8366659-OM-wait-suspend-deadlock

This commit is contained in:
Anton Artemov 2025-12-01 10:32:04 +00:00
commit 8283d9c0c2
804 changed files with 38160 additions and 14146 deletions

View File

@ -535,6 +535,8 @@ failure. This helps to reproduce intermittent test failures. Defaults to
<h4 id="report">REPORT</h4>
<p>Use this report style when reporting test results (sent to JTReg as
<code>-report</code>). Defaults to <code>files</code>.</p>
<h4 id="manual">MANUAL</h4>
<p>Set to <code>true</code> to execute manual tests only.</p>
<h3 id="gtest-keywords">Gtest keywords</h3>
<h4 id="repeat">REPEAT</h4>
<p>The number of times to repeat the tests

View File

@ -512,6 +512,10 @@ helps to reproduce intermittent test failures. Defaults to 0.
Use this report style when reporting test results (sent to JTReg as `-report`).
Defaults to `files`.
#### MANUAL
Set to `true` to execute manual tests only.
### Gtest keywords
#### REPEAT

View File

@ -206,7 +206,7 @@ $(eval $(call ParseKeywordVariable, JTREG, \
SINGLE_KEYWORDS := JOBS TIMEOUT_FACTOR FAILURE_HANDLER_TIMEOUT \
TEST_MODE ASSERT VERBOSE RETAIN TEST_THREAD_FACTORY JVMTI_STRESS_AGENT \
MAX_MEM RUN_PROBLEM_LISTS RETRY_COUNT REPEAT_COUNT MAX_OUTPUT REPORT \
AOT_JDK $(CUSTOM_JTREG_SINGLE_KEYWORDS), \
AOT_JDK MANUAL $(CUSTOM_JTREG_SINGLE_KEYWORDS), \
STRING_KEYWORDS := OPTIONS JAVA_OPTIONS VM_OPTIONS KEYWORDS \
EXTRA_PROBLEM_LISTS LAUNCHER_OPTIONS \
$(CUSTOM_JTREG_STRING_KEYWORDS), \
@ -911,7 +911,13 @@ define SetupRunJtregTestBody
-vmoption:-Dtest.boot.jdk="$$(BOOT_JDK)" \
-vmoption:-Djava.io.tmpdir="$$($1_TEST_TMP_DIR)"
$1_JTREG_BASIC_OPTIONS += -automatic -ignore:quiet
$1_JTREG_BASIC_OPTIONS += -ignore:quiet
ifeq ($$(JTREG_MANUAL), true)
$1_JTREG_BASIC_OPTIONS += -manual
else
$1_JTREG_BASIC_OPTIONS += -automatic
endif
# Make it possible to specify the JIB_DATA_DIR for tests using the
# JIB Artifact resolver
@ -1151,6 +1157,7 @@ define SetupRunJtregTestBody
$$(EXPR) $$($1_PASSED) + $$($1_FAILED) + $$($1_ERROR) + $$($1_SKIPPED))) \
, \
$$(eval $1_PASSED_AND_RUNTIME_SKIPPED := 0) \
$$(eval $1_PASSED := 0) \
$$(eval $1_RUNTIME_SKIPPED := 0) \
$$(eval $1_SKIPPED := 0) \
$$(eval $1_FAILED := 0) \

View File

@ -282,10 +282,17 @@ AC_DEFUN([FLAGS_SETUP_OPTIMIZATION],
C_O_FLAG_DEBUG_JVM="-O0"
C_O_FLAG_NONE="-O0"
if test "x$TOOLCHAIN_TYPE" = xgcc; then
C_O_FLAG_LTO="-flto=auto -fuse-linker-plugin -fno-strict-aliasing -fno-fat-lto-objects"
else
C_O_FLAG_LTO="-flto -fno-strict-aliasing"
fi
if test "x$TOOLCHAIN_TYPE" = xclang && test "x$OPENJDK_TARGET_OS" = xaix; then
C_O_FLAG_HIGHEST_JVM="${C_O_FLAG_HIGHEST_JVM} -finline-functions"
C_O_FLAG_HIGHEST="${C_O_FLAG_HIGHEST} -finline-functions"
C_O_FLAG_HI="${C_O_FLAG_HI} -finline-functions"
C_O_FLAG_LTO="${C_O_FLAG_LTO} -ffat-lto-objects"
fi
# -D_FORTIFY_SOURCE=2 hardening option needs optimization (at least -O1) enabled
@ -317,6 +324,7 @@ AC_DEFUN([FLAGS_SETUP_OPTIMIZATION],
C_O_FLAG_DEBUG_JVM=""
C_O_FLAG_NONE="-Od"
C_O_FLAG_SIZE="-O1"
C_O_FLAG_LTO="-GL"
fi
# Now copy to C++ flags
@ -328,6 +336,7 @@ AC_DEFUN([FLAGS_SETUP_OPTIMIZATION],
CXX_O_FLAG_DEBUG_JVM="$C_O_FLAG_DEBUG_JVM"
CXX_O_FLAG_NONE="$C_O_FLAG_NONE"
CXX_O_FLAG_SIZE="$C_O_FLAG_SIZE"
CXX_O_FLAG_LTO="$C_O_FLAG_LTO"
# Adjust optimization flags according to debug level.
case $DEBUG_LEVEL in
@ -360,12 +369,15 @@ AC_DEFUN([FLAGS_SETUP_OPTIMIZATION],
AC_SUBST(C_O_FLAG_NORM)
AC_SUBST(C_O_FLAG_NONE)
AC_SUBST(C_O_FLAG_SIZE)
AC_SUBST(C_O_FLAG_LTO)
AC_SUBST(CXX_O_FLAG_HIGHEST_JVM)
AC_SUBST(CXX_O_FLAG_HIGHEST)
AC_SUBST(CXX_O_FLAG_HI)
AC_SUBST(CXX_O_FLAG_NORM)
AC_SUBST(CXX_O_FLAG_NONE)
AC_SUBST(CXX_O_FLAG_SIZE)
AC_SUBST(CXX_O_FLAG_LTO)
])
AC_DEFUN([FLAGS_SETUP_CFLAGS],

View File

@ -50,7 +50,14 @@ AC_DEFUN([FLAGS_SETUP_LDFLAGS_HELPER],
# add -z,relro (mark relocations read only) for all libs
# add -z,now ("full relro" - more of the Global Offset Table GOT is marked read only)
# add --no-as-needed to disable default --as-needed link flag on some GCC toolchains
# add --icf=all (Identical Code Folding — merges identical functions)
BASIC_LDFLAGS="-Wl,-z,defs -Wl,-z,relro -Wl,-z,now -Wl,--no-as-needed -Wl,--exclude-libs,ALL"
if test "x$LINKER_TYPE" = "xgold"; then
if test x$DEBUG_LEVEL = xrelease; then
BASIC_LDFLAGS="$BASIC_LDFLAGS -Wl,--icf=all"
fi
fi
# Linux : remove unused code+data in link step
if test "x$ENABLE_LINKTIME_GC" = xtrue; then
if test "x$OPENJDK_TARGET_CPU" = xs390x; then
@ -61,6 +68,7 @@ AC_DEFUN([FLAGS_SETUP_LDFLAGS_HELPER],
fi
BASIC_LDFLAGS_JVM_ONLY=""
LDFLAGS_LTO="-flto=auto -fuse-linker-plugin -fno-strict-aliasing"
LDFLAGS_CXX_PARTIAL_LINKING="$MACHINE_FLAG -r"
@ -68,6 +76,7 @@ AC_DEFUN([FLAGS_SETUP_LDFLAGS_HELPER],
BASIC_LDFLAGS_JVM_ONLY="-mno-omit-leaf-frame-pointer -mstack-alignment=16 \
-fPIC"
LDFLAGS_LTO="-flto=auto -fuse-linker-plugin -fno-strict-aliasing"
LDFLAGS_CXX_PARTIAL_LINKING="$MACHINE_FLAG -r"
if test "x$OPENJDK_TARGET_OS" = xlinux; then
@ -87,6 +96,7 @@ AC_DEFUN([FLAGS_SETUP_LDFLAGS_HELPER],
BASIC_LDFLAGS="-opt:ref"
BASIC_LDFLAGS_JDK_ONLY="-incremental:no"
BASIC_LDFLAGS_JVM_ONLY="-opt:icf,8 -subsystem:windows"
LDFLAGS_LTO="-LTCG:INCREMENTAL"
fi
if (test "x$TOOLCHAIN_TYPE" = xgcc || test "x$TOOLCHAIN_TYPE" = xclang) \
@ -148,6 +158,7 @@ AC_DEFUN([FLAGS_SETUP_LDFLAGS_HELPER],
# Export some intermediate variables for compatibility
LDFLAGS_CXX_JDK="$DEBUGLEVEL_LDFLAGS_JDK_ONLY"
AC_SUBST(LDFLAGS_LTO)
AC_SUBST(LDFLAGS_CXX_JDK)
AC_SUBST(LDFLAGS_CXX_PARTIAL_LINKING)
])

View File

@ -513,12 +513,14 @@ C_O_FLAG_HI := @C_O_FLAG_HI@
C_O_FLAG_NORM := @C_O_FLAG_NORM@
C_O_FLAG_NONE := @C_O_FLAG_NONE@
C_O_FLAG_SIZE := @C_O_FLAG_SIZE@
C_O_FLAG_LTO := @C_O_FLAG_LTO@
CXX_O_FLAG_HIGHEST_JVM := @CXX_O_FLAG_HIGHEST_JVM@
CXX_O_FLAG_HIGHEST := @CXX_O_FLAG_HIGHEST@
CXX_O_FLAG_HI := @CXX_O_FLAG_HI@
CXX_O_FLAG_NORM := @CXX_O_FLAG_NORM@
CXX_O_FLAG_NONE := @CXX_O_FLAG_NONE@
CXX_O_FLAG_SIZE := @CXX_O_FLAG_SIZE@
CXX_O_FLAG_LTO := @CXX_O_FLAG_LTO@
GENDEPS_FLAGS := @GENDEPS_FLAGS@
@ -587,6 +589,9 @@ LDFLAGS_CXX_JDK := @LDFLAGS_CXX_JDK@
# LDFLAGS specific to partial linking.
LDFLAGS_CXX_PARTIAL_LINKING := @LDFLAGS_CXX_PARTIAL_LINKING@
# LDFLAGS specific to link time optimization
LDFLAGS_LTO := @LDFLAGS_LTO@
# Sometimes a different linker is needed for c++ libs
LDCXX := @LDCXX@
# The flags for linking libstdc++ linker.

View File

@ -516,6 +516,7 @@ AC_DEFUN([TOOLCHAIN_EXTRACT_LD_VERSION],
if [ [[ "$LINKER_VERSION_STRING" == *gold* ]] ]; then
[ LINKER_VERSION_NUMBER=`$ECHO $LINKER_VERSION_STRING | \
$SED -e 's/.* \([0-9][0-9]*\(\.[0-9][0-9]*\)*\).*) .*/\1/'` ]
LINKER_TYPE=gold
else
[ LINKER_VERSION_NUMBER=`$ECHO $LINKER_VERSION_STRING | \
$SED -e 's/.* \([0-9][0-9]*\(\.[0-9][0-9]*\)*\).*/\1/'` ]

View File

@ -98,6 +98,7 @@ include native/Paths.gmk
# SYSROOT_CFLAGS the compiler flags for using the specific sysroot
# SYSROOT_LDFLAGS the linker flags for using the specific sysroot
# OPTIMIZATION sets optimization level to NONE, LOW, HIGH, HIGHEST, HIGHEST_JVM, SIZE
# LINK_TIME_OPTIMIZATION if set to true, enables link time optimization
# DISABLED_WARNINGS_<toolchain> Disable the given warnings for the specified toolchain
# DISABLED_WARNINGS_<toolchain>_<OS> Disable the given warnings for the specified
# toolchain and target OS

View File

@ -194,6 +194,11 @@ define SetupCompilerFlags
$1_EXTRA_CXXFLAGS += $(CFLAGS_WARNINGS_ARE_ERRORS)
endif
ifeq (true, $$($1_LINK_TIME_OPTIMIZATION))
$1_EXTRA_CFLAGS += $(C_O_FLAG_LTO)
$1_EXTRA_CXXFLAGS += $(CXX_O_FLAG_LTO)
endif
ifeq (NONE, $$($1_OPTIMIZATION))
$1_OPT_CFLAGS := $(C_O_FLAG_NONE)
$1_OPT_CXXFLAGS := $(CXX_O_FLAG_NONE)
@ -222,6 +227,10 @@ define SetupLinkerFlags
# Pickup extra OPENJDK_TARGET_OS_TYPE, OPENJDK_TARGET_OS and TOOLCHAIN_TYPE
# dependent variables for LDFLAGS and LIBS, and additionally the pair dependent
# TOOLCHAIN_TYPE plus OPENJDK_TARGET_OS
ifeq ($$($1_LINK_TIME_OPTIMIZATION), true)
$1_EXTRA_LDFLAGS += $(LDFLAGS_LTO)
endif
$1_EXTRA_LDFLAGS += $$($1_LDFLAGS_$(OPENJDK_TARGET_OS_TYPE)) $$($1_LDFLAGS_$(OPENJDK_TARGET_OS)) \
$$($1_LDFLAGS_$(TOOLCHAIN_TYPE)) $$($1_LDFLAGS_$(TOOLCHAIN_TYPE)_$(OPENJDK_TARGET_OS))
$1_EXTRA_LIBS += $$($1_LIBS_$(OPENJDK_TARGET_OS_TYPE)) $$($1_LIBS_$(OPENJDK_TARGET_OS)) \

View File

@ -234,6 +234,7 @@ $(eval $(call SetupJdkLibrary, BUILD_LIBJVM, \
LDFLAGS := $(JVM_LDFLAGS), \
LIBS := $(JVM_LIBS), \
OPTIMIZATION := $(JVM_OPTIMIZATION), \
LINK_TIME_OPTIMIZATION := $(JVM_LTO), \
OBJECT_DIR := $(JVM_OUTPUTDIR)/objs, \
STRIPFLAGS := $(JVM_STRIPFLAGS), \
EMBED_MANIFEST := true, \

View File

@ -175,22 +175,12 @@ ifeq ($(call check-jvm-feature, link-time-opt), true)
# Set JVM_OPTIMIZATION directly so other jvm-feature flags can override it
# later on if desired
JVM_OPTIMIZATION := HIGHEST_JVM
ifeq ($(call isCompiler, gcc), true)
JVM_CFLAGS_FEATURES += -flto=auto -fuse-linker-plugin -fno-strict-aliasing \
-fno-fat-lto-objects
JVM_LDFLAGS_FEATURES += $(CXX_O_FLAG_HIGHEST_JVM) -flto=auto \
-fuse-linker-plugin -fno-strict-aliasing
else ifeq ($(call isCompiler, clang), true)
JVM_CFLAGS_FEATURES += -flto -fno-strict-aliasing
ifeq ($(call isBuildOs, aix), true)
JVM_CFLAGS_FEATURES += -ffat-lto-objects
endif
JVM_LDFLAGS_FEATURES += $(CXX_O_FLAG_HIGHEST_JVM) -flto -fno-strict-aliasing
else ifeq ($(call isCompiler, microsoft), true)
JVM_CFLAGS_FEATURES += -GL
JVM_LDFLAGS_FEATURES += -LTCG:INCREMENTAL
JVM_LTO := true
ifneq ($(call isCompiler, microsoft), true)
JVM_LDFLAGS_FEATURES += $(CXX_O_FLAG_HIGHEST_JVM)
endif
else
JVM_LTO := false
ifeq ($(call isCompiler, gcc), true)
JVM_LDFLAGS_FEATURES += -O1
endif

View File

@ -226,6 +226,7 @@ ifeq ($(ENABLE_HEADLESS_ONLY), false)
EXCLUDE_FILES := imageioJPEG.c jpegdecoder.c pngtest.c, \
EXCLUDES := $(LIBSPLASHSCREEN_EXCLUDES), \
OPTIMIZATION := SIZE, \
LINK_TIME_OPTIMIZATION := true, \
CFLAGS := $(LIBSPLASHSCREEN_CFLAGS) \
$(GIFLIB_CFLAGS) $(LIBJPEG_CFLAGS) $(PNG_CFLAGS) $(LIBZ_CFLAGS) \
$(ICONV_CFLAGS), \
@ -236,7 +237,7 @@ ifeq ($(ENABLE_HEADLESS_ONLY), false)
DISABLED_WARNINGS_gcc_dgif_lib.c := sign-compare, \
DISABLED_WARNINGS_gcc_jcmaster.c := implicit-fallthrough, \
DISABLED_WARNINGS_gcc_jdphuff.c := shift-negative-value, \
DISABLED_WARNINGS_gcc_png.c := maybe-uninitialized unused-function, \
DISABLED_WARNINGS_gcc_png.c := maybe-uninitialized, \
DISABLED_WARNINGS_gcc_pngerror.c := maybe-uninitialized, \
DISABLED_WARNINGS_gcc_splashscreen_gfx_impl.c := implicit-fallthrough \
maybe-uninitialized, \
@ -247,7 +248,6 @@ ifeq ($(ENABLE_HEADLESS_ONLY), false)
DISABLED_WARNINGS_clang := deprecated-non-prototype, \
DISABLED_WARNINGS_clang_dgif_lib.c := sign-compare, \
DISABLED_WARNINGS_clang_gzwrite.c := format-nonliteral, \
DISABLED_WARNINGS_clang_png.c := unused-function, \
DISABLED_WARNINGS_clang_splashscreen_impl.c := sign-compare \
unused-but-set-variable unused-function, \
DISABLED_WARNINGS_clang_splashscreen_png.c := \

View File

@ -1,6 +1,7 @@
//
// Copyright (c) 2003, 2025, Oracle and/or its affiliates. All rights reserved.
// Copyright (c) 2014, 2024, Red Hat, Inc. All rights reserved.
// Copyright 2025 Arm Limited and/or its affiliates.
// DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
//
// This code is free software; you can redistribute it and/or modify it
@ -1194,15 +1195,10 @@ class HandlerImpl {
public:
static int emit_exception_handler(C2_MacroAssembler *masm);
static int emit_deopt_handler(C2_MacroAssembler* masm);
static uint size_exception_handler() {
return MacroAssembler::far_codestub_branch_size();
}
static uint size_deopt_handler() {
// count one adr and one far branch instruction
// count one branch instruction and one far call instruction sequence
return NativeInstruction::instruction_size + MacroAssembler::far_codestub_branch_size();
}
};
@ -2261,25 +2257,6 @@ uint MachUEPNode::size(PhaseRegAlloc* ra_) const
//=============================================================================
// Emit exception handler code.
int HandlerImpl::emit_exception_handler(C2_MacroAssembler* masm)
{
// mov rscratch1 #exception_blob_entry_point
// br rscratch1
// Note that the code buffer's insts_mark is always relative to insts.
// That's why we must use the macroassembler to generate a handler.
address base = __ start_a_stub(size_exception_handler());
if (base == nullptr) {
ciEnv::current()->record_failure("CodeCache is full");
return 0; // CodeBuffer::expand failed
}
int offset = __ offset();
__ far_jump(RuntimeAddress(OptoRuntime::exception_blob()->entry_point()));
assert(__ offset() - offset <= (int) size_exception_handler(), "overflow");
__ end_a_stub();
return offset;
}
// Emit deopt handler code.
int HandlerImpl::emit_deopt_handler(C2_MacroAssembler* masm)
{
@ -2290,14 +2267,20 @@ int HandlerImpl::emit_deopt_handler(C2_MacroAssembler* masm)
ciEnv::current()->record_failure("CodeCache is full");
return 0; // CodeBuffer::expand failed
}
int offset = __ offset();
__ adr(lr, __ pc());
__ far_jump(RuntimeAddress(SharedRuntime::deopt_blob()->unpack()));
int offset = __ offset();
Label start;
__ bind(start);
__ far_call(RuntimeAddress(SharedRuntime::deopt_blob()->unpack()));
int entry_offset = __ offset();
__ b(start);
assert(__ offset() - offset == (int) size_deopt_handler(), "overflow");
assert(__ offset() - entry_offset >= NativePostCallNop::first_check_size,
"out of bounds read in post-call NOP check");
__ end_a_stub();
return offset;
return entry_offset;
}
// REQUIRED MATCHER CODE
@ -2473,6 +2456,10 @@ bool Matcher::is_reg2reg_move(MachNode* m) {
return false;
}
bool Matcher::is_register_biasing_candidate(const MachNode* mdef, int oper_index) {
return false;
}
bool Matcher::is_generic_vector(MachOper* opnd) {
return opnd->opcode() == VREG;
}
@ -3388,28 +3375,28 @@ encode %{
// aarch64_enc_cmpxchg_acq is that we use load-acquire in the
// CompareAndSwap sequence to serve as a barrier on acquiring a
// lock.
enc_class aarch64_enc_cmpxchg_acq(memory mem, iRegLNoSp oldval, iRegLNoSp newval) %{
enc_class aarch64_enc_cmpxchg_acq(memory mem, iRegL oldval, iRegL newval) %{
guarantee($mem$$index == -1 && $mem$$disp == 0, "impossible encoding");
__ cmpxchg($mem$$base$$Register, $oldval$$Register, $newval$$Register,
Assembler::xword, /*acquire*/ true, /*release*/ true,
/*weak*/ false, noreg);
%}
enc_class aarch64_enc_cmpxchgw_acq(memory mem, iRegINoSp oldval, iRegINoSp newval) %{
enc_class aarch64_enc_cmpxchgw_acq(memory mem, iRegI oldval, iRegI newval) %{
guarantee($mem$$index == -1 && $mem$$disp == 0, "impossible encoding");
__ cmpxchg($mem$$base$$Register, $oldval$$Register, $newval$$Register,
Assembler::word, /*acquire*/ true, /*release*/ true,
/*weak*/ false, noreg);
%}
enc_class aarch64_enc_cmpxchgs_acq(memory mem, iRegINoSp oldval, iRegINoSp newval) %{
enc_class aarch64_enc_cmpxchgs_acq(memory mem, iRegI oldval, iRegI newval) %{
guarantee($mem$$index == -1 && $mem$$disp == 0, "impossible encoding");
__ cmpxchg($mem$$base$$Register, $oldval$$Register, $newval$$Register,
Assembler::halfword, /*acquire*/ true, /*release*/ true,
/*weak*/ false, noreg);
%}
enc_class aarch64_enc_cmpxchgb_acq(memory mem, iRegINoSp oldval, iRegINoSp newval) %{
enc_class aarch64_enc_cmpxchgb_acq(memory mem, iRegI oldval, iRegI newval) %{
guarantee($mem$$index == -1 && $mem$$disp == 0, "impossible encoding");
__ cmpxchg($mem$$base$$Register, $oldval$$Register, $newval$$Register,
Assembler::byte, /*acquire*/ true, /*release*/ true,
@ -3417,7 +3404,7 @@ encode %{
%}
// auxiliary used for CompareAndSwapX to set result register
enc_class aarch64_enc_cset_eq(iRegINoSp res) %{
enc_class aarch64_enc_cset_eq(iRegI res) %{
Register res_reg = as_Register($res$$reg);
__ cset(res_reg, Assembler::EQ);
%}
@ -8403,7 +8390,7 @@ instruct castVVMask(pRegGov dst)
// XXX No flag versions for CompareAndSwap{I,L,P,N} because matcher
// can't match them
instruct compareAndSwapB(iRegINoSp res, indirect mem, iRegINoSp oldval, iRegINoSp newval, rFlagsReg cr) %{
instruct compareAndSwapB(iRegINoSp res, indirect mem, iRegI oldval, iRegI newval, rFlagsReg cr) %{
match(Set res (CompareAndSwapB mem (Binary oldval newval)));
ins_cost(2 * VOLATILE_REF_COST);
@ -8421,7 +8408,7 @@ instruct compareAndSwapB(iRegINoSp res, indirect mem, iRegINoSp oldval, iRegINoS
ins_pipe(pipe_slow);
%}
instruct compareAndSwapS(iRegINoSp res, indirect mem, iRegINoSp oldval, iRegINoSp newval, rFlagsReg cr) %{
instruct compareAndSwapS(iRegINoSp res, indirect mem, iRegI oldval, iRegI newval, rFlagsReg cr) %{
match(Set res (CompareAndSwapS mem (Binary oldval newval)));
ins_cost(2 * VOLATILE_REF_COST);
@ -8439,7 +8426,7 @@ instruct compareAndSwapS(iRegINoSp res, indirect mem, iRegINoSp oldval, iRegINoS
ins_pipe(pipe_slow);
%}
instruct compareAndSwapI(iRegINoSp res, indirect mem, iRegINoSp oldval, iRegINoSp newval, rFlagsReg cr) %{
instruct compareAndSwapI(iRegINoSp res, indirect mem, iRegI oldval, iRegI newval, rFlagsReg cr) %{
match(Set res (CompareAndSwapI mem (Binary oldval newval)));
ins_cost(2 * VOLATILE_REF_COST);
@ -8457,7 +8444,7 @@ instruct compareAndSwapI(iRegINoSp res, indirect mem, iRegINoSp oldval, iRegINoS
ins_pipe(pipe_slow);
%}
instruct compareAndSwapL(iRegINoSp res, indirect mem, iRegLNoSp oldval, iRegLNoSp newval, rFlagsReg cr) %{
instruct compareAndSwapL(iRegINoSp res, indirect mem, iRegL oldval, iRegL newval, rFlagsReg cr) %{
match(Set res (CompareAndSwapL mem (Binary oldval newval)));
ins_cost(2 * VOLATILE_REF_COST);
@ -8494,7 +8481,7 @@ instruct compareAndSwapP(iRegINoSp res, indirect mem, iRegP oldval, iRegP newval
ins_pipe(pipe_slow);
%}
instruct compareAndSwapN(iRegINoSp res, indirect mem, iRegNNoSp oldval, iRegNNoSp newval, rFlagsReg cr) %{
instruct compareAndSwapN(iRegINoSp res, indirect mem, iRegN oldval, iRegN newval, rFlagsReg cr) %{
match(Set res (CompareAndSwapN mem (Binary oldval newval)));
predicate(n->as_LoadStore()->barrier_data() == 0);
@ -8515,7 +8502,7 @@ instruct compareAndSwapN(iRegINoSp res, indirect mem, iRegNNoSp oldval, iRegNNoS
// alternative CompareAndSwapX when we are eliding barriers
instruct compareAndSwapBAcq(iRegINoSp res, indirect mem, iRegINoSp oldval, iRegINoSp newval, rFlagsReg cr) %{
instruct compareAndSwapBAcq(iRegINoSp res, indirect mem, iRegI oldval, iRegI newval, rFlagsReg cr) %{
predicate(needs_acquiring_load_exclusive(n));
match(Set res (CompareAndSwapB mem (Binary oldval newval)));
@ -8534,7 +8521,7 @@ instruct compareAndSwapBAcq(iRegINoSp res, indirect mem, iRegINoSp oldval, iRegI
ins_pipe(pipe_slow);
%}
instruct compareAndSwapSAcq(iRegINoSp res, indirect mem, iRegINoSp oldval, iRegINoSp newval, rFlagsReg cr) %{
instruct compareAndSwapSAcq(iRegINoSp res, indirect mem, iRegI oldval, iRegI newval, rFlagsReg cr) %{
predicate(needs_acquiring_load_exclusive(n));
match(Set res (CompareAndSwapS mem (Binary oldval newval)));
@ -8553,7 +8540,7 @@ instruct compareAndSwapSAcq(iRegINoSp res, indirect mem, iRegINoSp oldval, iRegI
ins_pipe(pipe_slow);
%}
instruct compareAndSwapIAcq(iRegINoSp res, indirect mem, iRegINoSp oldval, iRegINoSp newval, rFlagsReg cr) %{
instruct compareAndSwapIAcq(iRegINoSp res, indirect mem, iRegI oldval, iRegI newval, rFlagsReg cr) %{
predicate(needs_acquiring_load_exclusive(n));
match(Set res (CompareAndSwapI mem (Binary oldval newval)));
@ -8572,7 +8559,7 @@ instruct compareAndSwapIAcq(iRegINoSp res, indirect mem, iRegINoSp oldval, iRegI
ins_pipe(pipe_slow);
%}
instruct compareAndSwapLAcq(iRegINoSp res, indirect mem, iRegLNoSp oldval, iRegLNoSp newval, rFlagsReg cr) %{
instruct compareAndSwapLAcq(iRegINoSp res, indirect mem, iRegL oldval, iRegL newval, rFlagsReg cr) %{
predicate(needs_acquiring_load_exclusive(n));
match(Set res (CompareAndSwapL mem (Binary oldval newval)));
@ -8610,7 +8597,7 @@ instruct compareAndSwapPAcq(iRegINoSp res, indirect mem, iRegP oldval, iRegP new
ins_pipe(pipe_slow);
%}
instruct compareAndSwapNAcq(iRegINoSp res, indirect mem, iRegNNoSp oldval, iRegNNoSp newval, rFlagsReg cr) %{
instruct compareAndSwapNAcq(iRegINoSp res, indirect mem, iRegN oldval, iRegN newval, rFlagsReg cr) %{
predicate(needs_acquiring_load_exclusive(n) && n->as_LoadStore()->barrier_data() == 0);
match(Set res (CompareAndSwapN mem (Binary oldval newval)));

View File

@ -449,12 +449,20 @@ int LIR_Assembler::emit_deopt_handler() {
int offset = code_offset();
__ adr(lr, pc());
__ far_jump(RuntimeAddress(SharedRuntime::deopt_blob()->unpack()));
Label start;
__ bind(start);
__ far_call(RuntimeAddress(SharedRuntime::deopt_blob()->unpack()));
int entry_offset = __ offset();
__ b(start);
guarantee(code_offset() - offset <= deopt_handler_size(), "overflow");
assert(code_offset() - entry_offset >= NativePostCallNop::first_check_size,
"out of bounds read in post-call NOP check");
__ end_a_stub();
return offset;
return entry_offset;
}
void LIR_Assembler::add_debug_info_for_branch(address adr, CodeEmitInfo* info) {

View File

@ -71,7 +71,7 @@ friend class ArrayCopyStub;
// CompiledDirectCall::to_trampoline_stub_size()
_call_stub_size = 13 * NativeInstruction::instruction_size,
_exception_handler_size = DEBUG_ONLY(1*K) NOT_DEBUG(175),
_deopt_handler_size = 7 * NativeInstruction::instruction_size
_deopt_handler_size = 4 * NativeInstruction::instruction_size
};
public:

View File

@ -394,12 +394,6 @@ void NativePostCallNop::make_deopt() {
NativeDeoptInstruction::insert(addr_at(0));
}
#ifdef ASSERT
static bool is_movk_to_zr(uint32_t insn) {
return ((insn & 0xffe0001f) == 0xf280001f);
}
#endif
bool NativePostCallNop::patch(int32_t oopmap_slot, int32_t cb_offset) {
if (((oopmap_slot & 0xff) != oopmap_slot) || ((cb_offset & 0xffffff) != cb_offset)) {
return false; // cannot encode

View File

@ -526,14 +526,31 @@ inline NativeLdSt* NativeLdSt_at(address addr) {
// can store an offset from the initial nop to the nmethod.
class NativePostCallNop: public NativeInstruction {
private:
static bool is_movk_to_zr(uint32_t insn) {
return ((insn & 0xffe0001f) == 0xf280001f);
}
public:
enum AArch64_specific_constants {
// The two parts should be checked separately to prevent out of bounds access in case
// the return address points to the deopt handler stub code entry point which could be
// at the end of page.
first_check_size = instruction_size
};
bool check() const {
uint64_t insns = *(uint64_t*)addr_at(0);
// Check for two instructions: nop; movk zr, xx
// These instructions only ever appear together in a post-call
// NOP, so it's unnecessary to check that the third instruction is
// a MOVK as well.
return (insns & 0xffe0001fffffffff) == 0xf280001fd503201f;
// Check the first instruction is NOP.
if (is_nop()) {
uint32_t insn = *(uint32_t*)addr_at(first_check_size);
// Check next instruction is MOVK zr, xx.
// These instructions only ever appear together in a post-call
// NOP, so it's unnecessary to check that the third instruction is
// a MOVK as well.
return is_movk_to_zr(insn);
}
return false;
}
bool decode(int32_t& oopmap_slot, int32_t& cb_offset) const {

View File

@ -260,8 +260,6 @@ UncommonTrapBlob* OptoRuntime::generate_uncommon_trap_blob() {
//------------------------------generate_exception_blob---------------------------
// creates exception blob at the end
// Using exception blob, this code is jumped from a compiled method.
// (see emit_exception_handler in aarch64.ad file)
//
// Given an exception pc at a call we call into the runtime for the
// handler in this method. This handler might merely restore state

View File

@ -105,14 +105,8 @@ class HandlerImpl {
public:
static int emit_exception_handler(C2_MacroAssembler *masm);
static int emit_deopt_handler(C2_MacroAssembler* masm);
static uint size_exception_handler() {
return ( 3 * 4 );
}
static uint size_deopt_handler() {
return ( 9 * 4 );
}
@ -876,26 +870,6 @@ uint MachUEPNode::size(PhaseRegAlloc *ra_) const {
//=============================================================================
// Emit exception handler code.
int HandlerImpl::emit_exception_handler(C2_MacroAssembler* masm) {
address base = __ start_a_stub(size_exception_handler());
if (base == nullptr) {
ciEnv::current()->record_failure("CodeCache is full");
return 0; // CodeBuffer::expand failed
}
int offset = __ offset();
// OK to trash LR, because exception blob will kill it
__ jump(OptoRuntime::exception_blob()->entry_point(), relocInfo::runtime_call_type, LR_tmp);
assert(__ offset() - offset <= (int) size_exception_handler(), "overflow");
__ end_a_stub();
return offset;
}
int HandlerImpl::emit_deopt_handler(C2_MacroAssembler* masm) {
// Can't use any of the current frame's registers as we may have deopted
// at a poll and everything can be live.
@ -906,19 +880,28 @@ int HandlerImpl::emit_deopt_handler(C2_MacroAssembler* masm) {
}
int offset = __ offset();
address deopt_pc = __ pc();
__ sub(SP, SP, wordSize); // make room for saved PC
__ push(LR); // save LR that may be live when we get here
__ mov_relative_address(LR, deopt_pc);
__ str(LR, Address(SP, wordSize)); // save deopt PC
__ pop(LR); // restore LR
Label start;
__ bind(start);
__ jump(SharedRuntime::deopt_blob()->unpack(), relocInfo::runtime_call_type, noreg);
int entry_offset = __ offset();
address deopt_pc = __ pc();
// Preserve R0 and reserve space for the address of the entry point
__ push(RegisterSet(R0) | RegisterSet(R1));
// Store the entry point address
__ mov_relative_address(R0, deopt_pc);
__ str(R0, Address(SP, wordSize));
__ pop(R0); // restore R0
__ b(start);
assert(__ offset() - offset <= (int) size_deopt_handler(), "overflow");
assert(__ offset() - entry_offset >= NativePostCallNop::first_check_size,
"out of bounds read in post-call NOP check");
__ end_a_stub();
return offset;
return entry_offset;
}
bool Matcher::match_rule_supported(int opcode) {
@ -1080,6 +1063,10 @@ bool Matcher::is_reg2reg_move(MachNode* m) {
return false;
}
bool Matcher::is_register_biasing_candidate(const MachNode* mdef, int oper_index) {
return false;
}
bool Matcher::is_generic_vector(MachOper* opnd) {
ShouldNotReachHere(); // generic vector operands not supported
return false;

View File

@ -62,22 +62,22 @@ register %{
// Integer/Long Registers
// ----------------------------
reg_def R_R0 (SOC, SOC, Op_RegI, 0, R(0)->as_VMReg());
reg_def R_R1 (SOC, SOC, Op_RegI, 1, R(1)->as_VMReg());
reg_def R_R2 (SOC, SOC, Op_RegI, 2, R(2)->as_VMReg());
reg_def R_R3 (SOC, SOC, Op_RegI, 3, R(3)->as_VMReg());
reg_def R_R4 (SOC, SOE, Op_RegI, 4, R(4)->as_VMReg());
reg_def R_R5 (SOC, SOE, Op_RegI, 5, R(5)->as_VMReg());
reg_def R_R6 (SOC, SOE, Op_RegI, 6, R(6)->as_VMReg());
reg_def R_R7 (SOC, SOE, Op_RegI, 7, R(7)->as_VMReg());
reg_def R_R8 (SOC, SOE, Op_RegI, 8, R(8)->as_VMReg());
reg_def R_R9 (SOC, SOE, Op_RegI, 9, R(9)->as_VMReg());
reg_def R_R10(NS, SOE, Op_RegI, 10, R(10)->as_VMReg());
reg_def R_R11(NS, SOE, Op_RegI, 11, R(11)->as_VMReg());
reg_def R_R12(SOC, SOC, Op_RegI, 12, R(12)->as_VMReg());
reg_def R_R13(NS, NS, Op_RegI, 13, R(13)->as_VMReg());
reg_def R_R14(SOC, SOC, Op_RegI, 14, R(14)->as_VMReg());
reg_def R_R15(NS, NS, Op_RegI, 15, R(15)->as_VMReg());
reg_def R_R0 (SOC, SOC, Op_RegI, 0, as_Register(0)->as_VMReg());
reg_def R_R1 (SOC, SOC, Op_RegI, 1, as_Register(1)->as_VMReg());
reg_def R_R2 (SOC, SOC, Op_RegI, 2, as_Register(2)->as_VMReg());
reg_def R_R3 (SOC, SOC, Op_RegI, 3, as_Register(3)->as_VMReg());
reg_def R_R4 (SOC, SOE, Op_RegI, 4, as_Register(4)->as_VMReg());
reg_def R_R5 (SOC, SOE, Op_RegI, 5, as_Register(5)->as_VMReg());
reg_def R_R6 (SOC, SOE, Op_RegI, 6, as_Register(6)->as_VMReg());
reg_def R_R7 (SOC, SOE, Op_RegI, 7, as_Register(7)->as_VMReg());
reg_def R_R8 (SOC, SOE, Op_RegI, 8, as_Register(8)->as_VMReg());
reg_def R_R9 (SOC, SOE, Op_RegI, 9, as_Register(9)->as_VMReg());
reg_def R_R10(NS, SOE, Op_RegI, 10, as_Register(10)->as_VMReg());
reg_def R_R11(NS, SOE, Op_RegI, 11, as_Register(11)->as_VMReg());
reg_def R_R12(SOC, SOC, Op_RegI, 12, as_Register(12)->as_VMReg());
reg_def R_R13(NS, NS, Op_RegI, 13, as_Register(13)->as_VMReg());
reg_def R_R14(SOC, SOC, Op_RegI, 14, as_Register(14)->as_VMReg());
reg_def R_R15(NS, NS, Op_RegI, 15, as_Register(15)->as_VMReg());
// ----------------------------
// Float/Double Registers

View File

@ -114,7 +114,7 @@ class RegisterSet {
}
RegisterSet(Register first, Register last) {
assert(first < last, "encoding constraint");
assert(first->encoding() < last->encoding(), "encoding constraint");
_encoding = (1 << (last->encoding() + 1)) - (1 << first->encoding());
}

View File

@ -181,7 +181,7 @@ void MonitorEnterStub::emit_code(LIR_Assembler* ce) {
const Register lock_reg = _lock_reg->as_pointer_register();
ce->verify_reserved_argument_area_size(2);
if (obj_reg < lock_reg) {
if (obj_reg->encoding() < lock_reg->encoding()) {
__ stmia(SP, RegisterSet(obj_reg) | RegisterSet(lock_reg));
} else {
__ str(obj_reg, Address(SP));

View File

@ -272,14 +272,22 @@ int LIR_Assembler::emit_deopt_handler() {
int offset = code_offset();
__ mov_relative_address(LR, __ pc());
__ push(LR); // stub expects LR to be saved
Label start;
__ bind(start);
__ jump(SharedRuntime::deopt_blob()->unpack(), relocInfo::runtime_call_type, noreg);
int entry_offset = __ offset();
__ mov_relative_address(LR, __ pc());
__ push(LR); // stub expects LR to be saved
__ b(start);
assert(code_offset() - offset <= deopt_handler_size(), "overflow");
assert(code_offset() - entry_offset >= NativePostCallNop::first_check_size,
"out of bounds read in post-call NOP check");
__ end_a_stub();
return offset;
return entry_offset;
}
@ -2631,11 +2639,11 @@ void LIR_Assembler::volatile_move_op(LIR_Opr src, LIR_Opr dest, BasicType type,
const Register src_hi = src->as_register_hi();
assert(addr->index()->is_illegal() && addr->disp() == 0, "The address is simple already");
if (src_lo < src_hi) {
if (src_lo->encoding() < src_hi->encoding()) {
null_check_offset = __ offset();
__ stmia(addr->base()->as_register(), RegisterSet(src_lo) | RegisterSet(src_hi));
} else {
assert(src_lo < Rtemp, "Rtemp is higher than any allocatable register");
assert(src_lo->encoding() < Rtemp->encoding(), "Rtemp is higher than any allocatable register");
__ mov(Rtemp, src_hi);
null_check_offset = __ offset();
__ stmia(addr->base()->as_register(), RegisterSet(src_lo) | RegisterSet(Rtemp));
@ -2648,10 +2656,10 @@ void LIR_Assembler::volatile_move_op(LIR_Opr src, LIR_Opr dest, BasicType type,
assert(addr->index()->is_illegal() && addr->disp() == 0, "The address is simple already");
null_check_offset = __ offset();
if (dest_lo < dest_hi) {
if (dest_lo->encoding() < dest_hi->encoding()) {
__ ldmia(addr->base()->as_register(), RegisterSet(dest_lo) | RegisterSet(dest_hi));
} else {
assert(dest_lo < Rtemp, "Rtemp is higher than any allocatable register");
assert(dest_lo->encoding() < Rtemp->encoding(), "Rtemp is higher than any allocatable register");
__ ldmia(addr->base()->as_register(), RegisterSet(dest_lo) | RegisterSet(Rtemp));
__ mov(dest_hi, Rtemp);
}

View File

@ -54,7 +54,7 @@
enum {
_call_stub_size = 16,
_exception_handler_size = PRODUCT_ONLY(68) NOT_PRODUCT(68+60),
_deopt_handler_size = 16
_deopt_handler_size = 20
};
public:

View File

@ -409,7 +409,7 @@ void InterpreterMacroAssembler::pop_i(Register r) {
void InterpreterMacroAssembler::pop_l(Register lo, Register hi) {
assert_different_registers(lo, hi);
assert(lo < hi, "lo must be < hi");
assert(lo->encoding() < hi->encoding(), "lo must be < hi");
pop(RegisterSet(lo) | RegisterSet(hi));
}
@ -459,7 +459,7 @@ void InterpreterMacroAssembler::push_i(Register r) {
void InterpreterMacroAssembler::push_l(Register lo, Register hi) {
assert_different_registers(lo, hi);
assert(lo < hi, "lo must be < hi");
assert(lo->encoding() < hi->encoding(), "lo must be < hi");
push(RegisterSet(lo) | RegisterSet(hi));
}

View File

@ -430,6 +430,13 @@ inline NativeCall* nativeCall_before(address return_address) {
class NativePostCallNop: public NativeInstruction {
public:
enum arm_specific_constants {
// If the check is adjusted to read beyond size of the instruction sequence at the deopt
// handler stub code entry point, it has to happen in two stages - to prevent out of bounds
// access in case the return address points to the entry point which could be at
// the end of page.
first_check_size = instruction_size
};
bool check() const { return is_nop(); }
bool decode(int32_t& oopmap_slot, int32_t& cb_offset) const { return false; }
bool patch(int32_t oopmap_slot, int32_t cb_offset) { return false; }

View File

@ -25,12 +25,19 @@
#include "register_arm.hpp"
#include "utilities/debug.hpp"
const int ConcreteRegisterImpl::max_gpr = ConcreteRegisterImpl::num_gpr;
const int ConcreteRegisterImpl::max_fpr = ConcreteRegisterImpl::num_fpr +
ConcreteRegisterImpl::max_gpr;
Register::RegisterImpl all_RegisterImpls [Register::number_of_registers + 1];
FloatRegister::FloatRegisterImpl all_FloatRegisterImpls [FloatRegister::number_of_registers + 1];
VFPSystemRegister::VFPSystemRegisterImpl all_VFPSystemRegisterImpls [VFPSystemRegister::number_of_registers + 1] {
{ -1 }, //vfpsnoreg
{ VFPSystemRegister::FPSID },
{ VFPSystemRegister::FPSCR },
{ VFPSystemRegister::MVFR0 },
{ VFPSystemRegister::MVFR1 }
};
const char* RegisterImpl::name() const {
const char* names[number_of_registers] = {
const char* Register::RegisterImpl::name() const {
static const char* names[number_of_registers + 1] = {
"noreg",
"r0", "r1", "r2", "r3", "r4", "r5", "r6",
#if (FP_REG_NUM == 7)
"fp",
@ -45,13 +52,14 @@ const char* RegisterImpl::name() const {
#endif
"r12", "sp", "lr", "pc"
};
return is_valid() ? names[encoding()] : "noreg";
return names[encoding() + 1];
}
const char* FloatRegisterImpl::name() const {
const char* names[number_of_registers] = {
"s0", "s1", "s2", "s3", "s4", "s5", "s6", "s7",
"s8", "s9", "s10", "s11", "s12", "s13", "s14", "s15",
const char* FloatRegister::FloatRegisterImpl::name() const {
static const char* names[number_of_registers + 1] = {
"fnoreg",
"s0", "s1", "s2", "s3", "s4", "s5", "s6", "s7",
"s8", "s9", "s10", "s11", "s12", "s13", "s14", "s15",
"s16", "s17", "s18", "s19", "s20", "s21", "s22", "s23",
"s24", "s25", "s26", "s27", "s28", "s29", "s30", "s31"
#ifdef COMPILER2
@ -61,5 +69,5 @@ const char* FloatRegisterImpl::name() const {
"s56", "s57?","s58", "s59?","s60", "s61?","s62", "s63?"
#endif
};
return is_valid() ? names[encoding()] : "fnoreg";
return names[encoding() + 1];
}

View File

@ -31,26 +31,6 @@
class VMRegImpl;
typedef VMRegImpl* VMReg;
// These are declared ucontext.h
#undef R0
#undef R1
#undef R2
#undef R3
#undef R4
#undef R5
#undef R6
#undef R7
#undef R8
#undef R9
#undef R10
#undef R11
#undef R12
#undef R13
#undef R14
#undef R15
#define R(r) ((Register)(r))
/////////////////////////////////
// Support for different ARM ABIs
// Note: default ABI is for linux
@ -94,25 +74,86 @@ typedef VMRegImpl* VMReg;
#define ALIGN_WIDE_ARGUMENTS 1
#endif
#define R0 ((Register)0)
#define R1 ((Register)1)
#define R2 ((Register)2)
#define R3 ((Register)3)
#define R4 ((Register)4)
#define R5 ((Register)5)
#define R6 ((Register)6)
#define R7 ((Register)7)
#define R8 ((Register)8)
#define R9 ((Register)9)
#define R10 ((Register)10)
#define R11 ((Register)11)
#define R12 ((Register)12)
#define R13 ((Register)13)
#define R14 ((Register)14)
#define R15 ((Register)15)
class Register {
private:
int _encoding;
constexpr explicit Register(int encoding) : _encoding(encoding) {}
public:
enum {
number_of_registers = 16,
max_slots_per_register = 1
};
class RegisterImpl : public AbstractRegisterImpl {
friend class Register;
static constexpr const RegisterImpl* first();
public:
// accessors and testers
int raw_encoding() const { return this - first(); }
int encoding() const { assert(is_valid(), "invalid register"); return raw_encoding(); }
bool is_valid() const { return 0 <= raw_encoding() && raw_encoding() < number_of_registers; }
inline Register successor() const;
VMReg as_VMReg() const;
const char* name() const;
};
#define FP ((Register)FP_REG_NUM)
inline friend constexpr Register as_Register(int encoding);
constexpr Register() : _encoding(-1) {} //noreg
int operator==(const Register r) const { return _encoding == r._encoding; }
int operator!=(const Register r) const { return _encoding != r._encoding; }
const RegisterImpl* operator->() const { return RegisterImpl::first() + _encoding; }
};
extern Register::RegisterImpl all_RegisterImpls[Register::number_of_registers + 1] INTERNAL_VISIBILITY;
inline constexpr const Register::RegisterImpl* Register::RegisterImpl::first() {
return all_RegisterImpls + 1;
}
constexpr Register noreg = Register();
inline constexpr Register as_Register(int encoding) {
if (0 <= encoding && encoding < Register::number_of_registers) {
return Register(encoding);
}
return noreg;
}
inline Register Register::RegisterImpl::successor() const {
assert(is_valid(), "sainty");
return as_Register(encoding() + 1);
}
constexpr Register R0 = as_Register( 0);
constexpr Register R1 = as_Register( 1);
constexpr Register R2 = as_Register( 2);
constexpr Register R3 = as_Register( 3);
constexpr Register R4 = as_Register( 4);
constexpr Register R5 = as_Register( 5);
constexpr Register R6 = as_Register( 6);
constexpr Register R7 = as_Register( 7);
constexpr Register R8 = as_Register( 8);
constexpr Register R9 = as_Register( 9);
constexpr Register R10 = as_Register(10);
constexpr Register R11 = as_Register(11);
constexpr Register R12 = as_Register(12);
constexpr Register R13 = as_Register(13);
constexpr Register R14 = as_Register(14);
constexpr Register R15 = as_Register(15);
constexpr Register FP = as_Register(FP_REG_NUM);
// Safe use of registers which may be FP on some platforms.
//
@ -122,185 +163,170 @@ typedef VMRegImpl* VMReg;
// as FP on supported ABIs (and replace R# by altFP_#_11). altFP_#_11
// must be #define to R11 if and only if # is FP_REG_NUM.
#if (FP_REG_NUM == 7)
#define altFP_7_11 ((Register)11)
constexpr Register altFP_7_11 = R11;
#else
#define altFP_7_11 ((Register)7)
constexpr Register altFP_7_11 = R7;
#endif
#define SP R13
#define LR R14
#define PC R15
constexpr Register SP = R13;
constexpr Register LR = R14;
constexpr Register PC = R15;
class RegisterImpl;
typedef RegisterImpl* Register;
class FloatRegister {
private:
int _encoding;
inline Register as_Register(int encoding) {
return (Register)(intptr_t)encoding;
}
constexpr explicit FloatRegister(int encoding) : _encoding(encoding) {}
class RegisterImpl : public AbstractRegisterImpl {
public:
enum {
number_of_registers = 16
number_of_registers = NOT_COMPILER2(32) COMPILER2_PRESENT(64),
max_slots_per_register = 1
};
Register successor() const { return as_Register(encoding() + 1); }
class FloatRegisterImpl : public AbstractRegisterImpl {
friend class FloatRegister;
inline friend Register as_Register(int encoding);
static constexpr const FloatRegisterImpl* first();
VMReg as_VMReg();
public:
// accessors
int encoding() const { assert(is_valid(), "invalid register"); return value(); }
const char* name() const;
// accessors and testers
int raw_encoding() const { return this - first(); }
int encoding() const { assert(is_valid(), "invalid register"); return raw_encoding(); }
bool is_valid() const { return 0 <= raw_encoding() && raw_encoding() < number_of_registers; }
inline FloatRegister successor() const;
// testers
bool is_valid() const { return 0 <= value() && value() < number_of_registers; }
VMReg as_VMReg() const;
int hi_bits() const {
return (encoding() >> 1) & 0xf;
}
int lo_bit() const {
return encoding() & 1;
}
int hi_bit() const {
return encoding() >> 5;
}
const char* name() const;
};
inline friend constexpr FloatRegister as_FloatRegister(int encoding);
constexpr FloatRegister() : _encoding(-1) {} // fnoreg
int operator==(const FloatRegister r) const { return _encoding == r._encoding; }
int operator!=(const FloatRegister r) const { return _encoding != r._encoding; }
const FloatRegisterImpl* operator->() const { return FloatRegisterImpl::first() + _encoding; }
};
CONSTANT_REGISTER_DECLARATION(Register, noreg, (-1));
extern FloatRegister::FloatRegisterImpl all_FloatRegisterImpls[FloatRegister::number_of_registers + 1] INTERNAL_VISIBILITY;
// Use FloatRegister as shortcut
class FloatRegisterImpl;
typedef FloatRegisterImpl* FloatRegister;
inline FloatRegister as_FloatRegister(int encoding) {
return (FloatRegister)(intptr_t)encoding;
inline constexpr const FloatRegister::FloatRegisterImpl* FloatRegister::FloatRegisterImpl::first() {
return all_FloatRegisterImpls + 1;
}
class FloatRegisterImpl : public AbstractRegisterImpl {
public:
enum {
number_of_registers = NOT_COMPILER2(32) COMPILER2_PRESENT(64)
};
constexpr FloatRegister fnoreg = FloatRegister();
inline friend FloatRegister as_FloatRegister(int encoding);
VMReg as_VMReg();
int encoding() const { assert(is_valid(), "invalid register"); return value(); }
bool is_valid() const { return 0 <= (intx)this && (intx)this < number_of_registers; }
FloatRegister successor() const { return as_FloatRegister(encoding() + 1); }
const char* name() const;
int hi_bits() const {
return (encoding() >> 1) & 0xf;
inline constexpr FloatRegister as_FloatRegister(int encoding) {
if (0 <= encoding && encoding < FloatRegister::number_of_registers) {
return FloatRegister(encoding);
}
return fnoreg;
}
int lo_bit() const {
return encoding() & 1;
}
int hi_bit() const {
return encoding() >> 5;
}
};
CONSTANT_REGISTER_DECLARATION(FloatRegister, fnoreg, (-1));
inline FloatRegister FloatRegister::FloatRegisterImpl::successor() const {
assert(is_valid(), "sainty");
return as_FloatRegister(encoding() + 1);
}
/*
* S1-S6 are named with "_reg" suffix to avoid conflict with
* constants defined in sharedRuntimeTrig.cpp
*/
CONSTANT_REGISTER_DECLARATION(FloatRegister, S0, ( 0));
CONSTANT_REGISTER_DECLARATION(FloatRegister, S1_reg, ( 1));
CONSTANT_REGISTER_DECLARATION(FloatRegister, S2_reg, ( 2));
CONSTANT_REGISTER_DECLARATION(FloatRegister, S3_reg, ( 3));
CONSTANT_REGISTER_DECLARATION(FloatRegister, S4_reg, ( 4));
CONSTANT_REGISTER_DECLARATION(FloatRegister, S5_reg, ( 5));
CONSTANT_REGISTER_DECLARATION(FloatRegister, S6_reg, ( 6));
CONSTANT_REGISTER_DECLARATION(FloatRegister, S7, ( 7));
CONSTANT_REGISTER_DECLARATION(FloatRegister, S8, ( 8));
CONSTANT_REGISTER_DECLARATION(FloatRegister, S9, ( 9));
CONSTANT_REGISTER_DECLARATION(FloatRegister, S10, (10));
CONSTANT_REGISTER_DECLARATION(FloatRegister, S11, (11));
CONSTANT_REGISTER_DECLARATION(FloatRegister, S12, (12));
CONSTANT_REGISTER_DECLARATION(FloatRegister, S13, (13));
CONSTANT_REGISTER_DECLARATION(FloatRegister, S14, (14));
CONSTANT_REGISTER_DECLARATION(FloatRegister, S15, (15));
CONSTANT_REGISTER_DECLARATION(FloatRegister, S16, (16));
CONSTANT_REGISTER_DECLARATION(FloatRegister, S17, (17));
CONSTANT_REGISTER_DECLARATION(FloatRegister, S18, (18));
CONSTANT_REGISTER_DECLARATION(FloatRegister, S19, (19));
CONSTANT_REGISTER_DECLARATION(FloatRegister, S20, (20));
CONSTANT_REGISTER_DECLARATION(FloatRegister, S21, (21));
CONSTANT_REGISTER_DECLARATION(FloatRegister, S22, (22));
CONSTANT_REGISTER_DECLARATION(FloatRegister, S23, (23));
CONSTANT_REGISTER_DECLARATION(FloatRegister, S24, (24));
CONSTANT_REGISTER_DECLARATION(FloatRegister, S25, (25));
CONSTANT_REGISTER_DECLARATION(FloatRegister, S26, (26));
CONSTANT_REGISTER_DECLARATION(FloatRegister, S27, (27));
CONSTANT_REGISTER_DECLARATION(FloatRegister, S28, (28));
CONSTANT_REGISTER_DECLARATION(FloatRegister, S29, (29));
CONSTANT_REGISTER_DECLARATION(FloatRegister, S30, (30));
CONSTANT_REGISTER_DECLARATION(FloatRegister, S31, (31));
CONSTANT_REGISTER_DECLARATION(FloatRegister, Stemp, (30));
constexpr FloatRegister S0 = as_FloatRegister( 0);
constexpr FloatRegister S1_reg = as_FloatRegister(1);
constexpr FloatRegister S2_reg = as_FloatRegister(2);
constexpr FloatRegister S3_reg = as_FloatRegister(3);
constexpr FloatRegister S4_reg = as_FloatRegister(4);
constexpr FloatRegister S5_reg = as_FloatRegister(5);
constexpr FloatRegister S6_reg = as_FloatRegister(6);
constexpr FloatRegister S7 = as_FloatRegister( 7);
constexpr FloatRegister S8 = as_FloatRegister( 8);
constexpr FloatRegister S9 = as_FloatRegister( 9);
constexpr FloatRegister S10 = as_FloatRegister(10);
constexpr FloatRegister S11 = as_FloatRegister(11);
constexpr FloatRegister S12 = as_FloatRegister(12);
constexpr FloatRegister S13 = as_FloatRegister(13);
constexpr FloatRegister S14 = as_FloatRegister(14);
constexpr FloatRegister S15 = as_FloatRegister(15);
constexpr FloatRegister S16 = as_FloatRegister(16);
constexpr FloatRegister S17 = as_FloatRegister(17);
constexpr FloatRegister S18 = as_FloatRegister(18);
constexpr FloatRegister S19 = as_FloatRegister(19);
constexpr FloatRegister S20 = as_FloatRegister(20);
constexpr FloatRegister S21 = as_FloatRegister(21);
constexpr FloatRegister S22 = as_FloatRegister(22);
constexpr FloatRegister S23 = as_FloatRegister(23);
constexpr FloatRegister S24 = as_FloatRegister(24);
constexpr FloatRegister S25 = as_FloatRegister(25);
constexpr FloatRegister S26 = as_FloatRegister(26);
constexpr FloatRegister S27 = as_FloatRegister(27);
constexpr FloatRegister S28 = as_FloatRegister(28);
constexpr FloatRegister S29 = as_FloatRegister(29);
constexpr FloatRegister S30 = as_FloatRegister(30);
constexpr FloatRegister S31 = as_FloatRegister(31);
constexpr FloatRegister Stemp = S30;
CONSTANT_REGISTER_DECLARATION(FloatRegister, D0, ( 0));
CONSTANT_REGISTER_DECLARATION(FloatRegister, D1, ( 2));
CONSTANT_REGISTER_DECLARATION(FloatRegister, D2, ( 4));
CONSTANT_REGISTER_DECLARATION(FloatRegister, D3, ( 6));
CONSTANT_REGISTER_DECLARATION(FloatRegister, D4, ( 8));
CONSTANT_REGISTER_DECLARATION(FloatRegister, D5, ( 10));
CONSTANT_REGISTER_DECLARATION(FloatRegister, D6, ( 12));
CONSTANT_REGISTER_DECLARATION(FloatRegister, D7, ( 14));
CONSTANT_REGISTER_DECLARATION(FloatRegister, D8, ( 16));
CONSTANT_REGISTER_DECLARATION(FloatRegister, D9, ( 18));
CONSTANT_REGISTER_DECLARATION(FloatRegister, D10, ( 20));
CONSTANT_REGISTER_DECLARATION(FloatRegister, D11, ( 22));
CONSTANT_REGISTER_DECLARATION(FloatRegister, D12, ( 24));
CONSTANT_REGISTER_DECLARATION(FloatRegister, D13, ( 26));
CONSTANT_REGISTER_DECLARATION(FloatRegister, D14, ( 28));
CONSTANT_REGISTER_DECLARATION(FloatRegister, D15, (30));
CONSTANT_REGISTER_DECLARATION(FloatRegister, D16, (32));
CONSTANT_REGISTER_DECLARATION(FloatRegister, D17, (34));
CONSTANT_REGISTER_DECLARATION(FloatRegister, D18, (36));
CONSTANT_REGISTER_DECLARATION(FloatRegister, D19, (38));
CONSTANT_REGISTER_DECLARATION(FloatRegister, D20, (40));
CONSTANT_REGISTER_DECLARATION(FloatRegister, D21, (42));
CONSTANT_REGISTER_DECLARATION(FloatRegister, D22, (44));
CONSTANT_REGISTER_DECLARATION(FloatRegister, D23, (46));
CONSTANT_REGISTER_DECLARATION(FloatRegister, D24, (48));
CONSTANT_REGISTER_DECLARATION(FloatRegister, D25, (50));
CONSTANT_REGISTER_DECLARATION(FloatRegister, D26, (52));
CONSTANT_REGISTER_DECLARATION(FloatRegister, D27, (54));
CONSTANT_REGISTER_DECLARATION(FloatRegister, D28, (56));
CONSTANT_REGISTER_DECLARATION(FloatRegister, D29, (58));
CONSTANT_REGISTER_DECLARATION(FloatRegister, D30, (60));
CONSTANT_REGISTER_DECLARATION(FloatRegister, D31, (62));
constexpr FloatRegister D0 = as_FloatRegister( 0);
constexpr FloatRegister D1 = as_FloatRegister( 2);
constexpr FloatRegister D2 = as_FloatRegister( 4);
constexpr FloatRegister D3 = as_FloatRegister( 6);
constexpr FloatRegister D4 = as_FloatRegister( 8);
constexpr FloatRegister D5 = as_FloatRegister(10);
constexpr FloatRegister D6 = as_FloatRegister(12);
constexpr FloatRegister D7 = as_FloatRegister(14);
constexpr FloatRegister D8 = as_FloatRegister(16);
constexpr FloatRegister D9 = as_FloatRegister(18);
constexpr FloatRegister D10 = as_FloatRegister(20);
constexpr FloatRegister D11 = as_FloatRegister(22);
constexpr FloatRegister D12 = as_FloatRegister(24);
constexpr FloatRegister D13 = as_FloatRegister(26);
constexpr FloatRegister D14 = as_FloatRegister(28);
constexpr FloatRegister D15 = as_FloatRegister(30);
constexpr FloatRegister D16 = as_FloatRegister(32);
constexpr FloatRegister D17 = as_FloatRegister(34);
constexpr FloatRegister D18 = as_FloatRegister(36);
constexpr FloatRegister D19 = as_FloatRegister(38);
constexpr FloatRegister D20 = as_FloatRegister(40);
constexpr FloatRegister D21 = as_FloatRegister(42);
constexpr FloatRegister D22 = as_FloatRegister(44);
constexpr FloatRegister D23 = as_FloatRegister(46);
constexpr FloatRegister D24 = as_FloatRegister(48);
constexpr FloatRegister D25 = as_FloatRegister(50);
constexpr FloatRegister D26 = as_FloatRegister(52);
constexpr FloatRegister D27 = as_FloatRegister(54);
constexpr FloatRegister D28 = as_FloatRegister(56);
constexpr FloatRegister D29 = as_FloatRegister(58);
constexpr FloatRegister D30 = as_FloatRegister(60);
constexpr FloatRegister D31 = as_FloatRegister(62);
class ConcreteRegisterImpl : public AbstractRegisterImpl {
public:
enum {
log_vmregs_per_word = LogBytesPerWord - LogBytesPerInt, // VMRegs are of 4-byte size
#ifdef COMPILER2
log_bytes_per_fpr = 2, // quad vectors
#else
log_bytes_per_fpr = 2, // double vectors
#endif
log_words_per_fpr = log_bytes_per_fpr - LogBytesPerWord,
words_per_fpr = 1 << log_words_per_fpr,
log_vmregs_per_fpr = log_bytes_per_fpr - LogBytesPerInt,
log_vmregs_per_gpr = log_vmregs_per_word,
vmregs_per_gpr = 1 << log_vmregs_per_gpr,
vmregs_per_fpr = 1 << log_vmregs_per_fpr,
max_gpr = Register::number_of_registers * Register::max_slots_per_register,
max_fpr = max_gpr + FloatRegister::number_of_registers * FloatRegister::max_slots_per_register,
num_gpr = RegisterImpl::number_of_registers << log_vmregs_per_gpr,
max_gpr0 = num_gpr,
num_fpr = FloatRegisterImpl::number_of_registers << log_vmregs_per_fpr,
max_fpr0 = max_gpr0 + num_fpr,
number_of_registers = num_gpr + num_fpr + 1+1 // APSR and FPSCR so that c2's REG_COUNT <= ConcreteRegisterImpl::number_of_registers
number_of_registers = max_fpr + 1+1 // APSR and FPSCR so that c2's REG_COUNT <= ConcreteRegisterImpl::number_of_registers
};
static const int max_gpr;
static const int max_fpr;
};
typedef AbstractRegSet<Register> RegSet;
@ -328,100 +354,156 @@ inline FloatRegister AbstractRegSet<FloatRegister>::last() {
class VFPSystemRegisterImpl;
typedef VFPSystemRegisterImpl* VFPSystemRegister;
class VFPSystemRegisterImpl : public AbstractRegisterImpl {
class VFPSystemRegister {
private:
int _store_idx;
constexpr explicit VFPSystemRegister(int store_idx) : _store_idx(store_idx) {}
enum {
_FPSID_store_idx = 0,
_FPSCR_store_idx = 1,
_MVFR0_store_idx = 2,
_MVFR1_store_idx = 3
};
public:
int encoding() const { return value(); }
enum {
FPSID = 0,
FPSCR = 1,
MVFR0 = 6,
MVFR1 = 7,
number_of_registers = 4
};
class VFPSystemRegisterImpl : public AbstractRegisterImpl {
friend class VFPSystemRegister;
int _encoding;
static constexpr const VFPSystemRegisterImpl* first();
public:
constexpr VFPSystemRegisterImpl(int encoding) : _encoding(encoding) {}
int encoding() const { return _encoding; }
};
inline friend constexpr VFPSystemRegister as_VFPSystemRegister(int encoding);
constexpr VFPSystemRegister() : _store_idx(-1) {} // vfpsnoreg
int operator==(const VFPSystemRegister r) const { return _store_idx == r._store_idx; }
int operator!=(const VFPSystemRegister r) const { return _store_idx != r._store_idx; }
const VFPSystemRegisterImpl* operator->() const { return VFPSystemRegisterImpl::first() + _store_idx; }
};
#define FPSID ((VFPSystemRegister)0)
#define FPSCR ((VFPSystemRegister)1)
#define MVFR0 ((VFPSystemRegister)0x6)
#define MVFR1 ((VFPSystemRegister)0x7)
extern VFPSystemRegister::VFPSystemRegisterImpl all_VFPSystemRegisterImpls[VFPSystemRegister::number_of_registers + 1] INTERNAL_VISIBILITY;
inline constexpr const VFPSystemRegister::VFPSystemRegisterImpl* VFPSystemRegister::VFPSystemRegisterImpl::first() {
return all_VFPSystemRegisterImpls + 1;
}
constexpr VFPSystemRegister vfpsnoreg = VFPSystemRegister();
inline constexpr VFPSystemRegister as_VFPSystemRegister(int encoding) {
switch (encoding) {
case VFPSystemRegister::FPSID: return VFPSystemRegister(VFPSystemRegister::_FPSID_store_idx);
case VFPSystemRegister::FPSCR: return VFPSystemRegister(VFPSystemRegister::_FPSCR_store_idx);
case VFPSystemRegister::MVFR0: return VFPSystemRegister(VFPSystemRegister::_MVFR0_store_idx);
case VFPSystemRegister::MVFR1: return VFPSystemRegister(VFPSystemRegister::_MVFR1_store_idx);
default: return vfpsnoreg;
}
}
constexpr VFPSystemRegister FPSID = as_VFPSystemRegister(VFPSystemRegister::FPSID);
constexpr VFPSystemRegister FPSCR = as_VFPSystemRegister(VFPSystemRegister::FPSCR);
constexpr VFPSystemRegister MVFR0 = as_VFPSystemRegister(VFPSystemRegister::MVFR0);
constexpr VFPSystemRegister MVFR1 = as_VFPSystemRegister(VFPSystemRegister::MVFR1);
/*
* Register definitions shared across interpreter and compiler
*/
#define Rexception_obj R4
#define Rexception_pc R5
constexpr Register Rexception_obj = R4;
constexpr Register Rexception_pc = R5;
/*
* Interpreter register definitions common to C++ and template interpreters.
*/
#define Rlocals R8
#define Rmethod R9
#define Rthread R10
#define Rtemp R12
constexpr Register Rlocals = R8;
constexpr Register Rmethod = R9;
constexpr Register Rthread = R10;
constexpr Register Rtemp = R12;
// Interpreter calling conventions
#define Rparams SP
#define Rsender_sp R4
constexpr Register Rparams = SP;
constexpr Register Rsender_sp = R4;
// JSR292
// Note: R5_mh is needed only during the call setup, including adapters
// This does not seem to conflict with Rexception_pc
// In case of issues, R3 might be OK but adapters calling the runtime would have to save it
#define R5_mh R5 // MethodHandle register, used during the call setup
constexpr Register R5_mh = R5; // MethodHandle register, used during the call setup
/*
* C++ Interpreter Register Defines
*/
#define Rsave0 R4
#define Rsave1 R5
#define Rsave2 R6
#define Rstate altFP_7_11 // R7 or R11
#define Ricklass R8
constexpr Register Rsave0 = R4;
constexpr Register Rsave1 = R5;
constexpr Register Rsave2 = R6;
constexpr Register Rstate = altFP_7_11; // R7 or R11
constexpr Register Ricklass = R8;
/*
* TemplateTable Interpreter Register Usage
*/
// Temporary registers
#define R0_tmp R0
#define R1_tmp R1
#define R2_tmp R2
#define R3_tmp R3
#define R4_tmp R4
#define R5_tmp R5
#define R12_tmp R12
#define LR_tmp LR
constexpr Register R0_tmp = R0;
constexpr Register R1_tmp = R1;
constexpr Register R2_tmp = R2;
constexpr Register R3_tmp = R3;
constexpr Register R4_tmp = R4;
constexpr Register R5_tmp = R5;
constexpr Register R12_tmp = R12;
constexpr Register LR_tmp = LR;
#define S0_tmp S0
#define S1_tmp S1_reg
constexpr FloatRegister S0_tmp = S0;
constexpr FloatRegister S1_tmp = S1_reg;
#define D0_tmp D0
#define D1_tmp D1
constexpr FloatRegister D0_tmp = D0;
constexpr FloatRegister D1_tmp = D1;
// Temporary registers saved across VM calls (according to C calling conventions)
#define Rtmp_save0 R4
#define Rtmp_save1 R5
constexpr Register Rtmp_save0 = R4;
constexpr Register Rtmp_save1 = R5;
// Cached TOS value
#define R0_tos R0
constexpr Register R0_tos = R0;
#define R0_tos_lo R0
#define R1_tos_hi R1
constexpr Register R0_tos_lo = R0;
constexpr Register R1_tos_hi = R1;
#define S0_tos S0
#define D0_tos D0
constexpr FloatRegister S0_tos = S0;
constexpr FloatRegister D0_tos = D0;
// Dispatch table
#define RdispatchTable R6
constexpr Register RdispatchTable = R6;
// Bytecode pointer
#define Rbcp altFP_7_11
constexpr Register Rbcp = altFP_7_11;
// Pre-loaded next bytecode for the dispatch
#define R3_bytecode R3
constexpr Register R3_bytecode = R3;
// Conventions between bytecode templates and stubs
#define R2_ClassCastException_obj R2
#define R4_ArrayIndexOutOfBounds_index R4
constexpr Register R2_ClassCastException_obj = R2;
constexpr Register R4_ArrayIndexOutOfBounds_index = R4;
// Interpreter expression stack top
#define Rstack_top SP
constexpr Register Rstack_top = SP;
/*
* Linux 32-bit ARM C ABI Register calling conventions
@ -444,10 +526,11 @@ class VFPSystemRegisterImpl : public AbstractRegisterImpl {
* R14 (LR) Link register
* R15 (PC) Program Counter
*/
#define c_rarg0 R0
#define c_rarg1 R1
#define c_rarg2 R2
#define c_rarg3 R3
constexpr Register c_rarg0 = R0;
constexpr Register c_rarg1 = R1;
constexpr Register c_rarg2 = R2;
constexpr Register c_rarg3 = R3;
#define GPR_PARAMS 4
@ -455,10 +538,10 @@ class VFPSystemRegisterImpl : public AbstractRegisterImpl {
// Java ABI
// XXX Is this correct?
#define j_rarg0 c_rarg0
#define j_rarg1 c_rarg1
#define j_rarg2 c_rarg2
#define j_rarg3 c_rarg3
constexpr Register j_rarg0 = c_rarg0;
constexpr Register j_rarg1 = c_rarg1;
constexpr Register j_rarg2 = c_rarg2;
constexpr Register j_rarg3 = c_rarg3;
#endif // CPU_ARM_REGISTER_ARM_HPP

View File

@ -182,8 +182,6 @@ UncommonTrapBlob* OptoRuntime::generate_uncommon_trap_blob() {
//------------------------------ generate_exception_blob ---------------------------
// creates exception blob at the end
// Using exception blob, this code is jumped from a compiled method.
// (see emit_exception_handler in sparc.ad file)
//
// Given an exception pc at a call we call into the runtime for the
// handler in this method. This handler might merely restore state

View File

@ -70,7 +70,7 @@ public:
enum RegisterLayout {
fpu_save_size = FloatRegisterImpl::number_of_registers,
fpu_save_size = FloatRegister::number_of_registers,
#ifndef __SOFTFP__
D0_offset = 0,
#endif
@ -139,8 +139,8 @@ OopMap* RegisterSaver::save_live_registers(MacroAssembler* masm,
if (VM_Version::has_vfp3_32()) {
__ fpush(FloatRegisterSet(D16, 16));
} else {
if (FloatRegisterImpl::number_of_registers > 32) {
assert(FloatRegisterImpl::number_of_registers == 64, "nb fp registers should be 64");
if (FloatRegister::number_of_registers > 32) {
assert(FloatRegister::number_of_registers == 64, "nb fp registers should be 64");
__ sub(SP, SP, 32 * wordSize);
}
}
@ -182,8 +182,8 @@ void RegisterSaver::restore_live_registers(MacroAssembler* masm, bool restore_lr
if (VM_Version::has_vfp3_32()) {
__ fpop(FloatRegisterSet(D16, 16));
} else {
if (FloatRegisterImpl::number_of_registers > 32) {
assert(FloatRegisterImpl::number_of_registers == 64, "nb fp registers should be 64");
if (FloatRegister::number_of_registers > 32) {
assert(FloatRegister::number_of_registers == 64, "nb fp registers should be 64");
__ add(SP, SP, 32 * wordSize);
}
}

View File

@ -30,14 +30,14 @@ void VMRegImpl::set_regName() {
Register reg = ::as_Register(0);
int i;
for (i = 0; i < ConcreteRegisterImpl::max_gpr; reg = reg->successor()) {
for (int j = 0; j < (1 << ConcreteRegisterImpl::log_vmregs_per_gpr); j++) {
for (int j = 0; j < Register::max_slots_per_register; j++) {
regName[i++] = reg->name();
}
}
#ifndef __SOFTFP__
FloatRegister freg = ::as_FloatRegister(0);
for ( ; i < ConcreteRegisterImpl::max_fpr ; ) {
for (int j = 0; j < (1 << ConcreteRegisterImpl::log_vmregs_per_fpr); j++) {
for (int j = 0; j < Register::max_slots_per_register; j++) {
regName[i++] = freg->name();
}
freg = freg->successor();

View File

@ -36,20 +36,20 @@
inline Register as_Register() {
assert(is_Register(), "must be");
assert(is_concrete(), "concrete register expected");
return ::as_Register(value() >> ConcreteRegisterImpl::log_vmregs_per_gpr);
return ::as_Register(value() / Register::max_slots_per_register);
}
inline FloatRegister as_FloatRegister() {
assert(is_FloatRegister(), "must be");
assert(is_concrete(), "concrete register expected");
return ::as_FloatRegister((value() - ConcreteRegisterImpl::max_gpr) >> ConcreteRegisterImpl::log_vmregs_per_fpr);
return ::as_FloatRegister((value() - ConcreteRegisterImpl::max_gpr) / FloatRegister::max_slots_per_register);
}
inline bool is_concrete() {
if (is_Register()) {
return ((value() & right_n_bits(ConcreteRegisterImpl::log_vmregs_per_gpr)) == 0);
return (value() % Register::max_slots_per_register == 0);
} else if (is_FloatRegister()) {
return (((value() - ConcreteRegisterImpl::max_gpr) & right_n_bits(ConcreteRegisterImpl::log_vmregs_per_fpr)) == 0);
return (value() % FloatRegister::max_slots_per_register == 0); // Single slot
} else {
return false;
}

View File

@ -25,11 +25,11 @@
#ifndef CPU_ARM_VMREG_ARM_INLINE_HPP
#define CPU_ARM_VMREG_ARM_INLINE_HPP
inline VMReg RegisterImpl::as_VMReg() {
return VMRegImpl::as_VMReg(encoding() << ConcreteRegisterImpl::log_vmregs_per_gpr);
inline VMReg Register::RegisterImpl::as_VMReg() const {
return VMRegImpl::as_VMReg(encoding() * Register::max_slots_per_register);
}
inline VMReg FloatRegisterImpl::as_VMReg() {
return VMRegImpl::as_VMReg((encoding() << ConcreteRegisterImpl::log_vmregs_per_fpr) + ConcreteRegisterImpl::max_gpr);
inline VMReg FloatRegister::FloatRegisterImpl::as_VMReg() const {
return VMRegImpl::as_VMReg((encoding() * FloatRegister::max_slots_per_register) + ConcreteRegisterImpl::max_gpr);
}
#endif // CPU_ARM_VMREG_ARM_INLINE_HPP

View File

@ -157,6 +157,9 @@ inline D AtomicAccess::PlatformAdd<8>::add_then_fetch(D volatile* dest, I add_va
return result;
}
template<>
struct AtomicAccess::PlatformXchg<1> : AtomicAccess::XchgUsingCmpxchg<1> {};
template<>
template<typename T>
inline T AtomicAccess::PlatformXchg<4>::operator()(T volatile* dest,

View File

@ -264,12 +264,19 @@ int LIR_Assembler::emit_deopt_handler() {
}
int offset = code_offset();
Label start;
__ bind(start);
__ bl64_patchable(SharedRuntime::deopt_blob()->unpack(), relocInfo::runtime_call_type);
int entry_offset = __ offset();
__ b(start);
guarantee(code_offset() - offset <= deopt_handler_size(), "overflow");
assert(code_offset() - entry_offset >= NativePostCallNop::first_check_size,
"out of bounds read in post-call NOP check");
__ end_a_stub();
return offset;
return entry_offset;
}

View File

@ -63,7 +63,7 @@ enum {
_static_call_stub_size = 4 * BytesPerInstWord + MacroAssembler::b64_patchable_size, // or smaller
_call_stub_size = _static_call_stub_size + MacroAssembler::trampoline_stub_size, // or smaller
_exception_handler_size = MacroAssembler::b64_patchable_size, // or smaller
_deopt_handler_size = MacroAssembler::bl64_patchable_size
_deopt_handler_size = MacroAssembler::bl64_patchable_size + BytesPerInstWord
};
// '_static_call_stub_size' is only used on ppc (see LIR_Assembler::emit_static_call_stub()

View File

@ -51,8 +51,6 @@ class NativeInstruction {
friend class Relocation;
public:
bool is_post_call_nop() const { return MacroAssembler::is_post_call_nop(long_at(0)); }
bool is_jump() const { return Assembler::is_b(long_at(0)); } // See NativeGeneralJump.
bool is_sigtrap_ic_miss_check() {
@ -531,6 +529,14 @@ class NativePostCallNop: public NativeInstruction {
};
public:
enum ppc_specific_constants {
// If the check is adjusted to read beyond size of the instruction at the deopt handler stub
// code entry point, it has to happen in two stages - to prevent out of bounds access in case
// the return address points to the entry point which could be at the end of page.
first_check_size = BytesPerInstWord
};
bool is_post_call_nop() const { return MacroAssembler::is_post_call_nop(long_at(0)); }
bool check() const { return is_post_call_nop(); }
bool decode(int32_t& oopmap_slot, int32_t& cb_offset) const {
uint32_t instr_bits = long_at(0);

View File

@ -2088,17 +2088,11 @@ class HandlerImpl {
public:
static int emit_exception_handler(C2_MacroAssembler *masm);
static int emit_deopt_handler(C2_MacroAssembler* masm);
static uint size_exception_handler() {
// The exception_handler is a b64_patchable.
return MacroAssembler::b64_patchable_size;
}
static uint size_deopt_handler() {
// The deopt_handler is a bl64_patchable.
return MacroAssembler::bl64_patchable_size;
return MacroAssembler::bl64_patchable_size + BytesPerInstWord;
}
};
@ -2114,22 +2108,6 @@ public:
source %{
int HandlerImpl::emit_exception_handler(C2_MacroAssembler *masm) {
address base = __ start_a_stub(size_exception_handler());
if (base == nullptr) {
ciEnv::current()->record_failure("CodeCache is full");
return 0; // CodeBuffer::expand failed
}
int offset = __ offset();
__ b64_patchable((address)OptoRuntime::exception_blob()->content_begin(),
relocInfo::runtime_call_type);
assert(__ offset() - offset == (int)size_exception_handler(), "must be fixed size");
__ end_a_stub();
return offset;
}
// The deopt_handler is like the exception handler, but it calls to
// the deoptimization blob instead of jumping to the exception blob.
int HandlerImpl::emit_deopt_handler(C2_MacroAssembler* masm) {
@ -2140,12 +2118,23 @@ int HandlerImpl::emit_deopt_handler(C2_MacroAssembler* masm) {
}
int offset = __ offset();
Label start;
__ bind(start);
__ bl64_patchable((address)SharedRuntime::deopt_blob()->unpack(),
relocInfo::runtime_call_type);
int entry_offset = __ offset();
__ b(start);
assert(__ offset() - offset == (int) size_deopt_handler(), "must be fixed size");
assert(__ offset() - entry_offset >= NativePostCallNop::first_check_size,
"out of bounds read in post-call NOP check");
__ end_a_stub();
return offset;
return entry_offset;
}
//=============================================================================
@ -2394,6 +2383,10 @@ bool Matcher::is_reg2reg_move(MachNode* m) {
return false;
}
bool Matcher::is_register_biasing_candidate(const MachNode* mdef, int oper_index) {
return false;
}
bool Matcher::is_generic_vector(MachOper* opnd) {
ShouldNotReachHere(); // generic vector operands not supported
return false;

View File

@ -46,7 +46,6 @@
//------------------------------generate_exception_blob---------------------------
// Creates exception blob at the end.
// Using exception blob, this code is jumped from a compiled method.
//
// Given an exception pc at a call we call into the runtime for the
// handler in this method. This handler might merely restore state

View File

@ -83,7 +83,6 @@ class RegisterSaver {
static OopMap* push_frame_reg_args_and_save_live_registers(MacroAssembler* masm,
int* out_frame_size_in_bytes,
bool generate_oop_map,
int return_pc_adjustment,
ReturnPCLocation return_pc_location,
bool save_vectors = false);
static void restore_live_registers_and_pop_frame(MacroAssembler* masm,
@ -262,7 +261,6 @@ static const RegisterSaver::LiveRegType RegisterSaver_LiveVecRegs[] = {
OopMap* RegisterSaver::push_frame_reg_args_and_save_live_registers(MacroAssembler* masm,
int* out_frame_size_in_bytes,
bool generate_oop_map,
int return_pc_adjustment,
ReturnPCLocation return_pc_location,
bool save_vectors) {
// Push an abi_reg_args-frame and store all registers which may be live.
@ -271,7 +269,6 @@ OopMap* RegisterSaver::push_frame_reg_args_and_save_live_registers(MacroAssemble
// propagated to the RegisterMap of the caller frame during
// StackFrameStream construction (needed for deoptimization; see
// compiledVFrame::create_stack_value).
// If return_pc_adjustment != 0 adjust the return pc by return_pc_adjustment.
// Updated return pc is returned in R31 (if not return_pc_is_pre_saved).
// calculate frame size
@ -305,14 +302,11 @@ OopMap* RegisterSaver::push_frame_reg_args_and_save_live_registers(MacroAssemble
// Do the save_LR by hand and adjust the return pc if requested.
switch (return_pc_location) {
case return_pc_is_lr: __ mflr(R31); break;
case return_pc_is_pre_saved: assert(return_pc_adjustment == 0, "unsupported"); break;
case return_pc_is_pre_saved: break;
case return_pc_is_thread_saved_exception_pc: __ ld(R31, thread_(saved_exception_pc)); break;
default: ShouldNotReachHere();
}
if (return_pc_location != return_pc_is_pre_saved) {
if (return_pc_adjustment != 0) {
__ addi(R31, R31, return_pc_adjustment);
}
__ std(R31, frame_size_in_bytes + _abi0(lr), R1_SP);
}
@ -2907,22 +2901,15 @@ void SharedRuntime::generate_deopt_blob() {
// deopt_handler: call_deopt_stub
// cur. return pc --> ...
//
// So currently SR_LR points behind the call in the deopt handler.
// We adjust it such that it points to the start of the deopt handler.
// The return_pc has been stored in the frame of the deoptee and
// will replace the address of the deopt_handler in the call
// to Deoptimization::fetch_unroll_info below.
// We can't grab a free register here, because all registers may
// contain live values, so let the RegisterSaver do the adjustment
// of the return pc.
const int return_pc_adjustment_no_exception = -MacroAssembler::bl64_patchable_size;
// Push the "unpack frame"
// Save everything in sight.
map = RegisterSaver::push_frame_reg_args_and_save_live_registers(masm,
&first_frame_size_in_bytes,
/*generate_oop_map=*/ true,
return_pc_adjustment_no_exception,
RegisterSaver::return_pc_is_lr);
assert(map != nullptr, "OopMap must have been created");
@ -2957,7 +2944,6 @@ void SharedRuntime::generate_deopt_blob() {
RegisterSaver::push_frame_reg_args_and_save_live_registers(masm,
&first_frame_size_in_bytes,
/*generate_oop_map=*/ false,
/*return_pc_adjustment_exception=*/ 0,
RegisterSaver::return_pc_is_pre_saved);
// Deopt during an exception. Save exec mode for unpack_frames.
@ -2975,7 +2961,6 @@ void SharedRuntime::generate_deopt_blob() {
RegisterSaver::push_frame_reg_args_and_save_live_registers(masm,
&first_frame_size_in_bytes,
/*generate_oop_map=*/ false,
/*return_pc_adjustment_reexecute=*/ 0,
RegisterSaver::return_pc_is_pre_saved);
__ li(exec_mode_reg, Deoptimization::Unpack_reexecute);
#endif
@ -3266,7 +3251,6 @@ SafepointBlob* SharedRuntime::generate_handler_blob(StubId id, address call_ptr)
map = RegisterSaver::push_frame_reg_args_and_save_live_registers(masm,
&frame_size_in_bytes,
/*generate_oop_map=*/ true,
/*return_pc_adjustment=*/0,
return_pc_location, save_vectors);
// The following is basically a call_VM. However, we need the precise
@ -3367,7 +3351,6 @@ RuntimeStub* SharedRuntime::generate_resolve_blob(StubId id, address destination
map = RegisterSaver::push_frame_reg_args_and_save_live_registers(masm,
&frame_size_in_bytes,
/*generate_oop_map*/ true,
/*return_pc_adjustment*/ 0,
RegisterSaver::return_pc_is_lr);
// Use noreg as last_Java_pc, the return pc will be reconstructed

View File

@ -377,12 +377,20 @@ int LIR_Assembler::emit_deopt_handler() {
int offset = code_offset();
__ auipc(ra, 0);
__ far_jump(RuntimeAddress(SharedRuntime::deopt_blob()->unpack()));
Label start;
__ bind(start);
__ far_call(RuntimeAddress(SharedRuntime::deopt_blob()->unpack()));
int entry_offset = __ offset();
__ j(start);
guarantee(code_offset() - offset <= deopt_handler_size(), "overflow");
assert(code_offset() - entry_offset >= NativePostCallNop::first_check_size,
"out of bounds read in post-call NOP check");
__ end_a_stub();
return offset;
return entry_offset;
}
void LIR_Assembler::return_op(LIR_Opr result, C1SafepointPollStub* code_stub) {

View File

@ -72,7 +72,7 @@ private:
// See emit_exception_handler for detail
_exception_handler_size = DEBUG_ONLY(256) NOT_DEBUG(32), // or smaller
// See emit_deopt_handler for detail
// auipc (1) + far_jump (2)
// far_call (2) + j (1)
_deopt_handler_size = 1 * MacroAssembler::instruction_size +
2 * MacroAssembler::instruction_size
};

View File

@ -311,12 +311,19 @@ inline bool NativeInstruction::is_jump_or_nop() {
// can store an offset from the initial nop to the nmethod.
class NativePostCallNop: public NativeInstruction {
public:
enum RISCV_specific_constants {
// The two parts should be checked separately to prevent out of bounds access in
// case the return address points to the deopt handler stub code entry point
// which could be at the end of page.
first_check_size = instruction_size
};
bool check() const {
// Check for two instructions: nop; lui zr, hi20
// These instructions only ever appear together in a post-call
// NOP, so it's unnecessary to check that the third instruction is
// an addiw as well.
return is_nop() && MacroAssembler::is_lui_to_zr_at(addr_at(4));
return is_nop() && MacroAssembler::is_lui_to_zr_at(addr_at(first_check_size));
}
bool decode(int32_t& oopmap_slot, int32_t& cb_offset) const;
bool patch(int32_t oopmap_slot, int32_t cb_offset);

View File

@ -1049,15 +1049,10 @@ class HandlerImpl {
public:
static int emit_exception_handler(C2_MacroAssembler *masm);
static int emit_deopt_handler(C2_MacroAssembler* masm);
static uint size_exception_handler() {
return MacroAssembler::far_branch_size();
}
static uint size_deopt_handler() {
// count auipc + far branch
// count far call + j
return NativeInstruction::instruction_size + MacroAssembler::far_branch_size();
}
};
@ -1838,25 +1833,6 @@ uint MachUEPNode::size(PhaseRegAlloc* ra_) const
//=============================================================================
// Emit exception handler code.
int HandlerImpl::emit_exception_handler(C2_MacroAssembler* masm)
{
// auipc t1, #exception_blob_entry_point
// jr (offset)t1
// Note that the code buffer's insts_mark is always relative to insts.
// That's why we must use the macroassembler to generate a handler.
address base = __ start_a_stub(size_exception_handler());
if (base == nullptr) {
ciEnv::current()->record_failure("CodeCache is full");
return 0; // CodeBuffer::expand failed
}
int offset = __ offset();
__ far_jump(RuntimeAddress(OptoRuntime::exception_blob()->entry_point()));
assert(__ offset() - offset <= (int) size_exception_handler(), "overflow");
__ end_a_stub();
return offset;
}
// Emit deopt handler code.
int HandlerImpl::emit_deopt_handler(C2_MacroAssembler* masm)
{
@ -1867,12 +1843,19 @@ int HandlerImpl::emit_deopt_handler(C2_MacroAssembler* masm)
}
int offset = __ offset();
__ auipc(ra, 0);
__ far_jump(RuntimeAddress(SharedRuntime::deopt_blob()->unpack()));
Label start;
__ bind(start);
__ far_call(RuntimeAddress(SharedRuntime::deopt_blob()->unpack()));
int entry_offset = __ offset();
__ j(start);
assert(__ offset() - offset <= (int) size_deopt_handler(), "overflow");
assert(__ offset() - entry_offset >= NativePostCallNop::first_check_size,
"out of bounds read in post-call NOP check");
__ end_a_stub();
return offset;
return entry_offset;
}
// REQUIRED MATCHER CODE
@ -2070,6 +2053,10 @@ bool Matcher::is_reg2reg_move(MachNode* m) {
return false;
}
bool Matcher::is_register_biasing_candidate(const MachNode* mdef, int oper_index) {
return false;
}
bool Matcher::is_generic_vector(MachOper* opnd) {
ShouldNotReachHere(); // generic vector operands not supported
return false;

View File

@ -249,8 +249,6 @@ UncommonTrapBlob* OptoRuntime::generate_uncommon_trap_blob() {
//------------------------------generate_exception_blob---------------------------
// creates exception blob at the end
// Using exception blob, this code is jumped from a compiled method.
// (see emit_exception_handler in riscv.ad file)
//
// Given an exception pc at a call we call into the runtime for the
// handler in this method. This handler might merely restore state

View File

@ -89,11 +89,12 @@ class VM_Version : public Abstract_VM_Version {
FLAG_SET_DEFAULT(flag, true); \
} else { \
FLAG_SET_DEFAULT(flag, false); \
stringStream ss; \
deps_string(ss, dep0, ##__VA_ARGS__); \
warning("Cannot enable " #flag ", it's missing dependent extension(s) %s", ss.as_string(true)); \
/* Sync CPU features with flags */ \
disable_feature(); \
stringStream ss; \
ss.print("missing dependent extension(s): "); \
deps_string(ss, dep0, ##__VA_ARGS__); \
log_disabled(ss.as_string(true)); \
} \
} else { \
/* Sync CPU features with flags */ \
@ -101,11 +102,12 @@ class VM_Version : public Abstract_VM_Version {
disable_feature(); \
} else if (!deps_all_enabled(dep0, ##__VA_ARGS__)) { \
FLAG_SET_DEFAULT(flag, false); \
stringStream ss; \
deps_string(ss, dep0, ##__VA_ARGS__); \
warning("Cannot enable " #flag ", it's missing dependent extension(s) %s", ss.as_string(true)); \
/* Sync CPU features with flags */ \
disable_feature(); \
stringStream ss; \
ss.print("missing dependent extension(s): "); \
deps_string(ss, dep0, ##__VA_ARGS__); \
log_disabled(ss.as_string(true)); \
} \
} \
} \
@ -136,6 +138,7 @@ class VM_Version : public Abstract_VM_Version {
RVExtFeatures::current()->clear_feature(_cpu_feature_index);
}
void log_enabled();
void log_disabled(const char* reason);
protected:
bool deps_all_enabled(RVExtFeatureValue* dep0, ...) {

View File

@ -272,14 +272,27 @@ int LIR_Assembler::emit_deopt_handler() {
// Not enough space left for the handler.
bailout("deopt handler overflow");
return -1;
} int offset = code_offset();
}
int offset = code_offset();
Label start;
__ bind(start);
// Size must be constant (see HandlerImpl::emit_deopt_handler).
__ load_const(Z_R1_scratch, SharedRuntime::deopt_blob()->unpack());
__ call(Z_R1_scratch);
int entry_offset = __ offset();
__ z_bru(start);
guarantee(code_offset() - offset <= deopt_handler_size(), "overflow");
assert(code_offset() - entry_offset >= NativePostCallNop::first_check_size,
"out of bounds read in post-call NOP check");
__ end_a_stub();
return offset;
return entry_offset;
}
void LIR_Assembler::jobject2reg(jobject o, Register reg) {

View File

@ -649,6 +649,13 @@ class NativeGeneralJump: public NativeInstruction {
class NativePostCallNop: public NativeInstruction {
public:
enum z_specific_constants {
// Once the check is implemented, this has to specify number of bytes checked on the first
// read. If the check would read beyond size of the instruction at the deopt handler stub
// code entry point, then it has to happen in two stages - to prevent out of bounds access
// in case the return address points to the entry point which could be at the end of page.
first_check_size = 0 // check is unimplemented
};
bool check() const { Unimplemented(); return false; }
bool decode(int32_t& oopmap_slot, int32_t& cb_offset) const { return false; }
bool patch(int32_t oopmap_slot, int32_t cb_offset) { Unimplemented(); return false; }

View File

@ -43,8 +43,6 @@
//------------------------------generate_exception_blob---------------------------
// creates exception blob at the end
// Using exception blob, this code is jumped from a compiled method.
// (see emit_exception_handler in s390.ad file)
//
// Given an exception pc at a call we call into the runtime for the
// handler in this method. This handler might merely restore state

View File

@ -1649,15 +1649,10 @@ source_hpp %{ // Header information of the source block.
class HandlerImpl {
public:
static int emit_exception_handler(C2_MacroAssembler *masm);
static int emit_deopt_handler(C2_MacroAssembler* masm);
static uint size_exception_handler() {
return NativeJump::max_instruction_size();
}
static uint size_deopt_handler() {
return NativeCall::max_instruction_size();
return NativeCall::max_instruction_size() + MacroAssembler::jump_pcrelative_size();
}
};
@ -1672,43 +1667,6 @@ public:
source %{
// This exception handler code snippet is placed after the method's
// code. It is the return point if an exception occurred. it jumps to
// the exception blob.
//
// If the method gets deoptimized, the method and this code snippet
// get patched.
//
// 1) Trampoline code gets patched into the end of this exception
// handler. the trampoline code jumps to the deoptimization blob.
//
// 2) The return address in the method's code will get patched such
// that it jumps to the trampoline.
//
// 3) The handler will get patched such that it does not jump to the
// exception blob, but to an entry in the deoptimization blob being
// aware of the exception.
int HandlerImpl::emit_exception_handler(C2_MacroAssembler *masm) {
Register temp_reg = Z_R1;
address base = __ start_a_stub(size_exception_handler());
if (base == nullptr) {
ciEnv::current()->record_failure("CodeCache is full");
return 0; // CodeBuffer::expand failed
}
int offset = __ offset();
// Use unconditional pc-relative jump with 32-bit range here.
__ load_const_optimized(temp_reg, (address)OptoRuntime::exception_blob()->content_begin());
__ z_br(temp_reg);
assert(__ offset() - offset <= (int) size_exception_handler(), "overflow");
__ end_a_stub();
return offset;
}
// Emit deopt handler code.
int HandlerImpl::emit_deopt_handler(C2_MacroAssembler* masm) {
address base = __ start_a_stub(size_deopt_handler());
@ -1720,14 +1678,24 @@ int HandlerImpl::emit_deopt_handler(C2_MacroAssembler* masm) {
int offset = __ offset();
Label start;
__ bind(start);
// Size_deopt_handler() must be exact on zarch, so for simplicity
// we do not use load_const_opt here.
__ load_const(Z_R1, SharedRuntime::deopt_blob()->unpack());
__ call(Z_R1);
int entry_offset = __ offset();
__ z_bru(start);
assert(__ offset() - offset == (int) size_deopt_handler(), "must be fixed size");
assert(__ offset() - entry_offset >= NativePostCallNop::first_check_size,
"out of bounds read in post-call NOP check");
__ end_a_stub();
return offset;
return entry_offset;
}
//=============================================================================
@ -1897,6 +1865,10 @@ bool Matcher::is_reg2reg_move(MachNode* m) {
return false;
}
bool Matcher::is_register_biasing_candidate(const MachNode* mdef, int oper_index) {
return false;
}
bool Matcher::is_generic_vector(MachOper* opnd) {
ShouldNotReachHere(); // generic vector operands not supported
return false;

View File

@ -2544,14 +2544,10 @@ void SharedRuntime::generate_deopt_blob() {
// Normal entry (non-exception case)
//
// We have been called from the deopt handler of the deoptee.
// Z_R14 points behind the call in the deopt handler. We adjust
// it such that it points to the start of the deopt handler.
// Z_R14 points to the entry point of the deopt handler.
// The return_pc has been stored in the frame of the deoptee and
// will replace the address of the deopt_handler in the call
// to Deoptimization::fetch_unroll_info below.
// The (int) cast is necessary, because -((unsigned int)14)
// is an unsigned int.
__ add2reg(Z_R14, -(int)NativeCall::max_instruction_size());
const Register exec_mode_reg = Z_tmp_1;

View File

@ -3860,6 +3860,46 @@ void Assembler::evmovdquq(Address dst, KRegister mask, XMMRegister src, bool mer
emit_operand(src, dst, 0);
}
void Assembler::vmovsldup(XMMRegister dst, XMMRegister src, int vector_len) {
assert(vector_len == AVX_512bit ? VM_Version::supports_evex() : VM_Version::supports_avx(), "");
InstructionAttr attributes(vector_len, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ true);
int encode = vex_prefix_and_encode(dst->encoding(), 0, src->encoding(), VEX_SIMD_F3, VEX_OPCODE_0F, &attributes);
emit_int16(0x12, (0xC0 | encode));
}
void Assembler::vmovshdup(XMMRegister dst, XMMRegister src, int vector_len) {
assert(vector_len == AVX_512bit ? VM_Version::supports_evex() : VM_Version::supports_avx(), "");
InstructionAttr attributes(vector_len, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ true);
int encode = vex_prefix_and_encode(dst->encoding(), 0, src->encoding(), VEX_SIMD_F3, VEX_OPCODE_0F, &attributes);
emit_int16(0x16, (0xC0 | encode));
}
void Assembler::evmovsldup(XMMRegister dst, KRegister mask, XMMRegister src, bool merge, int vector_len) {
assert(VM_Version::supports_evex(), "");
assert(vector_len == AVX_512bit || VM_Version::supports_avx512vl(), "");
InstructionAttr attributes(vector_len, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ false, /* uses_vl */ true);
attributes.set_embedded_opmask_register_specifier(mask);
attributes.set_is_evex_instruction();
if (merge) {
attributes.reset_is_clear_context();
}
int encode = vex_prefix_and_encode(dst->encoding(), 0, src->encoding(), VEX_SIMD_F3, VEX_OPCODE_0F, &attributes);
emit_int16(0x12, (0xC0 | encode));
}
void Assembler::evmovshdup(XMMRegister dst, KRegister mask, XMMRegister src, bool merge, int vector_len) {
assert(VM_Version::supports_evex(), "");
assert(vector_len == AVX_512bit || VM_Version::supports_avx512vl(), "");
InstructionAttr attributes(vector_len, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ false, /* uses_vl */ true);
attributes.set_embedded_opmask_register_specifier(mask);
attributes.set_is_evex_instruction();
if (merge) {
attributes.reset_is_clear_context();
}
int encode = vex_prefix_and_encode(dst->encoding(), 0, src->encoding(), VEX_SIMD_F3, VEX_OPCODE_0F, &attributes);
emit_int16(0x16, (0xC0 | encode));
}
// Uses zero extension on 64bit
void Assembler::movl(Register dst, int32_t imm32) {

View File

@ -1664,6 +1664,11 @@ private:
void evmovdqaq(XMMRegister dst, Address src, int vector_len);
void evmovdqaq(XMMRegister dst, KRegister mask, Address src, bool merge, int vector_len);
void vmovsldup(XMMRegister dst, XMMRegister src, int vector_len);
void vmovshdup(XMMRegister dst, XMMRegister src, int vector_len);
void evmovsldup(XMMRegister dst, KRegister mask, XMMRegister src, bool merge, int vector_len);
void evmovshdup(XMMRegister dst, KRegister mask, XMMRegister src, bool merge, int vector_len);
// Move lower 64bit to high 64bit in 128bit register
void movlhps(XMMRegister dst, XMMRegister src);

View File

@ -450,14 +450,22 @@ int LIR_Assembler::emit_deopt_handler() {
}
int offset = code_offset();
InternalAddress here(__ pc());
__ pushptr(here.addr(), rscratch1);
__ jump(RuntimeAddress(SharedRuntime::deopt_blob()->unpack()));
Label start;
__ bind(start);
__ call(RuntimeAddress(SharedRuntime::deopt_blob()->unpack()));
int entry_offset = __ offset();
__ jmp(start);
guarantee(code_offset() - offset <= deopt_handler_size(), "overflow");
assert(code_offset() - entry_offset >= NativePostCallNop::first_check_size,
"out of bounds read in post-call NOP check");
__ end_a_stub();
return offset;
return entry_offset;
}
void LIR_Assembler::return_op(LIR_Opr result, C1SafepointPollStub* code_stub) {

View File

@ -48,7 +48,7 @@
enum {
_call_stub_size = 28,
_exception_handler_size = DEBUG_ONLY(1*K) NOT_DEBUG(175),
_deopt_handler_size = 17
_deopt_handler_size = 7
};
public:

View File

@ -89,10 +89,10 @@ void G1BarrierSetAssembler::gen_write_ref_array_pre_barrier(MacroAssembler* masm
void G1BarrierSetAssembler::gen_write_ref_array_post_barrier(MacroAssembler* masm, DecoratorSet decorators,
Register addr, Register count, Register tmp) {
Label done;
Label L_done;
__ testptr(count, count);
__ jcc(Assembler::zero, done);
__ jccb(Assembler::zero, L_done);
// Calculate end address in "count".
Address::ScaleFactor scale = UseCompressedOops ? Address::times_4 : Address::times_8;
@ -111,31 +111,31 @@ void G1BarrierSetAssembler::gen_write_ref_array_post_barrier(MacroAssembler* mas
__ shrptr(count, CardTable::card_shift());
__ addptr(count, tmp);
Label loop;
Label L_loop;
// Iterate from start card to end card (inclusive).
__ bind(loop);
__ bind(L_loop);
Label is_clean_card;
Label L_is_clean_card;
if (UseCondCardMark) {
__ cmpb(Address(addr, 0), G1CardTable::clean_card_val());
__ jcc(Assembler::equal, is_clean_card);
__ jccb(Assembler::equal, L_is_clean_card);
} else {
__ movb(Address(addr, 0), G1CardTable::dirty_card_val());
}
Label next_card;
__ bind(next_card);
Label L_next_card;
__ bind(L_next_card);
__ addptr(addr, sizeof(CardTable::CardValue));
__ cmpptr(addr, count);
__ jcc(Assembler::belowEqual, loop);
__ jmp(done);
__ jccb(Assembler::belowEqual, L_loop);
__ jmpb(L_done);
__ bind(is_clean_card);
// Card was clean. Dirty card and go to next..
__ bind(L_is_clean_card);
// Card was clean. Dirty card and go to next.
__ movb(Address(addr, 0), G1CardTable::dirty_card_val());
__ jmp(next_card);
__ jmpb(L_next_card);
__ bind(done);
__ bind(L_done);
}
void G1BarrierSetAssembler::load_at(MacroAssembler* masm, DecoratorSet decorators, BasicType type,
@ -157,22 +157,6 @@ void G1BarrierSetAssembler::load_at(MacroAssembler* masm, DecoratorSet decorator
}
}
static void generate_queue_insertion(MacroAssembler* masm, ByteSize index_offset, ByteSize buffer_offset, Label& runtime,
const Register thread, const Register value, const Register temp) {
// This code assumes that buffer index is pointer sized.
STATIC_ASSERT(in_bytes(SATBMarkQueue::byte_width_of_index()) == sizeof(intptr_t));
// Can we store a value in the given thread's buffer?
// (The index field is typed as size_t.)
__ movptr(temp, Address(thread, in_bytes(index_offset))); // temp := *(index address)
__ testptr(temp, temp); // index == 0?
__ jcc(Assembler::zero, runtime); // jump to runtime if index == 0 (full buffer)
// The buffer is not full, store value into it.
__ subptr(temp, wordSize); // temp := next index
__ movptr(Address(thread, in_bytes(index_offset)), temp); // *(index address) := next index
__ addptr(temp, Address(thread, in_bytes(buffer_offset))); // temp := buffer address + next index
__ movptr(Address(temp, 0), value); // *(buffer address + next index) := value
}
static void generate_pre_barrier_fast_path(MacroAssembler* masm,
const Register thread) {
Address in_progress(thread, in_bytes(G1ThreadLocalData::satb_mark_queue_active_offset()));
@ -190,21 +174,40 @@ static void generate_pre_barrier_slow_path(MacroAssembler* masm,
const Register pre_val,
const Register thread,
const Register tmp,
Label& done,
Label& runtime) {
Label& L_done) {
Address index_addr(thread, in_bytes(G1ThreadLocalData::satb_mark_queue_index_offset()));
Address buffer_addr(thread, in_bytes(G1ThreadLocalData::satb_mark_queue_buffer_offset()));
// This code assumes that buffer index is pointer sized.
STATIC_ASSERT(in_bytes(SATBMarkQueue::byte_width_of_index()) == sizeof(intptr_t));
Label L_runtime;
// Do we need to load the previous value?
if (obj != noreg) {
__ load_heap_oop(pre_val, Address(obj, 0), noreg, AS_RAW);
}
// Is the previous value null?
__ cmpptr(pre_val, NULL_WORD);
__ jcc(Assembler::equal, done);
generate_queue_insertion(masm,
G1ThreadLocalData::satb_mark_queue_index_offset(),
G1ThreadLocalData::satb_mark_queue_buffer_offset(),
runtime,
thread, pre_val, tmp);
__ jmp(done);
__ testptr(pre_val, pre_val);
__ jcc(Assembler::equal, L_done);
// Can we store a value in the given thread's buffer?
// (The index field is typed as size_t.)
__ movptr(tmp, index_addr); // temp := *(index address)
__ testptr(tmp, tmp); // index == 0?
__ jccb(Assembler::zero, L_runtime); // jump to runtime if index == 0 (full buffer)
// The buffer is not full, store value into it.
__ subptr(tmp, wordSize); // temp := next index
__ movptr(index_addr, tmp); // *(index address) := next index
__ addptr(tmp, buffer_addr); // temp := buffer address + next index
__ movptr(Address(tmp, 0), pre_val); // *(buffer address + next index) := value
// Jump out if done, or fall-through to runtime.
// "L_done" is far away, so jump cannot be short.
__ jmp(L_done);
__ bind(L_runtime);
}
void G1BarrierSetAssembler::g1_write_barrier_pre(MacroAssembler* masm,
@ -219,7 +222,6 @@ void G1BarrierSetAssembler::g1_write_barrier_pre(MacroAssembler* masm,
const Register thread = r15_thread;
Label done;
Label runtime;
assert(pre_val != noreg, "check this code");
@ -231,9 +233,7 @@ void G1BarrierSetAssembler::g1_write_barrier_pre(MacroAssembler* masm,
generate_pre_barrier_fast_path(masm, thread);
// If marking is not active (*(mark queue active address) == 0), jump to done
__ jcc(Assembler::equal, done);
generate_pre_barrier_slow_path(masm, obj, pre_val, thread, tmp, done, runtime);
__ bind(runtime);
generate_pre_barrier_slow_path(masm, obj, pre_val, thread, tmp, done);
// Determine and save the live input values
__ push_call_clobbered_registers();
@ -272,23 +272,23 @@ static void generate_post_barrier(MacroAssembler* masm,
const Register store_addr,
const Register new_val,
const Register tmp1,
Label& done,
bool new_val_may_be_null) {
assert_different_registers(store_addr, new_val, tmp1, noreg);
Register thread = r15_thread;
Label L_done;
// Does store cross heap regions?
__ movptr(tmp1, store_addr); // tmp1 := store address
__ xorptr(tmp1, new_val); // tmp1 := store address ^ new value
__ shrptr(tmp1, G1HeapRegion::LogOfHRGrainBytes); // ((store address ^ new value) >> LogOfHRGrainBytes) == 0?
__ jcc(Assembler::equal, done);
__ jccb(Assembler::equal, L_done);
// Crosses regions, storing null?
if (new_val_may_be_null) {
__ cmpptr(new_val, NULL_WORD); // new value == null?
__ jcc(Assembler::equal, done);
__ testptr(new_val, new_val); // new value == null?
__ jccb(Assembler::equal, L_done);
}
__ movptr(tmp1, store_addr); // tmp1 := store address
@ -298,20 +298,19 @@ static void generate_post_barrier(MacroAssembler* masm,
__ addptr(tmp1, card_table_addr); // tmp1 := card address
if (UseCondCardMark) {
__ cmpb(Address(tmp1, 0), G1CardTable::clean_card_val()); // *(card address) == clean_card_val?
__ jcc(Assembler::notEqual, done);
__ jccb(Assembler::notEqual, L_done);
}
// Storing a region crossing, non-null oop, card is clean.
// Dirty card.
__ movb(Address(tmp1, 0), G1CardTable::dirty_card_val()); // *(card address) := dirty_card_val
__ bind(L_done);
}
void G1BarrierSetAssembler::g1_write_barrier_post(MacroAssembler* masm,
Register store_addr,
Register new_val,
Register tmp) {
Label done;
generate_post_barrier(masm, store_addr, new_val, tmp, done, true /* new_val_may_be_null */);
__ bind(done);
generate_post_barrier(masm, store_addr, new_val, tmp, true /* new_val_may_be_null */);
}
#if defined(COMPILER2)
@ -354,7 +353,6 @@ void G1BarrierSetAssembler::g1_write_barrier_pre_c2(MacroAssembler* masm,
void G1BarrierSetAssembler::generate_c2_pre_barrier_stub(MacroAssembler* masm,
G1PreBarrierStubC2* stub) const {
Assembler::InlineSkippedInstructionsCounter skip_counter(masm);
Label runtime;
Register obj = stub->obj();
Register pre_val = stub->pre_val();
Register thread = stub->thread();
@ -362,9 +360,8 @@ void G1BarrierSetAssembler::generate_c2_pre_barrier_stub(MacroAssembler* masm,
assert(stub->tmp2() == noreg, "not needed in this platform");
__ bind(*stub->entry());
generate_pre_barrier_slow_path(masm, obj, pre_val, thread, tmp, *stub->continuation(), runtime);
generate_pre_barrier_slow_path(masm, obj, pre_val, thread, tmp, *stub->continuation());
__ bind(runtime);
generate_c2_barrier_runtime_call(masm, stub, pre_val, CAST_FROM_FN_PTR(address, G1BarrierSetRuntime::write_ref_field_pre_entry));
__ jmp(*stub->continuation());
}
@ -374,9 +371,7 @@ void G1BarrierSetAssembler::g1_write_barrier_post_c2(MacroAssembler* masm,
Register new_val,
Register tmp,
bool new_val_may_be_null) {
Label done;
generate_post_barrier(masm, store_addr, new_val, tmp, done, new_val_may_be_null);
__ bind(done);
generate_post_barrier(masm, store_addr, new_val, tmp, new_val_may_be_null);
}
#endif // COMPILER2
@ -449,7 +444,7 @@ void G1BarrierSetAssembler::gen_pre_barrier_stub(LIR_Assembler* ce, G1PreBarrier
ce->mem2reg(stub->addr(), stub->pre_val(), T_OBJECT, stub->patch_code(), stub->info(), false /*wide*/);
}
__ cmpptr(pre_val_reg, NULL_WORD);
__ testptr(pre_val_reg, pre_val_reg);
__ jcc(Assembler::equal, *stub->continuation());
ce->store_parameter(stub->pre_val()->as_register(), 0);
__ call(RuntimeAddress(bs->pre_barrier_c1_runtime_code_blob()->code_begin()));
@ -465,9 +460,7 @@ void G1BarrierSetAssembler::g1_write_barrier_post_c1(MacroAssembler* masm,
Register thread,
Register tmp1,
Register tmp2 /* unused on x86 */) {
Label done;
generate_post_barrier(masm, store_addr, new_val, tmp1, done, true /* new_val_may_be_null */);
masm->bind(done);
generate_post_barrier(masm, store_addr, new_val, tmp1, true /* new_val_may_be_null */);
}
#define __ sasm->
@ -490,8 +483,7 @@ void G1BarrierSetAssembler::generate_c1_pre_barrier_runtime_stub(StubAssembler*
Address queue_index(thread, in_bytes(G1ThreadLocalData::satb_mark_queue_index_offset()));
Address buffer(thread, in_bytes(G1ThreadLocalData::satb_mark_queue_buffer_offset()));
Label done;
Label runtime;
Label L_done, L_runtime;
// Is marking still active?
if (in_bytes(SATBMarkQueue::byte_width_of_active()) == 4) {
@ -500,13 +492,13 @@ void G1BarrierSetAssembler::generate_c1_pre_barrier_runtime_stub(StubAssembler*
assert(in_bytes(SATBMarkQueue::byte_width_of_active()) == 1, "Assumption");
__ cmpb(queue_active, 0);
}
__ jcc(Assembler::equal, done);
__ jcc(Assembler::equal, L_done);
// Can we store original value in the thread's buffer?
__ movptr(tmp, queue_index);
__ testptr(tmp, tmp);
__ jcc(Assembler::zero, runtime);
__ jccb(Assembler::zero, L_runtime);
__ subptr(tmp, wordSize);
__ movptr(queue_index, tmp);
__ addptr(tmp, buffer);
@ -514,9 +506,9 @@ void G1BarrierSetAssembler::generate_c1_pre_barrier_runtime_stub(StubAssembler*
// prev_val (rax)
__ load_parameter(0, pre_val);
__ movptr(Address(tmp, 0), pre_val);
__ jmp(done);
__ jmp(L_done);
__ bind(runtime);
__ bind(L_runtime);
__ push_call_clobbered_registers();
@ -526,7 +518,7 @@ void G1BarrierSetAssembler::generate_c1_pre_barrier_runtime_stub(StubAssembler*
__ pop_call_clobbered_registers();
__ bind(done);
__ bind(L_done);
__ pop_ppx(rdx);
__ pop_ppx(rax);

View File

@ -1368,6 +1368,7 @@ public:
void vpcmpeqw(XMMRegister dst, XMMRegister nds, Address src, int vector_len);
void vpcmpeqw(XMMRegister dst, XMMRegister nds, XMMRegister src, int vector_len);
using Assembler::evpcmpeqd;
void evpcmpeqd(KRegister kdst, KRegister mask, XMMRegister nds, AddressLiteral src, int vector_len, Register rscratch = noreg);
// Vector compares

View File

@ -73,6 +73,7 @@ class NativeInstruction {
s_char sbyte_at(int offset) const { return *(s_char*) addr_at(offset); }
u_char ubyte_at(int offset) const { return *(u_char*) addr_at(offset); }
jshort short_at(int offset) const { return *(jshort*) addr_at(offset); }
jint int_at(int offset) const { return *(jint*) addr_at(offset); }
intptr_t ptr_at(int offset) const { return *(intptr_t*) addr_at(offset); }
@ -578,10 +579,15 @@ public:
instruction_code = 0x0f,
instruction_size = 8,
instruction_offset = 0,
displacement_offset = 4
displacement_offset = 4,
// The two parts should be checked separately to prevent out of bounds access in case
// the return address points to the deopt handler stub code entry point which could be
// at the end of page.
first_check_size = 2
};
bool check() const { return int_at(0) == 0x841f0f; }
bool check() const { return short_at(0) == 0x1f0f && short_at(first_check_size) == 0x0084; }
bool decode(int32_t& oopmap_slot, int32_t& cb_offset) const {
int32_t data = int_at(displacement_offset);
if (data == 0) {

View File

@ -242,8 +242,6 @@ UncommonTrapBlob* OptoRuntime::generate_uncommon_trap_blob() {
//------------------------------generate_exception_blob---------------------------
// creates exception blob at the end
// Using exception blob, this code is jumped from a compiled method.
// (see emit_exception_handler in x86_64.ad file)
//
// Given an exception pc at a call we call into the runtime for the
// handler in this method. This handler might merely restore state

File diff suppressed because it is too large Load Diff

View File

@ -1271,8 +1271,7 @@ void VM_Version::get_processor_features() {
}
// Dilithium Intrinsics
// Currently we only have them for AVX512
if (supports_evex() && supports_avx512bw()) {
if (UseAVX > 1) {
if (FLAG_IS_DEFAULT(UseDilithiumIntrinsics)) {
UseDilithiumIntrinsics = true;
}

View File

@ -2633,6 +2633,70 @@ bool Matcher::supports_vector_calling_convention(void) {
return EnableVectorSupport;
}
static bool is_ndd_demotable(const MachNode* mdef) {
return ((mdef->flags() & Node::PD::Flag_ndd_demotable) != 0);
}
static bool is_ndd_demotable_commutative(const MachNode* mdef) {
return ((mdef->flags() & Node::PD::Flag_ndd_demotable_commutative) != 0);
}
static bool is_demotion_candidate(const MachNode* mdef) {
return (is_ndd_demotable(mdef) || is_ndd_demotable_commutative(mdef));
}
bool Matcher::is_register_biasing_candidate(const MachNode* mdef,
int oper_index) {
if (mdef == nullptr) {
return false;
}
if (mdef->num_opnds() <= oper_index || mdef->operand_index(oper_index) < 0 ||
mdef->in(mdef->operand_index(oper_index)) == nullptr) {
assert(oper_index != 1 || !is_demotion_candidate(mdef), "%s", mdef->Name());
assert(oper_index != 2 || !is_ndd_demotable_commutative(mdef), "%s", mdef->Name());
return false;
}
// Complex memory operand covers multiple incoming edges needed for
// address computation. Biasing def towards any address component will not
// result in NDD demotion by assembler.
if (mdef->operand_num_edges(oper_index) != 1) {
assert(!is_ndd_demotable(mdef), "%s", mdef->Name());
return false;
}
// Demotion candidate must be register mask compatible with definition.
const RegMask& oper_mask = mdef->in_RegMask(mdef->operand_index(oper_index));
if (!oper_mask.overlap(mdef->out_RegMask())) {
assert(!is_demotion_candidate(mdef), "%s", mdef->Name());
return false;
}
switch (oper_index) {
// First operand of MachNode corresponding to Intel APX NDD selection
// pattern can share its assigned register with definition operand if
// their live ranges do not overlap. In such a scenario we can demote
// it to legacy map0/map1 instruction by replacing its 4-byte extended
// EVEX prefix with shorter REX/REX2 encoding. Demotion candidates
// are decorated with a special flag by instruction selector.
case 1:
return is_demotion_candidate(mdef);
// Definition operand of commutative operation can be biased towards second
// operand.
case 2:
return is_ndd_demotable_commutative(mdef);
// Current scheme only selects up to two biasing candidates
default:
assert(false, "unhandled operand index: %s", mdef->Name());
break;
}
return false;
}
OptoRegPair Matcher::vector_return_value(uint ideal_reg) {
assert(EnableVectorSupport, "sanity");
int lo = XMM0_num;
@ -2767,21 +2831,11 @@ class HandlerImpl {
public:
static int emit_exception_handler(C2_MacroAssembler *masm);
static int emit_deopt_handler(C2_MacroAssembler* masm);
static uint size_exception_handler() {
// NativeCall instruction size is the same as NativeJump.
// exception handler starts out as jump and can be patched to
// a call be deoptimization. (4932387)
// Note that this value is also credited (in output.cpp) to
// the size of the code section.
return NativeJump::instruction_size;
}
static uint size_deopt_handler() {
// three 5 byte instructions plus one move for unreachable address.
return 15+3;
// one call and one jmp.
return 7;
}
};
@ -2822,7 +2876,7 @@ static inline bool is_clz_non_subword_predicate_evex(BasicType bt, int vlen_byte
class Node::PD {
public:
enum NodeFlags {
enum NodeFlags : uint64_t {
Flag_intel_jcc_erratum = Node::_last_flag << 1,
Flag_sets_carry_flag = Node::_last_flag << 2,
Flag_sets_parity_flag = Node::_last_flag << 3,
@ -2834,7 +2888,9 @@ public:
Flag_clears_zero_flag = Node::_last_flag << 9,
Flag_clears_overflow_flag = Node::_last_flag << 10,
Flag_clears_sign_flag = Node::_last_flag << 11,
_last_flag = Flag_clears_sign_flag
Flag_ndd_demotable = Node::_last_flag << 12,
Flag_ndd_demotable_commutative = Node::_last_flag << 13,
_last_flag = Flag_ndd_demotable_commutative
};
};
@ -2873,24 +2929,6 @@ int MachNode::compute_padding(int current_offset) const {
}
}
// Emit exception handler code.
// Stuff framesize into a register and call a VM stub routine.
int HandlerImpl::emit_exception_handler(C2_MacroAssembler* masm) {
// Note that the code buffer's insts_mark is always relative to insts.
// That's why we must use the macroassembler to generate a handler.
address base = __ start_a_stub(size_exception_handler());
if (base == nullptr) {
ciEnv::current()->record_failure("CodeCache is full");
return 0; // CodeBuffer::expand failed
}
int offset = __ offset();
__ jump(RuntimeAddress(OptoRuntime::exception_blob()->entry_point()));
assert(__ offset() - offset <= (int) size_exception_handler(), "overflow");
__ end_a_stub();
return offset;
}
// Emit deopt handler code.
int HandlerImpl::emit_deopt_handler(C2_MacroAssembler* masm) {
@ -2903,21 +2941,20 @@ int HandlerImpl::emit_deopt_handler(C2_MacroAssembler* masm) {
}
int offset = __ offset();
address the_pc = (address) __ pc();
Label next;
// push a "the_pc" on the stack without destroying any registers
// as they all may be live.
Label start;
__ bind(start);
// push address of "next"
__ call(next, relocInfo::none); // reloc none is fine since it is a disp32
__ bind(next);
// adjust it so it matches "the_pc"
__ subptr(Address(rsp, 0), __ offset() - offset);
__ call(RuntimeAddress(SharedRuntime::deopt_blob()->unpack()));
int entry_offset = __ offset();
__ jmp(start);
__ jump(RuntimeAddress(SharedRuntime::deopt_blob()->unpack()));
assert(__ offset() - offset <= (int) size_deopt_handler(), "overflow %d", (__ offset() - offset));
assert(__ offset() - entry_offset >= NativePostCallNop::first_check_size,
"out of bounds read in post-call NOP check");
__ end_a_stub();
return offset;
return entry_offset;
}
static Assembler::Width widthForType(BasicType bt) {
@ -9830,7 +9867,7 @@ instruct addI_rReg_ndd(rRegI dst, rRegI src1, rRegI src2, rFlagsReg cr)
predicate(UseAPX);
match(Set dst (AddI src1 src2));
effect(KILL cr);
flag(PD::Flag_sets_overflow_flag, PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_carry_flag, PD::Flag_sets_parity_flag);
flag(PD::Flag_sets_overflow_flag, PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_carry_flag, PD::Flag_sets_parity_flag, PD::Flag_ndd_demotable_commutative);
format %{ "eaddl $dst, $src1, $src2\t# int ndd" %}
ins_encode %{
@ -9858,7 +9895,7 @@ instruct addI_rReg_rReg_imm_ndd(rRegI dst, rRegI src1, immI src2, rFlagsReg cr)
predicate(UseAPX);
match(Set dst (AddI src1 src2));
effect(KILL cr);
flag(PD::Flag_sets_overflow_flag, PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_carry_flag, PD::Flag_sets_parity_flag);
flag(PD::Flag_sets_overflow_flag, PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_carry_flag, PD::Flag_sets_parity_flag, PD::Flag_ndd_demotable);
format %{ "eaddl $dst, $src1, $src2\t# int ndd" %}
ins_encode %{
@ -9901,7 +9938,7 @@ instruct addI_rReg_rReg_mem_ndd(rRegI dst, rRegI src1, memory src2, rFlagsReg cr
predicate(UseAPX);
match(Set dst (AddI src1 (LoadI src2)));
effect(KILL cr);
flag(PD::Flag_sets_overflow_flag, PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_carry_flag, PD::Flag_sets_parity_flag);
flag(PD::Flag_sets_overflow_flag, PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_carry_flag, PD::Flag_sets_parity_flag, PD::Flag_ndd_demotable_commutative);
ins_cost(150);
format %{ "eaddl $dst, $src1, $src2\t# int ndd" %}
@ -9958,6 +9995,7 @@ instruct incI_rReg_ndd(rRegI dst, rRegI src, immI_1 val, rFlagsReg cr)
predicate(UseAPX && UseIncDec);
match(Set dst (AddI src val));
effect(KILL cr);
flag(PD::Flag_ndd_demotable);
format %{ "eincl $dst, $src\t# int ndd" %}
ins_encode %{
@ -10012,6 +10050,7 @@ instruct decI_rReg_ndd(rRegI dst, rRegI src, immI_M1 val, rFlagsReg cr)
predicate(UseAPX && UseIncDec);
match(Set dst (AddI src val));
effect(KILL cr);
flag(PD::Flag_ndd_demotable);
format %{ "edecl $dst, $src\t# int ndd" %}
ins_encode %{
@ -10118,7 +10157,7 @@ instruct addL_rReg_ndd(rRegL dst, rRegL src1, rRegL src2, rFlagsReg cr)
predicate(UseAPX);
match(Set dst (AddL src1 src2));
effect(KILL cr);
flag(PD::Flag_sets_overflow_flag, PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_carry_flag, PD::Flag_sets_parity_flag);
flag(PD::Flag_sets_overflow_flag, PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_carry_flag, PD::Flag_sets_parity_flag, PD::Flag_ndd_demotable_commutative);
format %{ "eaddq $dst, $src1, $src2\t# long ndd" %}
ins_encode %{
@ -10146,7 +10185,7 @@ instruct addL_rReg_rReg_imm_ndd(rRegL dst, rRegL src1, immL32 src2, rFlagsReg cr
predicate(UseAPX);
match(Set dst (AddL src1 src2));
effect(KILL cr);
flag(PD::Flag_sets_overflow_flag, PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_carry_flag, PD::Flag_sets_parity_flag);
flag(PD::Flag_sets_overflow_flag, PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_carry_flag, PD::Flag_sets_parity_flag, PD::Flag_ndd_demotable);
format %{ "eaddq $dst, $src1, $src2\t# long ndd" %}
ins_encode %{
@ -10189,7 +10228,7 @@ instruct addL_rReg_rReg_mem_ndd(rRegL dst, rRegL src1, memory src2, rFlagsReg cr
predicate(UseAPX);
match(Set dst (AddL src1 (LoadL src2)));
effect(KILL cr);
flag(PD::Flag_sets_overflow_flag, PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_carry_flag, PD::Flag_sets_parity_flag);
flag(PD::Flag_sets_overflow_flag, PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_carry_flag, PD::Flag_sets_parity_flag, PD::Flag_ndd_demotable_commutative);
ins_cost(150);
format %{ "eaddq $dst, $src1, $src2\t# long ndd" %}
@ -10245,6 +10284,7 @@ instruct incL_rReg_ndd(rRegL dst, rRegI src, immL1 val, rFlagsReg cr)
predicate(UseAPX && UseIncDec);
match(Set dst (AddL src val));
effect(KILL cr);
flag(PD::Flag_ndd_demotable);
format %{ "eincq $dst, $src\t# long ndd" %}
ins_encode %{
@ -10299,6 +10339,7 @@ instruct decL_rReg_ndd(rRegL dst, rRegL src, immL_M1 val, rFlagsReg cr)
predicate(UseAPX && UseIncDec);
match(Set dst (AddL src val));
effect(KILL cr);
flag(PD::Flag_ndd_demotable);
format %{ "edecq $dst, $src\t# long ndd" %}
ins_encode %{
@ -11013,7 +11054,7 @@ instruct subI_rReg_ndd(rRegI dst, rRegI src1, rRegI src2, rFlagsReg cr)
predicate(UseAPX);
match(Set dst (SubI src1 src2));
effect(KILL cr);
flag(PD::Flag_sets_overflow_flag, PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_carry_flag, PD::Flag_sets_parity_flag);
flag(PD::Flag_sets_overflow_flag, PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_carry_flag, PD::Flag_sets_parity_flag, PD::Flag_ndd_demotable);
format %{ "esubl $dst, $src1, $src2\t# int ndd" %}
ins_encode %{
@ -11027,7 +11068,7 @@ instruct subI_rReg_rReg_imm_ndd(rRegI dst, rRegI src1, immI src2, rFlagsReg cr)
predicate(UseAPX);
match(Set dst (SubI src1 src2));
effect(KILL cr);
flag(PD::Flag_sets_overflow_flag, PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_carry_flag, PD::Flag_sets_parity_flag);
flag(PD::Flag_sets_overflow_flag, PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_carry_flag, PD::Flag_sets_parity_flag, PD::Flag_ndd_demotable);
format %{ "esubl $dst, $src1, $src2\t# int ndd" %}
ins_encode %{
@ -11070,7 +11111,7 @@ instruct subI_rReg_rReg_mem_ndd(rRegI dst, rRegI src1, memory src2, rFlagsReg cr
predicate(UseAPX);
match(Set dst (SubI src1 (LoadI src2)));
effect(KILL cr);
flag(PD::Flag_sets_overflow_flag, PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_carry_flag, PD::Flag_sets_parity_flag);
flag(PD::Flag_sets_overflow_flag, PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_carry_flag, PD::Flag_sets_parity_flag, PD::Flag_ndd_demotable);
ins_cost(150);
format %{ "esubl $dst, $src1, $src2\t# int ndd" %}
@ -11128,7 +11169,7 @@ instruct subL_rReg_ndd(rRegL dst, rRegL src1, rRegL src2, rFlagsReg cr)
predicate(UseAPX);
match(Set dst (SubL src1 src2));
effect(KILL cr);
flag(PD::Flag_sets_overflow_flag, PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_carry_flag, PD::Flag_sets_parity_flag);
flag(PD::Flag_sets_overflow_flag, PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_carry_flag, PD::Flag_sets_parity_flag, PD::Flag_ndd_demotable);
format %{ "esubq $dst, $src1, $src2\t# long ndd" %}
ins_encode %{
@ -11142,7 +11183,7 @@ instruct subL_rReg_rReg_imm_ndd(rRegL dst, rRegL src1, immL32 src2, rFlagsReg cr
predicate(UseAPX);
match(Set dst (SubL src1 src2));
effect(KILL cr);
flag(PD::Flag_sets_overflow_flag, PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_carry_flag, PD::Flag_sets_parity_flag);
flag(PD::Flag_sets_overflow_flag, PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_carry_flag, PD::Flag_sets_parity_flag, PD::Flag_ndd_demotable);
format %{ "esubq $dst, $src1, $src2\t# long ndd" %}
ins_encode %{
@ -11185,7 +11226,7 @@ instruct subL_rReg_rReg_mem_ndd(rRegL dst, rRegL src1, memory src2, rFlagsReg cr
predicate(UseAPX);
match(Set dst (SubL src1 (LoadL src2)));
effect(KILL cr);
flag(PD::Flag_sets_overflow_flag, PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_carry_flag, PD::Flag_sets_parity_flag);
flag(PD::Flag_sets_overflow_flag, PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_carry_flag, PD::Flag_sets_parity_flag, PD::Flag_ndd_demotable);
ins_cost(150);
format %{ "esubq $dst, $src1, $src2\t# long ndd" %}
@ -11257,7 +11298,7 @@ instruct negI_rReg_ndd(rRegI dst, rRegI src, immI_0 zero, rFlagsReg cr)
predicate(UseAPX);
match(Set dst (SubI zero src));
effect(KILL cr);
flag(PD::Flag_sets_overflow_flag, PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_parity_flag);
flag(PD::Flag_sets_overflow_flag, PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_parity_flag, PD::Flag_ndd_demotable);
format %{ "enegl $dst, $src\t# int ndd" %}
ins_encode %{
@ -11285,7 +11326,7 @@ instruct negI_rReg_2_ndd(rRegI dst, rRegI src, rFlagsReg cr)
predicate(UseAPX);
match(Set dst (NegI src));
effect(KILL cr);
flag(PD::Flag_sets_overflow_flag, PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_parity_flag);
flag(PD::Flag_sets_overflow_flag, PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_parity_flag, PD::Flag_ndd_demotable);
format %{ "enegl $dst, $src\t# int ndd" %}
ins_encode %{
@ -11326,7 +11367,7 @@ instruct negL_rReg_ndd(rRegL dst, rRegL src, immL0 zero, rFlagsReg cr)
predicate(UseAPX);
match(Set dst (SubL zero src));
effect(KILL cr);
flag(PD::Flag_sets_overflow_flag, PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_parity_flag);
flag(PD::Flag_sets_overflow_flag, PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_parity_flag, PD::Flag_ndd_demotable);
format %{ "enegq $dst, $src\t# long ndd" %}
ins_encode %{
@ -11354,7 +11395,7 @@ instruct negL_rReg_2_ndd(rRegL dst, rRegL src, rFlagsReg cr)
predicate(UseAPX);
match(Set dst (NegL src));
effect(KILL cr);
flag(PD::Flag_sets_overflow_flag, PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_parity_flag);
flag(PD::Flag_sets_overflow_flag, PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_parity_flag, PD::Flag_ndd_demotable);
format %{ "enegq $dst, $src\t# long ndd" %}
ins_encode %{
@ -11399,6 +11440,7 @@ instruct mulI_rReg_ndd(rRegI dst, rRegI src1, rRegI src2, rFlagsReg cr)
predicate(UseAPX);
match(Set dst (MulI src1 src2));
effect(KILL cr);
flag(PD::Flag_ndd_demotable_commutative);
ins_cost(300);
format %{ "eimull $dst, $src1, $src2\t# int ndd" %}
@ -11440,6 +11482,7 @@ instruct mulI_rReg_rReg_mem_ndd(rRegI dst, rRegI src1, memory src2, rFlagsReg cr
predicate(UseAPX);
match(Set dst (MulI src1 (LoadI src2)));
effect(KILL cr);
flag(PD::Flag_ndd_demotable);
ins_cost(350);
format %{ "eimull $dst, $src1, $src2\t# int ndd" %}
@ -11491,6 +11534,7 @@ instruct mulL_rReg_ndd(rRegL dst, rRegL src1, rRegL src2, rFlagsReg cr)
predicate(UseAPX);
match(Set dst (MulL src1 src2));
effect(KILL cr);
flag(PD::Flag_ndd_demotable_commutative);
ins_cost(300);
format %{ "eimulq $dst, $src1, $src2\t# long ndd" %}
@ -11532,6 +11576,7 @@ instruct mulL_rReg_rReg_mem_ndd(rRegL dst, rRegL src1, memory src2, rFlagsReg cr
predicate(UseAPX);
match(Set dst (MulL src1 (LoadL src2)));
effect(KILL cr);
flag(PD::Flag_ndd_demotable_commutative);
ins_cost(350);
format %{ "eimulq $dst, $src1, $src2 \t# long" %}
@ -11806,6 +11851,7 @@ instruct salI_rReg_immI2_ndd(rRegI dst, rRegI src, immI2 shift, rFlagsReg cr)
predicate(UseAPX);
match(Set dst (LShiftI src shift));
effect(KILL cr);
flag(PD::Flag_ndd_demotable);
format %{ "esall $dst, $src, $shift\t# int(ndd)" %}
ins_encode %{
@ -11834,6 +11880,7 @@ instruct salI_rReg_imm_ndd(rRegI dst, rRegI src, immI8 shift, rFlagsReg cr)
predicate(UseAPX);
match(Set dst (LShiftI src shift));
effect(KILL cr);
flag(PD::Flag_ndd_demotable);
format %{ "esall $dst, $src, $shift\t# int (ndd)" %}
ins_encode %{
@ -11940,6 +11987,7 @@ instruct sarI_rReg_imm_ndd(rRegI dst, rRegI src, immI8 shift, rFlagsReg cr)
predicate(UseAPX);
match(Set dst (RShiftI src shift));
effect(KILL cr);
flag(PD::Flag_ndd_demotable);
format %{ "esarl $dst, $src, $shift\t# int (ndd)" %}
ins_encode %{
@ -12046,6 +12094,7 @@ instruct shrI_rReg_imm_ndd(rRegI dst, rRegI src, immI8 shift, rFlagsReg cr)
predicate(UseAPX);
match(Set dst (URShiftI src shift));
effect(KILL cr);
flag(PD::Flag_ndd_demotable);
format %{ "eshrl $dst, $src, $shift\t # int (ndd)" %}
ins_encode %{
@ -12153,6 +12202,7 @@ instruct salL_rReg_immI2_ndd(rRegL dst, rRegL src, immI2 shift, rFlagsReg cr)
predicate(UseAPX);
match(Set dst (LShiftL src shift));
effect(KILL cr);
flag(PD::Flag_ndd_demotable);
format %{ "esalq $dst, $src, $shift\t# long (ndd)" %}
ins_encode %{
@ -12181,6 +12231,7 @@ instruct salL_rReg_imm_ndd(rRegL dst, rRegL src, immI8 shift, rFlagsReg cr)
predicate(UseAPX);
match(Set dst (LShiftL src shift));
effect(KILL cr);
flag(PD::Flag_ndd_demotable);
format %{ "esalq $dst, $src, $shift\t# long (ndd)" %}
ins_encode %{
@ -12287,6 +12338,7 @@ instruct sarL_rReg_imm_ndd(rRegL dst, rRegL src, immI shift, rFlagsReg cr)
predicate(UseAPX);
match(Set dst (RShiftL src shift));
effect(KILL cr);
flag(PD::Flag_ndd_demotable);
format %{ "esarq $dst, $src, $shift\t# long (ndd)" %}
ins_encode %{
@ -12393,6 +12445,7 @@ instruct shrL_rReg_imm_ndd(rRegL dst, rRegL src, immI8 shift, rFlagsReg cr)
predicate(UseAPX);
match(Set dst (URShiftL src shift));
effect(KILL cr);
flag(PD::Flag_ndd_demotable);
format %{ "eshrq $dst, $src, $shift\t# long (ndd)" %}
ins_encode %{
@ -12564,6 +12617,7 @@ instruct rolI_rReg_Var_ndd(rRegI dst, rRegI src, rcx_RegI shift, rFlagsReg cr)
predicate(UseAPX && n->bottom_type()->basic_type() == T_INT);
match(Set dst (RotateLeft src shift));
effect(KILL cr);
flag(PD::Flag_ndd_demotable);
format %{ "eroll $dst, $src, $shift\t# rotate left (int ndd)" %}
ins_encode %{
@ -12628,6 +12682,7 @@ instruct rorI_rReg_Var_ndd(rRegI dst, rRegI src, rcx_RegI shift, rFlagsReg cr)
predicate(UseAPX && n->bottom_type()->basic_type() == T_INT);
match(Set dst (RotateRight src shift));
effect(KILL cr);
flag(PD::Flag_ndd_demotable);
format %{ "erorl $dst, $src, $shift\t# rotate right(int ndd)" %}
ins_encode %{
@ -12680,6 +12735,7 @@ instruct rolL_rReg_Var(rRegL dst, rcx_RegI shift, rFlagsReg cr)
predicate(!UseAPX && n->bottom_type()->basic_type() == T_LONG);
match(Set dst (RotateLeft dst shift));
effect(KILL cr);
format %{ "rolq $dst, $shift" %}
ins_encode %{
__ rolq($dst$$Register);
@ -12693,6 +12749,7 @@ instruct rolL_rReg_Var_ndd(rRegL dst, rRegL src, rcx_RegI shift, rFlagsReg cr)
predicate(UseAPX && n->bottom_type()->basic_type() == T_LONG);
match(Set dst (RotateLeft src shift));
effect(KILL cr);
flag(PD::Flag_ndd_demotable);
format %{ "erolq $dst, $src, $shift\t# rotate left(long ndd)" %}
ins_encode %{
@ -12757,6 +12814,7 @@ instruct rorL_rReg_Var_ndd(rRegL dst, rRegL src, rcx_RegI shift, rFlagsReg cr)
predicate(UseAPX && n->bottom_type()->basic_type() == T_LONG);
match(Set dst (RotateRight src shift));
effect(KILL cr);
flag(PD::Flag_ndd_demotable);
format %{ "erorq $dst, $src, $shift\t# rotate right(long ndd)" %}
ins_encode %{
@ -12834,7 +12892,7 @@ instruct andI_rReg_ndd(rRegI dst, rRegI src1, rRegI src2, rFlagsReg cr)
predicate(UseAPX);
match(Set dst (AndI src1 src2));
effect(KILL cr);
flag(PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_parity_flag, PD::Flag_clears_overflow_flag, PD::Flag_clears_carry_flag);
flag(PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_parity_flag, PD::Flag_clears_overflow_flag, PD::Flag_clears_carry_flag, PD::Flag_ndd_demotable_commutative);
format %{ "eandl $dst, $src1, $src2\t# int ndd" %}
ins_encode %{
@ -12927,7 +12985,7 @@ instruct andI_rReg_rReg_imm_ndd(rRegI dst, rRegI src1, immI src2, rFlagsReg cr)
predicate(UseAPX);
match(Set dst (AndI src1 src2));
effect(KILL cr);
flag(PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_parity_flag, PD::Flag_clears_overflow_flag, PD::Flag_clears_carry_flag);
flag(PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_parity_flag, PD::Flag_clears_overflow_flag, PD::Flag_clears_carry_flag, PD::Flag_ndd_demotable);
format %{ "eandl $dst, $src1, $src2\t# int ndd" %}
ins_encode %{
@ -12971,7 +13029,7 @@ instruct andI_rReg_rReg_mem_ndd(rRegI dst, rRegI src1, memory src2, rFlagsReg cr
predicate(UseAPX);
match(Set dst (AndI src1 (LoadI src2)));
effect(KILL cr);
flag(PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_parity_flag, PD::Flag_clears_overflow_flag, PD::Flag_clears_carry_flag);
flag(PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_parity_flag, PD::Flag_clears_overflow_flag, PD::Flag_clears_carry_flag, PD::Flag_ndd_demotable_commutative);
ins_cost(150);
format %{ "eandl $dst, $src1, $src2\t# int ndd" %}
@ -13171,7 +13229,7 @@ instruct orI_rReg_ndd(rRegI dst, rRegI src1, rRegI src2, rFlagsReg cr)
predicate(UseAPX);
match(Set dst (OrI src1 src2));
effect(KILL cr);
flag(PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_parity_flag, PD::Flag_clears_overflow_flag, PD::Flag_clears_carry_flag);
flag(PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_parity_flag, PD::Flag_clears_overflow_flag, PD::Flag_clears_carry_flag, PD::Flag_ndd_demotable_commutative);
format %{ "eorl $dst, $src1, $src2\t# int ndd" %}
ins_encode %{
@ -13200,7 +13258,7 @@ instruct orI_rReg_rReg_imm_ndd(rRegI dst, rRegI src1, immI src2, rFlagsReg cr)
predicate(UseAPX);
match(Set dst (OrI src1 src2));
effect(KILL cr);
flag(PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_parity_flag, PD::Flag_clears_overflow_flag, PD::Flag_clears_carry_flag);
flag(PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_parity_flag, PD::Flag_clears_overflow_flag, PD::Flag_clears_carry_flag, PD::Flag_ndd_demotable);
format %{ "eorl $dst, $src1, $src2\t# int ndd" %}
ins_encode %{
@ -13214,7 +13272,7 @@ instruct orI_rReg_imm_rReg_ndd(rRegI dst, immI src1, rRegI src2, rFlagsReg cr)
predicate(UseAPX);
match(Set dst (OrI src1 src2));
effect(KILL cr);
flag(PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_parity_flag, PD::Flag_clears_overflow_flag, PD::Flag_clears_carry_flag);
flag(PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_parity_flag, PD::Flag_clears_overflow_flag, PD::Flag_clears_carry_flag, PD::Flag_ndd_demotable);
format %{ "eorl $dst, $src2, $src1\t# int ndd" %}
ins_encode %{
@ -13258,7 +13316,7 @@ instruct orI_rReg_rReg_mem_ndd(rRegI dst, rRegI src1, memory src2, rFlagsReg cr)
predicate(UseAPX);
match(Set dst (OrI src1 (LoadI src2)));
effect(KILL cr);
flag(PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_parity_flag, PD::Flag_clears_overflow_flag, PD::Flag_clears_carry_flag);
flag(PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_parity_flag, PD::Flag_clears_overflow_flag, PD::Flag_clears_carry_flag, PD::Flag_ndd_demotable);
ins_cost(150);
format %{ "eorl $dst, $src1, $src2\t# int ndd" %}
@ -13334,7 +13392,7 @@ instruct xorI_rReg_ndd(rRegI dst, rRegI src1, rRegI src2, rFlagsReg cr)
predicate(UseAPX);
match(Set dst (XorI src1 src2));
effect(KILL cr);
flag(PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_parity_flag, PD::Flag_clears_overflow_flag, PD::Flag_clears_carry_flag);
flag(PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_parity_flag, PD::Flag_clears_overflow_flag, PD::Flag_clears_carry_flag, PD::Flag_ndd_demotable_commutative);
format %{ "exorl $dst, $src1, $src2\t# int ndd" %}
ins_encode %{
@ -13360,6 +13418,7 @@ instruct xorI_rReg_im1_ndd(rRegI dst, rRegI src, immI_M1 imm)
%{
match(Set dst (XorI src imm));
predicate(UseAPX);
flag(PD::Flag_ndd_demotable);
format %{ "enotl $dst, $src" %}
ins_encode %{
@ -13390,7 +13449,7 @@ instruct xorI_rReg_rReg_imm_ndd(rRegI dst, rRegI src1, immI src2, rFlagsReg cr)
predicate(UseAPX && n->in(2)->bottom_type()->is_int()->get_con() != -1);
match(Set dst (XorI src1 src2));
effect(KILL cr);
flag(PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_parity_flag, PD::Flag_clears_overflow_flag, PD::Flag_clears_carry_flag);
flag(PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_parity_flag, PD::Flag_clears_overflow_flag, PD::Flag_clears_carry_flag, PD::Flag_ndd_demotable);
format %{ "exorl $dst, $src1, $src2\t# int ndd" %}
ins_encode %{
@ -13436,7 +13495,7 @@ instruct xorI_rReg_rReg_mem_ndd(rRegI dst, rRegI src1, memory src2, rFlagsReg cr
predicate(UseAPX);
match(Set dst (XorI src1 (LoadI src2)));
effect(KILL cr);
flag(PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_parity_flag, PD::Flag_clears_overflow_flag, PD::Flag_clears_carry_flag);
flag(PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_parity_flag, PD::Flag_clears_overflow_flag, PD::Flag_clears_carry_flag, PD::Flag_ndd_demotable);
ins_cost(150);
format %{ "exorl $dst, $src1, $src2\t# int ndd" %}
@ -13515,7 +13574,7 @@ instruct andL_rReg_ndd(rRegL dst, rRegL src1, rRegL src2, rFlagsReg cr)
predicate(UseAPX);
match(Set dst (AndL src1 src2));
effect(KILL cr);
flag(PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_parity_flag, PD::Flag_clears_overflow_flag, PD::Flag_clears_carry_flag);
flag(PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_parity_flag, PD::Flag_clears_overflow_flag, PD::Flag_clears_carry_flag, PD::Flag_ndd_demotable_commutative);
format %{ "eandq $dst, $src1, $src2\t# long ndd" %}
ins_encode %{
@ -13571,7 +13630,7 @@ instruct andL_rReg_rReg_imm_ndd(rRegL dst, rRegL src1, immL32 src2, rFlagsReg cr
predicate(UseAPX);
match(Set dst (AndL src1 src2));
effect(KILL cr);
flag(PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_parity_flag, PD::Flag_clears_overflow_flag, PD::Flag_clears_carry_flag);
flag(PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_parity_flag, PD::Flag_clears_overflow_flag, PD::Flag_clears_carry_flag, PD::Flag_ndd_demotable);
format %{ "eandq $dst, $src1, $src2\t# long ndd" %}
ins_encode %{
@ -13615,7 +13674,7 @@ instruct andL_rReg_rReg_mem_ndd(rRegL dst, rRegL src1, memory src2, rFlagsReg cr
predicate(UseAPX);
match(Set dst (AndL src1 (LoadL src2)));
effect(KILL cr);
flag(PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_parity_flag, PD::Flag_clears_overflow_flag, PD::Flag_clears_carry_flag);
flag(PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_parity_flag, PD::Flag_clears_overflow_flag, PD::Flag_clears_carry_flag, PD::Flag_ndd_demotable_commutative);
ins_cost(150);
format %{ "eandq $dst, $src1, $src2\t# long ndd" %}
@ -13818,7 +13877,7 @@ instruct orL_rReg_ndd(rRegL dst, rRegL src1, rRegL src2, rFlagsReg cr)
predicate(UseAPX);
match(Set dst (OrL src1 src2));
effect(KILL cr);
flag(PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_parity_flag, PD::Flag_clears_overflow_flag, PD::Flag_clears_carry_flag);
flag(PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_parity_flag, PD::Flag_clears_overflow_flag, PD::Flag_clears_carry_flag, PD::Flag_ndd_demotable_commutative);
format %{ "eorq $dst, $src1, $src2\t# long ndd" %}
ins_encode %{
@ -13873,7 +13932,7 @@ instruct orL_rReg_rReg_imm_ndd(rRegL dst, rRegL src1, immL32 src2, rFlagsReg cr)
predicate(UseAPX);
match(Set dst (OrL src1 src2));
effect(KILL cr);
flag(PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_parity_flag, PD::Flag_clears_overflow_flag, PD::Flag_clears_carry_flag);
flag(PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_parity_flag, PD::Flag_clears_overflow_flag, PD::Flag_clears_carry_flag, PD::Flag_ndd_demotable);
format %{ "eorq $dst, $src1, $src2\t# long ndd" %}
ins_encode %{
@ -13887,7 +13946,7 @@ instruct orL_rReg_imm_rReg_ndd(rRegL dst, immL32 src1, rRegL src2, rFlagsReg cr)
predicate(UseAPX);
match(Set dst (OrL src1 src2));
effect(KILL cr);
flag(PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_parity_flag, PD::Flag_clears_overflow_flag, PD::Flag_clears_carry_flag);
flag(PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_parity_flag, PD::Flag_clears_overflow_flag, PD::Flag_clears_carry_flag, PD::Flag_ndd_demotable);
format %{ "eorq $dst, $src2, $src1\t# long ndd" %}
ins_encode %{
@ -13932,7 +13991,7 @@ instruct orL_rReg_rReg_mem_ndd(rRegL dst, rRegL src1, memory src2, rFlagsReg cr)
predicate(UseAPX);
match(Set dst (OrL src1 (LoadL src2)));
effect(KILL cr);
flag(PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_parity_flag, PD::Flag_clears_overflow_flag, PD::Flag_clears_carry_flag);
flag(PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_parity_flag, PD::Flag_clears_overflow_flag, PD::Flag_clears_carry_flag, PD::Flag_ndd_demotable_commutative);
ins_cost(150);
format %{ "eorq $dst, $src1, $src2\t# long ndd" %}
@ -14011,7 +14070,7 @@ instruct xorL_rReg_ndd(rRegL dst, rRegL src1, rRegL src2, rFlagsReg cr)
predicate(UseAPX);
match(Set dst (XorL src1 src2));
effect(KILL cr);
flag(PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_parity_flag, PD::Flag_clears_overflow_flag, PD::Flag_clears_carry_flag);
flag(PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_parity_flag, PD::Flag_clears_overflow_flag, PD::Flag_clears_carry_flag, PD::Flag_ndd_demotable_commutative);
format %{ "exorq $dst, $src1, $src2\t# long ndd" %}
ins_encode %{
@ -14037,6 +14096,7 @@ instruct xorL_rReg_im1_ndd(rRegL dst,rRegL src, immL_M1 imm)
%{
predicate(UseAPX);
match(Set dst (XorL src imm));
flag(PD::Flag_ndd_demotable);
format %{ "enotq $dst, $src" %}
ins_encode %{
@ -14067,7 +14127,7 @@ instruct xorL_rReg_rReg_imm(rRegL dst, rRegL src1, immL32 src2, rFlagsReg cr)
predicate(UseAPX && n->in(2)->bottom_type()->is_long()->get_con() != -1L);
match(Set dst (XorL src1 src2));
effect(KILL cr);
flag(PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_parity_flag, PD::Flag_clears_overflow_flag, PD::Flag_clears_carry_flag);
flag(PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_parity_flag, PD::Flag_clears_overflow_flag, PD::Flag_clears_carry_flag, PD::Flag_ndd_demotable);
format %{ "exorq $dst, $src1, $src2\t# long ndd" %}
ins_encode %{
@ -14113,7 +14173,7 @@ instruct xorL_rReg_rReg_mem_ndd(rRegL dst, rRegL src1, memory src2, rFlagsReg cr
predicate(UseAPX);
match(Set dst (XorL src1 (LoadL src2)));
effect(KILL cr);
flag(PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_parity_flag, PD::Flag_clears_overflow_flag, PD::Flag_clears_carry_flag);
flag(PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_parity_flag, PD::Flag_clears_overflow_flag, PD::Flag_clears_carry_flag, PD::Flag_ndd_demotable_commutative);
ins_cost(150);
format %{ "exorq $dst, $src1, $src2\t# long ndd" %}
@ -16568,6 +16628,7 @@ instruct minI_rReg_ndd(rRegI dst, rRegI src1, rRegI src2)
predicate(UseAPX);
match(Set dst (MinI src1 src2));
effect(DEF dst, USE src1, USE src2);
flag(PD::Flag_ndd_demotable);
ins_cost(200);
expand %{
@ -16619,6 +16680,7 @@ instruct maxI_rReg_ndd(rRegI dst, rRegI src1, rRegI src2)
predicate(UseAPX);
match(Set dst (MaxI src1 src2));
effect(DEF dst, USE src1, USE src2);
flag(PD::Flag_ndd_demotable);
ins_cost(200);
expand %{

View File

@ -1747,6 +1747,9 @@ size_t os::pd_pretouch_memory(void* first, void* last, size_t page_size) {
return page_size;
}
void os::numa_set_thread_affinity(Thread *thread, int node) {
}
void os::numa_make_global(char *addr, size_t bytes) {
}

View File

@ -1581,6 +1581,9 @@ size_t os::pd_pretouch_memory(void* first, void* last, size_t page_size) {
return page_size;
}
void os::numa_set_thread_affinity(Thread *thread, int node) {
}
void os::numa_make_global(char *addr, size_t bytes) {
}

View File

@ -209,14 +209,14 @@ class CgroupV1Subsystem: public CgroupSubsystem {
bool pids_max(uint64_t& result) override;
bool pids_current(uint64_t& result) override;
bool is_containerized();
bool is_containerized() override;
const char * container_type() {
const char * container_type() override {
return "cgroupv1";
}
CachingCgroupController<CgroupMemoryController>* memory_controller() { return _memory; }
CachingCgroupController<CgroupCpuController>* cpu_controller() { return _cpu; }
CgroupCpuacctController* cpuacct_controller() { return _cpuacct; }
CachingCgroupController<CgroupMemoryController>* memory_controller() override { return _memory; }
CachingCgroupController<CgroupCpuController>* cpu_controller() override { return _cpu; }
CgroupCpuacctController* cpuacct_controller() override { return _cpuacct; }
private:
/* controllers */

View File

@ -159,9 +159,7 @@ physical_memory_size_type os::Linux::_physical_memory = 0;
address os::Linux::_initial_thread_stack_bottom = nullptr;
uintptr_t os::Linux::_initial_thread_stack_size = 0;
int (*os::Linux::_pthread_getcpuclockid)(pthread_t, clockid_t *) = nullptr;
pthread_t os::Linux::_main_thread;
bool os::Linux::_supports_fast_thread_cpu_time = false;
const char * os::Linux::_libc_version = nullptr;
const char * os::Linux::_libpthread_version = nullptr;
@ -1475,29 +1473,6 @@ void os::Linux::capture_initial_stack(size_t max_size) {
////////////////////////////////////////////////////////////////////////////////
// time support
void os::Linux::fast_thread_clock_init() {
clockid_t clockid;
struct timespec tp;
int (*pthread_getcpuclockid_func)(pthread_t, clockid_t *) =
(int(*)(pthread_t, clockid_t *)) dlsym(RTLD_DEFAULT, "pthread_getcpuclockid");
// Switch to using fast clocks for thread cpu time if
// the clock_getres() returns 0 error code.
// Note, that some kernels may support the current thread
// clock (CLOCK_THREAD_CPUTIME_ID) but not the clocks
// returned by the pthread_getcpuclockid().
// If the fast POSIX clocks are supported then the clock_getres()
// must return at least tp.tv_sec == 0 which means a resolution
// better than 1 sec. This is extra check for reliability.
if (pthread_getcpuclockid_func &&
pthread_getcpuclockid_func(_main_thread, &clockid) == 0 &&
clock_getres(clockid, &tp) == 0 && tp.tv_sec == 0) {
_supports_fast_thread_cpu_time = true;
_pthread_getcpuclockid = pthread_getcpuclockid_func;
}
}
// thread_id is kernel thread id (similar to Solaris LWP id)
intx os::current_thread_id() { return os::Linux::gettid(); }
int os::current_process_id() {
@ -1770,7 +1745,9 @@ void * os::dll_load(const char *filename, char *ebuf, int ebuflen) {
{EM_LOONGARCH, EM_LOONGARCH, ELFCLASS64, ELFDATA2LSB, (char*)"LoongArch"},
};
#if (defined AMD64)
#if (defined IA32)
static Elf32_Half running_arch_code=EM_386;
#elif (defined AMD64) || (defined X32)
static Elf32_Half running_arch_code=EM_X86_64;
#elif (defined __sparc) && (defined _LP64)
static Elf32_Half running_arch_code=EM_SPARCV9;
@ -1804,7 +1781,7 @@ void * os::dll_load(const char *filename, char *ebuf, int ebuflen) {
static Elf32_Half running_arch_code=EM_LOONGARCH;
#else
#error Method os::dll_load requires that one of following is defined:\
AARCH64, ALPHA, ARM, AMD64, LOONGARCH64, M68K, MIPS, MIPSEL, PARISC, __powerpc__, __powerpc64__, RISCV, S390, SH, __sparc
AARCH64, ALPHA, ARM, AMD64, IA32, LOONGARCH64, M68K, MIPS, MIPSEL, PARISC, __powerpc__, __powerpc64__, RISCV, S390, SH, __sparc
#endif
// Identify compatibility class for VM's architecture and library's architecture
@ -1866,6 +1843,7 @@ void * os::dll_load(const char *filename, char *ebuf, int ebuflen) {
}
void * os::Linux::dlopen_helper(const char *filename, char *ebuf, int ebuflen) {
#ifndef IA32
bool ieee_handling = IEEE_subnormal_handling_OK();
if (!ieee_handling) {
Events::log_dll_message(nullptr, "IEEE subnormal handling check failed before loading %s", filename);
@ -1888,9 +1866,14 @@ void * os::Linux::dlopen_helper(const char *filename, char *ebuf, int ebuflen) {
// numerical "accuracy", but we need to protect Java semantics first
// and foremost. See JDK-8295159.
// This workaround is ineffective on IA32 systems because the MXCSR
// register (which controls flush-to-zero mode) is not stored in the
// legacy fenv.
fenv_t default_fenv;
int rtn = fegetenv(&default_fenv);
assert(rtn == 0, "fegetenv must succeed");
#endif // IA32
void* result;
JFR_ONLY(NativeLibraryLoadEvent load_event(filename, &result);)
@ -1910,6 +1893,7 @@ void * os::Linux::dlopen_helper(const char *filename, char *ebuf, int ebuflen) {
} else {
Events::log_dll_message(nullptr, "Loaded shared library %s", filename);
log_info(os)("shared library load of %s was successful", filename);
#ifndef IA32
// Quickly test to make sure subnormals are correctly handled.
if (! IEEE_subnormal_handling_OK()) {
// We just dlopen()ed a library that mangled the floating-point flags.
@ -1935,6 +1919,7 @@ void * os::Linux::dlopen_helper(const char *filename, char *ebuf, int ebuflen) {
assert(false, "fesetenv didn't work");
}
}
#endif // IA32
}
return result;
}
@ -2433,6 +2418,7 @@ void os::Linux::print_uptime_info(outputStream* st) {
if (ret == 0) {
os::print_dhm(st, "OS uptime:", (long) sinfo.uptime);
}
assert(ret == 0, "sysinfo failed: %s", os::strerror(errno));
}
bool os::Linux::print_container_info(outputStream* st) {
@ -2597,7 +2583,8 @@ void os::print_memory_info(outputStream* st) {
// values in struct sysinfo are "unsigned long"
struct sysinfo si;
sysinfo(&si);
int ret = sysinfo(&si);
assert(ret == 0, "sysinfo failed: %s", os::strerror(errno));
physical_memory_size_type phys_mem = physical_memory();
st->print(", physical " PHYS_MEM_TYPE_FORMAT "k",
phys_mem >> 10);
@ -2605,10 +2592,12 @@ void os::print_memory_info(outputStream* st) {
(void)os::available_memory(avail_mem);
st->print("(" PHYS_MEM_TYPE_FORMAT "k free)",
avail_mem >> 10);
st->print(", swap " UINT64_FORMAT "k",
((jlong)si.totalswap * si.mem_unit) >> 10);
st->print("(" UINT64_FORMAT "k free)",
((jlong)si.freeswap * si.mem_unit) >> 10);
if (ret == 0) {
st->print(", swap " UINT64_FORMAT "k",
((jlong)si.totalswap * si.mem_unit) >> 10);
st->print("(" UINT64_FORMAT "k free)",
((jlong)si.freeswap * si.mem_unit) >> 10);
}
st->cr();
st->print("Page Sizes: ");
_page_sizes.print_on(st);
@ -2991,6 +2980,10 @@ size_t os::pd_pretouch_memory(void* first, void* last, size_t page_size) {
return page_size;
}
void os::numa_set_thread_affinity(Thread* thread, int node) {
Linux::numa_set_thread_affinity(thread->osthread()->thread_id(), node);
}
void os::numa_make_global(char *addr, size_t bytes) {
Linux::numa_interleave_memory(addr, bytes);
}
@ -3173,6 +3166,8 @@ bool os::Linux::libnuma_init() {
libnuma_dlsym(handle, "numa_set_bind_policy")));
set_numa_bitmask_isbitset(CAST_TO_FN_PTR(numa_bitmask_isbitset_func_t,
libnuma_dlsym(handle, "numa_bitmask_isbitset")));
set_numa_bitmask_clearbit(CAST_TO_FN_PTR(numa_bitmask_clearbit_func_t,
libnuma_dlsym(handle, "numa_bitmask_clearbit")));
set_numa_bitmask_equal(CAST_TO_FN_PTR(numa_bitmask_equal_func_t,
libnuma_dlsym(handle, "numa_bitmask_equal")));
set_numa_distance(CAST_TO_FN_PTR(numa_distance_func_t,
@ -3187,20 +3182,32 @@ bool os::Linux::libnuma_init() {
libnuma_dlsym(handle, "numa_set_preferred")));
set_numa_get_run_node_mask(CAST_TO_FN_PTR(numa_get_run_node_mask_func_t,
libnuma_v2_dlsym(handle, "numa_get_run_node_mask")));
set_numa_sched_setaffinity(CAST_TO_FN_PTR(numa_sched_setaffinity_func_t,
libnuma_v2_dlsym(handle, "numa_sched_setaffinity")));
set_numa_allocate_cpumask(CAST_TO_FN_PTR(numa_allocate_cpumask_func_t,
libnuma_v2_dlsym(handle, "numa_allocate_cpumask")));
if (numa_available() != -1) {
set_numa_all_nodes((unsigned long*)libnuma_dlsym(handle, "numa_all_nodes"));
set_numa_all_nodes_ptr((struct bitmask **)libnuma_dlsym(handle, "numa_all_nodes_ptr"));
set_numa_nodes_ptr((struct bitmask **)libnuma_dlsym(handle, "numa_nodes_ptr"));
set_numa_all_cpus_ptr((struct bitmask **)libnuma_dlsym(handle, "numa_all_cpus_ptr"));
set_numa_interleave_bitmask(_numa_get_interleave_mask());
set_numa_membind_bitmask(_numa_get_membind());
set_numa_cpunodebind_bitmask(_numa_get_run_node_mask());
// Create an index -> node mapping, since nodes are not always consecutive
_nindex_to_node = new (mtInternal) GrowableArray<int>(0, mtInternal);
rebuild_nindex_to_node_map();
// Create a cpu -> node mapping
_cpu_to_node = new (mtInternal) GrowableArray<int>(0, mtInternal);
rebuild_cpu_to_node_map();
// Create a node -> CPUs mapping
_numa_affinity_masks = new (mtInternal) GrowableArray<struct bitmask*>(0, mtInternal);
build_numa_affinity_masks();
return true;
}
}
@ -3236,6 +3243,42 @@ size_t os::Linux::default_guard_size(os::ThreadType thr_type) {
return ((thr_type == java_thread || thr_type == compiler_thread) ? 0 : os::vm_page_size());
}
void os::Linux::build_numa_affinity_masks() {
// We only build the affinity masks if running libnuma v2 (_numa_node_to_cpus_v2
// is available) and we have the affinity mask of the process when it started.
if (_numa_node_to_cpus_v2 == nullptr || _numa_all_cpus_ptr == nullptr) {
return;
}
// It's important that we respect any user configuration by removing the
// CPUs we're not allowed to run on from the affinity mask. For example,
// if the user runs the JVM with "numactl -C 0-1,4-5" on a machine with
// the following NUMA setup:
// NUMA 0: CPUs 0-3, NUMA 1: CPUs 4-7
// We expect to get the following affinity masks:
// Affinity masks: idx 0 = (0, 1), idx 1 = (4, 5)
const int num_nodes = get_existing_num_nodes();
const unsigned num_cpus = (unsigned)os::processor_count();
for (int i = 0; i < num_nodes; i++) {
struct bitmask* affinity_mask = _numa_allocate_cpumask();
// Fill the affinity mask with all CPUs belonging to NUMA node i
_numa_node_to_cpus_v2(i, affinity_mask);
// Clear the bits of all CPUs that the process is not allowed to
// execute tasks on
for (unsigned j = 0; j < num_cpus; j++) {
if (!_numa_bitmask_isbitset(_numa_all_cpus_ptr, j)) {
_numa_bitmask_clearbit(affinity_mask, j);
}
}
_numa_affinity_masks->push(affinity_mask);
}
}
void os::Linux::rebuild_nindex_to_node_map() {
int highest_node_number = Linux::numa_max_node();
@ -3351,6 +3394,25 @@ int os::Linux::numa_node_to_cpus(int node, unsigned long *buffer, int bufferlen)
return -1;
}
void os::Linux::numa_set_thread_affinity(pid_t tid, int node) {
// We only set affinity if running libnuma v2 (_numa_sched_setaffinity
// is available) and we have all affinity mask
if (_numa_sched_setaffinity == nullptr ||
_numa_all_cpus_ptr == nullptr ||
_numa_affinity_masks->is_empty()) {
return;
}
if (node == -1) {
// If the node is -1, the affinity is reverted to the original affinity
// of the thread when the VM was started
_numa_sched_setaffinity(tid, _numa_all_cpus_ptr);
} else {
// Normal case, set the affinity to the corresponding affinity mask
_numa_sched_setaffinity(tid, _numa_affinity_masks->at(node));
}
}
int os::Linux::get_node_by_cpu(int cpu_id) {
if (cpu_to_node() != nullptr && cpu_id >= 0 && cpu_id < cpu_to_node()->length()) {
return cpu_to_node()->at(cpu_id);
@ -3360,6 +3422,7 @@ int os::Linux::get_node_by_cpu(int cpu_id) {
GrowableArray<int>* os::Linux::_cpu_to_node;
GrowableArray<int>* os::Linux::_nindex_to_node;
GrowableArray<struct bitmask*>* os::Linux::_numa_affinity_masks;
os::Linux::sched_getcpu_func_t os::Linux::_sched_getcpu;
os::Linux::numa_node_to_cpus_func_t os::Linux::_numa_node_to_cpus;
os::Linux::numa_node_to_cpus_v2_func_t os::Linux::_numa_node_to_cpus_v2;
@ -3371,17 +3434,21 @@ os::Linux::numa_interleave_memory_func_t os::Linux::_numa_interleave_memory;
os::Linux::numa_interleave_memory_v2_func_t os::Linux::_numa_interleave_memory_v2;
os::Linux::numa_set_bind_policy_func_t os::Linux::_numa_set_bind_policy;
os::Linux::numa_bitmask_isbitset_func_t os::Linux::_numa_bitmask_isbitset;
os::Linux::numa_bitmask_clearbit_func_t os::Linux::_numa_bitmask_clearbit;
os::Linux::numa_bitmask_equal_func_t os::Linux::_numa_bitmask_equal;
os::Linux::numa_distance_func_t os::Linux::_numa_distance;
os::Linux::numa_get_membind_func_t os::Linux::_numa_get_membind;
os::Linux::numa_get_interleave_mask_func_t os::Linux::_numa_get_interleave_mask;
os::Linux::numa_get_run_node_mask_func_t os::Linux::_numa_get_run_node_mask;
os::Linux::numa_sched_setaffinity_func_t os::Linux::_numa_sched_setaffinity;
os::Linux::numa_allocate_cpumask_func_t os::Linux::_numa_allocate_cpumask;
os::Linux::numa_move_pages_func_t os::Linux::_numa_move_pages;
os::Linux::numa_set_preferred_func_t os::Linux::_numa_set_preferred;
os::Linux::NumaAllocationPolicy os::Linux::_current_numa_policy;
unsigned long* os::Linux::_numa_all_nodes;
struct bitmask* os::Linux::_numa_all_nodes_ptr;
struct bitmask* os::Linux::_numa_nodes_ptr;
struct bitmask* os::Linux::_numa_all_cpus_ptr;
struct bitmask* os::Linux::_numa_interleave_bitmask;
struct bitmask* os::Linux::_numa_membind_bitmask;
struct bitmask* os::Linux::_numa_cpunodebind_bitmask;
@ -4236,7 +4303,7 @@ OSReturn os::get_native_priority(const Thread* const thread,
// For reference, please, see IEEE Std 1003.1-2004:
// http://www.unix.org/single_unix_specification
jlong os::Linux::fast_thread_cpu_time(clockid_t clockid) {
jlong os::Linux::total_thread_cpu_time(clockid_t clockid) {
struct timespec tp;
int status = clock_gettime(clockid, &tp);
assert(status == 0, "clock_gettime error: %s", os::strerror(errno));
@ -4464,8 +4531,6 @@ jint os::init_2(void) {
os::Posix::init_2();
Linux::fast_thread_clock_init();
if (PosixSignals::init() == JNI_ERR) {
return JNI_ERR;
}
@ -4893,14 +4958,14 @@ int os::open(const char *path, int oflag, int mode) {
return fd;
}
static jlong slow_thread_cpu_time(Thread *thread, bool user_sys_cpu_time);
static jlong user_thread_cpu_time(Thread *thread);
static jlong fast_cpu_time(Thread *thread) {
static jlong total_thread_cpu_time(Thread *thread) {
clockid_t clockid;
int rc = os::Linux::pthread_getcpuclockid(thread->osthread()->pthread_id(),
int rc = pthread_getcpuclockid(thread->osthread()->pthread_id(),
&clockid);
if (rc == 0) {
return os::Linux::fast_thread_cpu_time(clockid);
return os::Linux::total_thread_cpu_time(clockid);
} else {
// It's possible to encounter a terminated native thread that failed
// to detach itself from the VM - which should result in ESRCH.
@ -4917,41 +4982,31 @@ static jlong fast_cpu_time(Thread *thread) {
// the fast estimate available on the platform.
jlong os::current_thread_cpu_time() {
if (os::Linux::supports_fast_thread_cpu_time()) {
return os::Linux::fast_thread_cpu_time(CLOCK_THREAD_CPUTIME_ID);
} else {
// return user + sys since the cost is the same
return slow_thread_cpu_time(Thread::current(), true /* user + sys */);
}
return os::Linux::total_thread_cpu_time(CLOCK_THREAD_CPUTIME_ID);
}
jlong os::thread_cpu_time(Thread* thread) {
// consistent with what current_thread_cpu_time() returns
if (os::Linux::supports_fast_thread_cpu_time()) {
return fast_cpu_time(thread);
} else {
return slow_thread_cpu_time(thread, true /* user + sys */);
}
return total_thread_cpu_time(thread);
}
jlong os::current_thread_cpu_time(bool user_sys_cpu_time) {
if (user_sys_cpu_time && os::Linux::supports_fast_thread_cpu_time()) {
return os::Linux::fast_thread_cpu_time(CLOCK_THREAD_CPUTIME_ID);
if (user_sys_cpu_time) {
return os::Linux::total_thread_cpu_time(CLOCK_THREAD_CPUTIME_ID);
} else {
return slow_thread_cpu_time(Thread::current(), user_sys_cpu_time);
return user_thread_cpu_time(Thread::current());
}
}
jlong os::thread_cpu_time(Thread *thread, bool user_sys_cpu_time) {
if (user_sys_cpu_time && os::Linux::supports_fast_thread_cpu_time()) {
return fast_cpu_time(thread);
if (user_sys_cpu_time) {
return total_thread_cpu_time(thread);
} else {
return slow_thread_cpu_time(thread, user_sys_cpu_time);
return user_thread_cpu_time(thread);
}
}
// -1 on error.
static jlong slow_thread_cpu_time(Thread *thread, bool user_sys_cpu_time) {
static jlong user_thread_cpu_time(Thread *thread) {
pid_t tid = thread->osthread()->thread_id();
char *s;
char stat[2048];
@ -4988,11 +5043,8 @@ static jlong slow_thread_cpu_time(Thread *thread, bool user_sys_cpu_time) {
&ldummy, &ldummy, &ldummy, &ldummy, &ldummy,
&user_time, &sys_time);
if (count != 13) return -1;
if (user_sys_cpu_time) {
return ((jlong)sys_time + (jlong)user_time) * (1000000000 / os::Posix::clock_tics_per_second());
} else {
return (jlong)user_time * (1000000000 / os::Posix::clock_tics_per_second());
}
return (jlong)user_time * (1000000000 / os::Posix::clock_tics_per_second());
}
void os::current_thread_cpu_time_info(jvmtiTimerInfo *info_ptr) {
@ -5071,7 +5123,7 @@ int os::get_core_path(char* buffer, size_t bufferSize) {
if (core_pattern[0] == '|') {
written = jio_snprintf(buffer, bufferSize,
"\"%s\" (or dumping to %s/core.%d)",
"\"%s\" (alternatively, falling back to %s/core.%d)",
&core_pattern[1], p, current_process_id());
} else if (pid_pos != nullptr) {
*pid_pos = '\0';

View File

@ -32,19 +32,19 @@
class os::Linux {
friend class os;
static int (*_pthread_getcpuclockid)(pthread_t, clockid_t *);
static address _initial_thread_stack_bottom;
static uintptr_t _initial_thread_stack_size;
static const char *_libc_version;
static const char *_libpthread_version;
static bool _supports_fast_thread_cpu_time;
static GrowableArray<int>* _cpu_to_node;
static GrowableArray<int>* _nindex_to_node;
static GrowableArray<struct bitmask*>* _numa_affinity_masks;
static void build_numa_affinity_masks();
protected:
static physical_memory_size_type _physical_memory;
@ -142,18 +142,7 @@ class os::Linux {
static bool manually_expand_stack(JavaThread * t, address addr);
static void expand_stack_to(address bottom);
// fast POSIX clocks support
static void fast_thread_clock_init(void);
static int pthread_getcpuclockid(pthread_t tid, clockid_t *clock_id) {
return _pthread_getcpuclockid ? _pthread_getcpuclockid(tid, clock_id) : -1;
}
static bool supports_fast_thread_cpu_time() {
return _supports_fast_thread_cpu_time;
}
static jlong fast_thread_cpu_time(clockid_t clockid);
static jlong total_thread_cpu_time(clockid_t clockid);
static jlong sendfile(int out_fd, int in_fd, jlong* offset, jlong count);
@ -230,8 +219,11 @@ class os::Linux {
typedef void (*numa_set_preferred_func_t)(int node);
typedef void (*numa_set_bind_policy_func_t)(int policy);
typedef int (*numa_bitmask_isbitset_func_t)(struct bitmask *bmp, unsigned int n);
typedef int (*numa_bitmask_clearbit_func_t)(struct bitmask *bmp, unsigned int n);
typedef int (*numa_bitmask_equal_func_t)(struct bitmask *bmp1, struct bitmask *bmp2);
typedef int (*numa_distance_func_t)(int node1, int node2);
typedef int (*numa_sched_setaffinity_func_t)(pid_t pid, struct bitmask* mask);
typedef struct bitmask* (*numa_allocate_cpumask_func_t)(void);
static sched_getcpu_func_t _sched_getcpu;
static numa_node_to_cpus_func_t _numa_node_to_cpus;
@ -244,6 +236,7 @@ class os::Linux {
static numa_interleave_memory_v2_func_t _numa_interleave_memory_v2;
static numa_set_bind_policy_func_t _numa_set_bind_policy;
static numa_bitmask_isbitset_func_t _numa_bitmask_isbitset;
static numa_bitmask_clearbit_func_t _numa_bitmask_clearbit;
static numa_bitmask_equal_func_t _numa_bitmask_equal;
static numa_distance_func_t _numa_distance;
static numa_get_membind_func_t _numa_get_membind;
@ -251,9 +244,12 @@ class os::Linux {
static numa_get_interleave_mask_func_t _numa_get_interleave_mask;
static numa_move_pages_func_t _numa_move_pages;
static numa_set_preferred_func_t _numa_set_preferred;
static numa_sched_setaffinity_func_t _numa_sched_setaffinity;
static numa_allocate_cpumask_func_t _numa_allocate_cpumask;
static unsigned long* _numa_all_nodes;
static struct bitmask* _numa_all_nodes_ptr;
static struct bitmask* _numa_nodes_ptr;
static struct bitmask* _numa_all_cpus_ptr;
static struct bitmask* _numa_interleave_bitmask;
static struct bitmask* _numa_membind_bitmask;
static struct bitmask* _numa_cpunodebind_bitmask;
@ -269,6 +265,7 @@ class os::Linux {
static void set_numa_interleave_memory_v2(numa_interleave_memory_v2_func_t func) { _numa_interleave_memory_v2 = func; }
static void set_numa_set_bind_policy(numa_set_bind_policy_func_t func) { _numa_set_bind_policy = func; }
static void set_numa_bitmask_isbitset(numa_bitmask_isbitset_func_t func) { _numa_bitmask_isbitset = func; }
static void set_numa_bitmask_clearbit(numa_bitmask_clearbit_func_t func) { _numa_bitmask_clearbit = func; }
static void set_numa_bitmask_equal(numa_bitmask_equal_func_t func) { _numa_bitmask_equal = func; }
static void set_numa_distance(numa_distance_func_t func) { _numa_distance = func; }
static void set_numa_get_membind(numa_get_membind_func_t func) { _numa_get_membind = func; }
@ -279,9 +276,12 @@ class os::Linux {
static void set_numa_all_nodes(unsigned long* ptr) { _numa_all_nodes = ptr; }
static void set_numa_all_nodes_ptr(struct bitmask **ptr) { _numa_all_nodes_ptr = (ptr == nullptr ? nullptr : *ptr); }
static void set_numa_nodes_ptr(struct bitmask **ptr) { _numa_nodes_ptr = (ptr == nullptr ? nullptr : *ptr); }
static void set_numa_all_cpus_ptr(struct bitmask **ptr) { _numa_all_cpus_ptr = (ptr == nullptr ? nullptr : *ptr); }
static void set_numa_interleave_bitmask(struct bitmask* ptr) { _numa_interleave_bitmask = ptr ; }
static void set_numa_membind_bitmask(struct bitmask* ptr) { _numa_membind_bitmask = ptr ; }
static void set_numa_cpunodebind_bitmask(struct bitmask* ptr) { _numa_cpunodebind_bitmask = ptr ; }
static void set_numa_sched_setaffinity(numa_sched_setaffinity_func_t func) { _numa_sched_setaffinity = func; }
static void set_numa_allocate_cpumask(numa_allocate_cpumask_func_t func) { _numa_allocate_cpumask = func; }
static int sched_getcpu_syscall(void);
enum NumaAllocationPolicy{
@ -292,6 +292,8 @@ class os::Linux {
static NumaAllocationPolicy _current_numa_policy;
public:
static void numa_set_thread_affinity(pid_t tid, int node);
static int sched_getcpu() { return _sched_getcpu != nullptr ? _sched_getcpu() : -1; }
static int numa_node_to_cpus(int node, unsigned long *buffer, int bufferlen);
static int numa_max_node() { return _numa_max_node != nullptr ? _numa_max_node() : -1; }

View File

@ -108,41 +108,60 @@ size_t os::_os_min_stack_allowed = PTHREAD_STACK_MIN;
// Check core dump limit and report possible place where core can be found
void os::check_core_dump_prerequisites(char* buffer, size_t bufferSize, bool check_only) {
stringStream buf(buffer, bufferSize);
if (!FLAG_IS_DEFAULT(CreateCoredumpOnCrash) && !CreateCoredumpOnCrash) {
jio_snprintf(buffer, bufferSize, "CreateCoredumpOnCrash is disabled from command line");
VMError::record_coredump_status(buffer, false);
buf.print("CreateCoredumpOnCrash is disabled from command line");
VMError::record_coredump_status(buf.freeze(), false);
} else {
struct rlimit rlim;
bool success = true;
bool warn = true;
char core_path[PATH_MAX];
if (get_core_path(core_path, PATH_MAX) <= 0) {
jio_snprintf(buffer, bufferSize, "core.%d (may not exist)", current_process_id());
// In the warning message, let the user know.
if (check_only) {
buf.print("the core path couldn't be determined. It commonly defaults to ");
}
buf.print("core.%d%s", current_process_id(), check_only ? "" : " (may not exist)");
#ifdef LINUX
} else if (core_path[0] == '"') { // redirect to user process
jio_snprintf(buffer, bufferSize, "Core dumps may be processed with %s", core_path);
if (check_only) {
buf.print("core dumps may be further processed by the following: ");
} else {
buf.print("Determined by the following: ");
}
buf.print("%s", core_path);
#endif
} else if (getrlimit(RLIMIT_CORE, &rlim) != 0) {
jio_snprintf(buffer, bufferSize, "%s (may not exist)", core_path);
if (check_only) {
buf.print("the rlimit couldn't be determined. If resource limits permit, the core dump will be located at ");
}
buf.print("%s%s", core_path, check_only ? "" : " (may not exist)");
} else {
switch(rlim.rlim_cur) {
case RLIM_INFINITY:
jio_snprintf(buffer, bufferSize, "%s", core_path);
buf.print("%s", core_path);
warn = false;
break;
case 0:
jio_snprintf(buffer, bufferSize, "Core dumps have been disabled. To enable core dumping, try \"ulimit -c unlimited\" before starting Java again");
buf.print("%s dumps have been disabled. To enable core dumping, try \"ulimit -c unlimited\" before starting Java again", check_only ? "core" : "Core");
success = false;
break;
default:
jio_snprintf(buffer, bufferSize, "%s (max size " UINT64_FORMAT " k). To ensure a full core dump, try \"ulimit -c unlimited\" before starting Java again", core_path, uint64_t(rlim.rlim_cur) / K);
if (check_only) {
buf.print("core dumps are constrained ");
} else {
buf.print( "%s ", core_path);
}
buf.print( "(max size " UINT64_FORMAT " k). To ensure a full core dump, try \"ulimit -c unlimited\" before starting Java again", uint64_t(rlim.rlim_cur) / K);
break;
}
}
const char* result = buf.freeze();
if (!check_only) {
VMError::record_coredump_status(buffer, success);
VMError::record_coredump_status(result, success);
} else if (warn) {
warning("CreateCoredumpOnCrash specified, but %s", buffer);
warning("CreateCoredumpOnCrash specified, but %s", result);
}
}
}

View File

@ -621,7 +621,7 @@ int JVM_HANDLE_XXX_SIGNAL(int sig, siginfo_t* info,
if (cb != nullptr && cb->is_nmethod()) {
nmethod* nm = cb->as_nmethod();
assert(nm->insts_contains_inclusive(pc), "");
address deopt = nm->deopt_handler_begin();
address deopt = nm->deopt_handler_entry();
assert(deopt != nullptr, "");
frame fr = os::fetch_frame_from_context(uc);

View File

@ -2795,7 +2795,7 @@ LONG WINAPI topLevelExceptionFilter(struct _EXCEPTION_POINTERS* exceptionInfo) {
if (cb != nullptr && cb->is_nmethod()) {
nmethod* nm = cb->as_nmethod();
frame fr = os::fetch_frame_from_context((void*)exceptionInfo->ContextRecord);
address deopt = nm->deopt_handler_begin();
address deopt = nm->deopt_handler_entry();
assert(nm->insts_contains_inclusive(pc), "");
nm->set_original_pc(&fr, pc);
// Set pc to handler
@ -3752,6 +3752,7 @@ size_t os::pd_pretouch_memory(void* first, void* last, size_t page_size) {
return page_size;
}
void os::numa_set_thread_affinity(Thread *thread, int node) { }
void os::numa_make_global(char *addr, size_t bytes) { }
void os::numa_make_local(char *addr, size_t bytes, int lgrp_hint) { }
size_t os::numa_get_groups_num() { return MAX2(numa_node_list_holder.get_count(), 1); }

View File

@ -52,12 +52,16 @@ struct AtomicAccess::PlatformAdd {
}
};
template<>
struct AtomicAccess::PlatformXchg<1> : AtomicAccess::XchgUsingCmpxchg<1> {};
template<size_t byte_size>
template<typename T>
inline T AtomicAccess::PlatformXchg<byte_size>::operator()(T volatile* dest,
T exchange_value,
atomic_memory_order order) const {
STATIC_ASSERT(byte_size == sizeof(T));
STATIC_ASSERT(byte_size == 4 || byte_size == 8);
T res = __atomic_exchange_n(dest, exchange_value, __ATOMIC_RELEASE);
FULL_MEM_BARRIER;
return res;

View File

@ -52,6 +52,9 @@ inline D AtomicAccess::PlatformAdd<4>::fetch_then_add(D volatile* dest, I add_va
return old_value;
}
template<>
struct AtomicAccess::PlatformXchg<1> : AtomicAccess::XchgUsingCmpxchg<1> {};
template<>
template<typename T>
inline T AtomicAccess::PlatformXchg<4>::operator()(T volatile* dest,

View File

@ -66,6 +66,9 @@ inline D AtomicAccess::PlatformAdd<8>::add_then_fetch(D volatile* dest, I add_va
return res;
}
template<>
struct AtomicAccess::PlatformXchg<1> : AtomicAccess::XchgUsingCmpxchg<1> {};
template<>
template<typename T>
inline T AtomicAccess::PlatformXchg<4>::operator()(T volatile* dest,

View File

@ -113,6 +113,9 @@ inline D AtomicAccess::PlatformAdd<8>::fetch_then_add(D volatile* dest, I add_va
return atomic_fastcall(stub, dest, add_value);
}
template<>
struct AtomicAccess::PlatformXchg<1> : AtomicAccess::XchgUsingCmpxchg<1> {};
template<>
template<typename T>
inline T AtomicAccess::PlatformXchg<4>::operator()(T volatile* dest,

View File

@ -118,6 +118,8 @@ inline D AtomicAccess::PlatformAdd<4>::add_then_fetch(D volatile* dest, I add_va
return add_using_helper<int32_t>(ARMAtomicFuncs::_add_func, dest, add_value);
}
template<>
struct AtomicAccess::PlatformXchg<1> : AtomicAccess::XchgUsingCmpxchg<1> {};
template<>
template<typename T>

View File

@ -246,9 +246,9 @@ void MacroAssembler::atomic_cas64(Register memval_lo, Register memval_hi, Regist
Label loop;
assert_different_registers(memval_lo, memval_hi, result, oldval_lo,
oldval_hi, newval_lo, newval_hi, base);
assert(memval_hi == memval_lo + 1 && memval_lo < R9, "cmpxchg_long: illegal registers");
assert(oldval_hi == oldval_lo + 1 && oldval_lo < R9, "cmpxchg_long: illegal registers");
assert(newval_hi == newval_lo + 1 && newval_lo < R9, "cmpxchg_long: illegal registers");
assert(memval_hi == as_Register(memval_lo->encoding() + 1) && memval_lo->encoding() < R9->encoding(), "cmpxchg_long: illegal registers");
assert(oldval_hi == as_Register(oldval_lo->encoding() + 1) && oldval_lo->encoding() < R9->encoding(), "cmpxchg_long: illegal registers");
assert(newval_hi == as_Register(newval_lo->encoding() + 1) && newval_lo->encoding() < R9->encoding(), "cmpxchg_long: illegal registers");
assert(result != R10, "cmpxchg_long: illegal registers");
assert(base != R10, "cmpxchg_long: illegal registers");

View File

@ -152,6 +152,9 @@ inline T AtomicAccess::PlatformCmpxchg<4>::operator()(T volatile* dest __attribu
}
#endif
template<>
struct AtomicAccess::PlatformXchg<1> : AtomicAccess::XchgUsingCmpxchg<1> {};
template<size_t byte_size>
template<typename T>
inline T AtomicAccess::PlatformXchg<byte_size>::operator()(T volatile* dest,
@ -164,6 +167,7 @@ inline T AtomicAccess::PlatformXchg<byte_size>::operator()(T volatile* dest,
#endif
STATIC_ASSERT(byte_size == sizeof(T));
STATIC_ASSERT(byte_size == 4 || byte_size == 8);
if (order != memory_order_relaxed) {
FULL_MEM_BARRIER;

View File

@ -104,11 +104,15 @@ uint32_t VM_Version::cpu_vector_length() {
}
void VM_Version::RVExtFeatureValue::log_enabled() {
log_debug(os, cpu)("Enabled RV64 feature \"%s\"", pretty());
log_info(os, cpu)("Enabled RV64 feature \"%s\"", pretty());
}
void VM_Version::RVExtFeatureValue::log_disabled(const char* reason) {
log_info(os, cpu)("Disabled RV64 feature \"%s\" (%s)", pretty(), reason);
}
void VM_Version::RVNonExtFeatureValue::log_enabled() {
log_debug(os, cpu)("Enabled RV64 feature \"%s\" (%ld)", pretty(), value());
log_info(os, cpu)("Enabled RV64 feature \"%s\" (%ld)", pretty(), value());
}
void VM_Version::setup_cpu_available_features() {
@ -193,7 +197,7 @@ void VM_Version::setup_cpu_available_features() {
// via PR_RISCV_SCOPE_PER_THREAD, i.e. on VM attach/deattach.
int ret = prctl(PR_RISCV_SET_ICACHE_FLUSH_CTX, PR_RISCV_CTX_SW_FENCEI_ON, PR_RISCV_SCOPE_PER_PROCESS);
if (ret == 0) {
log_debug(os, cpu)("UseCtxFencei (PR_RISCV_CTX_SW_FENCEI_ON) enabled.");
log_info(os, cpu)("UseCtxFencei (PR_RISCV_CTX_SW_FENCEI_ON) enabled.");
} else {
FLAG_SET_ERGO(UseCtxFencei, false);
log_info(os, cpu)("UseCtxFencei (PR_RISCV_CTX_SW_FENCEI_ON) disabled, unsupported by kernel.");

View File

@ -209,6 +209,9 @@ inline D AtomicAccess::PlatformAdd<8>::add_then_fetch(D volatile* dest, I inc,
//
// The return value is the (unchanged) value from memory as it was when the
// replacement succeeded.
template<>
struct AtomicAccess::PlatformXchg<1> : AtomicAccess::XchgUsingCmpxchg<1> {};
template<>
template<typename T>
inline T AtomicAccess::PlatformXchg<4>::operator()(T volatile* dest,

View File

@ -52,6 +52,9 @@ inline D AtomicAccess::PlatformAdd<4>::fetch_then_add(D volatile* dest, I add_va
return old_value;
}
template<>
struct AtomicAccess::PlatformXchg<1> : AtomicAccess::XchgUsingCmpxchg<1> {};
template<>
template<typename T>
inline T AtomicAccess::PlatformXchg<4>::operator()(T volatile* dest,

View File

@ -65,6 +65,9 @@ inline D AtomicAccess::PlatformAdd<8>::add_then_fetch(D volatile* dest, I add_va
return res;
}
template<>
struct AtomicAccess::PlatformXchg<1> : AtomicAccess::XchgUsingCmpxchg<1> {};
template<>
template<typename T>
inline T AtomicAccess::PlatformXchg<4>::operator()(T volatile* dest,

View File

@ -68,6 +68,9 @@ DEFINE_INTRINSIC_ADD(InterlockedAdd64, __int64)
#undef DEFINE_INTRINSIC_ADD
template<>
struct AtomicAccess::PlatformXchg<1> : AtomicAccess::XchgUsingCmpxchg<1> {};
#define DEFINE_INTRINSIC_XCHG(IntrinsicName, IntrinsicType) \
template<> \
template<typename T> \
@ -75,6 +78,8 @@ DEFINE_INTRINSIC_ADD(InterlockedAdd64, __int64)
T exchange_value, \
atomic_memory_order order) const { \
STATIC_ASSERT(sizeof(IntrinsicType) == sizeof(T)); \
STATIC_ASSERT(sizeof(IntrinsicType) == 4 || \
sizeof(IntrinsicType) == 8); \
return PrimitiveConversions::cast<T>( \
IntrinsicName(reinterpret_cast<IntrinsicType volatile *>(dest), \
PrimitiveConversions::cast<IntrinsicType>(exchange_value))); \

View File

@ -70,6 +70,9 @@ DEFINE_INTRINSIC_ADD(InterlockedAdd64, __int64)
#undef DEFINE_INTRINSIC_ADD
template<>
struct AtomicAccess::PlatformXchg<1> : AtomicAccess::XchgUsingCmpxchg<1> {};
#define DEFINE_INTRINSIC_XCHG(IntrinsicName, IntrinsicType) \
template<> \
template<typename T> \
@ -77,6 +80,8 @@ DEFINE_INTRINSIC_ADD(InterlockedAdd64, __int64)
T exchange_value, \
atomic_memory_order order) const { \
STATIC_ASSERT(sizeof(IntrinsicType) == sizeof(T)); \
STATIC_ASSERT(sizeof(IntrinsicType) == 4 || \
sizeof(IntrinsicType) == 8); \
return PrimitiveConversions::cast<T>( \
IntrinsicName(reinterpret_cast<IntrinsicType volatile *>(dest), \
PrimitiveConversions::cast<IntrinsicType>(exchange_value))); \

View File

@ -449,7 +449,7 @@ bool AOTConstantPoolResolver::check_lambda_metafactory_signature(ConstantPool* c
}
bool AOTConstantPoolResolver::check_lambda_metafactory_methodtype_arg(ConstantPool* cp, int bsms_attribute_index, int arg_i) {
int mt_index = cp->bsm_attribute_entry(bsms_attribute_index)->argument_index(arg_i);
int mt_index = cp->bsm_attribute_entry(bsms_attribute_index)->argument(arg_i);
if (!cp->tag_at(mt_index).is_method_type()) {
// malformed class?
return false;
@ -465,7 +465,7 @@ bool AOTConstantPoolResolver::check_lambda_metafactory_methodtype_arg(ConstantPo
}
bool AOTConstantPoolResolver::check_lambda_metafactory_methodhandle_arg(ConstantPool* cp, int bsms_attribute_index, int arg_i) {
int mh_index = cp->bsm_attribute_entry(bsms_attribute_index)->argument_index(arg_i);
int mh_index = cp->bsm_attribute_entry(bsms_attribute_index)->argument(arg_i);
if (!cp->tag_at(mh_index).is_method_handle()) {
// malformed class?
return false;

View File

@ -114,6 +114,7 @@ intx AOTMetaspace::_relocation_delta;
char* AOTMetaspace::_requested_base_address;
Array<Method*>* AOTMetaspace::_archived_method_handle_intrinsics = nullptr;
bool AOTMetaspace::_use_optimized_module_handling = true;
int volatile AOTMetaspace::_preimage_static_archive_dumped = 0;
FileMapInfo* AOTMetaspace::_output_mapinfo = nullptr;
// The CDS archive is divided into the following regions:
@ -1056,7 +1057,21 @@ void AOTMetaspace::exercise_runtime_cds_code(TRAPS) {
CDSProtectionDomain::to_file_URL("dummy.jar", Handle(), CHECK);
}
bool AOTMetaspace::preimage_static_archive_dumped() {
assert(CDSConfig::is_dumping_preimage_static_archive(), "Required");
return AtomicAccess::load_acquire(&_preimage_static_archive_dumped) == 1;
}
void AOTMetaspace::dump_static_archive_impl(StaticArchiveBuilder& builder, TRAPS) {
if (CDSConfig::is_dumping_preimage_static_archive()) {
// When dumping to the AOT configuration file ensure this function is only executed once.
// Multiple invocations may happen via JCmd, during VM exit or other means (in the future)
// from different threads and possibly concurrently.
if (AtomicAccess::cmpxchg(&_preimage_static_archive_dumped, 0, 1) != 0) {
return;
}
}
if (CDSConfig::is_dumping_classic_static_archive()) {
// We are running with -Xshare:dump
load_classes(CHECK);
@ -1355,8 +1370,11 @@ bool AOTMetaspace::try_link_class(JavaThread* current, InstanceKlass* ik) {
ik->link_class(THREAD);
if (HAS_PENDING_EXCEPTION) {
ResourceMark rm(THREAD);
aot_log_warning(aot)("Preload Warning: Verification failed for %s",
ik->external_name());
oop message = java_lang_Throwable::message(current->pending_exception());
aot_log_warning(aot)("Preload Warning: Verification failed for %s because a %s was thrown: %s",
ik->external_name(),
current->pending_exception()->klass()->external_name(),
message == nullptr ? "(no message)" : java_lang_String::as_utf8_string(message));
CLEAR_PENDING_EXCEPTION;
SystemDictionaryShared::set_class_has_failed_verification(ik);
} else {

View File

@ -60,6 +60,7 @@ class AOTMetaspace : AllStatic {
static char* _requested_base_address;
static bool _use_optimized_module_handling;
static Array<Method*>* _archived_method_handle_intrinsics;
static int volatile _preimage_static_archive_dumped;
static FileMapInfo* _output_mapinfo;
public:
@ -115,6 +116,8 @@ public:
// inside the metaspace of the dynamic static CDS archive
static bool in_aot_cache_dynamic_region(void* p) NOT_CDS_RETURN_(false);
static bool preimage_static_archive_dumped() NOT_CDS_RETURN_(false);
static void unrecoverable_loading_error(const char* message = "unrecoverable error");
static void report_loading_error(const char* format, ...) ATTRIBUTE_PRINTF(1, 0);
static void unrecoverable_writing_error(const char* message = nullptr);

View File

@ -1057,7 +1057,9 @@ void ciEnv::register_method(ciMethod* target,
}
assert(offsets->value(CodeOffsets::Deopt) != -1, "must have deopt entry");
assert(offsets->value(CodeOffsets::Exceptions) != -1, "must have exception entry");
assert(compiler->type() == compiler_c2 ||
offsets->value(CodeOffsets::Exceptions) != -1, "must have exception entry");
nm = nmethod::new_nmethod(method,
compile_id(),

View File

@ -47,6 +47,7 @@
#include "memory/resourceArea.hpp"
#include "memory/universe.hpp"
#include "oops/annotations.hpp"
#include "oops/bsmAttribute.inline.hpp"
#include "oops/constantPool.inline.hpp"
#include "oops/fieldInfo.hpp"
#include "oops/fieldStreams.inline.hpp"
@ -3298,8 +3299,9 @@ void ClassFileParser::parse_classfile_bootstrap_methods_attribute(const ClassFil
TRAPS) {
assert(cfs != nullptr, "invariant");
assert(cp != nullptr, "invariant");
const int cp_size = cp->length();
const u1* const current_start = cfs->current();
const u1* const current_before_parsing = cfs->current();
guarantee_property(attribute_byte_length >= sizeof(u2),
"Invalid BootstrapMethods attribute length %u in class file %s",
@ -3308,57 +3310,40 @@ void ClassFileParser::parse_classfile_bootstrap_methods_attribute(const ClassFil
cfs->guarantee_more(attribute_byte_length, CHECK);
const int attribute_array_length = cfs->get_u2_fast();
const int num_bootstrap_methods = cfs->get_u2_fast();
guarantee_property(_max_bootstrap_specifier_index < attribute_array_length,
guarantee_property(_max_bootstrap_specifier_index < num_bootstrap_methods,
"Short length on BootstrapMethods in class file %s",
CHECK);
const u4 bootstrap_methods_u2_len = (attribute_byte_length - sizeof(u2)) / sizeof(u2);
// The attribute contains a counted array of counted tuples of shorts,
// represending bootstrap specifiers:
// length*{bootstrap_method_index, argument_count*{argument_index}}
const unsigned int operand_count = (attribute_byte_length - (unsigned)sizeof(u2)) / (unsigned)sizeof(u2);
// operand_count = number of shorts in attr, except for leading length
// The attribute is copied into a short[] array.
// The array begins with a series of short[2] pairs, one for each tuple.
const int index_size = (attribute_array_length * 2);
Array<u2>* const operands =
MetadataFactory::new_array<u2>(_loader_data, index_size + operand_count, CHECK);
// Eagerly assign operands so they will be deallocated with the constant
// Eagerly assign the arrays so that they will be deallocated with the constant
// pool if there is an error.
cp->set_operands(operands);
BSMAttributeEntries::InsertionIterator iter =
cp->bsm_entries().start_extension(num_bootstrap_methods,
bootstrap_methods_u2_len,
_loader_data,
CHECK);
int operand_fill_index = index_size;
const int cp_size = cp->length();
for (int n = 0; n < attribute_array_length; n++) {
// Store a 32-bit offset into the header of the operand array.
ConstantPool::operand_offset_at_put(operands, n, operand_fill_index);
// Read a bootstrap specifier.
for (int i = 0; i < num_bootstrap_methods; i++) {
cfs->guarantee_more(sizeof(u2) * 2, CHECK); // bsm, argc
const u2 bootstrap_method_index = cfs->get_u2_fast();
const u2 argument_count = cfs->get_u2_fast();
u2 bootstrap_method_ref = cfs->get_u2_fast();
u2 num_bootstrap_arguments = cfs->get_u2_fast();
guarantee_property(
valid_cp_range(bootstrap_method_index, cp_size) &&
cp->tag_at(bootstrap_method_index).is_method_handle(),
"bootstrap_method_index %u has bad constant type in class file %s",
bootstrap_method_index,
CHECK);
valid_cp_range(bootstrap_method_ref, cp_size) &&
cp->tag_at(bootstrap_method_ref).is_method_handle(),
"bootstrap_method_index %u has bad constant type in class file %s",
bootstrap_method_ref,
CHECK);
cfs->guarantee_more(sizeof(u2) * num_bootstrap_arguments, CHECK); // argv[argc]
guarantee_property((operand_fill_index + 1 + argument_count) < operands->length(),
"Invalid BootstrapMethods num_bootstrap_methods or num_bootstrap_arguments value in class file %s",
CHECK);
BSMAttributeEntry* entry = iter.reserve_new_entry(bootstrap_method_ref, num_bootstrap_arguments);
guarantee_property(entry != nullptr,
"Invalid BootstrapMethods num_bootstrap_methods."
" The total amount of space reserved for the BootstrapMethod attribute was not sufficient", CHECK);
operands->at_put(operand_fill_index++, bootstrap_method_index);
operands->at_put(operand_fill_index++, argument_count);
cfs->guarantee_more(sizeof(u2) * argument_count, CHECK); // argv[argc]
for (int j = 0; j < argument_count; j++) {
for (int argi = 0; argi < num_bootstrap_arguments; argi++) {
const u2 argument_index = cfs->get_u2_fast();
guarantee_property(
valid_cp_range(argument_index, cp_size) &&
@ -3366,10 +3351,11 @@ void ClassFileParser::parse_classfile_bootstrap_methods_attribute(const ClassFil
"argument_index %u has bad constant type in class file %s",
argument_index,
CHECK);
operands->at_put(operand_fill_index++, argument_index);
entry->set_argument(argi, argument_index);
}
}
guarantee_property(current_start + attribute_byte_length == cfs->current(),
cp->bsm_entries().end_extension(iter, _loader_data, CHECK);
guarantee_property(current_before_parsing + attribute_byte_length == cfs->current(),
"Bad length on BootstrapMethods in class file %s",
CHECK);
}

View File

@ -1302,7 +1302,7 @@ nmethod::nmethod(
}
// Native wrappers do not have deopt handlers. Make the values
// something that will never match a pc like the nmethod vtable entry
_deopt_handler_offset = 0;
_deopt_handler_entry_offset = 0;
_unwind_handler_offset = 0;
CHECKED_CAST(_oops_size, uint16_t, align_up(code_buffer->total_oop_size(), oopSize));
@ -1442,7 +1442,7 @@ nmethod::nmethod(const nmethod &nm) : CodeBlob(nm._name, nm._kind, nm._size, nm.
_skipped_instructions_size = nm._skipped_instructions_size;
_stub_offset = nm._stub_offset;
_exception_offset = nm._exception_offset;
_deopt_handler_offset = nm._deopt_handler_offset;
_deopt_handler_entry_offset = nm._deopt_handler_entry_offset;
_unwind_handler_offset = nm._unwind_handler_offset;
_num_stack_arg_slots = nm._num_stack_arg_slots;
_oops_size = nm._oops_size;
@ -1704,19 +1704,26 @@ nmethod::nmethod(
_exception_offset = -1;
}
if (offsets->value(CodeOffsets::Deopt) != -1) {
_deopt_handler_offset = code_offset() + offsets->value(CodeOffsets::Deopt);
_deopt_handler_entry_offset = code_offset() + offsets->value(CodeOffsets::Deopt);
} else {
_deopt_handler_offset = -1;
_deopt_handler_entry_offset = -1;
}
} else
#endif
{
// Exception handler and deopt handler are in the stub section
assert(offsets->value(CodeOffsets::Exceptions) != -1, "must be set");
assert(offsets->value(CodeOffsets::Deopt ) != -1, "must be set");
_exception_offset = _stub_offset + offsets->value(CodeOffsets::Exceptions);
_deopt_handler_offset = _stub_offset + offsets->value(CodeOffsets::Deopt);
bool has_exception_handler = (offsets->value(CodeOffsets::Exceptions) != -1);
assert(has_exception_handler == (compiler->type() != compiler_c2),
"C2 compiler doesn't provide exception handler stub code.");
if (has_exception_handler) {
_exception_offset = _stub_offset + offsets->value(CodeOffsets::Exceptions);
} else {
_exception_offset = -1;
}
_deopt_handler_entry_offset = _stub_offset + offsets->value(CodeOffsets::Deopt);
}
if (offsets->value(CodeOffsets::UnwindHandler) != -1) {
// C1 generates UnwindHandler at the end of instructions section.
@ -4024,7 +4031,7 @@ const char* nmethod::nmethod_section_label(address pos) const {
// Check stub_code before checking exception_handler or deopt_handler.
if (pos == this->stub_begin()) label = "[Stub Code]";
if (JVMCI_ONLY(_exception_offset >= 0 &&) pos == exception_begin()) label = "[Exception Handler]";
if (JVMCI_ONLY(_deopt_handler_offset != -1 &&) pos == deopt_handler_begin()) label = "[Deopt Handler Code]";
if (JVMCI_ONLY(_deopt_handler_entry_offset != -1 &&) pos == deopt_handler_entry()) label = "[Deopt Handler Entry Point]";
return label;
}

View File

@ -229,7 +229,7 @@ class nmethod : public CodeBlob {
int _exception_offset;
// All deoptee's will resume execution at this location described by
// this offset.
int _deopt_handler_offset;
int _deopt_handler_entry_offset;
// Offset (from insts_end) of the unwind handler if it exists
int16_t _unwind_handler_offset;
// Number of arguments passed on the stack
@ -617,7 +617,7 @@ public:
address stub_begin () const { return header_begin() + _stub_offset ; }
address stub_end () const { return code_end() ; }
address exception_begin () const { return header_begin() + _exception_offset ; }
address deopt_handler_begin () const { return header_begin() + _deopt_handler_offset ; }
address deopt_handler_entry () const { return header_begin() + _deopt_handler_entry_offset ; }
address unwind_handler_begin () const { return _unwind_handler_offset != -1 ? (insts_end() - _unwind_handler_offset) : nullptr; }
oop* oops_begin () const { return (oop*) data_begin(); }
oop* oops_end () const { return (oop*) data_end(); }

View File

@ -34,7 +34,7 @@
inline bool nmethod::is_deopt_pc(address pc) { return is_deopt_entry(pc); }
inline bool nmethod::is_deopt_entry(address pc) {
return pc == deopt_handler_begin();
return pc == deopt_handler_entry();
}
// class ExceptionCache methods

View File

@ -1010,8 +1010,10 @@ void CompilationMemoryStatistic::print_error_report(outputStream* st) {
oom_stats->print_peak_state_on(st);
st->cr();
}
st->print_cr("Compiler Memory Statistic, 10 most expensive compilations:");
print_all_by_size(st, false, false, 0, 10);
if (Thread::current_or_null_safe() != nullptr) {
st->print_cr("Compiler Memory Statistic, 10 most expensive compilations:");
print_all_by_size(st, false, false, 0, 10);
}
}
void CompilationMemoryStatistic::print_final_report(outputStream* st) {

View File

@ -79,11 +79,10 @@ class [[deprecated]] bad_array_new_length;
// version to decide whether to redeclare deprecated.
#if defined(__clang__)
#if __clang_major__ >= 19
// clang18 and earlier may accept the declaration but go wrong with uses.
// Different warnings and link-time failures are both possible.
#define CAN_DEPRECATE_HARDWARE_INTERFERENCE_SIZES 1
#endif // restrict clang version
// Some versions of clang with some stdlibs reject the declaration. Others may
// accept the declaration but go wrong with uses. Different warnings and
// link-time failures are both possible.
// Known to have problems at least through clang19.
#elif defined(__GNUC__)
#if (__GNUC__ > 13) || (__GNUC__ == 13 && __GNUC_MINOR__ >= 2)

View File

@ -33,10 +33,10 @@
#include "utilities/align.hpp"
G1CollectedHeap* G1AllocRegion::_g1h = nullptr;
G1HeapRegion* G1AllocRegion::_dummy_region = nullptr;
Atomic<G1HeapRegion*> G1AllocRegion::_dummy_region;
void G1AllocRegion::setup(G1CollectedHeap* g1h, G1HeapRegion* dummy_region) {
assert(_dummy_region == nullptr, "should be set once");
assert(_dummy_region.load_relaxed() == nullptr, "should be set once");
assert(dummy_region != nullptr, "pre-condition");
assert(dummy_region->free() == 0, "pre-condition");
@ -46,11 +46,11 @@ void G1AllocRegion::setup(G1CollectedHeap* g1h, G1HeapRegion* dummy_region) {
assert(dummy_region->par_allocate(1, 1, &assert_tmp) == nullptr, "should fail");
_g1h = g1h;
_dummy_region = dummy_region;
_dummy_region.release_store(dummy_region);
}
size_t G1AllocRegion::fill_up_remaining_space(G1HeapRegion* alloc_region) {
assert(alloc_region != nullptr && alloc_region != _dummy_region,
assert(alloc_region != nullptr && alloc_region != _dummy_region.load_relaxed(),
"pre-condition");
size_t result = 0;
@ -111,13 +111,13 @@ size_t G1AllocRegion::retire_internal(G1HeapRegion* alloc_region, bool fill_up)
}
size_t G1AllocRegion::retire(bool fill_up) {
assert_alloc_region(_alloc_region != nullptr, "not initialized properly");
assert_alloc_region(_alloc_region.load_relaxed() != nullptr, "not initialized properly");
size_t waste = 0;
trace("retiring");
G1HeapRegion* alloc_region = _alloc_region;
if (alloc_region != _dummy_region) {
G1HeapRegion* alloc_region = _alloc_region.load_acquire();
if (alloc_region != _dummy_region.load_relaxed()) {
waste = retire_internal(alloc_region, fill_up);
reset_alloc_region();
}
@ -127,7 +127,7 @@ size_t G1AllocRegion::retire(bool fill_up) {
}
HeapWord* G1AllocRegion::new_alloc_region_and_allocate(size_t word_size) {
assert_alloc_region(_alloc_region == _dummy_region, "pre-condition");
assert_alloc_region(_alloc_region.load_relaxed() == _dummy_region.load_relaxed(), "pre-condition");
trace("attempting region allocation");
G1HeapRegion* new_alloc_region = allocate_new_region(word_size);
@ -138,7 +138,6 @@ HeapWord* G1AllocRegion::new_alloc_region_and_allocate(size_t word_size) {
HeapWord* result = new_alloc_region->allocate(word_size);
assert_alloc_region(result != nullptr, "the allocation should succeeded");
OrderAccess::storestore();
// Note that we first perform the allocation and then we store the
// region in _alloc_region. This is the reason why an active region
// can never be empty.
@ -154,16 +153,16 @@ HeapWord* G1AllocRegion::new_alloc_region_and_allocate(size_t word_size) {
void G1AllocRegion::init() {
trace("initializing");
assert_alloc_region(_alloc_region == nullptr, "pre-condition");
assert_alloc_region(_dummy_region != nullptr, "should have been set");
_alloc_region = _dummy_region;
assert_alloc_region(_alloc_region.load_relaxed() == nullptr, "pre-condition");
assert_alloc_region(_dummy_region.load_relaxed() != nullptr, "should have been set");
_alloc_region.release_store(_dummy_region.load_relaxed());
_count = 0;
trace("initialized");
}
void G1AllocRegion::set(G1HeapRegion* alloc_region) {
trace("setting");
assert_alloc_region(_alloc_region == _dummy_region && _count == 0, "pre-condition");
assert_alloc_region(_alloc_region.load_relaxed() == _dummy_region.load_relaxed() && _count == 0, "pre-condition");
update_alloc_region(alloc_region);
trace("set");
@ -175,19 +174,19 @@ void G1AllocRegion::update_alloc_region(G1HeapRegion* alloc_region) {
// maintain the "the alloc region cannot be empty" invariant.
assert_alloc_region(alloc_region != nullptr && !alloc_region->is_empty(), "pre-condition");
_alloc_region = alloc_region;
_alloc_region.release_store(alloc_region);
_count += 1;
trace("updated");
}
G1HeapRegion* G1AllocRegion::release() {
trace("releasing");
G1HeapRegion* alloc_region = _alloc_region;
G1HeapRegion* alloc_region = _alloc_region.load_acquire();
retire(false /* fill_up */);
assert_alloc_region(_alloc_region == _dummy_region, "post-condition of retire()");
_alloc_region = nullptr;
assert_alloc_region(_alloc_region.load_relaxed() == _dummy_region.load_relaxed(), "post-condition of retire()");
_alloc_region.store_relaxed(nullptr);
trace("released");
return (alloc_region == _dummy_region) ? nullptr : alloc_region;
return (alloc_region == _dummy_region.load_relaxed()) ? nullptr : alloc_region;
}
#ifndef PRODUCT
@ -211,12 +210,13 @@ void G1AllocRegion::trace(const char* str, size_t min_word_size, size_t desired_
out->print("%s: %u ", _name, _count);
if (_alloc_region == nullptr) {
G1HeapRegion* alloc_region = _alloc_region.load_acquire();
if (alloc_region == nullptr) {
out->print("null");
} else if (_alloc_region == _dummy_region) {
} else if (alloc_region == _dummy_region.load_relaxed()) {
out->print("DUMMY");
} else {
out->print(HR_FORMAT, HR_FORMAT_PARAMS(_alloc_region));
out->print(HR_FORMAT, HR_FORMAT_PARAMS(alloc_region));
}
out->print(" : %s", str);
@ -235,7 +235,7 @@ void G1AllocRegion::trace(const char* str, size_t min_word_size, size_t desired_
#endif // PRODUCT
G1AllocRegion::G1AllocRegion(const char* name, uint node_index)
: _alloc_region(nullptr),
: _alloc_region(),
_count(0),
_name(name),
_node_index(node_index)
@ -250,7 +250,7 @@ void MutatorAllocRegion::retire_region(G1HeapRegion* alloc_region) {
}
void MutatorAllocRegion::init() {
assert(_retained_alloc_region == nullptr, "Pre-condition");
assert(_retained_alloc_region.load_relaxed() == nullptr, "Pre-condition");
G1AllocRegion::init();
_wasted_bytes = 0;
}
@ -261,8 +261,9 @@ bool MutatorAllocRegion::should_retain(G1HeapRegion* region) {
return false;
}
if (_retained_alloc_region != nullptr &&
free_bytes < _retained_alloc_region->free()) {
G1HeapRegion* retained_alloc_region = _retained_alloc_region.load_acquire();
if (retained_alloc_region != nullptr &&
free_bytes < retained_alloc_region->free()) {
return false;
}
@ -278,10 +279,11 @@ size_t MutatorAllocRegion::retire(bool fill_up) {
// free than the currently retained region.
if (should_retain(current_region)) {
trace("mutator retained");
if (_retained_alloc_region != nullptr) {
waste = retire_internal(_retained_alloc_region, true);
G1HeapRegion* retained_alloc_region = _retained_alloc_region.load_acquire();
if (retained_alloc_region != nullptr) {
waste = retire_internal(retained_alloc_region, true);
}
_retained_alloc_region = current_region;
_retained_alloc_region.release_store(current_region);
} else {
waste = retire_internal(current_region, fill_up);
}
@ -300,7 +302,7 @@ size_t MutatorAllocRegion::used_in_alloc_regions() {
used += hr->used();
}
hr = _retained_alloc_region;
hr = _retained_alloc_region.load_acquire();
if (hr != nullptr) {
used += hr->used();
}
@ -313,9 +315,10 @@ G1HeapRegion* MutatorAllocRegion::release() {
// The retained alloc region must be retired and this must be
// done after the above call to release the mutator alloc region,
// since it might update the _retained_alloc_region member.
if (_retained_alloc_region != nullptr) {
_wasted_bytes += retire_internal(_retained_alloc_region, false);
_retained_alloc_region = nullptr;
G1HeapRegion* retained_alloc_region = _retained_alloc_region.load_acquire();
if (retained_alloc_region != nullptr) {
_wasted_bytes += retire_internal(retained_alloc_region, false);
_retained_alloc_region.store_relaxed(nullptr);
}
log_debug(gc, alloc, region)("Mutator Allocation stats, regions: %u, wasted size: %zu%s (%4.1f%%)",
count(),

View File

@ -29,6 +29,7 @@
#include "gc/g1/g1HeapRegion.hpp"
#include "gc/g1/g1HeapRegionAttr.hpp"
#include "gc/g1/g1NUMA.hpp"
#include "runtime/atomic.hpp"
class G1CollectedHeap;
@ -40,8 +41,6 @@ class G1CollectedHeap;
// replaced.
class G1AllocRegion : public CHeapObj<mtGC> {
private:
// The active allocating region we are currently allocating out
// of. The invariant is that if this object is initialized (i.e.,
// init() has been called and release() has not) then _alloc_region
@ -52,7 +51,7 @@ private:
// then _alloc_region is null and this object should not be used to
// satisfy allocation requests (it was done this way to force the
// correct use of init() and release()).
G1HeapRegion* volatile _alloc_region;
Atomic<G1HeapRegion*> _alloc_region;
// It keeps track of the distinct number of regions that are used
// for allocation in the active interval of this object, i.e.,
@ -71,7 +70,7 @@ private:
// == end()). When we don't have a valid active region we make
// _alloc_region point to this. This allows us to skip checking
// whether the _alloc_region is null or not.
static G1HeapRegion* _dummy_region;
static Atomic<G1HeapRegion*> _dummy_region;
// After a region is allocated by alloc_new_region, this
// method is used to set it as the active alloc_region
@ -124,9 +123,9 @@ public:
static void setup(G1CollectedHeap* g1h, G1HeapRegion* dummy_region);
G1HeapRegion* get() const {
G1HeapRegion * hr = _alloc_region;
G1HeapRegion * hr = _alloc_region.load_acquire();
// Make sure that the dummy region does not escape this class.
return (hr == _dummy_region) ? nullptr : hr;
return (hr == _dummy_region.load_relaxed()) ? nullptr : hr;
}
uint count() { return _count; }
@ -177,7 +176,7 @@ private:
// Retained allocation region. Used to lower the waste generated
// during mutation by having two active regions if the free space
// in a region about to be retired still could fit a TLAB.
G1HeapRegion* volatile _retained_alloc_region;
Atomic<G1HeapRegion*> _retained_alloc_region;
// Decide if the region should be retained, based on the free size
// in it and the free size in the currently retained region, if any.

View File

@ -32,13 +32,13 @@
#define assert_alloc_region(p, message) \
do { \
assert((p), "[%s] %s c: %u r: " PTR_FORMAT, \
_name, (message), _count, p2i(_alloc_region) \
_name, (message), _count, p2i(_alloc_region.load_relaxed()) \
); \
} while (0)
inline void G1AllocRegion::reset_alloc_region() {
_alloc_region = _dummy_region;
_alloc_region.store_relaxed(_dummy_region.load_relaxed());
}
inline HeapWord* G1AllocRegion::par_allocate(G1HeapRegion* alloc_region, size_t word_size) {
@ -51,7 +51,7 @@ inline HeapWord* G1AllocRegion::par_allocate(G1HeapRegion* alloc_region, size_t
inline HeapWord* G1AllocRegion::attempt_allocation(size_t min_word_size,
size_t desired_word_size,
size_t* actual_word_size) {
G1HeapRegion* alloc_region = _alloc_region;
G1HeapRegion* alloc_region = _alloc_region.load_acquire();
assert_alloc_region(alloc_region != nullptr && !alloc_region->is_empty(), "not initialized properly");
HeapWord* result = alloc_region->par_allocate(min_word_size, desired_word_size, actual_word_size);
@ -97,8 +97,9 @@ inline HeapWord* G1AllocRegion::attempt_allocation_using_new_region(size_t min_w
inline HeapWord* MutatorAllocRegion::attempt_retained_allocation(size_t min_word_size,
size_t desired_word_size,
size_t* actual_word_size) {
if (_retained_alloc_region != nullptr) {
HeapWord* result = _retained_alloc_region->par_allocate(min_word_size, desired_word_size, actual_word_size);
G1HeapRegion* retained_alloc_region = _retained_alloc_region.load_acquire();
if (retained_alloc_region != nullptr) {
HeapWord* result = retained_alloc_region->par_allocate(min_word_size, desired_word_size, actual_word_size);
if (result != nullptr) {
trace("alloc retained", min_word_size, desired_word_size, *actual_word_size, result);
return result;

View File

@ -478,11 +478,6 @@ HeapWord* G1CollectedHeap::attempt_allocation_slow(uint node_index, size_t word_
log_trace(gc, alloc)("%s: Unsuccessfully scheduled collection allocating %zu words",
Thread::current()->name(), word_size);
if (is_shutting_down()) {
stall_for_vm_shutdown();
return nullptr;
}
// Has the gc overhead limit been reached in the meantime? If so, this mutator
// should receive null even when unsuccessfully scheduling a collection as well
// for global consistency.
@ -738,11 +733,6 @@ HeapWord* G1CollectedHeap::attempt_allocation_humongous(size_t word_size) {
log_trace(gc, alloc)("%s: Unsuccessfully scheduled collection allocating %zu",
Thread::current()->name(), word_size);
if (is_shutting_down()) {
stall_for_vm_shutdown();
return nullptr;
}
// Has the gc overhead limit been reached in the meantime? If so, this mutator
// should receive null even when unsuccessfully scheduling a collection as well
// for global consistency.
@ -1645,6 +1635,10 @@ jint G1CollectedHeap::initialize() {
return JNI_OK;
}
bool G1CollectedHeap::concurrent_mark_is_terminating() const {
return _cm_thread->should_terminate();
}
void G1CollectedHeap::stop() {
// Stop all concurrent threads. We do this to make sure these threads
// do not continue to execute and access resources (e.g. logging)
@ -1965,8 +1959,8 @@ bool G1CollectedHeap::try_collect_concurrently(size_t allocation_word_size,
}
// If VMOp skipped initiating concurrent marking cycle because
// we're terminating, then we're done.
if (is_shutting_down()) {
// we're shutting down, then we're done.
if (op.is_shutting_down()) {
LOG_COLLECT_CONCURRENTLY(cause, "skipped: terminating");
return false;
}
@ -2361,7 +2355,8 @@ static void print_region_type(outputStream* st, const char* type, uint count, bo
}
void G1CollectedHeap::print_heap_on(outputStream* st) const {
size_t heap_used = Heap_lock->owned_by_self() ? used() : used_unlocked();
size_t heap_used = (Thread::current_or_null_safe() != nullptr &&
Heap_lock->owned_by_self()) ? used() : used_unlocked();
st->print("%-20s", "garbage-first heap");
st->print(" total reserved %zuK, committed %zuK, used %zuK",
_hrm.reserved().byte_size()/K, capacity()/K, heap_used/K);

View File

@ -917,6 +917,9 @@ public:
// specified by the policy object.
jint initialize() override;
// Returns whether concurrent mark threads (and the VM) are about to terminate.
bool concurrent_mark_is_terminating() const;
void safepoint_synchronize_begin() override;
void safepoint_synchronize_end() override;

View File

@ -267,8 +267,6 @@ void G1CollectionSetCandidates::set_candidates_from_marking(G1HeapRegion** candi
// the same MixedGC.
uint group_limit = p->calc_min_old_cset_length(num_candidates);
uint num_added_to_group = 0;
G1CSetCandidateGroup::reset_next_group_id();
G1CSetCandidateGroup* current = nullptr;
@ -279,7 +277,7 @@ void G1CollectionSetCandidates::set_candidates_from_marking(G1HeapRegion** candi
assert(!contains(r), "must not contain region %u", r->hrm_index());
_contains_map[r->hrm_index()] = CandidateOrigin::Marking;
if (num_added_to_group == group_limit) {
if (current->length() == group_limit) {
if (group_limit != G1OldCSetGroupSize) {
group_limit = G1OldCSetGroupSize;
}
@ -287,10 +285,8 @@ void G1CollectionSetCandidates::set_candidates_from_marking(G1HeapRegion** candi
_from_marking_groups.append(current);
current = new G1CSetCandidateGroup();
num_added_to_group = 0;
}
current->add(r);
num_added_to_group++;
}
_from_marking_groups.append(current);

View File

@ -1883,7 +1883,7 @@ bool G1ConcurrentMark::concurrent_cycle_abort() {
// nothing, but this situation should be extremely rare (a full gc after shutdown
// has been signalled is already rare), and this work should be negligible compared
// to actual full gc work.
if (!cm_thread()->in_progress() && !_g1h->is_shutting_down()) {
if (!cm_thread()->in_progress() && !_g1h->concurrent_mark_is_terminating()) {
return false;
}

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