diff --git a/make/autoconf/boot-jdk.m4 b/make/autoconf/boot-jdk.m4 index 1d82f7c79b943..9c0f9018bfcc1 100644 --- a/make/autoconf/boot-jdk.m4 +++ b/make/autoconf/boot-jdk.m4 @@ -298,6 +298,28 @@ AC_DEFUN([BOOTJDK_CHECK_TOOL_IN_BOOTJDK], ]) ]) +# Setup CLASSPATH environment variable +AC_DEFUN([BOOTJDK_SETUP_CLASSPATH], +[ + AC_ARG_WITH([classpath], [AS_HELP_STRING([--with-classpath], + [Optional classpath to set as CLASSPATH to all Java invocations @<:@none@:>@])]) + + if test "x$CLASSPATH" != x; then + AC_MSG_WARN([CLASSPATH is set in the environment. This will be ignored. Use --with-classpath instead.]) + fi + + CLASSPATH= + + if test "x$with_classpath" != x && test "x$with_classpath" != xyes && + test "x$with_classpath" != xno ; then + CLASSPATH="$with_classpath" + AC_MSG_CHECKING([for classpath to use for all Java invocations]) + AC_MSG_RESULT([$CLASSPATH]) + fi + + AC_SUBST(CLASSPATH) +]) + ############################################################################### # # We need a Boot JDK to bootstrap the build. @@ -394,6 +416,8 @@ AC_DEFUN_ONCE([BOOTJDK_SETUP_BOOT_JDK], BOOTJDK_USE_LOCAL_CDS=false AC_MSG_RESULT([no, -XX:SharedArchiveFile not supported]) fi + + BOOTJDK_SETUP_CLASSPATH ]) AC_DEFUN_ONCE([BOOTJDK_SETUP_BOOT_JDK_ARGUMENTS], diff --git a/make/autoconf/flags-cflags.m4 b/make/autoconf/flags-cflags.m4 index 5eed1138f1f20..ba4cb3e9ac731 100644 --- a/make/autoconf/flags-cflags.m4 +++ b/make/autoconf/flags-cflags.m4 @@ -137,7 +137,7 @@ AC_DEFUN([FLAGS_SETUP_WARNINGS], DISABLED_WARNINGS="4800" if test "x$TOOLCHAIN_VERSION" = x2017; then # VS2017 incorrectly triggers this warning for constexpr - DISABLED_WARNINGS+=" 4307" + DISABLED_WARNINGS="$DISABLED_WARNINGS 4307" fi ;; diff --git a/make/autoconf/flags-other.m4 b/make/autoconf/flags-other.m4 index 0a0429c354bba..eaed7515bf224 100644 --- a/make/autoconf/flags-other.m4 +++ b/make/autoconf/flags-other.m4 @@ -89,11 +89,12 @@ AC_DEFUN([FLAGS_SETUP_ASFLAGS], # Fix linker warning. # Code taken from make/autoconf/flags-cflags.m4 and adapted. - JVM_BASIC_ASFLAGS+=" -DMAC_OS_X_VERSION_MIN_REQUIRED=$MACOSX_VERSION_MIN_NODOTS \ + JVM_BASIC_ASFLAGS="$JVM_BASIC_ASFLAGS \ + -DMAC_OS_X_VERSION_MIN_REQUIRED=$MACOSX_VERSION_MIN_NODOTS \ -mmacosx-version-min=$MACOSX_VERSION_MIN" if test -n "$MACOSX_VERSION_MAX"; then - JVM_BASIC_ASFLAGS+=" $OS_CFLAGS \ + JVM_BASIC_ASFLAGS="$JVM_BASIC_ASFLAGS $OS_CFLAGS \ -DMAC_OS_X_VERSION_MAX_ALLOWED=$MACOSX_VERSION_MAX_NODOTS" fi fi diff --git a/make/autoconf/help.m4 b/make/autoconf/help.m4 index 7de6398bbd6e0..924cc42560986 100644 --- a/make/autoconf/help.m4 +++ b/make/autoconf/help.m4 @@ -1,5 +1,5 @@ # -# Copyright (c) 2011, 2020, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2011, 2021, Oracle and/or its affiliates. All rights reserved. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. # # This code is free software; you can redistribute it and/or modify it @@ -42,21 +42,21 @@ AC_DEFUN([HELP_MSG_MISSING_DEPENDENCY], PKGHANDLER_COMMAND= case $PKGHANDLER in - apt-get) + *apt-get) apt_help $MISSING_DEPENDENCY ;; - yum) + *yum) yum_help $MISSING_DEPENDENCY ;; - brew) + *brew) brew_help $MISSING_DEPENDENCY ;; - port) + *port) port_help $MISSING_DEPENDENCY ;; - pkgutil) + *pkgutil) pkgutil_help $MISSING_DEPENDENCY ;; - pkgadd) + *pkgadd) pkgadd_help $MISSING_DEPENDENCY ;; - zypper) + *zypper) zypper_help $MISSING_DEPENDENCY ;; - pacman) + *pacman) pacman_help $MISSING_DEPENDENCY ;; esac @@ -274,7 +274,7 @@ AC_DEFUN_ONCE([HELP_PRINT_SUMMARY_AND_WARNINGS], printf "\n" printf "Build performance summary:\n" - printf "* Cores to use: $JOBS\n" + printf "* Build jobs: $JOBS\n" printf "* Memory limit: $MEMORY_SIZE MB\n" if test "x$CCACHE_STATUS" != "x"; then printf "* ccache status: $CCACHE_STATUS\n" diff --git a/make/autoconf/jdk-version.m4 b/make/autoconf/jdk-version.m4 index 092e7a6f490a0..60405d67bcb07 100644 --- a/make/autoconf/jdk-version.m4 +++ b/make/autoconf/jdk-version.m4 @@ -1,5 +1,5 @@ # -# Copyright (c) 2015, 2019, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2015, 2021, Oracle and/or its affiliates. All rights reserved. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. # # This code is free software; you can redistribute it and/or modify it @@ -525,7 +525,7 @@ AC_DEFUN_ONCE([JDKVER_SETUP_JDK_VERSION_NUMBERS], MACOSX_BUNDLE_BUILD_VERSION="$VERSION_BUILD" # If VERSION_OPT consists of only numbers and periods, add it. if [ [[ $VERSION_OPT =~ ^[0-9\.]+$ ]] ]; then - MACOSX_BUNDLE_BUILD_VERSION+=".$VERSION_OPT" + MACOSX_BUNDLE_BUILD_VERSION="$MACOSX_BUNDLE_BUILD_VERSION.$VERSION_OPT" fi fi AC_SUBST(MACOSX_BUNDLE_BUILD_VERSION) diff --git a/make/autoconf/libraries.m4 b/make/autoconf/libraries.m4 index a65d91ee974bf..8e4012910d890 100644 --- a/make/autoconf/libraries.m4 +++ b/make/autoconf/libraries.m4 @@ -43,11 +43,9 @@ AC_DEFUN_ONCE([LIB_DETERMINE_DEPENDENCIES], if test "x$OPENJDK_TARGET_OS" = xwindows || test "x$OPENJDK_TARGET_OS" = xmacosx; then # No X11 support on windows or macosx NEEDS_LIB_X11=false - elif test "x$ENABLE_HEADLESS_ONLY" = xtrue; then - # No X11 support needed when building headless only - NEEDS_LIB_X11=false else - # All other instances need X11 + # All other instances need X11, even if building headless only, libawt still + # needs X11 headers. NEEDS_LIB_X11=true fi diff --git a/make/autoconf/spec.gmk.in b/make/autoconf/spec.gmk.in index 29445c8c24f4e..bb7d63346f442 100644 --- a/make/autoconf/spec.gmk.in +++ b/make/autoconf/spec.gmk.in @@ -54,6 +54,9 @@ MAKE := @MAKE@ # Make sure all shell commands are executed with the C locale export LC_ALL := C +# Make sure we override any local CLASSPATH variable +export CLASSPATH := @CLASSPATH@ + # The default make arguments MAKE_ARGS = $(MAKE_LOG_FLAGS) -r -R -I $(TOPDIR)/make/common SPEC=$(SPEC) \ MAKE_LOG_FLAGS="$(MAKE_LOG_FLAGS)" $(MAKE_LOG_VARS) diff --git a/make/conf/javadoc.conf b/make/conf/javadoc.conf index 6c92e40329afa..f13d882b96185 100644 --- a/make/conf/javadoc.conf +++ b/make/conf/javadoc.conf @@ -1,4 +1,4 @@ -# Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2020, 2021, Oracle and/or its affiliates. All rights reserved. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. # # This code is free software; you can redistribute it and/or modify it @@ -23,9 +23,9 @@ # # URLs -JAVADOC_BASE_URL=https://docs.oracle.com/pls/topic/lookup?ctx=javase$(VERSION_NUMBER)&id=homepage +JAVADOC_BASE_URL=https://docs.oracle.com/pls/topic/lookup?ctx=javase$(VERSION_FEATURE)&id=homepage BUG_SUBMIT_URL=https://bugreport.java.com/bugreport/ COPYRIGHT_URL=legal/copyright.html -LICENSE_URL=https://www.oracle.com/java/javase/terms/license/java$(VERSION_NUMBER)speclicense.html +LICENSE_URL=https://www.oracle.com/java/javase/terms/license/java$(VERSION_FEATURE)speclicense.html REDISTRIBUTION_URL=https://www.oracle.com/technetwork/java/redist-137594.html OTHER_JDK_VERSIONS_URL=https://docs.oracle.com/en/java/javase/index.html diff --git a/make/data/charsetmapping/charsets b/make/data/charsetmapping/charsets index a06e4038d697f..5932645bfbdc0 100644 --- a/make/data/charsetmapping/charsets +++ b/make/data/charsetmapping/charsets @@ -1,5 +1,5 @@ # -# Copyright (c) 2000, 2020, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2000, 2021, Oracle and/or its affiliates. All rights reserved. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. # # This code is free software; you can redistribute it and/or modify it @@ -49,7 +49,6 @@ charset US-ASCII US_ASCII alias IBM367 alias cp367 alias csASCII - alias default # Other aliases alias 646 # Solaris POSIX locale alias iso_646.irv:1983 diff --git a/make/devkit/createMacosxDevkit.sh b/make/devkit/createMacosxDevkit.sh index cd1058233666b..84fbb3a8098cc 100644 --- a/make/devkit/createMacosxDevkit.sh +++ b/make/devkit/createMacosxDevkit.sh @@ -1,6 +1,6 @@ #!/bin/bash # -# Copyright (c) 2015, 2020, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2015, 2021, Oracle and/or its affiliates. All rights reserved. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. # # This code is free software; you can redistribute it and/or modify it @@ -102,7 +102,7 @@ EXCLUDE_DIRS=" \ " for ex in $EXCLUDE_DIRS; do - EXCLUDE_ARGS+="--exclude=$ex " + EXCLUDE_ARGS="$EXCLUDE_ARGS --exclude=$ex" done echo "Copying Xcode.app..." diff --git a/src/hotspot/cpu/aarch64/globals_aarch64.hpp b/src/hotspot/cpu/aarch64/globals_aarch64.hpp index a3159db967a7b..aa6c3ad95f534 100644 --- a/src/hotspot/cpu/aarch64/globals_aarch64.hpp +++ b/src/hotspot/cpu/aarch64/globals_aarch64.hpp @@ -39,7 +39,6 @@ define_pd_global(bool, UncommonNullCast, true); // Uncommon-trap NULLs define_pd_global(uintx, CodeCacheSegmentSize, 64 COMPILER1_AND_COMPILER2_PRESENT(+64)); // Tiered compilation has large code-entry alignment. define_pd_global(intx, CodeEntryAlignment, 64); define_pd_global(intx, OptoLoopAlignment, 16); -define_pd_global(intx, InlineFrequencyCount, 100); #define DEFAULT_STACK_YELLOW_PAGES (2) #define DEFAULT_STACK_RED_PAGES (1) diff --git a/src/hotspot/cpu/aarch64/pauth_aarch64.hpp b/src/hotspot/cpu/aarch64/pauth_aarch64.hpp index 6109964458fb8..e12a671daf1e2 100644 --- a/src/hotspot/cpu/aarch64/pauth_aarch64.hpp +++ b/src/hotspot/cpu/aarch64/pauth_aarch64.hpp @@ -22,8 +22,8 @@ * */ -#ifndef CPU_AARCH64_PAUTH_AARCH64_INLINE_HPP -#define CPU_AARCH64_PAUTH_AARCH64_INLINE_HPP +#ifndef CPU_AARCH64_PAUTH_AARCH64_HPP +#define CPU_AARCH64_PAUTH_AARCH64_HPP #include OS_CPU_HEADER_INLINE(pauth) @@ -32,4 +32,4 @@ inline bool pauth_ptr_is_raw(address ptr) { return ptr == pauth_strip_pointer(ptr); } -#endif // CPU_AARCH64_PAUTH_AARCH64_INLINE_HPP +#endif // CPU_AARCH64_PAUTH_AARCH64_HPP diff --git a/src/hotspot/cpu/arm/globals_arm.hpp b/src/hotspot/cpu/arm/globals_arm.hpp index bd7ef342944d5..9e135d493424d 100644 --- a/src/hotspot/cpu/arm/globals_arm.hpp +++ b/src/hotspot/cpu/arm/globals_arm.hpp @@ -53,7 +53,6 @@ define_pd_global(intx, StackRedPages, DEFAULT_STACK_RED_PAGES); define_pd_global(intx, StackShadowPages, DEFAULT_STACK_SHADOW_PAGES); define_pd_global(intx, StackReservedPages, DEFAULT_STACK_RESERVED_PAGES); -define_pd_global(intx, InlineFrequencyCount, 50); #if defined(COMPILER1) || defined(COMPILER2) define_pd_global(intx, InlineSmallCode, 1500); #endif diff --git a/src/hotspot/cpu/ppc/frame_ppc.cpp b/src/hotspot/cpu/ppc/frame_ppc.cpp index 36585185812e8..e59cc9e51288b 100644 --- a/src/hotspot/cpu/ppc/frame_ppc.cpp +++ b/src/hotspot/cpu/ppc/frame_ppc.cpp @@ -52,7 +52,6 @@ void RegisterMap::check_location_valid() { #endif // ASSERT bool frame::safe_for_sender(JavaThread *thread) { - bool safe = false; address sp = (address)_sp; address fp = (address)_fp; address unextended_sp = (address)_unextended_sp; @@ -70,28 +69,23 @@ bool frame::safe_for_sender(JavaThread *thread) { // An fp must be within the stack and above (but not equal) sp. bool fp_safe = thread->is_in_stack_range_excl(fp, sp); - // An interpreter fp must be within the stack and above (but not equal) sp. - // Moreover, it must be at least the size of the ijava_state structure. + // An interpreter fp must be fp_safe. + // Moreover, it must be at a distance at least the size of the ijava_state structure. bool fp_interp_safe = fp_safe && ((fp - sp) >= ijava_state_size); // We know sp/unextended_sp are safe, only fp is questionable here // If the current frame is known to the code cache then we can attempt to - // to construct the sender and do some validation of it. This goes a long way + // construct the sender and do some validation of it. This goes a long way // toward eliminating issues when we get in frame construction code if (_cb != NULL ){ - // Entry frame checks - if (is_entry_frame()) { - // An entry frame must have a valid fp. - return fp_safe && is_entry_frame_valid(thread); - } - // Now check if the frame is complete and the test is - // reliable. Unfortunately we can only check frame completeness for - // runtime stubs and nmethods. Other generic buffer blobs are more - // problematic so we just assume they are OK. Adapter blobs never have a - // complete frame and are never OK + // First check if the frame is complete and the test is reliable. + // Unfortunately we can only check frame completeness for runtime stubs + // and nmethods. Other generic buffer blobs are more problematic + // so we just assume they are OK. + // Adapter blobs never have a complete frame and are never OK if (!_cb->is_frame_complete_at(_pc)) { if (_cb->is_compiled() || _cb->is_adapter_blob() || _cb->is_runtime_stub()) { return false; @@ -103,10 +97,23 @@ bool frame::safe_for_sender(JavaThread *thread) { return false; } + // Entry frame checks + if (is_entry_frame()) { + // An entry frame must have a valid fp. + return fp_safe && is_entry_frame_valid(thread); + } + if (is_interpreted_frame() && !fp_interp_safe) { return false; } + // At this point, there still is a chance that fp_safe is false. + // In particular, (fp == NULL) might be true. So let's check and + // bail out before we actually dereference from fp. + if (!fp_safe) { + return false; + } + abi_minframe* sender_abi = (abi_minframe*) fp; intptr_t* sender_sp = (intptr_t*) fp; address sender_pc = (address) sender_abi->lr;; diff --git a/src/hotspot/cpu/ppc/globals_ppc.hpp b/src/hotspot/cpu/ppc/globals_ppc.hpp index 0625c34a97d88..0bab7663feb32 100644 --- a/src/hotspot/cpu/ppc/globals_ppc.hpp +++ b/src/hotspot/cpu/ppc/globals_ppc.hpp @@ -58,7 +58,6 @@ define_pd_global(intx, StackReservedPages, DEFAULT_STACK_RESERVED_PAGES); define_pd_global(uintx, CodeCacheSegmentSize, 128); define_pd_global(intx, CodeEntryAlignment, 128); define_pd_global(intx, OptoLoopAlignment, 16); -define_pd_global(intx, InlineFrequencyCount, 100); define_pd_global(intx, InlineSmallCode, 1500); // Flags for template interpreter. diff --git a/src/hotspot/cpu/s390/frame_s390.cpp b/src/hotspot/cpu/s390/frame_s390.cpp index 2486c6c636083..dd322c5c4236d 100644 --- a/src/hotspot/cpu/s390/frame_s390.cpp +++ b/src/hotspot/cpu/s390/frame_s390.cpp @@ -55,7 +55,6 @@ void RegisterMap::check_location_valid() { // Profiling/safepoint support bool frame::safe_for_sender(JavaThread *thread) { - bool safe = false; address sp = (address)_sp; address fp = (address)_fp; address unextended_sp = (address)_unextended_sp; @@ -73,28 +72,23 @@ bool frame::safe_for_sender(JavaThread *thread) { // An fp must be within the stack and above (but not equal) sp. bool fp_safe = thread->is_in_stack_range_excl(fp, sp); - // An interpreter fp must be within the stack and above (but not equal) sp. - // Moreover, it must be at least the size of the z_ijava_state structure. + // An interpreter fp must be fp_safe. + // Moreover, it must be at a distance at least the size of the z_ijava_state structure. bool fp_interp_safe = fp_safe && ((fp - sp) >= z_ijava_state_size); // We know sp/unextended_sp are safe, only fp is questionable here // If the current frame is known to the code cache then we can attempt to - // to construct the sender and do some validation of it. This goes a long way + // construct the sender and do some validation of it. This goes a long way // toward eliminating issues when we get in frame construction code if (_cb != NULL ) { - // Entry frame checks - if (is_entry_frame()) { - // An entry frame must have a valid fp. - return fp_safe && is_entry_frame_valid(thread); - } - // Now check if the frame is complete and the test is - // reliable. Unfortunately we can only check frame completeness for - // runtime stubs. Other generic buffer blobs are more - // problematic so we just assume they are OK. Adapter blobs never have a - // complete frame and are never OK. nmethods should be OK on s390. + // First check if the frame is complete and the test is reliable. + // Unfortunately we can only check frame completeness for runtime stubs. + // Other generic buffer blobs are more problematic so we just assume they are OK. + // Adapter blobs never have a complete frame and are never OK. + // nmethods should be OK on s390. if (!_cb->is_frame_complete_at(_pc)) { if (_cb->is_adapter_blob() || _cb->is_runtime_stub()) { return false; @@ -106,13 +100,26 @@ bool frame::safe_for_sender(JavaThread *thread) { return false; } + // Entry frame checks + if (is_entry_frame()) { + // An entry frame must have a valid fp. + return fp_safe && is_entry_frame_valid(thread); + } + if (is_interpreted_frame() && !fp_interp_safe) { return false; } + // At this point, there still is a chance that fp_safe is false. + // In particular, (fp == NULL) might be true. So let's check and + // bail out before we actually dereference from fp. + if (!fp_safe) { + return false; + } + z_abi_160* sender_abi = (z_abi_160*) fp; intptr_t* sender_sp = (intptr_t*) sender_abi->callers_sp; - address sender_pc = (address) sender_abi->return_pc; + address sender_pc = (address) sender_abi->return_pc; // We must always be able to find a recognizable pc. CodeBlob* sender_blob = CodeCache::find_blob_unsafe(sender_pc); diff --git a/src/hotspot/cpu/s390/globals_s390.hpp b/src/hotspot/cpu/s390/globals_s390.hpp index 80e7baca71d53..8e8dabf484038 100644 --- a/src/hotspot/cpu/s390/globals_s390.hpp +++ b/src/hotspot/cpu/s390/globals_s390.hpp @@ -43,7 +43,6 @@ define_pd_global(uintx, CodeCacheSegmentSize, 256); // code size significantly by padding nops between IVC and second UEP. define_pd_global(intx, CodeEntryAlignment, 64); define_pd_global(intx, OptoLoopAlignment, 2); -define_pd_global(intx, InlineFrequencyCount, 100); define_pd_global(intx, InlineSmallCode, 2000); #define DEFAULT_STACK_YELLOW_PAGES (2) diff --git a/src/hotspot/cpu/x86/globals_x86.hpp b/src/hotspot/cpu/x86/globals_x86.hpp index be15b94f92a95..f17f62a915d5e 100644 --- a/src/hotspot/cpu/x86/globals_x86.hpp +++ b/src/hotspot/cpu/x86/globals_x86.hpp @@ -49,7 +49,6 @@ define_pd_global(intx, CodeEntryAlignment, 32); define_pd_global(intx, CodeEntryAlignment, 16); #endif // COMPILER2_OR_JVMCI define_pd_global(intx, OptoLoopAlignment, 16); -define_pd_global(intx, InlineFrequencyCount, 100); define_pd_global(intx, InlineSmallCode, 1000); #define DEFAULT_STACK_YELLOW_PAGES (NOT_WINDOWS(2) WINDOWS_ONLY(3)) diff --git a/src/hotspot/cpu/x86/macroAssembler_x86.hpp b/src/hotspot/cpu/x86/macroAssembler_x86.hpp index 6db55cafd5980..4ecbe6add71e3 100644 --- a/src/hotspot/cpu/x86/macroAssembler_x86.hpp +++ b/src/hotspot/cpu/x86/macroAssembler_x86.hpp @@ -945,12 +945,19 @@ class MacroAssembler: public Assembler { void roundDec(XMMRegister key, int rnum); void lastroundDec(XMMRegister key, int rnum); void ev_load_key(XMMRegister xmmdst, Register key, int offset, XMMRegister xmm_shuf_mask); - + void gfmul_avx512(XMMRegister ghash, XMMRegister hkey); + void generateHtbl_48_block_zmm(Register htbl); + void ghash16_encrypt16_parallel(Register key, Register subkeyHtbl, XMMRegister ctr_blockx, + XMMRegister aad_hashx, Register in, Register out, Register data, Register pos, bool reduction, + XMMRegister addmask, bool no_ghash_input, Register rounds, Register ghash_pos, + bool final_reduction, int index, XMMRegister counter_inc_mask); public: void aesecb_encrypt(Register source_addr, Register dest_addr, Register key, Register len); void aesecb_decrypt(Register source_addr, Register dest_addr, Register key, Register len); void aesctr_encrypt(Register src_addr, Register dest_addr, Register key, Register counter, Register len_reg, Register used, Register used_addr, Register saved_encCounter_start); + void aesgcm_encrypt(Register in, Register len, Register ct, Register out, Register key, + Register state, Register subkeyHtbl, Register counter); #endif diff --git a/src/hotspot/cpu/x86/macroAssembler_x86_aes.cpp b/src/hotspot/cpu/x86/macroAssembler_x86_aes.cpp index 778dd1a1b7e39..caa27290727b0 100644 --- a/src/hotspot/cpu/x86/macroAssembler_x86_aes.cpp +++ b/src/hotspot/cpu/x86/macroAssembler_x86_aes.cpp @@ -1267,4 +1267,627 @@ void MacroAssembler::aesctr_encrypt(Register src_addr, Register dest_addr, Regis bind(EXIT); } -#endif // _LP64 +void MacroAssembler::gfmul_avx512(XMMRegister GH, XMMRegister HK) { + const XMMRegister TMP1 = xmm0; + const XMMRegister TMP2 = xmm1; + const XMMRegister TMP3 = xmm2; + + evpclmulqdq(TMP1, GH, HK, 0x11, Assembler::AVX_512bit); + evpclmulqdq(TMP2, GH, HK, 0x00, Assembler::AVX_512bit); + evpclmulqdq(TMP3, GH, HK, 0x01, Assembler::AVX_512bit); + evpclmulqdq(GH, GH, HK, 0x10, Assembler::AVX_512bit); + evpxorq(GH, GH, TMP3, Assembler::AVX_512bit); + vpsrldq(TMP3, GH, 8, Assembler::AVX_512bit); + vpslldq(GH, GH, 8, Assembler::AVX_512bit); + evpxorq(TMP1, TMP1, TMP3, Assembler::AVX_512bit); + evpxorq(GH, GH, TMP2, Assembler::AVX_512bit); + + evmovdquq(TMP3, ExternalAddress(StubRoutines::x86::ghash_polynomial512_addr()), Assembler::AVX_512bit, r15); + evpclmulqdq(TMP2, TMP3, GH, 0x01, Assembler::AVX_512bit); + vpslldq(TMP2, TMP2, 8, Assembler::AVX_512bit); + evpxorq(GH, GH, TMP2, Assembler::AVX_512bit); + evpclmulqdq(TMP2, TMP3, GH, 0x00, Assembler::AVX_512bit); + vpsrldq(TMP2, TMP2, 4, Assembler::AVX_512bit); + evpclmulqdq(GH, TMP3, GH, 0x10, Assembler::AVX_512bit); + vpslldq(GH, GH, 4, Assembler::AVX_512bit); + vpternlogq(GH, 0x96, TMP1, TMP2, Assembler::AVX_512bit); +} + +void MacroAssembler::generateHtbl_48_block_zmm(Register htbl) { + const XMMRegister HK = xmm6; + const XMMRegister ZT5 = xmm4; + const XMMRegister ZT7 = xmm7; + const XMMRegister ZT8 = xmm8; + + Label GFMUL_AVX512; + + movdqu(HK, Address(htbl, 0)); + movdqu(xmm10, ExternalAddress(StubRoutines::x86::ghash_long_swap_mask_addr())); + vpshufb(HK, HK, xmm10, Assembler::AVX_128bit); + + movdqu(xmm11, ExternalAddress(StubRoutines::x86::ghash_polynomial512_addr() + 64)); // Poly + movdqu(xmm12, ExternalAddress(StubRoutines::x86::ghash_polynomial512_addr() + 80)); // Twoone + // Compute H ^ 2 from the input subkeyH + movdqu(xmm2, xmm6); + vpsllq(xmm6, xmm6, 1, Assembler::AVX_128bit); + vpsrlq(xmm2, xmm2, 63, Assembler::AVX_128bit); + movdqu(xmm1, xmm2); + vpslldq(xmm2, xmm2, 8, Assembler::AVX_128bit); + vpsrldq(xmm1, xmm1, 8, Assembler::AVX_128bit); + vpor(xmm6, xmm6, xmm2, Assembler::AVX_128bit); + + vpshufd(xmm2, xmm1, 0x24, Assembler::AVX_128bit); + vpcmpeqd(xmm2, xmm2, xmm12, AVX_128bit); + vpand(xmm2, xmm2, xmm11, Assembler::AVX_128bit); + vpxor(xmm6, xmm6, xmm2, Assembler::AVX_128bit); + movdqu(Address(htbl, 16 * 56), xmm6); // H ^ 2 + // Compute the remaining three powers of H using XMM registers and all following powers using ZMM + movdqu(ZT5, HK); + vinserti32x4(ZT7, ZT7, HK, 3); + + gfmul_avx512(ZT5, HK); + movdqu(Address(htbl, 16 * 55), ZT5); // H ^ 2 * 2 + vinserti32x4(ZT7, ZT7, ZT5, 2); + + gfmul_avx512(ZT5, HK); + movdqu(Address(htbl, 16 * 54), ZT5); // H ^ 2 * 3 + vinserti32x4(ZT7, ZT7, ZT5, 1); + + gfmul_avx512(ZT5, HK); + movdqu(Address(htbl, 16 * 53), ZT5); // H ^ 2 * 4 + vinserti32x4(ZT7, ZT7, ZT5, 0); + + evshufi64x2(ZT5, ZT5, ZT5, 0x00, Assembler::AVX_512bit); + evmovdquq(ZT8, ZT7, Assembler::AVX_512bit); + gfmul_avx512(ZT7, ZT5); + evmovdquq(Address(htbl, 16 * 49), ZT7, Assembler::AVX_512bit); + evshufi64x2(ZT5, ZT7, ZT7, 0x00, Assembler::AVX_512bit); + gfmul_avx512(ZT8, ZT5); + evmovdquq(Address(htbl, 16 * 45), ZT8, Assembler::AVX_512bit); + gfmul_avx512(ZT7, ZT5); + evmovdquq(Address(htbl, 16 * 41), ZT7, Assembler::AVX_512bit); + gfmul_avx512(ZT8, ZT5); + evmovdquq(Address(htbl, 16 * 37), ZT8, Assembler::AVX_512bit); + gfmul_avx512(ZT7, ZT5); + evmovdquq(Address(htbl, 16 * 33), ZT7, Assembler::AVX_512bit); + gfmul_avx512(ZT8, ZT5); + evmovdquq(Address(htbl, 16 * 29), ZT8, Assembler::AVX_512bit); + gfmul_avx512(ZT7, ZT5); + evmovdquq(Address(htbl, 16 * 25), ZT7, Assembler::AVX_512bit); + gfmul_avx512(ZT8, ZT5); + evmovdquq(Address(htbl, 16 * 21), ZT8, Assembler::AVX_512bit); + gfmul_avx512(ZT7, ZT5); + evmovdquq(Address(htbl, 16 * 17), ZT7, Assembler::AVX_512bit); + gfmul_avx512(ZT8, ZT5); + evmovdquq(Address(htbl, 16 * 13), ZT8, Assembler::AVX_512bit); + gfmul_avx512(ZT7, ZT5); + evmovdquq(Address(htbl, 16 * 9), ZT7, Assembler::AVX_512bit); + ret(0); +} + +#define vclmul_reduce(out, poly, hi128, lo128, tmp0, tmp1) \ +evpclmulqdq(tmp0, poly, lo128, 0x01, Assembler::AVX_512bit); \ +vpslldq(tmp0, tmp0, 8, Assembler::AVX_512bit); \ +evpxorq(tmp0, lo128, tmp0, Assembler::AVX_512bit); \ +evpclmulqdq(tmp1, poly, tmp0, 0x00, Assembler::AVX_512bit); \ +vpsrldq(tmp1, tmp1, 4, Assembler::AVX_512bit); \ +evpclmulqdq(out, poly, tmp0, 0x10, Assembler::AVX_512bit); \ +vpslldq(out, out, 4, Assembler::AVX_512bit); \ +vpternlogq(out, 0x96, tmp1, hi128, Assembler::AVX_512bit); \ + +#define vhpxori4x128(reg, tmp) \ +vextracti64x4(tmp, reg, 1); \ +evpxorq(reg, reg, tmp, Assembler::AVX_256bit); \ +vextracti32x4(tmp, reg, 1); \ +evpxorq(reg, reg, tmp, Assembler::AVX_128bit); \ + +#define roundEncode(key, dst1, dst2, dst3, dst4) \ +vaesenc(dst1, dst1, key, Assembler::AVX_512bit); \ +vaesenc(dst2, dst2, key, Assembler::AVX_512bit); \ +vaesenc(dst3, dst3, key, Assembler::AVX_512bit); \ +vaesenc(dst4, dst4, key, Assembler::AVX_512bit); \ + +#define lastroundEncode(key, dst1, dst2, dst3, dst4) \ +vaesenclast(dst1, dst1, key, Assembler::AVX_512bit); \ +vaesenclast(dst2, dst2, key, Assembler::AVX_512bit); \ +vaesenclast(dst3, dst3, key, Assembler::AVX_512bit); \ +vaesenclast(dst4, dst4, key, Assembler::AVX_512bit); \ + +#define storeData(dst, position, src1, src2, src3, src4) \ +evmovdquq(Address(dst, position, Address::times_1, 0 * 64), src1, Assembler::AVX_512bit); \ +evmovdquq(Address(dst, position, Address::times_1, 1 * 64), src2, Assembler::AVX_512bit); \ +evmovdquq(Address(dst, position, Address::times_1, 2 * 64), src3, Assembler::AVX_512bit); \ +evmovdquq(Address(dst, position, Address::times_1, 3 * 64), src4, Assembler::AVX_512bit); \ + +#define loadData(src, position, dst1, dst2, dst3, dst4) \ +evmovdquq(dst1, Address(src, position, Address::times_1, 0 * 64), Assembler::AVX_512bit); \ +evmovdquq(dst2, Address(src, position, Address::times_1, 1 * 64), Assembler::AVX_512bit); \ +evmovdquq(dst3, Address(src, position, Address::times_1, 2 * 64), Assembler::AVX_512bit); \ +evmovdquq(dst4, Address(src, position, Address::times_1, 3 * 64), Assembler::AVX_512bit); \ + +#define carrylessMultiply(dst00, dst01, dst10, dst11, ghdata, hkey) \ +evpclmulqdq(dst00, ghdata, hkey, 0x00, Assembler::AVX_512bit); \ +evpclmulqdq(dst01, ghdata, hkey, 0x01, Assembler::AVX_512bit); \ +evpclmulqdq(dst10, ghdata, hkey, 0x10, Assembler::AVX_512bit); \ +evpclmulqdq(dst11, ghdata, hkey, 0x11, Assembler::AVX_512bit); \ + +#define shuffleExorRnd1Key(dst0, dst1, dst2, dst3, shufmask, rndkey) \ +vpshufb(dst0, dst0, shufmask, Assembler::AVX_512bit); \ +evpxorq(dst0, dst0, rndkey, Assembler::AVX_512bit); \ +vpshufb(dst1, dst1, shufmask, Assembler::AVX_512bit); \ +evpxorq(dst1, dst1, rndkey, Assembler::AVX_512bit); \ +vpshufb(dst2, dst2, shufmask, Assembler::AVX_512bit); \ +evpxorq(dst2, dst2, rndkey, Assembler::AVX_512bit); \ +vpshufb(dst3, dst3, shufmask, Assembler::AVX_512bit); \ +evpxorq(dst3, dst3, rndkey, Assembler::AVX_512bit); \ + +#define xorBeforeStore(dst0, dst1, dst2, dst3, src0, src1, src2, src3) \ +evpxorq(dst0, dst0, src0, Assembler::AVX_512bit); \ +evpxorq(dst1, dst1, src1, Assembler::AVX_512bit); \ +evpxorq(dst2, dst2, src2, Assembler::AVX_512bit); \ +evpxorq(dst3, dst3, src3, Assembler::AVX_512bit); \ + +#define xorGHASH(dst0, dst1, dst2, dst3, src02, src03, src12, src13, src22, src23, src32, src33) \ +vpternlogq(dst0, 0x96, src02, src03, Assembler::AVX_512bit); \ +vpternlogq(dst1, 0x96, src12, src13, Assembler::AVX_512bit); \ +vpternlogq(dst2, 0x96, src22, src23, Assembler::AVX_512bit); \ +vpternlogq(dst3, 0x96, src32, src33, Assembler::AVX_512bit); \ + +void MacroAssembler::ghash16_encrypt16_parallel(Register key, Register subkeyHtbl, XMMRegister ctr_blockx, XMMRegister aad_hashx, + Register in, Register out, Register data, Register pos, bool first_time_reduction, XMMRegister addmask, bool ghash_input, Register rounds, + Register ghash_pos, bool final_reduction, int i, XMMRegister counter_inc_mask) { + + Label AES_192, AES_256, LAST_AES_RND; + const XMMRegister ZTMP0 = xmm0; + const XMMRegister ZTMP1 = xmm3; + const XMMRegister ZTMP2 = xmm4; + const XMMRegister ZTMP3 = xmm5; + const XMMRegister ZTMP5 = xmm7; + const XMMRegister ZTMP6 = xmm10; + const XMMRegister ZTMP7 = xmm11; + const XMMRegister ZTMP8 = xmm12; + const XMMRegister ZTMP9 = xmm13; + const XMMRegister ZTMP10 = xmm15; + const XMMRegister ZTMP11 = xmm16; + const XMMRegister ZTMP12 = xmm17; + + const XMMRegister ZTMP13 = xmm19; + const XMMRegister ZTMP14 = xmm20; + const XMMRegister ZTMP15 = xmm21; + const XMMRegister ZTMP16 = xmm30; + const XMMRegister ZTMP17 = xmm31; + const XMMRegister ZTMP18 = xmm1; + const XMMRegister ZTMP19 = xmm2; + const XMMRegister ZTMP20 = xmm8; + const XMMRegister ZTMP21 = xmm22; + const XMMRegister ZTMP22 = xmm23; + + // Pre increment counters + vpaddd(ZTMP0, ctr_blockx, counter_inc_mask, Assembler::AVX_512bit); + vpaddd(ZTMP1, ZTMP0, counter_inc_mask, Assembler::AVX_512bit); + vpaddd(ZTMP2, ZTMP1, counter_inc_mask, Assembler::AVX_512bit); + vpaddd(ZTMP3, ZTMP2, counter_inc_mask, Assembler::AVX_512bit); + // Save counter value + evmovdquq(ctr_blockx, ZTMP3, Assembler::AVX_512bit); + + // Reuse ZTMP17 / ZTMP18 for loading AES Keys + // Pre-load AES round keys + ev_load_key(ZTMP17, key, 0, xmm29); + ev_load_key(ZTMP18, key, 1 * 16, xmm29); + + // ZTMP19 & ZTMP20 used for loading hash key + // Pre-load hash key + evmovdquq(ZTMP19, Address(subkeyHtbl, i * 64 + 144), Assembler::AVX_512bit); + evmovdquq(ZTMP20, Address(subkeyHtbl, ++i * 64 + 144), Assembler::AVX_512bit); + // Load data for computing ghash + evmovdquq(ZTMP21, Address(data, ghash_pos, Address::times_1, 0 * 64), Assembler::AVX_512bit); + vpshufb(ZTMP21, ZTMP21, xmm24, Assembler::AVX_512bit); + + // Xor cipher block 0 with input ghash, if available + if (ghash_input) { + evpxorq(ZTMP21, ZTMP21, aad_hashx, Assembler::AVX_512bit); + } + // Load data for computing ghash + evmovdquq(ZTMP22, Address(data, ghash_pos, Address::times_1, 1 * 64), Assembler::AVX_512bit); + vpshufb(ZTMP22, ZTMP22, xmm24, Assembler::AVX_512bit); + + // stitch AES rounds with GHASH + // AES round 0, xmm24 has shuffle mask + shuffleExorRnd1Key(ZTMP0, ZTMP1, ZTMP2, ZTMP3, xmm24, ZTMP17); + // Reuse ZTMP17 / ZTMP18 for loading remaining AES Keys + ev_load_key(ZTMP17, key, 2 * 16, xmm29); + // GHASH 4 blocks + carrylessMultiply(ZTMP6, ZTMP7, ZTMP8, ZTMP5, ZTMP21, ZTMP19); + // Load the next hkey and Ghash data + evmovdquq(ZTMP19, Address(subkeyHtbl, ++i * 64 + 144), Assembler::AVX_512bit); + evmovdquq(ZTMP21, Address(data, ghash_pos, Address::times_1, 2 * 64), Assembler::AVX_512bit); + vpshufb(ZTMP21, ZTMP21, xmm24, Assembler::AVX_512bit); + + // AES round 1 + roundEncode(ZTMP18, ZTMP0, ZTMP1, ZTMP2, ZTMP3); + ev_load_key(ZTMP18, key, 3 * 16, xmm29); + + // GHASH 4 blocks(11 to 8) + carrylessMultiply(ZTMP10, ZTMP12, ZTMP11, ZTMP9, ZTMP22, ZTMP20); + // Load the next hkey and GDATA + evmovdquq(ZTMP20, Address(subkeyHtbl, ++i * 64 + 144), Assembler::AVX_512bit); + evmovdquq(ZTMP22, Address(data, ghash_pos, Address::times_1, 3 * 64), Assembler::AVX_512bit); + vpshufb(ZTMP22, ZTMP22, xmm24, Assembler::AVX_512bit); + + // AES round 2 + roundEncode(ZTMP17, ZTMP0, ZTMP1, ZTMP2, ZTMP3); + ev_load_key(ZTMP17, key, 4 * 16, xmm29); + + // GHASH 4 blocks(7 to 4) + carrylessMultiply(ZTMP14, ZTMP16, ZTMP15, ZTMP13, ZTMP21, ZTMP19); + // AES rounds 3 + roundEncode(ZTMP18, ZTMP0, ZTMP1, ZTMP2, ZTMP3); + ev_load_key(ZTMP18, key, 5 * 16, xmm29); + + // Gather(XOR) GHASH for 12 blocks + xorGHASH(ZTMP5, ZTMP6, ZTMP8, ZTMP7, ZTMP9, ZTMP13, ZTMP10, ZTMP14, ZTMP12, ZTMP16, ZTMP11, ZTMP15); + + // AES rounds 4 + roundEncode(ZTMP17, ZTMP0, ZTMP1, ZTMP2, ZTMP3); + ev_load_key(ZTMP17, key, 6 * 16, xmm29); + + // load plain / cipher text(recycle registers) + loadData(in, pos, ZTMP13, ZTMP14, ZTMP15, ZTMP16); + + // AES rounds 5 + roundEncode(ZTMP18, ZTMP0, ZTMP1, ZTMP2, ZTMP3); + ev_load_key(ZTMP18, key, 7 * 16, xmm29); + // GHASH 4 blocks(3 to 0) + carrylessMultiply(ZTMP10, ZTMP12, ZTMP11, ZTMP9, ZTMP22, ZTMP20); + + // AES round 6 + roundEncode(ZTMP17, ZTMP0, ZTMP1, ZTMP2, ZTMP3); + ev_load_key(ZTMP17, key, 8 * 16, xmm29); + + // gather GHASH in ZTMP6(low) and ZTMP5(high) + if (first_time_reduction) { + vpternlogq(ZTMP7, 0x96, ZTMP8, ZTMP12, Assembler::AVX_512bit); + evpxorq(xmm25, ZTMP7, ZTMP11, Assembler::AVX_512bit); + evpxorq(xmm27, ZTMP5, ZTMP9, Assembler::AVX_512bit); + evpxorq(xmm26, ZTMP6, ZTMP10, Assembler::AVX_512bit); + } + else if (!first_time_reduction && !final_reduction) { + xorGHASH(ZTMP7, xmm25, xmm27, xmm26, ZTMP8, ZTMP12, ZTMP7, ZTMP11, ZTMP5, ZTMP9, ZTMP6, ZTMP10); + } + + if (final_reduction) { + // Phase one: Add mid products together + // Also load polynomial constant for reduction + vpternlogq(ZTMP7, 0x96, ZTMP8, ZTMP12, Assembler::AVX_512bit); + vpternlogq(ZTMP7, 0x96, xmm25, ZTMP11, Assembler::AVX_512bit); + vpsrldq(ZTMP11, ZTMP7, 8, Assembler::AVX_512bit); + vpslldq(ZTMP7, ZTMP7, 8, Assembler::AVX_512bit); + evmovdquq(ZTMP12, ExternalAddress(StubRoutines::x86::ghash_polynomial512_addr()), Assembler::AVX_512bit, rbx); + } + // AES round 7 + roundEncode(ZTMP18, ZTMP0, ZTMP1, ZTMP2, ZTMP3); + ev_load_key(ZTMP18, key, 9 * 16, xmm29); + if (final_reduction) { + vpternlogq(ZTMP5, 0x96, ZTMP9, ZTMP11, Assembler::AVX_512bit); + evpxorq(ZTMP5, ZTMP5, xmm27, Assembler::AVX_512bit); + vpternlogq(ZTMP6, 0x96, ZTMP10, ZTMP7, Assembler::AVX_512bit); + evpxorq(ZTMP6, ZTMP6, xmm26, Assembler::AVX_512bit); + } + // AES round 8 + roundEncode(ZTMP17, ZTMP0, ZTMP1, ZTMP2, ZTMP3); + ev_load_key(ZTMP17, key, 10 * 16, xmm29); + + // Horizontal xor of low and high 4*128 + if (final_reduction) { + vhpxori4x128(ZTMP5, ZTMP9); + vhpxori4x128(ZTMP6, ZTMP10); + } + // AES round 9 + roundEncode(ZTMP18, ZTMP0, ZTMP1, ZTMP2, ZTMP3); + // First phase of reduction + if (final_reduction) { + evpclmulqdq(ZTMP10, ZTMP12, ZTMP6, 0x01, Assembler::AVX_128bit); + vpslldq(ZTMP10, ZTMP10, 8, Assembler::AVX_128bit); + evpxorq(ZTMP10, ZTMP6, ZTMP10, Assembler::AVX_128bit); + } + cmpl(rounds, 52); + jcc(Assembler::greaterEqual, AES_192); + jmp(LAST_AES_RND); + // AES rounds upto 11 (AES192) or 13 (AES256) + bind(AES_192); + roundEncode(ZTMP17, ZTMP0, ZTMP1, ZTMP2, ZTMP3); + ev_load_key(ZTMP18, key, 11 * 16, xmm29); + roundEncode(ZTMP18, ZTMP0, ZTMP1, ZTMP2, ZTMP3); + ev_load_key(ZTMP17, key, 12 * 16, xmm29); + cmpl(rounds, 60); + jcc(Assembler::aboveEqual, AES_256); + jmp(LAST_AES_RND); + + bind(AES_256); + roundEncode(ZTMP17, ZTMP0, ZTMP1, ZTMP2, ZTMP3); + ev_load_key(ZTMP18, key, 13 * 16, xmm29); + roundEncode(ZTMP18, ZTMP0, ZTMP1, ZTMP2, ZTMP3); + ev_load_key(ZTMP17, key, 14 * 16, xmm29); + + bind(LAST_AES_RND); + // Second phase of reduction + if (final_reduction) { + evpclmulqdq(ZTMP9, ZTMP12, ZTMP10, 0x00, Assembler::AVX_128bit); + vpsrldq(ZTMP9, ZTMP9, 4, Assembler::AVX_128bit); // Shift-R 1-DW to obtain 2-DWs shift-R + evpclmulqdq(ZTMP11, ZTMP12, ZTMP10, 0x10, Assembler::AVX_128bit); + vpslldq(ZTMP11, ZTMP11, 4, Assembler::AVX_128bit); // Shift-L 1-DW for result + // ZTMP5 = ZTMP5 X ZTMP11 X ZTMP9 + vpternlogq(ZTMP5, 0x96, ZTMP11, ZTMP9, Assembler::AVX_128bit); + } + // Last AES round + lastroundEncode(ZTMP17, ZTMP0, ZTMP1, ZTMP2, ZTMP3); + // XOR against plain / cipher text + xorBeforeStore(ZTMP0, ZTMP1, ZTMP2, ZTMP3, ZTMP13, ZTMP14, ZTMP15, ZTMP16); + // store cipher / plain text + storeData(out, pos, ZTMP0, ZTMP1, ZTMP2, ZTMP3); +} + +void MacroAssembler::aesgcm_encrypt(Register in, Register len, Register ct, Register out, Register key, + Register state, Register subkeyHtbl, Register counter) { + + Label ENC_DEC_DONE, GENERATE_HTBL_48_BLKS, AES_192, AES_256, STORE_CT, GHASH_LAST_32, + AES_32_BLOCKS, GHASH_AES_PARALLEL, LOOP, ACCUMULATE, GHASH_16_AES_16; + const XMMRegister CTR_BLOCKx = xmm9; + const XMMRegister AAD_HASHx = xmm14; + const Register pos = rax; + const Register rounds = r15; + Register ghash_pos; +#ifndef _WIN64 + ghash_pos = r14; +#else + ghash_pos = r11; +#endif // !_WIN64 + const XMMRegister ZTMP0 = xmm0; + const XMMRegister ZTMP1 = xmm3; + const XMMRegister ZTMP2 = xmm4; + const XMMRegister ZTMP3 = xmm5; + const XMMRegister ZTMP4 = xmm6; + const XMMRegister ZTMP5 = xmm7; + const XMMRegister ZTMP6 = xmm10; + const XMMRegister ZTMP7 = xmm11; + const XMMRegister ZTMP8 = xmm12; + const XMMRegister ZTMP9 = xmm13; + const XMMRegister ZTMP10 = xmm15; + const XMMRegister ZTMP11 = xmm16; + const XMMRegister ZTMP12 = xmm17; + const XMMRegister ZTMP13 = xmm19; + const XMMRegister ZTMP14 = xmm20; + const XMMRegister ZTMP15 = xmm21; + const XMMRegister ZTMP16 = xmm30; + const XMMRegister COUNTER_INC_MASK = xmm18; + + movl(pos, 0); // Total length processed + // Min data size processed = 768 bytes + cmpl(len, 768); + jcc(Assembler::less, ENC_DEC_DONE); + + // Generate 48 constants for htbl + call(GENERATE_HTBL_48_BLKS, relocInfo::none); + int index = 0; // Index for choosing subkeyHtbl entry + movl(ghash_pos, 0); // Pointer for ghash read and store operations + + // Move initial counter value and STATE value into variables + movdqu(CTR_BLOCKx, Address(counter, 0)); + movdqu(AAD_HASHx, Address(state, 0)); + // Load lswap mask for ghash + movdqu(xmm24, ExternalAddress(StubRoutines::x86::ghash_long_swap_mask_addr()), rbx); + // Shuffle input state using lswap mask + vpshufb(AAD_HASHx, AAD_HASHx, xmm24, Assembler::AVX_128bit); + + // Compute #rounds for AES based on the length of the key array + movl(rounds, Address(key, arrayOopDesc::length_offset_in_bytes() - arrayOopDesc::base_offset_in_bytes(T_INT))); + + // Broadcast counter value to 512 bit register + evshufi64x2(CTR_BLOCKx, CTR_BLOCKx, CTR_BLOCKx, 0, Assembler::AVX_512bit); + // Load counter shuffle mask + evmovdquq(xmm24, ExternalAddress(StubRoutines::x86::counter_mask_addr()), Assembler::AVX_512bit, rbx); + // Shuffle counter + vpshufb(CTR_BLOCKx, CTR_BLOCKx, xmm24, Assembler::AVX_512bit); + + // Load mask for incrementing counter + evmovdquq(COUNTER_INC_MASK, ExternalAddress(StubRoutines::x86::counter_mask_addr() + 128), Assembler::AVX_512bit, rbx); + // Pre-increment counter + vpaddd(ZTMP5, CTR_BLOCKx, ExternalAddress(StubRoutines::x86::counter_mask_addr() + 64), Assembler::AVX_512bit, rbx); + vpaddd(ZTMP6, ZTMP5, COUNTER_INC_MASK, Assembler::AVX_512bit); + vpaddd(ZTMP7, ZTMP6, COUNTER_INC_MASK, Assembler::AVX_512bit); + vpaddd(ZTMP8, ZTMP7, COUNTER_INC_MASK, Assembler::AVX_512bit); + + // Begin 32 blocks of AES processing + bind(AES_32_BLOCKS); + // Save incremented counter before overwriting it with AES data + evmovdquq(CTR_BLOCKx, ZTMP8, Assembler::AVX_512bit); + + // Move 256 bytes of data + loadData(in, pos, ZTMP0, ZTMP1, ZTMP2, ZTMP3); + // Load key shuffle mask + movdqu(xmm29, ExternalAddress(StubRoutines::x86::key_shuffle_mask_addr()), rbx); + // Load 0th AES round key + ev_load_key(ZTMP4, key, 0, xmm29); + // AES-ROUND0, xmm24 has the shuffle mask + shuffleExorRnd1Key(ZTMP5, ZTMP6, ZTMP7, ZTMP8, xmm24, ZTMP4); + + for (int j = 1; j < 10; j++) { + ev_load_key(ZTMP4, key, j * 16, xmm29); + roundEncode(ZTMP4, ZTMP5, ZTMP6, ZTMP7, ZTMP8); + } + ev_load_key(ZTMP4, key, 10 * 16, xmm29); + // AES rounds upto 11 (AES192) or 13 (AES256) + cmpl(rounds, 52); + jcc(Assembler::greaterEqual, AES_192); + lastroundEncode(ZTMP4, ZTMP5, ZTMP6, ZTMP7, ZTMP8); + jmp(STORE_CT); + + bind(AES_192); + roundEncode(ZTMP4, ZTMP5, ZTMP6, ZTMP7, ZTMP8); + ev_load_key(ZTMP4, key, 11 * 16, xmm29); + roundEncode(ZTMP4, ZTMP5, ZTMP6, ZTMP7, ZTMP8); + cmpl(rounds, 60); + jcc(Assembler::aboveEqual, AES_256); + ev_load_key(ZTMP4, key, 12 * 16, xmm29); + lastroundEncode(ZTMP4, ZTMP5, ZTMP6, ZTMP7, ZTMP8); + jmp(STORE_CT); + + bind(AES_256); + ev_load_key(ZTMP4, key, 12 * 16, xmm29); + roundEncode(ZTMP4, ZTMP5, ZTMP6, ZTMP7, ZTMP8); + ev_load_key(ZTMP4, key, 13 * 16, xmm29); + roundEncode(ZTMP4, ZTMP5, ZTMP6, ZTMP7, ZTMP8); + ev_load_key(ZTMP4, key, 14 * 16, xmm29); + // Last AES round + lastroundEncode(ZTMP4, ZTMP5, ZTMP6, ZTMP7, ZTMP8); + + bind(STORE_CT); + // Xor the encrypted key with PT to obtain CT + xorBeforeStore(ZTMP5, ZTMP6, ZTMP7, ZTMP8, ZTMP0, ZTMP1, ZTMP2, ZTMP3); + storeData(out, pos, ZTMP5, ZTMP6, ZTMP7, ZTMP8); + // 16 blocks encryption completed + addl(pos, 256); + cmpl(pos, 512); + jcc(Assembler::aboveEqual, GHASH_AES_PARALLEL); + vpaddd(ZTMP5, CTR_BLOCKx, COUNTER_INC_MASK, Assembler::AVX_512bit); + vpaddd(ZTMP6, ZTMP5, COUNTER_INC_MASK, Assembler::AVX_512bit); + vpaddd(ZTMP7, ZTMP6, COUNTER_INC_MASK, Assembler::AVX_512bit); + vpaddd(ZTMP8, ZTMP7, COUNTER_INC_MASK, Assembler::AVX_512bit); + jmp(AES_32_BLOCKS); + + bind(GHASH_AES_PARALLEL); + // Ghash16_encrypt16_parallel takes place in the order with three reduction values: + // 1) First time -> cipher xor input ghash + // 2) No reduction -> accumulate multiplication values + // 3) Final reduction post 48 blocks -> new ghash value is computed for the next round + // Reduction value = first time + ghash16_encrypt16_parallel(key, subkeyHtbl, CTR_BLOCKx, AAD_HASHx, in, out, ct, pos, true, xmm24, true, rounds, ghash_pos, false, index, COUNTER_INC_MASK); + addl(pos, 256); + addl(ghash_pos, 256); + index += 4; + + // At this point we have processed 768 bytes of AES and 256 bytes of GHASH. + // If the remaining length is less than 768, process remaining 512 bytes of ghash in GHASH_LAST_32 code + subl(len, 768); + cmpl(len, 768); + jcc(Assembler::less, GHASH_LAST_32); + + // AES 16 blocks and GHASH 16 blocks in parallel + // For multiples of 48 blocks we will do ghash16_encrypt16 interleaved multiple times + // Reduction value = no reduction means that the carryless multiplication values are accumulated for further calculations + // Each call uses 4 subkeyHtbl values, so increment the index by 4. + bind(GHASH_16_AES_16); + // Reduction value = no reduction + ghash16_encrypt16_parallel(key, subkeyHtbl, CTR_BLOCKx, AAD_HASHx, in, out, ct, pos, false, xmm24, false, rounds, ghash_pos, false, index, COUNTER_INC_MASK); + addl(pos, 256); + addl(ghash_pos, 256); + index += 4; + // Reduction value = final reduction means that the accumulated values have to be reduced as we have completed 48 blocks of ghash + ghash16_encrypt16_parallel(key, subkeyHtbl, CTR_BLOCKx, AAD_HASHx, in, out, ct, pos, false, xmm24, false, rounds, ghash_pos, true, index, COUNTER_INC_MASK); + addl(pos, 256); + addl(ghash_pos, 256); + // Calculated ghash value needs to be moved to AAD_HASHX so that we can restart the ghash16-aes16 pipeline + movdqu(AAD_HASHx, ZTMP5); + index = 0; // Reset subkeyHtbl index + + // Restart the pipeline + // Reduction value = first time + ghash16_encrypt16_parallel(key, subkeyHtbl, CTR_BLOCKx, AAD_HASHx, in, out, ct, pos, true, xmm24, true, rounds, ghash_pos, false, index, COUNTER_INC_MASK); + addl(pos, 256); + addl(ghash_pos, 256); + index += 4; + + subl(len, 768); + cmpl(len, 768); + jcc(Assembler::greaterEqual, GHASH_16_AES_16); + + // GHASH last 32 blocks processed here + // GHASH products accumulated in ZMM27, ZMM25 and ZMM26 during GHASH16-AES16 operation is used + bind(GHASH_LAST_32); + // Use rbx as a pointer to the htbl; For last 32 blocks of GHASH, use key# 4-11 entry in subkeyHtbl + movl(rbx, 256); + // Load cipher blocks + evmovdquq(ZTMP13, Address(ct, ghash_pos, Address::times_1, 0 * 64), Assembler::AVX_512bit); + evmovdquq(ZTMP14, Address(ct, ghash_pos, Address::times_1, 1 * 64), Assembler::AVX_512bit); + vpshufb(ZTMP13, ZTMP13, xmm24, Assembler::AVX_512bit); + vpshufb(ZTMP14, ZTMP14, xmm24, Assembler::AVX_512bit); + // Load ghash keys + evmovdquq(ZTMP15, Address(subkeyHtbl, rbx, Address::times_1, 0 * 64 + 144), Assembler::AVX_512bit); + evmovdquq(ZTMP16, Address(subkeyHtbl, rbx, Address::times_1, 1 * 64 + 144), Assembler::AVX_512bit); + + // Ghash blocks 0 - 3 + carrylessMultiply(ZTMP2, ZTMP3, ZTMP4, ZTMP1, ZTMP13, ZTMP15); + // Ghash blocks 4 - 7 + carrylessMultiply(ZTMP6, ZTMP7, ZTMP8, ZTMP5, ZTMP14, ZTMP16); + + vpternlogq(ZTMP1, 0x96, ZTMP5, xmm27, Assembler::AVX_512bit); // ZTMP1 = ZTMP1 + ZTMP5 + zmm27 + vpternlogq(ZTMP2, 0x96, ZTMP6, xmm26, Assembler::AVX_512bit); // ZTMP2 = ZTMP2 + ZTMP6 + zmm26 + vpternlogq(ZTMP3, 0x96, ZTMP7, xmm25, Assembler::AVX_512bit); // ZTMP3 = ZTMP3 + ZTMP7 + zmm25 + evpxorq(ZTMP4, ZTMP4, ZTMP8, Assembler::AVX_512bit); // ZTMP4 = ZTMP4 + ZTMP8 + + addl(ghash_pos, 128); + addl(rbx, 128); + + // Ghash remaining blocks + bind(LOOP); + cmpl(ghash_pos, pos); + jcc(Assembler::aboveEqual, ACCUMULATE); + // Load next cipher blocks and corresponding ghash keys + evmovdquq(ZTMP13, Address(ct, ghash_pos, Address::times_1, 0 * 64), Assembler::AVX_512bit); + evmovdquq(ZTMP14, Address(ct, ghash_pos, Address::times_1, 1 * 64), Assembler::AVX_512bit); + vpshufb(ZTMP13, ZTMP13, xmm24, Assembler::AVX_512bit); + vpshufb(ZTMP14, ZTMP14, xmm24, Assembler::AVX_512bit); + evmovdquq(ZTMP15, Address(subkeyHtbl, rbx, Address::times_1, 0 * 64 + 144), Assembler::AVX_512bit); + evmovdquq(ZTMP16, Address(subkeyHtbl, rbx, Address::times_1, 1 * 64 + 144), Assembler::AVX_512bit); + + // ghash blocks 0 - 3 + carrylessMultiply(ZTMP6, ZTMP7, ZTMP8, ZTMP5, ZTMP13, ZTMP15); + + // ghash blocks 4 - 7 + carrylessMultiply(ZTMP10, ZTMP11, ZTMP12, ZTMP9, ZTMP14, ZTMP16); + + // update sums + // ZTMP1 = ZTMP1 + ZTMP5 + ZTMP9 + // ZTMP2 = ZTMP2 + ZTMP6 + ZTMP10 + // ZTMP3 = ZTMP3 + ZTMP7 xor ZTMP11 + // ZTMP4 = ZTMP4 + ZTMP8 xor ZTMP12 + xorGHASH(ZTMP1, ZTMP2, ZTMP3, ZTMP4, ZTMP5, ZTMP9, ZTMP6, ZTMP10, ZTMP7, ZTMP11, ZTMP8, ZTMP12); + addl(ghash_pos, 128); + addl(rbx, 128); + jmp(LOOP); + + // Integrate ZTMP3/ZTMP4 into ZTMP1 and ZTMP2 + bind(ACCUMULATE); + evpxorq(ZTMP3, ZTMP3, ZTMP4, Assembler::AVX_512bit); + vpsrldq(ZTMP7, ZTMP3, 8, Assembler::AVX_512bit); + vpslldq(ZTMP8, ZTMP3, 8, Assembler::AVX_512bit); + evpxorq(ZTMP1, ZTMP1, ZTMP7, Assembler::AVX_512bit); + evpxorq(ZTMP2, ZTMP2, ZTMP8, Assembler::AVX_512bit); + + // Add ZTMP1 and ZTMP2 128 - bit words horizontally + vhpxori4x128(ZTMP1, ZTMP11); + vhpxori4x128(ZTMP2, ZTMP12); + // Load reduction polynomial and compute final reduction + evmovdquq(ZTMP15, ExternalAddress(StubRoutines::x86::ghash_polynomial512_addr()), Assembler::AVX_512bit, rbx); + vclmul_reduce(AAD_HASHx, ZTMP15, ZTMP1, ZTMP2, ZTMP3, ZTMP4); + + // Pre-increment counter for next operation + vpaddd(CTR_BLOCKx, CTR_BLOCKx, xmm18, Assembler::AVX_128bit); + // Shuffle counter and save the updated value + vpshufb(CTR_BLOCKx, CTR_BLOCKx, xmm24, Assembler::AVX_512bit); + movdqu(Address(counter, 0), CTR_BLOCKx); + // Load ghash lswap mask + movdqu(xmm24, ExternalAddress(StubRoutines::x86::ghash_long_swap_mask_addr())); + // Shuffle ghash using lbswap_mask and store it + vpshufb(AAD_HASHx, AAD_HASHx, xmm24, Assembler::AVX_128bit); + movdqu(Address(state, 0), AAD_HASHx); + jmp(ENC_DEC_DONE); + + bind(GENERATE_HTBL_48_BLKS); + generateHtbl_48_block_zmm(subkeyHtbl); + + bind(ENC_DEC_DONE); + movq(rax, pos); +} + +#endif // _LP64 \ No newline at end of file diff --git a/src/hotspot/cpu/x86/stubGenerator_x86_64.cpp b/src/hotspot/cpu/x86/stubGenerator_x86_64.cpp index c0f143f2da130..acbf0228dcab4 100644 --- a/src/hotspot/cpu/x86/stubGenerator_x86_64.cpp +++ b/src/hotspot/cpu/x86/stubGenerator_x86_64.cpp @@ -4368,6 +4368,95 @@ class StubGenerator: public StubCodeGenerator { return start; } + address ghash_polynomial512_addr() { + __ align(CodeEntryAlignment); + StubCodeMark mark(this, "StubRoutines", "_ghash_poly512_addr"); + address start = __ pc(); + __ emit_data64(0x00000001C2000000, relocInfo::none); // POLY for reduction + __ emit_data64(0xC200000000000000, relocInfo::none); + __ emit_data64(0x00000001C2000000, relocInfo::none); + __ emit_data64(0xC200000000000000, relocInfo::none); + __ emit_data64(0x00000001C2000000, relocInfo::none); + __ emit_data64(0xC200000000000000, relocInfo::none); + __ emit_data64(0x00000001C2000000, relocInfo::none); + __ emit_data64(0xC200000000000000, relocInfo::none); + __ emit_data64(0x0000000000000001, relocInfo::none); // POLY + __ emit_data64(0xC200000000000000, relocInfo::none); + __ emit_data64(0x0000000000000001, relocInfo::none); // TWOONE + __ emit_data64(0x0000000100000000, relocInfo::none); + return start; +} + + // Vector AES Galois Counter Mode implementation. Parameters: + // Windows regs | Linux regs + // in = c_rarg0 (rcx) | c_rarg0 (rsi) + // len = c_rarg1 (rdx) | c_rarg1 (rdi) + // ct = c_rarg2 (r8) | c_rarg2 (rdx) + // out = c_rarg3 (r9) | c_rarg3 (rcx) + // key = r10 | c_rarg4 (r8) + // state = r13 | c_rarg5 (r9) + // subkeyHtbl = r14 | r11 + // counter = rsi | r12 + // return - number of processed bytes + address generate_galoisCounterMode_AESCrypt() { + __ align(CodeEntryAlignment); + StubCodeMark mark(this, "StubRoutines", "galoisCounterMode_AESCrypt"); + address start = __ pc(); + const Register in = c_rarg0; + const Register len = c_rarg1; + const Register ct = c_rarg2; + const Register out = c_rarg3; + // and updated with the incremented counter in the end +#ifndef _WIN64 + const Register key = c_rarg4; + const Register state = c_rarg5; + const Address subkeyH_mem(rbp, 2 * wordSize); + const Register subkeyHtbl = r11; + const Address counter_mem(rbp, 3 * wordSize); + const Register counter = r12; +#else + const Address key_mem(rbp, 6 * wordSize); + const Register key = r10; + const Address state_mem(rbp, 7 * wordSize); + const Register state = r13; + const Address subkeyH_mem(rbp, 8 * wordSize); + const Register subkeyHtbl = r14; + const Address counter_mem(rbp, 9 * wordSize); + const Register counter = rsi; +#endif + __ enter(); + // Save state before entering routine + __ push(r12); + __ push(r13); + __ push(r14); + __ push(r15); + __ push(rbx); +#ifdef _WIN64 + // on win64, fill len_reg from stack position + __ push(rsi); + __ movptr(key, key_mem); + __ movptr(state, state_mem); +#endif + __ movptr(subkeyHtbl, subkeyH_mem); + __ movptr(counter, counter_mem); + + __ aesgcm_encrypt(in, len, ct, out, key, state, subkeyHtbl, counter); + + // Restore state before leaving routine +#ifdef _WIN64 + __ pop(rsi); +#endif + __ pop(rbx); + __ pop(r15); + __ pop(r14); + __ pop(r13); + __ pop(r12); + + __ leave(); // required for proper stackwalking of RuntimeStub frame + __ ret(0); + return start; + } + // This mask is used for incrementing counter value(linc0, linc4, etc.) address counter_mask_addr() { __ align(64); @@ -7618,13 +7707,20 @@ address generate_avx_ghash_processBlocks() { StubRoutines::_cipherBlockChaining_decryptAESCrypt = generate_cipherBlockChaining_decryptVectorAESCrypt(); StubRoutines::_electronicCodeBook_encryptAESCrypt = generate_electronicCodeBook_encryptAESCrypt(); StubRoutines::_electronicCodeBook_decryptAESCrypt = generate_electronicCodeBook_decryptAESCrypt(); + StubRoutines::x86::_counter_mask_addr = counter_mask_addr(); + StubRoutines::x86::_ghash_poly512_addr = ghash_polynomial512_addr(); + StubRoutines::x86::_ghash_long_swap_mask_addr = generate_ghash_long_swap_mask(); + StubRoutines::_galoisCounterMode_AESCrypt = generate_galoisCounterMode_AESCrypt(); } else { StubRoutines::_cipherBlockChaining_decryptAESCrypt = generate_cipherBlockChaining_decryptAESCrypt_Parallel(); } } + if (UseAESCTRIntrinsics) { if (VM_Version::supports_avx512_vaes() && VM_Version::supports_avx512bw() && VM_Version::supports_avx512vl()) { - StubRoutines::x86::_counter_mask_addr = counter_mask_addr(); + if (StubRoutines::x86::_counter_mask_addr == NULL) { + StubRoutines::x86::_counter_mask_addr = counter_mask_addr(); + } StubRoutines::_counterMode_AESCrypt = generate_counterMode_VectorAESCrypt(); } else { StubRoutines::x86::_counter_shuffle_mask_addr = generate_counter_shuffle_mask(); @@ -7664,7 +7760,9 @@ address generate_avx_ghash_processBlocks() { // Generate GHASH intrinsics code if (UseGHASHIntrinsics) { - StubRoutines::x86::_ghash_long_swap_mask_addr = generate_ghash_long_swap_mask(); + if (StubRoutines::x86::_ghash_long_swap_mask_addr == NULL) { + StubRoutines::x86::_ghash_long_swap_mask_addr = generate_ghash_long_swap_mask(); + } StubRoutines::x86::_ghash_byte_swap_mask_addr = generate_ghash_byte_swap_mask(); if (VM_Version::supports_avx()) { StubRoutines::x86::_ghash_shuffmask_addr = ghash_shufflemask_addr(); diff --git a/src/hotspot/cpu/x86/stubRoutines_x86.cpp b/src/hotspot/cpu/x86/stubRoutines_x86.cpp index a306f4a063711..9a4523cd06f12 100644 --- a/src/hotspot/cpu/x86/stubRoutines_x86.cpp +++ b/src/hotspot/cpu/x86/stubRoutines_x86.cpp @@ -80,6 +80,7 @@ address StubRoutines::x86::_join_0_1_base64 = NULL; address StubRoutines::x86::_join_1_2_base64 = NULL; address StubRoutines::x86::_join_2_3_base64 = NULL; address StubRoutines::x86::_decoding_table_base64 = NULL; +address StubRoutines::x86::_ghash_poly512_addr = NULL; #endif address StubRoutines::x86::_pshuffle_byte_flip_mask_addr = NULL; diff --git a/src/hotspot/cpu/x86/stubRoutines_x86.hpp b/src/hotspot/cpu/x86/stubRoutines_x86.hpp index 3f682d7d0b22d..b93e50b6d5146 100644 --- a/src/hotspot/cpu/x86/stubRoutines_x86.hpp +++ b/src/hotspot/cpu/x86/stubRoutines_x86.hpp @@ -33,7 +33,7 @@ static bool returns_to_call_stub(address return_pc) { return return_pc == _call_ enum platform_dependent_constants { code_size1 = 20000 LP64_ONLY(+10000), // simply increase if too small (assembler will crash if too small) - code_size2 = 35300 LP64_ONLY(+25000) // simply increase if too small (assembler will crash if too small) + code_size2 = 35300 LP64_ONLY(+32000) // simply increase if too small (assembler will crash if too small) }; class x86 { @@ -198,6 +198,7 @@ class x86 { static address _join_1_2_base64; static address _join_2_3_base64; static address _decoding_table_base64; + static address _ghash_poly512_addr; #endif // byte flip mask for sha256 static address _pshuffle_byte_flip_mask_addr; @@ -254,6 +255,7 @@ class x86 { static address crc_by128_masks_avx512_addr() { return (address)_crc_by128_masks_avx512; } static address shuf_table_crc32_avx512_addr() { return (address)_shuf_table_crc32_avx512; } static address crc_table_avx512_addr() { return (address)_crc_table_avx512; } + static address ghash_polynomial512_addr() { return _ghash_poly512_addr; } #endif // _LP64 static address ghash_long_swap_mask_addr() { return _ghash_long_swap_mask_addr; } static address ghash_byte_swap_mask_addr() { return _ghash_byte_swap_mask_addr; } diff --git a/src/hotspot/cpu/zero/globals_zero.hpp b/src/hotspot/cpu/zero/globals_zero.hpp index 33f208b28f27a..aa330925c5a18 100644 --- a/src/hotspot/cpu/zero/globals_zero.hpp +++ b/src/hotspot/cpu/zero/globals_zero.hpp @@ -39,7 +39,6 @@ define_pd_global(bool, UncommonNullCast, true); define_pd_global(uintx, CodeCacheSegmentSize, 64 COMPILER1_AND_COMPILER2_PRESENT(+64)); // Tiered compilation has large code-entry alignment. define_pd_global(intx, CodeEntryAlignment, 32); define_pd_global(intx, OptoLoopAlignment, 16); -define_pd_global(intx, InlineFrequencyCount, 100); define_pd_global(intx, InlineSmallCode, 1000); // not used, but must satisfy following constraints: diff --git a/src/hotspot/os/aix/osThread_aix.cpp b/src/hotspot/os/aix/osThread_aix.cpp index 6303dc27eb8bb..bf0d53e2b4962 100644 --- a/src/hotspot/os/aix/osThread_aix.cpp +++ b/src/hotspot/os/aix/osThread_aix.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2021, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2012, 2015 SAP SE. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -46,7 +46,7 @@ void OSThread::pd_initialize() { sigemptyset(&_caller_sigmask); - _startThread_lock = new Monitor(Mutex::event, "startThread_lock", true, + _startThread_lock = new Monitor(Mutex::event, "startThread_lock", Monitor::_safepoint_check_never); assert(_startThread_lock != NULL, "check"); } diff --git a/src/hotspot/os/bsd/osThread_bsd.cpp b/src/hotspot/os/bsd/osThread_bsd.cpp index 9eba7288fbe36..d41c9a992a82a 100644 --- a/src/hotspot/os/bsd/osThread_bsd.cpp +++ b/src/hotspot/os/bsd/osThread_bsd.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2021, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -45,7 +45,7 @@ void OSThread::pd_initialize() { sigemptyset(&_caller_sigmask); - _startThread_lock = new Monitor(Mutex::event, "startThread_lock", true, + _startThread_lock = new Monitor(Mutex::event, "startThread_lock", Monitor::_safepoint_check_never); assert(_startThread_lock !=NULL, "check"); } diff --git a/src/hotspot/os/linux/osThread_linux.cpp b/src/hotspot/os/linux/osThread_linux.cpp index 6f7e074a522d6..3846c571454ec 100644 --- a/src/hotspot/os/linux/osThread_linux.cpp +++ b/src/hotspot/os/linux/osThread_linux.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2021, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -40,7 +40,7 @@ void OSThread::pd_initialize() { sigemptyset(&_caller_sigmask); - _startThread_lock = new Monitor(Mutex::event, "startThread_lock", true, + _startThread_lock = new Monitor(Mutex::event, "startThread_lock", Monitor::_safepoint_check_never); assert(_startThread_lock !=NULL, "check"); } diff --git a/src/hotspot/os/posix/os_posix.hpp b/src/hotspot/os/posix/os_posix.hpp index af2c158511b2c..a745a8f48dbe0 100644 --- a/src/hotspot/os/posix/os_posix.hpp +++ b/src/hotspot/os/posix/os_posix.hpp @@ -25,6 +25,15 @@ #ifndef OS_POSIX_OS_POSIX_HPP #define OS_POSIX_OS_POSIX_HPP +// Note: the Posix API aims to capture functionality available on all Posix +// compliant platforms, but in practice the implementations may depend on +// non-Posix functionality. For example, the use of lseek64 and ftruncate64. +// This use of non-Posix API's is made possible by compiling/linking in a mode +// that is not restricted to being fully Posix complaint, such as by declaring +// -D_GNU_SOURCE. But be aware that in doing so we may enable non-Posix +// behaviour in API's that are defined by Posix. For example, that SIGSTKSZ +// is not defined as a constant as of Glibc 2.34. + // File conventions static const char* file_separator() { return "/"; } static const char* line_separator() { return "\n"; } diff --git a/src/hotspot/os_cpu/bsd_aarch64/pauth_bsd_aarch64.inline.hpp b/src/hotspot/os_cpu/bsd_aarch64/pauth_bsd_aarch64.inline.hpp index 21193e181f2b7..a4d416d384e29 100644 --- a/src/hotspot/os_cpu/bsd_aarch64/pauth_bsd_aarch64.inline.hpp +++ b/src/hotspot/os_cpu/bsd_aarch64/pauth_bsd_aarch64.inline.hpp @@ -22,8 +22,8 @@ * */ -#ifndef OS_CPU_LINUX_AARCH64_PAUTH_BSD_AARCH64_INLINE_HPP -#define OS_CPU_LINUX_AARCH64_PAUTH_BSD_AARCH64_INLINE_HPP +#ifndef OS_CPU_BSD_AARCH64_PAUTH_BSD_AARCH64_INLINE_HPP +#define OS_CPU_BSD_AARCH64_PAUTH_BSD_AARCH64_INLINE_HPP #ifdef __APPLE__ #include @@ -49,5 +49,5 @@ inline address pauth_strip_pointer(address ptr) { #undef XPACLRI -#endif // OS_CPU_LINUX_AARCH64_PAUTH_BSD_AARCH64_INLINE_HPP +#endif // OS_CPU_BSD_AARCH64_PAUTH_BSD_AARCH64_INLINE_HPP diff --git a/src/hotspot/os_cpu/linux_ppc/thread_linux_ppc.cpp b/src/hotspot/os_cpu/linux_ppc/thread_linux_ppc.cpp index 9f77945664021..d09608c6aa763 100644 --- a/src/hotspot/os_cpu/linux_ppc/thread_linux_ppc.cpp +++ b/src/hotspot/os_cpu/linux_ppc/thread_linux_ppc.cpp @@ -35,6 +35,8 @@ frame JavaThread::pd_last_frame() { address pc = _anchor.last_Java_pc(); // Last_Java_pc ist not set, if we come here from compiled code. + // Assume spill slot for link register contains a suitable pc. + // Should have been filled by method entry code. if (pc == NULL) { pc = (address) *(sp + 2); } @@ -64,6 +66,17 @@ bool JavaThread::pd_get_top_frame_for_profiling(frame* fr_addr, void* ucontext, return false; } + if (ret_frame.fp() == NULL) { + // The found frame does not have a valid frame pointer. + // Bail out because this will create big trouble later on, either + // - when using istate, calculated as (NULL - ijava_state_size) or + // - when using fp() directly in safe_for_sender() + // + // There is no conclusive description (yet) how this could happen, but it does. + // For more details on what was observed, see thread_linux_s390.cpp + return false; + } + if (ret_frame.is_interpreted_frame()) { frame::ijava_state *istate = ret_frame.get_ijava_state(); const Method *m = (const Method*)(istate->method); diff --git a/src/hotspot/os_cpu/linux_s390/thread_linux_s390.cpp b/src/hotspot/os_cpu/linux_s390/thread_linux_s390.cpp index eeaf2f47fc607..d06b851a99f67 100644 --- a/src/hotspot/os_cpu/linux_s390/thread_linux_s390.cpp +++ b/src/hotspot/os_cpu/linux_s390/thread_linux_s390.cpp @@ -35,6 +35,8 @@ frame JavaThread::pd_last_frame() { address pc = _anchor.last_Java_pc(); // Last_Java_pc ist not set if we come here from compiled code. + // Assume spill slot for Z_R14 (return register) contains a suitable pc. + // Should have been filled by method entry code. if (pc == NULL) { pc = (address) *(sp + 14); } @@ -51,6 +53,9 @@ bool JavaThread::pd_get_top_frame_for_profiling(frame* fr_addr, void* ucontext, return true; } + // At this point, we don't have a last_Java_frame, so + // we try to glean some information out of the ucontext + // if we were running Java code when SIGPROF came in. if (isInJava) { ucontext_t* uc = (ucontext_t*) ucontext; frame ret_frame((intptr_t*)uc->uc_mcontext.gregs[15/*Z_SP*/], @@ -61,6 +66,38 @@ bool JavaThread::pd_get_top_frame_for_profiling(frame* fr_addr, void* ucontext, return false; } + if (ret_frame.fp() == NULL) { + // The found frame does not have a valid frame pointer. + // Bail out because this will create big trouble later on, either + // - when using istate, calculated as (NULL - z_ijava_state_size (= 0x70 (dbg) or 0x68 (rel)) or + // - when using fp() directly in safe_for_sender() + // + // There is no conclusive description (yet) how this could happen, but it does: + // + // We observed a SIGSEGV with the following stack trace (openjdk.jdk11u-dev, 2021-07-07, linuxs390x fastdebug) + // V [libjvm.so+0x12c8f12] JavaThread::pd_get_top_frame_for_profiling(frame*, void*, bool)+0x142 + // V [libjvm.so+0xb1020c] JfrGetCallTrace::get_topframe(void*, frame&)+0x3c + // V [libjvm.so+0xba0b08] OSThreadSampler::protected_task(os::SuspendedThreadTaskContext const&)+0x98 + // V [libjvm.so+0xff33c4] os::SuspendedThreadTask::internal_do_task()+0x14c + // V [libjvm.so+0xfe3c9c] os::SuspendedThreadTask::run()+0x24 + // V [libjvm.so+0xba0c66] JfrThreadSampleClosure::sample_thread_in_java(JavaThread*, JfrStackFrame*, unsigned int)+0x66 + // V [libjvm.so+0xba1718] JfrThreadSampleClosure::do_sample_thread(JavaThread*, JfrStackFrame*, unsigned int, JfrSampleType)+0x278 + // V [libjvm.so+0xba4f54] JfrThreadSampler::task_stacktrace(JfrSampleType, JavaThread**) [clone .constprop.62]+0x284 + // V [libjvm.so+0xba5e54] JfrThreadSampler::run()+0x2ec + // V [libjvm.so+0x12adc9c] Thread::call_run()+0x9c + // V [libjvm.so+0xff5ab0] thread_native_entry(Thread*)+0x128 + // siginfo: si_signo: 11 (SIGSEGV), si_code: 1 (SEGV_MAPERR), si_addr: 0xfffffffffffff000 + // failing instruction: e320 6008 0004 LG r2,8(r0,r6) + // contents of r6: 0xffffffffffffff90 + // + // Here is the sequence of what happens: + // - ret_frame is constructed with _fp == NULL (for whatever reason) + // - ijava_state_unchecked() calculates it's result as + // istate = fp() - z_ijava_state_size() = NULL - 0x68 DEBUG_ONLY(-8) + // - istate->method dereferences memory at offset 8 from istate + return false; + } + if (ret_frame.is_interpreted_frame()) { frame::z_ijava_state* istate = ret_frame.ijava_state_unchecked(); if (is_in_full_stack((address)istate)) { diff --git a/src/hotspot/os_cpu/windows_aarch64/pauth_windows_aarch64.inline.hpp b/src/hotspot/os_cpu/windows_aarch64/pauth_windows_aarch64.inline.hpp index bf1d2aa99e1c8..844291ee1e412 100644 --- a/src/hotspot/os_cpu/windows_aarch64/pauth_windows_aarch64.inline.hpp +++ b/src/hotspot/os_cpu/windows_aarch64/pauth_windows_aarch64.inline.hpp @@ -22,13 +22,13 @@ * */ -#ifndef OS_CPU_LINUX_AARCH64_PAUTH_WINDOWS_AARCH64_INLINE_HPP -#define OS_CPU_LINUX_AARCH64_PAUTH_WINDOWS_AARCH64_INLINE_HPP +#ifndef OS_CPU_WINDOWS_AARCH64_PAUTH_WINDOWS_AARCH64_INLINE_HPP +#define OS_CPU_WINDOWS_AARCH64_PAUTH_WINDOWS_AARCH64_INLINE_HPP inline address pauth_strip_pointer(address ptr) { // No PAC support in windows as of yet. return ptr; } -#endif // OS_CPU_LINUX_AARCH64_PAUTH_WINDOWS_AARCH64_INLINE_HPP +#endif // OS_CPU_WINDOWS_AARCH64_PAUTH_WINDOWS_AARCH64_INLINE_HPP diff --git a/src/hotspot/share/cds/archiveBuilder.cpp b/src/hotspot/share/cds/archiveBuilder.cpp index 6e0a392e739c1..c2bd7eecf92fc 100644 --- a/src/hotspot/share/cds/archiveBuilder.cpp +++ b/src/hotspot/share/cds/archiveBuilder.cpp @@ -115,20 +115,16 @@ class RelocateEmbeddedPointers : public BitMapClosure { _builder(builder), _dumped_obj(dumped_obj), _start_idx(start_idx) {} bool do_bit(BitMap::idx_t bit_offset) { - uintx FLAG_MASK = 0x03; // See comments around MetaspaceClosure::FLAG_MASK size_t field_offset = size_t(bit_offset - _start_idx) * sizeof(address); address* ptr_loc = (address*)(_dumped_obj + field_offset); - uintx old_p_and_bits = (uintx)(*ptr_loc); - uintx flag_bits = (old_p_and_bits & FLAG_MASK); - address old_p = (address)(old_p_and_bits & (~FLAG_MASK)); + address old_p = *ptr_loc; address new_p = _builder->get_dumped_addr(old_p); - uintx new_p_and_bits = ((uintx)new_p) | flag_bits; log_trace(cds)("Ref: [" PTR_FORMAT "] -> " PTR_FORMAT " => " PTR_FORMAT, p2i(ptr_loc), p2i(old_p), p2i(new_p)); - ArchivePtrMarker::set_and_mark_pointer(ptr_loc, (address)(new_p_and_bits)); + ArchivePtrMarker::set_and_mark_pointer(ptr_loc, new_p); return true; // keep iterating the bitmap } }; diff --git a/src/hotspot/share/classfile/classLoaderData.cpp b/src/hotspot/share/classfile/classLoaderData.cpp index 6e0ef18786e68..87d8bfeef8204 100644 --- a/src/hotspot/share/classfile/classLoaderData.cpp +++ b/src/hotspot/share/classfile/classLoaderData.cpp @@ -133,7 +133,7 @@ void ClassLoaderData::initialize_name(Handle class_loader) { ClassLoaderData::ClassLoaderData(Handle h_class_loader, bool has_class_mirror_holder) : _metaspace(NULL), - _metaspace_lock(new Mutex(Mutex::leaf+1, "Metaspace allocation lock", true, + _metaspace_lock(new Mutex(Mutex::leaf+1, "Metaspace allocation lock", Mutex::_safepoint_check_never)), _unloading(false), _has_class_mirror_holder(has_class_mirror_holder), _modified_oops(true), @@ -964,11 +964,13 @@ void ClassLoaderData::print_on(outputStream* out) const { out->print_cr(" - keep alive %d", _keep_alive); out->print (" - claim "); switch(_claim) { - case _claim_none: out->print_cr("none"); break; - case _claim_finalizable:out->print_cr("finalizable"); break; - case _claim_strong: out->print_cr("strong"); break; - case _claim_other: out->print_cr("other"); break; - default: ShouldNotReachHere(); + case _claim_none: out->print_cr("none"); break; + case _claim_finalizable: out->print_cr("finalizable"); break; + case _claim_strong: out->print_cr("strong"); break; + case _claim_other: out->print_cr("other"); break; + case _claim_other | _claim_finalizable: out->print_cr("other and finalizable"); break; + case _claim_other | _claim_strong: out->print_cr("other and strong"); break; + default: ShouldNotReachHere(); } out->print_cr(" - handles %d", _handles.count()); out->print_cr(" - dependency count %d", _dependency_count); diff --git a/src/hotspot/share/classfile/javaClasses.cpp b/src/hotspot/share/classfile/javaClasses.cpp index dde42ba528e19..c5515d3d73e15 100644 --- a/src/hotspot/share/classfile/javaClasses.cpp +++ b/src/hotspot/share/classfile/javaClasses.cpp @@ -206,9 +206,6 @@ int java_lang_String::_flags_offset; bool java_lang_String::_initialized; -bool java_lang_String::is_instance(oop obj) { - return is_instance_inlined(obj); -} bool java_lang_String::test_and_set_flag(oop java_string, uint8_t flag_mask) { uint8_t* addr = flags_addr(java_string); diff --git a/src/hotspot/share/classfile/javaClasses.hpp b/src/hotspot/share/classfile/javaClasses.hpp index 44ae70ac87df0..62481fbcc1a1b 100644 --- a/src/hotspot/share/classfile/javaClasses.hpp +++ b/src/hotspot/share/classfile/javaClasses.hpp @@ -237,9 +237,8 @@ class java_lang_String : AllStatic { static Symbol* as_symbol(oop java_string); static Symbol* as_symbol_or_null(oop java_string); - // Testers - static bool is_instance(oop obj); - static inline bool is_instance_inlined(oop obj); + // Tester + static inline bool is_instance(oop obj); // Debugging static void print(oop java_string, outputStream* st); diff --git a/src/hotspot/share/classfile/javaClasses.inline.hpp b/src/hotspot/share/classfile/javaClasses.inline.hpp index 6d8bcc3cf913f..e8ee4fce25e74 100644 --- a/src/hotspot/share/classfile/javaClasses.inline.hpp +++ b/src/hotspot/share/classfile/javaClasses.inline.hpp @@ -123,7 +123,7 @@ int java_lang_String::length(oop java_string) { return length(java_string, value); } -bool java_lang_String::is_instance_inlined(oop obj) { +bool java_lang_String::is_instance(oop obj) { return obj != NULL && obj->klass() == vmClasses::String_klass(); } diff --git a/src/hotspot/share/classfile/vmIntrinsics.cpp b/src/hotspot/share/classfile/vmIntrinsics.cpp index fea61d5a76651..205ba8969cb0a 100644 --- a/src/hotspot/share/classfile/vmIntrinsics.cpp +++ b/src/hotspot/share/classfile/vmIntrinsics.cpp @@ -182,6 +182,7 @@ int vmIntrinsics::predicates_needed(vmIntrinsics::ID id) { case vmIntrinsics::_electronicCodeBook_encryptAESCrypt: case vmIntrinsics::_electronicCodeBook_decryptAESCrypt: case vmIntrinsics::_counterMode_AESCrypt: + case vmIntrinsics::_galoisCounterMode_AESCrypt: return 1; case vmIntrinsics::_digestBase_implCompressMB: return 5; @@ -429,6 +430,9 @@ bool vmIntrinsics::disabled_by_jvm_flags(vmIntrinsics::ID id) { case vmIntrinsics::_counterMode_AESCrypt: if (!UseAESCTRIntrinsics) return true; break; + case vmIntrinsics::_galoisCounterMode_AESCrypt: + if (!UseAESIntrinsics) return true; + break; case vmIntrinsics::_md5_implCompress: if (!UseMD5Intrinsics) return true; break; diff --git a/src/hotspot/share/classfile/vmIntrinsics.hpp b/src/hotspot/share/classfile/vmIntrinsics.hpp index f4121d90baded..02aa3cb56155c 100644 --- a/src/hotspot/share/classfile/vmIntrinsics.hpp +++ b/src/hotspot/share/classfile/vmIntrinsics.hpp @@ -415,6 +415,11 @@ class methodHandle; do_intrinsic(_counterMode_AESCrypt, com_sun_crypto_provider_counterMode, crypt_name, byteArray_int_int_byteArray_int_signature, F_R) \ do_name( crypt_name, "implCrypt") \ \ + do_class(com_sun_crypto_provider_galoisCounterMode, "com/sun/crypto/provider/GaloisCounterMode") \ + do_intrinsic(_galoisCounterMode_AESCrypt, com_sun_crypto_provider_galoisCounterMode, gcm_crypt_name, aes_gcm_signature, F_S) \ + do_name(gcm_crypt_name, "implGCMCrypt") \ + do_signature(aes_gcm_signature, "([BII[BI[BILcom/sun/crypto/provider/GCTR;Lcom/sun/crypto/provider/GHASH;)I") \ + \ /* support for sun.security.provider.MD5 */ \ do_class(sun_security_provider_md5, "sun/security/provider/MD5") \ do_intrinsic(_md5_implCompress, sun_security_provider_md5, implCompress_name, implCompress_signature, F_R) \ diff --git a/src/hotspot/share/compiler/compileTask.hpp b/src/hotspot/share/compiler/compileTask.hpp index 03beb350b1bb9..812c3ae9fb06a 100644 --- a/src/hotspot/share/compiler/compileTask.hpp +++ b/src/hotspot/share/compiler/compileTask.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2021, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -104,7 +104,7 @@ class CompileTask : public CHeapObj { public: CompileTask() : _failure_reason(NULL), _failure_reason_on_C_heap(false) { - _lock = new Monitor(Mutex::nonleaf+2, "CompileTaskLock"); + _lock = new Monitor(Mutex::nonleaf+2, "CompileTaskLock", Mutex::_safepoint_check_always); } void initialize(int compile_id, const methodHandle& method, int osr_bci, int comp_level, diff --git a/src/hotspot/share/gc/g1/g1BarrierSet.cpp b/src/hotspot/share/gc/g1/g1BarrierSet.cpp index 9ffd5ed784623..994bf16c2e30b 100644 --- a/src/hotspot/share/gc/g1/g1BarrierSet.cpp +++ b/src/hotspot/share/gc/g1/g1BarrierSet.cpp @@ -58,8 +58,7 @@ G1BarrierSet::G1BarrierSet(G1CardTable* card_table) : _satb_mark_queue_buffer_allocator("SATB Buffer Allocator", G1SATBBufferSize), _dirty_card_queue_buffer_allocator("DC Buffer Allocator", G1UpdateBufferSize), _satb_mark_queue_set(&_satb_mark_queue_buffer_allocator), - _dirty_card_queue_set(&_dirty_card_queue_buffer_allocator), - _shared_dirty_card_queue(&_dirty_card_queue_set) + _dirty_card_queue_set(&_dirty_card_queue_buffer_allocator) {} void G1BarrierSet::enqueue(oop pre_val) { diff --git a/src/hotspot/share/gc/g1/g1BarrierSet.hpp b/src/hotspot/share/gc/g1/g1BarrierSet.hpp index 8d009a9e19f3f..e8eb6e9c9d1df 100644 --- a/src/hotspot/share/gc/g1/g1BarrierSet.hpp +++ b/src/hotspot/share/gc/g1/g1BarrierSet.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2021, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -27,7 +27,6 @@ #include "gc/g1/g1DirtyCardQueue.hpp" #include "gc/g1/g1SATBMarkQueueSet.hpp" -#include "gc/g1/g1SharedDirtyCardQueue.hpp" #include "gc/shared/cardTable.hpp" #include "gc/shared/cardTableBarrierSet.hpp" @@ -43,7 +42,6 @@ class G1BarrierSet: public CardTableBarrierSet { BufferNode::Allocator _dirty_card_queue_buffer_allocator; G1SATBMarkQueueSet _satb_mark_queue_set; G1DirtyCardQueueSet _dirty_card_queue_set; - G1SharedDirtyCardQueue _shared_dirty_card_queue; static G1BarrierSet* g1_barrier_set() { return barrier_set_cast(BarrierSet::barrier_set()); @@ -94,10 +92,6 @@ class G1BarrierSet: public CardTableBarrierSet { return g1_barrier_set()->_dirty_card_queue_set; } - static G1SharedDirtyCardQueue& shared_dirty_card_queue() { - return g1_barrier_set()->_shared_dirty_card_queue; - } - // Callbacks for runtime accesses. template class AccessBarrier: public ModRefBarrierSet::AccessBarrier { diff --git a/src/hotspot/share/gc/g1/g1BlockOffsetTable.cpp b/src/hotspot/share/gc/g1/g1BlockOffsetTable.cpp index 5f78a40e36d22..d01ceb6156741 100644 --- a/src/hotspot/share/gc/g1/g1BlockOffsetTable.cpp +++ b/src/hotspot/share/gc/g1/g1BlockOffsetTable.cpp @@ -337,8 +337,8 @@ void G1BlockOffsetTablePart::verify() const { assert(_hr->bottom() < _hr->top(), "Only non-empty regions should be verified."); size_t start_card = _bot->index_for(_hr->bottom()); // Do not verify beyond the BOT allocation threshold. - size_t next_offset_index = _bot->index_for_raw(_next_offset_threshold); - size_t end_card = MIN2(_bot->index_for(_hr->top() - 1), next_offset_index - 1); + assert(_hr->top() <= _next_offset_threshold, "invariant"); + size_t end_card = _bot->index_for(_hr->top() - 1); for (size_t current_card = start_card; current_card < end_card; current_card++) { u_char entry = _bot->offset_array(current_card); @@ -398,13 +398,6 @@ void G1BlockOffsetTablePart::print_on(outputStream* out) { } #endif // !PRODUCT -HeapWord* G1BlockOffsetTablePart::initialize_threshold_raw() { - size_t next_offset_index = _bot->index_for_raw(_hr->bottom()) + 1; - _next_offset_threshold = - _bot->address_for_index_raw(next_offset_index); - return _next_offset_threshold; -} - void G1BlockOffsetTablePart::zero_bottom_entry_raw() { size_t bottom_index = _bot->index_for_raw(_hr->bottom()); assert(_bot->address_for_index_raw(bottom_index) == _hr->bottom(), @@ -413,9 +406,7 @@ void G1BlockOffsetTablePart::zero_bottom_entry_raw() { } HeapWord* G1BlockOffsetTablePart::initialize_threshold() { - size_t next_offset_index = _bot->index_for(_hr->bottom()) + 1 ; - _next_offset_threshold = - _bot->address_for_index(next_offset_index); + _next_offset_threshold = _hr->bottom() + BOTConstants::N_words; return _next_offset_threshold; } diff --git a/src/hotspot/share/gc/g1/g1BlockOffsetTable.hpp b/src/hotspot/share/gc/g1/g1BlockOffsetTable.hpp index 02928425cb6de..d6d3ac20678eb 100644 --- a/src/hotspot/share/gc/g1/g1BlockOffsetTable.hpp +++ b/src/hotspot/share/gc/g1/g1BlockOffsetTable.hpp @@ -134,9 +134,6 @@ class G1BlockOffsetTablePart { // Zero out the entry for _bottom (offset will be zero). Does not check for availability of the // memory first. void zero_bottom_entry_raw(); - // Variant of initialize_threshold that does not check for availability of the - // memory first. - HeapWord* initialize_threshold_raw(); inline size_t block_size(const HeapWord* p) const; @@ -200,7 +197,7 @@ class G1BlockOffsetTablePart { void reset_bot() { zero_bottom_entry_raw(); - initialize_threshold_raw(); + initialize_threshold(); } // Return the next threshold, the point at which the table should be diff --git a/src/hotspot/share/gc/g1/g1CollectedHeap.cpp b/src/hotspot/share/gc/g1/g1CollectedHeap.cpp index ef0b3e81ad733..0163613a5de5f 100644 --- a/src/hotspot/share/gc/g1/g1CollectedHeap.cpp +++ b/src/hotspot/share/gc/g1/g1CollectedHeap.cpp @@ -68,6 +68,7 @@ #include "gc/g1/g1ServiceThread.hpp" #include "gc/g1/g1UncommitRegionTask.hpp" #include "gc/g1/g1VMOperations.hpp" +#include "gc/g1/g1YoungGCEvacFailureInjector.hpp" #include "gc/g1/g1YoungGCPostEvacuateTasks.hpp" #include "gc/g1/heapRegion.inline.hpp" #include "gc/g1/heapRegionRemSet.inline.hpp" @@ -1113,8 +1114,9 @@ bool G1CollectedHeap::do_full_collection(bool explicit_gc, const bool do_clear_all_soft_refs = clear_all_soft_refs || soft_ref_policy()->should_clear_all_soft_refs(); - G1FullCollector collector(this, explicit_gc, do_clear_all_soft_refs, do_maximum_compaction); + G1FullGCMark gc_mark; GCTraceTime(Info, gc) tm("Pause Full", NULL, gc_cause(), true); + G1FullCollector collector(this, explicit_gc, do_clear_all_soft_refs, do_maximum_compaction); collector.prepare_collection(); collector.collect(); @@ -1447,6 +1449,7 @@ G1CollectedHeap::G1CollectedHeap() : _numa(G1NUMA::create()), _hrm(), _allocator(NULL), + _evac_failure_injector(), _verifier(NULL), _summary_bytes_used(0), _bytes_used_during_gc(0), @@ -1477,13 +1480,6 @@ G1CollectedHeap::G1CollectedHeap() : _task_queues(NULL), _num_regions_failed_evacuation(0), _regions_failed_evacuation(mtGC), - _evacuation_failed_info_array(NULL), - _preserved_marks_set(true /* in_c_heap */), -#ifndef PRODUCT - _evacuation_failure_alot_for_current_gc(false), - _evacuation_failure_alot_gc_number(0), - _evacuation_failure_alot_count(0), -#endif _ref_processor_stw(NULL), _is_alive_closure_stw(this), _is_subject_to_discovery_stw(this), @@ -1507,16 +1503,11 @@ G1CollectedHeap::G1CollectedHeap() : uint n_queues = ParallelGCThreads; _task_queues = new G1ScannerTasksQueueSet(n_queues); - _evacuation_failed_info_array = NEW_C_HEAP_ARRAY(EvacuationFailedInfo, n_queues, mtGC); - for (uint i = 0; i < n_queues; i++) { G1ScannerTasksQueue* q = new G1ScannerTasksQueue(); _task_queues->register_queue(i, q); - ::new (&_evacuation_failed_info_array[i]) EvacuationFailedInfo(); } - // Initialize the G1EvacuationFailureALot counters and flags. - NOT_PRODUCT(reset_evacuation_should_fail();) _gc_tracer_stw->initialize(); guarantee(_task_queues != NULL, "task_queues allocation failure."); @@ -1767,12 +1758,12 @@ jint G1CollectedHeap::initialize() { // values in the heap have been properly initialized. _monitoring_support = new G1MonitoringSupport(this); - _preserved_marks_set.init(ParallelGCThreads); - _collection_set.initialize(max_reserved_regions()); _regions_failed_evacuation.resize(max_regions()); + evac_failure_injector()->reset(); + G1InitLogger::print(); return JNI_OK; @@ -2999,6 +2990,19 @@ class G1YoungGCJFRTracerMark : public G1JFRTracerMark { } }; +class G1PreservedMarksSet : public PreservedMarksSet { +public: + + G1PreservedMarksSet(uint num_workers) : PreservedMarksSet(true /* in_c_heap */) { + init(num_workers); + } + + virtual ~G1PreservedMarksSet() { + assert_empty(); + reclaim(); + } +}; + void G1CollectedHeap::set_young_collection_default_active_worker_threads(){ uint active_workers = WorkerPolicy::calc_active_workers(workers()->total_workers(), workers()->active_workers(), @@ -3042,10 +3046,6 @@ void G1CollectedHeap::do_collection_pause_at_safepoint_helper(double target_paus bool should_start_concurrent_mark_operation = collector_state()->in_concurrent_start_gc(); bool concurrent_operation_is_full_mark = false; - // Verification may use the gang workers, so they must be set up before. - // Individual parallel phases may override this. - set_young_collection_default_active_worker_threads(); - { // Do timing/tracing/statistics/pre- and post-logging/verification work not // directly related to the collection. They should not be accounted for in @@ -3055,16 +3055,21 @@ void G1CollectedHeap::do_collection_pause_at_safepoint_helper(double target_paus // determining collector state. G1YoungGCTraceTime tm(gc_cause()); - // Young GC internal pause timing - G1YoungGCNotifyPauseMark npm; // JFR G1YoungGCJFRTracerMark jtm(_gc_timer_stw, _gc_tracer_stw, gc_cause()); // JStat/MXBeans G1MonitoringScope ms(monitoring_support(), false /* full_gc */, collector_state()->in_mixed_phase() /* all_memory_pools_affected */); - + // Create the heap printer before internal pause timing to have + // heap information printed as last part of detailed GC log. G1HeapPrinterMark hpm(this); + // Young GC internal pause timing + G1YoungGCNotifyPauseMark npm; + + // Verification may use the gang workers, so they must be set up before. + // Individual parallel phases may override this. + set_young_collection_default_active_worker_threads(); // Wait for root region scan here to make sure that it is done before any // use of the STW work gang to maximize cpu use (i.e. all cores are available @@ -3083,8 +3088,10 @@ void G1CollectedHeap::do_collection_pause_at_safepoint_helper(double target_paus calculate_collection_set(jtm.evacuation_info(), target_pause_time_ms); G1RedirtyCardsQueueSet rdcqs(G1BarrierSet::dirty_card_queue_set().allocator()); + G1PreservedMarksSet preserved_marks_set(workers()->active_workers()); G1ParScanThreadStateSet per_thread_states(this, &rdcqs, + &preserved_marks_set, workers()->active_workers(), collection_set()->young_region_length(), collection_set()->optional_region_length()); @@ -3097,7 +3104,7 @@ void G1CollectedHeap::do_collection_pause_at_safepoint_helper(double target_paus if (may_do_optional_evacuation) { evacuate_optional_collection_set(&per_thread_states); } - post_evacuate_collection_set(jtm.evacuation_info(), &rdcqs, &per_thread_states); + post_evacuate_collection_set(jtm.evacuation_info(), &per_thread_states); // Refine the type of a concurrent mark operation now that we did the // evacuation, eventually aborting it. @@ -3126,11 +3133,6 @@ void G1CollectedHeap::do_collection_pause_at_safepoint_helper(double target_paus } } -void G1CollectedHeap::preserve_mark_during_evac_failure(uint worker_id, oop obj, markWord m) { - _evacuation_failed_info_array[worker_id].register_copy_failure(obj->size()); - _preserved_marks_set.get(worker_id)->push_if_necessary(obj, m); -} - bool G1ParEvacuateFollowersClosure::offer_termination() { EventGCPhaseParallel event; G1ParScanThreadState* const pss = par_scan_state(); @@ -3441,12 +3443,13 @@ class G1PrepareEvacuationTask : public AbstractGangTask { _g1h->set_humongous_reclaim_candidate(index, false); _g1h->register_region_with_region_attr(hr); } - log_debug(gc, humongous)("Humongous region %u (object size " SIZE_FORMAT " @ " PTR_FORMAT ") remset " SIZE_FORMAT " code roots " SIZE_FORMAT " marked %d reclaim candidate %d type array %d", + log_debug(gc, humongous)("Humongous region %u (object size " SIZE_FORMAT " @ " PTR_FORMAT ") remset " SIZE_FORMAT " code roots " SIZE_FORMAT " marked (prev/next) %d/%d reclaim candidate %d type array %d", index, (size_t)cast_to_oop(hr->bottom())->size() * HeapWordSize, p2i(hr->bottom()), hr->rem_set()->occupied(), hr->rem_set()->strong_code_roots_list_length(), + _g1h->concurrent_mark()->prev_mark_bitmap()->is_marked(hr->bottom()), _g1h->concurrent_mark()->next_mark_bitmap()->is_marked(hr->bottom()), _g1h->is_humongous_reclaim_candidate(index), cast_to_oop(hr->bottom())->is_typeArray() @@ -3559,7 +3562,6 @@ void G1CollectedHeap::pre_evacuate_collection_set(G1EvacuationInfo* evacuation_i } assert(_verifier->check_region_attr_table(), "Inconsistency in the region attributes table."); - _preserved_marks_set.assert_empty(); #if COMPILER2_OR_JVMCI DerivedPointerTable::clear(); @@ -3578,7 +3580,7 @@ void G1CollectedHeap::pre_evacuate_collection_set(G1EvacuationInfo* evacuation_i } // Should G1EvacuationFailureALot be in effect for this GC? - NOT_PRODUCT(set_evacuation_failure_alot_for_current_gc();) + evac_failure_injector()->arm_if_needed(); } class G1EvacuateRegionsBaseTask : public AbstractGangTask { @@ -3798,7 +3800,6 @@ void G1CollectedHeap::evacuate_optional_collection_set(G1ParScanThreadStateSet* } void G1CollectedHeap::post_evacuate_collection_set(G1EvacuationInfo* evacuation_info, - G1RedirtyCardsQueueSet* rdcqs, G1ParScanThreadStateSet* per_thread_states) { G1GCPhaseTimes* p = phase_times(); @@ -3816,9 +3817,9 @@ void G1CollectedHeap::post_evacuate_collection_set(G1EvacuationInfo* evacuation_ _allocator->release_gc_alloc_regions(evacuation_info); - post_evacuate_cleanup_1(per_thread_states, rdcqs); + post_evacuate_cleanup_1(per_thread_states); - post_evacuate_cleanup_2(&_preserved_marks_set, rdcqs, evacuation_info, per_thread_states->surviving_young_words()); + post_evacuate_cleanup_2(per_thread_states, evacuation_info); assert_used_and_recalculate_used_equal(this); @@ -3903,23 +3904,20 @@ void G1CollectedHeap::decrement_summary_bytes(size_t bytes) { decrease_used(bytes); } -void G1CollectedHeap::post_evacuate_cleanup_1(G1ParScanThreadStateSet* per_thread_states, - G1RedirtyCardsQueueSet* rdcqs) { +void G1CollectedHeap::post_evacuate_cleanup_1(G1ParScanThreadStateSet* per_thread_states) { Ticks start = Ticks::now(); { - G1PostEvacuateCollectionSetCleanupTask1 cl(per_thread_states, rdcqs); + G1PostEvacuateCollectionSetCleanupTask1 cl(per_thread_states); run_batch_task(&cl); } phase_times()->record_post_evacuate_cleanup_task_1_time((Ticks::now() - start).seconds() * 1000.0); } -void G1CollectedHeap::post_evacuate_cleanup_2(PreservedMarksSet* preserved_marks, - G1RedirtyCardsQueueSet* rdcqs, - G1EvacuationInfo* evacuation_info, - const size_t* surviving_young_words) { +void G1CollectedHeap::post_evacuate_cleanup_2(G1ParScanThreadStateSet* per_thread_states, + G1EvacuationInfo* evacuation_info) { Ticks start = Ticks::now(); { - G1PostEvacuateCollectionSetCleanupTask2 cl(preserved_marks, rdcqs, evacuation_info, surviving_young_words); + G1PostEvacuateCollectionSetCleanupTask2 cl(per_thread_states, evacuation_info); run_batch_task(&cl); } phase_times()->record_post_evacuate_cleanup_task_2_time((Ticks::now() - start).seconds() * 1000.0); @@ -4297,18 +4295,13 @@ void G1CollectedHeap::unregister_nmethod(nmethod* nm) { void G1CollectedHeap::update_used_after_gc() { if (evacuation_failed()) { // Reset the G1EvacuationFailureALot counters and flags - NOT_PRODUCT(reset_evacuation_should_fail();) + evac_failure_injector()->reset(); set_used(recalculate_used()); if (_archive_allocator != NULL) { _archive_allocator->clear_used(); } - for (uint i = 0; i < ParallelGCThreads; i++) { - if (_evacuation_failed_info_array[i].has_failed()) { - _gc_tracer_stw->report_evacuation_failed(_evacuation_failed_info_array[i]); - } - } } else { // The "used" of the the collection set have already been subtracted // when they were freed. Add in the bytes used. diff --git a/src/hotspot/share/gc/g1/g1CollectedHeap.hpp b/src/hotspot/share/gc/g1/g1CollectedHeap.hpp index 5311b25cab38b..9b6c8d6a12b5c 100644 --- a/src/hotspot/share/gc/g1/g1CollectedHeap.hpp +++ b/src/hotspot/share/gc/g1/g1CollectedHeap.hpp @@ -47,13 +47,13 @@ #include "gc/g1/g1NUMA.hpp" #include "gc/g1/g1RedirtyCardsQueue.hpp" #include "gc/g1/g1SurvivorRegions.hpp" +#include "gc/g1/g1YoungGCEvacFailureInjector.hpp" #include "gc/g1/heapRegionManager.hpp" #include "gc/g1/heapRegionSet.hpp" #include "gc/shared/barrierSet.hpp" #include "gc/shared/collectedHeap.hpp" #include "gc/shared/gcHeapSummary.hpp" #include "gc/shared/plab.hpp" -#include "gc/shared/preservedMarks.hpp" #include "gc/shared/softRefPolicy.hpp" #include "gc/shared/taskqueue.hpp" #include "memory/memRegion.hpp" @@ -93,7 +93,6 @@ class G1ConcurrentRefine; class GenerationCounters; class STWGCTimer; class G1NewTracer; -class EvacuationFailedInfo; class nmethod; class WorkGang; class G1Allocator; @@ -150,8 +149,6 @@ class G1CollectedHeap : public CollectedHeap { friend class G1YoungGCVerifierMark; // Closures used in implementation. - friend class G1ParScanThreadState; - friend class G1ParScanThreadStateSet; friend class G1EvacuateRegionsTask; friend class G1PLABAllocator; @@ -215,6 +212,8 @@ class G1CollectedHeap : public CollectedHeap { // Manages all allocations with regions except humongous object allocations. G1Allocator* _allocator; + G1YoungGCEvacFailureInjector _evac_failure_injector; + // Manages all heap verification. G1HeapVerifier* _verifier; @@ -566,6 +565,8 @@ class G1CollectedHeap : public CollectedHeap { return _allocator; } + G1YoungGCEvacFailureInjector* evac_failure_injector() { return &_evac_failure_injector; } + G1HeapVerifier* verifier() { return _verifier; } @@ -834,7 +835,6 @@ class G1CollectedHeap : public CollectedHeap { public: void pre_evacuate_collection_set(G1EvacuationInfo* evacuation_info, G1ParScanThreadStateSet* pss); void post_evacuate_collection_set(G1EvacuationInfo* evacuation_info, - G1RedirtyCardsQueueSet* rdcqs, G1ParScanThreadStateSet* pss); void expand_heap_after_young_collection(); @@ -849,12 +849,9 @@ class G1CollectedHeap : public CollectedHeap { // Global card set configuration G1CardSetConfiguration _card_set_config; - void post_evacuate_cleanup_1(G1ParScanThreadStateSet* per_thread_states, - G1RedirtyCardsQueueSet* rdcqs); - void post_evacuate_cleanup_2(PreservedMarksSet* preserved_marks, - G1RedirtyCardsQueueSet* rdcqs, - G1EvacuationInfo* evacuation_info, - const size_t* surviving_young_words); + void post_evacuate_cleanup_1(G1ParScanThreadStateSet* per_thread_states); + void post_evacuate_cleanup_2(G1ParScanThreadStateSet* per_thread_states, + G1EvacuationInfo* evacuation_info); // After a collection pause, reset eden and the collection set. void clear_eden(); @@ -879,47 +876,10 @@ class G1CollectedHeap : public CollectedHeap { // Records for every region on the heap whether evacuation failed for it. CHeapBitMap _regions_failed_evacuation; - EvacuationFailedInfo* _evacuation_failed_info_array; - - PreservedMarksSet _preserved_marks_set; - // Preserve the mark of "obj", if necessary, in preparation for its mark // word being overwritten with a self-forwarding-pointer. void preserve_mark_during_evac_failure(uint worker_id, oop obj, markWord m); -#ifndef PRODUCT - // Support for forcing evacuation failures. Analogous to - // PromotionFailureALot for the other collectors. - - // Records whether G1EvacuationFailureALot should be in effect - // for the current GC - bool _evacuation_failure_alot_for_current_gc; - - // Used to record the GC number for interval checking when - // determining whether G1EvaucationFailureALot is in effect - // for the current GC. - size_t _evacuation_failure_alot_gc_number; - - // Count of the number of evacuations between failures. - volatile size_t _evacuation_failure_alot_count; - - // Set whether G1EvacuationFailureALot should be in effect - // for the current GC (based upon the type of GC and which - // command line flags are set); - inline bool evacuation_failure_alot_for_gc_type(bool for_young_gc, - bool during_concurrent_start, - bool mark_or_rebuild_in_progress); - - inline void set_evacuation_failure_alot_for_current_gc(); - - // Return true if it's time to cause an evacuation failure. - inline bool evacuation_should_fail(); - - // Reset the G1EvacuationFailureALot counters. Should be called at - // the end of an evacuation pause in which an evacuation failure occurred. - inline void reset_evacuation_should_fail(); -#endif // !PRODUCT - // ("Weak") Reference processing support. // // G1 has 2 instances of the reference processor class. diff --git a/src/hotspot/share/gc/g1/g1CollectedHeap.inline.hpp b/src/hotspot/share/gc/g1/g1CollectedHeap.inline.hpp index af214eff23961..d22a98c812289 100644 --- a/src/hotspot/share/gc/g1/g1CollectedHeap.inline.hpp +++ b/src/hotspot/share/gc/g1/g1CollectedHeap.inline.hpp @@ -211,78 +211,6 @@ bool G1CollectedHeap::notify_region_failed_evacuation(uint const region_idx) { return result; } -#ifndef PRODUCT -// Support for G1EvacuationFailureALot - -inline bool -G1CollectedHeap::evacuation_failure_alot_for_gc_type(bool for_young_gc, - bool during_concurrent_start, - bool mark_or_rebuild_in_progress) { - bool res = false; - if (mark_or_rebuild_in_progress) { - res |= G1EvacuationFailureALotDuringConcMark; - } - if (during_concurrent_start) { - res |= G1EvacuationFailureALotDuringConcurrentStart; - } - if (for_young_gc) { - res |= G1EvacuationFailureALotDuringYoungGC; - } else { - // GCs are mixed - res |= G1EvacuationFailureALotDuringMixedGC; - } - return res; -} - -inline void -G1CollectedHeap::set_evacuation_failure_alot_for_current_gc() { - if (G1EvacuationFailureALot) { - // Note we can't assert that _evacuation_failure_alot_for_current_gc - // is clear here. It may have been set during a previous GC but that GC - // did not copy enough objects (i.e. G1EvacuationFailureALotCount) to - // trigger an evacuation failure and clear the flags and and counts. - - // Check if we have gone over the interval. - const size_t gc_num = total_collections(); - const size_t elapsed_gcs = gc_num - _evacuation_failure_alot_gc_number; - - _evacuation_failure_alot_for_current_gc = (elapsed_gcs >= G1EvacuationFailureALotInterval); - - // Now check if G1EvacuationFailureALot is enabled for the current GC type. - const bool in_young_only_phase = collector_state()->in_young_only_phase(); - const bool in_concurrent_start_gc = collector_state()->in_concurrent_start_gc(); - const bool mark_or_rebuild_in_progress = collector_state()->mark_or_rebuild_in_progress(); - - _evacuation_failure_alot_for_current_gc &= - evacuation_failure_alot_for_gc_type(in_young_only_phase, - in_concurrent_start_gc, - mark_or_rebuild_in_progress); - } -} - -inline bool G1CollectedHeap::evacuation_should_fail() { - if (!G1EvacuationFailureALot || !_evacuation_failure_alot_for_current_gc) { - return false; - } - // G1EvacuationFailureALot is in effect for current GC - // Access to _evacuation_failure_alot_count is not atomic; - // the value does not have to be exact. - if (++_evacuation_failure_alot_count < G1EvacuationFailureALotCount) { - return false; - } - _evacuation_failure_alot_count = 0; - return true; -} - -inline void G1CollectedHeap::reset_evacuation_should_fail() { - if (G1EvacuationFailureALot) { - _evacuation_failure_alot_gc_number = total_collections(); - _evacuation_failure_alot_count = 0; - _evacuation_failure_alot_for_current_gc = false; - } -} -#endif // #ifndef PRODUCT - inline bool G1CollectedHeap::is_in_young(const oop obj) { if (obj == NULL) { return false; diff --git a/src/hotspot/share/gc/g1/g1ConcurrentMark.cpp b/src/hotspot/share/gc/g1/g1ConcurrentMark.cpp index edc0164f3e90b..50a5804b08215 100644 --- a/src/hotspot/share/gc/g1/g1ConcurrentMark.cpp +++ b/src/hotspot/share/gc/g1/g1ConcurrentMark.cpp @@ -581,29 +581,65 @@ class G1ClearBitMapTask : public AbstractGangTask { static size_t chunk_size() { return M; } private: - // Heap region closure used for clearing the given mark bitmap. + // Heap region closure used for clearing the _next_mark_bitmap. class G1ClearBitmapHRClosure : public HeapRegionClosure { private: - G1CMBitMap* _bitmap; G1ConcurrentMark* _cm; - public: - G1ClearBitmapHRClosure(G1CMBitMap* bitmap, G1ConcurrentMark* cm) : HeapRegionClosure(), _bitmap(bitmap), _cm(cm) { + G1CMBitMap* _bitmap; + bool _suspendible; // If suspendible, do yield checks. + + bool suspendible() { + return _suspendible; + } + + bool is_clear_concurrent_undo() { + return suspendible() && _cm->cm_thread()->in_undo_mark(); + } + + bool has_aborted() { + if (suspendible()) { + _cm->do_yield_check(); + return _cm->has_aborted(); + } + return false; + } + + HeapWord* region_clear_limit(HeapRegion* r) { + // During a Concurrent Undo Mark cycle, the _next_mark_bitmap is cleared + // without swapping with the _prev_mark_bitmap. Therefore, the per region + // next_top_at_mark_start and live_words data are current wrt + // _next_mark_bitmap. We use this information to only clear ranges of the + // bitmap that require clearing. + if (is_clear_concurrent_undo()) { + // No need to clear bitmaps for empty regions. + if (_cm->live_words(r->hrm_index()) == 0) { + assert(_bitmap->get_next_marked_addr(r->bottom(), r->end()) == r->end(), "Should not have marked bits"); + return r->bottom(); + } + assert(_bitmap->get_next_marked_addr(r->next_top_at_mark_start(), r->end()) == r->end(), "Should not have marked bits above ntams"); + } + return r->end(); } + public: + G1ClearBitmapHRClosure(G1ConcurrentMark* cm, bool suspendible) : + HeapRegionClosure(), + _cm(cm), + _bitmap(cm->next_mark_bitmap()), + _suspendible(suspendible) + { } + virtual bool do_heap_region(HeapRegion* r) { - size_t const chunk_size_in_words = G1ClearBitMapTask::chunk_size() / HeapWordSize; + if (has_aborted()) { + return true; + } HeapWord* cur = r->bottom(); - HeapWord* const end = r->end(); + HeapWord* const end = region_clear_limit(r); + + size_t const chunk_size_in_words = G1ClearBitMapTask::chunk_size() / HeapWordSize; while (cur < end) { - // Abort iteration if necessary. - if (_cm != NULL) { - _cm->do_yield_check(); - if (_cm->has_aborted()) { - return true; - } - } MemRegion mr(cur, MIN2(cur + chunk_size_in_words, end)); _bitmap->clear_range(mr); @@ -614,10 +650,15 @@ class G1ClearBitMapTask : public AbstractGangTask { // as asserts here to minimize their overhead on the product. However, we // will have them as guarantees at the beginning / end of the bitmap // clearing to get some checking in the product. - assert(_cm == NULL || _cm->cm_thread()->in_progress(), "invariant"); - assert(_cm == NULL || !G1CollectedHeap::heap()->collector_state()->mark_or_rebuild_in_progress(), "invariant"); + assert(!suspendible() || _cm->cm_thread()->in_progress(), "invariant"); + assert(!suspendible() || !G1CollectedHeap::heap()->collector_state()->mark_or_rebuild_in_progress(), "invariant"); + + // Abort iteration if necessary. + if (has_aborted()) { + return true; + } } - assert(cur == end, "Must have completed iteration over the bitmap for region %u.", r->hrm_index()); + assert(cur >= end, "Must have completed iteration over the bitmap for region %u.", r->hrm_index()); return false; } @@ -628,9 +669,9 @@ class G1ClearBitMapTask : public AbstractGangTask { bool _suspendible; // If the task is suspendible, workers must join the STS. public: - G1ClearBitMapTask(G1CMBitMap* bitmap, G1ConcurrentMark* cm, uint n_workers, bool suspendible) : + G1ClearBitMapTask(G1ConcurrentMark* cm, uint n_workers, bool suspendible) : AbstractGangTask("G1 Clear Bitmap"), - _cl(bitmap, suspendible ? cm : NULL), + _cl(cm, suspendible), _hr_claimer(n_workers), _suspendible(suspendible) { } @@ -645,7 +686,7 @@ class G1ClearBitMapTask : public AbstractGangTask { } }; -void G1ConcurrentMark::clear_bitmap(G1CMBitMap* bitmap, WorkGang* workers, bool may_yield) { +void G1ConcurrentMark::clear_next_bitmap(WorkGang* workers, bool may_yield) { assert(may_yield || SafepointSynchronize::is_at_safepoint(), "Non-yielding bitmap clear only allowed at safepoint."); size_t const num_bytes_to_clear = (HeapRegion::GrainBytes * _g1h->num_regions()) / G1CMBitMap::heap_map_factor(); @@ -653,7 +694,7 @@ void G1ConcurrentMark::clear_bitmap(G1CMBitMap* bitmap, WorkGang* workers, bool uint const num_workers = (uint)MIN2(num_chunks, (size_t)workers->active_workers()); - G1ClearBitMapTask cl(bitmap, this, num_workers, may_yield); + G1ClearBitMapTask cl(this, num_workers, may_yield); log_debug(gc, ergo)("Running %s with %u workers for " SIZE_FORMAT " work units.", cl.name(), num_workers, num_chunks); workers->run_task(&cl, num_workers); @@ -671,7 +712,7 @@ void G1ConcurrentMark::cleanup_for_next_mark() { // is the case. guarantee(!_g1h->collector_state()->mark_or_rebuild_in_progress(), "invariant"); - clear_bitmap(_next_mark_bitmap, _concurrent_workers, true); + clear_next_bitmap(_concurrent_workers, true); // Repeat the asserts from above. guarantee(cm_thread()->in_progress(), "invariant"); @@ -685,7 +726,7 @@ void G1ConcurrentMark::clear_next_bitmap(WorkGang* workers) { // as efficiently as possible the number of active workers are temporarily // increased to include all currently created workers. WithUpdatedActiveWorkers update(workers, workers->created_workers()); - clear_bitmap(_next_mark_bitmap, workers, false); + clear_next_bitmap(workers, false); } class NoteStartOfMarkHRClosure : public HeapRegionClosure { diff --git a/src/hotspot/share/gc/g1/g1ConcurrentMark.hpp b/src/hotspot/share/gc/g1/g1ConcurrentMark.hpp index 99812c53f127f..84eab67a554b7 100644 --- a/src/hotspot/share/gc/g1/g1ConcurrentMark.hpp +++ b/src/hotspot/share/gc/g1/g1ConcurrentMark.hpp @@ -444,9 +444,9 @@ class G1ConcurrentMark : public CHeapObj { void enter_first_sync_barrier(uint worker_id); void enter_second_sync_barrier(uint worker_id); - // Clear the given bitmap in parallel using the given WorkGang. If may_yield is + // Clear the next marking bitmap in parallel using the given WorkGang. If may_yield is // true, periodically insert checks to see if this method should exit prematurely. - void clear_bitmap(G1CMBitMap* bitmap, WorkGang* workers, bool may_yield); + void clear_next_bitmap(WorkGang* workers, bool may_yield); // Region statistics gathered during marking. G1RegionMarkStats* _region_mark_stats; diff --git a/src/hotspot/share/gc/g1/g1ConcurrentMarkThread.cpp b/src/hotspot/share/gc/g1/g1ConcurrentMarkThread.cpp index f03bbb42a7b9e..dde620e9398f8 100644 --- a/src/hotspot/share/gc/g1/g1ConcurrentMarkThread.cpp +++ b/src/hotspot/share/gc/g1/g1ConcurrentMarkThread.cpp @@ -324,6 +324,8 @@ void G1ConcurrentMarkThread::concurrent_undo_cycle_do() { // some reason. if (_cm->has_aborted()) { return; } + _cm->flush_all_task_caches(); + // Phase 1: Clear bitmap for next mark. phase_clear_bitmap_for_next_mark(); } diff --git a/src/hotspot/share/gc/g1/g1ConcurrentMarkThread.hpp b/src/hotspot/share/gc/g1/g1ConcurrentMarkThread.hpp index 1a57e5bfd7e0e..c3503eea7bd0b 100644 --- a/src/hotspot/share/gc/g1/g1ConcurrentMarkThread.hpp +++ b/src/hotspot/share/gc/g1/g1ConcurrentMarkThread.hpp @@ -108,6 +108,8 @@ class G1ConcurrentMarkThread: public ConcurrentGCThread { // marking bitmap has been cleared and in_progress() is // cleared). bool in_progress() const; + + bool in_undo_mark() const; }; #endif // SHARE_GC_G1_G1CONCURRENTMARKTHREAD_HPP diff --git a/src/hotspot/share/gc/g1/g1ConcurrentMarkThread.inline.hpp b/src/hotspot/share/gc/g1/g1ConcurrentMarkThread.inline.hpp index ce0944314e30e..52ebf1c6e37ac 100644 --- a/src/hotspot/share/gc/g1/g1ConcurrentMarkThread.inline.hpp +++ b/src/hotspot/share/gc/g1/g1ConcurrentMarkThread.inline.hpp @@ -60,4 +60,8 @@ inline bool G1ConcurrentMarkThread::in_progress() const { return !idle(); } +inline bool G1ConcurrentMarkThread::in_undo_mark() const { + return _state == UndoMark; +} + #endif // SHARE_GC_G1_G1CONCURRENTMARKTHREAD_INLINE_HPP diff --git a/src/hotspot/share/gc/g1/g1DirtyCardQueue.cpp b/src/hotspot/share/gc/g1/g1DirtyCardQueue.cpp index 0a4a6c40d235e..15e5d57495172 100644 --- a/src/hotspot/share/gc/g1/g1DirtyCardQueue.cpp +++ b/src/hotspot/share/gc/g1/g1DirtyCardQueue.cpp @@ -546,8 +546,6 @@ void G1DirtyCardQueueSet::abandon_logs() { } } closure(*this); Threads::threads_do(&closure); - - G1BarrierSet::shared_dirty_card_queue().reset(); } void G1DirtyCardQueueSet::concatenate_logs() { @@ -571,7 +569,6 @@ void G1DirtyCardQueueSet::concatenate_logs() { } closure(*this); Threads::threads_do(&closure); - G1BarrierSet::shared_dirty_card_queue().flush(); enqueue_all_paused_buffers(); verify_num_cards(); set_max_cards(old_limit); diff --git a/src/hotspot/share/gc/g1/g1FullCollector.cpp b/src/hotspot/share/gc/g1/g1FullCollector.cpp index b52c14eb31de3..46f3804668ef1 100644 --- a/src/hotspot/share/gc/g1/g1FullCollector.cpp +++ b/src/hotspot/share/gc/g1/g1FullCollector.cpp @@ -224,8 +224,7 @@ void G1FullCollector::complete_collection() { void G1FullCollector::before_marking_update_attribute_table(HeapRegion* hr) { if (hr->is_free()) { - // Set as Invalid by default. - _region_attr_table.verify_is_invalid(hr->hrm_index()); + _region_attr_table.set_free(hr->hrm_index()); } else if (hr->is_closed_archive()) { _region_attr_table.set_skip_marking(hr->hrm_index()); } else if (hr->is_pinned()) { diff --git a/src/hotspot/share/gc/g1/g1FullCollector.hpp b/src/hotspot/share/gc/g1/g1FullCollector.hpp index 176d7b9f5ce4a..1f9c12abd241e 100644 --- a/src/hotspot/share/gc/g1/g1FullCollector.hpp +++ b/src/hotspot/share/gc/g1/g1FullCollector.hpp @@ -31,6 +31,8 @@ #include "gc/g1/g1FullGCOopClosures.hpp" #include "gc/g1/g1FullGCScope.hpp" #include "gc/g1/g1RegionMarkStatsCache.hpp" +#include "gc/shared/gcId.hpp" +#include "gc/shared/gcTraceTime.hpp" #include "gc/shared/preservedMarks.hpp" #include "gc/shared/referenceProcessor.hpp" #include "gc/shared/taskqueue.hpp" @@ -55,6 +57,16 @@ class G1FullGCSubjectToDiscoveryClosure: public BoolObjectClosure { } }; +// Full GC Mark that holds GC id and CPU time trace. Needs to be separate +// from the G1FullCollector and G1FullGCScope to allow the Full GC logging +// to have the same structure as the Young GC logging. +class G1FullGCMark : StackObj { + GCIdMark _gc_id; + GCTraceCPUTime _cpu_time; +public: + G1FullGCMark() : _gc_id(), _cpu_time() { } +}; + // The G1FullCollector holds data associated with the current Full GC. class G1FullCollector : StackObj { G1CollectedHeap* _heap; @@ -109,7 +121,8 @@ class G1FullCollector : StackObj { inline bool is_skip_compacting(uint region_index) const; inline bool is_skip_marking(oop obj) const; - inline void set_invalid(uint region_idx); + inline void set_free(uint region_idx); + inline bool is_free(uint region_idx) const; inline void update_from_compacting_to_skip_compacting(uint region_idx); private: diff --git a/src/hotspot/share/gc/g1/g1FullCollector.inline.hpp b/src/hotspot/share/gc/g1/g1FullCollector.inline.hpp index 69b48a123fd3e..5a0863b202a07 100644 --- a/src/hotspot/share/gc/g1/g1FullCollector.inline.hpp +++ b/src/hotspot/share/gc/g1/g1FullCollector.inline.hpp @@ -43,8 +43,12 @@ bool G1FullCollector::is_skip_marking(oop obj) const { return _region_attr_table.is_skip_marking(cast_from_oop(obj)); } -void G1FullCollector::set_invalid(uint region_idx) { - _region_attr_table.set_invalid(region_idx); +void G1FullCollector::set_free(uint region_idx) { + _region_attr_table.set_free(region_idx); +} + +bool G1FullCollector::is_free(uint region_idx) const { + return _region_attr_table.is_free(region_idx); } void G1FullCollector::update_from_compacting_to_skip_compacting(uint region_idx) { diff --git a/src/hotspot/share/gc/g1/g1FullGCCompactTask.cpp b/src/hotspot/share/gc/g1/g1FullGCCompactTask.cpp index a7aec46d2eef3..d0dc0593d3bbc 100644 --- a/src/hotspot/share/gc/g1/g1FullGCCompactTask.cpp +++ b/src/hotspot/share/gc/g1/g1FullGCCompactTask.cpp @@ -79,13 +79,17 @@ size_t G1FullGCCompactTask::G1CompactRegionClosure::apply(oop obj) { void G1FullGCCompactTask::compact_region(HeapRegion* hr) { assert(!hr->is_pinned(), "Should be no pinned region in compaction queue"); assert(!hr->is_humongous(), "Should be no humongous regions in compaction queue"); - G1CompactRegionClosure compact(collector()->mark_bitmap()); - hr->apply_to_marked_objects(collector()->mark_bitmap(), &compact); - // Clear the liveness information for this region if necessary i.e. if we actually look at it - // for bitmap verification. Otherwise it is sufficient that we move the TAMS to bottom(). - if (G1VerifyBitmaps) { - collector()->mark_bitmap()->clear_region(hr); + + if (!collector()->is_free(hr->hrm_index())) { + G1CompactRegionClosure compact(collector()->mark_bitmap()); + hr->apply_to_marked_objects(collector()->mark_bitmap(), &compact); + // Clear the liveness information for this region if necessary i.e. if we actually look at it + // for bitmap verification. Otherwise it is sufficient that we move the TAMS to bottom(). + if (G1VerifyBitmaps) { + collector()->mark_bitmap()->clear_region(hr); + } } + hr->reset_compacted_after_full_gc(); } diff --git a/src/hotspot/share/gc/g1/g1FullGCHeapRegionAttr.hpp b/src/hotspot/share/gc/g1/g1FullGCHeapRegionAttr.hpp index 65fb062428047..ca2f970edde55 100644 --- a/src/hotspot/share/gc/g1/g1FullGCHeapRegionAttr.hpp +++ b/src/hotspot/share/gc/g1/g1FullGCHeapRegionAttr.hpp @@ -41,11 +41,12 @@ class G1FullGCHeapRegionAttr : public G1BiasedMappedArray { static const uint8_t Compacting = 0; // Region will be compacted. static const uint8_t SkipCompacting = 1; // Region should not be compacted, but otherwise handled as usual. static const uint8_t SkipMarking = 2; // Region contents are not even marked through, but contain live objects. + static const uint8_t Free = 3; // Regions is free. static const uint8_t Invalid = 255; - bool is_invalid(HeapWord* obj) const { - return get_by_address(obj) == Invalid; + bool is_free(HeapWord* obj) const { + return get_by_address(obj) == Free; } protected: @@ -57,14 +58,15 @@ class G1FullGCHeapRegionAttr : public G1BiasedMappedArray { void set_compacting(uint idx) { set_by_index(idx, Compacting); } void set_skip_marking(uint idx) { set_by_index(idx, SkipMarking); } void set_skip_compacting(uint idx) { set_by_index(idx, SkipCompacting); } + void set_free(uint idx) { set_by_index(idx, Free); } bool is_skip_marking(HeapWord* obj) const { - assert(!is_invalid(obj), "not initialized yet"); + assert(!is_free(obj), "Should not have objects in free regions."); return get_by_address(obj) == SkipMarking; } bool is_compacting(HeapWord* obj) const { - assert(!is_invalid(obj), "not initialized yet"); + assert(!is_free(obj), "Should not have objects in free regions."); return get_by_address(obj) == Compacting; } @@ -72,6 +74,10 @@ class G1FullGCHeapRegionAttr : public G1BiasedMappedArray { return get_by_index(idx) == SkipCompacting; } + bool is_free(uint idx) const { + return get_by_index(idx) == Free; + } + void verify_is_compacting(uint idx) { assert(get_by_index(idx) == Compacting, "invariant"); } void verify_is_invalid(uint idx) { assert(get_by_index(idx) == Invalid, "invariant"); } diff --git a/src/hotspot/share/gc/g1/g1FullGCMarker.inline.hpp b/src/hotspot/share/gc/g1/g1FullGCMarker.inline.hpp index 992cbb2321c83..3ef6375c3a4b5 100644 --- a/src/hotspot/share/gc/g1/g1FullGCMarker.inline.hpp +++ b/src/hotspot/share/gc/g1/g1FullGCMarker.inline.hpp @@ -64,7 +64,7 @@ inline bool G1FullGCMarker::mark_object(oop obj) { // Check if deduplicatable string. if (StringDedup::is_enabled() && - java_lang_String::is_instance_inlined(obj) && + java_lang_String::is_instance(obj) && G1StringDedup::is_candidate_from_mark(obj)) { _string_dedup_requests.add(obj); } diff --git a/src/hotspot/share/gc/g1/g1FullGCPrepareTask.cpp b/src/hotspot/share/gc/g1/g1FullGCPrepareTask.cpp index cc486aa8e7a8a..817966a273bbf 100644 --- a/src/hotspot/share/gc/g1/g1FullGCPrepareTask.cpp +++ b/src/hotspot/share/gc/g1/g1FullGCPrepareTask.cpp @@ -47,8 +47,8 @@ void G1FullGCPrepareTask::G1CalculatePointersClosure::free_pinned_region(HeapReg } else { _g1h->free_region(hr, nullptr); } + _collector->set_free(hr->hrm_index()); prepare_for_compaction(hr); - _collector->set_invalid(hr->hrm_index()); } bool G1FullGCPrepareTask::G1CalculatePointersClosure::do_heap_region(HeapRegion* hr) { @@ -182,9 +182,11 @@ size_t G1FullGCPrepareTask::G1RePrepareClosure::apply(oop obj) { void G1FullGCPrepareTask::G1CalculatePointersClosure::prepare_for_compaction_work(G1FullGCCompactionPoint* cp, HeapRegion* hr) { - G1PrepareCompactLiveClosure prepare_compact(cp); hr->set_compaction_top(hr->bottom()); - hr->apply_to_marked_objects(_bitmap, &prepare_compact); + if (!_collector->is_free(hr->hrm_index())) { + G1PrepareCompactLiveClosure prepare_compact(cp); + hr->apply_to_marked_objects(_bitmap, &prepare_compact); + } } void G1FullGCPrepareTask::G1CalculatePointersClosure::prepare_for_compaction(HeapRegion* hr) { diff --git a/src/hotspot/share/gc/g1/g1FullGCScope.cpp b/src/hotspot/share/gc/g1/g1FullGCScope.cpp index 3aef04b49e791..b4d3b3656034b 100644 --- a/src/hotspot/share/gc/g1/g1FullGCScope.cpp +++ b/src/hotspot/share/gc/g1/g1FullGCScope.cpp @@ -42,12 +42,10 @@ G1FullGCScope::G1FullGCScope(G1MonitoringSupport* monitoring_support, _rm(), _explicit_gc(explicit_gc), _g1h(G1CollectedHeap::heap()), - _gc_id(), _svc_marker(SvcGCMarker::FULL), _timer(), _tracer(), _active(), - _cpu_time(), _tracer_mark(&_timer, &_tracer), _soft_refs(clear_soft, _g1h->soft_ref_policy()), _monitoring_scope(monitoring_support, true /* full_gc */, true /* all_memory_pools_affected */), diff --git a/src/hotspot/share/gc/g1/g1FullGCScope.hpp b/src/hotspot/share/gc/g1/g1FullGCScope.hpp index 2be5dec2666b7..c0035b9052aa7 100644 --- a/src/hotspot/share/gc/g1/g1FullGCScope.hpp +++ b/src/hotspot/share/gc/g1/g1FullGCScope.hpp @@ -28,8 +28,6 @@ #include "gc/g1/g1CollectedHeap.hpp" #include "gc/g1/g1HeapTransition.hpp" #include "gc/g1/g1Trace.hpp" -#include "gc/shared/gcId.hpp" -#include "gc/shared/gcTraceTime.hpp" #include "gc/shared/gcTimer.hpp" #include "gc/shared/gcVMOperations.hpp" #include "gc/shared/isGCActiveMark.hpp" @@ -51,12 +49,10 @@ class G1FullGCScope : public StackObj { ResourceMark _rm; bool _explicit_gc; G1CollectedHeap* _g1h; - GCIdMark _gc_id; SvcGCMarker _svc_marker; STWGCTimer _timer; G1FullGCTracer _tracer; IsGCActiveMark _active; - GCTraceCPUTime _cpu_time; G1FullGCJFRTracerMark _tracer_mark; ClearedAllSoftRefs _soft_refs; G1MonitoringScope _monitoring_scope; diff --git a/src/hotspot/share/gc/g1/g1HeapRegionAttr.hpp b/src/hotspot/share/gc/g1/g1HeapRegionAttr.hpp index 50fc8b8ca97a2..2d8ae1fae4079 100644 --- a/src/hotspot/share/gc/g1/g1HeapRegionAttr.hpp +++ b/src/hotspot/share/gc/g1/g1HeapRegionAttr.hpp @@ -39,6 +39,8 @@ struct G1HeapRegionAttr { #else typedef int8_t region_type_t; #endif + // _needs_remset_update_t is essentially bool, but we need precise control + // on the size, and sizeof(bool) is implementation specific. typedef uint8_t needs_remset_update_t; private: diff --git a/src/hotspot/share/gc/g1/g1ParScanThreadState.cpp b/src/hotspot/share/gc/g1/g1ParScanThreadState.cpp index dc2614f3fcd1f..2727f45268e93 100644 --- a/src/hotspot/share/gc/g1/g1ParScanThreadState.cpp +++ b/src/hotspot/share/gc/g1/g1ParScanThreadState.cpp @@ -31,7 +31,9 @@ #include "gc/g1/g1RootClosures.hpp" #include "gc/g1/g1StringDedup.hpp" #include "gc/g1/g1Trace.hpp" +#include "gc/g1/g1YoungGCEvacFailureInjector.inline.hpp" #include "gc/shared/partialArrayTaskStepper.inline.hpp" +#include "gc/shared/preservedMarks.inline.hpp" #include "gc/shared/stringdedup/stringDedup.hpp" #include "gc/shared/taskqueue.inline.hpp" #include "memory/allocation.inline.hpp" @@ -52,6 +54,7 @@ G1ParScanThreadState::G1ParScanThreadState(G1CollectedHeap* g1h, G1RedirtyCardsQueueSet* rdcqs, + PreservedMarks* preserved_marks, uint worker_id, uint n_workers, size_t young_cset_length, @@ -79,7 +82,9 @@ G1ParScanThreadState::G1ParScanThreadState(G1CollectedHeap* g1h, _string_dedup_requests(), _num_optional_regions(optional_cset_length), _numa(g1h->numa()), - _obj_alloc_stat(NULL) + _obj_alloc_stat(NULL), + _preserved_marks(preserved_marks), + _evacuation_failed_info() { // We allocate number of young gen regions in the collection set plus one // entries, since entry 0 keeps track of surviving bytes for non-young regions. @@ -108,6 +113,10 @@ size_t G1ParScanThreadState::flush(size_t* surviving_young_words) { _plab_allocator->flush_and_retire_stats(); _g1h->policy()->record_age_table(&_age_table); + if (_evacuation_failed_info.has_failed()) { + _g1h->gc_tracer_stw()->report_evacuation_failed(_evacuation_failed_info); + } + size_t sum = 0; for (uint i = 0; i < _surviving_words_length; i++) { surviving_young_words[i] += _surviving_young_words[i]; @@ -369,12 +378,12 @@ void G1ParScanThreadState::report_promotion_event(G1HeapRegionAttr const dest_at HeapWord * const obj_ptr, uint node_index) const { PLAB* alloc_buf = _plab_allocator->alloc_buffer(dest_attr, node_index); if (alloc_buf->contains(obj_ptr)) { - _g1h->_gc_tracer_stw->report_promotion_in_new_plab_event(old->klass(), word_sz * HeapWordSize, age, - dest_attr.type() == G1HeapRegionAttr::Old, - alloc_buf->word_sz() * HeapWordSize); + _g1h->gc_tracer_stw()->report_promotion_in_new_plab_event(old->klass(), word_sz * HeapWordSize, age, + dest_attr.type() == G1HeapRegionAttr::Old, + alloc_buf->word_sz() * HeapWordSize); } else { - _g1h->_gc_tracer_stw->report_promotion_outside_plab_event(old->klass(), word_sz * HeapWordSize, age, - dest_attr.type() == G1HeapRegionAttr::Old); + _g1h->gc_tracer_stw()->report_promotion_outside_plab_event(old->klass(), word_sz * HeapWordSize, age, + dest_attr.type() == G1HeapRegionAttr::Old); } } @@ -401,7 +410,7 @@ HeapWord* G1ParScanThreadState::allocate_copy_slow(G1HeapRegionAttr* dest_attr, } if (obj_ptr != NULL) { update_numa_stats(node_index); - if (_g1h->_gc_tracer_stw->should_report_promotion_events()) { + if (_g1h->gc_tracer_stw()->should_report_promotion_events()) { // The events are checked individually as part of the actual commit report_promotion_event(*dest_attr, old, word_sz, age, obj_ptr, node_index); } @@ -445,22 +454,20 @@ oop G1ParScanThreadState::do_copy_to_survivor_space(G1HeapRegionAttr const regio if (obj_ptr == NULL) { // This will either forward-to-self, or detect that someone else has // installed a forwarding pointer. - return handle_evacuation_failure_par(old, old_mark); + return handle_evacuation_failure_par(old, old_mark, word_sz); } } assert(obj_ptr != NULL, "when we get here, allocation should have succeeded"); assert(_g1h->is_in_reserved(obj_ptr), "Allocated memory should be in the heap"); -#ifndef PRODUCT // Should this evacuation fail? - if (_g1h->evacuation_should_fail()) { + if (_g1h->evac_failure_injector()->evacuation_should_fail()) { // Doing this after all the allocation attempts also tests the // undo_allocation() method too. undo_allocation(dest_attr, obj_ptr, word_sz, node_index); - return handle_evacuation_failure_par(old, old_mark); + return handle_evacuation_failure_par(old, old_mark, word_sz); } -#endif // !PRODUCT // We're going to allocate linearly, so might as well prefetch ahead. Prefetch::write(obj_ptr, PrefetchCopyIntervalInBytes); @@ -531,7 +538,8 @@ G1ParScanThreadState* G1ParScanThreadStateSet::state_for_worker(uint worker_id) assert(worker_id < _n_workers, "out of bounds access"); if (_states[worker_id] == NULL) { _states[worker_id] = - new G1ParScanThreadState(_g1h, _rdcqs, + new G1ParScanThreadState(_g1h, rdcqs(), + _preserved_marks_set->get(worker_id), worker_id, _n_workers, _young_cset_length, _optional_cset_length); } @@ -579,7 +587,7 @@ void G1ParScanThreadStateSet::record_unused_optional_region(HeapRegion* hr) { } NOINLINE -oop G1ParScanThreadState::handle_evacuation_failure_par(oop old, markWord m) { +oop G1ParScanThreadState::handle_evacuation_failure_par(oop old, markWord m, size_t word_sz) { assert(_g1h->is_in_cset(old), "Object " PTR_FORMAT " should be in the CSet", p2i(old)); oop forward_ptr = old->forward_to_atomic(old, m, memory_order_relaxed); @@ -591,7 +599,8 @@ oop G1ParScanThreadState::handle_evacuation_failure_par(oop old, markWord m) { _g1h->hr_printer()->evac_failure(r); } - _g1h->preserve_mark_during_evac_failure(_worker_id, old, m); + _preserved_marks->push_if_necessary(old, m); + _evacuation_failed_info.register_copy_failure(word_sz); G1ScanInYoungSetter x(&_scanner, r->is_young()); old->oop_iterate_backwards(&_scanner); @@ -637,11 +646,13 @@ void G1ParScanThreadState::update_numa_stats(uint node_index) { G1ParScanThreadStateSet::G1ParScanThreadStateSet(G1CollectedHeap* g1h, G1RedirtyCardsQueueSet* rdcqs, + PreservedMarksSet* preserved_marks_set, uint n_workers, size_t young_cset_length, size_t optional_cset_length) : _g1h(g1h), _rdcqs(rdcqs), + _preserved_marks_set(preserved_marks_set), _states(NEW_C_HEAP_ARRAY(G1ParScanThreadState*, n_workers, mtGC)), _surviving_young_words_total(NEW_C_HEAP_ARRAY(size_t, young_cset_length + 1, mtGC)), _young_cset_length(young_cset_length), diff --git a/src/hotspot/share/gc/g1/g1ParScanThreadState.hpp b/src/hotspot/share/gc/g1/g1ParScanThreadState.hpp index 75df743a9b8df..88d03520cf923 100644 --- a/src/hotspot/share/gc/g1/g1ParScanThreadState.hpp +++ b/src/hotspot/share/gc/g1/g1ParScanThreadState.hpp @@ -32,6 +32,7 @@ #include "gc/g1/g1RemSet.hpp" #include "gc/g1/heapRegionRemSet.inline.hpp" #include "gc/shared/ageTable.hpp" +#include "gc/shared/copyFailedInfo.hpp" #include "gc/shared/partialArrayTaskStepper.hpp" #include "gc/shared/stringdedup/stringDedup.hpp" #include "gc/shared/taskqueue.hpp" @@ -43,6 +44,8 @@ class G1OopStarChunkedList; class G1PLABAllocator; class G1EvacuationRootClosures; class HeapRegion; +class PreservedMarks; +class PreservedMarksSet; class outputStream; class G1ParScanThreadState : public CHeapObj { @@ -91,15 +94,21 @@ class G1ParScanThreadState : public CHeapObj { G1OopStarChunkedList* _oops_into_optional_regions; G1NUMA* _numa; - // Records how many object allocations happened at each node during copy to survivor. // Only starts recording when log of gc+heap+numa is enabled and its data is // transferred when flushed. size_t* _obj_alloc_stat; + // Per-thread evacuation failure data structures. + PreservedMarks* _preserved_marks; + EvacuationFailedInfo _evacuation_failed_info; + + void handle_evacuation_failure_notifications(oop obj, markWord m, size_t word_sz); + public: G1ParScanThreadState(G1CollectedHeap* g1h, G1RedirtyCardsQueueSet* rdcqs, + PreservedMarks* preserved_marks, uint worker_id, uint n_workers, size_t young_cset_length, @@ -213,7 +222,7 @@ class G1ParScanThreadState : public CHeapObj { void reset_trim_ticks(); // An attempt to evacuate "obj" has failed; take necessary steps. - oop handle_evacuation_failure_par(oop obj, markWord m); + oop handle_evacuation_failure_par(oop obj, markWord m, size_t word_sz); template inline void remember_root_into_optional_region(T* p); @@ -226,6 +235,7 @@ class G1ParScanThreadState : public CHeapObj { class G1ParScanThreadStateSet : public StackObj { G1CollectedHeap* _g1h; G1RedirtyCardsQueueSet* _rdcqs; + PreservedMarksSet* _preserved_marks_set; G1ParScanThreadState** _states; size_t* _surviving_young_words_total; size_t _young_cset_length; @@ -236,11 +246,15 @@ class G1ParScanThreadStateSet : public StackObj { public: G1ParScanThreadStateSet(G1CollectedHeap* g1h, G1RedirtyCardsQueueSet* rdcqs, + PreservedMarksSet* preserved_marks_set, uint n_workers, size_t young_cset_length, size_t optional_cset_length); ~G1ParScanThreadStateSet(); + G1RedirtyCardsQueueSet* rdcqs() { return _rdcqs; } + PreservedMarksSet* preserved_marks_set() { return _preserved_marks_set; } + void flush(); void record_unused_optional_region(HeapRegion* hr); diff --git a/src/hotspot/share/gc/g1/g1RegionToSpaceMapper.cpp b/src/hotspot/share/gc/g1/g1RegionToSpaceMapper.cpp index ecbb56d777052..8a5f27eff0a6f 100644 --- a/src/hotspot/share/gc/g1/g1RegionToSpaceMapper.cpp +++ b/src/hotspot/share/gc/g1/g1RegionToSpaceMapper.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2021, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -167,7 +167,7 @@ class G1RegionsSmallerThanCommitSizeMapper : public G1RegionToSpaceMapper { MEMFLAGS type) : G1RegionToSpaceMapper(rs, actual_size, page_size, alloc_granularity, commit_factor, type), _regions_per_page((page_size * commit_factor) / alloc_granularity), - _lock(Mutex::leaf, "G1 mapper lock", true, Mutex::_safepoint_check_never) { + _lock(Mutex::leaf, "G1 mapper lock", Mutex::_safepoint_check_never) { guarantee((page_size * commit_factor) >= alloc_granularity, "allocation granularity smaller than commit granularity"); } diff --git a/src/hotspot/share/gc/g1/g1RemSet.cpp b/src/hotspot/share/gc/g1/g1RemSet.cpp index 6e9508b47aea9..467b9d864f861 100644 --- a/src/hotspot/share/gc/g1/g1RemSet.cpp +++ b/src/hotspot/share/gc/g1/g1RemSet.cpp @@ -41,7 +41,6 @@ #include "gc/g1/g1RootClosures.hpp" #include "gc/g1/g1RemSet.hpp" #include "gc/g1/g1ServiceThread.hpp" -#include "gc/g1/g1SharedDirtyCardQueue.hpp" #include "gc/g1/g1_globals.hpp" #include "gc/g1/heapRegion.inline.hpp" #include "gc/g1/heapRegionManager.inline.hpp" @@ -1688,12 +1687,27 @@ void G1RemSet::refine_card_concurrently(CardValue* const card_ptr, return; } - // Re-dirty the card and enqueue in the *shared* queue. Can't use - // the thread-local queue, because that might be the queue that is - // being processed by us; we could be a Java thread conscripted to - // perform refinement on our queue's current buffer. + enqueue_for_reprocessing(card_ptr); +} + +// Re-dirty and re-enqueue the card to retry refinement later. +// This is used to deal with a rare race condition in concurrent refinement. +void G1RemSet::enqueue_for_reprocessing(CardValue* card_ptr) { + // We can't use the thread-local queue, because that might be the queue + // that is being processed by us; we could be a Java thread conscripted to + // perform refinement on our queue's current buffer. This situation only + // arises from rare race condition, so it's not worth any significant + // development effort or clever lock-free queue implementation. Instead + // we use brute force, allocating and enqueuing an entire buffer for just + // this card. Since buffers are processed in FIFO order and we try to + // keep some in the queue, it is likely that the racing state will have + // resolved by the time this card comes up for reprocessing. *card_ptr = G1CardTable::dirty_card_val(); - G1BarrierSet::shared_dirty_card_queue().enqueue(card_ptr); + G1DirtyCardQueueSet& dcqs = G1BarrierSet::dirty_card_queue_set(); + void** buffer = dcqs.allocate_buffer(); + size_t index = dcqs.buffer_size() - 1; + buffer[index] = card_ptr; + dcqs.enqueue_completed_buffer(BufferNode::make_node_from_buffer(buffer, index)); } void G1RemSet::print_periodic_summary_info(const char* header, uint period_count) { diff --git a/src/hotspot/share/gc/g1/g1RemSet.hpp b/src/hotspot/share/gc/g1/g1RemSet.hpp index 874ccd3c8f5be..7bc463650f033 100644 --- a/src/hotspot/share/gc/g1/g1RemSet.hpp +++ b/src/hotspot/share/gc/g1/g1RemSet.hpp @@ -57,6 +57,9 @@ class HeapRegionClaimer; // external heap references into it. Uses a mod ref bs to track updates, // so that they can be used to update the individual region remsets. class G1RemSet: public CHeapObj { +public: + typedef CardTable::CardValue CardValue; + private: G1RemSetScanState* _scan_state; @@ -72,10 +75,10 @@ class G1RemSet: public CHeapObj { void print_merge_heap_roots_stats(); void assert_scan_top_is_null(uint hrm_index) NOT_DEBUG_RETURN; -public: - typedef CardTable::CardValue CardValue; + void enqueue_for_reprocessing(CardValue* card_ptr); +public: // Initialize data that depends on the heap size being known. void initialize(uint max_reserved_regions); diff --git a/src/hotspot/share/gc/g1/g1ServiceThread.cpp b/src/hotspot/share/gc/g1/g1ServiceThread.cpp index fa4e14a0585f0..0a8b7f94cc012 100644 --- a/src/hotspot/share/gc/g1/g1ServiceThread.cpp +++ b/src/hotspot/share/gc/g1/g1ServiceThread.cpp @@ -42,7 +42,6 @@ G1ServiceThread::G1ServiceThread() : ConcurrentGCThread(), _monitor(Mutex::leaf, "G1ServiceThread monitor", - true, Monitor::_safepoint_check_never), _task_queue() { set_name("G1 Service"); diff --git a/src/hotspot/share/gc/g1/g1SharedDirtyCardQueue.cpp b/src/hotspot/share/gc/g1/g1SharedDirtyCardQueue.cpp deleted file mode 100644 index c7ade86926e47..0000000000000 --- a/src/hotspot/share/gc/g1/g1SharedDirtyCardQueue.cpp +++ /dev/null @@ -1,73 +0,0 @@ -/* - * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - * - */ - -#include "precompiled.hpp" -#include "gc/g1/g1DirtyCardQueue.hpp" -#include "gc/g1/g1SharedDirtyCardQueue.hpp" -#include "gc/shared/ptrQueue.hpp" -#include "runtime/mutex.hpp" -#include "runtime/mutexLocker.hpp" - -G1SharedDirtyCardQueue::G1SharedDirtyCardQueue(G1DirtyCardQueueSet* qset) : - _qset(qset), - _buffer(NULL), - _index(0) -{} - -G1SharedDirtyCardQueue::~G1SharedDirtyCardQueue() { - flush(); -} - -void G1SharedDirtyCardQueue::enqueue(void* card_ptr) { - MutexLocker ml(Shared_DirtyCardQ_lock, Mutex::_no_safepoint_check_flag); - if (_index == 0) { - flush(); - _buffer = _qset->allocate_buffer(); - _index = _qset->buffer_size(); - assert(_index != 0, "invariant"); - } - _buffer[--_index] = card_ptr; -} - -void G1SharedDirtyCardQueue::flush() { - if (_buffer != NULL) { - BufferNode* node = BufferNode::make_node_from_buffer(_buffer, _index); - _buffer = NULL; - _index = 0; - if (node->index() == _qset->buffer_size()) { - _qset->deallocate_buffer(node); - } else { - _qset->enqueue_completed_buffer(node); - } - } - assert(_index == 0, "invariant"); -} - -void G1SharedDirtyCardQueue::reset() { - if (_buffer == NULL) { - _index = 0; - } else { - _index = _qset->buffer_size(); - } -} diff --git a/src/hotspot/share/gc/g1/g1YoungGCEvacFailureInjector.cpp b/src/hotspot/share/gc/g1/g1YoungGCEvacFailureInjector.cpp new file mode 100644 index 0000000000000..478d7ae4c4c97 --- /dev/null +++ b/src/hotspot/share/gc/g1/g1YoungGCEvacFailureInjector.cpp @@ -0,0 +1,82 @@ +/* + * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +#include "precompiled.hpp" + +#include "gc/g1/g1CollectedHeap.inline.hpp" +#include "gc/g1/g1YoungGCEvacFailureInjector.inline.hpp" +#include "gc/g1/g1_globals.hpp" + +#ifndef PRODUCT + +bool G1YoungGCEvacFailureInjector::arm_if_needed_for_gc_type(bool for_young_gc, + bool during_concurrent_start, + bool mark_or_rebuild_in_progress) { + bool res = false; + if (mark_or_rebuild_in_progress) { + res |= G1EvacuationFailureALotDuringConcMark; + } + if (during_concurrent_start) { + res |= G1EvacuationFailureALotDuringConcurrentStart; + } + if (for_young_gc) { + res |= G1EvacuationFailureALotDuringYoungGC; + } else { + // GCs are mixed + res |= G1EvacuationFailureALotDuringMixedGC; + } + return res; +} + +void G1YoungGCEvacFailureInjector::arm_if_needed() { + if (G1EvacuationFailureALot) { + G1CollectedHeap* g1h = G1CollectedHeap::heap(); + // Check if we have gone over the interval. + const size_t gc_num = g1h->total_collections(); + const size_t elapsed_gcs = gc_num - _last_collection_with_evacuation_failure; + + _inject_evacuation_failure_for_current_gc = (elapsed_gcs >= G1EvacuationFailureALotInterval); + + // Now check if evacuation failure injection should be enabled for the current GC. + G1CollectorState* collector_state = g1h->collector_state(); + const bool in_young_only_phase = collector_state->in_young_only_phase(); + const bool in_concurrent_start_gc = collector_state->in_concurrent_start_gc(); + const bool mark_or_rebuild_in_progress = collector_state->mark_or_rebuild_in_progress(); + + _inject_evacuation_failure_for_current_gc &= + arm_if_needed_for_gc_type(in_young_only_phase, + in_concurrent_start_gc, + mark_or_rebuild_in_progress); + } +} + +void G1YoungGCEvacFailureInjector::reset() { + if (G1EvacuationFailureALot) { + _last_collection_with_evacuation_failure = G1CollectedHeap::heap()->total_collections(); + _evacuation_failure_object_count = 0; + _inject_evacuation_failure_for_current_gc = false; + } +} + +#endif // #ifndef PRODUCT diff --git a/src/hotspot/share/gc/g1/g1YoungGCEvacFailureInjector.hpp b/src/hotspot/share/gc/g1/g1YoungGCEvacFailureInjector.hpp new file mode 100644 index 0000000000000..8318675d11e08 --- /dev/null +++ b/src/hotspot/share/gc/g1/g1YoungGCEvacFailureInjector.hpp @@ -0,0 +1,71 @@ +/* + * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +#ifndef SHARE_GC_G1_G1YOUNGGCEVACUATIONFAILUREINJECTOR_HPP +#define SHARE_GC_G1_G1YOUNGGCEVACUATIONFAILUREINJECTOR_HPP + +#include "memory/allStatic.hpp" +#include "utilities/globalDefinitions.hpp" + +// Support for injecting evacuation failures based on the G1EvacuationFailureALot* +// flags. Analogous to PromotionFailureALot for the other collectors. +// +// Every G1EvacuationFailureALotInterval collections without evacuation failure +// inbetween we "arm" the injector to induce evacuation failures after +// G1EvacuationFailureALotCount successful evacuations. +// +// Available only in non-product builds. +class G1YoungGCEvacFailureInjector { +#ifndef PRODUCT + // Should we inject evacuation failures in the current GC. + bool _inject_evacuation_failure_for_current_gc; + + // Records the number of the last collection when evacuation failure happened. + // Used to determine whether evacuation failure injection should be in effect + // for the current GC. + size_t _last_collection_with_evacuation_failure; + + // The number of evacuations between induced failures. + volatile size_t _evacuation_failure_object_count; +#endif + + bool arm_if_needed_for_gc_type(bool for_young_gc, + bool during_concurrent_start, + bool mark_or_rebuild_in_progress) PRODUCT_RETURN_( return false; ); +public: + + // Arm the evacuation failure injector if needed for the current + // GC (based upon the type of GC and which command line flags are set); + void arm_if_needed() PRODUCT_RETURN; + + // Return true if it's time to cause an evacuation failure. + bool evacuation_should_fail() PRODUCT_RETURN_( return false; ); + + // Reset the evacuation failure injection counters. Should be called at + // the end of an evacuation pause in which an evacuation failure occurred. + void reset() PRODUCT_RETURN; +}; + +#endif /* SHARE_GC_G1_G1YOUNGGCEVACUATIONFAILUREINJECTOR_HPP */ + diff --git a/src/hotspot/share/gc/g1/g1SharedDirtyCardQueue.hpp b/src/hotspot/share/gc/g1/g1YoungGCEvacFailureInjector.inline.hpp similarity index 51% rename from src/hotspot/share/gc/g1/g1SharedDirtyCardQueue.hpp rename to src/hotspot/share/gc/g1/g1YoungGCEvacFailureInjector.inline.hpp index 2f28e2f630030..6bf14e29eeb2a 100644 --- a/src/hotspot/share/gc/g1/g1SharedDirtyCardQueue.hpp +++ b/src/hotspot/share/gc/g1/g1YoungGCEvacFailureInjector.inline.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -22,37 +22,30 @@ * */ -#ifndef SHARE_GC_G1_G1SHAREDDIRTYCARDQUEUE_HPP -#define SHARE_GC_G1_G1SHAREDDIRTYCARDQUEUE_HPP +#ifndef SHARE_GC_G1_G1YOUNGGCEVACUATIONFAILUREINJECTOR_INLINE_HPP +#define SHARE_GC_G1_G1YOUNGGCEVACUATIONFAILUREINJECTOR_INLINE_HPP -#include "utilities/globalDefinitions.hpp" +#include "gc/g1/g1_globals.hpp" +#include "gc/g1/g1CollectedHeap.inline.hpp" +#include "gc/g1/g1YoungGCEvacFailureInjector.hpp" -class G1DirtyCardQueueSet; +#ifndef PRODUCT -// A dirty card queue providing thread-safe enqueue. A shared global -// instance can be used for cases where a thread-local dirty card can't -// be used. -class G1SharedDirtyCardQueue { - G1DirtyCardQueueSet* const _qset; - void** _buffer; - size_t _index; +inline bool G1YoungGCEvacFailureInjector::evacuation_should_fail() { + if (!G1EvacuationFailureALot || !_inject_evacuation_failure_for_current_gc) { + return false; + } + // Injecting evacuation failures is in effect for current GC + // Access to _evacuation_failure_alot_count is not atomic; + // the value does not have to be exact. + if (++_evacuation_failure_object_count < G1EvacuationFailureALotCount) { + return false; + } + _evacuation_failure_object_count = 0; + return true; +} - NONCOPYABLE(G1SharedDirtyCardQueue); +#endif // #ifndef PRODUCT -public: - G1SharedDirtyCardQueue(G1DirtyCardQueueSet* qset); - ~G1SharedDirtyCardQueue(); // flushes the queue. +#endif /* SHARE_GC_G1_G1YOUNGGCEVACUATIONFAILUREINJECTOR_INLINE_HPP */ - // Thread-safe addition to shared logging buffer. - void enqueue(void* card_ptr); - - // Flush any pending entries to the qset and remove the buffer. - // Not thread-safe. - void flush(); - - // Discard any pending entries. - // Not thread-safe. - void reset(); -}; - -#endif // SHARE_GC_G1_G1SHAREDDIRTYCARDQUEUE_HPP diff --git a/src/hotspot/share/gc/g1/g1YoungGCPostEvacuateTasks.cpp b/src/hotspot/share/gc/g1/g1YoungGCPostEvacuateTasks.cpp index 5891ff7436839..46acb07039798 100644 --- a/src/hotspot/share/gc/g1/g1YoungGCPostEvacuateTasks.cpp +++ b/src/hotspot/share/gc/g1/g1YoungGCPostEvacuateTasks.cpp @@ -34,11 +34,11 @@ #include "gc/g1/g1ParScanThreadState.hpp" #include "gc/g1/g1RemSet.hpp" #include "gc/g1/g1YoungGCPostEvacuateTasks.hpp" +#include "gc/shared/preservedMarks.inline.hpp" #include "jfr/jfrEvents.hpp" #include "utilities/ticks.hpp" -G1PostEvacuateCollectionSetCleanupTask1::G1PostEvacuateCollectionSetCleanupTask1(G1ParScanThreadStateSet* per_thread_states, - G1RedirtyCardsQueueSet* rdcqs) : +G1PostEvacuateCollectionSetCleanupTask1::G1PostEvacuateCollectionSetCleanupTask1(G1ParScanThreadStateSet* per_thread_states) : G1BatchedGangTask("Post Evacuate Cleanup 1", G1CollectedHeap::heap()->phase_times()) { add_serial_task(new MergePssTask(per_thread_states)); @@ -47,7 +47,7 @@ G1PostEvacuateCollectionSetCleanupTask1::G1PostEvacuateCollectionSetCleanupTask1 add_serial_task(new SampleCollectionSetCandidatesTask()); } if (RemoveSelfForwardPtrsTask::should_execute()) { - add_parallel_task(new RemoveSelfForwardPtrsTask(rdcqs)); + add_parallel_task(new RemoveSelfForwardPtrsTask(per_thread_states->rdcqs())); } add_parallel_task(G1CollectedHeap::heap()->rem_set()->create_cleanup_after_scan_heap_roots_task()); } @@ -601,10 +601,8 @@ void G1PostEvacuateCollectionSetCleanupTask2::FreeCollectionSetTask::do_work(uin cl.report_timing(); } -G1PostEvacuateCollectionSetCleanupTask2::G1PostEvacuateCollectionSetCleanupTask2(PreservedMarksSet* preserved_marks_set, - G1RedirtyCardsQueueSet* rdcqs, - G1EvacuationInfo* evacuation_info, - const size_t* surviving_young_words) : +G1PostEvacuateCollectionSetCleanupTask2::G1PostEvacuateCollectionSetCleanupTask2(G1ParScanThreadStateSet* per_thread_states, + G1EvacuationInfo* evacuation_info) : G1BatchedGangTask("Post Evacuate Cleanup 2", G1CollectedHeap::heap()->phase_times()) { add_serial_task(new ResetHotCardCacheTask()); @@ -617,8 +615,8 @@ G1PostEvacuateCollectionSetCleanupTask2::G1PostEvacuateCollectionSetCleanupTask2 } if (RestorePreservedMarksTask::should_execute()) { - add_parallel_task(new RestorePreservedMarksTask(preserved_marks_set)); + add_parallel_task(new RestorePreservedMarksTask(per_thread_states->preserved_marks_set())); } - add_parallel_task(new RedirtyLoggedCardsTask(rdcqs)); - add_parallel_task(new FreeCollectionSetTask(evacuation_info, surviving_young_words)); + add_parallel_task(new RedirtyLoggedCardsTask(per_thread_states->rdcqs())); + add_parallel_task(new FreeCollectionSetTask(evacuation_info, per_thread_states->surviving_young_words())); } diff --git a/src/hotspot/share/gc/g1/g1YoungGCPostEvacuateTasks.hpp b/src/hotspot/share/gc/g1/g1YoungGCPostEvacuateTasks.hpp index 511c3ba101ab0..549ea7f755f70 100644 --- a/src/hotspot/share/gc/g1/g1YoungGCPostEvacuateTasks.hpp +++ b/src/hotspot/share/gc/g1/g1YoungGCPostEvacuateTasks.hpp @@ -48,8 +48,7 @@ class G1PostEvacuateCollectionSetCleanupTask1 : public G1BatchedGangTask { class RemoveSelfForwardPtrsTask; public: - G1PostEvacuateCollectionSetCleanupTask1(G1ParScanThreadStateSet* per_thread_states, - G1RedirtyCardsQueueSet* rdcqs); + G1PostEvacuateCollectionSetCleanupTask1(G1ParScanThreadStateSet* per_thread_states); }; class G1PostEvacuateCollectionSetCleanupTask1::MergePssTask : public G1AbstractSubTask { @@ -114,10 +113,8 @@ class G1PostEvacuateCollectionSetCleanupTask2 : public G1BatchedGangTask { class FreeCollectionSetTask; public: - G1PostEvacuateCollectionSetCleanupTask2(PreservedMarksSet* preserved_marks_set, - G1RedirtyCardsQueueSet* rdcqs, - G1EvacuationInfo* evacuation_info, - const size_t* surviving_young_words); + G1PostEvacuateCollectionSetCleanupTask2(G1ParScanThreadStateSet* per_thread_states, + G1EvacuationInfo* evacuation_info); }; class G1PostEvacuateCollectionSetCleanupTask2::ResetHotCardCacheTask : public G1AbstractSubTask { diff --git a/src/hotspot/share/gc/g1/heapRegion.cpp b/src/hotspot/share/gc/g1/heapRegion.cpp index e884afe133b53..ed1f6134d4f53 100644 --- a/src/hotspot/share/gc/g1/heapRegion.cpp +++ b/src/hotspot/share/gc/g1/heapRegion.cpp @@ -233,7 +233,7 @@ HeapRegion::HeapRegion(uint hrm_index, _top(NULL), _compaction_top(NULL), _bot_part(bot, this), - _par_alloc_lock(Mutex::leaf, "HeapRegion par alloc lock", true), + _par_alloc_lock(Mutex::leaf, "HeapRegion par alloc lock", Mutex::_safepoint_check_always, true), _pre_dummy_top(NULL), _rem_set(NULL), _hrm_index(hrm_index), @@ -714,7 +714,8 @@ void HeapRegion::verify(VerifyOption vo, p += obj_size; } - if (!is_empty()) { + // Only regions in old generation contain valid BOT. + if (!is_empty() && !is_young()) { _bot_part.verify(); } diff --git a/src/hotspot/share/gc/g1/heapRegionRemSet.cpp b/src/hotspot/share/gc/g1/heapRegionRemSet.cpp index 9feab88fde74d..5c875d26753f2 100644 --- a/src/hotspot/share/gc/g1/heapRegionRemSet.cpp +++ b/src/hotspot/share/gc/g1/heapRegionRemSet.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2021, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -47,7 +47,7 @@ const char* HeapRegionRemSet::_short_state_strings[] = {"UNTRA", "UPDAT", "CMPL HeapRegionRemSet::HeapRegionRemSet(HeapRegion* hr, G1CardSetConfiguration* config) : - _m(Mutex::leaf + 1, FormatBuffer<128>("HeapRegionRemSet lock #%u", hr->hrm_index()), true, Monitor::_safepoint_check_never), + _m(Mutex::leaf + 1, FormatBuffer<128>("HeapRegionRemSet lock #%u", hr->hrm_index()), Monitor::_safepoint_check_never), _code_roots(), _card_set_mm(config, G1CardSetFreePool::free_list_pool()), _card_set(config, &_card_set_mm), diff --git a/src/hotspot/share/gc/parallel/parallelScavengeHeap.hpp b/src/hotspot/share/gc/parallel/parallelScavengeHeap.hpp index 752218a574b78..a3c92af436ac7 100644 --- a/src/hotspot/share/gc/parallel/parallelScavengeHeap.hpp +++ b/src/hotspot/share/gc/parallel/parallelScavengeHeap.hpp @@ -50,6 +50,26 @@ class PSAdaptiveSizePolicy; class PSCardTable; class PSHeapSummary; +// ParallelScavengeHeap is the implementation of CollectedHeap for Parallel GC. +// +// The heap is reserved up-front in a single contiguous block, split into two +// parts, the old and young generation. The old generation resides at lower +// addresses, the young generation at higher addresses. The boundary address +// between the generations is fixed. Within a generation, committed memory +// grows towards higher addresses. +// +// +// low high +// +// +-- generation boundary (fixed after startup) +// | +// |<- old gen (reserved) ->|<- young gen (reserved) ->| +// +---------------+--------+-----------------+--------+--------+--------+ +// | old | | eden | from | to | | +// | | | | (to) | (from) | | +// +---------------+--------+-----------------+--------+--------+--------+ +// |<- committed ->| |<- committed ->| +// class ParallelScavengeHeap : public CollectedHeap { friend class VMStructs; private: diff --git a/src/hotspot/share/gc/parallel/psCompactionManager.cpp b/src/hotspot/share/gc/parallel/psCompactionManager.cpp index ce690cb0ee4eb..3ea3c4a9c106b 100644 --- a/src/hotspot/share/gc/parallel/psCompactionManager.cpp +++ b/src/hotspot/share/gc/parallel/psCompactionManager.cpp @@ -93,7 +93,7 @@ void ParCompactionManager::initialize(ParMarkBitMap* mbm) { _shadow_region_array = new (ResourceObj::C_HEAP, mtGC) GrowableArray(10, mtGC); _shadow_region_monitor = new Monitor(Mutex::barrier, "CompactionManager monitor", - Mutex::_allow_vm_block_flag, Monitor::_safepoint_check_never); + Monitor::_safepoint_check_never); } void ParCompactionManager::reset_all_bitmap_query_caches() { diff --git a/src/hotspot/share/gc/parallel/psCompactionManager.inline.hpp b/src/hotspot/share/gc/parallel/psCompactionManager.inline.hpp index 45e8dae5aeba4..470c915889986 100644 --- a/src/hotspot/share/gc/parallel/psCompactionManager.inline.hpp +++ b/src/hotspot/share/gc/parallel/psCompactionManager.inline.hpp @@ -111,7 +111,7 @@ inline void ParCompactionManager::mark_and_push(T* p) { push(obj); if (StringDedup::is_enabled() && - java_lang_String::is_instance_inlined(obj) && + java_lang_String::is_instance(obj) && psStringDedup::is_candidate_from_mark(obj)) { _string_dedup_requests.add(obj); } diff --git a/src/hotspot/share/gc/parallel/psParallelCompact.cpp b/src/hotspot/share/gc/parallel/psParallelCompact.cpp index a787f98c00422..94eab7f86d6de 100644 --- a/src/hotspot/share/gc/parallel/psParallelCompact.cpp +++ b/src/hotspot/share/gc/parallel/psParallelCompact.cpp @@ -1792,7 +1792,7 @@ bool PSParallelCompact::invoke_no_policy(bool maximum_heap_compaction) { ref_processor()->start_discovery(maximum_heap_compaction); marking_start.update(); - marking_phase(vmthread_cm, maximum_heap_compaction, &_gc_tracer); + marking_phase(vmthread_cm, &_gc_tracer); bool max_on_system_gc = UseMaximumCompactionOnSystemGC && GCCause::is_user_requested_gc(gc_cause); @@ -2077,7 +2077,6 @@ class ParallelCompactRefProcProxyTask : public RefProcProxyTask { }; void PSParallelCompact::marking_phase(ParCompactionManager* cm, - bool maximum_heap_compaction, ParallelOldTracer *gc_tracer) { // Recursively traverse all live objects and mark them GCTraceTime(Info, gc, phases) tm("Marking Phase", &_gc_timer); @@ -2282,7 +2281,6 @@ void PSParallelCompact::prepare_region_draining_tasks(uint parallel_gc_threads) FillableRegionLogger region_logger; for (unsigned int id = to_space_id; id + 1 > old_space_id; --id) { SpaceInfo* const space_info = _space_info + id; - MutableSpace* const space = space_info->space(); HeapWord* const new_top = space_info->new_top(); const size_t beg_region = sd.addr_to_region_idx(space_info->dense_prefix()); @@ -3092,12 +3090,6 @@ bool PSParallelCompact::steal_unavailable_region(ParCompactionManager* cm, size_ // the shadow region by copying live objects from source regions of the unavailable one. Once // the unavailable region becomes available, the data in the shadow region will be copied back. // Shadow regions are empty regions in the to-space and regions between top and end of other spaces. -// -// For more details, please refer to §4.2 of the VEE'19 paper: -// Haoyu Li, Mingyu Wu, Binyu Zang, and Haibo Chen. 2019. ScissorGC: scalable and efficient -// compaction for Java full garbage collection. In Proceedings of the 15th ACM SIGPLAN/SIGOPS -// International Conference on Virtual Execution Environments (VEE 2019). ACM, New York, NY, USA, -// 108-121. DOI: https://doi.org/10.1145/3313808.3313820 void PSParallelCompact::initialize_shadow_regions(uint parallel_gc_threads) { const ParallelCompactData& sd = PSParallelCompact::summary_data(); diff --git a/src/hotspot/share/gc/parallel/psParallelCompact.hpp b/src/hotspot/share/gc/parallel/psParallelCompact.hpp index c4319a0806c60..0b8eb6b011675 100644 --- a/src/hotspot/share/gc/parallel/psParallelCompact.hpp +++ b/src/hotspot/share/gc/parallel/psParallelCompact.hpp @@ -950,7 +950,6 @@ inline void ParMarkBitMapClosure::decrement_words_remaining(size_t words) { // has been updated. KKK likely resides in a region to the left of the region // containing AAA. These AAA's have there references updated at the end in a // clean up phase. See the method PSParallelCompact::update_deferred_objects(). -// An alternate strategy is being investigated for this deferral of updating. // // Compaction is done on a region basis. A region that is ready to be filled is // put on a ready list and GC threads take region off the list and fill them. A @@ -961,6 +960,25 @@ inline void ParMarkBitMapClosure::decrement_words_remaining(size_t words) { // regions and regions compacting into themselves. There is always at least 1 // region that can be put on the ready list. The regions are atomically added // and removed from the ready list. +// +// During compaction, there is a natural task dependency among regions because +// destination regions may also be source regions themselves. Consequently, the +// destination regions are not available for processing until all live objects +// within them are evacuated to their destinations. These dependencies lead to +// limited thread utilization as threads spin waiting on regions to be ready. +// Shadow regions are utilized to address these region dependencies. The basic +// idea is that, if a region is unavailable because it still contains live +// objects and thus cannot serve as a destination momentarily, the GC thread +// may allocate a shadow region as a substitute destination and directly copy +// live objects into this shadow region. Live objects in the shadow region will +// be copied into the target destination region when it becomes available. +// +// For more details on shadow regions, please refer to §4.2 of the VEE'19 paper: +// Haoyu Li, Mingyu Wu, Binyu Zang, and Haibo Chen. 2019. ScissorGC: scalable +// and efficient compaction for Java full garbage collection. In Proceedings of +// the 15th ACM SIGPLAN/SIGOPS International Conference on Virtual Execution +// Environments (VEE 2019). ACM, New York, NY, USA, 108-121. DOI: +// https://doi.org/10.1145/3313808.3313820 class TaskQueue; @@ -1045,7 +1063,6 @@ class PSParallelCompact : AllStatic { // Mark live objects static void marking_phase(ParCompactionManager* cm, - bool maximum_heap_compaction, ParallelOldTracer *gc_tracer); // Compute the dense prefix for the designated space. This is an experimental @@ -1114,7 +1131,6 @@ class PSParallelCompact : AllStatic { DEBUG_ONLY(static void write_block_fill_histogram();) // Move objects to new locations. - static void compact_perm(ParCompactionManager* cm); static void compact(); // Add available regions to the stack and draining tasks to the task queue. diff --git a/src/hotspot/share/gc/parallel/psPromotionManager.inline.hpp b/src/hotspot/share/gc/parallel/psPromotionManager.inline.hpp index 582a587e37bbe..29053cd5c3555 100644 --- a/src/hotspot/share/gc/parallel/psPromotionManager.inline.hpp +++ b/src/hotspot/share/gc/parallel/psPromotionManager.inline.hpp @@ -287,7 +287,7 @@ inline oop PSPromotionManager::copy_unmarked_to_survivor_space(oop o, push_contents(new_obj); if (StringDedup::is_enabled() && - java_lang_String::is_instance_inlined(new_obj) && + java_lang_String::is_instance(new_obj) && psStringDedup::is_candidate_from_evacuation(new_obj, new_obj_is_tenured)) { _string_dedup_requests.add(o); } diff --git a/src/hotspot/share/gc/serial/defNewGeneration.cpp b/src/hotspot/share/gc/serial/defNewGeneration.cpp index 566b4eb3d6fba..63d33a14ac541 100644 --- a/src/hotspot/share/gc/serial/defNewGeneration.cpp +++ b/src/hotspot/share/gc/serial/defNewGeneration.cpp @@ -26,6 +26,7 @@ #include "gc/serial/defNewGeneration.inline.hpp" #include "gc/serial/serialGcRefProcProxyTask.hpp" #include "gc/serial/serialHeap.inline.hpp" +#include "gc/serial/serialStringDedup.inline.hpp" #include "gc/serial/tenuredGeneration.hpp" #include "gc/shared/adaptiveSizePolicy.hpp" #include "gc/shared/ageTable.inline.hpp" @@ -142,7 +143,8 @@ DefNewGeneration::DefNewGeneration(ReservedSpace rs, : Generation(rs, initial_size), _preserved_marks_set(false /* in_c_heap */), _promo_failure_drain_in_progress(false), - _should_allocate_from_space(false) + _should_allocate_from_space(false), + _string_dedup_requests() { MemRegion cmr((HeapWord*)_virtual_space.low(), (HeapWord*)_virtual_space.high()); @@ -601,6 +603,8 @@ void DefNewGeneration::collect(bool full, // Verify that the usage of keep_alive didn't copy any objects. assert(heap->no_allocs_since_save_marks(), "save marks have not been newly set."); + _string_dedup_requests.flush(); + if (!_promotion_failed) { // Swap the survivor spaces. eden()->clear(SpaceDecorator::Mangle); @@ -705,6 +709,7 @@ oop DefNewGeneration::copy_to_survivor_space(oop old) { obj = cast_to_oop(to()->allocate(s)); } + bool new_obj_is_tenured = false; // Otherwise try allocating obj tenured if (obj == NULL) { obj = _old_gen->promote(old, s); @@ -712,6 +717,7 @@ oop DefNewGeneration::copy_to_survivor_space(oop old) { handle_promotion_failure(old); return old; } + new_obj_is_tenured = true; } else { // Prefetch beyond obj const intx interval = PrefetchCopyIntervalInBytes; @@ -728,6 +734,11 @@ oop DefNewGeneration::copy_to_survivor_space(oop old) { // Done, insert forward pointer to obj in this header old->forward_to(obj); + if (SerialStringDedup::is_candidate_from_evacuation(obj, new_obj_is_tenured)) { + // Record old; request adds a new weak reference, which reference + // processing expects to refer to a from-space object. + _string_dedup_requests.add(old); + } return obj; } diff --git a/src/hotspot/share/gc/serial/defNewGeneration.hpp b/src/hotspot/share/gc/serial/defNewGeneration.hpp index a1e84b225fbb0..5ea7785256654 100644 --- a/src/hotspot/share/gc/serial/defNewGeneration.hpp +++ b/src/hotspot/share/gc/serial/defNewGeneration.hpp @@ -31,6 +31,7 @@ #include "gc/shared/generation.hpp" #include "gc/shared/generationCounters.hpp" #include "gc/shared/preservedMarks.hpp" +#include "gc/shared/stringdedup/stringDedup.hpp" #include "gc/shared/tlab_globals.hpp" #include "utilities/align.hpp" #include "utilities/stack.hpp" @@ -139,6 +140,8 @@ class DefNewGeneration: public Generation { STWGCTimer* _gc_timer; + StringDedup::Requests _string_dedup_requests; + enum SomeProtectedConstants { // Generations are GenGrain-aligned and have size that are multiples of // GenGrain. diff --git a/src/hotspot/share/gc/serial/genMarkSweep.cpp b/src/hotspot/share/gc/serial/genMarkSweep.cpp index 2adf17574f5e4..53356516aec4e 100644 --- a/src/hotspot/share/gc/serial/genMarkSweep.cpp +++ b/src/hotspot/share/gc/serial/genMarkSweep.cpp @@ -112,6 +112,8 @@ void GenMarkSweep::invoke_at_safepoint(ReferenceProcessor* rp, bool clear_all_so deallocate_stacks(); + MarkSweep::_string_dedup_requests->flush(); + // If compaction completely evacuated the young generation then we // can clear the card table. Otherwise, we must invalidate // it (consider all cards dirty). In the future, we might consider doing diff --git a/src/hotspot/share/gc/serial/markSweep.cpp b/src/hotspot/share/gc/serial/markSweep.cpp index 403a9f1481d87..8856ce2fee1cf 100644 --- a/src/hotspot/share/gc/serial/markSweep.cpp +++ b/src/hotspot/share/gc/serial/markSweep.cpp @@ -57,6 +57,8 @@ ReferenceProcessor* MarkSweep::_ref_processor = NULL; STWGCTimer* MarkSweep::_gc_timer = NULL; SerialOldTracer* MarkSweep::_gc_tracer = NULL; +StringDedup::Requests* MarkSweep::_string_dedup_requests = NULL; + MarkSweep::FollowRootClosure MarkSweep::follow_root_closure; MarkAndPushClosure MarkSweep::mark_and_push_closure; @@ -214,4 +216,5 @@ void MarkSweep::KeepAliveClosure::do_oop(narrowOop* p) { MarkSweep::KeepAliveClo void MarkSweep::initialize() { MarkSweep::_gc_timer = new (ResourceObj::C_HEAP, mtGC) STWGCTimer(); MarkSweep::_gc_tracer = new (ResourceObj::C_HEAP, mtGC) SerialOldTracer(); + MarkSweep::_string_dedup_requests = new StringDedup::Requests(); } diff --git a/src/hotspot/share/gc/serial/markSweep.hpp b/src/hotspot/share/gc/serial/markSweep.hpp index eb379b9a2c694..f3e818f3e4cd8 100644 --- a/src/hotspot/share/gc/serial/markSweep.hpp +++ b/src/hotspot/share/gc/serial/markSweep.hpp @@ -27,6 +27,7 @@ #include "gc/shared/collectedHeap.hpp" #include "gc/shared/genOopClosures.hpp" +#include "gc/shared/stringdedup/stringDedup.hpp" #include "gc/shared/taskqueue.hpp" #include "memory/iterator.hpp" #include "oops/markWord.hpp" @@ -111,6 +112,8 @@ class MarkSweep : AllStatic { static STWGCTimer* _gc_timer; static SerialOldTracer* _gc_tracer; + static StringDedup::Requests* _string_dedup_requests; + // Non public closures static KeepAliveClosure keep_alive; diff --git a/src/hotspot/share/gc/serial/markSweep.inline.hpp b/src/hotspot/share/gc/serial/markSweep.inline.hpp index 9dc5069922d23..6af4ffe3e3cd5 100644 --- a/src/hotspot/share/gc/serial/markSweep.inline.hpp +++ b/src/hotspot/share/gc/serial/markSweep.inline.hpp @@ -28,6 +28,8 @@ #include "gc/serial/markSweep.hpp" #include "classfile/classLoaderData.inline.hpp" +#include "classfile/javaClasses.inline.hpp" +#include "gc/serial/serialStringDedup.hpp" #include "memory/universe.hpp" #include "oops/markWord.hpp" #include "oops/access.inline.hpp" @@ -37,6 +39,12 @@ #include "utilities/stack.inline.hpp" inline void MarkSweep::mark_object(oop obj) { + if (StringDedup::is_enabled() && + java_lang_String::is_instance(obj) && + SerialStringDedup::is_candidate_from_mark(obj)) { + _string_dedup_requests->add(obj); + } + // some marks may contain information we need to preserve so we store them away // and overwrite the mark. We'll restore it at the end of markSweep. markWord mark = obj->mark(); diff --git a/src/hotspot/share/gc/serial/serialHeap.cpp b/src/hotspot/share/gc/serial/serialHeap.cpp index d9a8812d580ed..19ca138d8d1f4 100644 --- a/src/hotspot/share/gc/serial/serialHeap.cpp +++ b/src/hotspot/share/gc/serial/serialHeap.cpp @@ -28,6 +28,7 @@ #include "gc/serial/tenuredGeneration.inline.hpp" #include "gc/shared/genMemoryPools.hpp" #include "gc/shared/strongRootsScope.hpp" +#include "gc/shared/suspendibleThreadSet.hpp" #include "memory/universe.hpp" #include "services/memoryManager.hpp" @@ -99,3 +100,15 @@ void SerialHeap::young_process_roots(OopIterateClosure* root_closure, old_gen()->younger_refs_iterate(old_gen_closure); } + +void SerialHeap::safepoint_synchronize_begin() { + if (UseStringDeduplication) { + SuspendibleThreadSet::synchronize(); + } +} + +void SerialHeap::safepoint_synchronize_end() { + if (UseStringDeduplication) { + SuspendibleThreadSet::desynchronize(); + } +} diff --git a/src/hotspot/share/gc/serial/serialHeap.hpp b/src/hotspot/share/gc/serial/serialHeap.hpp index 91b65b896f8f3..8e79f21971ccd 100644 --- a/src/hotspot/share/gc/serial/serialHeap.hpp +++ b/src/hotspot/share/gc/serial/serialHeap.hpp @@ -80,6 +80,9 @@ class SerialHeap : public GenCollectedHeap { void young_process_roots(OopIterateClosure* root_closure, OopIterateClosure* old_gen_closure, CLDClosure* cld_closure); + + virtual void safepoint_synchronize_begin(); + virtual void safepoint_synchronize_end(); }; #endif // SHARE_GC_SERIAL_SERIALHEAP_HPP diff --git a/src/hotspot/share/gc/serial/serialStringDedup.cpp b/src/hotspot/share/gc/serial/serialStringDedup.cpp new file mode 100644 index 0000000000000..93910ae65d375 --- /dev/null +++ b/src/hotspot/share/gc/serial/serialStringDedup.cpp @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2021, Alibaba Group Holding Limited. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +#include "precompiled.hpp" +#include "gc/serial/defNewGeneration.hpp" +#include "gc/serial/serialHeap.hpp" +#include "gc/serial/serialStringDedup.hpp" +#include "oops/oop.inline.hpp" + +bool SerialStringDedup::is_candidate_from_mark(oop java_string) { + // Candidate if string is being evacuated from young to old but has not + // reached the deduplication age threshold, i.e. has not previously been a + // candidate during its life in the young generation. + return SerialHeap::heap()->young_gen()->is_in_reserved(java_string) && + StringDedup::is_below_threshold_age(java_string->age()); +} diff --git a/src/hotspot/share/gc/serial/serialStringDedup.hpp b/src/hotspot/share/gc/serial/serialStringDedup.hpp new file mode 100644 index 0000000000000..9d4548acf369d --- /dev/null +++ b/src/hotspot/share/gc/serial/serialStringDedup.hpp @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2021, Alibaba Group Holding Limited. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +#ifndef SHARE_GC_SERIAL_STRINGDEDUP_HPP +#define SHARE_GC_SERIAL_STRINGDEDUP_HPP + +#include "memory/allStatic.hpp" +#include "oops/oopsHierarchy.hpp" + +class SerialStringDedup : AllStatic { +public: + + // Candidate selection policy for full GC, returning true if the given + // String is a candidate for string deduplication. + // precondition: StringDedup::is_enabled() + // precondition: java_string is a Java String + static bool is_candidate_from_mark(oop java_string); + + // Candidate selection policy for young during evacuation. + static inline bool is_candidate_from_evacuation(oop obj, bool obj_is_tenured); + +}; + +#endif // SHARE_GC_SERIAL_STRINGDEDUP_HPP diff --git a/src/hotspot/share/gc/serial/serialStringDedup.inline.hpp b/src/hotspot/share/gc/serial/serialStringDedup.inline.hpp new file mode 100644 index 0000000000000..ebf29113a0bb8 --- /dev/null +++ b/src/hotspot/share/gc/serial/serialStringDedup.inline.hpp @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2021, Alibaba Group Holding Limited. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +#ifndef SHARE_GC_SERIAL_STRINGDEDUP_INLINE_HPP +#define SHARE_GC_SERIAL_STRINGDEDUP_INLINE_HPP + +#include "gc/serial/serialStringDedup.hpp" + +#include "classfile/javaClasses.inline.hpp" +#include "oops/oop.inline.hpp" + +bool SerialStringDedup::is_candidate_from_evacuation(oop obj, + bool obj_is_tenured) { + return StringDedup::is_enabled() && + java_lang_String::is_instance(obj) && + (obj_is_tenured ? + StringDedup::is_below_threshold_age(obj->age()) : + StringDedup::is_threshold_age(obj->age())); +} + +#endif // SHARE_GC_SERIAL_STRINGDEDUP_INLINE_HPP diff --git a/src/hotspot/share/gc/shared/gcLogPrecious.cpp b/src/hotspot/share/gc/shared/gcLogPrecious.cpp index eddbbdcf11d3c..b1a730829e657 100644 --- a/src/hotspot/share/gc/shared/gcLogPrecious.cpp +++ b/src/hotspot/share/gc/shared/gcLogPrecious.cpp @@ -35,7 +35,6 @@ void GCLogPrecious::initialize() { _temp = new (ResourceObj::C_HEAP, mtGC) stringStream(); _lock = new Mutex(Mutex::event, /* The lowest lock rank I could find */ "GCLogPrecious Lock", - true, Mutex::_safepoint_check_never); } diff --git a/src/hotspot/share/gc/shared/generation.hpp b/src/hotspot/share/gc/shared/generation.hpp index e769820d6fe09..452212ffd7224 100644 --- a/src/hotspot/share/gc/shared/generation.hpp +++ b/src/hotspot/share/gc/shared/generation.hpp @@ -126,11 +126,6 @@ class Generation: public CHeapObj { virtual Generation::Name kind() { return Generation::Other; } - // This properly belongs in the collector, but for now this - // will do. - virtual bool refs_discovery_is_atomic() const { return true; } - virtual bool refs_discovery_is_mt() const { return false; } - // Space inquiries (results in bytes) size_t initial_size(); virtual size_t capacity() const = 0; // The maximum number of object bytes the diff --git a/src/hotspot/share/gc/shared/oopStorage.cpp b/src/hotspot/share/gc/shared/oopStorage.cpp index 4869b6f03b5c1..b9ece642f9186 100644 --- a/src/hotspot/share/gc/shared/oopStorage.cpp +++ b/src/hotspot/share/gc/shared/oopStorage.cpp @@ -814,7 +814,7 @@ static Mutex* make_oopstorage_mutex(const char* storage_name, int rank) { char name[256]; os::snprintf(name, sizeof(name), "%s %s lock", storage_name, kind); - return new PaddedMutex(rank, name, true, Mutex::_safepoint_check_never); + return new PaddedMutex(rank, name, Mutex::_safepoint_check_never); } void* OopStorage::operator new(size_t size, MEMFLAGS memflags) { diff --git a/src/hotspot/share/gc/shared/space.cpp b/src/hotspot/share/gc/shared/space.cpp index 97f3599dd9a9e..e8e3a312f5094 100644 --- a/src/hotspot/share/gc/shared/space.cpp +++ b/src/hotspot/share/gc/shared/space.cpp @@ -777,7 +777,8 @@ HeapWord* OffsetTableContigSpace::cross_threshold(HeapWord* start, HeapWord* end OffsetTableContigSpace::OffsetTableContigSpace(BlockOffsetSharedArray* sharedOffsetArray, MemRegion mr) : _offsets(sharedOffsetArray, mr), - _par_alloc_lock(Mutex::leaf, "OffsetTableContigSpace par alloc lock", true) + _par_alloc_lock(Mutex::leaf, "OffsetTableContigSpace par alloc lock", + Mutex::_safepoint_check_always, true) { _offsets.set_contig_space(this); initialize(mr, SpaceDecorator::Clear, SpaceDecorator::Mangle); diff --git a/src/hotspot/share/gc/shared/stringdedup/stringDedup.hpp b/src/hotspot/share/gc/shared/stringdedup/stringDedup.hpp index 3484fe13e2a29..da220b93307f2 100644 --- a/src/hotspot/share/gc/shared/stringdedup/stringDedup.hpp +++ b/src/hotspot/share/gc/shared/stringdedup/stringDedup.hpp @@ -96,6 +96,7 @@ // For additional information on string deduplication, please see JEP 192, // http://openjdk.java.net/jeps/192 +#include "memory/allocation.hpp" #include "memory/allStatic.hpp" #include "oops/oopsHierarchy.hpp" #include "utilities/globalDefinitions.hpp" @@ -195,7 +196,7 @@ class StringDedup : public AllStatic { // Each marking thread should have it's own Requests object. When marking // is completed the Requests object must be flushed (either explicitly or by // the destructor). -class StringDedup::Requests { +class StringDedup::Requests : public CHeapObj { StorageUse* _storage_for_requests; oop** _buffer; size_t _index; diff --git a/src/hotspot/share/gc/shared/stringdedup/stringDedupConfig.cpp b/src/hotspot/share/gc/shared/stringdedup/stringDedupConfig.cpp index 2da8fb4c44cca..a01548a72b08d 100644 --- a/src/hotspot/share/gc/shared/stringdedup/stringDedupConfig.cpp +++ b/src/hotspot/share/gc/shared/stringdedup/stringDedupConfig.cpp @@ -116,7 +116,7 @@ size_t StringDedup::Config::desired_table_size(size_t entry_count) { bool StringDedup::Config::ergo_initialize() { if (!UseStringDeduplication) { return true; - } else if (!UseG1GC && !UseShenandoahGC && !UseZGC && !UseParallelGC) { + } else if (!UseG1GC && !UseShenandoahGC && !UseZGC && !UseParallelGC && !UseSerialGC) { // String deduplication requested but not supported by the selected GC. // Warn and force disable, but don't error except in debug build with // incorrect default. diff --git a/src/hotspot/share/gc/shared/taskTerminator.cpp b/src/hotspot/share/gc/shared/taskTerminator.cpp index b0d7663c296f1..59dd67c2230e5 100644 --- a/src/hotspot/share/gc/shared/taskTerminator.cpp +++ b/src/hotspot/share/gc/shared/taskTerminator.cpp @@ -72,7 +72,7 @@ TaskTerminator::TaskTerminator(uint n_threads, TaskQueueSetSuper* queue_set) : _n_threads(n_threads), _queue_set(queue_set), _offered_termination(0), - _blocker(Mutex::leaf, "TaskTerminator", false, Monitor::_safepoint_check_never), + _blocker(Mutex::leaf, "TaskTerminator", Monitor::_safepoint_check_never), _spin_master(NULL) { } TaskTerminator::~TaskTerminator() { diff --git a/src/hotspot/share/gc/shared/workgroup.cpp b/src/hotspot/share/gc/shared/workgroup.cpp index d197efef09dc6..795c1efebd153 100644 --- a/src/hotspot/share/gc/shared/workgroup.cpp +++ b/src/hotspot/share/gc/shared/workgroup.cpp @@ -266,13 +266,13 @@ void GangWorker::loop() { // *** WorkGangBarrierSync WorkGangBarrierSync::WorkGangBarrierSync() - : _monitor(Mutex::safepoint, "work gang barrier sync", true, + : _monitor(Mutex::safepoint, "work gang barrier sync", Monitor::_safepoint_check_never), _n_workers(0), _n_completed(0), _should_reset(false), _aborted(false) { } WorkGangBarrierSync::WorkGangBarrierSync(uint n_workers, const char* name) - : _monitor(Mutex::safepoint, name, true, Monitor::_safepoint_check_never), + : _monitor(Mutex::safepoint, name, Monitor::_safepoint_check_never), _n_workers(n_workers), _n_completed(0), _should_reset(false), _aborted(false) { } diff --git a/src/hotspot/share/gc/shenandoah/shenandoahConcurrentMark.cpp b/src/hotspot/share/gc/shenandoah/shenandoahConcurrentMark.cpp index 87c3ee8dc2090..214ab73a2a2c5 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahConcurrentMark.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahConcurrentMark.cpp @@ -86,9 +86,11 @@ class ShenandoahConcurrentMarkingTask : public AbstractGangTask { ShenandoahObjToScanQueue* q = _cm->get_queue(worker_id); ShenandoahReferenceProcessor* rp = heap->ref_processor(); assert(rp != NULL, "need reference processor"); + StringDedup::Requests requests; _cm->mark_loop(worker_id, _terminator, rp, true /*cancellable*/, - ShenandoahStringDedup::is_enabled() ? ENQUEUE_DEDUP : NO_DEDUP); + ShenandoahStringDedup::is_enabled() ? ENQUEUE_DEDUP : NO_DEDUP, + &requests); } }; @@ -134,6 +136,7 @@ class ShenandoahFinalMarkingTask : public AbstractGangTask { ShenandoahParallelWorkerSession worker_session(worker_id); ShenandoahReferenceProcessor* rp = heap->ref_processor(); + StringDedup::Requests requests; // First drain remaining SATB buffers. { @@ -144,14 +147,15 @@ class ShenandoahFinalMarkingTask : public AbstractGangTask { while (satb_mq_set.apply_closure_to_completed_buffer(&cl)) {} assert(!heap->has_forwarded_objects(), "Not expected"); - ShenandoahMarkRefsClosure mark_cl(q, rp); + ShenandoahMarkRefsClosure mark_cl(q, rp); ShenandoahSATBAndRemarkThreadsClosure tc(satb_mq_set, ShenandoahIUBarrier ? &mark_cl : NULL); Threads::threads_do(&tc); } _cm->mark_loop(worker_id, _terminator, rp, false /*not cancellable*/, - _dedup_string ? ENQUEUE_DEDUP : NO_DEDUP); + _dedup_string ? ENQUEUE_DEDUP : NO_DEDUP, + &requests); assert(_cm->task_queues()->is_empty(), "Should be empty"); } }; @@ -189,9 +193,7 @@ ShenandoahMarkConcurrentRootsTask::ShenandoahMarkConcurrentRootsTask(ShenandoahO void ShenandoahMarkConcurrentRootsTask::work(uint worker_id) { ShenandoahConcurrentWorkerSession worker_session(worker_id); ShenandoahObjToScanQueue* q = _queue_set->queue(worker_id); - // Cannot enable string deduplication during root scanning. Otherwise, - // may result lock inversion between stack watermark and string dedup queue lock. - ShenandoahMarkRefsClosure cl(q, _rp); + ShenandoahMarkRefsClosure cl(q, _rp); _root_scanner.roots_do(&cl, worker_id); } diff --git a/src/hotspot/share/gc/shenandoah/shenandoahControlThread.cpp b/src/hotspot/share/gc/shenandoah/shenandoahControlThread.cpp index a7e4fed5d5edb..97f1bfde2498e 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahControlThread.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahControlThread.cpp @@ -47,8 +47,8 @@ ShenandoahControlThread::ShenandoahControlThread() : ConcurrentGCThread(), - _alloc_failure_waiters_lock(Mutex::leaf, "ShenandoahAllocFailureGC_lock", true, Monitor::_safepoint_check_always), - _gc_waiters_lock(Mutex::leaf, "ShenandoahRequestedGC_lock", true, Monitor::_safepoint_check_always), + _alloc_failure_waiters_lock(Mutex::leaf, "ShenandoahAllocFailureGC_lock", Monitor::_safepoint_check_always, true), + _gc_waiters_lock(Mutex::leaf, "ShenandoahRequestedGC_lock", Monitor::_safepoint_check_always, true), _periodic_task(this), _requested_gc_cause(GCCause::_no_cause_specified), _degen_point(ShenandoahGC::_degenerated_outside_cycle), diff --git a/src/hotspot/share/gc/shenandoah/shenandoahMark.cpp b/src/hotspot/share/gc/shenandoah/shenandoahMark.cpp index 76edf786018e9..7fb77f381df3e 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahMark.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahMark.cpp @@ -36,7 +36,6 @@ ShenandoahMarkRefsSuperClosure::ShenandoahMarkRefsSuperClosure(ShenandoahObjToScanQueue* q, ShenandoahReferenceProcessor* rp) : MetadataVisitingOopIterateClosure(rp), - _stringDedup_requests(), _queue(q), _mark_context(ShenandoahHeap::heap()->marking_context()), _weak(false) @@ -56,7 +55,7 @@ void ShenandoahMark::clear() { } template -void ShenandoahMark::mark_loop_prework(uint w, TaskTerminator *t, ShenandoahReferenceProcessor *rp) { +void ShenandoahMark::mark_loop_prework(uint w, TaskTerminator *t, ShenandoahReferenceProcessor *rp, StringDedup::Requests* const req) { ShenandoahObjToScanQueue* q = get_queue(w); ShenandoahHeap* const heap = ShenandoahHeap::heap(); @@ -66,23 +65,23 @@ void ShenandoahMark::mark_loop_prework(uint w, TaskTerminator *t, ShenandoahRefe // play nice with specialized_oop_iterators. if (heap->unload_classes()) { if (heap->has_forwarded_objects()) { - using Closure = ShenandoahMarkUpdateRefsMetadataClosure; + using Closure = ShenandoahMarkUpdateRefsMetadataClosure; Closure cl(q, rp); - mark_loop_work(&cl, ld, w, t); + mark_loop_work(&cl, ld, w, t, req); } else { - using Closure = ShenandoahMarkRefsMetadataClosure; + using Closure = ShenandoahMarkRefsMetadataClosure; Closure cl(q, rp); - mark_loop_work(&cl, ld, w, t); + mark_loop_work(&cl, ld, w, t, req); } } else { if (heap->has_forwarded_objects()) { - using Closure = ShenandoahMarkUpdateRefsClosure; + using Closure = ShenandoahMarkUpdateRefsClosure; Closure cl(q, rp); - mark_loop_work(&cl, ld, w, t); + mark_loop_work(&cl, ld, w, t, req); } else { - using Closure = ShenandoahMarkRefsClosure; + using Closure = ShenandoahMarkRefsClosure; Closure cl(q, rp); - mark_loop_work(&cl, ld, w, t); + mark_loop_work(&cl, ld, w, t, req); } } @@ -90,36 +89,36 @@ void ShenandoahMark::mark_loop_prework(uint w, TaskTerminator *t, ShenandoahRefe } void ShenandoahMark::mark_loop(uint worker_id, TaskTerminator* terminator, ShenandoahReferenceProcessor *rp, - bool cancellable, StringDedupMode dedup_mode) { + bool cancellable, StringDedupMode dedup_mode, StringDedup::Requests* const req) { if (cancellable) { switch(dedup_mode) { case NO_DEDUP: - mark_loop_prework(worker_id, terminator, rp); + mark_loop_prework(worker_id, terminator, rp, req); break; case ENQUEUE_DEDUP: - mark_loop_prework(worker_id, terminator, rp); + mark_loop_prework(worker_id, terminator, rp, req); break; case ALWAYS_DEDUP: - mark_loop_prework(worker_id, terminator, rp); + mark_loop_prework(worker_id, terminator, rp, req); break; } } else { switch(dedup_mode) { case NO_DEDUP: - mark_loop_prework(worker_id, terminator, rp); + mark_loop_prework(worker_id, terminator, rp, req); break; case ENQUEUE_DEDUP: - mark_loop_prework(worker_id, terminator, rp); + mark_loop_prework(worker_id, terminator, rp, req); break; case ALWAYS_DEDUP: - mark_loop_prework(worker_id, terminator, rp); + mark_loop_prework(worker_id, terminator, rp, req); break; } } } -template -void ShenandoahMark::mark_loop_work(T* cl, ShenandoahLiveData* live_data, uint worker_id, TaskTerminator *terminator) { +template +void ShenandoahMark::mark_loop_work(T* cl, ShenandoahLiveData* live_data, uint worker_id, TaskTerminator *terminator, StringDedup::Requests* const req) { uintx stride = ShenandoahMarkLoopStride; ShenandoahHeap* heap = ShenandoahHeap::heap(); @@ -147,7 +146,7 @@ void ShenandoahMark::mark_loop_work(T* cl, ShenandoahLiveData* live_data, uint w for (uint i = 0; i < stride; i++) { if (q->pop(t)) { - do_task(q, cl, live_data, &t); + do_task(q, cl, live_data, req, &t); } else { assert(q->is_empty(), "Must be empty"); q = queues->claim_next(); @@ -176,7 +175,7 @@ void ShenandoahMark::mark_loop_work(T* cl, ShenandoahLiveData* live_data, uint w for (uint i = 0; i < stride; i++) { if (q->pop(t) || queues->steal(worker_id, t)) { - do_task(q, cl, live_data, &t); + do_task(q, cl, live_data, req, &t); work++; } else { break; diff --git a/src/hotspot/share/gc/shenandoah/shenandoahMark.hpp b/src/hotspot/share/gc/shenandoah/shenandoahMark.hpp index 6b31fabee25fa..5b29fa54e35d6 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahMark.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahMark.hpp @@ -45,8 +45,8 @@ class ShenandoahMark: public StackObj { ShenandoahMark(); public: - template - static inline void mark_through_ref(T* p, ShenandoahObjToScanQueue* q, ShenandoahMarkingContext* const mark_context, StringDedup::Requests* const req, bool weak); + template + static inline void mark_through_ref(T* p, ShenandoahObjToScanQueue* q, ShenandoahMarkingContext* const mark_context, bool weak); static void clear(); @@ -56,8 +56,8 @@ class ShenandoahMark: public StackObj { // ---------- Marking loop and tasks private: - template - inline void do_task(ShenandoahObjToScanQueue* q, T* cl, ShenandoahLiveData* live_data, ShenandoahMarkTask* task); + template + inline void do_task(ShenandoahObjToScanQueue* q, T* cl, ShenandoahLiveData* live_data, StringDedup::Requests* const req, ShenandoahMarkTask* task); template inline void do_chunked_array_start(ShenandoahObjToScanQueue* q, T* cl, oop array, bool weak); @@ -67,15 +67,17 @@ class ShenandoahMark: public StackObj { inline void count_liveness(ShenandoahLiveData* live_data, oop obj); - template - void mark_loop_work(T* cl, ShenandoahLiveData* live_data, uint worker_id, TaskTerminator *t); + template + void mark_loop_work(T* cl, ShenandoahLiveData* live_data, uint worker_id, TaskTerminator *t, StringDedup::Requests* const req); template - void mark_loop_prework(uint worker_id, TaskTerminator *terminator, ShenandoahReferenceProcessor *rp); + void mark_loop_prework(uint worker_id, TaskTerminator *terminator, ShenandoahReferenceProcessor *rp, StringDedup::Requests* const req); + template + inline void dedup_string(oop obj, StringDedup::Requests* const req); protected: void mark_loop(uint worker_id, TaskTerminator* terminator, ShenandoahReferenceProcessor *rp, - bool cancellable, StringDedupMode dedup_mode); + bool cancellable, StringDedupMode dedup_mode, StringDedup::Requests* const req); }; #endif // SHARE_GC_SHENANDOAH_SHENANDOAHMARK_HPP diff --git a/src/hotspot/share/gc/shenandoah/shenandoahMark.inline.hpp b/src/hotspot/share/gc/shenandoah/shenandoahMark.inline.hpp index 929965ce8eceb..cfafd623d8e75 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahMark.inline.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahMark.inline.hpp @@ -40,8 +40,22 @@ #include "runtime/prefetch.inline.hpp" #include "utilities/powerOfTwo.hpp" -template -void ShenandoahMark::do_task(ShenandoahObjToScanQueue* q, T* cl, ShenandoahLiveData* live_data, ShenandoahMarkTask* task) { +template +void ShenandoahMark::dedup_string(oop obj, StringDedup::Requests* const req) { + if (STRING_DEDUP == ENQUEUE_DEDUP) { + if (ShenandoahStringDedup::is_candidate(obj)) { + req->add(obj); + } + } else if (STRING_DEDUP == ALWAYS_DEDUP) { + if (ShenandoahStringDedup::is_string_candidate(obj) && + !ShenandoahStringDedup::dedup_requested(obj)) { + req->add(obj); + } + } +} + +template +void ShenandoahMark::do_task(ShenandoahObjToScanQueue* q, T* cl, ShenandoahLiveData* live_data, StringDedup::Requests* const req, ShenandoahMarkTask* task) { oop obj = task->obj(); shenandoah_assert_not_forwarded(NULL, obj); @@ -56,6 +70,7 @@ void ShenandoahMark::do_task(ShenandoahObjToScanQueue* q, T* cl, ShenandoahLiveD if (obj->is_instance()) { // Case 1: Normal oop, process as usual. obj->oop_iterate(cl); + dedup_string(obj, req); } else if (obj->is_objArray()) { // Case 2: Object array instance and no chunk is set. Must be the first // time we visit it, start the chunked processing. @@ -208,7 +223,6 @@ inline void ShenandoahMark::do_chunked_array(ShenandoahObjToScanQueue* q, T* cl, class ShenandoahSATBBufferClosure : public SATBBufferClosure { private: - StringDedup::Requests _stringdedup_requests; ShenandoahObjToScanQueue* _queue; ShenandoahHeap* _heap; ShenandoahMarkingContext* const _mark_context; @@ -222,24 +236,15 @@ class ShenandoahSATBBufferClosure : public SATBBufferClosure { void do_buffer(void **buffer, size_t size) { assert(size == 0 || !_heap->has_forwarded_objects(), "Forwarded objects are not expected here"); - if (ShenandoahStringDedup::is_enabled()) { - do_buffer_impl(buffer, size); - } else { - do_buffer_impl(buffer, size); - } - } - - template - void do_buffer_impl(void **buffer, size_t size) { for (size_t i = 0; i < size; ++i) { oop *p = (oop *) &buffer[i]; - ShenandoahMark::mark_through_ref(p, _queue, _mark_context, &_stringdedup_requests, false); + ShenandoahMark::mark_through_ref(p, _queue, _mark_context, false); } } }; -template -inline void ShenandoahMark::mark_through_ref(T* p, ShenandoahObjToScanQueue* q, ShenandoahMarkingContext* const mark_context, StringDedup::Requests* const req, bool weak) { +template +inline void ShenandoahMark::mark_through_ref(T* p, ShenandoahObjToScanQueue* q, ShenandoahMarkingContext* const mark_context, bool weak) { T o = RawAccess<>::oop_load(p); if (!CompressedOops::is_null(o)) { oop obj = CompressedOops::decode_not_null(o); @@ -257,16 +262,6 @@ inline void ShenandoahMark::mark_through_ref(T* p, ShenandoahObjToScanQueue* q, if (marked) { bool pushed = q->push(ShenandoahMarkTask(obj, skip_live, weak)); assert(pushed, "overflow queue should always succeed pushing"); - - if ((STRING_DEDUP == ENQUEUE_DEDUP) && ShenandoahStringDedup::is_candidate(obj)) { - assert(ShenandoahStringDedup::is_enabled(), "Must be enabled"); - req->add(obj); - } else if ((STRING_DEDUP == ALWAYS_DEDUP) && - ShenandoahStringDedup::is_string_candidate(obj) && - !ShenandoahStringDedup::dedup_requested(obj)) { - assert(ShenandoahStringDedup::is_enabled(), "Must be enabled"); - req->add(obj); - } } shenandoah_assert_marked(p, obj); diff --git a/src/hotspot/share/gc/shenandoah/shenandoahOopClosures.hpp b/src/hotspot/share/gc/shenandoah/shenandoahOopClosures.hpp index fe3cb0fe77b2d..5bd42916a2f55 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahOopClosures.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahOopClosures.hpp @@ -40,13 +40,12 @@ enum StringDedupMode { class ShenandoahMarkRefsSuperClosure : public MetadataVisitingOopIterateClosure { private: - StringDedup::Requests _stringDedup_requests; ShenandoahObjToScanQueue* _queue; ShenandoahMarkingContext* const _mark_context; bool _weak; protected: - template + template void work(T *p); public: @@ -65,7 +64,7 @@ class ShenandoahMarkUpdateRefsSuperClosure : public ShenandoahMarkRefsSuperClosu protected: ShenandoahHeap* const _heap; - template + template inline void work(T* p); public: @@ -76,11 +75,10 @@ class ShenandoahMarkUpdateRefsSuperClosure : public ShenandoahMarkRefsSuperClosu }; }; -template class ShenandoahMarkUpdateRefsClosure : public ShenandoahMarkUpdateRefsSuperClosure { private: template - inline void do_oop_work(T* p) { work(p); } + inline void do_oop_work(T* p) { work(p); } public: ShenandoahMarkUpdateRefsClosure(ShenandoahObjToScanQueue* q, ShenandoahReferenceProcessor* rp) : @@ -91,11 +89,10 @@ class ShenandoahMarkUpdateRefsClosure : public ShenandoahMarkUpdateRefsSuperClos virtual bool do_metadata() { return false; } }; -template class ShenandoahMarkUpdateRefsMetadataClosure : public ShenandoahMarkUpdateRefsSuperClosure { private: template - inline void do_oop_work(T* p) { work(p); } + inline void do_oop_work(T* p) { work(p); } public: ShenandoahMarkUpdateRefsMetadataClosure(ShenandoahObjToScanQueue* q, ShenandoahReferenceProcessor* rp) : @@ -107,11 +104,10 @@ class ShenandoahMarkUpdateRefsMetadataClosure : public ShenandoahMarkUpdateRefsS }; -template class ShenandoahMarkRefsClosure : public ShenandoahMarkRefsSuperClosure { private: template - inline void do_oop_work(T* p) { work(p); } + inline void do_oop_work(T* p) { work(p); } public: ShenandoahMarkRefsClosure(ShenandoahObjToScanQueue* q, ShenandoahReferenceProcessor* rp) : @@ -123,11 +119,10 @@ class ShenandoahMarkRefsClosure : public ShenandoahMarkRefsSuperClosure { }; -template class ShenandoahMarkRefsMetadataClosure : public ShenandoahMarkRefsSuperClosure { private: template - inline void do_oop_work(T* p) { work(p); } + inline void do_oop_work(T* p) { work(p); } public: ShenandoahMarkRefsMetadataClosure(ShenandoahObjToScanQueue* q, ShenandoahReferenceProcessor* rp) : diff --git a/src/hotspot/share/gc/shenandoah/shenandoahOopClosures.inline.hpp b/src/hotspot/share/gc/shenandoah/shenandoahOopClosures.inline.hpp index 47bd5cac5c1e7..1812b4e8f0577 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahOopClosures.inline.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahOopClosures.inline.hpp @@ -30,18 +30,18 @@ #include "gc/shenandoah/shenandoahHeap.inline.hpp" #include "gc/shenandoah/shenandoahMark.inline.hpp" -template +template inline void ShenandoahMarkRefsSuperClosure::work(T* p) { - ShenandoahMark::mark_through_ref(p, _queue, _mark_context, &_stringDedup_requests, _weak); + ShenandoahMark::mark_through_ref(p, _queue, _mark_context, _weak); } -template +template inline void ShenandoahMarkUpdateRefsSuperClosure::work(T* p) { // Update the location _heap->update_with_forwarded(p); // ...then do the usual thing - ShenandoahMarkRefsSuperClosure::work(p); + ShenandoahMarkRefsSuperClosure::work(p); } template diff --git a/src/hotspot/share/gc/shenandoah/shenandoahPacer.hpp b/src/hotspot/share/gc/shenandoah/shenandoahPacer.hpp index 6b2dd53ff760e..a42c8d0bbcdf1 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahPacer.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahPacer.hpp @@ -67,7 +67,7 @@ class ShenandoahPacer : public CHeapObj { _heap(heap), _last_time(os::elapsedTime()), _progress_history(new TruncatedSeq(5)), - _wait_monitor(new Monitor(Mutex::leaf, "_wait_monitor", true, Monitor::_safepoint_check_always)), + _wait_monitor(new Monitor(Mutex::leaf, "_wait_monitor", Monitor::_safepoint_check_always, true)), _epoch(0), _tax_rate(1), _budget(0), diff --git a/src/hotspot/share/gc/shenandoah/shenandoahSTWMark.cpp b/src/hotspot/share/gc/shenandoah/shenandoahSTWMark.cpp index 1d4d46dc5383c..09fea5b848779 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahSTWMark.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahSTWMark.cpp @@ -57,7 +57,7 @@ ShenandoahInitMarkRootsClosure::ShenandoahInitMarkRootsClosure(ShenandoahObjToSc template void ShenandoahInitMarkRootsClosure::do_oop_work(T* p) { - ShenandoahMark::mark_through_ref(p, _queue, _mark_context, NULL, false); + ShenandoahMark::mark_through_ref(p, _queue, _mark_context, false); } class ShenandoahSTWMarkTask : public AbstractGangTask { @@ -131,9 +131,10 @@ void ShenandoahSTWMark::finish_mark(uint worker_id) { ShenandoahPhaseTimings::Phase phase = _full_gc ? ShenandoahPhaseTimings::full_gc_mark : ShenandoahPhaseTimings::degen_gc_stw_mark; ShenandoahWorkerTimingsTracker timer(phase, ShenandoahPhaseTimings::ParallelMark, worker_id); ShenandoahReferenceProcessor* rp = ShenandoahHeap::heap()->ref_processor(); + StringDedup::Requests requests; mark_loop(worker_id, &_terminator, rp, false /* not cancellable */, - ShenandoahStringDedup::is_enabled() ? ALWAYS_DEDUP : NO_DEDUP); + ShenandoahStringDedup::is_enabled() ? ALWAYS_DEDUP : NO_DEDUP, &requests); } diff --git a/src/hotspot/share/gc/shenandoah/shenandoahStringDedup.inline.hpp b/src/hotspot/share/gc/shenandoah/shenandoahStringDedup.inline.hpp index 57b30358e94b2..869a17c3d9b78 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahStringDedup.inline.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahStringDedup.inline.hpp @@ -32,7 +32,7 @@ bool ShenandoahStringDedup::is_string_candidate(oop obj) { assert(Thread::current()->is_Worker_thread(), "Only from a GC worker thread"); - return java_lang_String::is_instance_inlined(obj) && + return java_lang_String::is_instance(obj) && java_lang_String::value(obj) != nullptr; } diff --git a/src/hotspot/share/gc/z/zMark.cpp b/src/hotspot/share/gc/z/zMark.cpp index 72f459b97fcc1..d73c2832854f5 100644 --- a/src/hotspot/share/gc/z/zMark.cpp +++ b/src/hotspot/share/gc/z/zMark.cpp @@ -288,7 +288,7 @@ static void try_deduplicate(ZMarkContext* context, oop obj) { return; } - if (!java_lang_String::is_instance_inlined(obj)) { + if (!java_lang_String::is_instance(obj)) { // Not a String object return; } diff --git a/src/hotspot/share/gc/z/zMessagePort.inline.hpp b/src/hotspot/share/gc/z/zMessagePort.inline.hpp index ce173a658a783..91f161684f459 100644 --- a/src/hotspot/share/gc/z/zMessagePort.inline.hpp +++ b/src/hotspot/share/gc/z/zMessagePort.inline.hpp @@ -68,7 +68,6 @@ template inline ZMessagePort::ZMessagePort() : _monitor(Monitor::leaf, "ZMessagePort", - Monitor::_allow_vm_block_flag, Monitor::_safepoint_check_never), _has_message(false), _seqnum(0), diff --git a/src/hotspot/share/gc/z/zMetronome.cpp b/src/hotspot/share/gc/z/zMetronome.cpp index d1c293dd60ceb..ff5f3749913c7 100644 --- a/src/hotspot/share/gc/z/zMetronome.cpp +++ b/src/hotspot/share/gc/z/zMetronome.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2021, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -28,7 +28,7 @@ #include "utilities/ticks.hpp" ZMetronome::ZMetronome(uint64_t hz) : - _monitor(Monitor::leaf, "ZMetronome", false, Monitor::_safepoint_check_never), + _monitor(Monitor::leaf, "ZMetronome", Monitor::_safepoint_check_never), _interval_ms(MILLIUNITS / hz), _start_ms(0), _nticks(0), diff --git a/src/hotspot/share/jvmci/jvmciCompilerToVM.cpp b/src/hotspot/share/jvmci/jvmciCompilerToVM.cpp index 772c8df7522a8..45d2ad1d2e4f1 100644 --- a/src/hotspot/share/jvmci/jvmciCompilerToVM.cpp +++ b/src/hotspot/share/jvmci/jvmciCompilerToVM.cpp @@ -2629,6 +2629,49 @@ C2V_VMENTRY(void, notifyCompilerInliningEvent, (JNIEnv* env, jobject, jint compi } } +C2V_VMENTRY(void, setThreadLocalObject, (JNIEnv* env, jobject, jint id, jobject value)) + requireInHotSpot("setThreadLocalObject", JVMCI_CHECK); + if (id == 0) { + thread->set_jvmci_reserved_oop0(JNIHandles::resolve(value)); + return; + } + THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(), + err_msg("%d is not a valid thread local id", id)); +} + +C2V_VMENTRY_NULL(jobject, getThreadLocalObject, (JNIEnv* env, jobject, jint id)) + requireInHotSpot("getThreadLocalObject", JVMCI_CHECK_NULL); + if (id == 0) { + return JNIHandles::make_local(thread->get_jvmci_reserved_oop0()); + } + THROW_MSG_0(vmSymbols::java_lang_IllegalArgumentException(), + err_msg("%d is not a valid thread local id", id)); +} + +C2V_VMENTRY(void, setThreadLocalLong, (JNIEnv* env, jobject, jint id, jlong value)) + requireInHotSpot("setThreadLocalLong", JVMCI_CHECK); + if (id == 0) { + thread->set_jvmci_reserved0(value); + } else if (id == 1) { + thread->set_jvmci_reserved1(value); + } else { + THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(), + err_msg("%d is not a valid thread local id", id)); + } +} + +C2V_VMENTRY_0(jlong, getThreadLocalLong, (JNIEnv* env, jobject, jint id)) + requireInHotSpot("getThreadLocalLong", JVMCI_CHECK_0); + if (id == 0) { + return thread->get_jvmci_reserved0(); + } else if (id == 1) { + return thread->get_jvmci_reserved1(); + } else { + THROW_MSG_0(vmSymbols::java_lang_IllegalArgumentException(), + err_msg("%d is not a valid thread local id", id)); + } +} + #define CC (char*) /*cast a literal from (const char*)*/ #define FN_PTR(f) CAST_FROM_FN_PTR(void*, &(c2v_ ## f)) @@ -2770,6 +2813,10 @@ JNINativeMethod CompilerToVM::methods[] = { {CC "addFailedSpeculation", CC "(J[B)Z", FN_PTR(addFailedSpeculation)}, {CC "callSystemExit", CC "(I)V", FN_PTR(callSystemExit)}, {CC "ticksNow", CC "()J", FN_PTR(ticksNow)}, + {CC "getThreadLocalObject", CC "(I)" OBJECT, FN_PTR(getThreadLocalObject)}, + {CC "setThreadLocalObject", CC "(I" OBJECT ")V", FN_PTR(setThreadLocalObject)}, + {CC "getThreadLocalLong", CC "(I)J", FN_PTR(getThreadLocalLong)}, + {CC "setThreadLocalLong", CC "(IJ)V", FN_PTR(setThreadLocalLong)}, {CC "registerCompilerPhase", CC "(" STRING ")I", FN_PTR(registerCompilerPhase)}, {CC "notifyCompilerPhaseEvent", CC "(JIII)V", FN_PTR(notifyCompilerPhaseEvent)}, {CC "notifyCompilerInliningEvent", CC "(I" HS_RESOLVED_METHOD HS_RESOLVED_METHOD "ZLjava/lang/String;I)V", FN_PTR(notifyCompilerInliningEvent)}, diff --git a/src/hotspot/share/jvmci/vmStructs_jvmci.cpp b/src/hotspot/share/jvmci/vmStructs_jvmci.cpp index 8a9c3c2fe3e92..43493e650009e 100644 --- a/src/hotspot/share/jvmci/vmStructs_jvmci.cpp +++ b/src/hotspot/share/jvmci/vmStructs_jvmci.cpp @@ -183,8 +183,8 @@ nonstatic_field(JavaThread, _pending_failed_speculation, jlong) \ nonstatic_field(JavaThread, _pending_transfer_to_interpreter, bool) \ nonstatic_field(JavaThread, _jvmci_counters, jlong*) \ - nonstatic_field(JavaThread, _jvmci_reserved0, intptr_t*) \ - nonstatic_field(JavaThread, _jvmci_reserved1, intptr_t*) \ + nonstatic_field(JavaThread, _jvmci_reserved0, jlong) \ + nonstatic_field(JavaThread, _jvmci_reserved1, jlong) \ nonstatic_field(JavaThread, _jvmci_reserved_oop0, oop) \ nonstatic_field(JavaThread, _should_post_on_exceptions_flag, int) \ nonstatic_field(JavaThread, _jni_environment, JNIEnv) \ @@ -308,6 +308,7 @@ static_field(StubRoutines, _electronicCodeBook_encryptAESCrypt, address) \ static_field(StubRoutines, _electronicCodeBook_decryptAESCrypt, address) \ static_field(StubRoutines, _counterMode_AESCrypt, address) \ + static_field(StubRoutines, _galoisCounterMode_AESCrypt, address) \ static_field(StubRoutines, _base64_encodeBlock, address) \ static_field(StubRoutines, _base64_decodeBlock, address) \ static_field(StubRoutines, _ghash_processBlocks, address) \ diff --git a/src/hotspot/share/logging/logConfiguration.cpp b/src/hotspot/share/logging/logConfiguration.cpp index 4c371e8506e7a..9428231551443 100644 --- a/src/hotspot/share/logging/logConfiguration.cpp +++ b/src/hotspot/share/logging/logConfiguration.cpp @@ -564,12 +564,20 @@ void LogConfiguration::print_command_line_help(outputStream* out) { out->print_cr(" file="); out->print_cr(" If the filename contains %%p and/or %%t, they will expand to the JVM's PID and startup timestamp, respectively."); out->print_cr(" Additional output-options for file outputs:"); - out->print_cr(" filesize=.. - Target byte size for log rotation (supports K/M/G suffix)." - " If set to 0, log rotation will not trigger automatically," - " but can be performed manually (see the VM.log DCMD)."); - out->print_cr(" filecount=.. - Number of files to keep in rotation (not counting the active file)." - " If set to 0, log rotation is disabled." - " This will cause existing log files to be overwritten."); + out->print_cr(" filesize=.. - Target byte size for log rotation (supports K/M/G suffix)." + " If set to 0, log rotation will not trigger automatically," + " but can be performed manually (see the VM.log DCMD)."); + out->print_cr(" filecount=.. - Number of files to keep in rotation (not counting the active file)." + " If set to 0, log rotation is disabled." + " This will cause existing log files to be overwritten."); + out->print_cr(" foldmultilines=.. - If set to true, a log event that consists of multiple lines" + " will be folded into a single line by replacing newline characters" + " with the sequence '\\' and 'n' in the output." + " Existing single backslash characters will also be replaced" + " with a sequence of two backslashes so that the conversion can be reversed." + " This option is safe to use with UTF-8 character encodings," + " but other encodings may not work."); + out->cr(); out->print_cr("\nAsynchronous logging (off by default):"); out->print_cr(" -Xlog:async"); diff --git a/src/hotspot/share/logging/logFileOutput.cpp b/src/hotspot/share/logging/logFileOutput.cpp index 856907f8be412..2838fb55c0805 100644 --- a/src/hotspot/share/logging/logFileOutput.cpp +++ b/src/hotspot/share/logging/logFileOutput.cpp @@ -195,7 +195,17 @@ bool LogFileOutput::parse_options(const char* options, outputStream* errstream) char* value_str = equals_pos + 1; *equals_pos = '\0'; - if (strcmp(FileCountOptionKey, key) == 0) { + if (strcmp(FoldMultilinesOptionKey, key) == 0) { + if (strcmp(value_str, "true") == 0) { + _fold_multilines = true; + } else if (strcmp(value_str, "false") == 0) { + _fold_multilines = false; + } else { + errstream->print_cr("Invalid option '%s' for %s.", value_str, FoldMultilinesOptionKey); + success = false; + break; + } + } else if (strcmp(FileCountOptionKey, key) == 0) { size_t value = parse_value(value_str); if (value > MaxRotationFileCount) { errstream->print_cr("Invalid option: %s must be in range [0, %u]", diff --git a/src/hotspot/share/logging/logFileStreamOutput.cpp b/src/hotspot/share/logging/logFileStreamOutput.cpp index 8ce465ed1ed8c..60296e4f05080 100644 --- a/src/hotspot/share/logging/logFileStreamOutput.cpp +++ b/src/hotspot/share/logging/logFileStreamOutput.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2021, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -30,6 +30,8 @@ #include "memory/allocation.inline.hpp" #include "utilities/defaultStream.hpp" +const char* const LogFileStreamOutput::FoldMultilinesOptionKey = "foldmultilines"; + static bool initialized; static union { char stdoutmem[sizeof(LogStdoutOutput)]; @@ -117,6 +119,30 @@ bool LogFileStreamOutput::flush() { total += result; \ } +int LogFileStreamOutput::write_internal(const char* msg) { + int written = 0; + if (!_fold_multilines) { + WRITE_LOG_WITH_RESULT_CHECK(jio_fprintf(_stream, "%s\n", msg), written); + } else { + char *dupstr = os::strdup_check_oom(msg, mtLogging); + char *cur = dupstr; + char *next; + do { + next = strpbrk(cur, "\n\\"); + if (next == NULL) { + WRITE_LOG_WITH_RESULT_CHECK(jio_fprintf(_stream, "%s\n", cur), written); + } else { + const char *found = (*next == '\n') ? "\\n" : "\\\\"; + *next = '\0'; + WRITE_LOG_WITH_RESULT_CHECK(jio_fprintf(_stream, "%s%s", cur, found), written); + cur = next + 1; + } + } while (next != NULL); + os::free(dupstr); + } + return written; +} + int LogFileStreamOutput::write(const LogDecorations& decorations, const char* msg) { const bool use_decorations = !_decorators.is_empty(); @@ -126,7 +152,7 @@ int LogFileStreamOutput::write(const LogDecorations& decorations, const char* ms WRITE_LOG_WITH_RESULT_CHECK(write_decorations(decorations), written); WRITE_LOG_WITH_RESULT_CHECK(jio_fprintf(_stream, " "), written); } - WRITE_LOG_WITH_RESULT_CHECK(jio_fprintf(_stream, "%s\n", msg), written); + written += write_internal(msg); return flush() ? written : -1; } @@ -141,7 +167,7 @@ int LogFileStreamOutput::write(LogMessageBuffer::Iterator msg_iterator) { WRITE_LOG_WITH_RESULT_CHECK(write_decorations(msg_iterator.decorations()), written); WRITE_LOG_WITH_RESULT_CHECK(jio_fprintf(_stream, " "), written); } - WRITE_LOG_WITH_RESULT_CHECK(jio_fprintf(_stream, "%s\n", msg_iterator.message()), written); + written += write_internal(msg_iterator.message()); } return flush() ? written : -1; diff --git a/src/hotspot/share/logging/logFileStreamOutput.hpp b/src/hotspot/share/logging/logFileStreamOutput.hpp index c4a0db7355d2c..d211e8bda2a13 100644 --- a/src/hotspot/share/logging/logFileStreamOutput.hpp +++ b/src/hotspot/share/logging/logFileStreamOutput.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2021, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -26,6 +26,7 @@ #include "logging/logDecorators.hpp" #include "logging/logOutput.hpp" +#include "runtime/os.hpp" #include "utilities/globalDefinitions.hpp" class LogDecorations; @@ -42,11 +43,15 @@ static LogFileStreamInitializer log_stream_initializer; class LogFileStreamOutput : public LogOutput { private: bool _write_error_is_shown; + + int write_internal(const char* msg); protected: + static const char* const FoldMultilinesOptionKey; FILE* _stream; size_t _decorator_padding[LogDecorators::Count]; + bool _fold_multilines; - LogFileStreamOutput(FILE *stream) : _write_error_is_shown(false), _stream(stream) { + LogFileStreamOutput(FILE *stream) : _write_error_is_shown(false), _stream(stream), _fold_multilines(false) { for (size_t i = 0; i < LogDecorators::Count; i++) { _decorator_padding[i] = 0; } diff --git a/src/hotspot/share/memory/heapInspection.hpp b/src/hotspot/share/memory/heapInspection.hpp index a7b2d6fa3f063..f73f1d8a4a32a 100644 --- a/src/hotspot/share/memory/heapInspection.hpp +++ b/src/hotspot/share/memory/heapInspection.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 2021, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -245,7 +245,7 @@ class ParHeapInspectTask : public AbstractGangTask { _filter(filter), _missed_count(0), _success(true), - _mutex(Mutex::leaf, "Parallel heap iteration data merge lock") {} + _mutex(Mutex::leaf, "Parallel heap iteration data merge lock", Mutex::_safepoint_check_always) {} uintx missed_count() const { return _missed_count; diff --git a/src/hotspot/share/memory/iterator.cpp b/src/hotspot/share/memory/iterator.cpp index f9fbaf51b90f1..6790289ae543c 100644 --- a/src/hotspot/share/memory/iterator.cpp +++ b/src/hotspot/share/memory/iterator.cpp @@ -40,10 +40,6 @@ void ObjectToOopClosure::do_object(oop obj) { obj->oop_iterate(_cl); } -void VoidClosure::do_void() { - ShouldNotCallThis(); -} - void CodeBlobToOopClosure::do_nmethod(nmethod* nm) { nm->oops_do(_cl); if (_fix_relocations) { diff --git a/src/hotspot/share/memory/iterator.hpp b/src/hotspot/share/memory/iterator.hpp index 23290a40fc4b1..d442cd1ccddc5 100644 --- a/src/hotspot/share/memory/iterator.hpp +++ b/src/hotspot/share/memory/iterator.hpp @@ -283,9 +283,7 @@ class MonitorClosure : public StackObj { // A closure that is applied without any arguments. class VoidClosure : public StackObj { public: - // I would have liked to declare this a pure virtual, but that breaks - // in mysterious ways, for unknown reasons. - virtual void do_void(); + virtual void do_void() = 0; }; diff --git a/src/hotspot/share/memory/metaspace/testHelpers.cpp b/src/hotspot/share/memory/metaspace/testHelpers.cpp index 901f48f9aec83..73554807b7d28 100644 --- a/src/hotspot/share/memory/metaspace/testHelpers.cpp +++ b/src/hotspot/share/memory/metaspace/testHelpers.cpp @@ -92,7 +92,7 @@ MetaspaceTestContext::~MetaspaceTestContext() { // Create an arena, feeding off this area. MetaspaceTestArena* MetaspaceTestContext::create_arena(Metaspace::MetaspaceType type) { const ArenaGrowthPolicy* growth_policy = ArenaGrowthPolicy::policy_for_space_type(type, false); - Mutex* lock = new Mutex(Monitor::native, "MetaspaceTestArea-lock", false, Monitor::_safepoint_check_never); + Mutex* lock = new Mutex(Monitor::leaf, "MetaspaceTestArea-lock", Monitor::_safepoint_check_never); MetaspaceArena* arena = NULL; { MutexLocker ml(lock, Mutex::_no_safepoint_check_flag); diff --git a/src/hotspot/share/memory/metaspaceClosure.cpp b/src/hotspot/share/memory/metaspaceClosure.cpp index 39c30e2ddf7f1..cc5e698f2f998 100644 --- a/src/hotspot/share/memory/metaspaceClosure.cpp +++ b/src/hotspot/share/memory/metaspaceClosure.cpp @@ -29,9 +29,7 @@ void MetaspaceClosure::Ref::update(address new_loc) const { log_trace(cds)("Ref: [" PTR_FORMAT "] -> " PTR_FORMAT " => " PTR_FORMAT, p2i(mpp()), p2i(obj()), p2i(new_loc)); - uintx p = (uintx)new_loc; - p |= flag_bits(); // Make sure the flag bits are copied to the new pointer. - *(address*)mpp() = (address)p; + *addr() = new_loc; } void MetaspaceClosure::push_impl(MetaspaceClosure::Ref* ref) { diff --git a/src/hotspot/share/memory/metaspaceClosure.hpp b/src/hotspot/share/memory/metaspaceClosure.hpp index 02606efe0f79b..2e675ee8683d5 100644 --- a/src/hotspot/share/memory/metaspaceClosure.hpp +++ b/src/hotspot/share/memory/metaspaceClosure.hpp @@ -128,10 +128,7 @@ class MetaspaceClosure { virtual ~Ref() {} address obj() const { - // In some rare cases we store some flags in the lowest 2 bits of a - // MetaspaceObj pointer. Unmask these when manipulating the pointer. - uintx p = (uintx)*mpp(); - return (address)(p & (~FLAG_MASK)); + return *addr(); } address* addr() const { @@ -147,14 +144,6 @@ class MetaspaceClosure { void* user_data() { return _user_data; } void set_next(Ref* n) { _next = n; } Ref* next() const { return _next; } - - private: - static const uintx FLAG_MASK = 0x03; - - int flag_bits() const { - uintx p = (uintx)*mpp(); - return (int)(p & FLAG_MASK); - } }; private: diff --git a/src/hotspot/share/oops/methodData.cpp b/src/hotspot/share/oops/methodData.cpp index dd60dd0892aaf..69f7ae1b85d1f 100644 --- a/src/hotspot/share/oops/methodData.cpp +++ b/src/hotspot/share/oops/methodData.cpp @@ -1206,7 +1206,7 @@ void MethodData::post_initialize(BytecodeStream* stream) { // Initialize the MethodData* corresponding to a given method. MethodData::MethodData(const methodHandle& method) : _method(method()), - _extra_data_lock(Mutex::leaf, "MDO extra data lock"), + _extra_data_lock(Mutex::leaf, "MDO extra data lock", Mutex::_safepoint_check_always), _compiler_counters(), _parameters_type_data_di(parameters_uninitialized) { initialize(); diff --git a/src/hotspot/share/opto/bytecodeInfo.cpp b/src/hotspot/share/opto/bytecodeInfo.cpp index 25ebd432ff6b5..0ce5143b59afc 100644 --- a/src/hotspot/share/opto/bytecodeInfo.cpp +++ b/src/hotspot/share/opto/bytecodeInfo.cpp @@ -156,18 +156,17 @@ bool InlineTree::should_inline(ciMethod* callee_method, ciMethod* caller_method, int invoke_count = method()->interpreter_invocation_count(); assert(invoke_count != 0, "require invocation count greater than zero"); - int freq = call_site_count / invoke_count; + double freq = (double)call_site_count / (double)invoke_count; // bump the max size if the call is frequent if ((freq >= InlineFrequencyRatio) || - (call_site_count >= InlineFrequencyCount) || is_unboxing_method(callee_method, C) || is_init_with_ea(callee_method, caller_method, C)) { max_inline_size = C->freq_inline_size(); if (size <= max_inline_size && TraceFrequencyInlining) { CompileTask::print_inline_indent(inline_level()); - tty->print_cr("Inlined frequent method (freq=%d count=%d):", freq, call_site_count); + tty->print_cr("Inlined frequent method (freq=%lf):", freq); CompileTask::print_inline_indent(inline_level()); callee_method->print(); tty->cr(); diff --git a/src/hotspot/share/opto/c2compiler.cpp b/src/hotspot/share/opto/c2compiler.cpp index 5a1d7888ae138..d5a59a413af75 100644 --- a/src/hotspot/share/opto/c2compiler.cpp +++ b/src/hotspot/share/opto/c2compiler.cpp @@ -640,6 +640,7 @@ bool C2Compiler::is_intrinsic_supported(const methodHandle& method, bool is_virt case vmIntrinsics::_electronicCodeBook_encryptAESCrypt: case vmIntrinsics::_electronicCodeBook_decryptAESCrypt: case vmIntrinsics::_counterMode_AESCrypt: + case vmIntrinsics::_galoisCounterMode_AESCrypt: case vmIntrinsics::_md5_implCompress: case vmIntrinsics::_sha_implCompress: case vmIntrinsics::_sha2_implCompress: diff --git a/src/hotspot/share/opto/escape.cpp b/src/hotspot/share/opto/escape.cpp index 06d3df4d6ab77..1fc2d21435b00 100644 --- a/src/hotspot/share/opto/escape.cpp +++ b/src/hotspot/share/opto/escape.cpp @@ -1087,6 +1087,7 @@ void ConnectionGraph::process_call_arguments(CallNode *call) { strcmp(call->as_CallLeaf()->_name, "electronicCodeBook_encryptAESCrypt") == 0 || strcmp(call->as_CallLeaf()->_name, "electronicCodeBook_decryptAESCrypt") == 0 || strcmp(call->as_CallLeaf()->_name, "counterMode_AESCrypt") == 0 || + strcmp(call->as_CallLeaf()->_name, "galoisCounterMode_AESCrypt") == 0 || strcmp(call->as_CallLeaf()->_name, "ghash_processBlocks") == 0 || strcmp(call->as_CallLeaf()->_name, "encodeBlock") == 0 || strcmp(call->as_CallLeaf()->_name, "decodeBlock") == 0 || diff --git a/src/hotspot/share/opto/graphKit.cpp b/src/hotspot/share/opto/graphKit.cpp index 4238bfa57cf81..200a902ea9614 100644 --- a/src/hotspot/share/opto/graphKit.cpp +++ b/src/hotspot/share/opto/graphKit.cpp @@ -2535,7 +2535,7 @@ Node* GraphKit::make_runtime_call(int flags, if (parm5 != NULL) { call->init_req(TypeFunc::Parms+5, parm5); if (parm6 != NULL) { call->init_req(TypeFunc::Parms+6, parm6); if (parm7 != NULL) { call->init_req(TypeFunc::Parms+7, parm7); - /* close each nested if ===> */ } } } } } } } } + /* close each nested if ===> */ } } } } } } } } assert(call->in(call->req()-1) != NULL, "must initialize all parms"); if (!is_leaf) { diff --git a/src/hotspot/share/opto/lcm.cpp b/src/hotspot/share/opto/lcm.cpp index 333678d712b4d..7197f1f3c2230 100644 --- a/src/hotspot/share/opto/lcm.cpp +++ b/src/hotspot/share/opto/lcm.cpp @@ -518,7 +518,7 @@ Node* PhaseCFG::select( uint score = 0; // Bigger is better int idx = -1; // Index in worklist int cand_cnt = 0; // Candidate count - bool block_size_threshold_ok = (block->number_of_nodes() > 10) ? true : false; + bool block_size_threshold_ok = (recalc_pressure_nodes != NULL) && (block->number_of_nodes() > 10); for( uint i=0; i& ready_cnt, Vecto return true; } - bool block_size_threshold_ok = (block->number_of_nodes() > 10) ? true : false; + bool block_size_threshold_ok = (recalc_pressure_nodes != NULL) && (block->number_of_nodes() > 10); // We track the uses of local definitions as input dependences so that // we know when a given instruction is avialable to be scheduled. diff --git a/src/hotspot/share/opto/library_call.cpp b/src/hotspot/share/opto/library_call.cpp index 701d1955716ab..f5d3d2d7115a9 100644 --- a/src/hotspot/share/opto/library_call.cpp +++ b/src/hotspot/share/opto/library_call.cpp @@ -547,6 +547,9 @@ bool LibraryCallKit::try_to_inline(int predicate) { case vmIntrinsics::_counterMode_AESCrypt: return inline_counterMode_AESCrypt(intrinsic_id()); + case vmIntrinsics::_galoisCounterMode_AESCrypt: + return inline_galoisCounterMode_AESCrypt(); + case vmIntrinsics::_md5_implCompress: case vmIntrinsics::_sha_implCompress: case vmIntrinsics::_sha2_implCompress: @@ -713,6 +716,8 @@ Node* LibraryCallKit::try_to_predicate(int predicate) { return inline_counterMode_AESCrypt_predicate(); case vmIntrinsics::_digestBase_implCompressMB: return inline_digestBase_implCompressMB_predicate(predicate); + case vmIntrinsics::_galoisCounterMode_AESCrypt: + return inline_galoisCounterMode_AESCrypt_predicate(); default: // If you get here, it may be that someone has added a new intrinsic @@ -2167,7 +2172,7 @@ const TypeOopPtr* LibraryCallKit::sharpen_unsafe_type(Compile::AliasType* alias_ // See if it is a narrow oop array. if (adr_type->isa_aryptr()) { if (adr_type->offset() >= objArrayOopDesc::base_offset_in_bytes()) { - const TypeOopPtr *elem_type = adr_type->is_aryptr()->elem()->isa_oopptr(); + const TypeOopPtr* elem_type = adr_type->is_aryptr()->elem()->make_oopptr(); if (elem_type != NULL) { sharpened_klass = elem_type->klass(); } @@ -6679,6 +6684,134 @@ bool LibraryCallKit::inline_digestBase_implCompressMB(Node* digestBase_obj, ciIn return true; } +//------------------------------inline_galoisCounterMode_AESCrypt----------------------- +bool LibraryCallKit::inline_galoisCounterMode_AESCrypt() { + assert(UseAES, "need AES instruction support"); + address stubAddr = NULL; + const char *stubName = NULL; + stubAddr = StubRoutines::galoisCounterMode_AESCrypt(); + stubName = "galoisCounterMode_AESCrypt"; + + if (stubAddr == NULL) return false; + + Node* in = argument(0); + Node* inOfs = argument(1); + Node* len = argument(2); + Node* ct = argument(3); + Node* ctOfs = argument(4); + Node* out = argument(5); + Node* outOfs = argument(6); + Node* gctr_object = argument(7); + Node* ghash_object = argument(8); + + // (1) in, ct and out are arrays. + const Type* in_type = in->Value(&_gvn); + const Type* ct_type = ct->Value(&_gvn); + const Type* out_type = out->Value(&_gvn); + const TypeAryPtr* top_in = in_type->isa_aryptr(); + const TypeAryPtr* top_ct = ct_type->isa_aryptr(); + const TypeAryPtr* top_out = out_type->isa_aryptr(); + assert(top_in != NULL && top_in->klass() != NULL && + top_ct != NULL && top_ct->klass() != NULL && + top_out != NULL && top_out->klass() != NULL, "args are strange"); + + // checks are the responsibility of the caller + Node* in_start = in; + Node* ct_start = ct; + Node* out_start = out; + if (inOfs != NULL || ctOfs != NULL || outOfs != NULL) { + assert(inOfs != NULL && ctOfs != NULL && outOfs != NULL, ""); + in_start = array_element_address(in, inOfs, T_BYTE); + ct_start = array_element_address(ct, ctOfs, T_BYTE); + out_start = array_element_address(out, outOfs, T_BYTE); + } + + // if we are in this set of code, we "know" the embeddedCipher is an AESCrypt object + // (because of the predicated logic executed earlier). + // so we cast it here safely. + // this requires a newer class file that has this array as littleEndian ints, otherwise we revert to java + Node* embeddedCipherObj = load_field_from_object(gctr_object, "embeddedCipher", "Lcom/sun/crypto/provider/SymmetricCipher;"); + Node* counter = load_field_from_object(gctr_object, "counter", "[B"); + Node* subkeyHtbl = load_field_from_object(ghash_object, "subkeyHtbl", "[J"); + Node* state = load_field_from_object(ghash_object, "state", "[J"); + + if (embeddedCipherObj == NULL || counter == NULL || subkeyHtbl == NULL || state == NULL) { + return false; + } + // cast it to what we know it will be at runtime + const TypeInstPtr* tinst = _gvn.type(gctr_object)->isa_instptr(); + assert(tinst != NULL, "GCTR obj is null"); + assert(tinst->klass()->is_loaded(), "GCTR obj is not loaded"); + ciKlass* klass_AESCrypt = tinst->klass()->as_instance_klass()->find_klass(ciSymbol::make("com/sun/crypto/provider/AESCrypt")); + assert(klass_AESCrypt->is_loaded(), "predicate checks that this class is loaded"); + ciInstanceKlass* instklass_AESCrypt = klass_AESCrypt->as_instance_klass(); + const TypeKlassPtr* aklass = TypeKlassPtr::make(instklass_AESCrypt); + const TypeOopPtr* xtype = aklass->as_instance_type(); + Node* aescrypt_object = new CheckCastPPNode(control(), embeddedCipherObj, xtype); + aescrypt_object = _gvn.transform(aescrypt_object); + // we need to get the start of the aescrypt_object's expanded key array + Node* k_start = get_key_start_from_aescrypt_object(aescrypt_object); + if (k_start == NULL) return false; + + // similarly, get the start address of the r vector + Node* cnt_start = array_element_address(counter, intcon(0), T_BYTE); + Node* state_start = array_element_address(state, intcon(0), T_LONG); + Node* subkeyHtbl_start = array_element_address(subkeyHtbl, intcon(0), T_LONG); + + // Call the stub, passing params + Node* gcmCrypt = make_runtime_call(RC_LEAF|RC_NO_FP, + OptoRuntime::galoisCounterMode_aescrypt_Type(), + stubAddr, stubName, TypePtr::BOTTOM, + in_start, len, ct_start, out_start, k_start, state_start, subkeyHtbl_start, cnt_start); + + // return cipher length (int) + Node* retvalue = _gvn.transform(new ProjNode(gcmCrypt, TypeFunc::Parms)); + set_result(retvalue); + return true; +} + +//----------------------------inline_galoisCounterMode_AESCrypt_predicate---------------------------- +// Return node representing slow path of predicate check. +// the pseudo code we want to emulate with this predicate is: +// for encryption: +// if (embeddedCipherObj instanceof AESCrypt) do_intrinsic, else do_javapath +// for decryption: +// if ((embeddedCipherObj instanceof AESCrypt) && (cipher!=plain)) do_intrinsic, else do_javapath +// note cipher==plain is more conservative than the original java code but that's OK +// + +Node* LibraryCallKit::inline_galoisCounterMode_AESCrypt_predicate() { + // The receiver was checked for NULL already. + Node* objGCTR = argument(7); + // Load embeddedCipher field of GCTR object. + Node* embeddedCipherObj = load_field_from_object(objGCTR, "embeddedCipher", "Lcom/sun/crypto/provider/SymmetricCipher;"); + assert(embeddedCipherObj != NULL, "embeddedCipherObj is null"); + + // get AESCrypt klass for instanceOf check + // AESCrypt might not be loaded yet if some other SymmetricCipher got us to this compile point + // will have same classloader as CipherBlockChaining object + const TypeInstPtr* tinst = _gvn.type(objGCTR)->isa_instptr(); + assert(tinst != NULL, "GCTR obj is null"); + assert(tinst->klass()->is_loaded(), "GCTR obj is not loaded"); + + // we want to do an instanceof comparison against the AESCrypt class + ciKlass* klass_AESCrypt = tinst->klass()->as_instance_klass()->find_klass(ciSymbol::make("com/sun/crypto/provider/AESCrypt")); + if (!klass_AESCrypt->is_loaded()) { + // if AESCrypt is not even loaded, we never take the intrinsic fast path + Node* ctrl = control(); + set_control(top()); // no regular fast path + return ctrl; + } + + ciInstanceKlass* instklass_AESCrypt = klass_AESCrypt->as_instance_klass(); + Node* instof = gen_instanceof(embeddedCipherObj, makecon(TypeKlassPtr::make(instklass_AESCrypt))); + Node* cmp_instof = _gvn.transform(new CmpINode(instof, intcon(1))); + Node* bool_instof = _gvn.transform(new BoolNode(cmp_instof, BoolTest::ne)); + Node* instof_false = generate_guard(bool_instof, NULL, PROB_MIN); + + return instof_false; // even if it is NULL +} + //------------------------------get_state_from_digest_object----------------------- Node * LibraryCallKit::get_state_from_digest_object(Node *digest_object, const char *state_type) { Node* digest_state = load_field_from_object(digest_object, "state", state_type); diff --git a/src/hotspot/share/opto/library_call.hpp b/src/hotspot/share/opto/library_call.hpp index 1f483219297f0..adb1cb06c957b 100644 --- a/src/hotspot/share/opto/library_call.hpp +++ b/src/hotspot/share/opto/library_call.hpp @@ -305,6 +305,8 @@ class LibraryCallKit : public GraphKit { bool inline_fma(vmIntrinsics::ID id); bool inline_character_compare(vmIntrinsics::ID id); bool inline_fp_min_max(vmIntrinsics::ID id); + bool inline_galoisCounterMode_AESCrypt(); + Node* inline_galoisCounterMode_AESCrypt_predicate(); bool inline_profileBoolean(); bool inline_isCompileConstant(); diff --git a/src/hotspot/share/opto/loopopts.cpp b/src/hotspot/share/opto/loopopts.cpp index d86a5db0718f7..5df0c71f53d52 100644 --- a/src/hotspot/share/opto/loopopts.cpp +++ b/src/hotspot/share/opto/loopopts.cpp @@ -1435,12 +1435,16 @@ void PhaseIdealLoop::split_if_with_blocks_post(Node *n) { // like various versions of induction variable+offset. Clone the // computation per usage to allow it to sink out of the loop. void PhaseIdealLoop::try_sink_out_of_loop(Node* n) { + bool is_raw_to_oop_cast = n->is_ConstraintCast() && + n->in(1)->bottom_type()->isa_rawptr() && + !n->bottom_type()->isa_rawptr(); if (has_ctrl(n) && !n->is_Phi() && !n->is_Bool() && !n->is_Proj() && !n->is_MergeMem() && !n->is_CMove() && + !is_raw_to_oop_cast && // don't extend live ranges of raw oops n->Opcode() != Op_Opaque4) { Node *n_ctrl = get_ctrl(n); IdealLoopTree *n_loop = get_loop(n_ctrl); diff --git a/src/hotspot/share/opto/runtime.cpp b/src/hotspot/share/opto/runtime.cpp index 3608f22d0cd76..22fa5e48bd7eb 100644 --- a/src/hotspot/share/opto/runtime.cpp +++ b/src/hotspot/share/opto/runtime.cpp @@ -955,6 +955,31 @@ const TypeFunc* OptoRuntime::counterMode_aescrypt_Type() { return TypeFunc::make(domain, range); } +//for counterMode calls of aescrypt encrypt/decrypt, four pointers and a length, returning int +const TypeFunc* OptoRuntime::galoisCounterMode_aescrypt_Type() { + // create input type (domain) + int num_args = 8; + int argcnt = num_args; + const Type** fields = TypeTuple::fields(argcnt); + int argp = TypeFunc::Parms; + fields[argp++] = TypePtr::NOTNULL; // byte[] in + inOfs + fields[argp++] = TypeInt::INT; // int len + fields[argp++] = TypePtr::NOTNULL; // byte[] ct + ctOfs + fields[argp++] = TypePtr::NOTNULL; // byte[] out + outOfs + fields[argp++] = TypePtr::NOTNULL; // byte[] key from AESCrypt obj + fields[argp++] = TypePtr::NOTNULL; // long[] state from GHASH obj + fields[argp++] = TypePtr::NOTNULL; // long[] subkeyHtbl from GHASH obj + fields[argp++] = TypePtr::NOTNULL; // byte[] counter from GCTR obj + + assert(argp == TypeFunc::Parms + argcnt, "correct decoding"); + const TypeTuple* domain = TypeTuple::make(TypeFunc::Parms + argcnt, fields); + // returning cipher len (int) + fields = TypeTuple::fields(1); + fields[TypeFunc::Parms + 0] = TypeInt::INT; + const TypeTuple* range = TypeTuple::make(TypeFunc::Parms + 1, fields); + return TypeFunc::make(domain, range); +} + /* * void implCompress(byte[] buf, int ofs) */ diff --git a/src/hotspot/share/opto/runtime.hpp b/src/hotspot/share/opto/runtime.hpp index ec83bda805caa..b056c2828c392 100644 --- a/src/hotspot/share/opto/runtime.hpp +++ b/src/hotspot/share/opto/runtime.hpp @@ -257,6 +257,7 @@ class OptoRuntime : public AllStatic { static const TypeFunc* cipherBlockChaining_aescrypt_Type(); static const TypeFunc* electronicCodeBook_aescrypt_Type(); static const TypeFunc* counterMode_aescrypt_Type(); + static const TypeFunc* galoisCounterMode_aescrypt_Type(); static const TypeFunc* digestBase_implCompress_Type(bool is_sha3); static const TypeFunc* digestBase_implCompressMB_Type(bool is_sha3); diff --git a/src/hotspot/share/prims/jni.cpp b/src/hotspot/share/prims/jni.cpp index 9d7a54e630d1e..745e472a81007 100644 --- a/src/hotspot/share/prims/jni.cpp +++ b/src/hotspot/share/prims/jni.cpp @@ -3658,7 +3658,7 @@ static jint JNI_CreateJavaVM_inner(JavaVM **vm, void **penv, void *args) { #endif // Since this is not a JVM_ENTRY we have to set the thread state manually before leaving. - ThreadStateTransition::transition(thread, _thread_in_vm, _thread_in_native); + ThreadStateTransition::transition_from_vm(thread, _thread_in_native); MACOS_AARCH64_ONLY(thread->enable_wx(WXExec)); } else { // If create_vm exits because of a pending exception, exit with that @@ -3878,11 +3878,8 @@ static jint attach_current_thread(JavaVM *vm, void **penv, void *_args, bool dae *(JNIEnv**)penv = thread->jni_environment(); // Now leaving the VM, so change thread_state. This is normally automatically taken care - // of in the JVM_ENTRY. But in this situation we have to do it manually. Notice, that by - // using ThreadStateTransition::transition, we do a callback to the safepoint code if - // needed. - - ThreadStateTransition::transition(thread, _thread_in_vm, _thread_in_native); + // of in the JVM_ENTRY. But in this situation we have to do it manually. + ThreadStateTransition::transition_from_vm(thread, _thread_in_native); MACOS_AARCH64_ONLY(thread->enable_wx(WXExec)); // Perform any platform dependent FPU setup diff --git a/src/hotspot/share/prims/jvmtiExport.cpp b/src/hotspot/share/prims/jvmtiExport.cpp index 80d2c7ddcdf09..7f484d1ebac6f 100644 --- a/src/hotspot/share/prims/jvmtiExport.cpp +++ b/src/hotspot/share/prims/jvmtiExport.cpp @@ -117,7 +117,7 @@ class JvmtiThreadEventTransition : StackObj { if (_saved_state == _thread_in_Java) { ThreadStateTransition::transition_from_java(_jthread, _thread_in_native); } else { - ThreadStateTransition::transition(_jthread, _saved_state, _thread_in_native); + ThreadStateTransition::transition_from_vm(_jthread, _thread_in_native); } } else { _jthread = NULL; diff --git a/src/hotspot/share/prims/jvmtiTagMap.cpp b/src/hotspot/share/prims/jvmtiTagMap.cpp index 5f9de94fbcfc4..e17a4dcb26371 100644 --- a/src/hotspot/share/prims/jvmtiTagMap.cpp +++ b/src/hotspot/share/prims/jvmtiTagMap.cpp @@ -72,8 +72,7 @@ bool JvmtiTagMap::_has_object_free_events = false; // create a JvmtiTagMap JvmtiTagMap::JvmtiTagMap(JvmtiEnv* env) : _env(env), - _lock(Mutex::nonleaf+1, "JvmtiTagMap_lock", Mutex::_allow_vm_block_flag, - Mutex::_safepoint_check_never), + _lock(Mutex::nonleaf+1, "JvmtiTagMap_lock", Mutex::_safepoint_check_never), _needs_rehashing(false), _needs_cleaning(false) { diff --git a/src/hotspot/share/prims/methodHandles.cpp b/src/hotspot/share/prims/methodHandles.cpp index 9419bab7b3615..5ae35e34a8c84 100644 --- a/src/hotspot/share/prims/methodHandles.cpp +++ b/src/hotspot/share/prims/methodHandles.cpp @@ -158,7 +158,7 @@ int MethodHandles::ref_kind_to_flags(int ref_kind) { Handle MethodHandles::resolve_MemberName_type(Handle mname, Klass* caller, TRAPS) { Handle empty; Handle type(THREAD, java_lang_invoke_MemberName::type(mname())); - if (!java_lang_String::is_instance_inlined(type())) { + if (!java_lang_String::is_instance(type())) { return type; // already resolved } Symbol* signature = java_lang_String::as_symbol_or_null(type()); @@ -536,7 +536,7 @@ Symbol* MethodHandles::lookup_signature(oop type_str, bool intern_if_not_found, return java_lang_invoke_MethodType::as_signature(type_str, intern_if_not_found); } else if (java_lang_Class::is_instance(type_str)) { return java_lang_Class::as_signature(type_str, false); - } else if (java_lang_String::is_instance_inlined(type_str)) { + } else if (java_lang_String::is_instance(type_str)) { if (intern_if_not_found) { return java_lang_String::as_symbol(type_str); } else { diff --git a/src/hotspot/share/prims/universalUpcallHandler.cpp b/src/hotspot/share/prims/universalUpcallHandler.cpp index 12379238f719a..3457d4202ff98 100644 --- a/src/hotspot/share/prims/universalUpcallHandler.cpp +++ b/src/hotspot/share/prims/universalUpcallHandler.cpp @@ -83,20 +83,12 @@ JavaThread* ProgrammableUpcallHandler::on_entry(OptimizedEntryBlob::FrameData* c // since it can potentially block. context->new_handles = JNIHandleBlock::allocate_block(thread); + // clear any pending exception in thread (native calls start with no exception pending) + thread->clear_pending_exception(); + // After this, we are officially in Java Code. This needs to be done before we change any of the thread local // info, since we cannot find oops before the new information is set up completely. - ThreadStateTransition::transition_from_native(thread, _thread_in_Java); - - // Make sure that we handle asynchronous stops and suspends _before_ we clear all thread state - // in OptimizedEntryBlob::FrameData. This way, we can decide if we need to do any pd actions - // to prepare for stop/suspend (cache sp, or other state). - bool clear_pending_exception = true; - if (thread->has_special_runtime_exit_condition()) { - thread->handle_special_runtime_exit_condition(); - if (thread->has_pending_exception()) { - clear_pending_exception = false; - } - } + ThreadStateTransition::transition_from_native(thread, _thread_in_Java, true /* check_asyncs */); context->old_handles = thread->active_handles(); @@ -111,11 +103,6 @@ JavaThread* ProgrammableUpcallHandler::on_entry(OptimizedEntryBlob::FrameData* c debug_only(thread->inc_java_call_counter()); thread->set_active_handles(context->new_handles); // install new handle block and reset Java frame linkage - // clear any pending exception in thread (native calls start with no exception pending) - if (clear_pending_exception) { - thread->clear_pending_exception(); - } - MACOS_AARCH64_ONLY(thread->enable_wx(WXExec)); return thread; diff --git a/src/hotspot/share/runtime/arguments.cpp b/src/hotspot/share/runtime/arguments.cpp index 870493ebb1028..a35570570612f 100644 --- a/src/hotspot/share/runtime/arguments.cpp +++ b/src/hotspot/share/runtime/arguments.cpp @@ -534,6 +534,7 @@ static SpecialFlag const special_jvm_flags[] = { // -------------- Obsolete Flags - sorted by expired_in -------------- { "CriticalJNINatives", JDK_Version::jdk(16), JDK_Version::jdk(18), JDK_Version::jdk(19) }, + { "InlineFrequencyCount", JDK_Version::undefined(), JDK_Version::jdk(18), JDK_Version::jdk(19) }, { "G1RSetRegionEntries", JDK_Version::undefined(), JDK_Version::jdk(18), JDK_Version::jdk(19) }, { "G1RSetSparseRegionEntries", JDK_Version::undefined(), JDK_Version::jdk(18), JDK_Version::jdk(19) }, { "AlwaysLockClassLoader", JDK_Version::jdk(17), JDK_Version::jdk(18), JDK_Version::jdk(19) }, diff --git a/src/hotspot/share/runtime/globals.hpp b/src/hotspot/share/runtime/globals.hpp index 354813c207c85..a1d30d694d1c7 100644 --- a/src/hotspot/share/runtime/globals.hpp +++ b/src/hotspot/share/runtime/globals.hpp @@ -457,22 +457,22 @@ const intx ObjectAlignmentInBytes = 8; "Used to help diagnose memory stomping bugs.") \ \ develop(bool, ZapResourceArea, trueInDebug, \ - "Zap freed resource/arena space with 0xABABABAB") \ + "Zap freed resource/arena space") \ \ notproduct(bool, ZapVMHandleArea, trueInDebug, \ - "Zap freed VM handle space with 0xBCBCBCBC") \ + "Zap freed VM handle space") \ \ notproduct(bool, ZapStackSegments, trueInDebug, \ - "Zap allocated/freed stack segments with 0xFADFADED") \ + "Zap allocated/freed stack segments") \ \ develop(bool, ZapUnusedHeapArea, trueInDebug, \ - "Zap unused heap space with 0xBAADBABE") \ + "Zap unused heap space") \ \ develop(bool, CheckZapUnusedHeapArea, false, \ "Check zapping of unused heap space") \ \ develop(bool, ZapFillerObjects, trueInDebug, \ - "Zap filler objects with 0xDEAFBABE") \ + "Zap filler objects") \ \ product(bool, ExecutingUnitTests, false, \ "Whether the JVM is running unit tests or not") \ @@ -1400,14 +1400,8 @@ const intx ObjectAlignmentInBytes = 8; product(intx, SpecTrapLimitExtraEntries, 3, EXPERIMENTAL, \ "Extra method data trap entries for speculation") \ \ - develop(intx, InlineFrequencyRatio, 20, \ + product(double, InlineFrequencyRatio, 0.25, DIAGNOSTIC, \ "Ratio of call site execution to caller method invocation") \ - range(0, max_jint) \ - \ - product_pd(intx, InlineFrequencyCount, DIAGNOSTIC, \ - "Count of call site execution necessary to trigger frequent " \ - "inlining") \ - range(0, max_jint) \ \ develop(intx, InlineThrowCount, 50, \ "Force inlining of interpreted methods that throw this often") \ diff --git a/src/hotspot/share/runtime/handshake.cpp b/src/hotspot/share/runtime/handshake.cpp index 2841d5a6f24a5..e2a951397ef58 100644 --- a/src/hotspot/share/runtime/handshake.cpp +++ b/src/hotspot/share/runtime/handshake.cpp @@ -408,7 +408,7 @@ void Handshake::execute(AsyncHandshakeClosure* hs_cl, JavaThread* target) { HandshakeState::HandshakeState(JavaThread* target) : _handshakee(target), _queue(), - _lock(Monitor::leaf, "HandshakeState", Mutex::_allow_vm_block_flag, Monitor::_safepoint_check_never), + _lock(Monitor::leaf, "HandshakeState", Monitor::_safepoint_check_never), _active_handshaker(), _suspended(false), _async_suspend_handshake(false) diff --git a/src/hotspot/share/runtime/interfaceSupport.inline.hpp b/src/hotspot/share/runtime/interfaceSupport.inline.hpp index 0701881ccb779..2628bfbdea1a4 100644 --- a/src/hotspot/share/runtime/interfaceSupport.inline.hpp +++ b/src/hotspot/share/runtime/interfaceSupport.inline.hpp @@ -76,59 +76,54 @@ class InterfaceSupport: AllStatic { class ThreadStateTransition : public StackObj { protected: JavaThread* _thread; - public: - ThreadStateTransition(JavaThread *thread) { - _thread = thread; - assert(thread != NULL, "must be active Java thread"); - assert(thread == Thread::current(), "must be current thread"); - } - // Change threadstate in a manner, so safepoint can detect changes. - // Time-critical: called on exit from every runtime routine - static inline void transition(JavaThread *thread, JavaThreadState from, JavaThreadState to) { - assert(from != _thread_in_Java, "use transition_from_java"); - assert(from != _thread_in_native, "use transition_from_native"); - assert((from & 1) == 0 && (to & 1) == 0, "odd numbers are transitions states"); - assert(thread->thread_state() == from, "coming from wrong thread state"); - - // Check NoSafepointVerifier - // This also clears unhandled oops if CheckUnhandledOops is used. + private: + static inline void transition_and_process(JavaThread *thread, JavaThreadState to, bool check_asyncs) { + // Check NoSafepointVerifier. This also clears unhandled oops if CheckUnhandledOops is used. thread->check_possible_safepoint(); - // Change to transition state and ensure it is seen by the VM thread. - thread->set_thread_state_fence((JavaThreadState)(from + 1)); - - SafepointMechanism::process_if_requested(thread); + thread->set_thread_state_fence(_thread_in_vm); + SafepointMechanism::process_if_requested_with_exit_check(thread, check_asyncs); thread->set_thread_state(to); } - // Same as above, but assumes from = _thread_in_Java. This is simpler, since we - // never block on entry to the VM. This will break the code, since e.g. preserve arguments - // have not been setup. + public: + ThreadStateTransition(JavaThread *thread) : _thread(thread) { + assert(thread != NULL, "must be active Java thread"); + assert(thread == Thread::current(), "must be current thread"); + } + static inline void transition_from_java(JavaThread *thread, JavaThreadState to) { assert(thread->thread_state() == _thread_in_Java, "coming from wrong thread state"); + assert(to == _thread_in_vm || to == _thread_in_native, "invalid transition"); thread->set_thread_state(to); } - static inline void transition_from_native(JavaThread *thread, JavaThreadState to) { - assert((to & 1) == 0, "odd numbers are transitions states"); + // We never install asynchronous exceptions when coming (back) in to the runtime + // from native code because the runtime is not set up to handle exceptions floating + // around at arbitrary points. + static inline void transition_from_native(JavaThread *thread, JavaThreadState to, bool check_asyncs = true) { assert(thread->thread_state() == _thread_in_native, "coming from wrong thread state"); - assert(!thread->has_last_Java_frame() || thread->frame_anchor()->walkable(), "Unwalkable stack in native->vm transition"); - - // Change to transition state and ensure it is seen by the VM thread. - thread->set_thread_state_fence(_thread_in_native_trans); - - // We never install asynchronous exceptions when coming (back) in - // to the runtime from native code because the runtime is not set - // up to handle exceptions floating around at arbitrary points. - SafepointMechanism::process_if_requested_with_exit_check(thread, false /* check asyncs */); - thread->set_thread_state(to); + assert(to == _thread_in_vm || to == _thread_in_Java, "invalid transition"); + assert(!thread->has_last_Java_frame() || thread->frame_anchor()->walkable(), "Unwalkable stack in native transition"); + transition_and_process(thread, to, to != _thread_in_Java ? false : check_asyncs); } - protected: - void trans(JavaThreadState from, JavaThreadState to) { transition(_thread, from, to); } - void trans_from_java(JavaThreadState to) { transition_from_java(_thread, to); } - void trans_from_native(JavaThreadState to) { transition_from_native(_thread, to); } + static inline void transition_from_vm(JavaThread *thread, JavaThreadState to, bool check_asyncs = true) { + assert(thread->thread_state() == _thread_in_vm, "coming from wrong thread state"); + if (to == _thread_in_Java) { + transition_and_process(thread, _thread_in_Java, check_asyncs); + } else { + assert(to == _thread_in_native || to == _thread_blocked, "invalid transition"); + // Check NoSafepointVerifier. This also clears unhandled oops if CheckUnhandledOops is used. + thread->check_possible_safepoint(); + + // Once we are in native/blocked vm expects stack to be walkable + thread->frame_anchor()->make_walkable(thread); + OrderAccess::storestore(); // Keep thread_state change and make_walkable() separate. + thread->set_thread_state(to); + } + } }; class ThreadInVMForHandshake : public ThreadStateTransition { @@ -158,16 +153,15 @@ class ThreadInVMfromJava : public ThreadStateTransition { bool _check_asyncs; public: ThreadInVMfromJava(JavaThread* thread, bool check_asyncs = true) : ThreadStateTransition(thread), _check_asyncs(check_asyncs) { - trans_from_java(_thread_in_vm); + transition_from_java(thread, _thread_in_vm); } ~ThreadInVMfromJava() { if (_thread->stack_overflow_state()->stack_yellow_reserved_zone_disabled()) { _thread->stack_overflow_state()->enable_stack_yellow_reserved_zone(); } - trans(_thread_in_vm, _thread_in_Java); // We prevent asynchronous exceptions from being installed on return to Java in situations // where we can't tolerate them. See bugs: 4324348, 4854693, 4998314, 5040492, 5050705. - if (_thread->has_special_runtime_exit_condition()) _thread->handle_special_runtime_exit_condition(_check_asyncs); + transition_from_vm(_thread, _thread_in_Java, _check_asyncs); } }; @@ -191,7 +185,7 @@ class ThreadInVMfromUnknown { } ~ThreadInVMfromUnknown() { if (_thread) { - ThreadStateTransition::transition(_thread, _thread_in_vm, _thread_in_native); + ThreadStateTransition::transition_from_vm(_thread, _thread_in_native); } } }; @@ -201,17 +195,12 @@ class ThreadInVMfromNative : public ThreadStateTransition { ResetNoHandleMark __rnhm; public: ThreadInVMfromNative(JavaThread* thread) : ThreadStateTransition(thread) { - trans_from_native(_thread_in_vm); + transition_from_native(thread, _thread_in_vm); } ~ThreadInVMfromNative() { - assert(_thread->thread_state() == _thread_in_vm, "coming from wrong thread state"); // We cannot assert !_thread->owns_locks() since we have valid cases where // we call known native code using this wrapper holding locks. - _thread->check_possible_safepoint(); - // Once we are in native vm expects stack to be walkable - _thread->frame_anchor()->make_walkable(_thread); - OrderAccess::storestore(); // Keep thread_state change and make_walkable() separate. - _thread->set_thread_state(_thread_in_native); + transition_from_vm(_thread, _thread_in_native); } }; @@ -219,17 +208,11 @@ class ThreadInVMfromNative : public ThreadStateTransition { class ThreadToNativeFromVM : public ThreadStateTransition { public: ThreadToNativeFromVM(JavaThread *thread) : ThreadStateTransition(thread) { - // We are leaving the VM at this point and going directly to native code. - // Block, if we are in the middle of a safepoint synchronization. assert(!thread->owns_locks(), "must release all locks when leaving VM"); - thread->frame_anchor()->make_walkable(thread); - trans(_thread_in_vm, _thread_in_native); - // Check for pending. async. exceptions or suspends. - if (_thread->has_special_runtime_exit_condition()) _thread->handle_special_runtime_exit_condition(false); + transition_from_vm(thread, _thread_in_native); } - ~ThreadToNativeFromVM() { - trans_from_native(_thread_in_vm); + transition_from_native(_thread, _thread_in_vm); assert(!_thread->is_pending_jni_exception_check(), "Pending JNI Exception Check"); // We don't need to clear_walkable because it will happen automagically when we return to java } @@ -247,12 +230,7 @@ class ThreadBlockInVMPreprocess : public ThreadStateTransition { public: ThreadBlockInVMPreprocess(JavaThread* thread, PRE_PROC& pr = emptyOp, bool allow_suspend = false) : ThreadStateTransition(thread), _pr(pr), _allow_suspend(allow_suspend) { - assert(thread->thread_state() == _thread_in_vm, "coming from wrong thread state"); - thread->check_possible_safepoint(); - // Once we are blocked vm expects stack to be walkable - thread->frame_anchor()->make_walkable(thread); - OrderAccess::storestore(); // Keep thread_state change and make_walkable() separate. - thread->set_thread_state(_thread_blocked); + transition_from_vm(thread, _thread_blocked); } ~ThreadBlockInVMPreprocess() { assert(_thread->thread_state() == _thread_blocked, "coming from wrong thread state"); diff --git a/src/hotspot/share/runtime/javaCalls.cpp b/src/hotspot/share/runtime/javaCalls.cpp index 798cee7a6f88b..5390c5f6eaf0f 100644 --- a/src/hotspot/share/runtime/javaCalls.cpp +++ b/src/hotspot/share/runtime/javaCalls.cpp @@ -54,7 +54,6 @@ JavaCallWrapper::JavaCallWrapper(const methodHandle& callee_method, Handle receiver, JavaValue* result, TRAPS) { JavaThread* thread = THREAD; - bool clear_pending_exception = true; guarantee(thread->is_Java_thread(), "crucial check - the VM thread cannot and must not escape to Java code"); assert(!thread->owns_locks(), "must release all locks when leaving VM"); @@ -65,19 +64,12 @@ JavaCallWrapper::JavaCallWrapper(const methodHandle& callee_method, Handle recei // since it can potentially block. JNIHandleBlock* new_handles = JNIHandleBlock::allocate_block(thread); + // clear any pending exception in thread (native calls start with no exception pending) + thread->clear_pending_exception(); + // After this, we are official in JavaCode. This needs to be done before we change any of the thread local // info, since we cannot find oops before the new information is set up completely. - ThreadStateTransition::transition(thread, _thread_in_vm, _thread_in_Java); - - // Make sure that we handle asynchronous stops and suspends _before_ we clear all thread state - // in JavaCallWrapper::JavaCallWrapper(). This way, we can decide if we need to do any pd actions - // to prepare for stop/suspend (flush register windows on sparcs, cache sp, or other state). - if (thread->has_special_runtime_exit_condition()) { - thread->handle_special_runtime_exit_condition(); - if (HAS_PENDING_EXCEPTION) { - clear_pending_exception = false; - } - } + ThreadStateTransition::transition_from_vm(thread, _thread_in_Java, true /* check_asyncs */); // Make sure to set the oop's after the thread transition - since we can block there. No one is GC'ing // the JavaCallWrapper before the entry frame is on the stack. @@ -104,11 +96,6 @@ JavaCallWrapper::JavaCallWrapper(const methodHandle& callee_method, Handle recei assert (_thread->thread_state() != _thread_in_native, "cannot set native pc to NULL"); - // clear any pending exception in thread (native calls start with no exception pending) - if(clear_pending_exception) { - _thread->clear_pending_exception(); - } - MACOS_AARCH64_ONLY(_thread->enable_wx(WXExec)); } diff --git a/src/hotspot/share/runtime/mutex.cpp b/src/hotspot/share/runtime/mutex.cpp index f56216a301810..265735cc5e296 100644 --- a/src/hotspot/share/runtime/mutex.cpp +++ b/src/hotspot/share/runtime/mutex.cpp @@ -274,8 +274,8 @@ Mutex::~Mutex() { os::free(const_cast(_name)); } -Mutex::Mutex(int Rank, const char * name, bool allow_vm_block, - SafepointCheckRequired safepoint_check_required) : _owner(NULL) { +Mutex::Mutex(int Rank, const char * name, SafepointCheckRequired safepoint_check_required, + bool allow_vm_block) : _owner(NULL) { assert(os::mutex_init_done(), "Too early!"); assert(name != NULL, "Mutex requires a name"); _name = os::strdup(name, mtInternal); @@ -287,13 +287,16 @@ Mutex::Mutex(int Rank, const char * name, bool allow_vm_block, assert(_rank > special || _safepoint_check_required == _safepoint_check_never, "Special locks or below should never safepoint"); + + // The allow_vm_block also includes allowing other non-Java threads to block or + // allowing Java threads to block in native. + assert(_safepoint_check_required == _safepoint_check_always || _allow_vm_block, + "Safepoint check never locks should always allow the vm to block"); + + assert(_rank >= 0, "Bad lock rank"); #endif } -Monitor::Monitor(int Rank, const char * name, bool allow_vm_block, - SafepointCheckRequired safepoint_check_required) : - Mutex(Rank, name, allow_vm_block, safepoint_check_required) {} - bool Mutex::owned_by_self() const { return owner() == Thread::current(); } @@ -364,23 +367,20 @@ Mutex* Mutex::get_least_ranked_lock_besides_this(Mutex* locks) { // Tests for rank violations that might indicate exposure to deadlock. void Mutex::check_rank(Thread* thread) { - assert(this->rank() >= 0, "bad lock rank"); Mutex* locks_owned = thread->owned_locks(); if (!SafepointSynchronize::is_at_safepoint()) { // We expect the locks already acquired to be in increasing rank order, - // modulo locks of native rank or acquired in try_lock_without_rank_check() + // modulo locks acquired in try_lock_without_rank_check() for (Mutex* tmp = locks_owned; tmp != NULL; tmp = tmp->next()) { if (tmp->next() != NULL) { - assert(tmp->rank() == Mutex::native || tmp->rank() < tmp->next()->rank() + assert(tmp->rank() < tmp->next()->rank() || tmp->skip_rank_check(), "mutex rank anomaly?"); } } } - // Locks with rank native are an exception and are not - // subject to the verification rules. - bool check_can_be_skipped = this->rank() == Mutex::native || SafepointSynchronize::is_at_safepoint(); + bool check_can_be_skipped = SafepointSynchronize::is_at_safepoint(); if (owned_by_self()) { // wait() case Mutex* least = get_least_ranked_lock_besides_this(locks_owned); diff --git a/src/hotspot/share/runtime/mutex.hpp b/src/hotspot/share/runtime/mutex.hpp index 13bfda92f3e31..82479267918d1 100644 --- a/src/hotspot/share/runtime/mutex.hpp +++ b/src/hotspot/share/runtime/mutex.hpp @@ -42,38 +42,19 @@ class Mutex : public CHeapObj { public: - // A special lock: Is a lock where you are guaranteed not to block while you are - // holding it, i.e., no vm operation can happen, taking other (blocking) locks, etc. - // The rank 'access' is similar to 'special' and has the same restrictions on usage. - // It is reserved for locks that may be required in order to perform memory accesses - // that require special barriers, e.g. SATB GC barriers, that in turn uses locks. - // The rank 'tty' is also similar to 'special' and has the same restrictions. - // It is reserved for the tty_lock. - // Since memory accesses should be able to be performed pretty much anywhere - // in the code, that requires locks required for performing accesses being - // inherently a bit more special than even locks of the 'special' rank. - // NOTE: It is critical that the rank 'special' be the lowest (earliest) - // (except for "event" and "access") for the deadlock detection to work correctly. - // The rank native was only for use in Mutexes created by JVM_RawMonitorCreate, - // which being external to the VM are not subject to deadlock detection, - // however it has now been used by other locks that don't fit into the - // deadlock detection scheme. - // While at a safepoint no mutexes of rank safepoint are held by any thread. - // The rank named "leaf" is probably historical (and should - // be changed) -- mutexes of this rank aren't really leaf mutexes - // at all. + // Special low level locks are given names and ranges avoid overlap. enum lock_types { event, - access = event + 1, - tty = access + 2, + service = event + 3, + stackwatermark = service + 3, + tty = stackwatermark + 3, special = tty + 3, oopstorage = special + 3, leaf = oopstorage + 2, safepoint = leaf + 10, barrier = safepoint + 1, nonleaf = barrier + 1, - max_nonleaf = nonleaf + 900, - native = max_nonleaf + 1 + max_nonleaf = nonleaf + 900 }; private: @@ -162,8 +143,12 @@ class Mutex : public CHeapObj { NOT_PRODUCT(SafepointCheckRequired _safepoint_check_required;) public: - Mutex(int rank, const char *name, bool allow_vm_block = false, - SafepointCheckRequired safepoint_check_required = _safepoint_check_always); + Mutex(int rank, const char *name, SafepointCheckRequired safepoint_check_required, bool allow_vm_block); + + Mutex(int rank, const char *name, SafepointCheckRequired safepoint_check_required) : + Mutex(rank, name, safepoint_check_required, + safepoint_check_required == _safepoint_check_never ? true : false) {} + ~Mutex(); void lock(); // prints out warning if VM thread blocks @@ -203,9 +188,12 @@ class Mutex : public CHeapObj { class Monitor : public Mutex { public: - Monitor(int rank, const char *name, bool allow_vm_block = false, - SafepointCheckRequired safepoint_check_required = _safepoint_check_always); - // default destructor + Monitor(int rank, const char *name, SafepointCheckRequired safepoint_check_required, bool allow_vm_block) : + Mutex(rank, name, safepoint_check_required, allow_vm_block) {} + + Monitor(int rank, const char *name, SafepointCheckRequired safepoint_check_required) : + Mutex(rank, name, safepoint_check_required) {} + // default destructor // Wait until monitor is notified (or times out). // Defaults are to make safepoint checks, wait time is forever (i.e., @@ -224,9 +212,10 @@ class PaddedMutex : public Mutex { }; char _padding[PADDING_LEN]; public: - PaddedMutex(int rank, const char *name, bool allow_vm_block = false, - SafepointCheckRequired safepoint_check_required = _safepoint_check_always) : - Mutex(rank, name, allow_vm_block, safepoint_check_required) {}; + PaddedMutex(int rank, const char *name, SafepointCheckRequired safepoint_check_required, bool allow_vm_block) : + Mutex(rank, name, safepoint_check_required, allow_vm_block) {}; + PaddedMutex(int rank, const char *name, SafepointCheckRequired safepoint_check_required) : + Mutex(rank, name, safepoint_check_required) {}; }; class PaddedMonitor : public Monitor { @@ -236,9 +225,10 @@ class PaddedMonitor : public Monitor { }; char _padding[PADDING_LEN]; public: - PaddedMonitor(int rank, const char *name, bool allow_vm_block = false, - SafepointCheckRequired safepoint_check_required = _safepoint_check_always) : - Monitor(rank, name, allow_vm_block, safepoint_check_required) {}; + PaddedMonitor(int rank, const char *name, SafepointCheckRequired safepoint_check_required, bool allow_vm_block) : + Monitor(rank, name, safepoint_check_required, allow_vm_block) {}; + PaddedMonitor(int rank, const char *name, SafepointCheckRequired safepoint_check_required) : + Monitor(rank, name, safepoint_check_required) {}; }; #endif // SHARE_RUNTIME_MUTEX_HPP diff --git a/src/hotspot/share/runtime/mutexLocker.cpp b/src/hotspot/share/runtime/mutexLocker.cpp index 75952da1e8616..7242279f839ff 100644 --- a/src/hotspot/share/runtime/mutexLocker.cpp +++ b/src/hotspot/share/runtime/mutexLocker.cpp @@ -74,7 +74,6 @@ Mutex* NonJavaThreadsListSync_lock = NULL; Monitor* CGC_lock = NULL; Monitor* STS_lock = NULL; Monitor* G1OldGCCount_lock = NULL; -Mutex* Shared_DirtyCardQ_lock = NULL; Mutex* G1DetachedRefinementStats_lock = NULL; Mutex* MarkStackFreeList_lock = NULL; Mutex* MarkStackChunkList_lock = NULL; @@ -201,10 +200,10 @@ void assert_locked_or_safepoint_or_handshake(const Mutex* lock, const JavaThread } #endif -#define def(var, type, pri, vm_block, safepoint_check_allowed ) { \ - var = new type(Mutex::pri, #var, vm_block, Mutex::safepoint_check_allowed); \ - assert(_num_mutex < MAX_NUM_MUTEX, "increase MAX_NUM_MUTEX"); \ - _mutex_array[_num_mutex++] = var; \ +#define def(var, type, pri, vm_block, safepoint_check_allowed ) { \ + var = new type(Mutex::pri, #var, Mutex::safepoint_check_allowed, vm_block); \ + assert(_num_mutex < MAX_NUM_MUTEX, "increase MAX_NUM_MUTEX"); \ + _mutex_array[_num_mutex++] = var; \ } // Using Padded subclasses to prevent false sharing of these global monitors and mutexes. @@ -217,8 +216,6 @@ void mutex_init() { if (UseG1GC) { def(G1OldGCCount_lock , PaddedMonitor, leaf, true, _safepoint_check_always); - def(Shared_DirtyCardQ_lock , PaddedMutex , access + 1, true, _safepoint_check_never); - def(G1DetachedRefinementStats_lock, PaddedMutex, leaf , true, _safepoint_check_never); def(FreeList_lock , PaddedMutex , leaf , true, _safepoint_check_never); @@ -229,7 +226,7 @@ void mutex_init() { def(MarkStackFreeList_lock , PaddedMutex , leaf , true, _safepoint_check_never); def(MarkStackChunkList_lock , PaddedMutex , leaf , true, _safepoint_check_never); - def(MonitoringSupport_lock , PaddedMutex , native , true, _safepoint_check_never); // used for serviceability monitoring support + def(MonitoringSupport_lock , PaddedMutex , service-1, true, _safepoint_check_never); // used for serviceability monitoring support } def(StringDedup_lock , PaddedMonitor, leaf, true, _safepoint_check_never); def(StringDedupIntern_lock , PaddedMutex , leaf, true, _safepoint_check_never); @@ -244,11 +241,11 @@ void mutex_init() { def(Patching_lock , PaddedMutex , special, true, _safepoint_check_never); // used for safepointing and code patching. def(CompiledMethod_lock , PaddedMutex , special-1, true, _safepoint_check_never); - def(MonitorDeflation_lock , PaddedMonitor, tty-2, true, _safepoint_check_never); // used for monitor deflation thread operations - def(Service_lock , PaddedMonitor, tty-2, true, _safepoint_check_never); // used for service thread operations + def(MonitorDeflation_lock , PaddedMonitor, special, true, _safepoint_check_never); // used for monitor deflation thread operations + def(Service_lock , PaddedMonitor, service, true, _safepoint_check_never); // used for service thread operations if (UseNotificationThread) { - def(Notification_lock , PaddedMonitor, special, true, _safepoint_check_never); // used for notification thread operations + def(Notification_lock , PaddedMonitor, service, true, _safepoint_check_never); // used for notification thread operations } else { Notification_lock = Service_lock; } @@ -291,14 +288,14 @@ void mutex_init() { def(Heap_lock , PaddedMonitor, nonleaf+1, false, _safepoint_check_always); // Doesn't safepoint check during termination. def(JfieldIdCreation_lock , PaddedMutex , nonleaf+1, true, _safepoint_check_always); // jfieldID, Used in VM_Operation - def(CompiledIC_lock , PaddedMutex , nonleaf+2, false, _safepoint_check_never); // locks VtableStubs_lock, InlineCacheBuffer_lock + def(CompiledIC_lock , PaddedMutex , nonleaf+2, true, _safepoint_check_never); // locks VtableStubs_lock, InlineCacheBuffer_lock def(CompileTaskAlloc_lock , PaddedMutex , nonleaf+2, true, _safepoint_check_always); def(CompileStatistics_lock , PaddedMutex , nonleaf+2, false, _safepoint_check_always); def(DirectivesStack_lock , PaddedMutex , special, true, _safepoint_check_never); def(MultiArray_lock , PaddedMutex , nonleaf+2, false, _safepoint_check_always); def(JvmtiThreadState_lock , PaddedMutex , nonleaf+2, false, _safepoint_check_always); // Used by JvmtiThreadState/JvmtiEventController - def(EscapeBarrier_lock , PaddedMonitor, leaf, false, _safepoint_check_never); // Used to synchronize object reallocation/relocking triggered by JVMTI + def(EscapeBarrier_lock , PaddedMonitor, leaf, true, _safepoint_check_never); // Used to synchronize object reallocation/relocking triggered by JVMTI def(Management_lock , PaddedMutex , nonleaf+2, false, _safepoint_check_always); // used for JVM management def(ConcurrentGCBreakpoints_lock , PaddedMonitor, nonleaf, true, _safepoint_check_always); @@ -316,26 +313,26 @@ void mutex_init() { def(Zip_lock , PaddedMonitor, leaf, true, _safepoint_check_never); if (WhiteBoxAPI) { - def(Compilation_lock , PaddedMonitor, leaf, false, _safepoint_check_never); + def(Compilation_lock , PaddedMonitor, leaf, true, _safepoint_check_never); } #if INCLUDE_JFR def(JfrMsg_lock , PaddedMonitor, leaf, true, _safepoint_check_always); def(JfrBuffer_lock , PaddedMutex , leaf, true, _safepoint_check_never); - def(JfrStream_lock , PaddedMutex , nonleaf + 1, false, _safepoint_check_never); - def(JfrStacktrace_lock , PaddedMutex , tty-2, true, _safepoint_check_never); + def(JfrStream_lock , PaddedMutex , nonleaf + 1, true, _safepoint_check_never); + def(JfrStacktrace_lock , PaddedMutex , stackwatermark-1, true, _safepoint_check_never); def(JfrThreadSampler_lock , PaddedMonitor, leaf, true, _safepoint_check_never); #endif #ifndef SUPPORTS_NATIVE_CX8 - def(UnsafeJlong_lock , PaddedMutex , special, false, _safepoint_check_never); + def(UnsafeJlong_lock , PaddedMutex , special, true, _safepoint_check_never); #endif def(CodeHeapStateAnalytics_lock , PaddedMutex , nonleaf+6, false, _safepoint_check_always); def(NMethodSweeperStats_lock , PaddedMutex , special, true, _safepoint_check_never); def(ThreadsSMRDelete_lock , PaddedMonitor, special, true, _safepoint_check_never); def(ThreadIdTableCreate_lock , PaddedMutex , leaf, false, _safepoint_check_always); - def(SharedDecoder_lock , PaddedMutex , native, true, _safepoint_check_never); + def(SharedDecoder_lock , PaddedMutex , tty-1, true, _safepoint_check_never); def(DCmdFactory_lock , PaddedMutex , leaf, true, _safepoint_check_never); #if INCLUDE_NMT def(NMTQuery_lock , PaddedMutex , max_nonleaf, false, _safepoint_check_always); @@ -350,7 +347,7 @@ void mutex_init() { def(ClassListFile_lock , PaddedMutex , leaf, true, _safepoint_check_never); def(LambdaFormInvokers_lock , PaddedMutex , nonleaf+2, false, _safepoint_check_always); #endif // INCLUDE_CDS - def(Bootclasspath_lock , PaddedMutex , leaf, false, _safepoint_check_never); + def(Bootclasspath_lock , PaddedMutex , leaf, true, _safepoint_check_never); #if INCLUDE_JVMCI def(JVMCI_lock , PaddedMonitor, nonleaf+2, true, _safepoint_check_always); diff --git a/src/hotspot/share/runtime/mutexLocker.hpp b/src/hotspot/share/runtime/mutexLocker.hpp index cec0728e1cb9f..015a91babd766 100644 --- a/src/hotspot/share/runtime/mutexLocker.hpp +++ b/src/hotspot/share/runtime/mutexLocker.hpp @@ -68,9 +68,6 @@ extern Monitor* CGC_lock; // used for coordination betwee // fore- & background GC threads. extern Monitor* STS_lock; // used for joining/leaving SuspendibleThreadSet. extern Monitor* G1OldGCCount_lock; // in support of "concurrent" full gc -extern Mutex* Shared_DirtyCardQ_lock; // Lock protecting dirty card - // queue shared by - // non-Java threads. extern Mutex* G1DetachedRefinementStats_lock; // Lock protecting detached refinement stats extern Mutex* MarkStackFreeList_lock; // Protects access to the global mark stack free list. extern Mutex* MarkStackChunkList_lock; // Protects access to the global mark stack chunk list. diff --git a/src/hotspot/share/runtime/safepoint.hpp b/src/hotspot/share/runtime/safepoint.hpp index e73d029a2f8c2..2342b379b74eb 100644 --- a/src/hotspot/share/runtime/safepoint.hpp +++ b/src/hotspot/share/runtime/safepoint.hpp @@ -129,11 +129,10 @@ class SafepointSynchronize : AllStatic { static bool is_a_block_safe_state(JavaThreadState state) { // Check that we have a valid thread_state before blocking for safepoints switch(state) { - case _thread_in_vm_trans: + case _thread_in_vm: case _thread_in_Java: // From compiled code case _thread_in_native_trans: case _thread_blocked_trans: - case _thread_new_trans: return true; default: return false; diff --git a/src/hotspot/share/runtime/stackWatermark.cpp b/src/hotspot/share/runtime/stackWatermark.cpp index 2ceb9383e9c06..921210c2dc312 100644 --- a/src/hotspot/share/runtime/stackWatermark.cpp +++ b/src/hotspot/share/runtime/stackWatermark.cpp @@ -164,7 +164,7 @@ StackWatermark::StackWatermark(JavaThread* jt, StackWatermarkKind kind, uint32_t _next(NULL), _jt(jt), _iterator(NULL), - _lock(Mutex::tty - 1, "stack_watermark_lock", true, Mutex::_safepoint_check_never), + _lock(Mutex::stackwatermark, "StackWatermark_lock", Mutex::_safepoint_check_never), _kind(kind), _linked_watermark(NULL) { } diff --git a/src/hotspot/share/runtime/stubRoutines.cpp b/src/hotspot/share/runtime/stubRoutines.cpp index b231ce533fb74..591950fa213f0 100644 --- a/src/hotspot/share/runtime/stubRoutines.cpp +++ b/src/hotspot/share/runtime/stubRoutines.cpp @@ -124,6 +124,7 @@ address StubRoutines::_cipherBlockChaining_decryptAESCrypt = NULL; address StubRoutines::_electronicCodeBook_encryptAESCrypt = NULL; address StubRoutines::_electronicCodeBook_decryptAESCrypt = NULL; address StubRoutines::_counterMode_AESCrypt = NULL; +address StubRoutines::_galoisCounterMode_AESCrypt = NULL; address StubRoutines::_ghash_processBlocks = NULL; address StubRoutines::_base64_encodeBlock = NULL; address StubRoutines::_base64_decodeBlock = NULL; diff --git a/src/hotspot/share/runtime/stubRoutines.hpp b/src/hotspot/share/runtime/stubRoutines.hpp index 315c774a08edc..8fc7880a0775a 100644 --- a/src/hotspot/share/runtime/stubRoutines.hpp +++ b/src/hotspot/share/runtime/stubRoutines.hpp @@ -206,6 +206,7 @@ class StubRoutines: AllStatic { static address _electronicCodeBook_encryptAESCrypt; static address _electronicCodeBook_decryptAESCrypt; static address _counterMode_AESCrypt; + static address _galoisCounterMode_AESCrypt; static address _ghash_processBlocks; static address _base64_encodeBlock; static address _base64_decodeBlock; @@ -410,6 +411,7 @@ class StubRoutines: AllStatic { static address montgomerySquare() { return _montgomerySquare; } static address bigIntegerRightShift() { return _bigIntegerRightShiftWorker; } static address bigIntegerLeftShift() { return _bigIntegerLeftShiftWorker; } + static address galoisCounterMode_AESCrypt() { return _galoisCounterMode_AESCrypt; } static address vectorizedMismatch() { return _vectorizedMismatch; } diff --git a/src/hotspot/share/runtime/thread.cpp b/src/hotspot/share/runtime/thread.cpp index 1c9db2d45d0af..dc31a48620cb7 100644 --- a/src/hotspot/share/runtime/thread.cpp +++ b/src/hotspot/share/runtime/thread.cpp @@ -1015,8 +1015,8 @@ JavaThread::JavaThread() : _pending_failed_speculation(0), _jvmci{nullptr}, _jvmci_counters(nullptr), - _jvmci_reserved0(nullptr), - _jvmci_reserved1(nullptr), + _jvmci_reserved0(0), + _jvmci_reserved1(0), _jvmci_reserved_oop0(nullptr), #endif // INCLUDE_JVMCI @@ -1227,7 +1227,9 @@ void JavaThread::run() { // Thread is now sufficiently initialized to be handled by the safepoint code as being // in the VM. Change thread state from _thread_new to _thread_in_vm - ThreadStateTransition::transition(this, _thread_new, _thread_in_vm); + assert(this->thread_state() == _thread_new, "wrong thread state"); + set_thread_state(_thread_in_vm); + // Before a thread is on the threads list it is always safe, so after leaving the // _thread_new we should emit a instruction barrier. The distance to modified code // from here is probably far enough, but this is consistent and safe. @@ -1644,7 +1646,7 @@ void JavaThread::check_and_handle_async_exceptions() { case _thread_in_Java: { ThreadInVMfromJava tiv(this); JavaThread* THREAD = this; - Exceptions::throw_unsafe_access_internal_error(THREAD, __FILE__, __LINE__, "a fault occurred in a recent unsafe memory access operation in compiled Java code"); + Exceptions::throw_unsafe_access_internal_error(THREAD, __FILE__, __LINE__, "a fault occurred in an unsafe memory access operation in compiled Java code"); return; } default: diff --git a/src/hotspot/share/runtime/thread.hpp b/src/hotspot/share/runtime/thread.hpp index 397181da04c50..9bc8c94882950 100644 --- a/src/hotspot/share/runtime/thread.hpp +++ b/src/hotspot/share/runtime/thread.hpp @@ -958,8 +958,8 @@ class JavaThread: public Thread { jlong* _jvmci_counters; // Fast thread locals for use by JVMCI - intptr_t* _jvmci_reserved0; - intptr_t* _jvmci_reserved1; + jlong _jvmci_reserved0; + jlong _jvmci_reserved1; oop _jvmci_reserved_oop0; public: @@ -970,6 +970,30 @@ class JavaThread: public Thread { static bool resize_all_jvmci_counters(int new_size); + void set_jvmci_reserved_oop0(oop value) { + _jvmci_reserved_oop0 = value; + } + + oop get_jvmci_reserved_oop0() { + return _jvmci_reserved_oop0; + } + + void set_jvmci_reserved0(jlong value) { + _jvmci_reserved0 = value; + } + + jlong get_jvmci_reserved0() { + return _jvmci_reserved0; + } + + void set_jvmci_reserved1(jlong value) { + _jvmci_reserved1 = value; + } + + jlong get_jvmci_reserved1() { + return _jvmci_reserved1; + } + private: #endif // INCLUDE_JVMCI diff --git a/src/hotspot/share/runtime/vmOperations.cpp b/src/hotspot/share/runtime/vmOperations.cpp index 424c49db034a8..a6d4212058260 100644 --- a/src/hotspot/share/runtime/vmOperations.cpp +++ b/src/hotspot/share/runtime/vmOperations.cpp @@ -368,8 +368,7 @@ int VM_Exit::wait_for_threads_in_native_to_block() { assert(SafepointSynchronize::is_at_safepoint(), "must be at safepoint already"); Thread * thr_cur = Thread::current(); - Monitor timer(Mutex::leaf, "VM_Exit timer", true, - Monitor::_safepoint_check_never); + Monitor timer(Mutex::leaf, "VM_Exit timer", Monitor::_safepoint_check_never); // Compiler threads need longer wait because they can access VM data directly // while in native. If they are active and some structures being used are diff --git a/src/hotspot/share/runtime/vmStructs.cpp b/src/hotspot/share/runtime/vmStructs.cpp index 5f0c7d38be64e..28d34525f1316 100644 --- a/src/hotspot/share/runtime/vmStructs.cpp +++ b/src/hotspot/share/runtime/vmStructs.cpp @@ -540,6 +540,7 @@ static_field(StubRoutines, _electronicCodeBook_encryptAESCrypt, address) \ static_field(StubRoutines, _electronicCodeBook_decryptAESCrypt, address) \ static_field(StubRoutines, _counterMode_AESCrypt, address) \ + static_field(StubRoutines, _galoisCounterMode_AESCrypt, address) \ static_field(StubRoutines, _ghash_processBlocks, address) \ static_field(StubRoutines, _base64_encodeBlock, address) \ static_field(StubRoutines, _base64_decodeBlock, address) \ diff --git a/src/hotspot/share/runtime/vmThread.cpp b/src/hotspot/share/runtime/vmThread.cpp index ed406b1c77d2a..48906c8c90c46 100644 --- a/src/hotspot/share/runtime/vmThread.cpp +++ b/src/hotspot/share/runtime/vmThread.cpp @@ -128,7 +128,7 @@ void VMThread::create() { assert(_timeout_task == NULL, "sanity"); } - _terminate_lock = new Monitor(Mutex::safepoint, "VMThread::_terminate_lock", true, + _terminate_lock = new Monitor(Mutex::safepoint, "VMThread::_terminate_lock", Monitor::_safepoint_check_never); if (UsePerfData) { diff --git a/src/hotspot/share/services/heapDumperCompression.cpp b/src/hotspot/share/services/heapDumperCompression.cpp index 41c9726109494..ec33264b889c5 100644 --- a/src/hotspot/share/services/heapDumperCompression.cpp +++ b/src/hotspot/share/services/heapDumperCompression.cpp @@ -201,7 +201,7 @@ CompressionBackend::CompressionBackend(AbstractWriter* writer, _writer(writer), _compressor(compressor), _lock(new (std::nothrow) PaddedMonitor(Mutex::leaf, "HProf Compression Backend", - true, Mutex::_safepoint_check_never)) { + Mutex::_safepoint_check_never)) { if (_writer == NULL) { set_error("Could not allocate writer"); } else if (_lock == NULL) { diff --git a/src/hotspot/share/services/memoryManager.cpp b/src/hotspot/share/services/memoryManager.cpp index a2c155b6fca6c..690393deb7817 100644 --- a/src/hotspot/share/services/memoryManager.cpp +++ b/src/hotspot/share/services/memoryManager.cpp @@ -174,7 +174,7 @@ GCMemoryManager::GCMemoryManager(const char* name, const char* gc_end_message) : MemoryManager(name), _gc_end_message(gc_end_message) { _num_collections = 0; _last_gc_stat = NULL; - _last_gc_lock = new Mutex(Mutex::leaf, "_last_gc_lock", true, + _last_gc_lock = new Mutex(Mutex::leaf, "_last_gc_lock", Mutex::_safepoint_check_never); _current_gc_stat = NULL; _num_gc_threads = 1; diff --git a/src/hotspot/share/utilities/concurrentHashTable.inline.hpp b/src/hotspot/share/utilities/concurrentHashTable.inline.hpp index b5c2389f11ae4..7719535cdfd82 100644 --- a/src/hotspot/share/utilities/concurrentHashTable.inline.hpp +++ b/src/hotspot/share/utilities/concurrentHashTable.inline.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2021, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -1014,7 +1014,7 @@ inline ConcurrentHashTable:: { _stats_rate = TableRateStatistics(); _resize_lock = - new Mutex(Mutex::leaf, "ConcurrentHashTable", true, + new Mutex(Mutex::leaf, "ConcurrentHashTable", Mutex::_safepoint_check_never); _table = new InternalTable(log2size); assert(log2size_limit >= log2size, "bad ergo"); diff --git a/src/hotspot/share/utilities/events.hpp b/src/hotspot/share/utilities/events.hpp index b5d67bd6a8ad8..7f9ae6909f760 100644 --- a/src/hotspot/share/utilities/events.hpp +++ b/src/hotspot/share/utilities/events.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2021, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -100,7 +100,7 @@ template class EventLogBase : public EventLog { public: EventLogBase(const char* name, const char* handle, int length = LogEventsBufferEntries): - _mutex(Mutex::event, name, true, Mutex::_safepoint_check_never), + _mutex(Mutex::event, name, Mutex::_safepoint_check_never), _name(name), _handle(handle), _length(length), diff --git a/src/java.base/share/classes/com/sun/crypto/provider/GHASH.java b/src/java.base/share/classes/com/sun/crypto/provider/GHASH.java index c0815524dd7c2..24cddd2b9f654 100644 --- a/src/java.base/share/classes/com/sun/crypto/provider/GHASH.java +++ b/src/java.base/share/classes/com/sun/crypto/provider/GHASH.java @@ -122,7 +122,7 @@ private static void blockMult(long[] st, long[] subH) { /* subkeyHtbl and state are stored in long[] for GHASH intrinsic use */ - // hashtable subkeyHtbl holds 2*9 powers of subkeyH computed using + // hashtable subkeyHtbl holds 2*57 powers of subkeyH computed using // carry-less multiplication private long[] subkeyHtbl; @@ -143,7 +143,9 @@ private static void blockMult(long[] st, long[] subH) { throw new ProviderException("Internal error"); } state = new long[2]; - subkeyHtbl = new long[2*9]; + // 48 keys for the interleaved implementation, + // 8 for avx-ghash implementation and 1 for the original key + subkeyHtbl = new long[2*57]; subkeyHtbl[0] = (long)asLongView.get(subkeyH, 0); subkeyHtbl[1] = (long)asLongView.get(subkeyH, 8); } @@ -264,7 +266,7 @@ private static void ghashRangeCheck(byte[] in, int inOfs, int inLen, throw new RuntimeException("internal state has invalid length: " + st.length); } - if (subH.length != 18) { + if (subH.length != 114) { throw new RuntimeException("internal subkeyHtbl has invalid length: " + subH.length); } diff --git a/src/java.base/share/classes/com/sun/crypto/provider/GaloisCounterMode.java b/src/java.base/share/classes/com/sun/crypto/provider/GaloisCounterMode.java index 7cad5ec9c822a..957823b886e61 100644 --- a/src/java.base/share/classes/com/sun/crypto/provider/GaloisCounterMode.java +++ b/src/java.base/share/classes/com/sun/crypto/provider/GaloisCounterMode.java @@ -25,6 +25,7 @@ package com.sun.crypto.provider; +import jdk.internal.misc.Unsafe; import sun.nio.ch.DirectBuffer; import sun.security.jca.JCAUtil; import sun.security.util.ArrayUtil; @@ -55,6 +56,8 @@ import java.security.spec.InvalidParameterSpecException; import java.util.Arrays; +import jdk.internal.vm.annotation.IntrinsicCandidate; + /** * This class represents ciphers in GaloisCounter (GCM) mode. * @@ -82,6 +85,8 @@ abstract class GaloisCounterMode extends CipherSpi { private static final int MAX_BUF_SIZE = Integer.MAX_VALUE; // data size when buffer is divided up to aid in intrinsics private static final int TRIGGERLEN = 65536; // 64k + // x86-64 parallel intrinsic data size + private static final int PARALLEL_LEN = 768; static final byte[] EMPTY_BUF = new byte[0]; @@ -566,35 +571,64 @@ private static byte[] getJ0(byte[] iv, byte[] subkeyH, int blockSize) { } /** - * Calculate if the given data lengths and the already processed data - * exceeds the maximum allowed processed data by GCM. - * @param lengths lengths of unprocessed data. + * Intrinsic for Vector AES Galois Counter Mode implementation. + * AES and GHASH operations are interleaved in the intrinsic implementation. + * return - number of processed bytes + * + * Requires 768 bytes (48 AES blocks) to efficiently use the intrinsic. + * inLen that is less than 768 size block sizes, before or after this + * intrinsic is used, will be done by the calling method + * @param in input buffer + * @param inOfs input offset + * @param inLen input length + * @param ct buffer that ghash will read (in for encrypt, out for decrypt) + * @param ctOfs offset for ct buffer + * @param out output buffer + * @param outOfs output offset + * @param gctr object for the GCTR operation + * @param ghash object for the ghash operation + * @return number of processed bytes */ - private void checkDataLength(int ... lengths) { - int max = MAX_BUF_SIZE; - for (int len : lengths) { - max = Math.subtractExact(max, len); - } - if (engine.processed > max) { - throw new ProviderException("SunJCE provider only supports " + - "input size up to " + MAX_BUF_SIZE + " bytes"); + @IntrinsicCandidate + private static int implGCMCrypt(byte[] in, int inOfs, int inLen, + byte[] ct, int ctOfs, byte[] out, int outOfs, + GCTR gctr, GHASH ghash) { + + inLen -= (inLen % PARALLEL_LEN); + + int len = 0; + int cOfs = ctOfs; + if (inLen >= TRIGGERLEN) { + int i = 0; + int segments = (inLen / 6); + segments -= segments % gctr.blockSize; + do { + len += gctr.update(in, inOfs + len, segments, out, + outOfs + len); + ghash.update(ct, cOfs, segments); + cOfs = ctOfs + len; + } while (++i < 5); + + inLen -= len; } + + len += gctr.update(in, inOfs + len, inLen, out, outOfs + len); + ghash.update(ct, cOfs, inLen); + return len; } + /** * Abstract class for GCMEncrypt and GCMDecrypt internal context objects */ abstract class GCMEngine { byte[] preCounterBlock; - GCTR gctrPAndC; - GHASH ghashAllToS; + GCTR gctr; + GHASH ghash; // Block size of the algorithm final int blockSize; - // length of total data, i.e. len(C) - int processed = 0; - // buffer for AAD data; if null, meaning update has been called ByteArrayOutputStream aadBuffer = null; int sizeOfAAD = 0; @@ -608,7 +642,6 @@ abstract class GCMEngine { byte[] originalOut = null; int originalOutOfs = 0; - GCMEngine(SymmetricCipher blockCipher) { blockSize = blockCipher.getBlockSize(); byte[] subkeyH = new byte[blockSize]; @@ -616,8 +649,8 @@ abstract class GCMEngine { preCounterBlock = getJ0(iv, subkeyH, blockSize); byte[] j0Plus1 = preCounterBlock.clone(); increment32(j0Plus1); - gctrPAndC = new GCTR(blockCipher, j0Plus1); - ghashAllToS = new GHASH(subkeyH); + gctr = new GCTR(blockCipher, j0Plus1); + ghash = new GHASH(subkeyH); } /** @@ -631,15 +664,15 @@ abstract class GCMEngine { abstract int getOutputSize(int inLen, boolean isFinal); // Update operations - abstract byte[] doUpdate(byte[] in, int inOff, int inLen); - abstract int doUpdate(byte[] in, int inOff, int inLen, byte[] out, - int outOff) throws ShortBufferException; + abstract byte[] doUpdate(byte[] in, int inOfs, int inLen); + abstract int doUpdate(byte[] in, int inOfs, int inLen, byte[] out, + int outOfs) throws ShortBufferException; abstract int doUpdate(ByteBuffer src, ByteBuffer dst) throws ShortBufferException; // Final operations - abstract int doFinal(byte[] in, int inOff, int inLen, byte[] out, - int outOff) throws IllegalBlockSizeException, AEADBadTagException, + abstract int doFinal(byte[] in, int inOfs, int inLen, byte[] out, + int outOfs) throws IllegalBlockSizeException, AEADBadTagException, ShortBufferException; abstract int doFinal(ByteBuffer src, ByteBuffer dst) throws IllegalBlockSizeException, AEADBadTagException, @@ -657,6 +690,48 @@ int getBufferedLength() { return (ibuffer == null ? 0 : ibuffer.size()); } + /** + * ByteBuffer wrapper for intrinsic implGCMCrypt. It will operate + * on 768 byte blocks and let the calling method operate on smaller + * sizes. + */ + int implGCMCrypt(ByteBuffer src, ByteBuffer dst) { + int srcLen = src.remaining() - (src.remaining() % PARALLEL_LEN); + + if (srcLen < PARALLEL_LEN) { + return 0; + } + + int len; + + if (src.hasArray() && dst.hasArray()) { + ByteBuffer ct = (encryption ? dst : src); + len = GaloisCounterMode.implGCMCrypt(src.array(), + src.arrayOffset() + src.position(), srcLen, + ct.array(), ct.arrayOffset() + ct.position(), + dst.array(), dst.arrayOffset() + dst.position(), + gctr, ghash); + src.position(src.position() + len); + dst.position(dst.position() + len); + return len; + + } else { + + byte[] bin = new byte[PARALLEL_LEN]; + byte[] bout = new byte[PARALLEL_LEN]; + byte[] ct = (encryption ? bout : bin); + len = srcLen; + do { + src.get(bin, 0, PARALLEL_LEN); + len -= GaloisCounterMode.implGCMCrypt(bin, 0, PARALLEL_LEN, + ct, 0, bout, 0, gctr, ghash); + dst.put(bout, 0, PARALLEL_LEN); + } while (len >= PARALLEL_LEN); + + return srcLen - len; + } + } + /** * The method takes two buffers to create one block of data. The * difference with the other mergeBlock is this will calculate @@ -704,8 +779,6 @@ int mergeBlock(byte[] buffer, int bufOfs, int bufLen, byte[] in, * (e.g., has not been initialized) or does not accept AAD, and one of * the {@code update} methods has already been called for the active * encryption/decryption operation - * @throws UnsupportedOperationException if this method - * has not been overridden by an implementation */ void updateAAD(byte[] src, int offset, int len) { if (encryption) { @@ -733,12 +806,12 @@ void processAAD() { int lastLen = aad.length % blockSize; if (lastLen != 0) { - ghashAllToS.update(aad, 0, aad.length - lastLen); + ghash.update(aad, 0, aad.length - lastLen); byte[] padded = expandToOneBlock(aad, aad.length - lastLen, lastLen, blockSize); - ghashAllToS.update(padded); + ghash.update(padded); } else { - ghashAllToS.update(aad); + ghash.update(aad); } } aadBuffer = null; @@ -751,18 +824,28 @@ void processAAD() { * For input it takes the ibuffer which is wrapped in 'buffer' and 'src' * from doFinal. */ - int doLastBlock(GCM op, ByteBuffer buffer, ByteBuffer src, ByteBuffer dst) { - int resultLen = 0; + int doLastBlock(GCMOperation op, ByteBuffer buffer, ByteBuffer src, + ByteBuffer dst) { + int len = 0; + int resultLen; int bLen = (buffer != null ? buffer.remaining() : 0); if (bLen > 0) { - // en/decrypt on how much buffer there is in AES_BLOCK_SIZE + // en/decrypt any PARALLEL_LEN sized data in the buffer + if (bLen >= PARALLEL_LEN) { + len = implGCMCrypt(buffer, dst); + bLen -= len; + } + + // en/decrypt any blocksize data in the buffer if (bLen >= blockSize) { - resultLen += op.update(buffer, dst); + resultLen = op.update(buffer, dst); + bLen -= resultLen; + len += resultLen; } // Process the remainder in the buffer - if (bLen - resultLen > 0) { + if (bLen > 0) { // Copy the buffer remainder into an extra block byte[] block = new byte[blockSize]; int over = buffer.remaining(); @@ -773,76 +856,26 @@ int doLastBlock(GCM op, ByteBuffer buffer, ByteBuffer src, ByteBuffer dst) { if (slen > 0) { src.get(block, over, slen); } - int len = slen + over; - if (len == blockSize) { - resultLen += op.update(block, 0, blockSize, dst); + int l = slen + over; + if (l == blockSize) { + len += op.update(block, 0, blockSize, dst); } else { - resultLen += op.doFinal(block, 0, len, block, - 0); + len += op.doFinal(block, 0, l, block,0); if (dst != null) { - dst.put(block, 0, len); + dst.put(block, 0, l); } - processed += resultLen; - return resultLen; + return len; } } } // en/decrypt whatever remains in src. // If src has been consumed, this will be a no-op - if (src.remaining() > TRIGGERLEN) { - resultLen += throttleData(op, src, dst); + if (src.remaining() >= PARALLEL_LEN) { + len += implGCMCrypt(src, dst); } - resultLen += op.doFinal(src, dst); - processed += resultLen; - return resultLen; - } - - - /** - * This segments large data into smaller chunks so hotspot will start - * using GCTR and GHASH intrinsics sooner. This is a problem for app - * and perf tests that only use large input sizes. - */ - int throttleData(GCM op, byte[] in, int inOfs, int inLen, - byte[] out, int outOfs) { - - int segments = (inLen / 6); - segments -= segments % blockSize; - int len = 0; - int i = 0; - do { - len += op.update(in, inOfs + len, segments, out,outOfs + len); - } while (++i < 5); - - len += op.update(in, inOfs + len, inLen - len, out, outOfs + len); - return len; - } - - - /** - * This segments large data into smaller chunks so hotspot will start - * using GCTR and GHASH intrinsics sooner. This is a problem for app - * and perf tests that only use large input sizes. - */ - int throttleData(GCM op, ByteBuffer src, ByteBuffer dst) { - int inLen = src.limit(); - int segments = (src.remaining() / 6); - segments -= segments % blockSize; - int i = 0, resultLen = 0; - do { - src.limit(src.position() + segments); - resultLen += op.update(src, dst); - } while (++i < 5); - - src.limit(inLen); - // If there is still at least a blockSize left - if (src.remaining() > blockSize) { - resultLen += op.update(src, dst); - } - - return resultLen; + return len + op.doFinal(src, dst); } /** @@ -900,7 +933,11 @@ ByteBuffer overlapDetection(ByteBuffer src, ByteBuffer dst) { // Position plus arrayOffset() will give us the true offset // from the underlying byte[] address. - if (src.position() + src.arrayOffset() >= + // If during encryption and the input offset is behind or + // the same as the output offset, the same buffer can be + // used. But during decryption always create a new + // buffer in case of a bad auth tag. + if (encryption && src.position() + src.arrayOffset() >= dst.position() + dst.arrayOffset()) { return dst; } @@ -923,12 +960,15 @@ ByteBuffer overlapDetection(ByteBuffer src, ByteBuffer dst) { } /** - * Overlap detection for data using byte array. + * This is used for both overlap detection for the data or decryption + * during in-place crypto, so to not overwrite the input if the auth tag + * is invalid. + * * If an intermediate array is needed, the original out array length is * allocated because for code simplicity. */ byte[] overlapDetection(byte[] in, int inOfs, byte[] out, int outOfs) { - if (in == out && inOfs < outOfs) { + if (in == out && (!encryption || inOfs < outOfs)) { originalOut = out; originalOutOfs = outOfs; return new byte[out.length]; @@ -969,11 +1009,31 @@ void restoreOut(byte[] out, int len) { * Encryption Engine object */ class GCMEncrypt extends GCMEngine { - GCTRGHASH gctrghash; + GCMOperation op; + + // data processed during encryption + int processed = 0; + GCMEncrypt(SymmetricCipher blockCipher) { super(blockCipher); - gctrghash = new GCTRGHASH(gctrPAndC, ghashAllToS); + op = new EncryptOp(gctr, ghash); + } + + /** + * Calculate if the given data lengths and the already processed data + * exceeds the maximum allowed processed data by GCM. + * @param lengths lengths of unprocessed data. + */ + private void checkDataLength(int ... lengths) { + int max = MAX_BUF_SIZE; + for (int len : lengths) { + max = Math.subtractExact(max, len); + if (processed > max) { + throw new ProviderException("SunJCE provider only " + + "supports input size up to " + MAX_BUF_SIZE + " bytes"); + } + } } @Override @@ -1034,7 +1094,7 @@ public int doUpdate(byte[] in, int inOfs, int inLen, byte[] out, System.arraycopy(buffer, 0, block, 0, bLen); System.arraycopy(in, inOfs, block, bLen, remainder); - len = gctrghash.update(block, 0, blockSize, out, outOfs); + len = op.update(block, 0, blockSize, out, outOfs); inOfs += remainder; inLen -= remainder; outOfs += blockSize; @@ -1043,8 +1103,20 @@ public int doUpdate(byte[] in, int inOfs, int inLen, byte[] out, } // Encrypt the remaining blocks inside of 'in' + if (inLen >= PARALLEL_LEN) { + int r = GaloisCounterMode.implGCMCrypt(in, inOfs, inLen, out, + outOfs, out, outOfs, gctr, ghash); + len += r; + inOfs += r; + inLen -= r; + outOfs += r; + } + if (inLen >= blockSize) { - len += gctrghash.update(in, inOfs, inLen, out, outOfs); + int r = op.update(in, inOfs, inLen, out, outOfs); + len += r; + inOfs += r; + inLen -= r; } // Write any remaining bytes less than a blockSize into ibuffer. @@ -1089,21 +1161,32 @@ public int doUpdate(ByteBuffer src, ByteBuffer dst) ByteBuffer buffer = ByteBuffer.wrap(ibuffer.toByteArray()); buffer.get(block, 0, bLen); src.get(block, bLen, remainder); - len += cryptBlocks( - ByteBuffer.wrap(block, 0, blockSize), dst); + len += op.update(ByteBuffer.wrap(block, 0, blockSize), + dst); ibuffer.reset(); } } - // encrypt any blocksized data in 'src' - if (src.remaining() >= blockSize) { - len += cryptBlocks(src, dst); + int srcLen = src.remaining(); + int resultLen; + // encrypt any PARALLEL_LEN sized data in 'src' + if (srcLen >= PARALLEL_LEN) { + resultLen = implGCMCrypt(src, dst); + srcLen -= resultLen; + len += resultLen; + } + + // encrypt any blocksize data in 'src' + if (srcLen >= blockSize) { + resultLen = op.update(src, dst); + srcLen -= resultLen; + len += resultLen; } // Write the remaining bytes into the 'ibuffer' - if (src.remaining() > 0) { - initBuffer(src.remaining()); - byte[] b = new byte[src.remaining()]; + if (srcLen > 0) { + initBuffer(srcLen); + byte[] b = new byte[srcLen]; src.get(b); // remainder offset is based on original buffer length try { @@ -1114,6 +1197,7 @@ public int doUpdate(ByteBuffer src, ByteBuffer dst) } restoreDst(dst); + processed += len; return len; } @@ -1127,7 +1211,7 @@ public int doFinal(byte[] in, int inOfs, int inLen, byte[] out, try { ArrayUtil.nullAndBoundsCheck(out, outOfs, getOutputSize(inLen, true)); - } catch (ArrayIndexOutOfBoundsException aiobe) { + } catch (ArrayIndexOutOfBoundsException e) { throw new ShortBufferException("Output buffer invalid"); } @@ -1136,7 +1220,7 @@ public int doFinal(byte[] in, int inOfs, int inLen, byte[] out, processAAD(); out = overlapDetection(in, inOfs, out, outOfs); - int resultLen = 0; + int len = 0; byte[] block; // process what is in the ibuffer @@ -1145,18 +1229,16 @@ public int doFinal(byte[] in, int inOfs, int inLen, byte[] out, // Make a block if the remaining ibuffer and 'in' can make one. if (bLen + inLen >= blockSize) { - int r, bufOfs = 0; + int r; block = new byte[blockSize]; - r = mergeBlock(buffer, bufOfs, in, inOfs, inLen, block); + r = mergeBlock(buffer, 0, in, inOfs, inLen, block); inOfs += r; inLen -= r; - r = gctrghash.update(block, 0, blockSize, out, - outOfs); - outOfs += r; - resultLen += r; - processed += r; + op.update(block, 0, blockSize, out, outOfs); + outOfs += blockSize; + len += blockSize; } else { - // Need to consume all the ibuffer here to prepare for doFinal() + // Need to consume the ibuffer here to prepare for doFinal() block = new byte[bLen + inLen]; System.arraycopy(buffer, 0, block, 0, bLen); System.arraycopy(in, inOfs, block, bLen, inLen); @@ -1167,28 +1249,18 @@ public int doFinal(byte[] in, int inOfs, int inLen, byte[] out, } // process what is left in the input buffer - if (inLen > TRIGGERLEN) { - int r = throttleData(gctrghash, in, inOfs, inLen, out, outOfs); - inOfs += r; - inLen -= r; - outOfs += r; - resultLen += r; - processed += r; - } - - processed += gctrghash.doFinal(in, inOfs, inLen, out, outOfs); + len += op.doFinal(in, inOfs, inLen, out, outOfs); outOfs += inLen; - resultLen += inLen; - block = getLengthBlock(sizeOfAAD, processed); - ghashAllToS.update(block); - block = ghashAllToS.digest(); + block = getLengthBlock(sizeOfAAD, processed + len); + ghash.update(block); + block = ghash.digest(); new GCTR(blockCipher, preCounterBlock).doFinal(block, 0, tagLenBytes, block, 0); // copy the tag to the end of the buffer System.arraycopy(block, 0, out, outOfs, tagLenBytes); - int len = resultLen + tagLenBytes; + len += tagLenBytes; restoreOut(out, len); reInit = true; @@ -1214,7 +1286,7 @@ public int doFinal(ByteBuffer src, ByteBuffer dst) throws processAAD(); if (len > 0) { - processed += doLastBlock(gctrghash, + processed += doLastBlock(op, (ibuffer == null || ibuffer.size() == 0) ? null : ByteBuffer.wrap(ibuffer.toByteArray()), src, dst); } @@ -1225,8 +1297,8 @@ public int doFinal(ByteBuffer src, ByteBuffer dst) throws } byte[] block = getLengthBlock(sizeOfAAD, processed); - ghashAllToS.update(block); - block = ghashAllToS.digest(); + ghash.update(block); + block = ghash.digest(); new GCTR(blockCipher, preCounterBlock).doFinal(block, 0, tagLenBytes, block, 0); dst.put(block, 0, tagLenBytes); @@ -1235,18 +1307,6 @@ public int doFinal(ByteBuffer src, ByteBuffer dst) throws reInit = true; return (len + tagLenBytes); } - - // Handler method for encrypting blocks - int cryptBlocks(ByteBuffer src, ByteBuffer dst) { - int len; - if (src.remaining() > TRIGGERLEN) { - len = throttleData(gctrghash, src, dst); - } else { - len = gctrghash.update(src, dst); - } - processed += len; - return len; - } } /** @@ -1262,6 +1322,22 @@ class GCMDecrypt extends GCMEngine { super(blockCipher); } + /** + * Calculate if the given data lengths exceeds the maximum allowed + * processed data by GCM. + * @param lengths lengths of unprocessed data. + */ + private void checkDataLength(int ... lengths) { + int max = MAX_BUF_SIZE; + for (int len : lengths) { + max = Math.subtractExact(max, len); + if (max < 0) { + throw new ProviderException("SunJCE provider only " + + "supports input size up to " + MAX_BUF_SIZE + " bytes"); + } + } + } + @Override public int getOutputSize(int inLen, boolean isFinal) { if (!isFinal) { @@ -1311,9 +1387,8 @@ public int doUpdate(byte[] in, int inOfs, int inLen, byte[] out, processAAD(); if (inLen > 0) { - // store internally until decryptFinal is called because - // spec mentioned that only return recovered data after tag - // is successfully verified + // store internally until doFinal. Per the spec, data is + // returned after tag is successfully verified. initBuffer(inLen); ibuffer.write(in, inOfs, inLen); } @@ -1350,38 +1425,43 @@ public int doUpdate(ByteBuffer src, ByteBuffer dst) } /** - * Use any data from ibuffer and 'in' to first verify the auth tag. If - * the tag is valid, decrypt the data. + * Use available data from ibuffer and 'in' to verify and decrypt the + * data. If the verification fails, the 'out' left to it's original + * values if crypto was in-place; otherwise 'out' is zeroed */ @Override public int doFinal(byte[] in, int inOfs, int inLen, byte[] out, int outOfs) throws IllegalBlockSizeException, AEADBadTagException, ShortBufferException { - GHASH save = null; int len = inLen + getBufferedLength(); + if (len < tagLenBytes) { + throw new AEADBadTagException("Input data too short to " + + "contain an expected tag length of " + tagLenBytes + + "bytes"); + } + try { ArrayUtil.nullAndBoundsCheck(out, outOfs, len - tagLenBytes); - } catch (ArrayIndexOutOfBoundsException aiobe) { + } catch (ArrayIndexOutOfBoundsException e) { throw new ShortBufferException("Output buffer invalid"); } - if (len < tagLenBytes) { - throw new AEADBadTagException("Input too short - need tag"); - } - if (len - tagLenBytes > out.length - outOfs) { - save = ghashAllToS.clone(); + throw new ShortBufferException("Output buffer too small, must" + + "be at least " + (len - tagLenBytes) + " bytes long"); } checkDataLength(len - tagLenBytes); processAAD(); - findTag(in, inOfs, inLen); - byte[] block = getLengthBlock(sizeOfAAD, - decryptBlocks(ghashAllToS, in, inOfs, inLen, null, 0)); - ghashAllToS.update(block); - block = ghashAllToS.digest(); + out = overlapDetection(in, inOfs, out, outOfs); + + len = decryptBlocks(new DecryptOp(gctr, ghash), in, inOfs, inLen, + out, outOfs); + byte[] block = getLengthBlock(sizeOfAAD, len); + ghash.update(block); + block = ghash.digest(); new GCTR(blockCipher, preCounterBlock).doFinal(block, 0, tagLenBytes, block, 0); @@ -1392,30 +1472,24 @@ public int doFinal(byte[] in, int inOfs, int inLen, byte[] out, } if (mismatch != 0) { - throw new AEADBadTagException("Tag mismatch!"); - } - - if (save != null) { - ghashAllToS = save; - throw new ShortBufferException("Output buffer too small, must" + - "be at least " + (len - tagLenBytes) + " bytes long"); + // Clear output data + Arrays.fill(out, outOfs, outOfs + len, (byte) 0); + throw new AEADBadTagException("Tag mismatch"); } - out = overlapDetection(in, inOfs, out, outOfs); - len = decryptBlocks(gctrPAndC, in, inOfs, inLen, out, outOfs); restoreOut(out, len); return len; } /** - * Use any data from ibuffer and 'src' to first verify the auth tag. If - * the tag is valid, decrypt the data. + * Use available data from ibuffer and 'src' to verify and decrypt the + * data. If the verification fails, the 'dst' left to it's original + * values if crypto was in-place; otherwise 'dst' is zeroed */ @Override public int doFinal(ByteBuffer src, ByteBuffer dst) throws IllegalBlockSizeException, AEADBadTagException, ShortBufferException { - GHASH save = null; ByteBuffer tag; ByteBuffer ct = src.duplicate(); @@ -1432,11 +1506,10 @@ public int doFinal(ByteBuffer src, ByteBuffer dst) checkDataLength(len); - // Save GHASH context to allow the tag to be checked even though - // the dst buffer is too short. Context will be restored so the - // method can be called again with the proper sized dst buffer. + // Verify dst is large enough if (len > dst.remaining()) { - save = ghashAllToS.clone(); + throw new ShortBufferException("Output buffer too small, " + + "must be at least " + len + " bytes long"); } // Create buffer 'tag' that contains only the auth tag @@ -1459,20 +1532,19 @@ public int doFinal(ByteBuffer src, ByteBuffer dst) tag.put(ct); tag.flip(); } else { - throw new AEADBadTagException("Input too short - need tag"); + throw new AEADBadTagException("Input data too short to " + + "contain an expected tag length of " + tagLenBytes + + "bytes"); } - // Set the mark for a later reset. Either it will be zero, or the - // tag buffer creation above will have consume some or all of it. - ct.mark(); - + dst = overlapDetection(src, dst); + dst.mark(); processAAD(); - // Perform GHASH check on data - doLastBlock(ghashAllToS, buffer, ct, null); + len = doLastBlock(new DecryptOp(gctr, ghash), buffer, ct, dst); byte[] block = getLengthBlock(sizeOfAAD, len); - ghashAllToS.update(block); - block = ghashAllToS.digest(); + ghash.update(block); + block = ghash.digest(); new GCTR(blockCipher, preCounterBlock).doFinal(block, 0, tagLenBytes, block, 0); @@ -1483,32 +1555,22 @@ public int doFinal(ByteBuffer src, ByteBuffer dst) } if (mismatch != 0) { - throw new AEADBadTagException("Tag mismatch!"); - } - - if (save != null) { - ghashAllToS = save; - throw new ShortBufferException("Output buffer too small, must" + - " be at least " + len + " bytes long"); - } - - // Prepare for decryption - if (buffer != null) { - buffer.flip(); + // Clear output data + dst.reset(); + if (dst.hasArray()) { + int ofs = dst.arrayOffset() + dst.position(); + Arrays.fill(dst.array(), ofs , ofs + len, (byte)0); + } else { + Unsafe.getUnsafe().setMemory(((DirectBuffer)dst).address(), + len + dst.position(), (byte)0); + } + throw new AEADBadTagException("Tag mismatch"); } - ct.reset(); - processed = 0; - // Check for overlap in the bytebuffers - dst = overlapDetection(src, dst); - // Decrypt the all the input data and put it into dst - doLastBlock(gctrPAndC, buffer, ct, dst); - restoreDst(dst); src.position(src.limit()); - if (ibuffer != null) { - ibuffer.reset(); - } - return processed; + engine = null; + restoreDst(dst); + return len; } /** @@ -1517,11 +1579,12 @@ public int doFinal(ByteBuffer src, ByteBuffer dst) * When this method is used, all the data is either in the ibuffer * or in 'in'. */ - int decryptBlocks(GCM op, byte[] in, int inOfs, int inLen, + int decryptBlocks(GCMOperation op, byte[] in, int inOfs, int inLen, byte[] out, int outOfs) { byte[] buffer; byte[] block; int len = 0; + int resultLen; // Calculate the encrypted data length inside the ibuffer // considering the tag location @@ -1538,15 +1601,24 @@ int decryptBlocks(GCM op, byte[] in, int inOfs, int inLen, if (bLen > 0) { buffer = ibuffer.toByteArray(); - if (bLen >= blockSize) { - len += op.update(buffer, 0, bLen, out, outOfs); - outOfs += len; // noop for ghash + if (bLen >= PARALLEL_LEN) { + len = GaloisCounterMode.implGCMCrypt(buffer, 0, bLen, + buffer, 0, out, outOfs, gctr, ghash); + outOfs += len; // Use len as it becomes the ibuffer offset, if // needed, in the next op } - // merge the remaining ibuffer with the 'in' int bufRemainder = bLen - len; + if (bufRemainder >= blockSize) { + resultLen = op.update(buffer, len, bufRemainder, out, + outOfs); + len += resultLen; + outOfs += resultLen; + bufRemainder -= resultLen; + } + + // merge the remaining ibuffer with the 'in' if (bufRemainder > 0) { block = new byte[blockSize]; int inUsed = mergeBlock(buffer, len, bufRemainder, in, @@ -1557,9 +1629,9 @@ int decryptBlocks(GCM op, byte[] in, int inOfs, int inLen, // If is more than block between the merged data and 'in', // update(), otherwise setup for final if (inLen > 0) { - int resultLen = op.update(block, 0, blockSize, + resultLen = op.update(block, 0, blockSize, out, outOfs); - outOfs += resultLen; // noop for ghash + outOfs += resultLen; len += resultLen; } else { in = block; @@ -1569,14 +1641,6 @@ int decryptBlocks(GCM op, byte[] in, int inOfs, int inLen, } } - // Finish off the operation - if (inLen > TRIGGERLEN) { - int l = throttleData(op, in, inOfs, inLen, out, outOfs); - inOfs += l; - inLen -= l; - outOfs += l; // noop for ghash - len += l; - } return len + op.doFinal(in, inOfs, inLen, out, outOfs); } } @@ -1609,11 +1673,11 @@ public AES256() { * This class is for encryption when both GCTR and GHASH * can operation in parallel. */ - static final class GCTRGHASH implements GCM { + static final class EncryptOp implements GCMOperation { GCTR gctr; GHASH ghash; - GCTRGHASH(GCTR c, GHASH g) { + EncryptOp(GCTR c, GHASH g) { gctr = c; ghash = g; } @@ -1645,19 +1709,96 @@ public int update(ByteBuffer src, ByteBuffer dst) { } @Override - public int doFinal(byte[] in, int inOfs, int inLen, byte[] out, int outOfs) { - int len = gctr.doFinal(in, inOfs, inLen, out, outOfs); - ghash.doFinal(out, outOfs, len); - return len; + public int doFinal(byte[] in, int inOfs, int inLen, byte[] out, + int outOfs) { + int len = 0; + + if (inLen >= PARALLEL_LEN) { + len = implGCMCrypt(in, inOfs, inLen, out, outOfs, out, outOfs, + gctr, ghash); + inLen -= len; + outOfs += len; + } + + gctr.doFinal(in, inOfs + len, inLen, out, outOfs); + return len + ghash.doFinal(out, outOfs, inLen); } @Override public int doFinal(ByteBuffer src, ByteBuffer dst) { dst.mark(); - int l = gctr.doFinal(src, dst); + int len = gctr.doFinal(src, dst); dst.reset(); - ghash.doFinal(dst, l); - return l; + ghash.doFinal(dst, len); + return len; + } + } + + /** + * This class is for decryption when both GCTR and GHASH + * can operation in parallel. + */ + static final class DecryptOp implements GCMOperation { + GCTR gctr; + GHASH ghash; + + DecryptOp(GCTR c, GHASH g) { + gctr = c; + ghash = g; } + + @Override + public int update(byte[] in, int inOfs, int inLen, byte[] out, + int outOfs) { + ghash.update(in, inOfs, inLen); + return gctr.update(in, inOfs, inLen, out, outOfs); + } + + @Override + public int update(byte[] in, int inOfs, int inLen, ByteBuffer dst) { + ghash.update(in, inOfs, inLen); + return gctr.update(in, inOfs, inLen, dst); + } + + @Override + public int update(ByteBuffer src, ByteBuffer dst) { + src.mark(); + ghash.update(src, src.remaining()); + src.reset(); + return gctr.update(src, dst); + } + + @Override + public int doFinal(byte[] in, int inOfs, int inLen, byte[] out, + int outOfs) { + int len = 0; + if (inLen >= PARALLEL_LEN) { + len += implGCMCrypt(in, inOfs, inLen, in, inOfs, out, outOfs, + gctr, ghash); + } + ghash.doFinal(in, inOfs + len, inLen - len); + return len + gctr.doFinal(in, inOfs + len, inLen - len, out, + outOfs + len); + } + + @Override + public int doFinal(ByteBuffer src, ByteBuffer dst) { + src.mark(); + ghash.doFinal(src, src.remaining()); + src.reset(); + return gctr.doFinal(src, dst); + } + } + + /** + * Interface to organize encryption and decryption operations in the + * proper order for GHASH and GCTR. + */ + public interface GCMOperation { + int update(byte[] in, int inOfs, int inLen, byte[] out, int outOfs); + int update(byte[] in, int inOfs, int inLen, ByteBuffer dst); + int update(ByteBuffer src, ByteBuffer dst); + int doFinal(byte[] in, int inOfs, int inLen, byte[] out, int outOfs); + int doFinal(ByteBuffer src, ByteBuffer dst); } } diff --git a/src/java.base/share/classes/java/io/ByteArrayOutputStream.java b/src/java.base/share/classes/java/io/ByteArrayOutputStream.java index 9e4f3d9a3ad55..09e79934bfa92 100644 --- a/src/java.base/share/classes/java/io/ByteArrayOutputStream.java +++ b/src/java.base/share/classes/java/io/ByteArrayOutputStream.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1994, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1994, 2021, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -198,16 +198,17 @@ public synchronized int size() { /** * Converts the buffer's contents into a string decoding bytes using the - * platform's default character set. The length of the new {@code String} - * is a function of the character set, and hence may not be equal to the + * default charset. The length of the new {@code String} + * is a function of the charset, and hence may not be equal to the * size of the buffer. * *

This method always replaces malformed-input and unmappable-character - * sequences with the default replacement string for the platform's - * default character set. The {@linkplain java.nio.charset.CharsetDecoder} + * sequences with the default replacement string for the + * default charset. The {@linkplain java.nio.charset.CharsetDecoder} * class should be used when more control over the decoding process is * required. * + * @see Charset#defaultCharset() * @return String decoded from the buffer's contents. * @since 1.1 */ @@ -217,10 +218,10 @@ public synchronized String toString() { /** * Converts the buffer's contents into a string by decoding the bytes using - * the named {@link java.nio.charset.Charset charset}. + * the named {@link Charset charset}. * *

This method is equivalent to {@code #toString(charset)} that takes a - * {@link java.nio.charset.Charset charset}. + * {@link Charset charset}. * *

An invocation of this method of the form * @@ -240,7 +241,7 @@ public synchronized String toString() { * * * @param charsetName the name of a supported - * {@link java.nio.charset.Charset charset} + * {@link Charset charset} * @return String decoded from the buffer's contents. * @throws UnsupportedEncodingException * If the named charset is not supported @@ -254,7 +255,7 @@ public synchronized String toString(String charsetName) /** * Converts the buffer's contents into a string by decoding the bytes using - * the specified {@link java.nio.charset.Charset charset}. The length of the new + * the specified {@link Charset charset}. The length of the new * {@code String} is a function of the charset, and hence may not be equal * to the length of the byte array. * @@ -263,7 +264,7 @@ public synchronized String toString(String charsetName) * java.nio.charset.CharsetDecoder} class should be used when more control * over the decoding process is required. * - * @param charset the {@linkplain java.nio.charset.Charset charset} + * @param charset the {@linkplain Charset charset} * to be used to decode the {@code bytes} * @return String decoded from the buffer's contents. * @since 10 @@ -286,14 +287,14 @@ public synchronized String toString(Charset charset) { * As of JDK 1.1, the preferred way to do this is via the * {@link #toString(String charsetName)} or {@link #toString(Charset charset)} * method, which takes an encoding-name or charset argument, - * or the {@code toString()} method, which uses the platform's default - * character encoding. + * or the {@code toString()} method, which uses the default charset. * * @param hibyte the high byte of each resulting Unicode character. * @return the current contents of the output stream, as a string. * @see java.io.ByteArrayOutputStream#size() * @see java.io.ByteArrayOutputStream#toString(String) * @see java.io.ByteArrayOutputStream#toString() + * @see Charset#defaultCharset() */ @Deprecated public synchronized String toString(int hibyte) { diff --git a/src/java.base/share/classes/java/io/Console.java b/src/java.base/share/classes/java/io/Console.java index ebc2b56e8bebd..683d836f85f29 100644 --- a/src/java.base/share/classes/java/io/Console.java +++ b/src/java.base/share/classes/java/io/Console.java @@ -29,6 +29,7 @@ import java.nio.charset.Charset; import jdk.internal.access.JavaIOAccess; import jdk.internal.access.SharedSecrets; +import jdk.internal.util.StaticProperty; import sun.nio.cs.StreamDecoder; import sun.nio.cs.StreamEncoder; import sun.security.action.GetPropertyAction; @@ -572,22 +573,34 @@ public int read(char[] cbuf, int offset, int length) private static final Charset CHARSET; static { - String csname = encoding(); Charset cs = null; - if (csname == null) { - csname = GetPropertyAction.privilegedGetProperty("sun.stdout.encoding"); + boolean istty = istty(); + + if (istty) { + String csname = encoding(); + if (csname == null) { + csname = GetPropertyAction.privilegedGetProperty("sun.stdout.encoding"); + } + if (csname != null) { + try { + cs = Charset.forName(csname); + } catch (Exception ignored) { } + } } - if (csname != null) { + if (cs == null) { try { - cs = Charset.forName(csname); - } catch (Exception ignored) { } + cs = Charset.forName(StaticProperty.nativeEncoding()); + } catch (Exception ignored) { + cs = Charset.defaultCharset(); + } } - CHARSET = cs == null ? Charset.defaultCharset() : cs; + + CHARSET = cs; // Set up JavaIOAccess in SharedSecrets SharedSecrets.setJavaIOAccess(new JavaIOAccess() { public Console console() { - if (istty()) { + if (istty) { if (cons == null) cons = new Console(); return cons; diff --git a/src/java.base/share/classes/java/io/FileReader.java b/src/java.base/share/classes/java/io/FileReader.java index dd1c60993900f..ef1868715b049 100644 --- a/src/java.base/share/classes/java/io/FileReader.java +++ b/src/java.base/share/classes/java/io/FileReader.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1996, 2021, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -29,9 +29,8 @@ /** * Reads text from character files using a default buffer size. Decoding from bytes - * to characters uses either a specified {@linkplain java.nio.charset.Charset charset} - * or the platform's - * {@linkplain java.nio.charset.Charset#defaultCharset() default charset}. + * to characters uses either a specified {@linkplain Charset charset} + * or the {@linkplain Charset#defaultCharset() default charset}. * *

* The {@code FileReader} is meant for reading streams of characters. For reading @@ -39,6 +38,7 @@ * * @see InputStreamReader * @see FileInputStream + * @see Charset#defaultCharset() * * @author Mark Reinhold * @since 1.1 @@ -47,14 +47,14 @@ public class FileReader extends InputStreamReader { /** * Creates a new {@code FileReader}, given the name of the file to read, - * using the platform's - * {@linkplain java.nio.charset.Charset#defaultCharset() default charset}. + * using the {@linkplain Charset#defaultCharset() default charset}. * * @param fileName the name of the file to read * @throws FileNotFoundException if the named file does not exist, * is a directory rather than a regular file, * or for some other reason cannot be opened for * reading. + * @see Charset#defaultCharset() */ public FileReader(String fileName) throws FileNotFoundException { super(new FileInputStream(fileName)); @@ -62,14 +62,14 @@ public FileReader(String fileName) throws FileNotFoundException { /** * Creates a new {@code FileReader}, given the {@code File} to read, - * using the platform's - * {@linkplain java.nio.charset.Charset#defaultCharset() default charset}. + * using the {@linkplain Charset#defaultCharset() default charset}. * * @param file the {@code File} to read * @throws FileNotFoundException if the file does not exist, * is a directory rather than a regular file, * or for some other reason cannot be opened for * reading. + * @see Charset#defaultCharset() */ public FileReader(File file) throws FileNotFoundException { super(new FileInputStream(file)); @@ -77,10 +77,10 @@ public FileReader(File file) throws FileNotFoundException { /** * Creates a new {@code FileReader}, given the {@code FileDescriptor} to read, - * using the platform's - * {@linkplain java.nio.charset.Charset#defaultCharset() default charset}. + * using the {@linkplain Charset#defaultCharset() default charset}. * * @param fd the {@code FileDescriptor} to read + * @see Charset#defaultCharset() */ public FileReader(FileDescriptor fd) { super(new FileInputStream(fd)); @@ -88,10 +88,10 @@ public FileReader(FileDescriptor fd) { /** * Creates a new {@code FileReader}, given the name of the file to read - * and the {@linkplain java.nio.charset.Charset charset}. + * and the {@linkplain Charset charset}. * * @param fileName the name of the file to read - * @param charset the {@linkplain java.nio.charset.Charset charset} + * @param charset the {@linkplain Charset charset} * @throws IOException if the named file does not exist, * is a directory rather than a regular file, * or for some other reason cannot be opened for @@ -105,10 +105,10 @@ public FileReader(String fileName, Charset charset) throws IOException { /** * Creates a new {@code FileReader}, given the {@code File} to read and - * the {@linkplain java.nio.charset.Charset charset}. + * the {@linkplain Charset charset}. * * @param file the {@code File} to read - * @param charset the {@linkplain java.nio.charset.Charset charset} + * @param charset the {@linkplain Charset charset} * @throws IOException if the file does not exist, * is a directory rather than a regular file, * or for some other reason cannot be opened for diff --git a/src/java.base/share/classes/java/io/FileWriter.java b/src/java.base/share/classes/java/io/FileWriter.java index e49b31676fa69..2c3a1a9c02865 100644 --- a/src/java.base/share/classes/java/io/FileWriter.java +++ b/src/java.base/share/classes/java/io/FileWriter.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1996, 2021, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -29,9 +29,8 @@ /** * Writes text to character files using a default buffer size. Encoding from characters - * to bytes uses either a specified {@linkplain java.nio.charset.Charset charset} - * or the platform's - * {@linkplain java.nio.charset.Charset#defaultCharset() default charset}. + * to bytes uses either a specified {@linkplain Charset charset} + * or the {@linkplain Charset#defaultCharset() default charset}. * *

* Whether or not a file is available or may be created depends upon the @@ -46,6 +45,7 @@ * * @see OutputStreamWriter * @see FileOutputStream + * @see Charset#defaultCharset() * * @author Mark Reinhold * @since 1.1 @@ -54,13 +54,14 @@ public class FileWriter extends OutputStreamWriter { /** - * Constructs a {@code FileWriter} given a file name, using the platform's - * {@linkplain java.nio.charset.Charset#defaultCharset() default charset} + * Constructs a {@code FileWriter} given a file name, using the + * {@linkplain Charset#defaultCharset() default charset} * * @param fileName String The system-dependent filename. * @throws IOException if the named file exists but is a directory rather * than a regular file, does not exist but cannot be * created, or cannot be opened for any other reason + * @see Charset#defaultCharset() */ public FileWriter(String fileName) throws IOException { super(new FileOutputStream(fileName)); @@ -68,8 +69,8 @@ public FileWriter(String fileName) throws IOException { /** * Constructs a {@code FileWriter} given a file name and a boolean indicating - * whether to append the data written, using the platform's - * {@linkplain java.nio.charset.Charset#defaultCharset() default charset}. + * whether to append the data written, using the + * {@linkplain Charset#defaultCharset() default charset}. * * @param fileName String The system-dependent filename. * @param append boolean if {@code true}, then data will be written @@ -77,6 +78,7 @@ public FileWriter(String fileName) throws IOException { * @throws IOException if the named file exists but is a directory rather * than a regular file, does not exist but cannot be * created, or cannot be opened for any other reason + * @see Charset#defaultCharset() */ public FileWriter(String fileName, boolean append) throws IOException { super(new FileOutputStream(fileName, append)); @@ -84,13 +86,13 @@ public FileWriter(String fileName, boolean append) throws IOException { /** * Constructs a {@code FileWriter} given the {@code File} to write, - * using the platform's - * {@linkplain java.nio.charset.Charset#defaultCharset() default charset} + * using the {@linkplain Charset#defaultCharset() default charset} * * @param file the {@code File} to write. * @throws IOException if the file exists but is a directory rather than * a regular file, does not exist but cannot be created, * or cannot be opened for any other reason + * @see Charset#defaultCharset() */ public FileWriter(File file) throws IOException { super(new FileOutputStream(file)); @@ -98,8 +100,8 @@ public FileWriter(File file) throws IOException { /** * Constructs a {@code FileWriter} given the {@code File} to write and - * a boolean indicating whether to append the data written, using the platform's - * {@linkplain java.nio.charset.Charset#defaultCharset() default charset}. + * a boolean indicating whether to append the data written, using the + * {@linkplain Charset#defaultCharset() default charset}. * * @param file the {@code File} to write * @param append if {@code true}, then bytes will be written @@ -107,6 +109,7 @@ public FileWriter(File file) throws IOException { * @throws IOException if the file exists but is a directory rather than * a regular file, does not exist but cannot be created, * or cannot be opened for any other reason + * @see Charset#defaultCharset() * @since 1.4 */ public FileWriter(File file, boolean append) throws IOException { @@ -115,10 +118,10 @@ public FileWriter(File file, boolean append) throws IOException { /** * Constructs a {@code FileWriter} given a file descriptor, - * using the platform's - * {@linkplain java.nio.charset.Charset#defaultCharset() default charset}. + * using the {@linkplain Charset#defaultCharset() default charset}. * * @param fd the {@code FileDescriptor} to write. + * @see Charset#defaultCharset() */ public FileWriter(FileDescriptor fd) { super(new FileOutputStream(fd)); @@ -127,10 +130,10 @@ public FileWriter(FileDescriptor fd) { /** * Constructs a {@code FileWriter} given a file name and - * {@linkplain java.nio.charset.Charset charset}. + * {@linkplain Charset charset}. * * @param fileName the name of the file to write - * @param charset the {@linkplain java.nio.charset.Charset charset} + * @param charset the {@linkplain Charset charset} * @throws IOException if the named file exists but is a directory rather * than a regular file, does not exist but cannot be * created, or cannot be opened for any other reason @@ -143,11 +146,11 @@ public FileWriter(String fileName, Charset charset) throws IOException { /** * Constructs a {@code FileWriter} given a file name, - * {@linkplain java.nio.charset.Charset charset} and a boolean indicating + * {@linkplain Charset charset} and a boolean indicating * whether to append the data written. * * @param fileName the name of the file to write - * @param charset the {@linkplain java.nio.charset.Charset charset} + * @param charset the {@linkplain Charset charset} * @param append a boolean. If {@code true}, the writer will write the data * to the end of the file rather than the beginning. * @throws IOException if the named file exists but is a directory rather @@ -162,10 +165,10 @@ public FileWriter(String fileName, Charset charset, boolean append) throws IOExc /** * Constructs a {@code FileWriter} given the {@code File} to write and - * {@linkplain java.nio.charset.Charset charset}. + * {@linkplain Charset charset}. * * @param file the {@code File} to write - * @param charset the {@linkplain java.nio.charset.Charset charset} + * @param charset the {@linkplain Charset charset} * @throws IOException if the file exists but is a directory rather than * a regular file, does not exist but cannot be created, * or cannot be opened for any other reason @@ -178,11 +181,11 @@ public FileWriter(File file, Charset charset) throws IOException { /** * Constructs a {@code FileWriter} given the {@code File} to write, - * {@linkplain java.nio.charset.Charset charset} and a boolean indicating + * {@linkplain Charset charset} and a boolean indicating * whether to append the data written. * * @param file the {@code File} to write - * @param charset the {@linkplain java.nio.charset.Charset charset} + * @param charset the {@linkplain Charset charset} * @param append a boolean. If {@code true}, the writer will write the data * to the end of the file rather than the beginning. * @throws IOException if the file exists but is a directory rather than diff --git a/src/java.base/share/classes/java/io/InputStreamReader.java b/src/java.base/share/classes/java/io/InputStreamReader.java index 850b8c4a3cb7a..ccd4b24348900 100644 --- a/src/java.base/share/classes/java/io/InputStreamReader.java +++ b/src/java.base/share/classes/java/io/InputStreamReader.java @@ -34,9 +34,9 @@ /** * An InputStreamReader is a bridge from byte streams to character streams: It * reads bytes and decodes them into characters using a specified {@link - * java.nio.charset.Charset charset}. The charset that it uses - * may be specified by name or may be given explicitly, or the platform's - * {@link Charset#defaultCharset() default charset} may be accepted. + * Charset charset}. The charset that it uses + * may be specified by name or may be given explicitly, or the + * {@link Charset#defaultCharset() default charset} may be used. * *

Each invocation of one of an InputStreamReader's read() methods may * cause one or more bytes to be read from the underlying byte-input stream. @@ -54,7 +54,7 @@ * * @see BufferedReader * @see InputStream - * @see java.nio.charset.Charset + * @see Charset * * @author Mark Reinhold * @since 1.1 @@ -85,8 +85,7 @@ public InputStreamReader(InputStream in) { * An InputStream * * @param charsetName - * The name of a supported - * {@link java.nio.charset.Charset charset} + * The name of a supported {@link Charset charset} * * @throws UnsupportedEncodingException * If the named charset is not supported @@ -145,7 +144,7 @@ public InputStreamReader(InputStream in, CharsetDecoder dec) { * @return The historical name of this encoding, or * {@code null} if the stream has been closed * - * @see java.nio.charset.Charset + * @see Charset * * @revised 1.4 */ diff --git a/src/java.base/share/classes/java/io/OutputStreamWriter.java b/src/java.base/share/classes/java/io/OutputStreamWriter.java index d513bcba2af58..f9acde201b760 100644 --- a/src/java.base/share/classes/java/io/OutputStreamWriter.java +++ b/src/java.base/share/classes/java/io/OutputStreamWriter.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1996, 2021, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -34,8 +34,8 @@ /** * An OutputStreamWriter is a bridge from character streams to byte streams: * Characters written to it are encoded into bytes using a specified {@link - * java.nio.charset.Charset charset}. The charset that it uses - * may be specified by name or may be given explicitly, or the platform's + * Charset charset}. The charset that it uses + * may be specified by name or may be given explicitly, or the * default charset may be accepted. * *

Each invocation of a write() method causes the encoding converter to be @@ -48,7 +48,7 @@ * *

  * Writer out
- *   = new BufferedWriter(new OutputStreamWriter(System.out));
+ *   = new BufferedWriter(new OutputStreamWriter(anOutputStream));
  * 
* *

A surrogate pair is a character represented by a sequence of two @@ -62,12 +62,12 @@ * *

This class always replaces malformed surrogate elements and unmappable * character sequences with the charset's default substitution sequence. - * The {@linkplain java.nio.charset.CharsetEncoder} class should be used when more + * The {@linkplain CharsetEncoder} class should be used when more * control over the encoding process is required. * * @see BufferedWriter * @see OutputStream - * @see java.nio.charset.Charset + * @see Charset * * @author Mark Reinhold * @since 1.1 @@ -84,8 +84,7 @@ public class OutputStreamWriter extends Writer { * An OutputStream * * @param charsetName - * The name of a supported - * {@link java.nio.charset.Charset charset} + * The name of a supported {@link Charset charset} * * @throws UnsupportedEncodingException * If the named encoding is not supported @@ -103,6 +102,7 @@ public OutputStreamWriter(OutputStream out, String charsetName) * Creates an OutputStreamWriter that uses the default character encoding. * * @param out An OutputStream + * @see Charset#defaultCharset() */ public OutputStreamWriter(OutputStream out) { super(out); @@ -161,7 +161,7 @@ public OutputStreamWriter(OutputStream out, CharsetEncoder enc) { * @return The historical name of this encoding, or possibly * {@code null} if the stream has been closed * - * @see java.nio.charset.Charset + * @see Charset * * @revised 1.4 */ diff --git a/src/java.base/share/classes/java/io/PrintStream.java b/src/java.base/share/classes/java/io/PrintStream.java index 163c860659aaa..3e07ac6300250 100644 --- a/src/java.base/share/classes/java/io/PrintStream.java +++ b/src/java.base/share/classes/java/io/PrintStream.java @@ -45,8 +45,8 @@ * ({@code '\n'}) is written. * *

All characters printed by a {@code PrintStream} are converted into - * bytes using the given encoding or charset, or the platform's default - * character encoding if not specified. + * bytes using the given encoding or charset, or the default charset if not + * specified. * The {@link PrintWriter} class should be used in situations that require * writing characters rather than bytes. * @@ -58,6 +58,7 @@ * @author Frank Yellin * @author Mark Reinhold * @since 1.0 + * @see Charset#defaultCharset() */ public class PrintStream extends FilterOutputStream @@ -123,12 +124,13 @@ private PrintStream(boolean autoFlush, Charset charset, OutputStream out) { /** * Creates a new print stream, without automatic line flushing, with the * specified OutputStream. Characters written to the stream are converted - * to bytes using the platform's default character encoding. + * to bytes using the default charset. * * @param out The output stream to which values and objects will be * printed * * @see java.io.PrintWriter#PrintWriter(java.io.OutputStream) + * @see Charset#defaultCharset() */ public PrintStream(OutputStream out) { this(out, false); @@ -137,7 +139,7 @@ public PrintStream(OutputStream out) { /** * Creates a new print stream, with the specified OutputStream and line * flushing. Characters written to the stream are converted to bytes using - * the platform's default character encoding. + * the default charset. * * @param out The output stream to which values and objects will be * printed @@ -147,6 +149,7 @@ public PrintStream(OutputStream out) { * character or byte ({@code '\n'}) is written * * @see java.io.PrintWriter#PrintWriter(java.io.OutputStream, boolean) + * @see Charset#defaultCharset() */ public PrintStream(OutputStream out, boolean autoFlush) { this(autoFlush, requireNonNull(out, "Null output stream")); @@ -189,7 +192,7 @@ public PrintStream(OutputStream out, boolean autoFlush, String encoding) * whenever a byte array is written, one of the * {@code println} methods is invoked, or a newline * character or byte ({@code '\n'}) is written - * @param charset A {@linkplain java.nio.charset.Charset charset} + * @param charset A {@linkplain Charset charset} * * @since 10 */ @@ -205,7 +208,7 @@ public PrintStream(OutputStream out, boolean autoFlush, Charset charset) { * specified file name. This convenience constructor creates * the necessary intermediate {@link java.io.OutputStreamWriter * OutputStreamWriter}, which will encode characters using the - * {@linkplain java.nio.charset.Charset#defaultCharset() default charset} + * {@linkplain Charset#defaultCharset() default charset} * for this instance of the Java virtual machine. * * @param fileName @@ -224,6 +227,7 @@ public PrintStream(OutputStream out, boolean autoFlush, Charset charset) { * If a security manager is present and {@link * SecurityManager#checkWrite checkWrite(fileName)} denies write * access to the file + * @see Charset#defaultCharset() * * @since 1.5 */ @@ -245,8 +249,7 @@ public PrintStream(String fileName) throws FileNotFoundException { * will be written to the file and is buffered. * * @param csn - * The name of a supported {@linkplain java.nio.charset.Charset - * charset} + * The name of a supported {@linkplain Charset charset} * * @throws FileNotFoundException * If the given file object does not denote an existing, writable @@ -285,7 +288,7 @@ public PrintStream(String fileName, String csn) * will be written to the file and is buffered. * * @param charset - * A {@linkplain java.nio.charset.Charset charset} + * A {@linkplain Charset charset} * * @throws IOException * if an I/O error occurs while opening or creating the file @@ -306,7 +309,7 @@ public PrintStream(String fileName, Charset charset) throws IOException { * specified file. This convenience constructor creates the necessary * intermediate {@link java.io.OutputStreamWriter OutputStreamWriter}, * which will encode characters using the {@linkplain - * java.nio.charset.Charset#defaultCharset() default charset} for this + * Charset#defaultCharset() default charset} for this * instance of the Java virtual machine. * * @param file @@ -325,6 +328,7 @@ public PrintStream(String fileName, Charset charset) throws IOException { * If a security manager is present and {@link * SecurityManager#checkWrite checkWrite(file.getPath())} * denies write access to the file + * @see Charset#defaultCharset() * * @since 1.5 */ @@ -346,8 +350,7 @@ public PrintStream(File file) throws FileNotFoundException { * file and is buffered. * * @param csn - * The name of a supported {@linkplain java.nio.charset.Charset - * charset} + * The name of a supported {@linkplain Charset charset} * * @throws FileNotFoundException * If the given file object does not denote an existing, writable @@ -387,7 +390,7 @@ public PrintStream(File file, String csn) * file and is buffered. * * @param charset - * A {@linkplain java.nio.charset.Charset charset} + * A {@linkplain Charset charset} * * @throws IOException * if an I/O error occurs while opening or creating the file @@ -519,9 +522,8 @@ protected void clearError() { * invoked on the underlying output stream. * *

Note that the byte is written as given; to write a character that - * will be translated according to the platform's default character - * encoding, use the {@code print(char)} or {@code println(char)} - * methods. + * will be translated according to the default charset, use the + * {@code print(char)} or {@code println(char)} methods. * * @param b The byte to be written * @see #print(char) @@ -552,9 +554,8 @@ public void write(int b) { * output stream. * *

Note that the bytes will be written as given; to write characters - * that will be translated according to the platform's default character - * encoding, use the {@code print(char)} or {@code println(char)} - * methods. + * that will be translated according to the default charset, use the + * {@code print(char)} or {@code println(char)} methods. * * @param buf A byte array * @param off Offset from which to start taking bytes @@ -584,9 +585,8 @@ public void write(byte[] buf, int off, int len) { * invoked on the underlying output stream. * *

Note that the bytes will be written as given; to write characters - * that will be translated according to the platform's default character - * encoding, use the {@code print(char[])} or {@code println(char[])} - * methods. + * that will be translated according to the default charset, use the + * {@code print(char[])} or {@code println(char[])} methods. * * @apiNote * Although declared to throw {@code IOException}, this method never @@ -622,9 +622,8 @@ public void write(byte[] buf) throws IOException { * will be invoked. * *

Note that the bytes will be written as given; to write characters - * that will be translated according to the platform's default character - * encoding, use the {@code print(char[])} or {@code println(char[])} - * methods. + * that will be translated according to the default charset, use the + * {@code print(char[])} or {@code println(char[])} methods. * * @implSpec * This method is equivalent to @@ -757,11 +756,12 @@ private void newLine() { /** * Prints a boolean value. The string produced by {@link * java.lang.String#valueOf(boolean)} is translated into bytes - * according to the platform's default character encoding, and these bytes + * according to the default charset, and these bytes * are written in exactly the manner of the * {@link #write(int)} method. * * @param b The {@code boolean} to be printed + * @see Charset#defaultCharset() */ public void print(boolean b) { write(String.valueOf(b)); @@ -770,10 +770,11 @@ public void print(boolean b) { /** * Prints a character. The character is translated into one or more bytes * according to the character encoding given to the constructor, or the - * platform's default character encoding if none specified. These bytes + * default charset if none specified. These bytes * are written in exactly the manner of the {@link #write(int)} method. * * @param c The {@code char} to be printed + * @see Charset#defaultCharset() */ public void print(char c) { write(String.valueOf(c)); @@ -782,12 +783,13 @@ public void print(char c) { /** * Prints an integer. The string produced by {@link * java.lang.String#valueOf(int)} is translated into bytes - * according to the platform's default character encoding, and these bytes + * according to the default charset, and these bytes * are written in exactly the manner of the * {@link #write(int)} method. * * @param i The {@code int} to be printed * @see java.lang.Integer#toString(int) + * @see Charset#defaultCharset() */ public void print(int i) { write(String.valueOf(i)); @@ -796,12 +798,13 @@ public void print(int i) { /** * Prints a long integer. The string produced by {@link * java.lang.String#valueOf(long)} is translated into bytes - * according to the platform's default character encoding, and these bytes + * according to the default charset, and these bytes * are written in exactly the manner of the * {@link #write(int)} method. * * @param l The {@code long} to be printed * @see java.lang.Long#toString(long) + * @see Charset#defaultCharset() */ public void print(long l) { write(String.valueOf(l)); @@ -810,12 +813,13 @@ public void print(long l) { /** * Prints a floating-point number. The string produced by {@link * java.lang.String#valueOf(float)} is translated into bytes - * according to the platform's default character encoding, and these bytes + * according to the default charset, and these bytes * are written in exactly the manner of the * {@link #write(int)} method. * * @param f The {@code float} to be printed * @see java.lang.Float#toString(float) + * @see Charset#defaultCharset() */ public void print(float f) { write(String.valueOf(f)); @@ -824,12 +828,13 @@ public void print(float f) { /** * Prints a double-precision floating-point number. The string produced by * {@link java.lang.String#valueOf(double)} is translated into - * bytes according to the platform's default character encoding, and these + * bytes according to the default charset, and these * bytes are written in exactly the manner of the {@link * #write(int)} method. * * @param d The {@code double} to be printed * @see java.lang.Double#toString(double) + * @see Charset#defaultCharset() */ public void print(double d) { write(String.valueOf(d)); @@ -838,10 +843,11 @@ public void print(double d) { /** * Prints an array of characters. The characters are converted into bytes * according to the character encoding given to the constructor, or the - * platform's default character encoding if none specified. These bytes + * default charset if none specified. These bytes * are written in exactly the manner of the {@link #write(int)} method. * * @param s The array of chars to be printed + * @see Charset#defaultCharset() * * @throws NullPointerException If {@code s} is {@code null} */ @@ -853,11 +859,12 @@ public void print(char[] s) { * Prints a string. If the argument is {@code null} then the string * {@code "null"} is printed. Otherwise, the string's characters are * converted into bytes according to the character encoding given to the - * constructor, or the platform's default character encoding if none + * constructor, or the default charset if none * specified. These bytes are written in exactly the manner of the * {@link #write(int)} method. * * @param s The {@code String} to be printed + * @see Charset#defaultCharset() */ public void print(String s) { write(String.valueOf(s)); @@ -866,12 +873,13 @@ public void print(String s) { /** * Prints an object. The string produced by the {@link * java.lang.String#valueOf(Object)} method is translated into bytes - * according to the platform's default character encoding, and these bytes + * according to the default charset, and these bytes * are written in exactly the manner of the * {@link #write(int)} method. * * @param obj The {@code Object} to be printed * @see java.lang.Object#toString() + * @see Charset#defaultCharset() */ public void print(Object obj) { write(String.valueOf(obj)); diff --git a/src/java.base/share/classes/java/io/PrintWriter.java b/src/java.base/share/classes/java/io/PrintWriter.java index 23e57cc2b2ace..447769d7fb320 100644 --- a/src/java.base/share/classes/java/io/PrintWriter.java +++ b/src/java.base/share/classes/java/io/PrintWriter.java @@ -118,11 +118,12 @@ public PrintWriter(Writer out, * Creates a new PrintWriter, without automatic line flushing, from an * existing OutputStream. This convenience constructor creates the * necessary intermediate OutputStreamWriter, which will convert characters - * into bytes using the default character encoding. + * into bytes using the default charset. * * @param out An output stream * - * @see java.io.OutputStreamWriter#OutputStreamWriter(java.io.OutputStream) + * @see OutputStreamWriter#OutputStreamWriter(OutputStream) + * @see Charset#defaultCharset() */ public PrintWriter(OutputStream out) { this(out, false); @@ -132,14 +133,15 @@ public PrintWriter(OutputStream out) { * Creates a new PrintWriter from an existing OutputStream. This * convenience constructor creates the necessary intermediate * OutputStreamWriter, which will convert characters into bytes using the - * default character encoding. + * default charset. * * @param out An output stream * @param autoFlush A boolean; if true, the {@code println}, * {@code printf}, or {@code format} methods will * flush the output buffer * - * @see java.io.OutputStreamWriter#OutputStreamWriter(java.io.OutputStream) + * @see OutputStreamWriter#OutputStreamWriter(OutputStream) + * @see Charset#defaultCharset() */ public PrintWriter(OutputStream out, boolean autoFlush) { this(out, autoFlush, Charset.defaultCharset()); @@ -156,7 +158,7 @@ public PrintWriter(OutputStream out, boolean autoFlush) { * {@code printf}, or {@code format} methods will * flush the output buffer * @param charset - * A {@linkplain java.nio.charset.Charset charset} + * A {@linkplain Charset charset} * * @since 10 */ @@ -172,9 +174,9 @@ public PrintWriter(OutputStream out, boolean autoFlush, Charset charset) { /** * Creates a new PrintWriter, without automatic line flushing, with the * specified file name. This convenience constructor creates the necessary - * intermediate {@link java.io.OutputStreamWriter OutputStreamWriter}, + * intermediate {@link OutputStreamWriter OutputStreamWriter}, * which will encode characters using the {@linkplain - * java.nio.charset.Charset#defaultCharset() default charset} for this + * Charset#defaultCharset() default charset} for this * instance of the Java virtual machine. * * @param fileName @@ -193,6 +195,7 @@ public PrintWriter(OutputStream out, boolean autoFlush, Charset charset) { * If a security manager is present and {@link * SecurityManager#checkWrite checkWrite(fileName)} denies write * access to the file + * @see Charset#defaultCharset() * * @since 1.5 */ @@ -212,7 +215,7 @@ private PrintWriter(Charset charset, File file) /** * Creates a new PrintWriter, without automatic line flushing, with the * specified file name and charset. This convenience constructor creates - * the necessary intermediate {@link java.io.OutputStreamWriter + * the necessary intermediate {@link OutputStreamWriter * OutputStreamWriter}, which will encode characters using the provided * charset. * @@ -223,8 +226,7 @@ private PrintWriter(Charset charset, File file) * written to the file and is buffered. * * @param csn - * The name of a supported {@linkplain java.nio.charset.Charset - * charset} + * The name of a supported {@linkplain Charset charset} * * @throws FileNotFoundException * If the given string does not denote an existing, writable @@ -251,7 +253,7 @@ public PrintWriter(String fileName, String csn) /** * Creates a new PrintWriter, without automatic line flushing, with the * specified file name and charset. This convenience constructor creates - * the necessary intermediate {@link java.io.OutputStreamWriter + * the necessary intermediate {@link OutputStreamWriter * OutputStreamWriter}, which will encode characters using the provided * charset. * @@ -262,7 +264,7 @@ public PrintWriter(String fileName, String csn) * written to the file and is buffered. * * @param charset - * A {@linkplain java.nio.charset.Charset charset} + * A {@linkplain Charset charset} * * @throws IOException * if an I/O error occurs while opening or creating the file @@ -281,9 +283,9 @@ public PrintWriter(String fileName, Charset charset) throws IOException { /** * Creates a new PrintWriter, without automatic line flushing, with the * specified file. This convenience constructor creates the necessary - * intermediate {@link java.io.OutputStreamWriter OutputStreamWriter}, + * intermediate {@link OutputStreamWriter OutputStreamWriter}, * which will encode characters using the {@linkplain - * java.nio.charset.Charset#defaultCharset() default charset} for this + * Charset#defaultCharset() default charset} for this * instance of the Java virtual machine. * * @param file @@ -302,6 +304,7 @@ public PrintWriter(String fileName, Charset charset) throws IOException { * If a security manager is present and {@link * SecurityManager#checkWrite checkWrite(file.getPath())} * denies write access to the file + * @see Charset#defaultCharset() * * @since 1.5 */ @@ -313,7 +316,7 @@ public PrintWriter(File file) throws FileNotFoundException { /** * Creates a new PrintWriter, without automatic line flushing, with the * specified file and charset. This convenience constructor creates the - * necessary intermediate {@link java.io.OutputStreamWriter + * necessary intermediate {@link OutputStreamWriter * OutputStreamWriter}, which will encode characters using the provided * charset. * @@ -324,8 +327,7 @@ public PrintWriter(File file) throws FileNotFoundException { * and is buffered. * * @param csn - * The name of a supported {@linkplain java.nio.charset.Charset - * charset} + * The name of a supported {@linkplain Charset charset} * * @throws FileNotFoundException * If the given file object does not denote an existing, writable @@ -363,7 +365,7 @@ public PrintWriter(File file, String csn) * and is buffered. * * @param charset - * A {@linkplain java.nio.charset.Charset charset} + * A {@linkplain Charset charset} * * @throws IOException * if an I/O error occurs while opening or creating the file @@ -580,11 +582,12 @@ private void newLine() { /** * Prints a boolean value. The string produced by {@link * java.lang.String#valueOf(boolean)} is translated into bytes - * according to the platform's default character encoding, and these bytes + * according to the default charset, and these bytes * are written in exactly the manner of the {@link * #write(int)} method. * * @param b The {@code boolean} to be printed + * @see Charset#defaultCharset() */ public void print(boolean b) { write(String.valueOf(b)); @@ -592,11 +595,12 @@ public void print(boolean b) { /** * Prints a character. The character is translated into one or more bytes - * according to the platform's default character encoding, and these bytes + * according to the default charset, and these bytes * are written in exactly the manner of the {@link * #write(int)} method. * * @param c The {@code char} to be printed + * @see Charset#defaultCharset() */ public void print(char c) { write(c); @@ -605,12 +609,13 @@ public void print(char c) { /** * Prints an integer. The string produced by {@link * java.lang.String#valueOf(int)} is translated into bytes according - * to the platform's default character encoding, and these bytes are + * to the default charset, and these bytes are * written in exactly the manner of the {@link #write(int)} * method. * * @param i The {@code int} to be printed * @see java.lang.Integer#toString(int) + * @see Charset#defaultCharset() */ public void print(int i) { write(String.valueOf(i)); @@ -619,12 +624,13 @@ public void print(int i) { /** * Prints a long integer. The string produced by {@link * java.lang.String#valueOf(long)} is translated into bytes - * according to the platform's default character encoding, and these bytes + * according to the default charset, and these bytes * are written in exactly the manner of the {@link #write(int)} * method. * * @param l The {@code long} to be printed * @see java.lang.Long#toString(long) + * @see Charset#defaultCharset() */ public void print(long l) { write(String.valueOf(l)); @@ -633,12 +639,13 @@ public void print(long l) { /** * Prints a floating-point number. The string produced by {@link * java.lang.String#valueOf(float)} is translated into bytes - * according to the platform's default character encoding, and these bytes + * according to the default charset, and these bytes * are written in exactly the manner of the {@link #write(int)} * method. * * @param f The {@code float} to be printed * @see java.lang.Float#toString(float) + * @see Charset#defaultCharset() */ public void print(float f) { write(String.valueOf(f)); @@ -647,12 +654,13 @@ public void print(float f) { /** * Prints a double-precision floating-point number. The string produced by * {@link java.lang.String#valueOf(double)} is translated into - * bytes according to the platform's default character encoding, and these + * bytes according to the default charset, and these * bytes are written in exactly the manner of the {@link * #write(int)} method. * * @param d The {@code double} to be printed * @see java.lang.Double#toString(double) + * @see Charset#defaultCharset() */ public void print(double d) { write(String.valueOf(d)); @@ -660,11 +668,12 @@ public void print(double d) { /** * Prints an array of characters. The characters are converted into bytes - * according to the platform's default character encoding, and these bytes + * according to the default charset, and these bytes * are written in exactly the manner of the {@link #write(int)} * method. * * @param s The array of chars to be printed + * @see Charset#defaultCharset() * * @throws NullPointerException If {@code s} is {@code null} */ @@ -675,11 +684,12 @@ public void print(char[] s) { /** * Prints a string. If the argument is {@code null} then the string * {@code "null"} is printed. Otherwise, the string's characters are - * converted into bytes according to the platform's default character - * encoding, and these bytes are written in exactly the manner of the + * converted into bytes according to the default charset, + * and these bytes are written in exactly the manner of the * {@link #write(int)} method. * * @param s The {@code String} to be printed + * @see Charset#defaultCharset() */ public void print(String s) { write(String.valueOf(s)); @@ -688,12 +698,13 @@ public void print(String s) { /** * Prints an object. The string produced by the {@link * java.lang.String#valueOf(Object)} method is translated into bytes - * according to the platform's default character encoding, and these bytes + * according to the default charset, and these bytes * are written in exactly the manner of the {@link #write(int)} * method. * * @param obj The {@code Object} to be printed * @see java.lang.Object#toString() + * @see Charset#defaultCharset() */ public void print(Object obj) { write(String.valueOf(obj)); diff --git a/src/java.base/share/classes/java/lang/Math.java b/src/java.base/share/classes/java/lang/Math.java index 02074573fc8af..1bdaa49dc373c 100644 --- a/src/java.base/share/classes/java/lang/Math.java +++ b/src/java.base/share/classes/java/lang/Math.java @@ -1308,7 +1308,7 @@ public static int floorDiv(int x, int y) { * @param x the dividend * @param y the divisor * @return the largest (closest to positive infinity) - * {@code int} value that is less than or equal to the algebraic quotient. + * {@code long} value that is less than or equal to the algebraic quotient. * @throws ArithmeticException if the divisor {@code y} is zero * @see #floorMod(long, int) * @see #floor(double) diff --git a/src/java.base/share/classes/java/lang/StrictMath.java b/src/java.base/share/classes/java/lang/StrictMath.java index 062e3fd3709d1..2bb5797a53358 100644 --- a/src/java.base/share/classes/java/lang/StrictMath.java +++ b/src/java.base/share/classes/java/lang/StrictMath.java @@ -1086,7 +1086,7 @@ public static int floorDiv(int x, int y) { * @param x the dividend * @param y the divisor * @return the largest (closest to positive infinity) - * {@code int} value that is less than or equal to the algebraic quotient. + * {@code long} value that is less than or equal to the algebraic quotient. * @throws ArithmeticException if the divisor {@code y} is zero * @see Math#floorDiv(long, int) * @see Math#floor(double) diff --git a/src/java.base/share/classes/java/lang/System.java b/src/java.base/share/classes/java/lang/System.java index 9022b1d9c08d6..edb636bfe210c 100644 --- a/src/java.base/share/classes/java/lang/System.java +++ b/src/java.base/share/classes/java/lang/System.java @@ -797,6 +797,15 @@ public static native void arraycopy(Object src, int srcPos, * The module name of the initial/main module * {@systemProperty jdk.module.main.class} * The main class name of the initial module + * {@systemProperty file.encoding} + * The name of the default charset, defaults to {@code UTF-8}. + * The property may be set on the command line to the value + * {@code UTF-8} or {@code COMPAT}. If set on the command line to + * the value {@code COMPAT} then the value is replaced with the + * value of the {@code native.encoding} property during startup. + * Setting the property to a value other than {@code UTF-8} or + * {@code COMPAT} leads to unspecified behavior. + * * * * @@ -2112,9 +2121,9 @@ private static void initPhase1() { setIn0(new BufferedInputStream(fdIn)); // sun.stdout/err.encoding are set when the VM is associated with the terminal, // thus they are equivalent to Console.charset(), otherwise the encoding - // defaults to Charset.defaultCharset() - setOut0(newPrintStream(fdOut, props.getProperty("sun.stdout.encoding"))); - setErr0(newPrintStream(fdErr, props.getProperty("sun.stderr.encoding"))); + // defaults to native.encoding + setOut0(newPrintStream(fdOut, props.getProperty("sun.stdout.encoding", StaticProperty.nativeEncoding()))); + setErr0(newPrintStream(fdErr, props.getProperty("sun.stderr.encoding", StaticProperty.nativeEncoding()))); // Setup Java signal handlers for HUP, TERM, and INT (where available). Terminator.setup(); diff --git a/src/java.base/share/classes/java/lang/runtime/ObjectMethods.java b/src/java.base/share/classes/java/lang/runtime/ObjectMethods.java index f1fa59658473b..62c81c42f5c8d 100644 --- a/src/java.base/share/classes/java/lang/runtime/ObjectMethods.java +++ b/src/java.base/share/classes/java/lang/runtime/ObjectMethods.java @@ -37,6 +37,8 @@ import java.util.List; import java.util.Objects; +import static java.util.Objects.requireNonNull; + /** * Bootstrap methods for state-driven implementations of core methods, * including {@link Object#equals(Object)}, {@link Object#hashCode()}, and @@ -317,22 +319,31 @@ private static MethodHandle makeToString(Class receiverClass, * @param recordClass the record class hosting the record components * @param names the list of component names, joined into a string * separated by ";", or the empty string if there are no - * components. Maybe be null, if the {@code methodName} - * is {@code "equals"} or {@code "hashCode"}. + * components. This parameter is ignored if the {@code methodName} + * parameter is {@code "equals"} or {@code "hashCode"} * @param getters method handles for the accessor methods for the components * @return a call site if invoked by indy, or a method handle * if invoked by a condy * @throws IllegalArgumentException if the bootstrap arguments are invalid * or inconsistent + * @throws NullPointerException if any argument but {@code lookup} is {@code null}, + * in the case of the {@code getters} argument, its + * contents cannot be {@code null} either * @throws Throwable if any exception is thrown during call site construction */ public static Object bootstrap(MethodHandles.Lookup lookup, String methodName, TypeDescriptor type, Class recordClass, String names, MethodHandle... getters) throws Throwable { + requireNonNull(methodName); + requireNonNull(type); + requireNonNull(recordClass); + requireNonNull(names); + requireNonNull(getters); + Arrays.stream(getters).forEach(Objects::requireNonNull); MethodType methodType; - if (type instanceof MethodType) - methodType = (MethodType) type; + if (type instanceof MethodType mt) + methodType = mt; else { methodType = null; if (!MethodHandle.class.equals(type)) diff --git a/src/java.base/share/classes/java/math/BigInteger.java b/src/java.base/share/classes/java/math/BigInteger.java index 14f2ae6154cd9..df06b44027688 100644 --- a/src/java.base/share/classes/java/math/BigInteger.java +++ b/src/java.base/share/classes/java/math/BigInteger.java @@ -1670,8 +1670,8 @@ private BigInteger multiply(BigInteger val, boolean isRecursion) { // are only considering the magnitudes as non-negative. The // Toom-Cook multiplication algorithm determines the sign // at its end from the two signum values. - if (bitLength(mag, mag.length) + - bitLength(val.mag, val.mag.length) > + if ((long)bitLength(mag, mag.length) + + (long)bitLength(val.mag, val.mag.length) > 32L*MAX_MAG_LENGTH) { reportOverflow(); } diff --git a/src/java.base/share/classes/java/net/CookieManager.java b/src/java.base/share/classes/java/net/CookieManager.java index e9f506c2d3743..53ef4cab71c03 100644 --- a/src/java.base/share/classes/java/net/CookieManager.java +++ b/src/java.base/share/classes/java/net/CookieManager.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2021, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -27,7 +27,6 @@ import java.util.Map; import java.util.List; -import java.util.Collections; import java.util.Comparator; import java.io.IOException; import sun.util.logging.PlatformLogger; @@ -407,7 +406,7 @@ private boolean pathMatches(String path, String pathToMatchWith) { * path are distinguished by creation time (older first). Method made PP to enable testing. */ static List sortByPathAndAge(List cookies) { - Collections.sort(cookies, new CookieComparator()); + cookies.sort(new CookieComparator()); List cookieHeader = new java.util.ArrayList<>(); for (HttpCookie cookie : cookies) { diff --git a/src/java.base/share/classes/java/net/URLDecoder.java b/src/java.base/share/classes/java/net/URLDecoder.java index 0003778860a18..8a67e8b06cdc8 100644 --- a/src/java.base/share/classes/java/net/URLDecoder.java +++ b/src/java.base/share/classes/java/net/URLDecoder.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2021, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -65,7 +65,7 @@ * will be replaced by the character(s) whose encoding would result * in those consecutive bytes. * The encoding scheme used to decode these characters may be specified, - * or if unspecified, the default encoding of the platform will be used. + * or if unspecified, the default charset will be used. * *

* There are two possible ways in which this decoder could deal with @@ -74,6 +74,8 @@ * Which approach the decoder takes is left to the * implementation. * + * @see Charset#defaultCharset() + * * @author Mark Chamness * @author Michael McCloskey * @since 1.2 @@ -86,17 +88,17 @@ public class URLDecoder { */ private URLDecoder() {} - // The platform default encoding + // The default charset static String dfltEncName = URLEncoder.dfltEncName; /** * Decodes a {@code x-www-form-urlencoded} string. - * The platform's default encoding is used to determine what characters + * The default charset is used to determine what characters * are represented by any consecutive sequences of the form * "{@code %xy}". * @param s the {@code String} to decode - * @deprecated The resulting string may vary depending on the platform's - * default encoding. Instead, use the decode(String,String) method + * @deprecated The resulting string may vary depending on the + * default charset. Instead, use the decode(String,String) method * to specify the encoding. * @return the newly decoded {@code String} */ @@ -108,7 +110,7 @@ public static String decode(String s) { try { str = decode(s, dfltEncName); } catch (UnsupportedEncodingException e) { - // The system should always have the platform default + // The system should always have the default charset } return str; @@ -120,7 +122,7 @@ public static String decode(String s) { * *

* This method behaves the same as {@linkplain decode(String s, Charset charset)} - * except that it will {@linkplain java.nio.charset.Charset#forName look up the charset} + * except that it will {@linkplain Charset#forName look up the charset} * using the given encoding name. * * @implNote This implementation will throw an {@link java.lang.IllegalArgumentException} @@ -152,7 +154,7 @@ public static String decode(String s, String enc) throws UnsupportedEncodingExce /** * Decodes an {@code application/x-www-form-urlencoded} string using - * a specific {@linkplain java.nio.charset.Charset Charset}. + * a specific {@linkplain Charset Charset}. * The supplied charset is used to determine * what characters are represented by any consecutive sequences of the * form "{@code %xy}". @@ -172,7 +174,7 @@ public static String decode(String s, String enc) throws UnsupportedEncodingExce * @throws NullPointerException if {@code s} or {@code charset} is {@code null} * @throws IllegalArgumentException if the implementation encounters illegal * characters - * @see URLEncoder#encode(java.lang.String, java.nio.charset.Charset) + * @see URLEncoder#encode(java.lang.String, Charset) * @since 10 */ public static String decode(String s, Charset charset) { diff --git a/src/java.base/share/classes/java/net/URLEncoder.java b/src/java.base/share/classes/java/net/URLEncoder.java index 078da900b1da5..b48c90c528561 100644 --- a/src/java.base/share/classes/java/net/URLEncoder.java +++ b/src/java.base/share/classes/java/net/URLEncoder.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1995, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1995, 2021, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -32,7 +32,8 @@ import java.nio.charset.UnsupportedCharsetException ; import java.util.BitSet; import java.util.Objects; -import sun.security.action.GetPropertyAction; + +import jdk.internal.util.StaticProperty; /** * Utility class for HTML form encoding. This class contains static methods @@ -60,7 +61,7 @@ * two-digit hexadecimal representation of the byte. * The recommended encoding scheme to use is UTF-8. However, * for compatibility reasons, if an encoding is not specified, - * then the default encoding of the platform is used. + * then the default charset is used. * * *

@@ -70,6 +71,8 @@ * ü is encoded as two bytes C3 (hex) and BC (hex), and the * character @ is encoded as one byte 40 (hex). * + * @see Charset#defaultCharset() + * * @author Herb Jellinek * @since 1.0 */ @@ -134,7 +137,7 @@ public class URLEncoder { dontNeedEncoding.set('.'); dontNeedEncoding.set('*'); - dfltEncName = GetPropertyAction.privilegedGetProperty("file.encoding"); + dfltEncName = StaticProperty.fileEncoding(); } /** @@ -144,12 +147,12 @@ private URLEncoder() { } /** * Translates a string into {@code x-www-form-urlencoded} - * format. This method uses the platform's default encoding + * format. This method uses the default charset * as the encoding scheme to obtain the bytes for unsafe characters. * * @param s {@code String} to be translated. - * @deprecated The resulting string may vary depending on the platform's - * default encoding. Instead, use the encode(String,String) + * @deprecated The resulting string may vary depending on the + * default charset. Instead, use the encode(String,String) * method to specify the encoding. * @return the translated {@code String}. */ @@ -161,7 +164,7 @@ public static String encode(String s) { try { str = encode(s, dfltEncName); } catch (UnsupportedEncodingException e) { - // The system should always have the platform default + // The system should always have the default charset } return str; @@ -172,7 +175,7 @@ public static String encode(String s) { * format using a specific encoding scheme. *

* This method behaves the same as {@linkplain #encode(String s, Charset charset)} - * except that it will {@linkplain java.nio.charset.Charset#forName look up the charset} + * except that it will {@linkplain Charset#forName look up the charset} * using the given encoding name. * * @param s {@code String} to be translated. @@ -201,7 +204,7 @@ public static String encode(String s, String enc) /** * Translates a string into {@code application/x-www-form-urlencoded} - * format using a specific {@linkplain java.nio.charset.Charset Charset}. + * format using a specific {@linkplain Charset Charset}. * This method uses the supplied charset to obtain the bytes for unsafe * characters. *

@@ -214,7 +217,7 @@ public static String encode(String s, String enc) * @param charset the given charset * @return the translated {@code String}. * @throws NullPointerException if {@code s} or {@code charset} is {@code null}. - * @see URLDecoder#decode(java.lang.String, java.nio.charset.Charset) + * @see URLDecoder#decode(java.lang.String, Charset) * @since 10 */ public static String encode(String s, Charset charset) { diff --git a/src/java.base/share/classes/java/nio/charset/Charset.java b/src/java.base/share/classes/java/nio/charset/Charset.java index 0ac18a23ba84c..f44ae78bae5f6 100644 --- a/src/java.base/share/classes/java/nio/charset/Charset.java +++ b/src/java.base/share/classes/java/nio/charset/Charset.java @@ -210,9 +210,8 @@ * ZERO-WIDTH NON-BREAKING SPACE. * *

Every instance of the Java virtual machine has a default charset, which - * may or may not be one of the standard charsets. The default charset is - * determined during virtual-machine startup and typically depends upon the - * locale and charset being used by the underlying operating system.

+ * is {@code UTF-8} unless changed in an implementation specific manner. Refer to + * {@link #defaultCharset()} for more detail. * *

The {@link StandardCharsets} class defines constants for each of the * standard charsets. @@ -592,11 +591,18 @@ public SortedMap run() { /** * Returns the default charset of this Java virtual machine. * - *

The default charset is determined during virtual-machine startup and - * typically depends upon the locale and charset of the underlying - * operating system. + *

The default charset is {@code UTF-8}, unless changed in an + * implementation specific manner. + * + * @implNote An implementation may override the default charset with + * the system property {@code file.encoding} on the command line. If the + * value is {@code COMPAT}, the default charset is derived from + * the {@code native.encoding} system property, which typically depends + * upon the locale and charset of the underlying operating system. * * @return A charset object for the default charset + * @see file.encoding + * @see native.encoding * * @since 1.5 */ diff --git a/src/java.base/share/classes/java/security/AuthProvider.java b/src/java.base/share/classes/java/security/AuthProvider.java index aad4bf0a57021..1c0ce64c625f2 100644 --- a/src/java.base/share/classes/java/security/AuthProvider.java +++ b/src/java.base/share/classes/java/security/AuthProvider.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2021, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -96,7 +96,7 @@ protected AuthProvider(String name, String versionStr, String info) { * from the caller, which may be {@code null} * * @throws IllegalStateException if the provider requires configuration - * and {@link configure} has not been called + * and {@link #configure} has not been called * @throws LoginException if the login operation fails * @throws SecurityException if the caller does not pass a * security check for @@ -111,7 +111,7 @@ public abstract void login(Subject subject, CallbackHandler handler) * Log out from this provider. * * @throws IllegalStateException if the provider requires configuration - * and {@link configure} has not been called + * and {@link #configure} has not been called * @throws LoginException if the logout operation fails * @throws SecurityException if the caller does not pass a * security check for @@ -139,7 +139,7 @@ public abstract void login(Subject subject, CallbackHandler handler) * authentication information, which may be {@code null} * * @throws IllegalStateException if the provider requires configuration - * and {@link configure} has not been called + * and {@link #configure} has not been called * @throws SecurityException if the caller does not pass a * security check for * {@code SecurityPermission("authProvider.name")}, diff --git a/src/java.base/share/classes/java/security/interfaces/package-info.java b/src/java.base/share/classes/java/security/interfaces/package-info.java index 0c0a9b24dd71a..a2d1fd1a509c8 100644 --- a/src/java.base/share/classes/java/security/interfaces/package-info.java +++ b/src/java.base/share/classes/java/security/interfaces/package-info.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2021, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -60,7 +60,7 @@ * * For further documentation, please see: *

    - *
  • {extLink security_guide_jca + *
  • {@extLink security_guide_jca * Java Cryptography Architecture Reference Guide}
  • *
* diff --git a/src/java.base/share/classes/java/time/format/DateTimeTextProvider.java b/src/java.base/share/classes/java/time/format/DateTimeTextProvider.java index 1db9edb427547..f9db0a10f65ea 100644 --- a/src/java.base/share/classes/java/time/format/DateTimeTextProvider.java +++ b/src/java.base/share/classes/java/time/format/DateTimeTextProvider.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2021, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -75,7 +75,6 @@ import java.util.AbstractMap.SimpleImmutableEntry; import java.util.ArrayList; import java.util.Calendar; -import java.util.Collections; import java.util.Comparator; import java.util.HashMap; import java.util.Iterator; @@ -553,12 +552,12 @@ static final class LocaleStore { } } List> list = new ArrayList<>(reverse.values()); - Collections.sort(list, COMPARATOR); + list.sort(COMPARATOR); map.put(vtmEntry.getKey(), list); allList.addAll(list); map.put(null, allList); } - Collections.sort(allList, COMPARATOR); + allList.sort(COMPARATOR); this.parsable = map; } diff --git a/src/java.base/share/classes/java/time/format/Parsed.java b/src/java.base/share/classes/java/time/format/Parsed.java index 377b5aa1ef604..567c2700a1558 100644 --- a/src/java.base/share/classes/java/time/format/Parsed.java +++ b/src/java.base/share/classes/java/time/format/Parsed.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2021, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -354,10 +354,11 @@ private void resolveInstantFields() { } private void resolveInstantFields0(ZoneId selectedZone) { - Instant instant = Instant.ofEpochSecond(fieldValues.remove(INSTANT_SECONDS)); + Instant instant = Instant.ofEpochSecond(fieldValues.get(INSTANT_SECONDS)); ChronoZonedDateTime zdt = chrono.zonedDateTime(instant, selectedZone); updateCheckConflict(zdt.toLocalDate()); updateCheckConflict(INSTANT_SECONDS, SECOND_OF_DAY, (long) zdt.toLocalTime().toSecondOfDay()); + updateCheckConflict(INSTANT_SECONDS, OFFSET_SECONDS, (long) zdt.getOffset().getTotalSeconds()); } //----------------------------------------------------------------------- @@ -641,9 +642,9 @@ private void resolveFractional() { } private void resolveInstant() { - // add instant seconds if we have date, time and zone + // add instant seconds (if not present) if we have date, time and zone // Offset (if present) will be given priority over the zone. - if (date != null && time != null) { + if (!fieldValues.containsKey(INSTANT_SECONDS) && date != null && time != null) { Long offsetSecs = fieldValues.get(OFFSET_SECONDS); if (offsetSecs != null) { ZoneOffset offset = ZoneOffset.ofTotalSeconds(offsetSecs.intValue()); diff --git a/src/java.base/share/classes/java/util/Scanner.java b/src/java.base/share/classes/java/util/Scanner.java index 78fffbe66a72c..9e544880ae238 100644 --- a/src/java.base/share/classes/java/util/Scanner.java +++ b/src/java.base/share/classes/java/util/Scanner.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2021, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -557,10 +557,11 @@ public Scanner(Readable source) { /** * Constructs a new {@code Scanner} that produces values scanned * from the specified input stream. Bytes from the stream are converted - * into characters using the underlying platform's - * {@linkplain java.nio.charset.Charset#defaultCharset() default charset}. + * into characters using the + * {@linkplain Charset#defaultCharset() default charset}. * * @param source An input stream to be scanned + * @see Charset#defaultCharset() */ public Scanner(InputStream source) { this(new InputStreamReader(source), WHITESPACE_PATTERN); @@ -629,11 +630,12 @@ private static Readable makeReadable(InputStream source, Charset charset) { /** * Constructs a new {@code Scanner} that produces values scanned * from the specified file. Bytes from the file are converted into - * characters using the underlying platform's - * {@linkplain java.nio.charset.Charset#defaultCharset() default charset}. + * characters using the + * {@linkplain Charset#defaultCharset() default charset}. * * @param source A file to be scanned * @throws FileNotFoundException if source is not found + * @see Charset#defaultCharset() */ public Scanner(File source) throws FileNotFoundException { this((ReadableByteChannel)(new FileInputStream(source).getChannel())); @@ -702,13 +704,14 @@ private static Readable makeReadable(ReadableByteChannel source, /** * Constructs a new {@code Scanner} that produces values scanned * from the specified file. Bytes from the file are converted into - * characters using the underlying platform's - * {@linkplain java.nio.charset.Charset#defaultCharset() default charset}. + * characters using the + * {@linkplain Charset#defaultCharset() default charset}. * * @param source * the path to the file to be scanned * @throws IOException * if an I/O error occurs opening source + * @see Charset#defaultCharset() * * @since 1.7 */ @@ -769,10 +772,11 @@ public Scanner(String source) { /** * Constructs a new {@code Scanner} that produces values scanned * from the specified channel. Bytes from the source are converted into - * characters using the underlying platform's - * {@linkplain java.nio.charset.Charset#defaultCharset() default charset}. + * characters using the + * {@linkplain Charset#defaultCharset() default charset}. * * @param source A channel to scan + * @see Charset#defaultCharset() */ public Scanner(ReadableByteChannel source) { this(makeReadable(Objects.requireNonNull(source, "source")), diff --git a/src/java.base/share/classes/java/util/random/package-info.java b/src/java.base/share/classes/java/util/random/package-info.java index 2e56c1b6db013..ec5f682262e7c 100644 --- a/src/java.base/share/classes/java/util/random/package-info.java +++ b/src/java.base/share/classes/java/util/random/package-info.java @@ -599,32 +599,32 @@ * {@code 0xd1342543de82ef95L} * {@code xoroshiro128}, version 1.0 * {@code (24, 16, 37)} - * mixLea32{@code (s+x0)} + * mixLea64{@code (s+x0)} * "L64X256MixRandom" * {@code 0xd1342543de82ef95L} * {@code xoshiro256}, version 1.0 * {@code (17, 45)} - * mixLea32{@code (s+x0)} + * mixLea64{@code (s+x0)} * "L64X1024MixRandom" * {@code 0xd1342543de82ef95L} * {@code xoroshiro1024}, version 1.0 * {@code (25, 27, 36)} - * mixLea32{@code (s+x0)} + * mixLea64{@code (s+x0)} * "L128X128MixRandom" * {@code 0x1d605bbb58c8abbfdL} * {@code xoroshiro128}, version 1.0 * {@code (24, 16, 37)} - * mixLea32{@code (sh+x0)} + * mixLea64{@code (sh+x0)} * "L128X256MixRandom" * {@code 0x1d605bbb58c8abbfdL} * {@code xoshiro256}, version 1.0 * {@code (17, 45)} - * mixLea32{@code (sh+x0)} + * mixLea64{@code (sh+x0)} * "L128X1024MixRandom" * {@code 0x1d605bbb58c8abbfdL} * {@code xoroshiro1024}, version 1.0 * {@code (25, 27, 36)} - * mixLea32{@code (sh+x0)} + * mixLea64{@code (sh+x0)} * * * diff --git a/src/java.base/share/classes/javax/net/ssl/SNIHostName.java b/src/java.base/share/classes/javax/net/ssl/SNIHostName.java index 9f16152b8c8d8..5e4e545a2dfc3 100644 --- a/src/java.base/share/classes/javax/net/ssl/SNIHostName.java +++ b/src/java.base/share/classes/javax/net/ssl/SNIHostName.java @@ -34,6 +34,7 @@ import java.util.Locale; import java.util.Objects; import java.util.regex.Pattern; +import java.util.regex.PatternSyntaxException; /** * Instances of this class represent a server name of type @@ -297,7 +298,7 @@ public String toString() { * @return a {@code SNIMatcher} object for {@code SNIHostName}s * @throws NullPointerException if {@code regex} is * {@code null} - * @throws java.util.regex.PatternSyntaxException if the regular expression's + * @throws PatternSyntaxException if the regular expression's * syntax is invalid */ public static SNIMatcher createSNIMatcher(String regex) { diff --git a/src/java.base/share/classes/javax/net/ssl/SNIMatcher.java b/src/java.base/share/classes/javax/net/ssl/SNIMatcher.java index a6c9ab92ee21c..a83a566fb7fa9 100644 --- a/src/java.base/share/classes/javax/net/ssl/SNIMatcher.java +++ b/src/java.base/share/classes/javax/net/ssl/SNIMatcher.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2021, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,6 +25,8 @@ package javax.net.ssl; +import java.util.Collection; + /** * Instances of this class represent a matcher that performs match * operations on an {@link SNIServerName} instance. diff --git a/src/java.base/share/classes/javax/net/ssl/SNIServerName.java b/src/java.base/share/classes/javax/net/ssl/SNIServerName.java index d0ec849f71b01..46df9d11a6e1f 100644 --- a/src/java.base/share/classes/javax/net/ssl/SNIServerName.java +++ b/src/java.base/share/classes/javax/net/ssl/SNIServerName.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2021, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -27,6 +27,7 @@ import java.util.Arrays; import java.util.HexFormat; +import java.util.List; /** * Instances of this class represent a server name in a Server Name diff --git a/src/java.base/share/classes/javax/net/ssl/SSLContextSpi.java b/src/java.base/share/classes/javax/net/ssl/SSLContextSpi.java index 4e2a414819348..29fa2032c7c1b 100644 --- a/src/java.base/share/classes/javax/net/ssl/SSLContextSpi.java +++ b/src/java.base/share/classes/javax/net/ssl/SSLContextSpi.java @@ -51,7 +51,7 @@ public SSLContextSpi() {} * @param tm the sources of peer authentication trust decisions * @param sr the source of randomness * @throws KeyManagementException if this operation fails - * @see SSLContext#init(KeyManager [], TrustManager [], SecureRandom) + * @see SSLContext#init(KeyManager[], TrustManager[], SecureRandom) */ protected abstract void engineInit(KeyManager[] km, TrustManager[] tm, SecureRandom sr) throws KeyManagementException; diff --git a/src/java.base/share/classes/javax/net/ssl/SSLEngine.java b/src/java.base/share/classes/javax/net/ssl/SSLEngine.java index 0102c17f2e21e..fff674ca1fd8e 100644 --- a/src/java.base/share/classes/javax/net/ssl/SSLEngine.java +++ b/src/java.base/share/classes/javax/net/ssl/SSLEngine.java @@ -312,7 +312,7 @@ * *
  • Enabled cipher suites, which may be fewer than * the full set of supported suites. This group is set using the - * {@link #setEnabledCipherSuites(String [])} method, and + * {@link #setEnabledCipherSuites(String[])} method, and * queried using the {@link #getEnabledCipherSuites()} method. * Initially, a default set of cipher suites will be enabled on a * new engine that represents the minimum suggested @@ -495,8 +495,8 @@ public int getPeerPort() { * An invocation of this method behaves in exactly the same manner * as the invocation: *
    -     * {@link #wrap(ByteBuffer [], int, int, ByteBuffer)
    -     *     engine.wrap(new ByteBuffer [] { src }, 0, 1, dst);}
    +     * {@link #wrap(ByteBuffer[], int, int, ByteBuffer)
    +     *     engine.wrap(new ByteBuffer[] { src }, 0, 1, dst);}
          * 
    * * @param src @@ -517,7 +517,7 @@ public int getPeerPort() { * is null. * @throws IllegalStateException if the client/server mode * has not yet been set. - * @see #wrap(ByteBuffer [], int, int, ByteBuffer) + * @see #wrap(ByteBuffer[], int, int, ByteBuffer) */ public SSLEngineResult wrap(ByteBuffer src, ByteBuffer dst) throws SSLException { @@ -531,7 +531,7 @@ public SSLEngineResult wrap(ByteBuffer src, * An invocation of this method behaves in exactly the same manner * as the invocation: *
    -     * {@link #wrap(ByteBuffer [], int, int, ByteBuffer)
    +     * {@link #wrap(ByteBuffer[], int, int, ByteBuffer)
          *     engine.wrap(srcs, 0, srcs.length, dst);}
          * 
    * @@ -554,7 +554,7 @@ public SSLEngineResult wrap(ByteBuffer src, * is null, or if any element in {@code srcs} is null. * @throws IllegalStateException if the client/server mode * has not yet been set. - * @see #wrap(ByteBuffer [], int, int, ByteBuffer) + * @see #wrap(ByteBuffer[], int, int, ByteBuffer) */ public SSLEngineResult wrap(ByteBuffer [] srcs, ByteBuffer dst) throws SSLException { @@ -650,8 +650,8 @@ public abstract SSLEngineResult wrap(ByteBuffer [] srcs, int offset, * An invocation of this method behaves in exactly the same manner * as the invocation: *
    -     * {@link #unwrap(ByteBuffer, ByteBuffer [], int, int)
    -     *     engine.unwrap(src, new ByteBuffer [] { dst }, 0, 1);}
    +     * {@link #unwrap(ByteBuffer, ByteBuffer[], int, int)
    +     *     engine.unwrap(src, new ByteBuffer[] { dst }, 0, 1);}
          * 
    * * @param src @@ -672,7 +672,7 @@ public abstract SSLEngineResult wrap(ByteBuffer [] srcs, int offset, * is null. * @throws IllegalStateException if the client/server mode * has not yet been set. - * @see #unwrap(ByteBuffer, ByteBuffer [], int, int) + * @see #unwrap(ByteBuffer, ByteBuffer[], int, int) */ public SSLEngineResult unwrap(ByteBuffer src, ByteBuffer dst) throws SSLException { @@ -686,7 +686,7 @@ public SSLEngineResult unwrap(ByteBuffer src, * An invocation of this method behaves in exactly the same manner * as the invocation: *
    -     * {@link #unwrap(ByteBuffer, ByteBuffer [], int, int)
    +     * {@link #unwrap(ByteBuffer, ByteBuffer[], int, int)
          *     engine.unwrap(src, dsts, 0, dsts.length);}
          * 
    * @@ -709,7 +709,7 @@ public SSLEngineResult unwrap(ByteBuffer src, * is null, or if any element in {@code dsts} is null. * @throws IllegalStateException if the client/server mode * has not yet been set. - * @see #unwrap(ByteBuffer, ByteBuffer [], int, int) + * @see #unwrap(ByteBuffer, ByteBuffer[], int, int) */ public SSLEngineResult unwrap(ByteBuffer src, ByteBuffer [] dsts) throws SSLException { @@ -926,7 +926,7 @@ public abstract SSLEngineResult unwrap(ByteBuffer src, * * @return an array of cipher suite names * @see #getEnabledCipherSuites() - * @see #setEnabledCipherSuites(String []) + * @see #setEnabledCipherSuites(String[]) */ public abstract String [] getSupportedCipherSuites(); @@ -952,7 +952,7 @@ public abstract SSLEngineResult unwrap(ByteBuffer src, * * @return an array of cipher suite names * @see #getSupportedCipherSuites() - * @see #setEnabledCipherSuites(String []) + * @see #setEnabledCipherSuites(String[]) */ public abstract String [] getEnabledCipherSuites(); @@ -983,7 +983,7 @@ public abstract SSLEngineResult unwrap(ByteBuffer src, * @see #getSupportedCipherSuites() * @see #getEnabledCipherSuites() */ - public abstract void setEnabledCipherSuites(String suites []); + public abstract void setEnabledCipherSuites(String[] suites); /** @@ -1005,7 +1005,7 @@ public abstract SSLEngineResult unwrap(ByteBuffer src, * by the protocol. * * @return an array of protocols - * @see #setEnabledProtocols(String []) + * @see #setEnabledProtocols(String[]) */ public abstract String [] getEnabledProtocols(); @@ -1024,7 +1024,7 @@ public abstract SSLEngineResult unwrap(ByteBuffer src, * when the protocols parameter is null. * @see #getEnabledProtocols() */ - public abstract void setEnabledProtocols(String protocols[]); + public abstract void setEnabledProtocols(String[] protocols); /** @@ -1161,7 +1161,7 @@ public SSLSession getHandshakeSession() { * * @implNote * The JDK SunJSSE provider implementation returns false unless - * {@link setUseClientMode(boolean)} is used to change the mode to true. + * {@link #setUseClientMode(boolean)} is used to change the mode to true. * * @return true if the engine should do handshaking * in "client" mode diff --git a/src/java.base/share/classes/javax/net/ssl/SSLEngineResult.java b/src/java.base/share/classes/javax/net/ssl/SSLEngineResult.java index 277b09178e513..ccb0222fb2136 100644 --- a/src/java.base/share/classes/javax/net/ssl/SSLEngineResult.java +++ b/src/java.base/share/classes/javax/net/ssl/SSLEngineResult.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2021, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,6 +25,8 @@ package javax.net.ssl; +import java.nio.ByteBuffer; + /** * An encapsulation of the result state produced by * {@code SSLEngine} I/O calls. diff --git a/src/java.base/share/classes/javax/net/ssl/SSLServerSocket.java b/src/java.base/share/classes/javax/net/ssl/SSLServerSocket.java index cb0a500608fbf..00a8bed19f091 100644 --- a/src/java.base/share/classes/javax/net/ssl/SSLServerSocket.java +++ b/src/java.base/share/classes/javax/net/ssl/SSLServerSocket.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2021, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -23,13 +23,11 @@ * questions. */ - package javax.net.ssl; import java.io.*; import java.net.*; - /** * This class extends ServerSocket and * provides secure server sockets using protocols such as the Secure @@ -205,7 +203,7 @@ protected SSLServerSocket(int port, int backlog, InetAddress address) * * @return an array of cipher suites enabled * @see #getSupportedCipherSuites() - * @see #setEnabledCipherSuites(String []) + * @see #setEnabledCipherSuites(String[]) */ public abstract String [] getEnabledCipherSuites(); @@ -261,7 +259,7 @@ protected SSLServerSocket(int port, int backlog, InetAddress address) * * @return an array of cipher suite names * @see #getEnabledCipherSuites() - * @see #setEnabledCipherSuites(String []) + * @see #setEnabledCipherSuites(String[]) */ public abstract String [] getSupportedCipherSuites(); @@ -271,7 +269,7 @@ protected SSLServerSocket(int port, int backlog, InetAddress address) * * @return an array of protocol names supported * @see #getEnabledProtocols() - * @see #setEnabledProtocols(String []) + * @see #setEnabledProtocols(String[]) */ public abstract String [] getSupportedProtocols(); @@ -287,7 +285,7 @@ protected SSLServerSocket(int port, int backlog, InetAddress address) * * @return an array of protocol names * @see #getSupportedProtocols() - * @see #setEnabledProtocols(String []) + * @see #setEnabledProtocols(String[]) */ public abstract String [] getEnabledProtocols(); diff --git a/src/java.base/share/classes/javax/net/ssl/SSLSession.java b/src/java.base/share/classes/javax/net/ssl/SSLSession.java index e89cee6477fd5..242e4fb94cf1c 100644 --- a/src/java.base/share/classes/javax/net/ssl/SSLSession.java +++ b/src/java.base/share/classes/javax/net/ssl/SSLSession.java @@ -26,6 +26,7 @@ package javax.net.ssl; import java.security.Principal; +import java.nio.ByteBuffer; /** * In SSL, sessions are used to describe an ongoing relationship between diff --git a/src/java.base/share/classes/javax/net/ssl/X509ExtendedTrustManager.java b/src/java.base/share/classes/javax/net/ssl/X509ExtendedTrustManager.java index b2064cdc4c327..90a2e5b687315 100644 --- a/src/java.base/share/classes/javax/net/ssl/X509ExtendedTrustManager.java +++ b/src/java.base/share/classes/javax/net/ssl/X509ExtendedTrustManager.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2010, 2021, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -26,8 +26,8 @@ package javax.net.ssl; import java.net.Socket; -import javax.net.ssl.X509TrustManager; +import java.security.AlgorithmConstraints; import java.security.cert.X509Certificate; import java.security.cert.CertificateException; diff --git a/src/java.base/share/classes/jdk/internal/util/StaticProperty.java b/src/java.base/share/classes/jdk/internal/util/StaticProperty.java index 896f43300360e..011cb148af110 100644 --- a/src/java.base/share/classes/jdk/internal/util/StaticProperty.java +++ b/src/java.base/share/classes/jdk/internal/util/StaticProperty.java @@ -50,6 +50,7 @@ public final class StaticProperty { private static final String JDK_SERIAL_FILTER_FACTORY; private static final String JAVA_IO_TMPDIR; private static final String NATIVE_ENCODING; + private static final String FILE_ENCODING; private StaticProperty() {} @@ -65,6 +66,7 @@ private StaticProperty() {} JDK_SERIAL_FILTER = getProperty(props, "jdk.serialFilter", null); JDK_SERIAL_FILTER_FACTORY = getProperty(props, "jdk.serialFilterFactory", null); NATIVE_ENCODING = getProperty(props, "native.encoding"); + FILE_ENCODING = getProperty(props, "file.encoding"); } private static String getProperty(Properties props, String key) { @@ -212,4 +214,17 @@ public static String jdkSerialFilterFactory() { public static String nativeEncoding() { return NATIVE_ENCODING; } + + /** + * Return the {@code file.encoding} system property. + * + * {@link SecurityManager#checkPropertyAccess} is NOT checked + * in this method. The caller of this method should take care to ensure + * that the returned property is not made accessible to untrusted code. + * + * @return the {@code file.encoding} system property + */ + public static String fileEncoding() { + return FILE_ENCODING; + } } diff --git a/src/java.base/share/classes/jdk/internal/util/SystemProps.java b/src/java.base/share/classes/jdk/internal/util/SystemProps.java index bb4fd699450be..3093e2c57bc1b 100644 --- a/src/java.base/share/classes/jdk/internal/util/SystemProps.java +++ b/src/java.base/share/classes/jdk/internal/util/SystemProps.java @@ -68,8 +68,14 @@ public static Map initProperties() { : raw.propDefault(Raw._file_encoding_NDX)); put(props, "native.encoding", nativeEncoding); - // Add properties that have not been overridden on the cmdline - putIfAbsent(props, "file.encoding", nativeEncoding); + // "file.encoding" defaults to "UTF-8", unless specified in the command line + // where "COMPAT" designates the native encoding. + var fileEncoding = props.getOrDefault("file.encoding", "UTF-8"); + if ("COMPAT".equals(fileEncoding)) { + put(props, "file.encoding", nativeEncoding); + } else { + putIfAbsent(props, "file.encoding", fileEncoding); + } // Use platform values if not overridden by a commandline -Dkey=value // In no particular order diff --git a/src/java.base/share/classes/sun/net/www/protocol/file/FileURLConnection.java b/src/java.base/share/classes/sun/net/www/protocol/file/FileURLConnection.java index c6878a6369945..603e8300ffc65 100644 --- a/src/java.base/share/classes/sun/net/www/protocol/file/FileURLConnection.java +++ b/src/java.base/share/classes/sun/net/www/protocol/file/FileURLConnection.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1995, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1995, 2021, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -198,7 +198,7 @@ public synchronized InputStream getInputStream() throw new FileNotFoundException(filename); } - Collections.sort(files, Collator.getInstance()); + files.sort(Collator.getInstance()); for (int i = 0 ; i < files.size() ; i++) { String fileName = files.get(i); diff --git a/src/java.base/share/classes/sun/security/provider/certpath/PKIX.java b/src/java.base/share/classes/sun/security/provider/certpath/PKIX.java index 6abb3c2458dcd..32f2034394fab 100644 --- a/src/java.base/share/classes/sun/security/provider/certpath/PKIX.java +++ b/src/java.base/share/classes/sun/security/provider/certpath/PKIX.java @@ -239,7 +239,7 @@ private void checkParams(PKIXBuilderParameters params) if (stores == null) { // reorder CertStores so that local CertStores are tried first stores = new ArrayList<>(params.getCertStores()); - Collections.sort(stores, new CertStoreComparator()); + stores.sort(new CertStoreComparator()); } return stores; } diff --git a/src/java.base/share/man/java.1 b/src/java.base/share/man/java.1 index c21177233e411..7885a035df9d7 100644 --- a/src/java.base/share/man/java.1 +++ b/src/java.base/share/man/java.1 @@ -4418,8 +4418,18 @@ selected. \f[I]output\-options\f[R] is .RS .PP -\f[CB]filecount=\f[R]\f[I]file\-count\f[R] \f[CB]filesize=\f[R]\f[I]file size -with optional K, M or G suffix\f[R] +\f[CB]filecount=\f[R]\f[I]file\-count\f[R] \f[CB]filesize=\f[R]\f[I]\f[R] \f[CB]foldmultilines=\f[R]\f[I]\f[R] +.RE +.PP +When \f[I]foldmultilines\f[R] is true, a log event that consists of +multiple lines will be folded into a single line by replacing newline characters +with the sequence '\\' and 'n' in the output. +Existing single backslash characters will also be replaced with a sequence of +two backslashes so that the conversion can be reversed. +This option is safe to use with UTF-8 character encodings, but other encodings may not work. +For example, it may incorrectly convert multi-byte sequences in Shift JIS and BIG5. +This option is available only for file outputs. .RE .RE .SS Default Configuration diff --git a/src/java.base/windows/classes/java/lang/ProcessEnvironment.java b/src/java.base/windows/classes/java/lang/ProcessEnvironment.java index 43ff33ffe40bf..9a30492149041 100644 --- a/src/java.base/windows/classes/java/lang/ProcessEnvironment.java +++ b/src/java.base/windows/classes/java/lang/ProcessEnvironment.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2011, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2021, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -63,7 +63,6 @@ package java.lang; -import java.io.*; import java.util.*; final class ProcessEnvironment extends HashMap @@ -301,7 +300,7 @@ static Map emptyEnvironment(int capacity) { String toEnvironmentBlock() { // Sort Unicode-case-insensitively by name List> list = new ArrayList<>(entrySet()); - Collections.sort(list, entryComparator); + list.sort(entryComparator); StringBuilder sb = new StringBuilder(size()*30); int cmp = -1; diff --git a/src/java.desktop/macosx/classes/sun/lwawt/macosx/CPlatformView.java b/src/java.desktop/macosx/classes/sun/lwawt/macosx/CPlatformView.java index 14063deec408f..5ff87b1c61a80 100644 --- a/src/java.desktop/macosx/classes/sun/lwawt/macosx/CPlatformView.java +++ b/src/java.desktop/macosx/classes/sun/lwawt/macosx/CPlatformView.java @@ -62,6 +62,7 @@ public void initialize(LWWindowPeer peer, CPlatformResponder responder) { initializeBase(peer, responder); this.windowLayer = CGraphicsDevice.usingMetalPipeline()? createMTLLayer() : createCGLayer(); + setPtr(nativeCreateView(0, 0, 0, 0, getWindowLayerPtr())); } diff --git a/src/java.desktop/macosx/classes/sun/lwawt/macosx/CPlatformWindow.java b/src/java.desktop/macosx/classes/sun/lwawt/macosx/CPlatformWindow.java index 4dff56cba219c..eb97221dc7288 100644 --- a/src/java.desktop/macosx/classes/sun/lwawt/macosx/CPlatformWindow.java +++ b/src/java.desktop/macosx/classes/sun/lwawt/macosx/CPlatformWindow.java @@ -363,7 +363,9 @@ public void initialize(Window _target, LWWindowPeer _peer, PlatformWindow _owner } }); setPtr(ref.get()); - + if (peer != null) { // Not applicable to CWarningWindow + peer.setTextured(IS(TEXTURED, styleBits)); + } if (target instanceof javax.swing.RootPaneContainer) { final javax.swing.JRootPane rootpane = ((javax.swing.RootPaneContainer)target).getRootPane(); if (rootpane != null) rootpane.addPropertyChangeListener("ancestor", new PropertyChangeListener() { @@ -530,8 +532,6 @@ protected int getInitialStyleBits() { } } - peer.setTextured(IS(TEXTURED, styleBits)); - return styleBits; } diff --git a/src/java.desktop/macosx/native/libawt_lwawt/awt/CInputMethod.m b/src/java.desktop/macosx/native/libawt_lwawt/awt/CInputMethod.m index 88585a6cbf7d7..3bfd72668c37d 100644 --- a/src/java.desktop/macosx/native/libawt_lwawt/awt/CInputMethod.m +++ b/src/java.desktop/macosx/native/libawt_lwawt/awt/CInputMethod.m @@ -115,9 +115,7 @@ + (void) _nativeNotifyPeerWithView:(AWTView *)view inputMethod:(jobject) inputMe AWT_ASSERT_APPKIT_THREAD; if (!view) return; - if (!inputMethod) return; - - [view setInputMethod:inputMethod]; // inputMethod is a GlobalRef + [view setInputMethod:inputMethod]; // inputMethod is a GlobalRef or null to disable. } + (void) _nativeEndComposition:(AWTView *)view { diff --git a/src/java.desktop/macosx/native/libawt_lwawt/awt/LWCToolkit.m b/src/java.desktop/macosx/native/libawt_lwawt/awt/LWCToolkit.m index 1c3fd329c59ed..ee0f4c87eaf17 100644 --- a/src/java.desktop/macosx/native/libawt_lwawt/awt/LWCToolkit.m +++ b/src/java.desktop/macosx/native/libawt_lwawt/awt/LWCToolkit.m @@ -259,6 +259,7 @@ BOOL isSWTInWebStart(JNIEnv* env) { static void AWT_NSUncaughtExceptionHandler(NSException *exception) { NSLog(@"Apple AWT Internal Exception: %@", [exception description]); + NSLog(@"trace: %@", [exception callStackSymbols]); } @interface AWTStarter : NSObject diff --git a/src/java.desktop/macosx/native/libawt_lwawt/java2d/metal/MTLPaints.h b/src/java.desktop/macosx/native/libawt_lwawt/java2d/metal/MTLPaints.h index 20ba80a994910..4db8f82992cb9 100644 --- a/src/java.desktop/macosx/native/libawt_lwawt/java2d/metal/MTLPaints.h +++ b/src/java.desktop/macosx/native/libawt_lwawt/java2d/metal/MTLPaints.h @@ -63,7 +63,17 @@ @end @interface MTLColorPaint : MTLPaint ++ (void)setPipelineState:(id )encoder + context:(MTLContext *)mtlc + renderOptions:(const RenderOptions *)renderOptions + pipelineStateStorage:(MTLPipelineStatesStorage *)pipelineStateStorage + rpDesc:(MTLRenderPipelineDescriptor *)rpDesc + vertShader:(NSString *)vertShader + fragShader:(NSString *)fragShader + color:(jint)color; + - (id)initWithColor:(jint)color; + @property (nonatomic, readonly) jint color; @end diff --git a/src/java.desktop/macosx/native/libawt_lwawt/java2d/metal/MTLPaints.m b/src/java.desktop/macosx/native/libawt_lwawt/java2d/metal/MTLPaints.m index 8bff3c4c2fbe3..a3b1254bf1374 100644 --- a/src/java.desktop/macosx/native/libawt_lwawt/java2d/metal/MTLPaints.m +++ b/src/java.desktop/macosx/native/libawt_lwawt/java2d/metal/MTLPaints.m @@ -141,6 +141,27 @@ @implementation MTLColorPaint { // color-mode jint _color; } ++ (void)setPipelineState:(id )encoder + context:(MTLContext *)mtlc + renderOptions:(const RenderOptions *)renderOptions + pipelineStateStorage:(MTLPipelineStatesStorage *)pipelineStateStorage + rpDesc:(MTLRenderPipelineDescriptor *)rpDesc + vertShader:(NSString *)vertShader + fragShader:(NSString *)fragShader + color:(jint)color { + + struct FrameUniforms uf = {RGBA_TO_V4(color)}; + [encoder setVertexBytes:&uf length:sizeof(uf) atIndex:FrameUniformBuffer]; + + id pipelineState = [pipelineStateStorage getPipelineState:rpDesc + vertexShaderId:vertShader + fragmentShaderId:fragShader + composite:mtlc.composite + renderOptions:renderOptions + stencilNeeded:[mtlc.clip isShape]]; + [encoder setRenderPipelineState:pipelineState]; +} + - (id)initWithColor:(jint)color { self = [super initWithState:sun_java2d_SunGraphics2D_PAINT_ALPHACOLOR]; @@ -217,16 +238,14 @@ - (void)setPipelineState:(id)encoder rpDesc = [[templateRenderPipelineDesc copy] autorelease]; } - struct FrameUniforms uf = {RGBA_TO_V4(_color)}; - [encoder setVertexBytes:&uf length:sizeof(uf) atIndex:FrameUniformBuffer]; - - id pipelineState = [pipelineStateStorage getPipelineState:rpDesc - vertexShaderId:vertShader - fragmentShaderId:fragShader - composite:mtlc.composite - renderOptions:renderOptions - stencilNeeded:[mtlc.clip isShape]]; - [encoder setRenderPipelineState:pipelineState]; + [MTLColorPaint setPipelineState:encoder + context:mtlc + renderOptions:renderOptions + pipelineStateStorage:pipelineStateStorage + rpDesc:rpDesc + vertShader:vertShader + fragShader:fragShader + color:_color]; } - (void)setXorModePipelineState:(id)encoder @@ -948,6 +967,16 @@ - (void)setPipelineState:(id )encoder renderOptions:renderOptions stencilNeeded:[mtlc.clip isShape]]; [encoder setRenderPipelineState:pipelineState]; + } else { + // Fallback to default pipeline state + [MTLColorPaint setPipelineState:encoder + context:mtlc + renderOptions:renderOptions + pipelineStateStorage:pipelineStateStorage + rpDesc:[[templateRenderPipelineDesc copy] autorelease] + vertShader:@"vert_col" + fragShader:@"frag_col" + color:0]; } } @@ -987,6 +1016,16 @@ - (void)setXorModePipelineState:(id )encoder renderOptions:renderOptions stencilNeeded:[mtlc.clip isShape]]; [encoder setRenderPipelineState:pipelineState]; + } else { + // Fallback to default pipeline state + [MTLColorPaint setPipelineState:encoder + context:mtlc + renderOptions:renderOptions + pipelineStateStorage:pipelineStateStorage + rpDesc:[[templateRenderPipelineDesc copy] autorelease] + vertShader:@"vert_col" + fragShader:@"frag_col" + color:0]; } } diff --git a/src/java.desktop/share/classes/javax/swing/JInternalFrame.java b/src/java.desktop/share/classes/javax/swing/JInternalFrame.java index fd4182814f767..17b0fecde0826 100644 --- a/src/java.desktop/share/classes/javax/swing/JInternalFrame.java +++ b/src/java.desktop/share/classes/javax/swing/JInternalFrame.java @@ -188,6 +188,8 @@ public class JInternalFrame extends JComponent implements protected String title; /** * The icon that is displayed when this internal frame is iconified. + * Subclassers must ensure this is set to a non-null value + * during construction and not subsequently set this to null. * @see #iconable */ protected JDesktopIcon desktopIcon; @@ -1307,11 +1309,15 @@ public JDesktopPane getDesktopPane() { * JInternalFrame. * * @param d the JDesktopIcon to display on the desktop + * @throws NullPointerException if the {@code d} is {@code null} * @see #getDesktopIcon */ @BeanProperty(description = "The icon shown when this internal frame is minimized.") public void setDesktopIcon(JDesktopIcon d) { + if (d == null) { + throw new NullPointerException("JDesktopIcon is null"); + } JDesktopIcon oldValue = getDesktopIcon(); desktopIcon = d; firePropertyChange("desktopIcon", oldValue, d); diff --git a/src/java.desktop/share/classes/javax/swing/plaf/basic/BasicTreeUI.java b/src/java.desktop/share/classes/javax/swing/plaf/basic/BasicTreeUI.java index 6d1d85df64395..650048a99734d 100644 --- a/src/java.desktop/share/classes/javax/swing/plaf/basic/BasicTreeUI.java +++ b/src/java.desktop/share/classes/javax/swing/plaf/basic/BasicTreeUI.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2021, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -34,7 +34,6 @@ import java.util.Enumeration; import java.util.Hashtable; import java.util.ArrayList; -import java.util.Collections; import java.util.Comparator; import javax.swing.plaf.ComponentUI; import javax.swing.plaf.UIResource; @@ -3751,7 +3750,7 @@ TreePath[] getDisplayOrderPaths(TreePath[] paths) { for (TreePath path : paths) { selOrder.add(path); } - Collections.sort(selOrder, this); + selOrder.sort(this); int n = selOrder.size(); TreePath[] displayPaths = new TreePath[n]; for (int i = 0; i < n; i++) { diff --git a/src/java.desktop/share/classes/javax/swing/plaf/nimbus/NimbusIcon.java b/src/java.desktop/share/classes/javax/swing/plaf/nimbus/NimbusIcon.java index afe7d825ec9fb..dcdb5a81e4cd0 100644 --- a/src/java.desktop/share/classes/javax/swing/plaf/nimbus/NimbusIcon.java +++ b/src/java.desktop/share/classes/javax/swing/plaf/nimbus/NimbusIcon.java @@ -43,7 +43,7 @@ * An icon that delegates to a painter. * @author rbair */ -class NimbusIcon implements SynthIcon { +class NimbusIcon implements SynthIcon, UIResource { private int width; private int height; private String prefix; diff --git a/src/java.desktop/share/classes/javax/swing/plaf/nimbus/NimbusStyle.java b/src/java.desktop/share/classes/javax/swing/plaf/nimbus/NimbusStyle.java index a1e542db52e22..b2c8fc6e679dc 100644 --- a/src/java.desktop/share/classes/javax/swing/plaf/nimbus/NimbusStyle.java +++ b/src/java.desktop/share/classes/javax/swing/plaf/nimbus/NimbusStyle.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2021, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -40,7 +40,6 @@ import java.awt.Insets; import java.lang.ref.WeakReference; import java.util.ArrayList; -import java.util.Collections; import java.util.Comparator; import java.util.HashMap; import java.util.List; @@ -463,7 +462,7 @@ private void validate() { //now that I've collected all the runtime states, I'll sort them based //on their integer "state" (see SynthState for how this works). - Collections.sort(runtimeStates, STATE_COMPARATOR); + runtimeStates.sort(STATE_COMPARATOR); //finally, set the array of runtime states on the values object values.states = runtimeStates.toArray(new RuntimeState[runtimeStates.size()]); diff --git a/src/java.desktop/share/classes/javax/swing/plaf/nimbus/skin.laf b/src/java.desktop/share/classes/javax/swing/plaf/nimbus/skin.laf index 17019bb00c2dd..f1d4301d47827 100644 --- a/src/java.desktop/share/classes/javax/swing/plaf/nimbus/skin.laf +++ b/src/java.desktop/share/classes/javax/swing/plaf/nimbus/skin.laf @@ -27352,10 +27352,10 @@