mirror of
https://github.com/openjdk/jdk.git
synced 2026-03-19 20:33:16 +00:00
Merge remote-tracking branch 'origin/master' into JDK-8366659-OM-wait-suspend-deadlock
This commit is contained in:
commit
8283d9c0c2
@ -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
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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) \
|
||||
|
||||
@ -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],
|
||||
|
||||
@ -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)
|
||||
])
|
||||
|
||||
@ -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.
|
||||
|
||||
@ -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/'` ]
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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)) \
|
||||
|
||||
@ -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, \
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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 := \
|
||||
|
||||
@ -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)));
|
||||
|
||||
@ -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) {
|
||||
|
||||
@ -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:
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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 {
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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());
|
||||
}
|
||||
|
||||
|
||||
@ -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));
|
||||
|
||||
@ -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);
|
||||
}
|
||||
|
||||
@ -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:
|
||||
|
||||
@ -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));
|
||||
}
|
||||
|
||||
|
||||
@ -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; }
|
||||
|
||||
@ -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];
|
||||
}
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@ -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();
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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,
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@ -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()
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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) {
|
||||
|
||||
@ -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
|
||||
};
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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, ...) {
|
||||
|
||||
@ -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) {
|
||||
|
||||
@ -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; }
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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;
|
||||
|
||||
|
||||
@ -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) {
|
||||
|
||||
@ -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);
|
||||
|
||||
|
||||
@ -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) {
|
||||
|
||||
@ -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:
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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) {
|
||||
|
||||
@ -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
@ -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;
|
||||
}
|
||||
|
||||
@ -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 %{
|
||||
|
||||
@ -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) {
|
||||
}
|
||||
|
||||
|
||||
@ -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) {
|
||||
}
|
||||
|
||||
|
||||
@ -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 */
|
||||
|
||||
@ -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';
|
||||
|
||||
@ -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; }
|
||||
|
||||
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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); }
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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,
|
||||
|
||||
@ -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,
|
||||
|
||||
@ -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,
|
||||
|
||||
@ -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>
|
||||
|
||||
@ -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");
|
||||
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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.");
|
||||
|
||||
@ -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,
|
||||
|
||||
@ -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,
|
||||
|
||||
@ -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,
|
||||
|
||||
@ -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))); \
|
||||
|
||||
@ -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))); \
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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 {
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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(),
|
||||
|
||||
@ -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);
|
||||
}
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
|
||||
@ -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(); }
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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) {
|
||||
|
||||
@ -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)
|
||||
|
||||
@ -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(),
|
||||
|
||||
@ -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.
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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;
|
||||
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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
Loading…
x
Reference in New Issue
Block a user