diff --git a/make/autoconf/flags-other.m4 b/make/autoconf/flags-other.m4 index 14bb3f5b52f..0a0429c354b 100644 --- a/make/autoconf/flags-other.m4 +++ b/make/autoconf/flags-other.m4 @@ -89,11 +89,11 @@ 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+=" -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+=" $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 7de6398bbd6..b28218d66aa 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 diff --git a/make/common/ProcessMarkdown.gmk b/make/common/ProcessMarkdown.gmk index 46cdbba0f85..fff54d16238 100644 --- a/make/common/ProcessMarkdown.gmk +++ b/make/common/ProcessMarkdown.gmk @@ -103,7 +103,7 @@ define ProcessMarkdown $$(call LogInfo, Post-processing markdown file $2) $$(call MakeDir, $$(SUPPORT_OUTPUTDIR)/markdown $$($1_$2_TARGET_DIR)) $$(call ExecuteWithLog, $$(SUPPORT_OUTPUTDIR)/markdown/$$($1_$2_MARKER)_post, \ - ( $$($1_POST_PROCESS) < $$($1_$2_PANDOC_OUTPUT) > $$($1_$2_OUTPUT_FILE) ) ) + ( $$($1_POST_PROCESS) $$($1_$2_PANDOC_OUTPUT) > $$($1_$2_OUTPUT_FILE) ) ) endif $1 += $$($1_$2_OUTPUT_FILE) diff --git a/src/hotspot/cpu/aarch64/pauth_aarch64.hpp b/src/hotspot/cpu/aarch64/pauth_aarch64.hpp index 6109964458f..e12a671daf1 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/x86/macroAssembler_x86.hpp b/src/hotspot/cpu/x86/macroAssembler_x86.hpp index ca49baa607f..c9faa064649 100644 --- a/src/hotspot/cpu/x86/macroAssembler_x86.hpp +++ b/src/hotspot/cpu/x86/macroAssembler_x86.hpp @@ -1005,12 +1005,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 778dd1a1b7e..caa27290727 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 ee38a82dab1..086f4a7ac8a 100644 --- a/src/hotspot/cpu/x86/stubGenerator_x86_64.cpp +++ b/src/hotspot/cpu/x86/stubGenerator_x86_64.cpp @@ -4407,6 +4407,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); @@ -7803,13 +7892,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(); @@ -7849,7 +7945,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 a306f4a0637..9a4523cd06f 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 3f682d7d0b2..b93e50b6d51 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/os_cpu/bsd_aarch64/pauth_bsd_aarch64.inline.hpp b/src/hotspot/os_cpu/bsd_aarch64/pauth_bsd_aarch64.inline.hpp index 21193e181f2..a4d416d384e 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/windows_aarch64/pauth_windows_aarch64.inline.hpp b/src/hotspot/os_cpu/windows_aarch64/pauth_windows_aarch64.inline.hpp index bf1d2aa99e1..844291ee1e4 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/classfile/classLoaderData.cpp b/src/hotspot/share/classfile/classLoaderData.cpp index e7ec9e393ca..d3e05a3b486 100644 --- a/src/hotspot/share/classfile/classLoaderData.cpp +++ b/src/hotspot/share/classfile/classLoaderData.cpp @@ -981,11 +981,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 165841e0c8c..6f51ce2f52a 100644 --- a/src/hotspot/share/classfile/javaClasses.cpp +++ b/src/hotspot/share/classfile/javaClasses.cpp @@ -208,9 +208,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 5c09f786c8d..ee6c4c1d052 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 0dfb64aafc8..cd67bc44d3f 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 d8806f0ace2..bbae290b33f 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; @@ -435,6 +436,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 6b7382f81be..117126c6fdd 100644 --- a/src/hotspot/share/classfile/vmIntrinsics.hpp +++ b/src/hotspot/share/classfile/vmIntrinsics.hpp @@ -419,6 +419,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/gc/g1/g1BarrierSet.cpp b/src/hotspot/share/gc/g1/g1BarrierSet.cpp index 9ffd5ed7846..994bf16c2e3 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 8d009a9e19f..e8eb6e9c9d1 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 5f78a40e36d..d01ceb61567 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 02928425cb6..d6d3ac20678 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/g1CollectionSet.cpp b/src/hotspot/share/gc/g1/g1CollectionSet.cpp index e447356f1df..f1c09642247 100644 --- a/src/hotspot/share/gc/g1/g1CollectionSet.cpp +++ b/src/hotspot/share/gc/g1/g1CollectionSet.cpp @@ -89,7 +89,7 @@ void G1CollectionSet::init_region_lengths(uint eden_cset_region_length, _survivor_region_length = survivor_cset_region_length; assert((size_t) young_region_length() == _collection_set_cur_length, - "Young region length %u should match collection set length " SIZE_FORMAT, young_region_length(), _collection_set_cur_length); + "Young region length %u should match collection set length %u", young_region_length(), _collection_set_cur_length); _old_region_length = 0; free_optional_regions(); @@ -130,8 +130,8 @@ void G1CollectionSet::add_old_region(HeapRegion* hr) { assert(!hr->in_collection_set(), "should not already be in the collection set"); _g1h->register_old_region_with_region_attr(hr); + assert(_collection_set_cur_length < _collection_set_max_length, "Collection set now larger than maximum size."); _collection_set_regions[_collection_set_cur_length++] = hr->hrm_index(); - assert(_collection_set_cur_length <= _collection_set_max_length, "Collection set now larger than maximum size."); _bytes_used_before += hr->used(); _recorded_rs_length += hr->rem_set()->occupied(); @@ -153,7 +153,7 @@ void G1CollectionSet::start_incremental_building() { assert(_collection_set_cur_length == 0, "Collection set must be empty before starting a new collection set."); assert(_inc_build_state == Inactive, "Precondition"); #ifdef ASSERT - for (size_t i = 0; i < _collection_set_max_length; i++) { + for (uint i = 0; i < _collection_set_max_length; i++) { _inc_collection_set_stats[i].reset(); } #endif @@ -326,15 +326,15 @@ void G1CollectionSet::add_young_region_common(HeapRegion* hr) { // We use UINT_MAX as "invalid" marker in verification. assert(_collection_set_cur_length < (UINT_MAX - 1), - "Collection set is too large with " SIZE_FORMAT " entries", _collection_set_cur_length); - hr->set_young_index_in_cset((uint)_collection_set_cur_length + 1); + "Collection set is too large with %u entries", _collection_set_cur_length); + hr->set_young_index_in_cset(_collection_set_cur_length + 1); + assert(_collection_set_cur_length < _collection_set_max_length, "Collection set larger than maximum allowed."); _collection_set_regions[_collection_set_cur_length] = hr->hrm_index(); // Concurrent readers must observe the store of the value in the array before an // update to the length field. OrderAccess::storestore(); _collection_set_cur_length++; - assert(_collection_set_cur_length <= _collection_set_max_length, "Collection set larger than maximum allowed."); } void G1CollectionSet::add_survivor_regions(HeapRegion* hr) { diff --git a/src/hotspot/share/gc/g1/g1CollectionSet.hpp b/src/hotspot/share/gc/g1/g1CollectionSet.hpp index af722761b08..a5c19b98d57 100644 --- a/src/hotspot/share/gc/g1/g1CollectionSet.hpp +++ b/src/hotspot/share/gc/g1/g1CollectionSet.hpp @@ -147,8 +147,8 @@ class G1CollectionSet { // concurrent readers. This means we are good with using storestore and loadload // barriers on the writer and reader respectively only. uint* _collection_set_regions; - volatile size_t _collection_set_cur_length; - size_t _collection_set_max_length; + volatile uint _collection_set_cur_length; + uint _collection_set_max_length; // When doing mixed collections we can add old regions to the collection set, which // will be collected only if there is enough time. We call these optional regions. diff --git a/src/hotspot/share/gc/g1/g1DirtyCardQueue.cpp b/src/hotspot/share/gc/g1/g1DirtyCardQueue.cpp index 0a4a6c40d23..15e5d574951 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 b52c14eb31d..46f3804668e 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 176d7b9f5ce..a2fdbfbf5f7 100644 --- a/src/hotspot/share/gc/g1/g1FullCollector.hpp +++ b/src/hotspot/share/gc/g1/g1FullCollector.hpp @@ -109,7 +109,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 69b48a123fd..5a0863b202a 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 a7aec46d2ee..d0dc0593d3b 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 65fb0624280..ca2f970edde 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 992cbb2321c..3ef6375c3a4 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 cc486aa8e7a..817966a273b 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/g1HeapRegionAttr.hpp b/src/hotspot/share/gc/g1/g1HeapRegionAttr.hpp index 50fc8b8ca97..2d8ae1fae40 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 12f65ef64dd..ddec4f059a7 100644 --- a/src/hotspot/share/gc/g1/g1ParScanThreadState.cpp +++ b/src/hotspot/share/gc/g1/g1ParScanThreadState.cpp @@ -464,11 +464,11 @@ oop G1ParScanThreadState::do_copy_to_survivor_space(G1HeapRegionAttr const regio // We're going to allocate linearly, so might as well prefetch ahead. Prefetch::write(obj_ptr, PrefetchCopyIntervalInBytes); + Copy::aligned_disjoint_words(cast_from_oop(old), obj_ptr, word_sz); const oop obj = cast_to_oop(obj_ptr); const oop forward_ptr = old->forward_to_atomic(obj, old_mark, memory_order_relaxed); if (forward_ptr == NULL) { - Copy::aligned_disjoint_words(cast_from_oop(old), obj_ptr, word_sz); { const uint young_index = from_region->young_index_in_cset(); @@ -480,19 +480,9 @@ oop G1ParScanThreadState::do_copy_to_survivor_space(G1HeapRegionAttr const regio if (dest_attr.is_young()) { if (age < markWord::max_age) { age++; - } - if (old_mark.has_displaced_mark_helper()) { - // In this case, we have to install the old mark word containing the - // displacement tag, and update the age in the displaced mark word. - markWord new_mark = old_mark.displaced_mark_helper().set_age(age); - old_mark.set_displaced_mark_helper(new_mark); - obj->set_mark(old_mark); - } else { - obj->set_mark(old_mark.set_age(age)); + obj->incr_age(); } _age_table.add(age, word_sz); - } else { - obj->set_mark(old_mark); } // Most objects are not arrays, so do one array check rather than @@ -559,10 +549,7 @@ void G1ParScanThreadStateSet::flush() { for (uint worker_id = 0; worker_id < _n_workers; ++worker_id) { G1ParScanThreadState* pss = _states[worker_id]; - - if (pss == NULL) { - continue; - } + assert(pss != nullptr, "must be initialized"); G1GCPhaseTimes* p = _g1h->phase_times(); @@ -585,10 +572,7 @@ void G1ParScanThreadStateSet::flush() { void G1ParScanThreadStateSet::record_unused_optional_region(HeapRegion* hr) { for (uint worker_index = 0; worker_index < _n_workers; ++worker_index) { G1ParScanThreadState* pss = _states[worker_index]; - - if (pss == NULL) { - continue; - } + assert(pss != nullptr, "must be initialized"); size_t used_memory = pss->oops_into_optional_region(hr)->used_memory(); _g1h->phase_times()->record_or_add_thread_work_item(G1GCPhaseTimes::OptScanHR, worker_index, used_memory, G1GCPhaseTimes::ScanHRUsedMemory); diff --git a/src/hotspot/share/gc/g1/g1RemSet.cpp b/src/hotspot/share/gc/g1/g1RemSet.cpp index 6e9508b47ae..467b9d864f8 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 874ccd3c8f5..7bc463650f0 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/g1SharedDirtyCardQueue.cpp b/src/hotspot/share/gc/g1/g1SharedDirtyCardQueue.cpp deleted file mode 100644 index c7ade86926e..00000000000 --- 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/heapRegion.cpp b/src/hotspot/share/gc/g1/heapRegion.cpp index e884afe133b..1b623483113 100644 --- a/src/hotspot/share/gc/g1/heapRegion.cpp +++ b/src/hotspot/share/gc/g1/heapRegion.cpp @@ -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/parallel/parallelScavengeHeap.cpp b/src/hotspot/share/gc/parallel/parallelScavengeHeap.cpp index c3cacaa86d0..567ae94b839 100644 --- a/src/hotspot/share/gc/parallel/parallelScavengeHeap.cpp +++ b/src/hotspot/share/gc/parallel/parallelScavengeHeap.cpp @@ -41,6 +41,7 @@ #include "gc/shared/gcInitLogger.hpp" #include "gc/shared/locationPrinter.inline.hpp" #include "gc/shared/scavengableNMethods.hpp" +#include "gc/shared/suspendibleThreadSet.hpp" #include "logging/log.hpp" #include "memory/iterator.hpp" #include "memory/metaspaceCounters.hpp" @@ -162,6 +163,17 @@ void ParallelScavengeHeap::initialize_serviceability() { } +void ParallelScavengeHeap::safepoint_synchronize_begin() { + if (UseStringDeduplication) { + SuspendibleThreadSet::synchronize(); + } +} + +void ParallelScavengeHeap::safepoint_synchronize_end() { + if (UseStringDeduplication) { + SuspendibleThreadSet::desynchronize(); + } +} class PSIsScavengable : public BoolObjectClosure { bool do_object_b(oop obj) { return ParallelScavengeHeap::heap()->is_in_young(obj); diff --git a/src/hotspot/share/gc/parallel/parallelScavengeHeap.hpp b/src/hotspot/share/gc/parallel/parallelScavengeHeap.hpp index f2eb1e33d96..752218a574b 100644 --- a/src/hotspot/share/gc/parallel/parallelScavengeHeap.hpp +++ b/src/hotspot/share/gc/parallel/parallelScavengeHeap.hpp @@ -139,6 +139,9 @@ class ParallelScavengeHeap : public CollectedHeap { // Returns JNI_OK on success virtual jint initialize(); + virtual void safepoint_synchronize_begin(); + virtual void safepoint_synchronize_end(); + void post_initialize(); void update_counters(); diff --git a/src/hotspot/share/gc/parallel/psCompactionManager.cpp b/src/hotspot/share/gc/parallel/psCompactionManager.cpp index 09a50994d6c..db2e8fbf6d0 100644 --- a/src/hotspot/share/gc/parallel/psCompactionManager.cpp +++ b/src/hotspot/share/gc/parallel/psCompactionManager.cpp @@ -104,6 +104,12 @@ void ParCompactionManager::reset_all_bitmap_query_caches() { } } +void ParCompactionManager::flush_all_string_dedup_requests() { + uint parallel_gc_threads = ParallelScavengeHeap::heap()->workers().total_workers(); + for (uint i=0; i<=parallel_gc_threads; i++) { + _manager_array[i]->flush_string_dedup_requests(); + } +} ParCompactionManager* ParCompactionManager::gc_thread_compaction_manager(uint index) { diff --git a/src/hotspot/share/gc/parallel/psCompactionManager.hpp b/src/hotspot/share/gc/parallel/psCompactionManager.hpp index a73e898f0b5..2e73da920b5 100644 --- a/src/hotspot/share/gc/parallel/psCompactionManager.hpp +++ b/src/hotspot/share/gc/parallel/psCompactionManager.hpp @@ -26,6 +26,7 @@ #define SHARE_GC_PARALLEL_PSCOMPACTIONMANAGER_HPP #include "gc/parallel/psParallelCompact.hpp" +#include "gc/shared/stringdedup/stringDedup.hpp" #include "gc/shared/taskqueue.hpp" #include "gc/shared/taskTerminator.hpp" #include "memory/allocation.hpp" @@ -88,6 +89,8 @@ class ParCompactionManager : public CHeapObj { oop _last_query_obj; size_t _last_query_ret; + StringDedup::Requests _string_dedup_requests; + static PSOldGen* old_gen() { return _old_gen; } static ObjectStartArray* start_array() { return _start_array; } static OopTaskQueueSet* oop_task_queues() { return _oop_task_queues; } @@ -125,6 +128,10 @@ class ParCompactionManager : public CHeapObj { _last_query_ret = 0; } + void flush_string_dedup_requests() { + _string_dedup_requests.flush(); + } + // Bitmap query support, cache last query and result HeapWord* last_query_begin() { return _last_query_beg; } oop last_query_object() { return _last_query_obj; } @@ -136,6 +143,8 @@ class ParCompactionManager : public CHeapObj { static void reset_all_bitmap_query_caches(); + static void flush_all_string_dedup_requests(); + RegionTaskQueue* region_stack() { return &_region_stack; } static ParCompactionManager* get_vmthread_cm() { return _manager_array[ParallelGCThreads]; } diff --git a/src/hotspot/share/gc/parallel/psCompactionManager.inline.hpp b/src/hotspot/share/gc/parallel/psCompactionManager.inline.hpp index e40e3689da2..470c9158899 100644 --- a/src/hotspot/share/gc/parallel/psCompactionManager.inline.hpp +++ b/src/hotspot/share/gc/parallel/psCompactionManager.inline.hpp @@ -31,6 +31,7 @@ #include "classfile/javaClasses.inline.hpp" #include "gc/parallel/parMarkBitMap.hpp" #include "gc/parallel/psParallelCompact.inline.hpp" +#include "gc/parallel/psStringDedup.hpp" #include "gc/shared/taskqueue.inline.hpp" #include "oops/access.inline.hpp" #include "oops/arrayOop.hpp" @@ -108,6 +109,12 @@ inline void ParCompactionManager::mark_and_push(T* p) { if (mark_bitmap()->is_unmarked(obj) && PSParallelCompact::mark_obj(obj)) { push(obj); + + if (StringDedup::is_enabled() && + 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 9024c4eccc4..15bb8f0a567 100644 --- a/src/hotspot/share/gc/parallel/psParallelCompact.cpp +++ b/src/hotspot/share/gc/parallel/psParallelCompact.cpp @@ -40,6 +40,7 @@ #include "gc/parallel/psPromotionManager.inline.hpp" #include "gc/parallel/psRootType.hpp" #include "gc/parallel/psScavenge.hpp" +#include "gc/parallel/psStringDedup.hpp" #include "gc/parallel/psYoungGen.hpp" #include "gc/shared/gcCause.hpp" #include "gc/shared/gcHeapSummary.hpp" @@ -1022,6 +1023,8 @@ void PSParallelCompact::post_compact() _space_info[id].publish_new_top(); } + ParCompactionManager::flush_all_string_dedup_requests(); + MutableSpace* const eden_space = _space_info[eden_space_id].space(); MutableSpace* const from_space = _space_info[from_space_id].space(); MutableSpace* const to_space = _space_info[to_space_id].space(); @@ -1790,7 +1793,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); @@ -2075,7 +2078,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); @@ -2280,7 +2282,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()); @@ -3090,12 +3091,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 c4319a0806c..0b8eb6b0116 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.cpp b/src/hotspot/share/gc/parallel/psPromotionManager.cpp index 47376a9bf83..d7d60524859 100644 --- a/src/hotspot/share/gc/parallel/psPromotionManager.cpp +++ b/src/hotspot/share/gc/parallel/psPromotionManager.cpp @@ -122,6 +122,7 @@ bool PSPromotionManager::post_scavenge(YoungGCTracer& gc_tracer) { promotion_failure_occurred = true; } manager->flush_labs(); + manager->flush_string_dedup_requests(); } if (!promotion_failure_occurred) { // If there was no promotion failure, the preserved mark stacks @@ -352,7 +353,7 @@ oop PSPromotionManager::oop_promotion_failed(oop obj, markWord obj_mark) { // this started. If it is the same (i.e., no forwarding // pointer has been installed), then this thread owns // it. - if (obj->cas_forward_to(obj, obj_mark)) { + if (obj->forward_to_atomic(obj, obj_mark) == NULL) { // We won any races, we "own" this object. assert(obj == obj->forwardee(), "Sanity"); diff --git a/src/hotspot/share/gc/parallel/psPromotionManager.hpp b/src/hotspot/share/gc/parallel/psPromotionManager.hpp index 923dec1ec1c..bd48135f134 100644 --- a/src/hotspot/share/gc/parallel/psPromotionManager.hpp +++ b/src/hotspot/share/gc/parallel/psPromotionManager.hpp @@ -29,6 +29,7 @@ #include "gc/shared/copyFailedInfo.hpp" #include "gc/shared/gcTrace.hpp" #include "gc/shared/preservedMarks.hpp" +#include "gc/shared/stringdedup/stringDedup.hpp" #include "gc/shared/taskqueue.hpp" #include "memory/padded.hpp" #include "utilities/globalDefinitions.hpp" @@ -91,6 +92,8 @@ class PSPromotionManager { PreservedMarks* _preserved_marks; PromotionFailedInfo _promotion_failed_info; + StringDedup::Requests _string_dedup_requests; + // Accessors static PSOldGen* old_gen() { return _old_gen; } static MutableSpace* young_space() { return _young_space; } @@ -145,6 +148,8 @@ class PSPromotionManager { static void restore_preserved_marks(); void flush_labs(); + void flush_string_dedup_requests() { _string_dedup_requests.flush(); } + void drain_stacks(bool totally_drain) { drain_stacks_depth(totally_drain); } diff --git a/src/hotspot/share/gc/parallel/psPromotionManager.inline.hpp b/src/hotspot/share/gc/parallel/psPromotionManager.inline.hpp index 5eb6a20b0b7..29053cd5c35 100644 --- a/src/hotspot/share/gc/parallel/psPromotionManager.inline.hpp +++ b/src/hotspot/share/gc/parallel/psPromotionManager.inline.hpp @@ -32,6 +32,7 @@ #include "gc/parallel/psOldGen.hpp" #include "gc/parallel/psPromotionLAB.inline.hpp" #include "gc/parallel/psScavenge.inline.hpp" +#include "gc/parallel/psStringDedup.hpp" #include "gc/shared/taskqueue.inline.hpp" #include "gc/shared/tlab_globals.hpp" #include "logging/log.hpp" @@ -284,6 +285,12 @@ inline oop PSPromotionManager::copy_unmarked_to_survivor_space(oop o, } else { // we'll just push its contents push_contents(new_obj); + + if (StringDedup::is_enabled() && + java_lang_String::is_instance(new_obj) && + psStringDedup::is_candidate_from_evacuation(new_obj, new_obj_is_tenured)) { + _string_dedup_requests.add(o); + } } return new_obj; } else { diff --git a/src/hotspot/share/gc/parallel/psStringDedup.hpp b/src/hotspot/share/gc/parallel/psStringDedup.hpp new file mode 100644 index 00000000000..d1debbddccc --- /dev/null +++ b/src/hotspot/share/gc/parallel/psStringDedup.hpp @@ -0,0 +1,50 @@ +/* + * 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_PARALLEL_PSSTRINGDEDUP_HPP +#define SHARE_GC_PARALLEL_PSSTRINGDEDUP_HPP + +#include "gc/parallel/psScavenge.hpp" +#include "gc/shared/stringdedup/stringDedup.hpp" +#include "memory/allStatic.hpp" +#include "oops/oopsHierarchy.hpp" + +class psStringDedup : AllStatic { +public: + static bool 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 PSScavenge::is_obj_in_young(java_string) && + StringDedup::is_below_threshold_age(java_string->age()); + } + + static bool is_candidate_from_evacuation(oop obj, + bool obj_is_tenured) { + return obj_is_tenured ? + StringDedup::is_below_threshold_age(obj->age()) : + StringDedup::is_threshold_age(obj->age()); + } +}; +#endif // SHARE_GC_PARALLEL_PSSTRINGDEDUP_HPP diff --git a/src/hotspot/share/gc/serial/defNewGeneration.cpp b/src/hotspot/share/gc/serial/defNewGeneration.cpp index 566b4eb3d6f..63d33a14ac5 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 a1e84b225fb..5ea77852566 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 a380e9709cb..53356516aec 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 @@ -167,8 +169,7 @@ void GenMarkSweep::deallocate_stacks() { GenCollectedHeap* gch = GenCollectedHeap::heap(); gch->release_scratch(); - _preserved_mark_stack.clear(true); - _preserved_oop_stack.clear(true); + _preserved_overflow_stack.clear(true); _marking_stack.clear(); _objarray_stack.clear(true); } diff --git a/src/hotspot/share/gc/serial/markSweep.cpp b/src/hotspot/share/gc/serial/markSweep.cpp index ca8a9fe80a4..8856ce2fee1 100644 --- a/src/hotspot/share/gc/serial/markSweep.cpp +++ b/src/hotspot/share/gc/serial/markSweep.cpp @@ -49,8 +49,7 @@ uint MarkSweep::_total_invocations = 0; Stack MarkSweep::_marking_stack; Stack MarkSweep::_objarray_stack; -Stack MarkSweep::_preserved_oop_stack; -Stack MarkSweep::_preserved_mark_stack; +Stack MarkSweep::_preserved_overflow_stack; size_t MarkSweep::_preserved_count = 0; size_t MarkSweep::_preserved_count_max = 0; PreservedMark* MarkSweep::_preserved_marks = NULL; @@ -58,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; @@ -161,10 +162,9 @@ void MarkSweep::preserve_mark(oop obj, markWord mark) { // sufficient space for the marks we need to preserve but if it isn't we fall // back to using Stacks to keep track of the overflow. if (_preserved_count < _preserved_count_max) { - _preserved_marks[_preserved_count++].init(obj, mark); + _preserved_marks[_preserved_count++] = PreservedMark(obj, mark); } else { - _preserved_mark_stack.push(mark); - _preserved_oop_stack.push(obj); + _preserved_overflow_stack.push(PreservedMark(obj, mark)); } } @@ -176,26 +176,21 @@ void MarkSweep::set_ref_processor(ReferenceProcessor* rp) { AdjustPointerClosure MarkSweep::adjust_pointer_closure; void MarkSweep::adjust_marks() { - assert( _preserved_oop_stack.size() == _preserved_mark_stack.size(), - "inconsistent preserved oop stacks"); - // adjust the oops we saved earlier for (size_t i = 0; i < _preserved_count; i++) { _preserved_marks[i].adjust_pointer(); } // deal with the overflow stack - StackIterator iter(_preserved_oop_stack); + StackIterator iter(_preserved_overflow_stack); while (!iter.is_empty()) { - oop* p = iter.next_addr(); - adjust_pointer(p); + PreservedMark* p = iter.next_addr(); + p->adjust_pointer(); } } void MarkSweep::restore_marks() { - assert(_preserved_oop_stack.size() == _preserved_mark_stack.size(), - "inconsistent preserved oop stacks"); - log_trace(gc)("Restoring " SIZE_FORMAT " marks", _preserved_count + _preserved_oop_stack.size()); + log_trace(gc)("Restoring " SIZE_FORMAT " marks", _preserved_count + _preserved_overflow_stack.size()); // restore the marks we saved earlier for (size_t i = 0; i < _preserved_count; i++) { @@ -203,10 +198,9 @@ void MarkSweep::restore_marks() { } // deal with the overflow - while (!_preserved_oop_stack.is_empty()) { - oop obj = _preserved_oop_stack.pop(); - markWord mark = _preserved_mark_stack.pop(); - obj->set_mark(mark); + while (!_preserved_overflow_stack.is_empty()) { + PreservedMark p = _preserved_overflow_stack.pop(); + p.restore(); } } @@ -222,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 e09d7d06833..f3e818f3e4c 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" @@ -100,8 +101,7 @@ class MarkSweep : AllStatic { static Stack _objarray_stack; // Space for storing/restoring mark word - static Stack _preserved_mark_stack; - static Stack _preserved_oop_stack; + static Stack _preserved_overflow_stack; static size_t _preserved_count; static size_t _preserved_count_max; static PreservedMark* _preserved_marks; @@ -112,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; @@ -199,11 +201,7 @@ class PreservedMark { markWord _mark; public: - void init(oop obj, markWord mark) { - _obj = obj; - _mark = mark; - } - + PreservedMark(oop obj, markWord mark) : _obj(obj), _mark(mark) {} void adjust_pointer(); void restore(); }; diff --git a/src/hotspot/share/gc/serial/markSweep.inline.hpp b/src/hotspot/share/gc/serial/markSweep.inline.hpp index 356c6ba6575..7d1285e797a 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 d9a8812d580..19ca138d8d1 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 91b65b896f8..8e79f21971c 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 00000000000..93910ae65d3 --- /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/g1/g1SharedDirtyCardQueue.hpp b/src/hotspot/share/gc/serial/serialStringDedup.hpp similarity index 51% rename from src/hotspot/share/gc/g1/g1SharedDirtyCardQueue.hpp rename to src/hotspot/share/gc/serial/serialStringDedup.hpp index 2f28e2f6300..9d4548acf36 100644 --- a/src/hotspot/share/gc/g1/g1SharedDirtyCardQueue.hpp +++ b/src/hotspot/share/gc/serial/serialStringDedup.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -19,40 +19,26 @@ * 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_G1SHAREDDIRTYCARDQUEUE_HPP -#define SHARE_GC_G1_G1SHAREDDIRTYCARDQUEUE_HPP - -#include "utilities/globalDefinitions.hpp" - -class G1DirtyCardQueueSet; - -// 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; +#ifndef SHARE_GC_SERIAL_STRINGDEDUP_HPP +#define SHARE_GC_SERIAL_STRINGDEDUP_HPP - NONCOPYABLE(G1SharedDirtyCardQueue); +#include "memory/allStatic.hpp" +#include "oops/oopsHierarchy.hpp" +class SerialStringDedup : AllStatic { public: - G1SharedDirtyCardQueue(G1DirtyCardQueueSet* qset); - ~G1SharedDirtyCardQueue(); // flushes the queue. - // Thread-safe addition to shared logging buffer. - void enqueue(void* card_ptr); + // 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); - // Flush any pending entries to the qset and remove the buffer. - // Not thread-safe. - void flush(); + // Candidate selection policy for young during evacuation. + static inline bool is_candidate_from_evacuation(oop obj, bool obj_is_tenured); - // Discard any pending entries. - // Not thread-safe. - void reset(); }; -#endif // SHARE_GC_G1_G1SHAREDDIRTYCARDQUEUE_HPP +#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 00000000000..ebf29113a0b --- /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/barrierSet.hpp b/src/hotspot/share/gc/shared/barrierSet.hpp index 2cd713c1395..c3fb6d8010c 100644 --- a/src/hotspot/share/gc/shared/barrierSet.hpp +++ b/src/hotspot/share/gc/shared/barrierSet.hpp @@ -319,9 +319,6 @@ class BarrierSet: public CHeapObj { Raw::value_copy(src, dst, md); } - static oop resolve(oop obj) { - return Raw::resolve(obj); - } }; }; diff --git a/src/hotspot/share/gc/shared/preservedMarks.inline.hpp b/src/hotspot/share/gc/shared/preservedMarks.inline.hpp index 44bb26f87e6..e3f9f513573 100644 --- a/src/hotspot/share/gc/shared/preservedMarks.inline.hpp +++ b/src/hotspot/share/gc/shared/preservedMarks.inline.hpp @@ -32,7 +32,7 @@ #include "utilities/stack.inline.hpp" inline bool PreservedMarks::should_preserve_mark(oop obj, markWord m) const { - return obj->mark_must_be_preserved_for_promotion_failure(m); + return obj->mark_must_be_preserved(m); } inline void PreservedMarks::push(oop obj, markWord m) { diff --git a/src/hotspot/share/gc/shared/space.cpp b/src/hotspot/share/gc/shared/space.cpp index 8e95115c2e7..97f3599dd9a 100644 --- a/src/hotspot/share/gc/shared/space.cpp +++ b/src/hotspot/share/gc/shared/space.cpp @@ -393,7 +393,84 @@ HeapWord* CompactibleSpace::forward(oop q, size_t size, #if INCLUDE_SERIALGC void ContiguousSpace::prepare_for_compaction(CompactPoint* cp) { - scan_and_forward(this, cp); + // Compute the new addresses for the live objects and store it in the mark + // Used by universe::mark_sweep_phase2() + + // We're sure to be here before any objects are compacted into this + // space, so this is a good time to initialize this: + set_compaction_top(bottom()); + + if (cp->space == NULL) { + assert(cp->gen != NULL, "need a generation"); + assert(cp->threshold == NULL, "just checking"); + assert(cp->gen->first_compaction_space() == this, "just checking"); + cp->space = cp->gen->first_compaction_space(); + cp->threshold = cp->space->initialize_threshold(); + cp->space->set_compaction_top(cp->space->bottom()); + } + + HeapWord* compact_top = cp->space->compaction_top(); // This is where we are currently compacting to. + + DeadSpacer dead_spacer(this); + + HeapWord* end_of_live = bottom(); // One byte beyond the last byte of the last live object. + HeapWord* first_dead = NULL; // The first dead object. + + const intx interval = PrefetchScanIntervalInBytes; + + HeapWord* cur_obj = bottom(); + HeapWord* scan_limit = top(); + + while (cur_obj < scan_limit) { + if (cast_to_oop(cur_obj)->is_gc_marked()) { + // prefetch beyond cur_obj + Prefetch::write(cur_obj, interval); + size_t size = cast_to_oop(cur_obj)->size(); + compact_top = cp->space->forward(cast_to_oop(cur_obj), size, cp, compact_top); + cur_obj += size; + end_of_live = cur_obj; + } else { + // run over all the contiguous dead objects + HeapWord* end = cur_obj; + do { + // prefetch beyond end + Prefetch::write(end, interval); + end += cast_to_oop(end)->size(); + } while (end < scan_limit && !cast_to_oop(end)->is_gc_marked()); + + // see if we might want to pretend this object is alive so that + // we don't have to compact quite as often. + if (cur_obj == compact_top && dead_spacer.insert_deadspace(cur_obj, end)) { + oop obj = cast_to_oop(cur_obj); + compact_top = cp->space->forward(obj, obj->size(), cp, compact_top); + end_of_live = end; + } else { + // otherwise, it really is a free region. + + // cur_obj is a pointer to a dead object. Use this dead memory to store a pointer to the next live object. + *(HeapWord**)cur_obj = end; + + // see if this is the first dead region. + if (first_dead == NULL) { + first_dead = cur_obj; + } + } + + // move on to the next object + cur_obj = end; + } + } + + assert(cur_obj == scan_limit, "just checking"); + _end_of_live = end_of_live; + if (first_dead != NULL) { + _first_dead = first_dead; + } else { + _first_dead = end_of_live; + } + + // save the compaction_top of the compaction space. + cp->space->set_compaction_top(compact_top); } void CompactibleSpace::adjust_pointers() { @@ -402,11 +479,94 @@ void CompactibleSpace::adjust_pointers() { return; // Nothing to do. } - scan_and_adjust_pointers(this); + // adjust all the interior pointers to point at the new locations of objects + // Used by MarkSweep::mark_sweep_phase3() + + HeapWord* cur_obj = bottom(); + HeapWord* const end_of_live = _end_of_live; // Established by prepare_for_compaction(). + HeapWord* const first_dead = _first_dead; // Established by prepare_for_compaction(). + + assert(first_dead <= end_of_live, "Stands to reason, no?"); + + const intx interval = PrefetchScanIntervalInBytes; + + debug_only(HeapWord* prev_obj = NULL); + while (cur_obj < end_of_live) { + Prefetch::write(cur_obj, interval); + if (cur_obj < first_dead || cast_to_oop(cur_obj)->is_gc_marked()) { + // cur_obj is alive + // point all the oops to the new location + size_t size = MarkSweep::adjust_pointers(cast_to_oop(cur_obj)); + debug_only(prev_obj = cur_obj); + cur_obj += size; + } else { + debug_only(prev_obj = cur_obj); + // cur_obj is not a live object, instead it points at the next live object + cur_obj = *(HeapWord**)cur_obj; + assert(cur_obj > prev_obj, "we should be moving forward through memory, cur_obj: " PTR_FORMAT ", prev_obj: " PTR_FORMAT, p2i(cur_obj), p2i(prev_obj)); + } + } + + assert(cur_obj == end_of_live, "just checking"); } void CompactibleSpace::compact() { - scan_and_compact(this); + // Copy all live objects to their new location + // Used by MarkSweep::mark_sweep_phase4() + + verify_up_to_first_dead(this); + + HeapWord* const start = bottom(); + HeapWord* const end_of_live = _end_of_live; + + assert(_first_dead <= end_of_live, "Invariant. _first_dead: " PTR_FORMAT " <= end_of_live: " PTR_FORMAT, p2i(_first_dead), p2i(end_of_live)); + if (_first_dead == end_of_live && (start == end_of_live || !cast_to_oop(start)->is_gc_marked())) { + // Nothing to compact. The space is either empty or all live object should be left in place. + clear_empty_region(this); + return; + } + + const intx scan_interval = PrefetchScanIntervalInBytes; + const intx copy_interval = PrefetchCopyIntervalInBytes; + + assert(start < end_of_live, "bottom: " PTR_FORMAT " should be < end_of_live: " PTR_FORMAT, p2i(start), p2i(end_of_live)); + HeapWord* cur_obj = start; + if (_first_dead > cur_obj && !cast_to_oop(cur_obj)->is_gc_marked()) { + // All object before _first_dead can be skipped. They should not be moved. + // A pointer to the first live object is stored at the memory location for _first_dead. + cur_obj = *(HeapWord**)(_first_dead); + } + + debug_only(HeapWord* prev_obj = NULL); + while (cur_obj < end_of_live) { + if (!cast_to_oop(cur_obj)->is_gc_marked()) { + debug_only(prev_obj = cur_obj); + // The first word of the dead object contains a pointer to the next live object or end of space. + cur_obj = *(HeapWord**)cur_obj; + assert(cur_obj > prev_obj, "we should be moving forward through memory"); + } else { + // prefetch beyond q + Prefetch::read(cur_obj, scan_interval); + + // size and destination + size_t size = cast_to_oop(cur_obj)->size(); + HeapWord* compaction_top = cast_from_oop(cast_to_oop(cur_obj)->forwardee()); + + // prefetch beyond compaction_top + Prefetch::write(compaction_top, copy_interval); + + // copy object and reinit its mark + assert(cur_obj != compaction_top, "everything in this pass should be moving"); + Copy::aligned_conjoint_words(cur_obj, compaction_top, size); + cast_to_oop(compaction_top)->init_mark(); + assert(cast_to_oop(compaction_top)->klass() != NULL, "should have a class"); + + debug_only(prev_obj = cur_obj); + cur_obj += size; + } + } + + clear_empty_region(this); } #endif // INCLUDE_SERIALGC diff --git a/src/hotspot/share/gc/shared/space.hpp b/src/hotspot/share/gc/shared/space.hpp index f0e4e80bd2e..056347333f6 100644 --- a/src/hotspot/share/gc/shared/space.hpp +++ b/src/hotspot/share/gc/shared/space.hpp @@ -308,49 +308,12 @@ class CompactPoint : public StackObj { // necessarily, a space that is normally contiguous. But, for example, a // free-list-based space whose normal collection is a mark-sweep without // compaction could still support compaction in full GC's. -// -// The compaction operations are implemented by the -// scan_and_{adjust_pointers,compact,forward} function templates. -// The following are, non-virtual, auxiliary functions used by these function templates: -// - scan_limit() -// - scanned_block_is_obj() -// - scanned_block_size() -// - adjust_obj_size() -// - obj_size() -// These functions are to be used exclusively by the scan_and_* function templates, -// and must be defined for all (non-abstract) subclasses of CompactibleSpace. -// -// NOTE: Any subclasses to CompactibleSpace wanting to change/define the behavior -// in any of the auxiliary functions must also override the corresponding -// prepare_for_compaction/adjust_pointers/compact functions using them. -// If not, such changes will not be used or have no effect on the compaction operations. -// -// This translates to the following dependencies: -// Overrides/definitions of -// - scan_limit -// - scanned_block_is_obj -// - scanned_block_size -// require override/definition of prepare_for_compaction(). -// Similar dependencies exist between -// - adjust_obj_size and adjust_pointers() -// - obj_size and compact(). -// -// Additionally, this also means that changes to block_size() or block_is_obj() that -// should be effective during the compaction operations must provide a corresponding -// definition of scanned_block_size/scanned_block_is_obj respectively. class CompactibleSpace: public Space { friend class VMStructs; private: HeapWord* _compaction_top; CompactibleSpace* _next_compaction_space; - // Auxiliary functions for scan_and_{forward,adjust_pointers,compact} support. - inline size_t adjust_obj_size(size_t size) const { - return size; - } - - inline size_t obj_size(const HeapWord* addr) const; - template static inline void verify_up_to_first_dead(SpaceType* space) NOT_DEBUG_RETURN; @@ -451,27 +414,6 @@ class CompactibleSpace: public Space { virtual HeapWord* cross_threshold(HeapWord* start, HeapWord* the_end) { return end(); } - - // Below are template functions for scan_and_* algorithms (avoiding virtual calls). - // The space argument should be a subclass of CompactibleSpace, implementing - // scan_limit(), scanned_block_is_obj(), and scanned_block_size(), - // and possibly also overriding obj_size(), and adjust_obj_size(). - // These functions should avoid virtual calls whenever possible. - -#if INCLUDE_SERIALGC - // Frequently calls adjust_obj_size(). - template - static inline void scan_and_adjust_pointers(SpaceType* space); -#endif - - // Frequently calls obj_size(). - template - static inline void scan_and_compact(SpaceType* space); - - // Frequently calls scanned_block_is_obj() and scanned_block_size(). - // Requires the scan_limit() function. - template - static inline void scan_and_forward(SpaceType* space, CompactPoint* cp); }; class GenSpaceMangler; @@ -480,22 +422,6 @@ class GenSpaceMangler; // faster allocation, and compaction. class ContiguousSpace: public CompactibleSpace { friend class VMStructs; - // Allow scan_and_forward function to call (private) overrides for auxiliary functions on this class - template - friend void CompactibleSpace::scan_and_forward(SpaceType* space, CompactPoint* cp); - - private: - // Auxiliary functions for scan_and_forward support. - // See comments for CompactibleSpace for more information. - inline HeapWord* scan_limit() const { - return top(); - } - - inline bool scanned_block_is_obj(const HeapWord* addr) const { - return true; // Always true, since scan_limit is top - } - - inline size_t scanned_block_size(const HeapWord* addr) const; protected: HeapWord* _top; diff --git a/src/hotspot/share/gc/shared/space.inline.hpp b/src/hotspot/share/gc/shared/space.inline.hpp index ce2423ece3f..953e8aa9a2f 100644 --- a/src/hotspot/share/gc/shared/space.inline.hpp +++ b/src/hotspot/share/gc/shared/space.inline.hpp @@ -76,10 +76,6 @@ OffsetTableContigSpace::block_start_const(const void* p) const { return _offsets.block_start(p); } -size_t CompactibleSpace::obj_size(const HeapWord* addr) const { - return cast_to_oop(addr)->size(); -} - #if INCLUDE_SERIALGC class DeadSpacer : StackObj { @@ -133,122 +129,6 @@ class DeadSpacer : StackObj { }; -template -inline void CompactibleSpace::scan_and_forward(SpaceType* space, CompactPoint* cp) { - // Compute the new addresses for the live objects and store it in the mark - // Used by universe::mark_sweep_phase2() - - // We're sure to be here before any objects are compacted into this - // space, so this is a good time to initialize this: - space->set_compaction_top(space->bottom()); - - if (cp->space == NULL) { - assert(cp->gen != NULL, "need a generation"); - assert(cp->threshold == NULL, "just checking"); - assert(cp->gen->first_compaction_space() == space, "just checking"); - cp->space = cp->gen->first_compaction_space(); - cp->threshold = cp->space->initialize_threshold(); - cp->space->set_compaction_top(cp->space->bottom()); - } - - HeapWord* compact_top = cp->space->compaction_top(); // This is where we are currently compacting to. - - DeadSpacer dead_spacer(space); - - HeapWord* end_of_live = space->bottom(); // One byte beyond the last byte of the last live object. - HeapWord* first_dead = NULL; // The first dead object. - - const intx interval = PrefetchScanIntervalInBytes; - - HeapWord* cur_obj = space->bottom(); - HeapWord* scan_limit = space->scan_limit(); - - while (cur_obj < scan_limit) { - if (space->scanned_block_is_obj(cur_obj) && cast_to_oop(cur_obj)->is_gc_marked()) { - // prefetch beyond cur_obj - Prefetch::write(cur_obj, interval); - size_t size = space->scanned_block_size(cur_obj); - compact_top = cp->space->forward(cast_to_oop(cur_obj), size, cp, compact_top); - cur_obj += size; - end_of_live = cur_obj; - } else { - // run over all the contiguous dead objects - HeapWord* end = cur_obj; - do { - // prefetch beyond end - Prefetch::write(end, interval); - end += space->scanned_block_size(end); - } while (end < scan_limit && (!space->scanned_block_is_obj(end) || !cast_to_oop(end)->is_gc_marked())); - - // see if we might want to pretend this object is alive so that - // we don't have to compact quite as often. - if (cur_obj == compact_top && dead_spacer.insert_deadspace(cur_obj, end)) { - oop obj = cast_to_oop(cur_obj); - compact_top = cp->space->forward(obj, obj->size(), cp, compact_top); - end_of_live = end; - } else { - // otherwise, it really is a free region. - - // cur_obj is a pointer to a dead object. Use this dead memory to store a pointer to the next live object. - *(HeapWord**)cur_obj = end; - - // see if this is the first dead region. - if (first_dead == NULL) { - first_dead = cur_obj; - } - } - - // move on to the next object - cur_obj = end; - } - } - - assert(cur_obj == scan_limit, "just checking"); - space->_end_of_live = end_of_live; - if (first_dead != NULL) { - space->_first_dead = first_dead; - } else { - space->_first_dead = end_of_live; - } - - // save the compaction_top of the compaction space. - cp->space->set_compaction_top(compact_top); -} - -template -inline void CompactibleSpace::scan_and_adjust_pointers(SpaceType* space) { - // adjust all the interior pointers to point at the new locations of objects - // Used by MarkSweep::mark_sweep_phase3() - - HeapWord* cur_obj = space->bottom(); - HeapWord* const end_of_live = space->_end_of_live; // Established by "scan_and_forward". - HeapWord* const first_dead = space->_first_dead; // Established by "scan_and_forward". - - assert(first_dead <= end_of_live, "Stands to reason, no?"); - - const intx interval = PrefetchScanIntervalInBytes; - - debug_only(HeapWord* prev_obj = NULL); - while (cur_obj < end_of_live) { - Prefetch::write(cur_obj, interval); - if (cur_obj < first_dead || cast_to_oop(cur_obj)->is_gc_marked()) { - // cur_obj is alive - // point all the oops to the new location - size_t size = MarkSweep::adjust_pointers(cast_to_oop(cur_obj)); - size = space->adjust_obj_size(size); - debug_only(prev_obj = cur_obj); - cur_obj += size; - } else { - debug_only(prev_obj = cur_obj); - // cur_obj is not a live object, instead it points at the next live object - cur_obj = *(HeapWord**)cur_obj; - assert(cur_obj > prev_obj, "we should be moving forward through memory, cur_obj: " PTR_FORMAT ", prev_obj: " PTR_FORMAT, p2i(cur_obj), p2i(prev_obj)); - } - } - - assert(cur_obj == end_of_live, "just checking"); -} - #ifdef ASSERT template inline void CompactibleSpace::verify_up_to_first_dead(SpaceType* space) { @@ -261,7 +141,7 @@ inline void CompactibleSpace::verify_up_to_first_dead(SpaceType* space) { HeapWord* prev_obj = NULL; while (cur_obj < space->_first_dead) { - size_t size = space->obj_size(cur_obj); + size_t size = cast_to_oop(cur_obj)->size(); assert(!cast_to_oop(cur_obj)->is_gc_marked(), "should be unmarked (special dense prefix handling)"); prev_obj = cur_obj; cur_obj += size; @@ -287,73 +167,8 @@ inline void CompactibleSpace::clear_empty_region(SpaceType* space) { if (ZapUnusedHeapArea) space->mangle_unused_area(); } } - -template -inline void CompactibleSpace::scan_and_compact(SpaceType* space) { - // Copy all live objects to their new location - // Used by MarkSweep::mark_sweep_phase4() - - verify_up_to_first_dead(space); - - HeapWord* const bottom = space->bottom(); - HeapWord* const end_of_live = space->_end_of_live; - - assert(space->_first_dead <= end_of_live, "Invariant. _first_dead: " PTR_FORMAT " <= end_of_live: " PTR_FORMAT, p2i(space->_first_dead), p2i(end_of_live)); - if (space->_first_dead == end_of_live && (bottom == end_of_live || !cast_to_oop(bottom)->is_gc_marked())) { - // Nothing to compact. The space is either empty or all live object should be left in place. - clear_empty_region(space); - return; - } - - const intx scan_interval = PrefetchScanIntervalInBytes; - const intx copy_interval = PrefetchCopyIntervalInBytes; - - assert(bottom < end_of_live, "bottom: " PTR_FORMAT " should be < end_of_live: " PTR_FORMAT, p2i(bottom), p2i(end_of_live)); - HeapWord* cur_obj = bottom; - if (space->_first_dead > cur_obj && !cast_to_oop(cur_obj)->is_gc_marked()) { - // All object before _first_dead can be skipped. They should not be moved. - // A pointer to the first live object is stored at the memory location for _first_dead. - cur_obj = *(HeapWord**)(space->_first_dead); - } - - debug_only(HeapWord* prev_obj = NULL); - while (cur_obj < end_of_live) { - if (!cast_to_oop(cur_obj)->is_gc_marked()) { - debug_only(prev_obj = cur_obj); - // The first word of the dead object contains a pointer to the next live object or end of space. - cur_obj = *(HeapWord**)cur_obj; - assert(cur_obj > prev_obj, "we should be moving forward through memory"); - } else { - // prefetch beyond q - Prefetch::read(cur_obj, scan_interval); - - // size and destination - size_t size = space->obj_size(cur_obj); - HeapWord* compaction_top = cast_from_oop(cast_to_oop(cur_obj)->forwardee()); - - // prefetch beyond compaction_top - Prefetch::write(compaction_top, copy_interval); - - // copy object and reinit its mark - assert(cur_obj != compaction_top, "everything in this pass should be moving"); - Copy::aligned_conjoint_words(cur_obj, compaction_top, size); - cast_to_oop(compaction_top)->init_mark(); - assert(cast_to_oop(compaction_top)->klass() != NULL, "should have a class"); - - debug_only(prev_obj = cur_obj); - cur_obj += size; - } - } - - clear_empty_region(space); -} - #endif // INCLUDE_SERIALGC -size_t ContiguousSpace::scanned_block_size(const HeapWord* addr) const { - return cast_to_oop(addr)->size(); -} - template void ContiguousSpace::oop_since_save_marks_iterate(OopClosureType* blk) { HeapWord* t; diff --git a/src/hotspot/share/gc/shared/stringdedup/stringDedup.hpp b/src/hotspot/share/gc/shared/stringdedup/stringDedup.hpp index 3484fe13e2a..da220b93307 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 30369ecb5e6..a01548a72b0 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) { + } 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/shenandoah/shenandoahStringDedup.inline.hpp b/src/hotspot/share/gc/shenandoah/shenandoahStringDedup.inline.hpp index 57b30358e94..869a17c3d9b 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 72f459b97fc..d73c2832854 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/jvmci/jvmciCompilerToVM.cpp b/src/hotspot/share/jvmci/jvmciCompilerToVM.cpp index 1f9ad5d346f..93b7c0d9bf2 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 1160bcf54ef..0d290f804e2 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/memory/iterator.cpp b/src/hotspot/share/memory/iterator.cpp index f9fbaf51b90..6790289ae54 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 4afe308d2ce..147aa103964 100644 --- a/src/hotspot/share/memory/iterator.hpp +++ b/src/hotspot/share/memory/iterator.hpp @@ -290,9 +290,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 901f48f9aec..2a8382ab811 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", false, Monitor::_safepoint_check_never); MetaspaceArena* arena = NULL; { MutexLocker ml(lock, Mutex::_no_safepoint_check_flag); diff --git a/src/hotspot/share/oops/access.hpp b/src/hotspot/share/oops/access.hpp index c17fc10ddb2..c3c415d84cc 100644 --- a/src/hotspot/share/oops/access.hpp +++ b/src/hotspot/share/oops/access.hpp @@ -58,7 +58,6 @@ // * arraycopy: Copy data from one heap array to another heap array. The ArrayAccess class has convenience functions for this. // * clone: Clone the contents of an object to a newly allocated object. // * value_copy: Copy the contents of a value type from one heap address to another -// * resolve: Resolve a stable to-space invariant oop that is guaranteed not to relocate its payload until a subsequent thread transition. // // == IMPLEMENTATION == // Each access goes through the following steps in a template pipeline. diff --git a/src/hotspot/share/oops/access.inline.hpp b/src/hotspot/share/oops/access.inline.hpp index f3f7e0278bf..cc7188a5b18 100644 --- a/src/hotspot/share/oops/access.inline.hpp +++ b/src/hotspot/share/oops/access.inline.hpp @@ -206,13 +206,6 @@ namespace AccessInternal { } }; - template - struct PostRuntimeDispatch: public AllStatic { - static oop access_barrier(oop obj) { - return GCBarrierType::resolve(obj); - } - }; - // Resolving accessors with barriers from the barrier set happens in two steps. // 1. Expand paths with runtime-decorators, e.g. is UseCompressedOops on or off. // 2. Expand paths for each BarrierSet available in the system. @@ -367,13 +360,6 @@ namespace AccessInternal { _value_copy_func = function; function(src, dst, md); } - - template - oop RuntimeDispatch::resolve_init(oop obj) { - func_t function = BarrierResolver::resolve_barrier(); - _resolve_func = function; - return function(obj); - } } #endif // SHARE_OOPS_ACCESS_INLINE_HPP diff --git a/src/hotspot/share/oops/accessBackend.hpp b/src/hotspot/share/oops/accessBackend.hpp index cf0aa9a891a..4140d45a23f 100644 --- a/src/hotspot/share/oops/accessBackend.hpp +++ b/src/hotspot/share/oops/accessBackend.hpp @@ -72,8 +72,7 @@ namespace AccessInternal { BARRIER_ATOMIC_XCHG_AT, BARRIER_ARRAYCOPY, BARRIER_CLONE, - BARRIER_VALUE_COPY, - BARRIER_RESOLVE + BARRIER_VALUE_COPY }; template @@ -124,7 +123,6 @@ namespace AccessInternal { size_t length); typedef void (*clone_func_t)(oop src, oop dst, size_t size); typedef void (*value_copy_func_t)(void* src, void* dst, InlineKlass* md); - typedef oop (*resolve_func_t)(oop obj); }; template @@ -152,7 +150,6 @@ namespace AccessInternal { ACCESS_GENERATE_ACCESS_FUNCTION(BARRIER_ARRAYCOPY, arraycopy_func_t); ACCESS_GENERATE_ACCESS_FUNCTION(BARRIER_CLONE, clone_func_t); ACCESS_GENERATE_ACCESS_FUNCTION(BARRIER_VALUE_COPY, value_copy_func_t); - ACCESS_GENERATE_ACCESS_FUNCTION(BARRIER_RESOLVE, resolve_func_t); #undef ACCESS_GENERATE_ACCESS_FUNCTION template @@ -402,10 +399,8 @@ class RawAccessBarrier: public AllStatic { size_t length); static void clone(oop src, oop dst, size_t size); - static void value_copy(void* src, void* dst, InlineKlass* md); - static oop resolve(oop obj) { return obj; } }; // Below is the implementation of the first 4 steps of the template pipeline: @@ -599,18 +594,6 @@ namespace AccessInternal { } }; - template - struct RuntimeDispatch: AllStatic { - typedef typename AccessFunction::type func_t; - static func_t _resolve_func; - - static oop resolve_init(oop obj); - - static inline oop resolve(oop obj) { - return _resolve_func(obj); - } - }; - // Initialize the function pointers to point to the resolving function. template typename AccessFunction::type @@ -656,10 +639,6 @@ namespace AccessInternal { typename AccessFunction::type RuntimeDispatch::_value_copy_func = &value_copy_init; - template - typename AccessFunction::type - RuntimeDispatch::_resolve_func = &resolve_init; - // Step 3: Pre-runtime dispatching. // The PreRuntimeDispatch class is responsible for filtering the barrier strength // decorators. That is, for AS_RAW, it hardwires the accesses without a runtime diff --git a/src/hotspot/share/oops/markWord.hpp b/src/hotspot/share/oops/markWord.hpp index 2b5962ee71d..67cdd5d3072 100644 --- a/src/hotspot/share/oops/markWord.hpp +++ b/src/hotspot/share/oops/markWord.hpp @@ -267,12 +267,6 @@ class markWord { return (!is_unlocked() || !has_no_hash() || (EnableValhalla && is_larval_state())); } - // Should this header (including its age bits) be preserved in the - // case of a promotion failure during scavenge? - bool must_be_preserved_for_promotion_failure(const oopDesc* obj) const { - return (!is_unlocked() || !has_no_hash() || (EnableValhalla && is_larval_state())); - } - // WARNING: The following routines are used EXCLUSIVELY by // synchronization functions. They are not really gc safe. // They must get updated if markWord layout get changed. diff --git a/src/hotspot/share/oops/oop.hpp b/src/hotspot/share/oops/oop.hpp index 607890cf1cc..bbfb545881f 100644 --- a/src/hotspot/share/oops/oop.hpp +++ b/src/hotspot/share/oops/oop.hpp @@ -261,7 +261,6 @@ class oopDesc { void verify_forwardee(oop forwardee) NOT_DEBUG_RETURN; inline void forward_to(oop p); - inline bool cas_forward_to(oop p, markWord compare, atomic_memory_order order = memory_order_conservative); // Like "forward_to", but inserts the forwarding pointer atomically. // Exactly one thread succeeds in inserting the forwarding pointer, and @@ -307,7 +306,6 @@ class oopDesc { // Checks if the mark word needs to be preserved inline bool mark_must_be_preserved() const; inline bool mark_must_be_preserved(markWord m) const; - inline bool mark_must_be_preserved_for_promotion_failure(markWord m) const; static bool has_klass_gap(); diff --git a/src/hotspot/share/oops/oop.inline.hpp b/src/hotspot/share/oops/oop.inline.hpp index 1ea10633ac4..d7443a46cf9 100644 --- a/src/hotspot/share/oops/oop.inline.hpp +++ b/src/hotspot/share/oops/oop.inline.hpp @@ -45,13 +45,11 @@ // We need a separate file to avoid circular references markWord oopDesc::mark() const { - uintptr_t v = HeapAccess::load_at(as_oop(), mark_offset_in_bytes()); - return markWord(v); + return Atomic::load(&_mark); } markWord oopDesc::mark_acquire() const { - uintptr_t v = HeapAccess::load_at(as_oop(), mark_offset_in_bytes()); - return markWord(v); + return Atomic::load_acquire(&_mark); } markWord* oopDesc::mark_addr() const { @@ -59,7 +57,7 @@ markWord* oopDesc::mark_addr() const { } void oopDesc::set_mark(markWord m) { - HeapAccess::store_at(as_oop(), mark_offset_in_bytes(), m.value()); + Atomic::store(&_mark, m); } void oopDesc::set_mark(HeapWord* mem, markWord m) { @@ -67,12 +65,11 @@ void oopDesc::set_mark(HeapWord* mem, markWord m) { } void oopDesc::release_set_mark(markWord m) { - HeapAccess::store_at(as_oop(), mark_offset_in_bytes(), m.value()); + Atomic::release_store(&_mark, m); } markWord oopDesc::cas_set_mark(markWord new_mark, markWord old_mark) { - uintptr_t v = HeapAccess<>::atomic_cmpxchg_at(as_oop(), mark_offset_in_bytes(), old_mark.value(), new_mark.value()); - return markWord(v); + return Atomic::cmpxchg(&_mark, old_mark, new_mark); } markWord oopDesc::cas_set_mark(markWord new_mark, markWord old_mark, atomic_memory_order order) { @@ -293,14 +290,6 @@ void oopDesc::forward_to(oop p) { set_mark(m); } -// Used by parallel scavengers -bool oopDesc::cas_forward_to(oop p, markWord compare, atomic_memory_order order) { - verify_forwardee(p); - markWord m = markWord::encode_pointer_as_mark(p); - assert(m.decode_pointer() == p, "encoding must be reversable"); - return cas_set_mark(m, compare, order) == compare; -} - oop oopDesc::forward_to_atomic(oop p, markWord compare, atomic_memory_order order) { verify_forwardee(p); markWord m = markWord::encode_pointer_as_mark(p); @@ -413,8 +402,4 @@ bool oopDesc::mark_must_be_preserved(markWord m) const { return m.must_be_preserved(this); } -bool oopDesc::mark_must_be_preserved_for_promotion_failure(markWord m) const { - return m.must_be_preserved_for_promotion_failure(this); -} - #endif // SHARE_OOPS_OOP_INLINE_HPP diff --git a/src/hotspot/share/opto/c2compiler.cpp b/src/hotspot/share/opto/c2compiler.cpp index 6aa4b2a1899..1aff1906a28 100644 --- a/src/hotspot/share/opto/c2compiler.cpp +++ b/src/hotspot/share/opto/c2compiler.cpp @@ -646,6 +646,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 979610b2a69..29092244c5e 100644 --- a/src/hotspot/share/opto/escape.cpp +++ b/src/hotspot/share/opto/escape.cpp @@ -1118,6 +1118,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 44702f8ed4f..f5e29944fde 100644 --- a/src/hotspot/share/opto/graphKit.cpp +++ b/src/hotspot/share/opto/graphKit.cpp @@ -2645,7 +2645,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 f88d2e3b08f..9e6e902f71c 100644 --- a/src/hotspot/share/opto/lcm.cpp +++ b/src/hotspot/share/opto/lcm.cpp @@ -543,7 +543,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 4990101d9db..3383a435999 100644 --- a/src/hotspot/share/opto/library_call.cpp +++ b/src/hotspot/share/opto/library_call.cpp @@ -555,6 +555,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: @@ -721,6 +724,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 @@ -7056,6 +7061,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 165153a222d..2cfbdc5e158 100644 --- a/src/hotspot/share/opto/library_call.hpp +++ b/src/hotspot/share/opto/library_call.hpp @@ -338,6 +338,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/loopTransform.cpp b/src/hotspot/share/opto/loopTransform.cpp index be406f1f826..3ad5480cd66 100644 --- a/src/hotspot/share/opto/loopTransform.cpp +++ b/src/hotspot/share/opto/loopTransform.cpp @@ -905,7 +905,7 @@ bool IdealLoopTree::policy_unroll(PhaseIdealLoop *phase) { // Progress defined as current size less than 20% larger than previous size. if (UseSuperWord && cl->node_count_before_unroll() > 0 && future_unroll_cnt > LoopUnrollMin && - (future_unroll_cnt - 1) * (100 / LoopPercentProfileLimit) > cl->profile_trip_cnt() && + (future_unroll_cnt - 1) * (100.0 / LoopPercentProfileLimit) > cl->profile_trip_cnt() && 1.2 * cl->node_count_before_unroll() < (double)_body.size()) { return false; } diff --git a/src/hotspot/share/opto/loopopts.cpp b/src/hotspot/share/opto/loopopts.cpp index 8700203c81e..d21942b9740 100644 --- a/src/hotspot/share/opto/loopopts.cpp +++ b/src/hotspot/share/opto/loopopts.cpp @@ -1604,12 +1604,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/memnode.cpp b/src/hotspot/share/opto/memnode.cpp index f13d701698d..0e13dafc5fd 100644 --- a/src/hotspot/share/opto/memnode.cpp +++ b/src/hotspot/share/opto/memnode.cpp @@ -599,7 +599,7 @@ Node* LoadNode::find_previous_arraycopy(PhaseTransform* phase, Node* ld_alloc, N ArrayCopyNode* MemNode::find_array_copy_clone(PhaseTransform* phase, Node* ld_alloc, Node* mem) const { if (mem->is_Proj() && mem->in(0) != NULL && (mem->in(0)->Opcode() == Op_MemBarStoreStore || - mem->in(0)->Opcode() == Op_MemBarCPUOrder)) { + mem->in(0)->Opcode() == Op_MemBarCPUOrder)) { if (ld_alloc != NULL) { // Check if there is an array copy for a clone Node* mb = mem->in(0); @@ -1069,7 +1069,6 @@ Node* MemNode::can_see_stored_value(Node* st, PhaseTransform* phase) const { // This is more general than load from boxing objects. if (skip_through_membars(atp, tp, phase->C->eliminate_boxing())) { uint alias_idx = atp->index(); - bool final = !atp->is_rewritable(); Node* result = NULL; Node* current = st; // Skip through chains of MemBarNodes checking the MergeMems for @@ -1077,17 +1076,19 @@ Node* MemNode::can_see_stored_value(Node* st, PhaseTransform* phase) const { // kind of node is encountered. Loads from final memory can skip // through any kind of MemBar but normal loads shouldn't skip // through MemBarAcquire since the could allow them to move out of - // a synchronized region. + // a synchronized region. It is not safe to step over MemBarCPUOrder, + // because alias info above them may be inaccurate (e.g., due to + // mixed/mismatched unsafe accesses). + bool is_final_mem = !atp->is_rewritable(); while (current->is_Proj()) { int opc = current->in(0)->Opcode(); - if ((final && (opc == Op_MemBarAcquire || - opc == Op_MemBarAcquireLock || - opc == Op_LoadFence)) || + if ((is_final_mem && (opc == Op_MemBarAcquire || + opc == Op_MemBarAcquireLock || + opc == Op_LoadFence)) || opc == Op_MemBarRelease || opc == Op_StoreFence || opc == Op_MemBarReleaseLock || - opc == Op_MemBarStoreStore || - opc == Op_MemBarCPUOrder) { + opc == Op_MemBarStoreStore) { Node* mem = current->in(0)->in(TypeFunc::Memory); if (mem->is_MergeMem()) { MergeMemNode* merge = mem->as_MergeMem(); diff --git a/src/hotspot/share/opto/runtime.cpp b/src/hotspot/share/opto/runtime.cpp index 818833791aa..a41f7123330 100644 --- a/src/hotspot/share/opto/runtime.cpp +++ b/src/hotspot/share/opto/runtime.cpp @@ -961,6 +961,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 abb29070418..4e2e5f58cd3 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 c06b19c97a7..6d3450227d4 100644 --- a/src/hotspot/share/prims/jni.cpp +++ b/src/hotspot/share/prims/jni.cpp @@ -3778,7 +3778,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 @@ -3998,11 +3998,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 5a268f514bd..db845d22140 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/methodHandles.cpp b/src/hotspot/share/prims/methodHandles.cpp index d440e244ece..a0b51e57142 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()); @@ -539,7 +539,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 12379238f71..3457d4202ff 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/globals.hpp b/src/hotspot/share/runtime/globals.hpp index 0086a09b889..ab7852793bd 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") \ diff --git a/src/hotspot/share/runtime/interfaceSupport.inline.hpp b/src/hotspot/share/runtime/interfaceSupport.inline.hpp index 0701881ccb7..2628bfbdea1 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 766f5c6ea4c..dc0d04759b6 100644 --- a/src/hotspot/share/runtime/javaCalls.cpp +++ b/src/hotspot/share/runtime/javaCalls.cpp @@ -55,7 +55,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"); @@ -66,19 +65,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. @@ -105,11 +97,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 f56216a3018..77d9671e285 100644 --- a/src/hotspot/share/runtime/mutex.cpp +++ b/src/hotspot/share/runtime/mutex.cpp @@ -369,18 +369,16 @@ void Mutex::check_rank(Thread* thread) { 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 13bfda92f3e..1c1938df541 100644 --- a/src/hotspot/share/runtime/mutex.hpp +++ b/src/hotspot/share/runtime/mutex.hpp @@ -54,10 +54,6 @@ class Mutex : public CHeapObj { // 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 @@ -65,15 +61,15 @@ class Mutex : public CHeapObj { enum lock_types { event, access = event + 1, - tty = access + 2, + service = access + 3, + tty = service + 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: diff --git a/src/hotspot/share/runtime/mutexLocker.cpp b/src/hotspot/share/runtime/mutexLocker.cpp index 75952da1e86..a6599c99ded 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; @@ -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); @@ -245,10 +242,10 @@ 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(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; } @@ -335,7 +332,7 @@ void mutex_init() { 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); diff --git a/src/hotspot/share/runtime/mutexLocker.hpp b/src/hotspot/share/runtime/mutexLocker.hpp index cec0728e1cb..015a91babd7 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 e73d029a2f8..2342b379b74 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/stubRoutines.cpp b/src/hotspot/share/runtime/stubRoutines.cpp index fecf207d1e3..ed9b418c3fc 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 88c883e3898..676fa971910 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; @@ -413,6 +414,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 96bacaac99c..49a5d1802a7 100644 --- a/src/hotspot/share/runtime/thread.cpp +++ b/src/hotspot/share/runtime/thread.cpp @@ -1017,8 +1017,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 @@ -1228,7 +1228,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. @@ -1645,7 +1647,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 59c6c2ea6a1..766fe24e30f 100644 --- a/src/hotspot/share/runtime/thread.hpp +++ b/src/hotspot/share/runtime/thread.hpp @@ -960,8 +960,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: @@ -972,6 +972,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/vmStructs.cpp b/src/hotspot/share/runtime/vmStructs.cpp index f59ac75322c..44a7aa34f53 100644 --- a/src/hotspot/share/runtime/vmStructs.cpp +++ b/src/hotspot/share/runtime/vmStructs.cpp @@ -542,6 +542,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/java.base/share/classes/com/sun/crypto/provider/GHASH.java b/src/java.base/share/classes/com/sun/crypto/provider/GHASH.java index c0815524dd7..24cddd2b9f6 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 7cad5ec9c82..957823b886e 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/text/DecimalFormat.java b/src/java.base/share/classes/java/text/DecimalFormat.java index 01258bdfa09..29855bcabd1 100644 --- a/src/java.base/share/classes/java/text/DecimalFormat.java +++ b/src/java.base/share/classes/java/text/DecimalFormat.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2020, 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 @@ -3406,16 +3406,14 @@ private void applyPattern(String pattern, boolean localized) { // opening quote or two quotes, which is a quote // literal. That is, we have the first quote in 'do' // or o''clock. - if (ch == QUOTE) { - if ((pos+1) < pattern.length() && - pattern.charAt(pos+1) == QUOTE) { - ++pos; - affix.append("''"); // o''clock - } else { - inQuote = true; // 'do' - } - continue; + if ((pos+1) < pattern.length() && + pattern.charAt(pos+1) == QUOTE) { + ++pos; + affix.append("''"); // o''clock + } else { + inQuote = true; // 'do' } + continue; } else if (ch == separator) { // Don't allow separators before we see digit // characters of phase 1, and don't allow separators diff --git a/src/java.base/share/classes/sun/security/ssl/ClientHello.java b/src/java.base/share/classes/sun/security/ssl/ClientHello.java index d39bb645712..1197802842d 100644 --- a/src/java.base/share/classes/sun/security/ssl/ClientHello.java +++ b/src/java.base/share/classes/sun/security/ssl/ClientHello.java @@ -402,9 +402,6 @@ public byte[] produce(ConnectionContext context) throws IOException { // clean up this producer chc.handshakeProducers.remove(SSLHandshake.CLIENT_HELLO.id); - // the max protocol version this client is supporting. - ProtocolVersion maxProtocolVersion = chc.maximumActiveProtocol; - // session ID of the ClientHello message SessionId sessionId = new SessionId(new byte[0]); @@ -538,14 +535,6 @@ public byte[] produce(ConnectionContext context) throws IOException { if (!session.getProtocolVersion().useTLS13PlusSpec()) { sessionId = session.getSessionId(); } - if (!maxProtocolVersion.equals(sessionVersion)) { - maxProtocolVersion = sessionVersion; - - // Update protocol version number in underlying socket and - // handshake output stream, so that the output records - // (at the record layer) have the correct version - chc.setVersion(sessionVersion); - } // If no new session is allowed, force use of the previous // session ciphersuite, and add the renegotiation SCSV if @@ -580,7 +569,7 @@ public byte[] produce(ConnectionContext context) throws IOException { "no existing session can be resumed"); } - if (maxProtocolVersion.useTLS13PlusSpec() && + if (chc.maximumActiveProtocol.useTLS13PlusSpec() && SSLConfiguration.useCompatibilityMode) { // In compatibility mode, the TLS 1.3 legacy_session_id // field MUST be non-empty, so a client not offering a @@ -623,7 +612,7 @@ public byte[] produce(ConnectionContext context) throws IOException { } // Create the handshake message. - ProtocolVersion clientHelloVersion = maxProtocolVersion; + ProtocolVersion clientHelloVersion = chc.maximumActiveProtocol; if (clientHelloVersion.useTLS13PlusSpec()) { // In (D)TLS 1.3, the client indicates its version preferences // in the "supported_versions" extension and the client_version diff --git a/src/java.base/share/classes/sun/security/ssl/HandshakeContext.java b/src/java.base/share/classes/sun/security/ssl/HandshakeContext.java index 2b267d6fb9f..ef13505dd87 100644 --- a/src/java.base/share/classes/sun/security/ssl/HandshakeContext.java +++ b/src/java.base/share/classes/sun/security/ssl/HandshakeContext.java @@ -534,15 +534,6 @@ boolean isNegotiable(ProtocolVersion protocolVersion) { return activeProtocols.contains(protocolVersion); } - /** - * Set the active protocol version and propagate it to the SSLSocket - * and our handshake streams. Called from ClientHandshaker - * and ServerHandshaker with the negotiated protocol version. - */ - void setVersion(ProtocolVersion protocolVersion) { - this.conContext.protocolVersion = protocolVersion; - } - private static boolean isActivatable(CipherSuite suite, AlgorithmConstraints algorithmConstraints, Map cachedStatus) { diff --git a/src/java.base/share/classes/sun/security/ssl/TransportContext.java b/src/java.base/share/classes/sun/security/ssl/TransportContext.java index 3085467110b..ecffb0a7ffb 100644 --- a/src/java.base/share/classes/sun/security/ssl/TransportContext.java +++ b/src/java.base/share/classes/sun/security/ssl/TransportContext.java @@ -81,7 +81,6 @@ final class TransportContext implements ConnectionContext { boolean needHandshakeFinishedStatus = false; boolean hasDelegatedFinished = false; - // negotiated security parameters SSLSessionImpl conSession; ProtocolVersion protocolVersion; 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 88585a6cbf7..3bfd72668c3 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 1c3fd329c59..ee0f4c87eaf 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/libosxapp/JNIUtilities.m b/src/java.desktop/macosx/native/libosxapp/JNIUtilities.m index 75d17803282..c0bab14c627 100644 --- a/src/java.desktop/macosx/native/libosxapp/JNIUtilities.m +++ b/src/java.desktop/macosx/native/libosxapp/JNIUtilities.m @@ -40,11 +40,18 @@ } jstring NSStringToJavaString(JNIEnv* env, NSString *str) { - if (str == NULL) { return NULL; } - jstring jStr = (*env)->NewStringUTF(env, [str UTF8String]); + jsize len = [str length]; + unichar *buffer = (unichar*)calloc(len, sizeof(unichar)); + if (buffer == NULL) { + return NULL; + } + NSRange crange = NSMakeRange(0, len); + [str getCharacters:buffer range:crange]; + jstring jStr = (*env)->NewString(env, buffer, len); + free(buffer); CHECK_EXCEPTION(); return jStr; } diff --git a/src/java.desktop/share/classes/javax/swing/JInternalFrame.java b/src/java.desktop/share/classes/javax/swing/JInternalFrame.java index fd4182814f7..17b0fecde08 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/native/libfontmanager/freetypeScaler.c b/src/java.desktop/share/native/libfontmanager/freetypeScaler.c index 16dc9cd1e44..d89e837855a 100644 --- a/src/java.desktop/share/native/libfontmanager/freetypeScaler.c +++ b/src/java.desktop/share/native/libfontmanager/freetypeScaler.c @@ -46,6 +46,12 @@ #include "fontscaler.h" +#define CHECK_EXCEPTION(env, describe) \ + if ((*(env))->ExceptionCheck(env)) { \ + if (describe) (*(env))->ExceptionDescribe(env);\ + else (*(env))->ExceptionClear(env); \ + } + #define ftFixed1 (FT_Fixed) (1 << 16) #define FloatToFTFixed(f) (FT_Fixed)((f) * (float)(ftFixed1)) #define FTFixedToFloat(x) ((x) / (float)(ftFixed1)) @@ -97,12 +103,18 @@ void z_error(char *s) {} /**************** Error handling utilities *****************/ static jmethodID invalidateScalerMID; +static jboolean debugFonts; // Stores the value of FontUtilities.debugFonts() JNIEXPORT void JNICALL Java_sun_font_FreetypeFontScaler_initIDs( JNIEnv *env, jobject scaler, jclass FFSClass) { invalidateScalerMID = (*env)->GetMethodID(env, FFSClass, "invalidateScaler", "()V"); + + jboolean ignoreException; + debugFonts = JNU_CallStaticMethodByName(env, &ignoreException, + "sun/font/FontUtilities", + "debugFonts", "()Z").z; } static void freeNativeResources(JNIEnv *env, FTScalerInfo* scalerInfo) { @@ -137,6 +149,9 @@ static void invalidateJavaScaler(JNIEnv *env, FTScalerInfo* scalerInfo) { freeNativeResources(env, scalerInfo); (*env)->CallVoidMethod(env, scaler, invalidateScalerMID); + // NB: Exceptions must not be cleared (and therefore no JNI calls + // performed) after calling this method because it intentionally + // leaves an exception pending. } /******************* I/O handlers ***************************/ @@ -187,6 +202,7 @@ static unsigned long ReadTTFontFileFunc(FT_Stream stream, scalerInfo->font2D, sunFontIDs.ttReadBlockMID, bBuffer, offset, numBytes); + CHECK_EXCEPTION(env, debugFonts); if (bread < 0) { return 0; } else { @@ -206,7 +222,8 @@ static unsigned long ReadTTFontFileFunc(FT_Stream stream, (*env)->CallObjectMethod(env, scalerInfo->font2D, sunFontIDs.ttReadBytesMID, offset, numBytes); - /* If there's an OutofMemoryError then byteArray will be null */ + CHECK_EXCEPTION(env, debugFonts); + /* If there's an OutOfMemoryError then byteArray will be null */ if (byteArray == NULL) { return 0; } else { @@ -239,6 +256,7 @@ static unsigned long ReadTTFontFileFunc(FT_Stream stream, sunFontIDs.ttReadBlockMID, bBuffer, offset, scalerInfo->fontDataLength); + CHECK_EXCEPTION(env, debugFonts); if (bread <= 0) { return 0; } else if ((unsigned long)bread < numBytes) { diff --git a/src/java.desktop/windows/native/libawt/java2d/d3d/D3DRenderQueue.cpp b/src/java.desktop/windows/native/libawt/java2d/d3d/D3DRenderQueue.cpp index d19626bc652..5508409b530 100644 --- a/src/java.desktop/windows/native/libawt/java2d/d3d/D3DRenderQueue.cpp +++ b/src/java.desktop/windows/native/libawt/java2d/d3d/D3DRenderQueue.cpp @@ -866,7 +866,11 @@ void D3DRQ_FlushBuffer(void *pParam) if (!JNU_IsNull(env, pFlush->runnable)) { J2dTraceLn(J2D_TRACE_VERBOSE, " executing runnable"); - JNU_CallMethodByName(env, NULL, pFlush->runnable, "run", "()V"); + jboolean hasException; + JNU_CallMethodByName(env, &hasException, pFlush->runnable, "run", "()V"); + if (hasException) { + J2dTraceLn(J2D_TRACE_ERROR, " exception occurred while executing runnable"); + } } } diff --git a/src/java.desktop/windows/native/libawt/windows/awt_Component.cpp b/src/java.desktop/windows/native/libawt/windows/awt_Component.cpp index 1ed97ba94d2..4868fed9089 100644 --- a/src/java.desktop/windows/native/libawt/windows/awt_Component.cpp +++ b/src/java.desktop/windows/native/libawt/windows/awt_Component.cpp @@ -6569,11 +6569,11 @@ JNIEXPORT void JNICALL Java_java_awt_Component_initIDs(JNIEnv *env, jclass cls) { TRY; - jclass inputEventClazz = env->FindClass("java/awt/event/InputEvent"); - CHECK_NULL(inputEventClazz); - jmethodID getButtonDownMasksID = env->GetStaticMethodID(inputEventClazz, "getButtonDownMasks", "()[I"); - CHECK_NULL(getButtonDownMasksID); - jintArray obj = (jintArray)env->CallStaticObjectMethod(inputEventClazz, getButtonDownMasksID); + jboolean ignoreException; + jintArray obj = (jintArray)JNU_CallStaticMethodByName(env, &ignoreException, + "java/awt/event/InputEvent", + "getButtonDownMasks", "()[I").l; + CHECK_NULL(obj); jint * tmp = env->GetIntArrayElements(obj, JNI_FALSE); CHECK_NULL(tmp); jsize len = env->GetArrayLength(obj); diff --git a/src/java.desktop/windows/native/libawt/windows/awt_DesktopProperties.cpp b/src/java.desktop/windows/native/libawt/windows/awt_DesktopProperties.cpp index 608138fb2eb..e9d4161c89b 100644 --- a/src/java.desktop/windows/native/libawt/windows/awt_DesktopProperties.cpp +++ b/src/java.desktop/windows/native/libawt/windows/awt_DesktopProperties.cpp @@ -752,6 +752,7 @@ void AwtDesktopProperties::SetStringProperty(LPCTSTR propName, LPTSTR value) { key, jValue); GetEnv()->DeleteLocalRef(jValue); GetEnv()->DeleteLocalRef(key); + (void)safe_ExceptionOccurred(GetEnv()); } void AwtDesktopProperties::SetIntegerProperty(LPCTSTR propName, int value) { @@ -764,6 +765,7 @@ void AwtDesktopProperties::SetIntegerProperty(LPCTSTR propName, int value) { AwtDesktopProperties::setIntegerPropertyID, key, (jint)value); GetEnv()->DeleteLocalRef(key); + (void)safe_ExceptionOccurred(GetEnv()); } void AwtDesktopProperties::SetBooleanProperty(LPCTSTR propName, BOOL value) { @@ -775,6 +777,7 @@ void AwtDesktopProperties::SetBooleanProperty(LPCTSTR propName, BOOL value) { AwtDesktopProperties::setBooleanPropertyID, key, value ? JNI_TRUE : JNI_FALSE); GetEnv()->DeleteLocalRef(key); + (void)safe_ExceptionOccurred(GetEnv()); } void AwtDesktopProperties::SetColorProperty(LPCTSTR propName, DWORD value) { @@ -787,6 +790,7 @@ void AwtDesktopProperties::SetColorProperty(LPCTSTR propName, DWORD value) { key, GetRValue(value), GetGValue(value), GetBValue(value)); GetEnv()->DeleteLocalRef(key); + (void)safe_ExceptionOccurred(GetEnv()); } void AwtDesktopProperties::SetFontProperty(HDC dc, int fontID, @@ -849,6 +853,7 @@ void AwtDesktopProperties::SetFontProperty(HDC dc, int fontID, key, fontName, style, pointSize); GetEnv()->DeleteLocalRef(key); GetEnv()->DeleteLocalRef(fontName); + (void)safe_ExceptionOccurred(GetEnv()); } } delete[] face; @@ -896,6 +901,7 @@ void AwtDesktopProperties::SetFontProperty(LPCTSTR propName, const LOGFONT & fon key, fontName, style, pointSize); GetEnv()->DeleteLocalRef(key); GetEnv()->DeleteLocalRef(fontName); + (void)safe_ExceptionOccurred(GetEnv()); } void AwtDesktopProperties::SetSoundProperty(LPCTSTR propName, LPCTSTR winEventName) { @@ -913,6 +919,7 @@ void AwtDesktopProperties::SetSoundProperty(LPCTSTR propName, LPCTSTR winEventNa key, event); GetEnv()->DeleteLocalRef(event); GetEnv()->DeleteLocalRef(key); + (void)safe_ExceptionOccurred(GetEnv()); } void AwtDesktopProperties::PlayWindowsSound(LPCTSTR event) { diff --git a/src/java.net.http/share/classes/jdk/internal/net/http/FilterFactory.java b/src/java.net.http/share/classes/jdk/internal/net/http/FilterFactory.java index 6ad6da6f682..ddc529dc592 100644 --- a/src/java.net.http/share/classes/jdk/internal/net/http/FilterFactory.java +++ b/src/java.net.http/share/classes/jdk/internal/net/http/FilterFactory.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2018, 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 @@ -25,20 +25,20 @@ package jdk.internal.net.http; -import java.util.LinkedList; +import java.util.ArrayList; import java.util.List; class FilterFactory { // Strictly-ordered list of filters. - final LinkedList> filterClasses = new LinkedList<>(); + final List> filterClasses = new ArrayList<>(3); public void addFilter(Class type) { filterClasses.add(type); } - LinkedList getFilterChain() { - LinkedList l = new LinkedList<>(); + List getFilterChain() { + List l = new ArrayList<>(filterClasses.size()); for (Class clazz : filterClasses) { try { // Requires a public no arg constructor. diff --git a/src/java.net.http/share/classes/jdk/internal/net/http/Http2Connection.java b/src/java.net.http/share/classes/jdk/internal/net/http/Http2Connection.java index c505282ebe6..59c88e9f099 100644 --- a/src/java.net.http/share/classes/jdk/internal/net/http/Http2Connection.java +++ b/src/java.net.http/share/classes/jdk/internal/net/http/Http2Connection.java @@ -468,10 +468,11 @@ private static CompletableFuture checkSSLConfig(AbstractAsyncSSLConnection ac CompletableFuture cf = new MinimalFuture<>(); SSLEngine engine = aconn.getEngine(); String engineAlpn = engine.getApplicationProtocol(); - assert Objects.equals(alpn, engineAlpn) - : "alpn: %s, engine: %s".formatted(alpn, engineAlpn); - - DEBUG_LOGGER.log("checkSSLConfig: alpn: %s", alpn ); + DEBUG_LOGGER.log("checkSSLConfig: alpn: '%s', engine: '%s'", alpn, engineAlpn); + if (alpn == null && engineAlpn != null) { + alpn = engineAlpn; + } + DEBUG_LOGGER.log("checkSSLConfig: alpn: '%s'", alpn ); if (alpn == null || !alpn.equals("h2")) { String msg; @@ -494,6 +495,8 @@ private static CompletableFuture checkSSLConfig(AbstractAsyncSSLConnection ac cf.completeExceptionally(new ALPNException(msg, aconn)); return cf; } + assert Objects.equals(alpn, engineAlpn) + : "alpn: %s, engine: %s".formatted(alpn, engineAlpn); cf.complete(null); return cf; }; diff --git a/src/java.net.http/share/classes/jdk/internal/net/http/HttpClientImpl.java b/src/java.net.http/share/classes/jdk/internal/net/http/HttpClientImpl.java index 28c30bbf2c3..ada37a1fbe9 100644 --- a/src/java.net.http/share/classes/jdk/internal/net/http/HttpClientImpl.java +++ b/src/java.net.http/share/classes/jdk/internal/net/http/HttpClientImpl.java @@ -56,14 +56,12 @@ import java.util.ArrayList; import java.util.HashSet; import java.util.Iterator; -import java.util.LinkedList; import java.util.List; import java.util.Objects; import java.util.Optional; import java.util.Set; import java.util.TreeSet; import java.util.concurrent.CompletableFuture; -import java.util.concurrent.CompletionException; import java.util.concurrent.ExecutionException; import java.util.concurrent.Executor; import java.util.concurrent.ExecutorService; @@ -1206,7 +1204,7 @@ private void addFilter(Class f) { filters.addFilter(f); } - final LinkedList filterChain() { + final List filterChain() { return filters.getFilterChain(); } diff --git a/src/java.net.http/share/classes/jdk/internal/net/http/MultiExchange.java b/src/java.net.http/share/classes/jdk/internal/net/http/MultiExchange.java index 1f6054dbe44..9f553606802 100644 --- a/src/java.net.http/share/classes/jdk/internal/net/http/MultiExchange.java +++ b/src/java.net.http/share/classes/jdk/internal/net/http/MultiExchange.java @@ -30,9 +30,9 @@ import java.net.ConnectException; import java.net.http.HttpConnectTimeoutException; import java.time.Duration; -import java.util.Iterator; -import java.util.LinkedList; import java.security.AccessControlContext; +import java.util.List; +import java.util.ListIterator; import java.util.Objects; import java.util.Optional; import java.util.concurrent.CancellationException; @@ -100,7 +100,7 @@ class MultiExchange implements Cancelable { "jdk.httpclient.redirects.retrylimit", DEFAULT_MAX_ATTEMPTS ); - private final LinkedList filters; + private final List filters; ResponseTimerEvent responseTimerEvent; volatile boolean cancelled; AtomicReference interrupted = new AtomicReference<>(); @@ -241,9 +241,9 @@ private void requestFilters(HttpRequestImpl r) throws IOException { private HttpRequestImpl responseFilters(Response response) throws IOException { Log.logTrace("Applying response filters"); - Iterator reverseItr = filters.descendingIterator(); - while (reverseItr.hasNext()) { - HeaderFilter filter = reverseItr.next(); + ListIterator reverseItr = filters.listIterator(filters.size()); + while (reverseItr.hasPrevious()) { + HeaderFilter filter = reverseItr.previous(); Log.logTrace("Applying {0}", filter); HttpRequestImpl newreq = filter.response(response); if (newreq != null) { diff --git a/src/java.security.jgss/share/classes/sun/security/krb5/internal/ktab/KeyTab.java b/src/java.security.jgss/share/classes/sun/security/krb5/internal/ktab/KeyTab.java index 3ffc29ee0f5..4801d099eb8 100644 --- a/src/java.security.jgss/share/classes/sun/security/krb5/internal/ktab/KeyTab.java +++ b/src/java.security.jgss/share/classes/sun/security/krb5/internal/ktab/KeyTab.java @@ -101,9 +101,15 @@ private KeyTab(String filename) { } catch (FileNotFoundException e) { entries.clear(); isMissing = true; + if (DEBUG) { + System.out.println("Cannot load keytab " + tabName + ": " + e); + } } catch (Exception ioe) { entries.clear(); isValid = false; + if (DEBUG) { + System.out.println("Cannot load keytab " + tabName + ": " + ioe); + } } } diff --git a/src/jdk.httpserver/share/classes/com/sun/net/httpserver/HttpExchange.java b/src/jdk.httpserver/share/classes/com/sun/net/httpserver/HttpExchange.java index 1508dcc06fe..5ad7cf5330b 100644 --- a/src/jdk.httpserver/share/classes/com/sun/net/httpserver/HttpExchange.java +++ b/src/jdk.httpserver/share/classes/com/sun/net/httpserver/HttpExchange.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2020, 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 @@ -30,7 +30,6 @@ import java.io.OutputStream; import java.net.InetSocketAddress; import java.net.URI; -import java.util.Map; /** * This class encapsulates a HTTP request received and a @@ -79,51 +78,54 @@ protected HttpExchange() { } /** - * Returns an immutable {@link Map} containing the HTTP headers that were - * included with this request. The keys in this {@code Map} will be the header - * names, while the values will be a {@link java.util.List} of + * Returns an immutable {@link Headers} containing the HTTP headers that + * were included with this request. + * + *

The keys in this {@code Headers} are the header names, while the + * values are a {@link java.util.List} of * {@linkplain java.lang.String Strings} containing each value that was - * included (either for a header that was listed several times, or one that - * accepts a comma-delimited list of values on a single line). In either of - * these cases, the values for the header name will be presented in the - * order that they were included in the request. + * included in the request, in the order they were included. Header fields + * appearing multiple times are represented as multiple string values. * - *

The keys in {@code Map} are case-insensitive. + *

The keys in {@code Headers} are case-insensitive. * - * @return a read-only {@code Map} which can be used to access request headers + * @return a read-only {@code Headers} which can be used to access request + * headers. */ public abstract Headers getRequestHeaders(); /** - * Returns a mutable {@link Map} into which the HTTP response headers can be - * stored and which will be transmitted as part of this response. The keys in - * the {@code Map} will be the header names, while the values must be a - * {@link java.util.List} of {@linkplain java.lang.String Strings} containing - * each value that should be included multiple times (in the order that they - * should be included). + * Returns a mutable {@link Headers} into which the HTTP response headers + * can be stored and which will be transmitted as part of this response. + * + *

The keys in the {@code Headers} are the header names, while the + * values must be a {@link java.util.List} of {@linkplain java.lang.String Strings} + * containing each value that should be included multiple times (in the + * order that they should be included). * - *

The keys in {@code Map} are case-insensitive. + *

The keys in {@code Headers} are case-insensitive. * - * @return a writable {@code Map} which can be used to set response headers. + * @return a writable {@code Headers} which can be used to set response + * headers. */ public abstract Headers getResponseHeaders(); /** - * Get the request {@link URI}. + * Returns the request {@link URI}. * * @return the request {@code URI} */ public abstract URI getRequestURI(); /** - * Get the request method. + * Returns the request method. * * @return the request method */ public abstract String getRequestMethod(); /** - * Get the {@link HttpContext} for this exchange. + * Returns the {@link HttpContext} for this exchange. * * @return the {@code HttpContext} */ diff --git a/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/CompilerToVM.java b/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/CompilerToVM.java index 9b83a08c77c..06fc14d252b 100644 --- a/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/CompilerToVM.java +++ b/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/CompilerToVM.java @@ -948,6 +948,26 @@ HotSpotResolvedObjectTypeImpl getResolvedJavaType(long displacement, boolean com */ native long ticksNow(); + /** + * @see HotSpotJVMCIRuntime#setThreadLocalObject(int, Object) + */ + native void setThreadLocalObject(int id, Object value); + + /** + * @see HotSpotJVMCIRuntime#getThreadLocalObject(int) + */ + native Object getThreadLocalObject(int id); + + /** + * @see HotSpotJVMCIRuntime#setThreadLocalLong(int, long) + */ + native void setThreadLocalLong(int id, long value); + + /** + * @see HotSpotJVMCIRuntime#getThreadLocalLong(int) + */ + native long getThreadLocalLong(int id); + /** * Adds phases in HotSpot JFR. * diff --git a/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotJVMCIRuntime.java b/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotJVMCIRuntime.java index 39cf0b415fa..e6ac574addd 100644 --- a/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotJVMCIRuntime.java +++ b/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotJVMCIRuntime.java @@ -584,6 +584,46 @@ private HotSpotJVMCIRuntime() { } } + /** + * Sets the current thread's {@code JavaThread::_jvmci_reserved_oop} field to {@code value}. + * + * @throws IllegalArgumentException if the {@code JavaThread::_jvmci_reserved_oop} field + * does not exist + */ + public void setThreadLocalObject(int id, Object value) { + compilerToVm.setThreadLocalObject(id, value); + } + + /** + * Get the value of the current thread's {@code JavaThread::_jvmci_reserved_oop} field. + * + * @throws IllegalArgumentException if the {@code JavaThread::_jvmci_reserved_oop} field + * does not exist + */ + public Object getThreadLocalObject(int id) { + return compilerToVm.getThreadLocalObject(id); + } + + /** + * Sets the current thread's {@code JavaThread::_jvmci_reserved} field to {@code value}. + * + * @throws IllegalArgumentException if the {@code JavaThread::_jvmci_reserved} field does + * not exist + */ + public void setThreadLocalLong(int id, long value) { + compilerToVm.setThreadLocalLong(id, value); + } + + /** + * Get the value of the current thread's {@code JavaThread::_jvmci_reserved} field. + * + * @throws IllegalArgumentException if the {@code JavaThread::_jvmci_reserved} field does + * not exist + */ + public long getThreadLocalLong(int id) { + return compilerToVm.getThreadLocalLong(id); + } + HotSpotResolvedJavaType createClass(Class javaClass) { if (javaClass.isPrimitive()) { return HotSpotResolvedPrimitiveType.forKind(JavaKind.fromJavaClass(javaClass)); diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/HtmlDocletWriter.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/HtmlDocletWriter.java index 1e177a5d735..0d6400b871f 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/HtmlDocletWriter.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/HtmlDocletWriter.java @@ -90,10 +90,8 @@ import jdk.javadoc.internal.doclets.formats.html.markup.Script; import jdk.javadoc.internal.doclets.formats.html.markup.TagName; import jdk.javadoc.internal.doclets.formats.html.markup.Text; -import jdk.javadoc.internal.doclets.toolkit.ClassWriter; import jdk.javadoc.internal.doclets.toolkit.Content; import jdk.javadoc.internal.doclets.toolkit.Messages; -import jdk.javadoc.internal.doclets.toolkit.PackageSummaryWriter; import jdk.javadoc.internal.doclets.toolkit.Resources; import jdk.javadoc.internal.doclets.toolkit.taglets.DocRootTaglet; import jdk.javadoc.internal.doclets.toolkit.taglets.Taglet; @@ -1228,10 +1226,10 @@ public void addSummaryDeprecatedComment(Element element, DeprecatedTree tag, Con } /** - * Adds the inline comment. + * Adds the full-body content of the given element. * - * @param element the Element for which the inline comments will be generated - * @param htmltree the documentation tree to which the inline comments will be added + * @param element the element for which the content will be added + * @param htmltree the documentation tree to which the content will be added */ public void addInlineComment(Element element, Content htmltree) { addCommentTags(element, utils.getFullBody(element), false, false, false, htmltree); diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/CommentUtils.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/CommentUtils.java index b03b145a541..51beb6db14f 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/CommentUtils.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/CommentUtils.java @@ -23,14 +23,6 @@ * questions. */ -/** - * A utility class. - * - *

This is NOT part of any supported API. - * If you write code that depends on this, you do so at your own risk. - * This code and its internal interfaces are subject to change or - * deletion without notice. - */ package jdk.javadoc.internal.doclets.toolkit; @@ -57,9 +49,13 @@ import com.sun.source.doctree.DocCommentTree; import com.sun.source.doctree.DocTree; import com.sun.source.doctree.IdentifierTree; +import com.sun.source.doctree.LiteralTree; import com.sun.source.doctree.ParamTree; import com.sun.source.doctree.ReferenceTree; +import com.sun.source.doctree.ReturnTree; +import com.sun.source.doctree.SinceTree; import com.sun.source.doctree.TextTree; +import com.sun.source.doctree.UnknownBlockTagTree; import com.sun.source.util.DocTreeFactory; import com.sun.source.util.DocTreePath; import com.sun.source.util.DocTrees; @@ -67,7 +63,16 @@ import com.sun.tools.javac.util.DefinedBy; import com.sun.tools.javac.util.DefinedBy.Api; import jdk.javadoc.internal.doclets.toolkit.util.Utils; +import jdk.javadoc.internal.doclets.toolkit.util.VisibleMemberTable; +/** + * A utility class for handling documentation comments. + * + *

This is NOT part of any supported API. + * If you write code that depends on this, you do so at your own risk. + * This code and its internal interfaces are subject to change or + * deletion without notice. + */ public class CommentUtils { final BaseConfiguration configuration; @@ -96,31 +101,28 @@ protected CommentUtils(BaseConfiguration configuration) { } public List makePropertyDescriptionTree(List content) { - List out = new ArrayList<>(); Name name = elementUtils.getName("propertyDescription"); - out.add(treeFactory.newUnknownBlockTagTree(name, content)); - return out; + return List.of(treeFactory.newUnknownBlockTagTree(name, content)); } - public List makePropertyDescriptionTree(String content) { - List inlist = new ArrayList<>(); - inlist.add(treeFactory.newCommentTree(content)); - List out = new ArrayList<>(); - Name name = elementUtils.getName("propertyDescription"); - out.add(treeFactory.newUnknownBlockTagTree(name, inlist)); - return out; + public LiteralTree makeCodeTree(String text) { + return treeFactory.newCodeTree(makeTextTree(text)); } public List makeFirstSentenceTree(String content) { - List out = new ArrayList<>(); - out.add(treeFactory.newTextTree(content)); - return out; + return List.of(treeFactory.newTextTree(content)); + } + + public ParamTree makeParamTree(Name name, List description) { + return treeFactory.newParamTree(false, treeFactory.newIdentifierTree(name), description); + } + + public ReturnTree makeReturnTree(List description) { + return treeFactory.newReturnTree(false, description); } public DocTree makeSeeTree(String sig, Element e) { - List list = new ArrayList<>(); - list.add(treeFactory.newReferenceTree(sig)); - return treeFactory.newSeeTree(list); + return treeFactory.newSeeTree(List.of(treeFactory.newReferenceTree(sig))); } public TextTree makeTextTree(String content) { @@ -189,7 +191,6 @@ public void setRecordConstructorTree(ExecutableElement ee) { makeDescriptionWithName("doclet.record_constructor_doc.fullbody", te.getSimpleName()); List tags = new ArrayList<>(); - java.util.List parameters = ee.getParameters(); for (VariableElement param : ee.getParameters()) { Name name = param.getSimpleName(); IdentifierTree id = treeFactory.newIdentifierTree(name); @@ -318,6 +319,107 @@ public void setRecordFieldTree(VariableElement ve) { dcInfoMap.put(ve, new DocCommentInfo(null, docTree)); } + + /** + * Update the property method, property setter and/or property getter + * comment text so that it contains the documentation from + * the preferred property description (field or property method). + * The method adds the leading sentence, copied documentation including + * the defaultValue tag and the {@code @see} tags if the appropriate methods are + * available. + * + * @param member the member which is to be augmented + * @param property the element containing the preferred property description + */ + public void updatePropertyMethodComment(ExecutableElement member, + Element property) { + final String memberName = member.getSimpleName().toString(); + final boolean isSetter = memberName.startsWith("set"); + final boolean isGetter = memberName.startsWith("get") || memberName.startsWith("is"); + + List fullBody = new ArrayList<>(); + List blockTags = new ArrayList<>(); + + if (isGetter || isSetter) { + DocTree propName = makeCodeTree(utils.propertyName(member)); + + if (isGetter) { + // Set the body and @return + fullBody.addAll(getComment("doclet.PropertyGetterWithName", propName)); + blockTags.add(makeReturnTree( + getComment("doclet.PropertyGetterReturn", propName))); + } + + if (isSetter) { + // Set the body and @param + fullBody.addAll(getComment("doclet.PropertySetterWithName", propName)); + VariableElement arg0 = member.getParameters().get(0); + blockTags.add(makeParamTree(arg0.getSimpleName(), + getComment("doclet.PropertySetterParam", propName))); + } + + // Set the @propertyDescription + List propertyTags = utils.getBlockTags(property, + t -> (t instanceof UnknownBlockTagTree tree) + && (tree.getTagName().equals("propertyDescription"))); + if (propertyTags.isEmpty()) { + List comment = utils.getFullBody(property); + blockTags.addAll(makePropertyDescriptionTree(comment)); + } + } else { + // property method + fullBody.addAll(utils.getFullBody(property)); + + // Set the @return + DocTree propName = makeCodeTree(configuration.propertyUtils.getBaseName(member)); + List returnTags = utils.getBlockTags(property, DocTree.Kind.RETURN); + if (returnTags.isEmpty()) { + blockTags.add(makeReturnTree( + getComment("doclet.PropertyMethodReturn", propName))); + } else { + blockTags.addAll(returnTags); + } + } + + // copy certain tags + List sinceTags = utils.getBlockTags(property, DocTree.Kind.SINCE, SinceTree.class); + blockTags.addAll(sinceTags); + + List bTags = utils.getBlockTags(property, + t -> (t instanceof UnknownBlockTagTree tree) + && (tree.getTagName().equals("defaultValue"))); + blockTags.addAll(bTags); + + //add @see tags + TypeElement te = (TypeElement) member.getEnclosingElement(); + VisibleMemberTable vmt = configuration.getVisibleMemberTable(te); + ExecutableElement getter = vmt.getPropertyGetter(member); + ExecutableElement setter = vmt.getPropertySetter(member); + ExecutableElement propMethod = vmt.getPropertyMethod(member); + + if (getter != null && getter != member) { + String sig = "#" + getter.getSimpleName() + "()"; + blockTags.add(makeSeeTree(sig, getter)); + } + + if (setter != null && setter != member) { + VariableElement param = setter.getParameters().get(0); + StringBuilder sb = new StringBuilder("#"); + sb.append(setter.getSimpleName()); + if (!utils.isTypeVariable(param.asType())) { + sb.append("(").append(utils.getTypeSignature(param.asType(), false, true)).append(")"); + } + blockTags.add(makeSeeTree(sb.toString(), setter)); + } + + if (propMethod != member) { + String sig = "#" + propMethod.getSimpleName() + "()"; + blockTags.add(makeSeeTree(sig, propMethod)); + } + + setDocCommentTree(member, fullBody, blockTags); + } + /** * Creates a description that contains a reference to a state component of a record. * The description is looked up as a resource, and should contain {@code {0}} where the @@ -401,6 +503,59 @@ private List makeDescriptionWithName(String key, Name name) { } } + /** + * Returns a list containing the string for a given key in the doclet's resources, + * formatted with given arguments. + * + * @param key the key for the desired string + * @param o0 string or tree argument to be formatted into the result + * @return a content tree for the text + */ + public List getComment(String key, Object o0) { + return getComment(key, o0, null, null); + } + + /** + * Returns a list containing the string for a given key in the doclet's resources, + * formatted with given arguments. + * + * @param key the key for the desired string + * @param o0 string or tree argument to be formatted into the result + * @param o1 string or tree argument to be formatted into the result + * @param o2 string or tree argument to be formatted into the result + * @return a content tree for the text + */ + public List getComment(String key, Object o0, Object o1, Object o2) { + List l = new ArrayList<>(); + Pattern p = Pattern.compile("\\{([012])\\}"); + String text = resources.getText(key); + Matcher m = p.matcher(text); + int start = 0; + while (m.find(start)) { + l.add(makeTextTree(text.substring(start, m.start()))); + + Object o = null; + switch (m.group(1).charAt(0)) { + case '0': o = o0; break; + case '1': o = o1; break; + case '2': o = o2; break; + } + + if (o == null) { + l.add(makeTextTree("{" + m.group(1) + "}")); + } else if (o instanceof String str) { + l.add(makeTextTree(str)); + } else if (o instanceof DocTree t) { + l.add(t); + } + + start = m.end(); + } + + l.add(makeTextTree(text.substring(start))); + return l; + } + /* * Returns the TreePath/DocCommentTree info that has been generated for an element. * @param e the element @@ -453,13 +608,18 @@ public CharSequence getCharContent(boolean ignoreEncoding) { }); } - public void setDocCommentTree(Element element, List fullBody, + public DocCommentInfo setDocCommentTree(Element element, List fullBody, List blockTags) { DocCommentTree docTree = treeFactory.newDocCommentTree(fullBody, blockTags); - dcInfoMap.put(element, new DocCommentInfo(null, docTree)); + return setDocCommentInfo(element, new DocCommentInfo(null, docTree)); + } + + public DocCommentInfo setDocCommentInfo(Element element, DocCommentInfo dci) { + DocCommentInfo prev = dcInfoMap.put(element, dci); // A method having null comment (no comment) that might need to be replaced // with a generated comment, remove such a comment from the cache. utils.removeCommentHelper(element); + return prev; } /** diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/PropertyWriter.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/PropertyWriter.java index 05ae66b0dc4..46875b73e2c 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/PropertyWriter.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/PropertyWriter.java @@ -74,7 +74,7 @@ public interface PropertyWriter extends MemberWriter { * Add the preview output for the given member. * * @param member the member being documented - * @param annotationDocTree content tree to which the preview information will be added + * @param contentTree content tree to which the preview information will be added */ void addPreview(ExecutableElement member, Content contentTree); diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/builders/MemberSummaryBuilder.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/builders/MemberSummaryBuilder.java index 118cc73afb8..219d9247fbc 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/builders/MemberSummaryBuilder.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/builders/MemberSummaryBuilder.java @@ -25,20 +25,26 @@ package jdk.javadoc.internal.doclets.toolkit.builders; -import java.text.MessageFormat; -import java.util.*; - +import java.util.Collection; +import java.util.Comparator; +import java.util.EnumMap; +import java.util.HashMap; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.SortedSet; +import java.util.TreeSet; import javax.lang.model.element.Element; import javax.lang.model.element.ExecutableElement; import javax.lang.model.element.TypeElement; import javax.lang.model.element.VariableElement; import javax.lang.model.util.ElementFilter; +import javax.tools.Diagnostic; import com.sun.source.doctree.DocCommentTree; import com.sun.source.doctree.DocTree; -import com.sun.source.doctree.DocTree.Kind; -import com.sun.source.doctree.SinceTree; -import com.sun.source.doctree.UnknownBlockTagTree; +import jdk.javadoc.internal.doclets.toolkit.BaseConfiguration; import jdk.javadoc.internal.doclets.toolkit.ClassWriter; import jdk.javadoc.internal.doclets.toolkit.Content; import jdk.javadoc.internal.doclets.toolkit.MemberSummaryWriter; @@ -47,7 +53,6 @@ import jdk.javadoc.internal.doclets.toolkit.util.DocFinder; import jdk.javadoc.internal.doclets.toolkit.util.Utils; import jdk.javadoc.internal.doclets.toolkit.util.VisibleMemberTable; -import jdk.javadoc.internal.doclets.toolkit.CommentUtils; import static jdk.javadoc.internal.doclets.toolkit.util.VisibleMemberTable.Kind.*; @@ -258,8 +263,8 @@ private void buildSummary(MemberSummaryWriter writer, if (!members.isEmpty()) { for (Element member : members) { final Element property = pHelper.getPropertyElement(member); - if (property != null) { - processProperty(member, property); + if (property != null && member instanceof ExecutableElement ee) { + configuration.cmtUtils.updatePropertyMethodComment(ee, property); } List firstSentenceTags = utils.getFirstSentenceTrees(member); if (utils.isExecutableElement(member) && firstSentenceTags.isEmpty()) { @@ -279,104 +284,6 @@ private void buildSummary(MemberSummaryWriter writer, } } - /** - * Process the property method, property setter and/or property getter - * comment text so that it contains the documentation from - * the property field. The method adds the leading sentence, - * copied documentation including the defaultValue tag and - * the see tags if the appropriate property getter and setter are - * available. - * - * @param member the member which is to be augmented. - * @param property the original property documentation. - */ - private void processProperty(Element member, - Element property) { - CommentUtils cmtutils = configuration.cmtUtils; - final boolean isSetter = isSetter(member); - final boolean isGetter = isGetter(member); - - List fullBody = new ArrayList<>(); - List blockTags = new ArrayList<>(); - if (isGetter || isSetter) { - //add "[GS]ets the value of the property PROPERTY_NAME." - if (isSetter) { - String text = MessageFormat.format( - resources.getText("doclet.PropertySetterWithName"), - utils.propertyName((ExecutableElement)member)); - fullBody.addAll(cmtutils.makeFirstSentenceTree(text)); - } - if (isGetter) { - String text = MessageFormat.format( - resources.getText("doclet.PropertyGetterWithName"), - utils.propertyName((ExecutableElement) member)); - fullBody.addAll(cmtutils.makeFirstSentenceTree(text)); - } - List propertyTags = utils.getBlockTags(property, - t -> (t instanceof UnknownBlockTagTree tree) - && (tree.getTagName().equals("propertyDescription"))); - if (propertyTags.isEmpty()) { - List comment = utils.getFullBody(property); - blockTags.addAll(cmtutils.makePropertyDescriptionTree(comment)); - } - } else { - fullBody.addAll(utils.getFullBody(property)); - } - - // copy certain tags - List tags = utils.getBlockTags(property, Kind.SINCE, SinceTree.class); - blockTags.addAll(tags); - - List bTags = utils.getBlockTags(property, - t -> (t instanceof UnknownBlockTagTree tree) - && (tree.getTagName().equals("defaultValue"))); - blockTags.addAll(bTags); - - //add @see tags - if (!isGetter && !isSetter) { - ExecutableElement getter = pHelper.getGetterForProperty((ExecutableElement)member); - ExecutableElement setter = pHelper.getSetterForProperty((ExecutableElement)member); - - if (null != getter) { - StringBuilder sb = new StringBuilder("#"); - sb.append(utils.getSimpleName(getter)).append("()"); - blockTags.add(cmtutils.makeSeeTree(sb.toString(), getter)); - } - - if (null != setter) { - VariableElement param = setter.getParameters().get(0); - StringBuilder sb = new StringBuilder("#"); - sb.append(utils.getSimpleName(setter)); - if (!utils.isTypeVariable(param.asType())) { - sb.append("(").append(utils.getTypeSignature(param.asType(), false, true)).append(")"); - } - blockTags.add(cmtutils.makeSeeTree(sb.toString(), setter)); - } - } - cmtutils.setDocCommentTree(member, fullBody, blockTags); - } - - /** - * Test whether the method is a getter. - * @param element property method documentation. Needs to be either property - * method, property getter, or property setter. - * @return true if the given documentation belongs to a getter. - */ - private boolean isGetter(Element element) { - final String pedName = element.getSimpleName().toString(); - return pedName.startsWith("get") || pedName.startsWith("is"); - } - - /** - * Test whether the method is a setter. - * @param element property method documentation. Needs to be either property - * method, property getter, or property setter. - * @return true if the given documentation belongs to a setter. - */ - private boolean isSetter(Element element) { - return element.getSimpleName().toString().startsWith("set"); - } - /** * Build the inherited member summary for the given methods. * @@ -456,6 +363,19 @@ private SortedSet asSortedSet(Collection m return out; } + /** + * A utility class to manage the property-related methods that should be + * synthesized or updated. + * + * A property may comprise a field (that is typically private, if present), + * a {@code fooProperty()} method (which is the defining characteristic for + * a property), a {@code getFoo()} method and/or a {@code setFoo(Foo foo)} method. + * + * Either the field (if present) or the {@code fooProperty()} method should have a + * comment. If there is no field, or no comment on the field, the description for + * the property will be derived from the description of the {@code fooProperty()} + * method. If any method does not have a comment, one will be provided. + */ static class PropertyHelper { private final Map classPropertiesMap = new HashMap<>(); @@ -483,22 +403,28 @@ private void addToPropertiesMap(ExecutableElement propertyMethod, VariableElement field, ExecutableElement getter, ExecutableElement setter) { - if (field == null || !builder.utils.hasDocCommentTree(field)) { - addToPropertiesMap(propertyMethod, propertyMethod); - addToPropertiesMap(getter, propertyMethod); - addToPropertiesMap(setter, propertyMethod); - } else { - addToPropertiesMap(propertyMethod, field); - addToPropertiesMap(getter, field); - addToPropertiesMap(setter, field); + // determine the preferred element from which to derive the property description + Element e = field == null || !builder.utils.hasDocCommentTree(field) + ? propertyMethod : field; + + if (e == field && builder.utils.hasDocCommentTree(propertyMethod)) { + BaseConfiguration configuration = builder.configuration; + configuration.getReporter().print(Diagnostic.Kind.WARNING, + propertyMethod, configuration.getDocResources().getText("doclet.duplicate.comment.for.property")); } + + addToPropertiesMap(propertyMethod, e); + addToPropertiesMap(getter, e); + addToPropertiesMap(setter, e); } private void addToPropertiesMap(Element propertyMethod, Element commentSource) { - if (null == propertyMethod || null == commentSource) { + Objects.requireNonNull(commentSource); + if (propertyMethod == null) { return; } + Utils utils = builder.utils; DocCommentTree docTree = utils.hasDocCommentTree(propertyMethod) ? utils.getDocCommentTree(propertyMethod) @@ -514,30 +440,12 @@ private void addToPropertiesMap(Element propertyMethod, } /** - * Returns the property field documentation belonging to the given member. + * Returns the element for the property documentation belonging to the given member. * @param element the member for which the property documentation is needed. - * @return the property field documentation, null if there is none. + * @return the element for the property documentation, null if there is none. */ public Element getPropertyElement(Element element) { return classPropertiesMap.get(element); } - - /** - * Returns the getter documentation belonging to the given property method. - * @param propertyMethod the method for which the getter is needed. - * @return the getter documentation, null if there is none. - */ - public ExecutableElement getGetterForProperty(ExecutableElement propertyMethod) { - return builder.getVisibleMemberTable().getPropertyGetter(propertyMethod); - } - - /** - * Returns the setter documentation belonging to the given property method. - * @param propertyMethod the method for which the setter is needed. - * @return the setter documentation, null if there is none. - */ - public ExecutableElement getSetterForProperty(ExecutableElement propertyMethod) { - return builder.getVisibleMemberTable().getPropertySetter(propertyMethod); - } } } diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/builders/PropertyBuilder.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/builders/PropertyBuilder.java index 4a31f1d9c00..ebd6d762a25 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/builders/PropertyBuilder.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/builders/PropertyBuilder.java @@ -25,18 +25,23 @@ package jdk.javadoc.internal.doclets.toolkit.builders; -import java.util.*; - +import java.util.ArrayList; +import java.util.List; +import java.util.Objects; +import java.util.stream.Collectors; import javax.lang.model.element.Element; import javax.lang.model.element.ExecutableElement; import javax.lang.model.element.TypeElement; +import com.sun.source.doctree.DocCommentTree; +import com.sun.source.doctree.DocTree; import jdk.javadoc.internal.doclets.toolkit.BaseOptions; +import jdk.javadoc.internal.doclets.toolkit.CommentUtils; import jdk.javadoc.internal.doclets.toolkit.Content; import jdk.javadoc.internal.doclets.toolkit.DocletException; import jdk.javadoc.internal.doclets.toolkit.PropertyWriter; -import static jdk.javadoc.internal.doclets.toolkit.util.VisibleMemberTable.Kind.*; +import static jdk.javadoc.internal.doclets.toolkit.util.VisibleMemberTable.Kind.PROPERTIES; /** * Builds documentation for a property. @@ -179,7 +184,25 @@ protected void buildPropertyComments(Content propertyDocTree) { * @param propertyDocTree the content tree to which the documentation will be added */ protected void buildTagInfo(Content propertyDocTree) { - writer.addTags(currentProperty, propertyDocTree); + CommentUtils cmtUtils = configuration.cmtUtils; + DocCommentTree dct = utils.getDocCommentTree(currentProperty); + var fullBody = dct.getFullBody(); + ArrayList blockTags = dct.getBlockTags().stream() + .filter(t -> t.getKind() != DocTree.Kind.RETURN) + .collect(Collectors.toCollection(ArrayList::new)); + String sig = "#" + currentProperty.getSimpleName() + "()"; + blockTags.add(cmtUtils.makeSeeTree(sig, currentProperty)); + // The property method is used as a proxy for the property + // (which does not have an explicit element of its own.) + // Temporarily override the doc comment for the property method + // by removing the `@return` tag, which should not be displayed for + // the property. + CommentUtils.DocCommentInfo prev = cmtUtils.setDocCommentTree(currentProperty, fullBody, blockTags); + try { + writer.addTags(currentProperty, propertyDocTree); + } finally { + cmtUtils.setDocCommentInfo(currentProperty, prev); + } } /** diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/resources/doclets.properties b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/resources/doclets.properties index 6cff94ffea3..fda35277989 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/resources/doclets.properties +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/resources/doclets.properties @@ -86,7 +86,10 @@ doclet.Author=Author: doclet.DefaultValue=Default value: doclet.PropertyDescription=Property description: doclet.PropertyGetterWithName=Gets the value of the property {0}. +doclet.PropertyGetterReturn=the value of the property {0} doclet.PropertySetterWithName=Sets the value of the property {0}. +doclet.PropertySetterParam=the value for the property {0} +doclet.PropertyMethodReturn=the property {0} doclet.Default=Default: doclet.Parameters=Parameters: doclet.TypeParameters=Type Parameters: @@ -237,6 +240,8 @@ doclet.linkMismatch_PackagedLinkedtoModule=The code being documented uses packag doclet.linkMismatch_ModuleLinkedtoPackage=The code being documented uses modules but the packages defined \ in {0} are in the unnamed module. doclet.urlRedirected=URL {0} was redirected to {1} -- Update the command-line options to suppress this warning. +doclet.duplicate.comment.for.property=Duplicate comment for property.\n\ + Remove the comment on the property field or on this method to suppress this warning. #Documentation for Enums doclet.enum_values_doc.fullbody=\ diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/taglets/ParamTaglet.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/taglets/ParamTaglet.java index 57303ffaa1d..b41260743ee 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/taglets/ParamTaglet.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/taglets/ParamTaglet.java @@ -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 @@ -67,10 +67,9 @@ public ParamTaglet() { } /** - * Given an array of Parameters, return - * a name/rank number map. If the array is null, then - * null is returned. - * @param params The array of parameters (from type or executable member) to + * Given a list of parameters, return a name/rank number map. + * If the list is null, then null is returned. + * @param params The list of parameters (from type or executable member) to * check. * @return a name-rank number map. */ @@ -245,28 +244,24 @@ private Content processParamTags(Element e, ParamKind kind, CommentHelper ch = writer.configuration().utils.getCommentHelper(e); for (ParamTree dt : paramTags) { String name = ch.getParameterName(dt); - String paramName = kind != ParamKind.TYPE_PARAMETER - ? name.toString() - : "<" + name + ">"; + String paramName = kind == ParamKind.TYPE_PARAMETER ? "<" + name + ">" : name; if (!rankMap.containsKey(name)) { - String key; - switch (kind) { - case PARAMETER: key = "doclet.Parameters_warn" ; break; - case TYPE_PARAMETER: key = "doclet.TypeParameters_warn" ; break; - case RECORD_COMPONENT: key = "doclet.RecordComponents_warn" ; break; - default: throw new IllegalArgumentException(kind.toString()); - } + String key = switch (kind) { + case PARAMETER -> "doclet.Parameters_warn"; + case TYPE_PARAMETER -> "doclet.TypeParameters_warn"; + case RECORD_COMPONENT -> "doclet.RecordComponents_warn"; + default -> throw new IllegalArgumentException(kind.toString()); + }; messages.warning(ch.getDocTreePath(dt), key, paramName); } String rank = rankMap.get(name); if (rank != null && alreadyDocumented.contains(rank)) { - String key; - switch (kind) { - case PARAMETER: key = "doclet.Parameters_dup_warn" ; break; - case TYPE_PARAMETER: key = "doclet.TypeParameters_dup_warn" ; break; - case RECORD_COMPONENT: key = "doclet.RecordComponents_dup_warn" ; break; - default: throw new IllegalArgumentException(kind.toString()); - } + String key = switch (kind) { + case PARAMETER -> "doclet.Parameters_dup_warn"; + case TYPE_PARAMETER -> "doclet.TypeParameters_dup_warn"; + case RECORD_COMPONENT -> "doclet.RecordComponents_dup_warn"; + default -> throw new IllegalArgumentException(kind.toString()); + }; messages.warning(ch.getDocTreePath(dt), key, paramName); } result.add(processParamTag(e, kind, writer, dt, diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/util/CommentHelper.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/util/CommentHelper.java index 24014e99494..2f5f77af44b 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/util/CommentHelper.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/util/CommentHelper.java @@ -139,7 +139,7 @@ public boolean isTypeParameter(DocTree dtree) { public String getParameterName(DocTree dtree) { if (dtree.getKind() == PARAM) { - return ((ParamTree) dtree).getName().toString(); + return ((ParamTree) dtree).getName().getName().toString(); } else { return null; } diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/util/VisibleMemberTable.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/util/VisibleMemberTable.java index 5a44bf7a20a..68d2f027113 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/util/VisibleMemberTable.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/util/VisibleMemberTable.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2020, 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 @@ -351,38 +351,57 @@ public boolean hasVisibleMembers(Kind kind) { } /** - * Returns the property field associated with the property method. - * @param propertyMethod the identifying property method + * Returns the field for a property identified by any of the methods + * for that property. + * + * @param ee the method * @return the field or null if absent */ - public VariableElement getPropertyField(ExecutableElement propertyMethod) { + public VariableElement getPropertyField(ExecutableElement ee) { ensureInitialized(); - PropertyMembers pm = propertyMap.get(propertyMethod); + PropertyMembers pm = propertyMap.get(ee); return pm == null ? null : pm.field; } /** - * Returns the getter method associated with the property method. - * @param propertyMethod the identifying property method + * Returns the getter method for a property identified by any of the methods + * for that property. + * + * @param ee the method * @return the getter or null if absent */ - public ExecutableElement getPropertyGetter(ExecutableElement propertyMethod) { + public ExecutableElement getPropertyGetter(ExecutableElement ee) { ensureInitialized(); - PropertyMembers pm = propertyMap.get(propertyMethod); + PropertyMembers pm = propertyMap.get(ee); return pm == null ? null : pm.getter; } /** - * Returns the setter method associated with the property method. - * @param propertyMethod the identifying property method + * Returns the setter method for a property identified by any of the methods + * for that property. + * + * @param ee the method * @return the setter or null if absent */ - public ExecutableElement getPropertySetter(ExecutableElement propertyMethod) { + public ExecutableElement getPropertySetter(ExecutableElement ee) { ensureInitialized(); - PropertyMembers pm = propertyMap.get(propertyMethod); + PropertyMembers pm = propertyMap.get(ee); return pm == null ? null : pm.setter; } + /** + * Returns the property method for a property identified by any of the methods + * for that property. + * + * @param ee the method + * @return the property method or null if absent + */ + public ExecutableElement getPropertyMethod(ExecutableElement ee) { + ensureInitialized(); + PropertyMembers pm = propertyMap.get(ee); + return pm == null ? null : pm.propertyMethod; + } + private void computeParents() { // suppress parents of annotation types if (utils.isAnnotationType(te)) { @@ -817,35 +836,28 @@ List getMembers(Element e, Kind kind) { } List getMembers(String key, Kind kind) { - Map > map = memberMap.get(kind); + Map> map = memberMap.get(kind); return map.getOrDefault(key, Collections.emptyList()); } - List getPropertyMethods(String methodName, int argcount) { + List getMembers(String key, Kind kind, Class clazz) { + Map> map = memberMap.get(kind); + return map.getOrDefault(key, Collections.emptyList()) + .stream() + .map(e -> clazz.cast(e)) + .toList(); + } + + List getPropertyMethods(String methodName, int argcount) { return getMembers(methodName + ":" + argcount, Kind.METHODS).stream() .filter(m -> (utils.isPublic(m) || utils.isProtected(m))) + .map(m -> (ExecutableElement) m) .toList(); } } - /** - * The properties triad for a property method. - */ - static class PropertyMembers { - final VariableElement field; - final ExecutableElement getter; - final ExecutableElement setter; - - PropertyMembers(VariableElement field, ExecutableElement getter, ExecutableElement setter) { - this.field = field; - this.getter = getter; - this.setter = setter; - } - - public String toString() { - return ("field: " + field + ", getter: " + getter + ", setter: " + setter); - } - } + record PropertyMembers(ExecutableElement propertyMethod, VariableElement field, + ExecutableElement getter, ExecutableElement setter) { } /* * JavaFX convention notes. @@ -901,11 +913,11 @@ private void computeVisibleProperties(LocalMemberTable lmt) { // Compute additional properties related sundries. for (ExecutableElement propertyMethod : propertyMethods) { String baseName = pUtils.getBaseName(propertyMethod); - List flist = lmt.getMembers(baseName, Kind.FIELDS); - Element field = flist.isEmpty() ? null : flist.get(0); + List flist = lmt.getMembers(baseName, Kind.FIELDS, VariableElement.class); + VariableElement field = flist.isEmpty() ? null : flist.get(0); - Element getter = null, setter = null; - List found = lmt.getPropertyMethods(pUtils.getGetName(propertyMethod), 0); + ExecutableElement getter = null, setter = null; + List found = lmt.getPropertyMethods(pUtils.getGetName(propertyMethod), 0); if (!found.isEmpty()) { // Getters have zero params, no overloads! pick the first. getter = found.get(0); @@ -914,7 +926,6 @@ private void computeVisibleProperties(LocalMemberTable lmt) { // Check if isProperty methods are present ? found = lmt.getPropertyMethods(pUtils.getIsName(propertyMethod), 0); if (!found.isEmpty()) { - String propertyTypeName = propertyMethod.getReturnType().toString(); // Check if the return type of property method matches an isProperty method. if (pUtils.hasIsMethod(propertyMethod)) { // Getters have zero params, no overloads!, pick the first. @@ -924,16 +935,22 @@ private void computeVisibleProperties(LocalMemberTable lmt) { } found = lmt.getPropertyMethods(pUtils.getSetName(propertyMethod), 1); if (found != null) { - for (Element e : found) { - if (pUtils.isValidSetterMethod((ExecutableElement)e)) { + for (ExecutableElement e : found) { + if (pUtils.isValidSetterMethod(e)) { setter = e; break; } } } - propertyMap.put(propertyMethod, new PropertyMembers((VariableElement)field, - (ExecutableElement)getter, (ExecutableElement)setter)); + PropertyMembers pm = new PropertyMembers(propertyMethod, field, getter, setter); + propertyMap.put(propertyMethod, pm); + if (getter != null) { + propertyMap.put(getter, pm); + } + if (setter != null) { + propertyMap.put(setter, pm); + } // Debugging purposes // System.out.println("te: " + te + ": " + utils.getEnclosingTypeElement(propertyMethod) + diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclint/Checker.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclint/Checker.java index 1a3d3cd1ced..4be169aef7c 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclint/Checker.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclint/Checker.java @@ -45,9 +45,12 @@ import javax.lang.model.element.ElementKind; import javax.lang.model.element.ExecutableElement; import javax.lang.model.element.Name; +import javax.lang.model.element.NestingKind; +import javax.lang.model.element.TypeElement; import javax.lang.model.element.VariableElement; import javax.lang.model.type.TypeKind; import javax.lang.model.type.TypeMirror; +import javax.lang.model.util.Elements; import javax.tools.Diagnostic.Kind; import javax.tools.JavaFileObject; @@ -188,7 +191,7 @@ public Void scan(DocCommentTree tree, TreePath p) { if (isNormalClass(p.getParentPath())) { reportMissing("dc.default.constructor"); } - } else if (!isOverridingMethod) { + } else if (!isOverridingMethod && !isSynthetic() && !isAnonymous()) { reportMissing("dc.missing.comment"); } return null; @@ -1158,6 +1161,15 @@ private boolean isCheckedException(TypeMirror t) { || env.types.isAssignable(t, env.java_lang_RuntimeException)); } + private boolean isSynthetic() { + return env.elements.getOrigin(env.currElement) == Elements.Origin.SYNTHETIC; + } + + private boolean isAnonymous() { + return (env.currElement instanceof TypeElement te) + && te.getNestingKind() == NestingKind.ANONYMOUS; + } + private boolean isDefaultConstructor() { switch (env.currElement.getKind()) { case CONSTRUCTOR: diff --git a/src/jdk.jfr/share/classes/jdk/jfr/internal/EventHandlerCreator.java b/src/jdk.jfr/share/classes/jdk/jfr/internal/EventHandlerCreator.java index 1642360b977..166d44e5a19 100644 --- a/src/jdk.jfr/share/classes/jdk/jfr/internal/EventHandlerCreator.java +++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/EventHandlerCreator.java @@ -121,7 +121,7 @@ private static List createFieldInfos(Class args; private final Set modules; + private final Platform platform; - DefaultExecutableImage(Path home, Set modules) { + DefaultExecutableImage(Path home, Set modules, Platform p) { Objects.requireNonNull(home); if (!Files.exists(home)) { throw new IllegalArgumentException("Invalid image home"); @@ -95,6 +96,7 @@ static final class DefaultExecutableImage implements ExecutableImage { this.home = home; this.modules = Collections.unmodifiableSet(modules); this.args = createArgs(home); + this.platform = p; } private static List createArgs(Path home) { @@ -127,13 +129,18 @@ public void storeLaunchArgs(List args) { throw new UncheckedIOException(ex); } } + + @Override + public Platform getTargetPlatform() { + return platform; + } } private final Path root; private final Map launchers; private final Path mdir; private final Set modules = new HashSet<>(); - private Platform targetPlatform; + private Platform platform; /** * Default image builder constructor. @@ -148,6 +155,11 @@ public DefaultImageBuilder(Path root, Map launchers) throws IOEx Files.createDirectories(mdir); } + @Override + public Platform getTargetPlatform() { + return platform; + } + @Override public void storeFiles(ResourcePool files) { try { @@ -158,7 +170,7 @@ public void storeFiles(ResourcePool files) { if (value == null) { throw new PluginException("ModuleTarget attribute is missing for java.base module"); } - this.targetPlatform = Platform.toPlatform(value); + this.platform = Platform.parsePlatform(value); checkResourcePool(files); @@ -474,7 +486,7 @@ private String nativeDir(String filename) { } private boolean isWindows() { - return targetPlatform == Platform.WINDOWS; + return platform.os() == Platform.OperatingSystem.WINDOWS; } /** @@ -509,7 +521,7 @@ private void setReadOnly(Path file) { @Override public ExecutableImage getExecutableImage() { - return new DefaultExecutableImage(root, modules); + return new DefaultExecutableImage(root, modules, platform); } // This is experimental, we should get rid-off the scripts in a near future @@ -551,7 +563,10 @@ public static ExecutableImage getExecutableImage(Path root) { Path binDir = root.resolve(BIN_DIRNAME); if (Files.exists(binDir.resolve("java")) || Files.exists(binDir.resolve("java.exe"))) { - return new DefaultExecutableImage(root, retrieveModules(root)); + // It may be possible to extract the platform info from the given image. + // --post-process-path is a hidden option and pass unknown platform for now. + // --generate-cds-archive plugin cannot be used with --post-process-path option. + return new DefaultExecutableImage(root, retrieveModules(root), Platform.UNKNOWN); } return null; } diff --git a/src/jdk.jlink/share/classes/jdk/tools/jlink/builder/ImageBuilder.java b/src/jdk.jlink/share/classes/jdk/tools/jlink/builder/ImageBuilder.java index 9ebc6211fc3..32440d5ba7f 100644 --- a/src/jdk.jlink/share/classes/jdk/tools/jlink/builder/ImageBuilder.java +++ b/src/jdk.jlink/share/classes/jdk/tools/jlink/builder/ImageBuilder.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 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,6 +28,7 @@ import java.util.Properties; import jdk.tools.jlink.internal.ExecutableImage; +import jdk.tools.jlink.internal.Platform; import jdk.tools.jlink.plugin.PluginException; import jdk.tools.jlink.plugin.ResourcePool; @@ -74,4 +75,13 @@ public default void storeFiles(ResourcePool content) { * @throws PluginException */ public ExecutableImage getExecutableImage(); + + /** + * Gets the platform of the image. + * + * @return {@code Platform} object representing the platform of the image + */ + public default Platform getTargetPlatform() { + return Platform.UNKNOWN; + } } diff --git a/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/ExecutableImage.java b/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/ExecutableImage.java index 1e788e0ce1d..6169cb8e44a 100644 --- a/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/ExecutableImage.java +++ b/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/ExecutableImage.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 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 @@ -61,4 +61,11 @@ public interface ExecutableImage { * @param args Additional arguments */ public void storeLaunchArgs(List args); + + /** + * The Platform of the image. + * + * @return Platform + */ + public Platform getTargetPlatform(); } diff --git a/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/Platform.java b/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/Platform.java index c3ea6fb1647..a08678455c6 100644 --- a/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/Platform.java +++ b/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/Platform.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 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 @@ -24,48 +24,112 @@ */ package jdk.tools.jlink.internal; -import jdk.tools.jlink.plugin.ResourcePoolModule; - import java.util.Locale; /** * Supported platforms */ -public enum Platform { - WINDOWS, - LINUX, - MACOS, - AIX, - UNKNOWN; +public record Platform(OperatingSystem os, Architecture arch) { - /** - * Returns the {@code Platform} derived from the target platform - * in the {@code ModuleTarget} attribute. + public enum OperatingSystem { + WINDOWS, + LINUX, + MACOS, + AIX, + UNKNOWN; + } + + public enum Architecture { + X86, + x64, + ARM, + AARCH64, + UNKNOWN; + } + + public static final Platform UNKNOWN = new Platform(OperatingSystem.UNKNOWN, Architecture.UNKNOWN); + + /* + * Returns the {@code Platform} based on the platformString of the form -. */ - public static Platform toPlatform(String targetPlatform) { + public static Platform parsePlatform(String platformString) { String osName; - int index = targetPlatform.indexOf("-"); + String archName; + int index = platformString.indexOf("-"); if (index < 0) { - osName = targetPlatform; + osName = platformString; + archName = "UNKNOWN"; } else { - osName = targetPlatform.substring(0, index); + osName = platformString.substring(0, index); + archName = platformString.substring(index + 1); } + OperatingSystem os; try { - return Platform.valueOf(osName.toUpperCase(Locale.ENGLISH)); + os = OperatingSystem.valueOf(osName.toUpperCase(Locale.ENGLISH)); } catch (IllegalArgumentException e) { - return Platform.UNKNOWN; + os = OperatingSystem.UNKNOWN; } + Architecture arch = toArch(archName); + return new Platform(os, arch); } /** - * Returns the {@code Platform} to which the given module is target to. + * @return true is it's a 64-bit platform */ - public static Platform getTargetPlatform(ResourcePoolModule module) { - String targetPlatform = module.targetPlatform(); - if (targetPlatform != null) { - return toPlatform(targetPlatform); - } else { - return Platform.UNKNOWN; - } + public boolean is64Bit() { + return (arch() == Platform.Architecture.x64 || + arch() == Platform.Architecture.AARCH64); + } + + /** + * Returns the runtime {@code Platform}. + */ + public static Platform runtime() { + return new Platform(runtimeOS(), runtimeArch()); + } + + /** + * Returns a {@code String} representation of a {@code Platform} in the format of - + */ + @Override + public String toString() { + return os.toString().toLowerCase() + "-" + arch.toString().toLowerCase(); + } + + /** + * Returns the runtime {@code Platform.OperatingSystem}. + */ + private static OperatingSystem runtimeOS() { + String osName = System.getProperty("os.name").substring(0, 3).toLowerCase(); + OperatingSystem os = switch (osName) { + case "win" -> OperatingSystem.WINDOWS; + case "lin" -> OperatingSystem.LINUX; + case "mac" -> OperatingSystem.MACOS; + case "aix" -> OperatingSystem.AIX; + default -> OperatingSystem.UNKNOWN; + }; + return os; + } + + /** + * Returns the runtime {@code Platform.Architechrure}. + */ + private static Architecture runtimeArch() { + String archName = System.getProperty("os.arch"); + return toArch(archName); + } + + /** + * Returns the {@code Platform.Architecture} based on the archName. + */ + private static Architecture toArch(String archName) { + Architecture arch = switch (archName) { + case "x86" -> Architecture.X86; + case "amd64", "x86_64" -> Architecture.x64; + case "arm" -> Architecture.ARM; + case "aarch64" -> Architecture.AARCH64; + default -> Architecture.UNKNOWN; + }; + return arch; } } diff --git a/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/plugins/CDSPlugin.java b/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/plugins/CDSPlugin.java new file mode 100644 index 00000000000..a1bee72c255 --- /dev/null +++ b/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/plugins/CDSPlugin.java @@ -0,0 +1,123 @@ +/* + * 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. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.tools.jlink.internal.plugins; + +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.*; + +import jdk.tools.jlink.internal.ExecutableImage; +import jdk.tools.jlink.internal.Platform; +import jdk.tools.jlink.internal.PostProcessor; +import jdk.tools.jlink.plugin.PluginException; +import jdk.tools.jlink.plugin.ResourcePool; +import jdk.tools.jlink.plugin.ResourcePoolBuilder; + +/** + * + * CDS plugin + */ +public final class CDSPlugin extends AbstractPlugin implements PostProcessor { + private static final String NAME = "generate-cds-archive"; + private Platform targetPlatform; + private Platform runtimePlatform; + + public CDSPlugin() { + super(NAME); + } + + + private String javaExecutableName() { + if (targetPlatform.os() == Platform.OperatingSystem.WINDOWS) { + return "java.exe"; + } else { + return "java"; + } + } + + private void generateCDSArchive(ExecutableImage image, boolean noCoops) { + List javaCmd = new ArrayList(); + Path javaPath = image.getHome().resolve("bin").resolve(javaExecutableName()); + if (!Files.exists(javaPath)) { + throw new PluginException("Cannot find java executable at: " + javaPath.toString()); + } + javaCmd.add(javaPath.toString()); + javaCmd.add("-Xshare:dump"); + String archiveMsg = "CDS"; + if (noCoops) { + javaCmd.add("-XX:-UseCompressedOops"); + archiveMsg += "-NOCOOPS"; + } + ProcessBuilder builder = new ProcessBuilder(javaCmd); + int status = -1; + try { + Process p = builder.inheritIO().start(); + status = p.waitFor(); + } catch (InterruptedException | IOException e) { + throw new PluginException(e); + } + + if (status != 0) { + throw new PluginException("Failed creating " + archiveMsg + " archive!"); + } + } + + @Override + public List process(ExecutableImage image) { + targetPlatform = image.getTargetPlatform(); + runtimePlatform = Platform.runtime(); + + if (!targetPlatform.equals(runtimePlatform)) { + throw new PluginException("Cannot generate CDS archives: target image platform " + + targetPlatform.toString() + " is different from runtime platform " + + runtimePlatform.toString()); + } + + Path classListPath = image.getHome().resolve("lib").resolve("classlist"); + if (Files.exists(classListPath)) { + generateCDSArchive(image,false); + + if (targetPlatform.is64Bit()) { + generateCDSArchive(image,true); + } + System.out.println("Created CDS archive successfully"); + } else { + throw new PluginException("Cannot generate CDS archives: classlist not found: " + + classListPath.toString()); + } + return null; + } + + @Override + public Category getType() { + return Category.PROCESSOR; + } + + @Override + public ResourcePool transform(ResourcePool in, ResourcePoolBuilder out) { + return in; + } +} diff --git a/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/plugins/ExcludeVMPlugin.java b/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/plugins/ExcludeVMPlugin.java index cdd0167eb6e..a9cc357787a 100644 --- a/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/plugins/ExcludeVMPlugin.java +++ b/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/plugins/ExcludeVMPlugin.java @@ -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 @@ -245,8 +245,9 @@ private ResourcePoolEntry handleJvmCfgFile(ResourcePoolEntry orig, } private static String[] jvmlibs(ResourcePoolModule module) { - Platform platform = Platform.getTargetPlatform(module); - switch (platform) { + String targetPlatform = module.targetPlatform(); + Platform platform = Platform.parsePlatform(targetPlatform); + switch (platform.os()) { case WINDOWS: return new String[] { "jvm.dll" }; case MACOS: diff --git a/src/jdk.jlink/share/classes/jdk/tools/jlink/resources/plugins.properties b/src/jdk.jlink/share/classes/jdk/tools/jlink/resources/plugins.properties index d49dd1d38bd..958c43c2ca4 100644 --- a/src/jdk.jlink/share/classes/jdk/tools/jlink/resources/plugins.properties +++ b/src/jdk.jlink/share/classes/jdk/tools/jlink/resources/plugins.properties @@ -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 @@ -137,6 +137,13 @@ exclude-jmod-section.usage=\ \ Specify a JMOD section to exclude.\n\ \ Where is \"man\" or \"headers\". + +generate-cds-archive.description=\ +CDS plugin: generate cds archives if the runtime image supports CDS feature.\n\ + +generate-cds-archive.usage=\ +\ --generate-cds-archive Generate CDS archives if the runtime image supports CDS feature. + generate-jli-classes.argument=@filename generate-jli-classes.description=\ diff --git a/src/jdk.jlink/share/classes/module-info.java b/src/jdk.jlink/share/classes/module-info.java index 3d097772e77..d2db4c5f9e4 100644 --- a/src/jdk.jlink/share/classes/module-info.java +++ b/src/jdk.jlink/share/classes/module-info.java @@ -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 @@ -76,6 +76,7 @@ jdk.tools.jlink.internal.plugins.AddOptionsPlugin, jdk.tools.jlink.internal.plugins.VendorBugURLPlugin, jdk.tools.jlink.internal.plugins.VendorVMBugURLPlugin, - jdk.tools.jlink.internal.plugins.VendorVersionPlugin; + jdk.tools.jlink.internal.plugins.VendorVersionPlugin, + jdk.tools.jlink.internal.plugins.CDSPlugin; } diff --git a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacBaseInstallerBundler.java b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacBaseInstallerBundler.java index 28eee6bdc4e..77677369a17 100644 --- a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacBaseInstallerBundler.java +++ b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacBaseInstallerBundler.java @@ -139,7 +139,7 @@ protected void validateAppImageAndBundeler( if (Optional.ofNullable( SIGN_BUNDLE.fetchFrom(params)).orElse(Boolean.FALSE)) { // if signing bundle with app-image, warn user if app-image - // is not allready signed. + // is not already signed. try { if (!(AppImageFile.load(applicationImage).isSigned())) { Log.info(MessageFormat.format(I18N.getString( diff --git a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/resources/Info-lite.plist.template b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/resources/Info-lite.plist.template index 632dcd31b94..b981dc41d65 100644 --- a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/resources/Info-lite.plist.template +++ b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/resources/Info-lite.plist.template @@ -33,5 +33,7 @@ DEPLOY_BUNDLE_COPYRIGHTDEPLOY_FILE_ASSOCIATIONS NSHighResolutionCapable true + NSMicrophoneUsageDescription + The application DEPLOY_LAUNCHER_NAME is requesting access to the microphone. diff --git a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/resources/sandbox.plist b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/resources/sandbox.plist index ad48d4f9517..408f95f1d2a 100644 --- a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/resources/sandbox.plist +++ b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/resources/sandbox.plist @@ -14,5 +14,7 @@ com.apple.security.cs.debugger + com.apple.security.device.audio-input + diff --git a/test/hotspot/gtest/metaspace/test_is_metaspace_obj.cpp b/test/hotspot/gtest/metaspace/test_is_metaspace_obj.cpp index d96f57d29d3..b6dec198731 100644 --- a/test/hotspot/gtest/metaspace/test_is_metaspace_obj.cpp +++ b/test/hotspot/gtest/metaspace/test_is_metaspace_obj.cpp @@ -49,7 +49,7 @@ class MetaspaceIsMetaspaceObjTest { } void do_test(Metaspace::MetadataType mdType) { - _lock = new Mutex(Monitor::native, "gtest-IsMetaspaceObjTest-lock", false, Monitor::_safepoint_check_never); + _lock = new Mutex(Monitor::leaf, "gtest-IsMetaspaceObjTest-lock", false, Monitor::_safepoint_check_never); { MutexLocker ml(_lock, Mutex::_no_safepoint_check_flag); _ms = new ClassLoaderMetaspace(_lock, Metaspace::StandardMetaspaceType); diff --git a/test/hotspot/gtest/metaspace/test_metaspacearena.cpp b/test/hotspot/gtest/metaspace/test_metaspacearena.cpp index 96f6b70bbf0..bf6626e869f 100644 --- a/test/hotspot/gtest/metaspace/test_metaspacearena.cpp +++ b/test/hotspot/gtest/metaspace/test_metaspacearena.cpp @@ -66,7 +66,7 @@ class MetaspaceArenaTestHelper { void initialize(const ArenaGrowthPolicy* growth_policy, const char* name = "gtest-MetaspaceArena") { _growth_policy = growth_policy; - _lock = new Mutex(Monitor::native, "gtest-MetaspaceArenaTest-lock", false, Monitor::_safepoint_check_never); + _lock = new Mutex(Monitor::leaf, "gtest-MetaspaceArenaTest-lock", false, Monitor::_safepoint_check_never); // Lock during space creation, since this is what happens in the VM too // (see ClassLoaderData::metaspace_non_null(), which we mimick here). { diff --git a/test/hotspot/gtest/metaspace/test_metaspacearena_stress.cpp b/test/hotspot/gtest/metaspace/test_metaspacearena_stress.cpp index c5674894308..4887b6f4648 100644 --- a/test/hotspot/gtest/metaspace/test_metaspacearena_stress.cpp +++ b/test/hotspot/gtest/metaspace/test_metaspacearena_stress.cpp @@ -139,7 +139,7 @@ class MetaspaceArenaTestBed : public CHeapObj { _alloc_count(), _dealloc_count() { - _lock = new Mutex(Monitor::native, "gtest-MetaspaceArenaTestBed-lock", false, Monitor::_safepoint_check_never); + _lock = new Mutex(Monitor::leaf, "gtest-MetaspaceArenaTestBed-lock", false, Monitor::_safepoint_check_never); // Lock during space creation, since this is what happens in the VM too // (see ClassLoaderData::metaspace_non_null(), which we mimick here). MutexLocker ml(_lock, Mutex::_no_safepoint_check_flag); diff --git a/test/hotspot/gtest/runtime/test_mutex.cpp b/test/hotspot/gtest/runtime/test_mutex.cpp index 4d3317b2ad0..ac7be6e3907 100644 --- a/test/hotspot/gtest/runtime/test_mutex.cpp +++ b/test/hotspot/gtest/runtime/test_mutex.cpp @@ -129,7 +129,7 @@ TEST_VM_ASSERT_MSG(MutexRank, mutex_trylock_rank_out_of_orderB, } TEST_VM_ASSERT_MSG(MutexRank, mutex_lock_access_leaf, - ".* Attempting to acquire lock mutex_rank_leaf/11 out of order with lock mutex_rank_access/1 " + ".* Attempting to acquire lock mutex_rank_leaf/.* out of order with lock mutex_rank_access/1 " "-- possible deadlock") { JavaThread* THREAD = JavaThread::current(); ThreadInVMfromNative invm(THREAD); @@ -144,7 +144,7 @@ TEST_VM_ASSERT_MSG(MutexRank, mutex_lock_access_leaf, } TEST_VM_ASSERT_MSG(MutexRank, mutex_lock_tty_special, - ".* Attempting to acquire lock mutex_rank_special/6 out of order with lock mutex_rank_tty/3 " + ".* Attempting to acquire lock mutex_rank_special/.* out of order with lock mutex_rank_tty/.*" "-- possible deadlock") { JavaThread* THREAD = JavaThread::current(); ThreadInVMfromNative invm(THREAD); @@ -205,7 +205,7 @@ TEST_VM_ASSERT_MSG(MutexRank, monitor_wait_rank_out_of_order_trylock, } TEST_VM_ASSERT_MSG(MutexRank, monitor_wait_rank_special, - ".* Attempting to wait on monitor monitor_rank_special_minus_one/5 while holding lock monitor_rank_special/6 " + ".* Attempting to wait on monitor monitor_rank_special_minus_one/.* while holding lock monitor_rank_special/.*" "-- possible deadlock. Should not block\\(wait\\) while holding a lock of rank special.") { JavaThread* THREAD = JavaThread::current(); ThreadInVMfromNative invm(THREAD); @@ -221,7 +221,7 @@ TEST_VM_ASSERT_MSG(MutexRank, monitor_wait_rank_special, } TEST_VM_ASSERT_MSG(MutexRank, monitor_wait_access_leaf, - ".* Attempting to wait on monitor monitor_rank_access/1 while holding lock monitor_rank_tty/3 " + ".* Attempting to wait on monitor monitor_rank_access/1 while holding lock monitor_rank_tty/.*" "-- possible deadlock. Should not block\\(wait\\) while holding a lock of rank special.") { JavaThread* THREAD = JavaThread::current(); ThreadInVMfromNative invm(THREAD); @@ -237,7 +237,7 @@ TEST_VM_ASSERT_MSG(MutexRank, monitor_wait_access_leaf, } TEST_VM_ASSERT_MSG(MutexRank, monitor_wait_tty_special, - ".* Attempting to wait on monitor monitor_rank_tty/3 while holding lock monitor_rank_special/6 " + ".* Attempting to wait on monitor monitor_rank_tty/.* while holding lock monitor_rank_special/.*" "-- possible deadlock. Should not block\\(wait\\) while holding a lock of rank special.") { JavaThread* THREAD = JavaThread::current(); ThreadInVMfromNative invm(THREAD); diff --git a/test/hotspot/jtreg/compiler/codegen/aes/TestAESMain.java b/test/hotspot/jtreg/compiler/codegen/aes/TestAESMain.java index e9c8e4aab31..8b76f5cc3d0 100644 --- a/test/hotspot/jtreg/compiler/codegen/aes/TestAESMain.java +++ b/test/hotspot/jtreg/compiler/codegen/aes/TestAESMain.java @@ -98,6 +98,27 @@ * @run main/othervm/timeout=600 -Xbatch -DcheckOutput=true -Dmode=GCM -DencInputOffset=1 -DencOutputOffset=1 -DdecOutputOffset=1 -DpaddingStr=NoPadding -DmsgSize=640 * -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:. * compiler.codegen.aes.TestAESMain + * @run main/othervm/timeout=600 -Xbatch -DcheckOutput=true -Dmode=GCM -DmsgSize=2054 + * -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:. + * compiler.codegen.aes.TestAESMain + * @run main/othervm/timeout=600 -Xbatch -DcheckOutput=true -Dmode=GCM -DencInputOffset=1 -DmsgSize=2054 + * -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:. + * compiler.codegen.aes.TestAESMain + * @run main/othervm/timeout=600 -Xbatch -DcheckOutput=true -Dmode=GCM -DencOutputOffset=1 -DmsgSize=2054 + * -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:. + * compiler.codegen.aes.TestAESMain + * @run main/othervm/timeout=600 -Xbatch -DcheckOutput=true -Dmode=GCM -DdecOutputOffset=1 -DmsgSize=2054 + * -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:. + * compiler.codegen.aes.TestAESMain + * @run main/othervm/timeout=600 -Xbatch -DcheckOutput=true -Dmode=GCM -DencInputOffset=1 -DencOutputOffset=1 -DmsgSize=2054 + * -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:. + * compiler.codegen.aes.TestAESMain + * @run main/othervm/timeout=600 -Xbatch -DcheckOutput=true -Dmode=GCM -DencInputOffset=1 -DencOutputOffset=1 -DdecOutputOffset=1 -DmsgSize=2054 + * -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:. + * compiler.codegen.aes.TestAESMain + * @run main/othervm/timeout=600 -Xbatch -DcheckOutput=true -Dmode=GCM -DencInputOffset=1 -DencOutputOffset=1 -DdecOutputOffset=1 -DpaddingStr=NoPadding -DmsgSize=2048 + * -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:. + * compiler.codegen.aes.TestAESMain * * @run main/othervm/timeout=600 -Xbatch -DcheckOutput=true -Dmode=CTR * -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:. diff --git a/test/hotspot/jtreg/compiler/regalloc/TestGCMRecalcPressureNodes.java b/test/hotspot/jtreg/compiler/regalloc/TestGCMRecalcPressureNodes.java new file mode 100644 index 00000000000..fe2fd7e4444 --- /dev/null +++ b/test/hotspot/jtreg/compiler/regalloc/TestGCMRecalcPressureNodes.java @@ -0,0 +1,53 @@ +/* + * Copyright (C) 2021 THL A29 Limited, a Tencent company. 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. + * + */ + +/** + * @test + * @bug 8272570 + * @summary crash in PhaseCFG::global_code_motion + * @requires vm.compiler2.enabled + * + * @run main/othervm -Xbatch TestGCMRecalcPressureNodes + */ + +public class TestGCMRecalcPressureNodes { + public boolean bo0; + public boolean bo1; + public void foo() { + int sh12 = 61; + for (int i = 0; i < 50; i++) { + sh12 *= 34; + } + Math.tan(1.0); + bo0 = true; + bo1 = true; + } + public static void main(String[] args) { + TestGCMRecalcPressureNodes instance = new TestGCMRecalcPressureNodes(); + for (int i = 0; i < 50000; i++) { + instance.foo(); + } + } +} + diff --git a/test/hotspot/jtreg/compiler/unsafe/MismatchedUnsafeAccessTest.java b/test/hotspot/jtreg/compiler/unsafe/MismatchedUnsafeAccessTest.java new file mode 100644 index 00000000000..be07a3bfc8e --- /dev/null +++ b/test/hotspot/jtreg/compiler/unsafe/MismatchedUnsafeAccessTest.java @@ -0,0 +1,73 @@ +/* + * 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. + */ + +/* + * @test + * @bug 8223923 + * @modules java.base/jdk.internal.misc + * @run main/othervm -Xbatch compiler.unsafe.MismatchedUnsafeAccessTest + */ +package compiler.unsafe; + +import jdk.internal.misc.Unsafe; + +public class MismatchedUnsafeAccessTest { + private static final Unsafe UNSAFE = Unsafe.getUnsafe(); + + public static class Test { + public int x = 0; + public int y = 0; + + public static final long offsetX; + public static final long offsetY; + + static { + try { + offsetX = UNSAFE.objectFieldOffset(Test.class.getField("x")); + offsetY = UNSAFE.objectFieldOffset(Test.class.getField("y")); + } catch (NoSuchFieldException e) { + throw new InternalError(e); + } + // Validate offsets + if (offsetX >= offsetY || offsetY - offsetX != 4) { + throw new InternalError("Wrong offsets: " + offsetX + " " + offsetY); + } + } + } + + public static int test(long l) { + Test a = new Test(); + UNSAFE.putLong(a, Test.offsetX, l); // mismatched access; interferes with subsequent load + return UNSAFE.getInt(a, Test.offsetY); + } + + public static void main(String[] args) { + for (int i = 0; i < 20_000; i++) { + int res = test(-1L); + if (res != -1) { + throw new AssertionError("Wrong result: " + res); + } + } + System.out.println("TEST PASSED"); + } +} diff --git a/test/hotspot/jtreg/gc/epsilon/TestAlignment.java b/test/hotspot/jtreg/gc/epsilon/TestAlignment.java index e4328f5ac4d..c4eb329d3f6 100644 --- a/test/hotspot/jtreg/gc/epsilon/TestAlignment.java +++ b/test/hotspot/jtreg/gc/epsilon/TestAlignment.java @@ -28,10 +28,24 @@ * @requires vm.gc.Epsilon * @summary Check Epsilon runs fine with (un)usual alignments * @bug 8212005 - * @run main/othervm -XX:+UnlockExperimentalVMOptions -Xmx128m -XX:+UseEpsilonGC -XX:+UseTLAB gc.epsilon.TestAlignment - * @run main/othervm -XX:+UnlockExperimentalVMOptions -Xmx128m -XX:+UseEpsilonGC -XX:-UseTLAB gc.epsilon.TestAlignment - * @run main/othervm -XX:+UnlockExperimentalVMOptions -Xmx128m -XX:+UseEpsilonGC -XX:+UseTLAB -XX:+IgnoreUnrecognizedVMOptions -XX:ObjectAlignmentInBytes=16 gc.epsilon.TestAlignment - * @run main/othervm -XX:+UnlockExperimentalVMOptions -Xmx128m -XX:+UseEpsilonGC -XX:-UseTLAB -XX:+IgnoreUnrecognizedVMOptions -XX:ObjectAlignmentInBytes=16 gc.epsilon.TestAlignment + * + * @run main/othervm -Xmx64m -XX:+UseTLAB + * -XX:+UnlockExperimentalVMOptions -XX:+UseEpsilonGC + * gc.epsilon.TestAlignment + * + * @run main/othervm -Xmx64m -XX:-UseTLAB + * -XX:+UnlockExperimentalVMOptions -XX:+UseEpsilonGC + * gc.epsilon.TestAlignment + * + * @run main/othervm -Xmx64m -XX:+UseTLAB + * -XX:+UnlockExperimentalVMOptions -XX:+UseEpsilonGC + * -XX:+IgnoreUnrecognizedVMOptions -XX:ObjectAlignmentInBytes=16 + * gc.epsilon.TestAlignment + * + * @run main/othervm -Xmx64m -XX:-UseTLAB + * -XX:+UnlockExperimentalVMOptions -XX:+UseEpsilonGC + * -XX:+IgnoreUnrecognizedVMOptions -XX:ObjectAlignmentInBytes=16 + * gc.epsilon.TestAlignment */ public class TestAlignment { diff --git a/test/hotspot/jtreg/gc/epsilon/TestAlwaysPretouch.java b/test/hotspot/jtreg/gc/epsilon/TestAlwaysPretouch.java index 75b0edf0058..b8ac4c802e4 100644 --- a/test/hotspot/jtreg/gc/epsilon/TestAlwaysPretouch.java +++ b/test/hotspot/jtreg/gc/epsilon/TestAlwaysPretouch.java @@ -24,13 +24,31 @@ /** * @test TestAlwaysPretouch * @requires vm.gc.Epsilon - * @summary Basic sanity test for Epsilon - * @run main/othervm -Xms128m -Xmx1g -XX:+UnlockExperimentalVMOptions -XX:+UseEpsilonGC gc.epsilon.TestAlwaysPretouch - * @run main/othervm -Xms128m -Xmx1g -XX:-AlwaysPreTouch -XX:+UnlockExperimentalVMOptions -XX:+UseEpsilonGC gc.epsilon.TestAlwaysPretouch - * @run main/othervm -Xms128m -Xmx1g -XX:+AlwaysPreTouch -XX:+UnlockExperimentalVMOptions -XX:+UseEpsilonGC gc.epsilon.TestAlwaysPretouch - * @run main/othervm -Xmx1g -XX:+UnlockExperimentalVMOptions -XX:+UseEpsilonGC gc.epsilon.TestAlwaysPretouch - * @run main/othervm -Xmx1g -XX:-AlwaysPreTouch -XX:+UnlockExperimentalVMOptions -XX:+UseEpsilonGC gc.epsilon.TestAlwaysPretouch - * @run main/othervm -Xmx1g -XX:+AlwaysPreTouch -XX:+UnlockExperimentalVMOptions -XX:+UseEpsilonGC gc.epsilon.TestAlwaysPretouch + * @summary Test that pre-touch works + * + * @run main/othervm -Xms64m -Xmx256m + * -XX:+UnlockExperimentalVMOptions -XX:+UseEpsilonGC + * gc.epsilon.TestAlwaysPretouch + * + * @run main/othervm -Xms64m -Xmx256m -XX:-AlwaysPreTouch + * -XX:+UnlockExperimentalVMOptions -XX:+UseEpsilonGC + * gc.epsilon.TestAlwaysPretouch + * + * @run main/othervm -Xms64m -Xmx256m -XX:+AlwaysPreTouch + * -XX:+UnlockExperimentalVMOptions -XX:+UseEpsilonGC + * gc.epsilon.TestAlwaysPretouch + * + * @run main/othervm -Xmx256m + * -XX:+UnlockExperimentalVMOptions -XX:+UseEpsilonGC + * gc.epsilon.TestAlwaysPretouch + * + * @run main/othervm -Xmx256m -XX:-AlwaysPreTouch + * -XX:+UnlockExperimentalVMOptions -XX:+UseEpsilonGC + * gc.epsilon.TestAlwaysPretouch + * + * @run main/othervm -Xmx256m -XX:+AlwaysPreTouch + * -XX:+UnlockExperimentalVMOptions -XX:+UseEpsilonGC + * gc.epsilon.TestAlwaysPretouch */ package gc.epsilon; diff --git a/test/hotspot/jtreg/gc/epsilon/TestArraycopyCheckcast.java b/test/hotspot/jtreg/gc/epsilon/TestArraycopyCheckcast.java index ca9eaf6d7d9..632137b644c 100644 --- a/test/hotspot/jtreg/gc/epsilon/TestArraycopyCheckcast.java +++ b/test/hotspot/jtreg/gc/epsilon/TestArraycopyCheckcast.java @@ -30,11 +30,24 @@ * @library /test/lib * @bug 8215724 * - * @run main/othervm -Xmx1g -XX:+UnlockExperimentalVMOptions -XX:+UseEpsilonGC gc.epsilon.TestArraycopyCheckcast - * @run main/othervm -Xmx1g -Xint -XX:+UnlockExperimentalVMOptions -XX:+UseEpsilonGC gc.epsilon.TestArraycopyCheckcast - * @run main/othervm -Xmx1g -Xbatch -Xcomp -XX:+UnlockExperimentalVMOptions -XX:+UseEpsilonGC gc.epsilon.TestArraycopyCheckcast - * @run main/othervm -Xmx1g -Xbatch -Xcomp -XX:TieredStopAtLevel=1 -XX:+UnlockExperimentalVMOptions -XX:+UseEpsilonGC gc.epsilon.TestArraycopyCheckcast - * @run main/othervm -Xmx1g -Xbatch -Xcomp -XX:-TieredCompilation -XX:+UnlockExperimentalVMOptions -XX:+UseEpsilonGC gc.epsilon.TestArraycopyCheckcast + * @run main/othervm -Xmx256m + * -XX:+UnlockExperimentalVMOptions -XX:+UseEpsilonGC + * gc.epsilon.TestArraycopyCheckcast + * + * @run main/othervm -Xmx256m + * -Xint + * -XX:+UnlockExperimentalVMOptions -XX:+UseEpsilonGC + * gc.epsilon.TestArraycopyCheckcast + * + * @run main/othervm -Xmx256m + * -Xbatch -Xcomp -XX:TieredStopAtLevel=1 + * -XX:+UnlockExperimentalVMOptions -XX:+UseEpsilonGC + * gc.epsilon.TestArraycopyCheckcast + * + * @run main/othervm -Xmx256m + * -Xbatch -Xcomp -XX:-TieredCompilation + * -XX:+UnlockExperimentalVMOptions -XX:+UseEpsilonGC + * gc.epsilon.TestArraycopyCheckcast */ public class TestArraycopyCheckcast { diff --git a/test/hotspot/jtreg/gc/epsilon/TestByteArrays.java b/test/hotspot/jtreg/gc/epsilon/TestByteArrays.java index 79219566b88..fac70baeda0 100644 --- a/test/hotspot/jtreg/gc/epsilon/TestByteArrays.java +++ b/test/hotspot/jtreg/gc/epsilon/TestByteArrays.java @@ -26,28 +26,54 @@ /** * @test TestByteArrays * @key randomness - * @requires vm.gc.Epsilon & os.maxMemory > 1G + * @requires vm.gc.Epsilon * @summary Epsilon is able to allocate arrays, and does not corrupt their state * @library /test/lib * - * @run main/othervm -Xmx1g -XX:+UseTLAB -XX:+UnlockExperimentalVMOptions -XX:+UseEpsilonGC gc.epsilon.TestByteArrays - * @run main/othervm -Xmx1g -Xint -XX:+UseTLAB -XX:+UnlockExperimentalVMOptions -XX:+UseEpsilonGC gc.epsilon.TestByteArrays - * @run main/othervm -Xmx1g -Xbatch -Xcomp -XX:+UseTLAB -XX:+UnlockExperimentalVMOptions -XX:+UseEpsilonGC gc.epsilon.TestByteArrays - * @run main/othervm -Xmx1g -Xbatch -Xcomp -XX:TieredStopAtLevel=1 -XX:+UseTLAB -XX:+UnlockExperimentalVMOptions -XX:+UseEpsilonGC gc.epsilon.TestByteArrays - * @run main/othervm -Xmx1g -Xbatch -Xcomp -XX:-TieredCompilation -XX:+UseTLAB -XX:+UnlockExperimentalVMOptions -XX:+UseEpsilonGC gc.epsilon.TestByteArrays + * @run main/othervm -XX:+UseTLAB -Xmx256m + * -XX:+UnlockExperimentalVMOptions -XX:+UseEpsilonGC + * gc.epsilon.TestByteArrays * - * @run main/othervm -Xmx1g -XX:-UseTLAB -XX:+UnlockExperimentalVMOptions -XX:+UseEpsilonGC gc.epsilon.TestByteArrays - * @run main/othervm -Xmx1g -Xint -XX:-UseTLAB -XX:+UnlockExperimentalVMOptions -XX:+UseEpsilonGC gc.epsilon.TestByteArrays - * @run main/othervm -Xmx1g -Xbatch -Xcomp -XX:-UseTLAB -XX:+UnlockExperimentalVMOptions -XX:+UseEpsilonGC gc.epsilon.TestByteArrays - * @run main/othervm -Xmx1g -Xbatch -Xcomp -XX:TieredStopAtLevel=1 -XX:-UseTLAB -XX:+UnlockExperimentalVMOptions -XX:+UseEpsilonGC gc.epsilon.TestByteArrays - * @run main/othervm -Xmx1g -Xbatch -Xcomp -XX:-TieredCompilation -XX:-UseTLAB -XX:+UnlockExperimentalVMOptions -XX:+UseEpsilonGC gc.epsilon.TestByteArrays + * @run main/othervm -XX:+UseTLAB -Xmx256m + * -Xint + * -XX:+UnlockExperimentalVMOptions -XX:+UseEpsilonGC + * gc.epsilon.TestByteArrays + * + * @run main/othervm -XX:+UseTLAB -Xmx256m + * -Xbatch -Xcomp -XX:TieredStopAtLevel=1 + * -XX:+UnlockExperimentalVMOptions -XX:+UseEpsilonGC + * gc.epsilon.TestByteArrays + * + * @run main/othervm -XX:+UseTLAB -Xmx256m + * -Xbatch -Xcomp -XX:-TieredCompilation + * -XX:+UnlockExperimentalVMOptions -XX:+UseEpsilonGC + * gc.epsilon.TestByteArrays + * + * @run main/othervm -XX:-UseTLAB -Xmx256m + * -XX:+UnlockExperimentalVMOptions -XX:+UseEpsilonGC + * gc.epsilon.TestByteArrays + * + * @run main/othervm -XX:-UseTLAB -Xmx256m + * -Xint + * -XX:+UnlockExperimentalVMOptions -XX:+UseEpsilonGC + * gc.epsilon.TestByteArrays + * + * @run main/othervm -XX:-UseTLAB -Xmx256m + * -Xbatch -Xcomp -XX:TieredStopAtLevel=1 + * -XX:+UnlockExperimentalVMOptions -XX:+UseEpsilonGC + * gc.epsilon.TestByteArrays + * + * @run main/othervm -XX:-UseTLAB -Xmx256m + * -Xbatch -Xcomp -XX:-TieredCompilation + * -XX:+UnlockExperimentalVMOptions -XX:+UseEpsilonGC + * gc.epsilon.TestByteArrays */ import java.util.Random; import jdk.test.lib.Utils; public class TestByteArrays { - static int COUNT = Integer.getInteger("count", 3000); // ~500 MB allocation + static int COUNT = Integer.getInteger("count", 500); // ~100 MB allocation static byte[][] arr; diff --git a/test/hotspot/jtreg/gc/epsilon/TestClasses.java b/test/hotspot/jtreg/gc/epsilon/TestClasses.java index 5f0ae333f11..aa081eeaf65 100644 --- a/test/hotspot/jtreg/gc/epsilon/TestClasses.java +++ b/test/hotspot/jtreg/gc/epsilon/TestClasses.java @@ -31,7 +31,10 @@ * @modules java.base/jdk.internal.org.objectweb.asm * java.base/jdk.internal.misc * - * @run main/othervm -Xmx1g -XX:MetaspaceSize=1m -XX:MaxMetaspaceSize=64m -XX:+UnlockExperimentalVMOptions -XX:+UseEpsilonGC -Xlog:gc -Xlog:gc+metaspace gc.epsilon.TestClasses + * @run main/othervm -Xmx256m + * -XX:MetaspaceSize=1m -XX:MaxMetaspaceSize=64m -Xlog:gc -Xlog:gc+metaspace + * -XX:+UnlockExperimentalVMOptions -XX:+UseEpsilonGC + * gc.epsilon.TestClasses */ import jdk.internal.org.objectweb.asm.ClassWriter; diff --git a/test/hotspot/jtreg/gc/epsilon/TestDieDefault.java b/test/hotspot/jtreg/gc/epsilon/TestDieDefault.java index b8a72660aaf..a883eb9f27c 100644 --- a/test/hotspot/jtreg/gc/epsilon/TestDieDefault.java +++ b/test/hotspot/jtreg/gc/epsilon/TestDieDefault.java @@ -53,31 +53,24 @@ public static void failWith(String... args) throws Exception { } public static void main(String[] args) throws Exception { - passWith("-Xmx128m", + passWith("-Xmx64m", "-XX:+UnlockExperimentalVMOptions", "-XX:+UseEpsilonGC", "-Dcount=1", TestDieDefault.Workload.class.getName()); - failWith("-Xmx128m", + failWith("-Xmx64m", "-XX:+UnlockExperimentalVMOptions", "-XX:+UseEpsilonGC", TestDieDefault.Workload.class.getName()); - failWith("-Xmx128m", + failWith("-Xmx64m", "-Xint", "-XX:+UnlockExperimentalVMOptions", "-XX:+UseEpsilonGC", TestDieDefault.Workload.class.getName()); - failWith("-Xmx128m", - "-Xbatch", - "-Xcomp", - "-XX:+UnlockExperimentalVMOptions", - "-XX:+UseEpsilonGC", - TestDieDefault.Workload.class.getName()); - - failWith("-Xmx128m", + failWith("-Xmx64m", "-Xbatch", "-Xcomp", "-XX:TieredStopAtLevel=1", @@ -85,7 +78,7 @@ public static void main(String[] args) throws Exception { "-XX:+UseEpsilonGC", TestDieDefault.Workload.class.getName()); - failWith("-Xmx128m", + failWith("-Xmx64m", "-Xbatch", "-Xcomp", "-XX:-TieredCompilation", diff --git a/test/hotspot/jtreg/gc/epsilon/TestDieWithHeapDump.java b/test/hotspot/jtreg/gc/epsilon/TestDieWithHeapDump.java index b1df98c9ade..c717b493330 100644 --- a/test/hotspot/jtreg/gc/epsilon/TestDieWithHeapDump.java +++ b/test/hotspot/jtreg/gc/epsilon/TestDieWithHeapDump.java @@ -59,35 +59,27 @@ public static void failWith(String... args) throws Exception { } public static void main(String[] args) throws Exception { - passWith("-Xmx128m", + passWith("-Xmx64m", "-XX:+UnlockExperimentalVMOptions", "-XX:+UseEpsilonGC", "-Dcount=1", "-XX:+HeapDumpOnOutOfMemoryError", TestDieWithHeapDump.Workload.class.getName()); - failWith("-Xmx128m", + failWith("-Xmx64m", "-XX:+UnlockExperimentalVMOptions", "-XX:+UseEpsilonGC", "-XX:+HeapDumpOnOutOfMemoryError", TestDieWithHeapDump.Workload.class.getName()); - failWith("-Xmx128m", + failWith("-Xmx64m", "-Xint", "-XX:+UnlockExperimentalVMOptions", "-XX:+UseEpsilonGC", "-XX:+HeapDumpOnOutOfMemoryError", TestDieWithHeapDump.Workload.class.getName()); - failWith("-Xmx128m", - "-Xbatch", - "-Xcomp", - "-XX:+UnlockExperimentalVMOptions", - "-XX:+UseEpsilonGC", - "-XX:+HeapDumpOnOutOfMemoryError", - TestDieWithHeapDump.Workload.class.getName()); - - failWith("-Xmx128m", + failWith("-Xmx64m", "-Xbatch", "-Xcomp", "-XX:TieredStopAtLevel=1", @@ -96,7 +88,7 @@ public static void main(String[] args) throws Exception { "-XX:+HeapDumpOnOutOfMemoryError", TestDieWithHeapDump.Workload.class.getName()); - failWith("-Xmx128m", + failWith("-Xmx64m", "-Xbatch", "-Xcomp", "-XX:-TieredCompilation", diff --git a/test/hotspot/jtreg/gc/epsilon/TestDieWithOnError.java b/test/hotspot/jtreg/gc/epsilon/TestDieWithOnError.java index c87658e3eea..2cac3843b0e 100644 --- a/test/hotspot/jtreg/gc/epsilon/TestDieWithOnError.java +++ b/test/hotspot/jtreg/gc/epsilon/TestDieWithOnError.java @@ -57,35 +57,27 @@ public static void failWith(String... args) throws Exception { } public static void main(String[] args) throws Exception { - passWith("-Xmx128m", + passWith("-Xmx64m", "-XX:+UnlockExperimentalVMOptions", "-XX:+UseEpsilonGC", "-Dcount=1", "-XX:OnOutOfMemoryError=echo " + ON_ERR_MSG, TestDieWithOnError.Workload.class.getName()); - failWith("-Xmx128m", + failWith("-Xmx64m", "-XX:+UnlockExperimentalVMOptions", "-XX:+UseEpsilonGC", "-XX:OnOutOfMemoryError=echo " + ON_ERR_MSG, TestDieWithOnError.Workload.class.getName()); - failWith("-Xmx128m", + failWith("-Xmx64m", "-Xint", "-XX:+UnlockExperimentalVMOptions", "-XX:+UseEpsilonGC", "-XX:OnOutOfMemoryError=echo " + ON_ERR_MSG, TestDieWithOnError.Workload.class.getName()); - failWith("-Xmx128m", - "-Xbatch", - "-Xcomp", - "-XX:+UnlockExperimentalVMOptions", - "-XX:+UseEpsilonGC", - "-XX:OnOutOfMemoryError=echo " + ON_ERR_MSG, - TestDieWithOnError.Workload.class.getName()); - - failWith("-Xmx128m", + failWith("-Xmx64m", "-Xbatch", "-Xcomp", "-XX:TieredStopAtLevel=1", @@ -94,7 +86,7 @@ public static void main(String[] args) throws Exception { "-XX:OnOutOfMemoryError=echo " + ON_ERR_MSG, TestDieWithOnError.Workload.class.getName()); - failWith("-Xmx128m", + failWith("-Xmx64m", "-Xbatch", "-Xcomp", "-XX:-TieredCompilation", diff --git a/test/hotspot/jtreg/gc/epsilon/TestElasticTLAB.java b/test/hotspot/jtreg/gc/epsilon/TestElasticTLAB.java index 4ea46ea0dd1..6a312ac198f 100644 --- a/test/hotspot/jtreg/gc/epsilon/TestElasticTLAB.java +++ b/test/hotspot/jtreg/gc/epsilon/TestElasticTLAB.java @@ -26,23 +26,41 @@ /** * @test TestElasticTLAB * @key randomness - * @requires vm.gc.Epsilon & os.maxMemory > 1G + * @requires vm.gc.Epsilon * @summary Epsilon is able to work with/without elastic TLABs * @library /test/lib * - * @run main/othervm -Xmx1g -XX:+UnlockExperimentalVMOptions -XX:+UseEpsilonGC -XX:-EpsilonElasticTLAB gc.epsilon.TestElasticTLAB - * @run main/othervm -Xmx1g -XX:+UnlockExperimentalVMOptions -XX:+UseEpsilonGC -XX:+EpsilonElasticTLAB -XX:EpsilonTLABElasticity=1 gc.epsilon.TestElasticTLAB - * @run main/othervm -Xmx1g -XX:+UnlockExperimentalVMOptions -XX:+UseEpsilonGC -XX:+EpsilonElasticTLAB -XX:EpsilonTLABElasticity=1.1 gc.epsilon.TestElasticTLAB - * @run main/othervm -Xmx1g -XX:+UnlockExperimentalVMOptions -XX:+UseEpsilonGC -XX:+EpsilonElasticTLAB -XX:EpsilonTLABElasticity=2.0 gc.epsilon.TestElasticTLAB - * @run main/othervm -Xmx1g -XX:+UnlockExperimentalVMOptions -XX:+UseEpsilonGC -XX:+EpsilonElasticTLAB -XX:EpsilonTLABElasticity=42 gc.epsilon.TestElasticTLAB - * @run main/othervm -Xmx1g -XX:+UnlockExperimentalVMOptions -XX:+UseEpsilonGC -XX:+EpsilonElasticTLAB -XX:EpsilonTLABElasticity=100 gc.epsilon.TestElasticTLAB + * @run main/othervm -Xmx256m + * -XX:+UnlockExperimentalVMOptions -XX:+UseEpsilonGC + * -XX:-EpsilonElasticTLAB + * gc.epsilon.TestElasticTLAB + * + * @run main/othervm -Xmx256m + * -XX:+UnlockExperimentalVMOptions -XX:+UseEpsilonGC + * -XX:+EpsilonElasticTLAB -XX:EpsilonTLABElasticity=1 + * gc.epsilon.TestElasticTLAB + * + * @run main/othervm -Xmx256m + * -XX:+UnlockExperimentalVMOptions -XX:+UseEpsilonGC + * -XX:+EpsilonElasticTLAB -XX:EpsilonTLABElasticity=1.1 + * gc.epsilon.TestElasticTLAB + * + * @run main/othervm -Xmx256m + * -XX:+UnlockExperimentalVMOptions -XX:+UseEpsilonGC + * -XX:+EpsilonElasticTLAB -XX:EpsilonTLABElasticity=2.0 + * gc.epsilon.TestElasticTLAB + * + * @run main/othervm -Xmx256m + * -XX:+UnlockExperimentalVMOptions -XX:+UseEpsilonGC + * -XX:+EpsilonElasticTLAB -XX:EpsilonTLABElasticity=100 + * gc.epsilon.TestElasticTLAB */ import java.util.Random; import jdk.test.lib.Utils; public class TestElasticTLAB { - static int COUNT = Integer.getInteger("count", 3000); // ~500 MB allocation + static int COUNT = Integer.getInteger("count", 500); // ~100 MB allocation static byte[][] arr; diff --git a/test/hotspot/jtreg/gc/epsilon/TestElasticTLABDecay.java b/test/hotspot/jtreg/gc/epsilon/TestElasticTLABDecay.java index 751f67911fc..c81ad29c059 100644 --- a/test/hotspot/jtreg/gc/epsilon/TestElasticTLABDecay.java +++ b/test/hotspot/jtreg/gc/epsilon/TestElasticTLABDecay.java @@ -26,20 +26,31 @@ /** * @test TestElasticTLABDecay * @key randomness - * @requires vm.gc.Epsilon & os.maxMemory > 1G - * @summary Epsilon is able to work with/without elastic TLABs + * @requires vm.gc.Epsilon + * @summary Epsilon is able to work with/without elastic TLABs decay * @library /test/lib * - * @run main/othervm -Xmx1g -XX:+UnlockExperimentalVMOptions -XX:+UseEpsilonGC -XX:+EpsilonElasticTLAB -XX:-EpsilonElasticTLABDecay gc.epsilon.TestElasticTLABDecay - * @run main/othervm -Xmx1g -XX:+UnlockExperimentalVMOptions -XX:+UseEpsilonGC -XX:+EpsilonElasticTLAB -XX:+EpsilonElasticTLABDecay -XX:EpsilonTLABDecayTime=1 gc.epsilon.TestElasticTLABDecay - * @run main/othervm -Xmx1g -XX:+UnlockExperimentalVMOptions -XX:+UseEpsilonGC -XX:+EpsilonElasticTLAB -XX:+EpsilonElasticTLABDecay -XX:EpsilonTLABDecayTime=100 gc.epsilon.TestElasticTLABDecay + * @run main/othervm -Xmx256m + * -XX:+UnlockExperimentalVMOptions -XX:+UseEpsilonGC + * -XX:+EpsilonElasticTLAB -XX:-EpsilonElasticTLABDecay + * gc.epsilon.TestElasticTLABDecay + * + * @run main/othervm -Xmx256m + * -XX:+UnlockExperimentalVMOptions -XX:+UseEpsilonGC + * -XX:+EpsilonElasticTLAB -XX:+EpsilonElasticTLABDecay -XX:EpsilonTLABDecayTime=1 + * gc.epsilon.TestElasticTLABDecay + * + * @run main/othervm -Xmx256m + * -XX:+UnlockExperimentalVMOptions -XX:+UseEpsilonGC + * -XX:+EpsilonElasticTLAB -XX:+EpsilonElasticTLABDecay -XX:EpsilonTLABDecayTime=100 + * gc.epsilon.TestElasticTLABDecay */ import java.util.Random; import jdk.test.lib.Utils; public class TestElasticTLABDecay { - static int COUNT = Integer.getInteger("count", 3000); // ~500 MB allocation + static int COUNT = Integer.getInteger("count", 500); // ~100 MB allocation static byte[][] arr; diff --git a/test/hotspot/jtreg/gc/epsilon/TestEpsilonEnabled.java b/test/hotspot/jtreg/gc/epsilon/TestEpsilonEnabled.java index 5908ed6a29f..32ada0dc373 100644 --- a/test/hotspot/jtreg/gc/epsilon/TestEpsilonEnabled.java +++ b/test/hotspot/jtreg/gc/epsilon/TestEpsilonEnabled.java @@ -28,7 +28,10 @@ * @requires vm.gc.Epsilon * @summary Basic sanity test for Epsilon * @library /test/lib - * @run main/othervm -XX:+UnlockExperimentalVMOptions -XX:+UseEpsilonGC gc.epsilon.TestEpsilonEnabled + * + * @run main/othervm -Xmx256m + * -XX:+UnlockExperimentalVMOptions -XX:+UseEpsilonGC + * gc.epsilon.TestEpsilonEnabled */ import java.lang.management.GarbageCollectorMXBean; diff --git a/test/hotspot/jtreg/gc/epsilon/TestHelloWorld.java b/test/hotspot/jtreg/gc/epsilon/TestHelloWorld.java index c045411bf56..9d47cc4e292 100644 --- a/test/hotspot/jtreg/gc/epsilon/TestHelloWorld.java +++ b/test/hotspot/jtreg/gc/epsilon/TestHelloWorld.java @@ -27,7 +27,8 @@ * @test TestHelloWorld * @requires vm.gc.Epsilon * @summary Basic sanity test for Epsilon - * @run main/othervm -XX:+UnlockExperimentalVMOptions -XX:+UseEpsilonGC gc.epsilon.TestHelloWorld + * @run main/othervm -XX:+UnlockExperimentalVMOptions -XX:+UseEpsilonGC + * gc.epsilon.TestHelloWorld */ public class TestHelloWorld { diff --git a/test/hotspot/jtreg/gc/epsilon/TestLogTrace.java b/test/hotspot/jtreg/gc/epsilon/TestLogTrace.java index 1dcb73046e8..c79295c3391 100644 --- a/test/hotspot/jtreg/gc/epsilon/TestLogTrace.java +++ b/test/hotspot/jtreg/gc/epsilon/TestLogTrace.java @@ -28,7 +28,10 @@ * @test TestLogTrace * @requires vm.gc.Epsilon * @summary Test that tracing does not crash Epsilon - * @run main/othervm -XX:+UnlockExperimentalVMOptions -XX:+UseEpsilonGC -Xlog:gc*=trace gc.epsilon.TestLogTrace + * + * @run main/othervm -Xmx256m -Xlog:gc*=trace + * -XX:+UnlockExperimentalVMOptions -XX:+UseEpsilonGC + * gc.epsilon.TestLogTrace */ public class TestLogTrace { diff --git a/test/hotspot/jtreg/gc/epsilon/TestManyThreads.java b/test/hotspot/jtreg/gc/epsilon/TestManyThreads.java index 8d9b2044829..5a03785cae4 100644 --- a/test/hotspot/jtreg/gc/epsilon/TestManyThreads.java +++ b/test/hotspot/jtreg/gc/epsilon/TestManyThreads.java @@ -28,17 +28,43 @@ * @requires vm.gc.Epsilon * @summary Test allocations from many threads * - * @run main/othervm -Xmx128m -Xss512k -XX:-UseTLAB -XX:+UnlockExperimentalVMOptions -XX:+UseEpsilonGC gc.epsilon.TestManyThreads - * @run main/othervm -Xmx128m -Xss512k -Xint -XX:-UseTLAB -XX:+UnlockExperimentalVMOptions -XX:+UseEpsilonGC gc.epsilon.TestManyThreads - * @run main/othervm -Xmx128m -Xss512k -Xbatch -Xcomp -XX:-UseTLAB -XX:+UnlockExperimentalVMOptions -XX:+UseEpsilonGC gc.epsilon.TestManyThreads - * @run main/othervm -Xmx128m -Xss512k -Xbatch -Xcomp -XX:TieredStopAtLevel=1 -XX:-UseTLAB -XX:+UnlockExperimentalVMOptions -XX:+UseEpsilonGC gc.epsilon.TestManyThreads - * @run main/othervm -Xmx128m -Xss512k -Xbatch -Xcomp -XX:-TieredCompilation -XX:-UseTLAB -XX:+UnlockExperimentalVMOptions -XX:+UseEpsilonGC gc.epsilon.TestManyThreads + * @run main/othervm -XX:-UseTLAB -Xmx256m -Xss512k + * -XX:+UnlockExperimentalVMOptions -XX:+UseEpsilonGC + * gc.epsilon.TestManyThreads * - * @run main/othervm -Xmx128m -Xss512k -XX:+UseTLAB -XX:+UnlockExperimentalVMOptions -XX:+UseEpsilonGC gc.epsilon.TestManyThreads - * @run main/othervm -Xmx128m -Xss512k -Xint -XX:+UseTLAB -XX:+UnlockExperimentalVMOptions -XX:+UseEpsilonGC gc.epsilon.TestManyThreads - * @run main/othervm -Xmx128m -Xss512k -Xbatch -Xcomp -XX:+UseTLAB -XX:+UnlockExperimentalVMOptions -XX:+UseEpsilonGC gc.epsilon.TestManyThreads - * @run main/othervm -Xmx128m -Xss512k -Xbatch -Xcomp -XX:TieredStopAtLevel=1 -XX:+UseTLAB -XX:+UnlockExperimentalVMOptions -XX:+UseEpsilonGC gc.epsilon.TestManyThreads - * @run main/othervm -Xmx128m -Xss512k -Xbatch -Xcomp -XX:-TieredCompilation -XX:+UseTLAB -XX:+UnlockExperimentalVMOptions -XX:+UseEpsilonGC gc.epsilon.TestManyThreads + * @run main/othervm -XX:-UseTLAB -Xmx256m -Xss512k + * -Xint + * -XX:+UnlockExperimentalVMOptions -XX:+UseEpsilonGC + * gc.epsilon.TestManyThreads + * + * @run main/othervm -XX:-UseTLAB -Xmx256m -Xss512k + * -Xbatch -Xcomp -XX:TieredStopAtLevel=1 + * -XX:+UnlockExperimentalVMOptions -XX:+UseEpsilonGC + * gc.epsilon.TestManyThreads + * + * @run main/othervm -XX:-UseTLAB -Xmx256m -Xss512k + * -Xbatch -Xcomp -XX:-TieredCompilation + * -XX:+UnlockExperimentalVMOptions -XX:+UseEpsilonGC + * gc.epsilon.TestManyThreads + * + * @run main/othervm -XX:+UseTLAB -Xmx256m -Xss512k + * -XX:+UnlockExperimentalVMOptions -XX:+UseEpsilonGC + * gc.epsilon.TestManyThreads + * + * @run main/othervm -XX:+UseTLAB -Xmx256m -Xss512k + * -Xint + * -XX:+UnlockExperimentalVMOptions -XX:+UseEpsilonGC + * gc.epsilon.TestManyThreads + * + * @run main/othervm -XX:+UseTLAB -Xmx256m -Xss512k + * -Xbatch -Xcomp -XX:TieredStopAtLevel=1 + * -XX:+UnlockExperimentalVMOptions -XX:+UseEpsilonGC + * gc.epsilon.TestManyThreads + * + * @run main/othervm -XX:+UseTLAB -Xmx256m -Xss512k + * -Xbatch -Xcomp -XX:-TieredCompilation + * -XX:+UnlockExperimentalVMOptions -XX:+UseEpsilonGC + * gc.epsilon.TestManyThreads */ import java.util.concurrent.atomic.*; diff --git a/test/hotspot/jtreg/gc/epsilon/TestMaxTLAB.java b/test/hotspot/jtreg/gc/epsilon/TestMaxTLAB.java index a345af6206c..c3ad148f014 100644 --- a/test/hotspot/jtreg/gc/epsilon/TestMaxTLAB.java +++ b/test/hotspot/jtreg/gc/epsilon/TestMaxTLAB.java @@ -29,15 +29,49 @@ * @summary Check EpsilonMaxTLAB options * @bug 8212177 * - * @run main/othervm -XX:+UnlockExperimentalVMOptions -Xmx128m -XX:+UseEpsilonGC -XX:EpsilonMaxTLABSize=1 gc.epsilon.TestMaxTLAB - * @run main/othervm -XX:+UnlockExperimentalVMOptions -Xmx128m -XX:+UseEpsilonGC -XX:EpsilonMaxTLABSize=1K gc.epsilon.TestMaxTLAB - * @run main/othervm -XX:+UnlockExperimentalVMOptions -Xmx128m -XX:+UseEpsilonGC -XX:EpsilonMaxTLABSize=1M gc.epsilon.TestMaxTLAB - * @run main/othervm -XX:+UnlockExperimentalVMOptions -Xmx128m -XX:+UseEpsilonGC -XX:EpsilonMaxTLABSize=12345 gc.epsilon.TestMaxTLAB - * - * @run main/othervm -XX:+UnlockExperimentalVMOptions -Xmx128m -XX:+UseEpsilonGC -XX:EpsilonMaxTLABSize=1 -XX:+IgnoreUnrecognizedVMOptions -XX:ObjectAlignmentInBytes=16 gc.epsilon.TestMaxTLAB - * @run main/othervm -XX:+UnlockExperimentalVMOptions -Xmx128m -XX:+UseEpsilonGC -XX:EpsilonMaxTLABSize=1K -XX:+IgnoreUnrecognizedVMOptions -XX:ObjectAlignmentInBytes=16 gc.epsilon.TestMaxTLAB - * @run main/othervm -XX:+UnlockExperimentalVMOptions -Xmx128m -XX:+UseEpsilonGC -XX:EpsilonMaxTLABSize=1M -XX:+IgnoreUnrecognizedVMOptions -XX:ObjectAlignmentInBytes=16 gc.epsilon.TestMaxTLAB - * @run main/othervm -XX:+UnlockExperimentalVMOptions -Xmx128m -XX:+UseEpsilonGC -XX:EpsilonMaxTLABSize=12345 -XX:+IgnoreUnrecognizedVMOptions -XX:ObjectAlignmentInBytes=16 gc.epsilon.TestMaxTLAB + * @run main/othervm -Xmx64m + * -XX:+UnlockExperimentalVMOptions -XX:+UseEpsilonGC + * -XX:EpsilonMaxTLABSize=1 + * gc.epsilon.TestMaxTLAB + * + * @run main/othervm -Xmx64m + * -XX:+UnlockExperimentalVMOptions -XX:+UseEpsilonGC + * -XX:EpsilonMaxTLABSize=1K + * gc.epsilon.TestMaxTLAB + * + * @run main/othervm -Xmx64m + * -XX:+UnlockExperimentalVMOptions -XX:+UseEpsilonGC + * -XX:EpsilonMaxTLABSize=1M + * gc.epsilon.TestMaxTLAB + * + * @run main/othervm -Xmx64m + * -XX:+UnlockExperimentalVMOptions -XX:+UseEpsilonGC + * -XX:EpsilonMaxTLABSize=12345 + * gc.epsilon.TestMaxTLAB + * + * @run main/othervm -Xmx64m + * -XX:+UnlockExperimentalVMOptions -XX:+UseEpsilonGC + * -XX:EpsilonMaxTLABSize=1 + * -XX:+IgnoreUnrecognizedVMOptions -XX:ObjectAlignmentInBytes=16 + * gc.epsilon.TestMaxTLAB + * + * @run main/othervm -Xmx64m + * -XX:+UnlockExperimentalVMOptions -XX:+UseEpsilonGC + * -XX:EpsilonMaxTLABSize=1K + * -XX:+IgnoreUnrecognizedVMOptions -XX:ObjectAlignmentInBytes=16 + * gc.epsilon.TestMaxTLAB + * + * @run main/othervm -Xmx64m + * -XX:+UnlockExperimentalVMOptions -XX:+UseEpsilonGC + * -XX:EpsilonMaxTLABSize=1M + * -XX:+IgnoreUnrecognizedVMOptions -XX:ObjectAlignmentInBytes=16 + * gc.epsilon.TestMaxTLAB + * + * @run main/othervm -Xmx64m + * -XX:+UnlockExperimentalVMOptions -XX:+UseEpsilonGC + * -XX:EpsilonMaxTLABSize=12345 + * -XX:+IgnoreUnrecognizedVMOptions -XX:ObjectAlignmentInBytes=16 + * gc.epsilon.TestMaxTLAB */ public class TestMaxTLAB { diff --git a/test/hotspot/jtreg/gc/epsilon/TestMemoryMXBeans.java b/test/hotspot/jtreg/gc/epsilon/TestMemoryMXBeans.java index 597ce76f829..a9ff8d00ba0 100644 --- a/test/hotspot/jtreg/gc/epsilon/TestMemoryMXBeans.java +++ b/test/hotspot/jtreg/gc/epsilon/TestMemoryMXBeans.java @@ -30,9 +30,21 @@ * @summary Test JMX memory beans * @modules java.base/jdk.internal.misc * java.management - * @run main/othervm -XX:+UnlockExperimentalVMOptions -XX:+UseEpsilonGC -Xmx1g gc.epsilon.TestMemoryMXBeans -1 1024 - * @run main/othervm -XX:+UnlockExperimentalVMOptions -XX:+UseEpsilonGC -Xms1g -Xmx1g gc.epsilon.TestMemoryMXBeans 1024 1024 - * @run main/othervm -XX:+UnlockExperimentalVMOptions -XX:+UseEpsilonGC -Xms128m -Xmx1g gc.epsilon.TestMemoryMXBeans 128 1024 + * + * @run main/othervm -Xmx256m + * -XX:+UnlockExperimentalVMOptions -XX:+UseEpsilonGC + * gc.epsilon.TestMemoryMXBeans + * -1 256 + * + * @run main/othervm -Xmx256m -Xmx256m + * -XX:+UnlockExperimentalVMOptions -XX:+UseEpsilonGC + * gc.epsilon.TestMemoryMXBeans + * 256 256 + * + * @run main/othervm -Xms64m -Xmx256m + * -XX:+UnlockExperimentalVMOptions -XX:+UseEpsilonGC + * gc.epsilon.TestMemoryMXBeans + * 64 256 */ import java.lang.management.*; diff --git a/test/hotspot/jtreg/gc/epsilon/TestMemoryPools.java b/test/hotspot/jtreg/gc/epsilon/TestMemoryPools.java index 90b5471cb7f..e05a257edc7 100644 --- a/test/hotspot/jtreg/gc/epsilon/TestMemoryPools.java +++ b/test/hotspot/jtreg/gc/epsilon/TestMemoryPools.java @@ -26,11 +26,14 @@ /** * @test TestMemoryPools - * @requires vm.gc.Epsilon & os.maxMemory >= 2G + * @requires vm.gc.Epsilon * @summary Test JMX memory pools * @modules java.base/jdk.internal.misc * java.management - * @run main/othervm -XX:+UnlockExperimentalVMOptions -XX:+UseEpsilonGC -Xmx1g -Xms1g gc.epsilon.TestMemoryPools + * + * @run main/othervm -Xms64m -Xmx64m + * -XX:+UnlockExperimentalVMOptions -XX:+UseEpsilonGC + * gc.epsilon.TestMemoryPools */ import java.lang.management.*; diff --git a/test/hotspot/jtreg/gc/epsilon/TestObjects.java b/test/hotspot/jtreg/gc/epsilon/TestObjects.java index 7cb5c4a8ae3..a63896fd19b 100644 --- a/test/hotspot/jtreg/gc/epsilon/TestObjects.java +++ b/test/hotspot/jtreg/gc/epsilon/TestObjects.java @@ -30,17 +30,43 @@ * @summary Epsilon is able to allocate objects, and does not corrupt their state * @library /test/lib * - * @run main/othervm -Xmx128m -XX:+UseTLAB -XX:+UnlockExperimentalVMOptions -XX:+UseEpsilonGC gc.epsilon.TestObjects - * @run main/othervm -Xmx128m -Xint -XX:+UseTLAB -XX:+UnlockExperimentalVMOptions -XX:+UseEpsilonGC gc.epsilon.TestObjects - * @run main/othervm -Xmx128m -Xbatch -Xcomp -XX:+UseTLAB -XX:+UnlockExperimentalVMOptions -XX:+UseEpsilonGC gc.epsilon.TestObjects - * @run main/othervm -Xmx128m -Xbatch -Xcomp -XX:TieredStopAtLevel=1 -XX:+UseTLAB -XX:+UnlockExperimentalVMOptions -XX:+UseEpsilonGC gc.epsilon.TestObjects - * @run main/othervm -Xmx128m -Xbatch -Xcomp -XX:-TieredCompilation -XX:+UseTLAB -XX:+UnlockExperimentalVMOptions -XX:+UseEpsilonGC gc.epsilon.TestObjects + * @run main/othervm -XX:+UseTLAB -Xmx256m + * -XX:+UnlockExperimentalVMOptions -XX:+UseEpsilonGC + * gc.epsilon.TestObjects * - * @run main/othervm -Xmx128m -XX:-UseTLAB -XX:+UnlockExperimentalVMOptions -XX:+UseEpsilonGC gc.epsilon.TestObjects - * @run main/othervm -Xmx128m -Xint -XX:-UseTLAB -XX:+UnlockExperimentalVMOptions -XX:+UseEpsilonGC gc.epsilon.TestObjects - * @run main/othervm -Xmx128m -Xbatch -Xcomp -XX:-UseTLAB -XX:+UnlockExperimentalVMOptions -XX:+UseEpsilonGC gc.epsilon.TestObjects - * @run main/othervm -Xmx128m -Xbatch -Xcomp -XX:TieredStopAtLevel=1 -XX:-UseTLAB -XX:+UnlockExperimentalVMOptions -XX:+UseEpsilonGC gc.epsilon.TestObjects - * @run main/othervm -Xmx128m -Xbatch -Xcomp -XX:-TieredCompilation -XX:-UseTLAB -XX:+UnlockExperimentalVMOptions -XX:+UseEpsilonGC gc.epsilon.TestObjects + * @run main/othervm -XX:+UseTLAB -Xmx256m + * -Xint + * -XX:+UnlockExperimentalVMOptions -XX:+UseEpsilonGC + * gc.epsilon.TestObjects + * + * @run main/othervm -XX:+UseTLAB -Xmx256m + * -Xbatch -Xcomp -XX:TieredStopAtLevel=1 + * -XX:+UnlockExperimentalVMOptions -XX:+UseEpsilonGC + * gc.epsilon.TestObjects + * + * @run main/othervm -XX:+UseTLAB -Xmx256m + * -Xbatch -Xcomp -XX:-TieredCompilation + * -XX:+UnlockExperimentalVMOptions -XX:+UseEpsilonGC + * gc.epsilon.TestObjects + * + * @run main/othervm -XX:-UseTLAB -Xmx256m + * -XX:+UnlockExperimentalVMOptions -XX:+UseEpsilonGC + * gc.epsilon.TestObjects + * + * @run main/othervm -XX:-UseTLAB -Xmx256m + * -Xint + * -XX:+UnlockExperimentalVMOptions -XX:+UseEpsilonGC + * gc.epsilon.TestObjects + * + * @run main/othervm -XX:-UseTLAB -Xmx256m + * -Xbatch -Xcomp -XX:TieredStopAtLevel=1 + * -XX:+UnlockExperimentalVMOptions -XX:+UseEpsilonGC + * gc.epsilon.TestObjects + * + * @run main/othervm -XX:-UseTLAB -Xmx256m + * -Xbatch -Xcomp -XX:-TieredCompilation + * -XX:+UnlockExperimentalVMOptions -XX:+UseEpsilonGC + * gc.epsilon.TestObjects */ import java.util.Random; diff --git a/test/hotspot/jtreg/gc/epsilon/TestPrintHeapSteps.java b/test/hotspot/jtreg/gc/epsilon/TestPrintHeapSteps.java index 5feef31b381..fb131b86eaa 100644 --- a/test/hotspot/jtreg/gc/epsilon/TestPrintHeapSteps.java +++ b/test/hotspot/jtreg/gc/epsilon/TestPrintHeapSteps.java @@ -27,9 +27,21 @@ * @test TestPrintSteps * @requires vm.gc.Epsilon * @summary Tests -XX:EpsilonPrintHeapSteps works - * @run main/othervm -XX:+UnlockExperimentalVMOptions -XX:+UseEpsilonGC -Xlog:gc -XX:EpsilonPrintHeapSteps=0 gc.epsilon.TestPrintHeapSteps - * @run main/othervm -XX:+UnlockExperimentalVMOptions -XX:+UseEpsilonGC -Xlog:gc -XX:EpsilonPrintHeapSteps=1 gc.epsilon.TestPrintHeapSteps - * @run main/othervm -XX:+UnlockExperimentalVMOptions -XX:+UseEpsilonGC -Xlog:gc -XX:EpsilonPrintHeapSteps=1000 gc.epsilon.TestPrintHeapSteps + * + * @run main/othervm -Xmx64m -Xlog:gc + * -XX:+UnlockExperimentalVMOptions -XX:+UseEpsilonGC + * -XX:EpsilonPrintHeapSteps=0 + * gc.epsilon.TestPrintHeapSteps + * + * @run main/othervm -Xmx64m -Xlog:gc + * -XX:+UnlockExperimentalVMOptions -XX:+UseEpsilonGC + * -XX:EpsilonPrintHeapSteps=1 + * gc.epsilon.TestPrintHeapSteps + * + * @run main/othervm -Xmx64m -Xlog:gc + * -XX:+UnlockExperimentalVMOptions -XX:+UseEpsilonGC + * -XX:EpsilonPrintHeapSteps=1000 + * gc.epsilon.TestPrintHeapSteps */ public class TestPrintHeapSteps { diff --git a/test/hotspot/jtreg/gc/epsilon/TestRefArrays.java b/test/hotspot/jtreg/gc/epsilon/TestRefArrays.java index 0dac53e4832..2be731eba62 100644 --- a/test/hotspot/jtreg/gc/epsilon/TestRefArrays.java +++ b/test/hotspot/jtreg/gc/epsilon/TestRefArrays.java @@ -30,24 +30,50 @@ * @summary Epsilon is able to allocate arrays, and does not corrupt their state * @library /test/lib * - * @run main/othervm -Xmx1g -XX:+UseTLAB -XX:+UnlockExperimentalVMOptions -XX:+UseEpsilonGC gc.epsilon.TestRefArrays - * @run main/othervm -Xmx1g -Xint -XX:+UseTLAB -XX:+UnlockExperimentalVMOptions -XX:+UseEpsilonGC gc.epsilon.TestRefArrays - * @run main/othervm -Xmx1g -Xbatch -Xcomp -XX:+UseTLAB -XX:+UnlockExperimentalVMOptions -XX:+UseEpsilonGC gc.epsilon.TestRefArrays - * @run main/othervm -Xmx1g -Xbatch -Xcomp -XX:TieredStopAtLevel=1 -XX:+UseTLAB -XX:+UnlockExperimentalVMOptions -XX:+UseEpsilonGC gc.epsilon.TestRefArrays - * @run main/othervm -Xmx1g -Xbatch -Xcomp -XX:-TieredCompilation -XX:+UseTLAB -XX:+UnlockExperimentalVMOptions -XX:+UseEpsilonGC gc.epsilon.TestRefArrays + * @run main/othervm -XX:+UseTLAB -Xmx256m + * -XX:+UnlockExperimentalVMOptions -XX:+UseEpsilonGC + * gc.epsilon.TestRefArrays * - * @run main/othervm -Xmx1g -XX:-UseTLAB -XX:+UnlockExperimentalVMOptions -XX:+UseEpsilonGC gc.epsilon.TestRefArrays - * @run main/othervm -Xmx1g -Xint -XX:-UseTLAB -XX:+UnlockExperimentalVMOptions -XX:+UseEpsilonGC gc.epsilon.TestRefArrays - * @run main/othervm -Xmx1g -Xbatch -Xcomp -XX:-UseTLAB -XX:+UnlockExperimentalVMOptions -XX:+UseEpsilonGC gc.epsilon.TestRefArrays - * @run main/othervm -Xmx1g -Xbatch -Xcomp -XX:TieredStopAtLevel=1 -XX:-UseTLAB -XX:+UnlockExperimentalVMOptions -XX:+UseEpsilonGC gc.epsilon.TestRefArrays - * @run main/othervm -Xmx1g -Xbatch -Xcomp -XX:-TieredCompilation -XX:-UseTLAB -XX:+UnlockExperimentalVMOptions -XX:+UseEpsilonGC gc.epsilon.TestRefArrays + * @run main/othervm -XX:+UseTLAB -Xmx256m + * -Xint + * -XX:+UnlockExperimentalVMOptions -XX:+UseEpsilonGC + * gc.epsilon.TestRefArrays + * + * @run main/othervm -XX:+UseTLAB -Xmx256m + * -Xbatch -Xcomp -XX:TieredStopAtLevel=1 + * -XX:+UnlockExperimentalVMOptions -XX:+UseEpsilonGC + * gc.epsilon.TestRefArrays + * + * @run main/othervm -XX:+UseTLAB -Xmx256m + * -Xbatch -Xcomp -XX:-TieredCompilation + * -XX:+UnlockExperimentalVMOptions -XX:+UseEpsilonGC + * gc.epsilon.TestRefArrays + * + * @run main/othervm -XX:-UseTLAB -Xmx256m + * -XX:+UnlockExperimentalVMOptions -XX:+UseEpsilonGC + * gc.epsilon.TestRefArrays + * + * @run main/othervm -XX:-UseTLAB -Xmx256m + * -Xint + * -XX:+UnlockExperimentalVMOptions -XX:+UseEpsilonGC + * gc.epsilon.TestRefArrays + * + * @run main/othervm -XX:-UseTLAB -Xmx256m + * -Xbatch -Xcomp -XX:TieredStopAtLevel=1 + * -XX:+UnlockExperimentalVMOptions -XX:+UseEpsilonGC + * gc.epsilon.TestRefArrays + * + * @run main/othervm -XX:-UseTLAB -Xmx256m + * -Xbatch -Xcomp -XX:-TieredCompilation + * -XX:+UnlockExperimentalVMOptions -XX:+UseEpsilonGC + * gc.epsilon.TestRefArrays */ import java.util.Random; import jdk.test.lib.Utils; public class TestRefArrays { - static int COUNT = Integer.getInteger("count", 1000); // ~500 MB allocation + static int COUNT = Integer.getInteger("count", 200); // ~100 MB allocation static MyObject[][] arr; diff --git a/test/hotspot/jtreg/gc/epsilon/TestUpdateCountersSteps.java b/test/hotspot/jtreg/gc/epsilon/TestUpdateCountersSteps.java index 94e743f65c6..6bf15805313 100644 --- a/test/hotspot/jtreg/gc/epsilon/TestUpdateCountersSteps.java +++ b/test/hotspot/jtreg/gc/epsilon/TestUpdateCountersSteps.java @@ -27,10 +27,26 @@ * @test TestUpdateCountersSteps * @requires vm.gc.Epsilon * @summary Test EpsilonUpdateCountersStep works - * @run main/othervm -XX:+UnlockExperimentalVMOptions -XX:+UseEpsilonGC -Xlog:gc -XX:EpsilonUpdateCountersStep=1 gc.epsilon.TestUpdateCountersSteps - * @run main/othervm -XX:+UnlockExperimentalVMOptions -XX:+UseEpsilonGC -Xlog:gc -XX:EpsilonUpdateCountersStep=10 gc.epsilon.TestUpdateCountersSteps - * @run main/othervm -XX:+UnlockExperimentalVMOptions -XX:+UseEpsilonGC -Xlog:gc -XX:EpsilonUpdateCountersStep=100 gc.epsilon.TestUpdateCountersSteps - * @run main/othervm -XX:+UnlockExperimentalVMOptions -XX:+UseEpsilonGC -Xlog:gc -XX:EpsilonUpdateCountersStep=1000 gc.epsilon.TestUpdateCountersSteps + * + * @run main/othervm -Xmx64m -Xlog:gc + * -XX:+UnlockExperimentalVMOptions -XX:+UseEpsilonGC + * -XX:EpsilonUpdateCountersStep=1 + * gc.epsilon.TestUpdateCountersSteps + * + * @run main/othervm -Xmx64m -Xlog:gc + * -XX:+UnlockExperimentalVMOptions -XX:+UseEpsilonGC + * -XX:EpsilonUpdateCountersStep=10 + * gc.epsilon.TestUpdateCountersSteps + * + * @run main/othervm -Xmx64m -Xlog:gc + * -XX:+UnlockExperimentalVMOptions -XX:+UseEpsilonGC + * -XX:EpsilonUpdateCountersStep=100 + * gc.epsilon.TestUpdateCountersSteps + * + * @run main/othervm -Xmx64m -Xlog:gc + * -XX:+UnlockExperimentalVMOptions -XX:+UseEpsilonGC + * -XX:EpsilonUpdateCountersStep=1000 + * gc.epsilon.TestUpdateCountersSteps */ public class TestUpdateCountersSteps { diff --git a/test/hotspot/jtreg/gc/stringdedup/TestStringDeduplicationAgeThreshold.java b/test/hotspot/jtreg/gc/stringdedup/TestStringDeduplicationAgeThreshold.java index 23261c9bea7..6034b9b0ecf 100644 --- a/test/hotspot/jtreg/gc/stringdedup/TestStringDeduplicationAgeThreshold.java +++ b/test/hotspot/jtreg/gc/stringdedup/TestStringDeduplicationAgeThreshold.java @@ -23,6 +23,19 @@ package gc.stringdedup; +/* + * @test TestStringDeduplicationAgeThreshold + * @summary Test string deduplication age threshold + * @bug 8029075 + * @requires vm.gc.Serial + * @library /test/lib + * @library / + * @modules java.base/jdk.internal.misc:open + * @modules java.base/java.lang:open + * java.management + * @run driver gc.stringdedup.TestStringDeduplicationAgeThreshold Serial + */ + /* * @test TestStringDeduplicationAgeThreshold * @summary Test string deduplication age threshold @@ -36,6 +49,19 @@ * @run driver gc.stringdedup.TestStringDeduplicationAgeThreshold G1 */ +/* + * @test TestStringDeduplicationAgeThreshold + * @summary Test string deduplication age threshold + * @bug 8029075 + * @requires vm.gc.Parallel + * @library /test/lib + * @library / + * @modules java.base/jdk.internal.misc:open + * @modules java.base/java.lang:open + * java.management + * @run driver gc.stringdedup.TestStringDeduplicationAgeThreshold Parallel + */ + /* * @test TestStringDeduplicationAgeThreshold * @summary Test string deduplication age threshold diff --git a/test/hotspot/jtreg/gc/stringdedup/TestStringDeduplicationFullGC.java b/test/hotspot/jtreg/gc/stringdedup/TestStringDeduplicationFullGC.java index e189cb8a1fb..724e69f8137 100644 --- a/test/hotspot/jtreg/gc/stringdedup/TestStringDeduplicationFullGC.java +++ b/test/hotspot/jtreg/gc/stringdedup/TestStringDeduplicationFullGC.java @@ -23,6 +23,19 @@ package gc.stringdedup; +/* + * @test TestStringDeduplicationFullGC + * @summary Test string deduplication during full GC + * @bug 8029075 + * @requires vm.gc.Serial + * @library /test/lib + * @library / + * @modules java.base/jdk.internal.misc:open + * @modules java.base/java.lang:open + * java.management + * @run driver gc.stringdedup.TestStringDeduplicationFullGC Serial + */ + /* * @test TestStringDeduplicationFullGC * @summary Test string deduplication during full GC @@ -36,6 +49,19 @@ * @run driver gc.stringdedup.TestStringDeduplicationFullGC G1 */ +/* + * @test TestStringDeduplicationFullGC + * @summary Test string deduplication during full GC + * @bug 8029075 + * @requires vm.gc.Parallel + * @library /test/lib + * @library / + * @modules java.base/jdk.internal.misc:open + * @modules java.base/java.lang:open + * java.management + * @run driver gc.stringdedup.TestStringDeduplicationFullGC Parallel + */ + /* * @test TestStringDeduplicationFullGC * @summary Test string deduplication during full GC diff --git a/test/hotspot/jtreg/gc/stringdedup/TestStringDeduplicationInterned.java b/test/hotspot/jtreg/gc/stringdedup/TestStringDeduplicationInterned.java index e3cd39baf40..790c7548161 100644 --- a/test/hotspot/jtreg/gc/stringdedup/TestStringDeduplicationInterned.java +++ b/test/hotspot/jtreg/gc/stringdedup/TestStringDeduplicationInterned.java @@ -23,6 +23,19 @@ package gc.stringdedup; +/* + * @test TestStringDeduplicationInterned + * @summary Test string deduplication of interned strings + * @bug 8029075 + * @requires vm.gc.Serial + * @library /test/lib + * @library / + * @modules java.base/jdk.internal.misc:open + * @modules java.base/java.lang:open + * java.management + * @run driver gc.stringdedup.TestStringDeduplicationInterned Serial + */ + /* * @test TestStringDeduplicationInterned * @summary Test string deduplication of interned strings @@ -36,6 +49,19 @@ * @run driver gc.stringdedup.TestStringDeduplicationInterned G1 */ +/* + * @test TestStringDeduplicationInterned + * @summary Test string deduplication of interned strings + * @bug 8029075 + * @requires vm.gc.Parallel + * @library /test/lib + * @library / + * @modules java.base/jdk.internal.misc:open + * @modules java.base/java.lang:open + * java.management + * @run driver gc.stringdedup.TestStringDeduplicationInterned Parallel + */ + /* * @test TestStringDeduplicationInterned * @summary Test string deduplication of interned strings diff --git a/test/hotspot/jtreg/gc/stringdedup/TestStringDeduplicationPrintOptions.java b/test/hotspot/jtreg/gc/stringdedup/TestStringDeduplicationPrintOptions.java index 6f75448bd0b..95480700f90 100644 --- a/test/hotspot/jtreg/gc/stringdedup/TestStringDeduplicationPrintOptions.java +++ b/test/hotspot/jtreg/gc/stringdedup/TestStringDeduplicationPrintOptions.java @@ -23,6 +23,19 @@ package gc.stringdedup; +/* + * @test TestStringDeduplicationPrintOptions + * @summary Test string deduplication print options + * @bug 8029075 + * @requires vm.gc.Serial + * @library /test/lib + * @library / + * @modules java.base/jdk.internal.misc:open + * @modules java.base/java.lang:open + * java.management + * @run driver gc.stringdedup.TestStringDeduplicationPrintOptions Serial + */ + /* * @test TestStringDeduplicationPrintOptions * @summary Test string deduplication print options @@ -36,6 +49,19 @@ * @run driver gc.stringdedup.TestStringDeduplicationPrintOptions G1 */ +/* + * @test TestStringDeduplicationPrintOptions + * @summary Test string deduplication print options + * @bug 8029075 + * @requires vm.gc.Parallel + * @library /test/lib + * @library / + * @modules java.base/jdk.internal.misc:open + * @modules java.base/java.lang:open + * java.management + * @run driver gc.stringdedup.TestStringDeduplicationPrintOptions Parallel + */ + /* * @test TestStringDeduplicationPrintOptions * @summary Test string deduplication print options diff --git a/test/hotspot/jtreg/gc/stringdedup/TestStringDeduplicationTableResize.java b/test/hotspot/jtreg/gc/stringdedup/TestStringDeduplicationTableResize.java index 0b2071f514c..e3227aec448 100644 --- a/test/hotspot/jtreg/gc/stringdedup/TestStringDeduplicationTableResize.java +++ b/test/hotspot/jtreg/gc/stringdedup/TestStringDeduplicationTableResize.java @@ -23,6 +23,19 @@ package gc.stringdedup; +/* + * @test TestStringDeduplicationTableResize + * @summary Test string deduplication table resize + * @bug 8029075 + * @requires vm.gc.Serial + * @library /test/lib + * @library / + * @modules java.base/jdk.internal.misc:open + * @modules java.base/java.lang:open + * java.management + * @run driver gc.stringdedup.TestStringDeduplicationTableResize Serial + */ + /* * @test TestStringDeduplicationTableResize * @summary Test string deduplication table resize @@ -36,6 +49,19 @@ * @run driver gc.stringdedup.TestStringDeduplicationTableResize G1 */ +/* + * @test TestStringDeduplicationTableResize + * @summary Test string deduplication table resize + * @bug 8029075 + * @requires vm.gc.Parallel + * @library /test/lib + * @library / + * @modules java.base/jdk.internal.misc:open + * @modules java.base/java.lang:open + * java.management + * @run driver gc.stringdedup.TestStringDeduplicationTableResize Parallel + */ + /* * @test TestStringDeduplicationTableResize * @summary Test string deduplication table resize diff --git a/test/hotspot/jtreg/gc/stringdedup/TestStringDeduplicationYoungGC.java b/test/hotspot/jtreg/gc/stringdedup/TestStringDeduplicationYoungGC.java index 9fc98056def..cb6aaf2cc61 100644 --- a/test/hotspot/jtreg/gc/stringdedup/TestStringDeduplicationYoungGC.java +++ b/test/hotspot/jtreg/gc/stringdedup/TestStringDeduplicationYoungGC.java @@ -23,6 +23,19 @@ package gc.stringdedup; +/* + * @test TestStringDeduplicationYoungGC + * @summary Test string deduplication during young GC + * @bug 8029075 + * @requires vm.gc.Serial + * @library /test/lib + * @library / + * @modules java.base/jdk.internal.misc:open + * @modules java.base/java.lang:open + * java.management + * @run driver gc.stringdedup.TestStringDeduplicationYoungGC Serial + */ + /* * @test TestStringDeduplicationYoungGC * @summary Test string deduplication during young GC @@ -36,6 +49,19 @@ * @run driver gc.stringdedup.TestStringDeduplicationYoungGC G1 */ +/* + * @test TestStringDeduplicationYoungGC + * @summary Test string deduplication during young GC + * @bug 8029075 + * @requires vm.gc.Parallel + * @library /test/lib + * @library / + * @modules java.base/jdk.internal.misc:open + * @modules java.base/java.lang:open + * java.management + * @run driver gc.stringdedup.TestStringDeduplicationYoungGC Parallel + */ + /* * @test TestStringDeduplicationYoungGC * @summary Test string deduplication during young GC diff --git a/test/hotspot/jtreg/runtime/CommandLine/CompilerConfigFileWarning.java b/test/hotspot/jtreg/runtime/CommandLine/CompilerConfigFileWarning.java index 28b0eb375d1..24738786115 100644 --- a/test/hotspot/jtreg/runtime/CommandLine/CompilerConfigFileWarning.java +++ b/test/hotspot/jtreg/runtime/CommandLine/CompilerConfigFileWarning.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 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 @@ -48,6 +48,8 @@ public static void main(String[] args) throws Exception { pb = ProcessTools.createJavaProcessBuilder("-XX:CompileCommandFile=hs_comp.txt", "-version"); output = new OutputAnalyzer(pb.start()); + // problems in CompileCommandFile are treated as warnings + output.shouldHaveExitValue(0); output.shouldContain("An error occurred during parsing"); output.shouldContain("Unrecognized option 'aaa'"); output.shouldContain("aaa, aaa"); @@ -60,6 +62,7 @@ public static void main(String[] args) throws Exception { pb = ProcessTools.createJavaProcessBuilder("-version"); output = new OutputAnalyzer(pb.start()); + output.shouldHaveExitValue(0); output.shouldContain("warning: .hotspot_compiler file is present but has been ignored. Run with -XX:CompileCommandFile=.hotspot_compiler to load the file."); } } diff --git a/test/hotspot/jtreg/runtime/CommandLine/ConfigFileWarning.java b/test/hotspot/jtreg/runtime/CommandLine/ConfigFileWarning.java index 1eca7c76d67..862ef4c9ce0 100644 --- a/test/hotspot/jtreg/runtime/CommandLine/ConfigFileWarning.java +++ b/test/hotspot/jtreg/runtime/CommandLine/ConfigFileWarning.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 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 @@ -59,6 +59,7 @@ public static void main(String[] args) throws Exception { pb = ProcessTools.createJavaProcessBuilder("-version"); output = new OutputAnalyzer(pb.start()); + output.shouldHaveExitValue(0); output.shouldContain("warning: .hotspotrc file is present but has been ignored. Run with -XX:Flags=.hotspotrc to load the file."); } } diff --git a/test/hotspot/jtreg/runtime/CommandLine/DoubleFlagWithIntegerValue.java b/test/hotspot/jtreg/runtime/CommandLine/DoubleFlagWithIntegerValue.java index 9824764e5b6..f26b7399671 100644 --- a/test/hotspot/jtreg/runtime/CommandLine/DoubleFlagWithIntegerValue.java +++ b/test/hotspot/jtreg/runtime/CommandLine/DoubleFlagWithIntegerValue.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 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 @@ -36,7 +36,7 @@ public class DoubleFlagWithIntegerValue { public static void testDoubleFlagWithValue(String value) throws Exception { - ProcessBuilder pb = ProcessTools.createJavaProcessBuilder("-XX:G1ConcMarkStepDurationMillis=" + value, "-version"); + ProcessBuilder pb = ProcessTools.createJavaProcessBuilder("-XX:SweeperThreshold=" + value, "-version"); OutputAnalyzer output = new OutputAnalyzer(pb.start()); output.shouldNotContain("Improperly specified VM option"); output.shouldHaveExitValue(0); diff --git a/test/hotspot/jtreg/runtime/CommandLine/ObsoleteFlagErrorMessage.java b/test/hotspot/jtreg/runtime/CommandLine/ObsoleteFlagErrorMessage.java index 0e700d73db4..485d3cc57f5 100644 --- a/test/hotspot/jtreg/runtime/CommandLine/ObsoleteFlagErrorMessage.java +++ b/test/hotspot/jtreg/runtime/CommandLine/ObsoleteFlagErrorMessage.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 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 @@ -52,6 +52,7 @@ public static void main(String[] args) throws Exception { "-XX:+" + flag, "-version"); OutputAnalyzer output2 = new OutputAnalyzer(pb2.start()); + output2.shouldHaveExitValue(0); output2.shouldContain("Ignoring option").shouldContain("support was removed"); output2.shouldContain(flag); } diff --git a/test/hotspot/jtreg/runtime/CommandLine/PrintTouchedMethods.java b/test/hotspot/jtreg/runtime/CommandLine/PrintTouchedMethods.java index 5db346a633e..601392fa343 100644 --- a/test/hotspot/jtreg/runtime/CommandLine/PrintTouchedMethods.java +++ b/test/hotspot/jtreg/runtime/CommandLine/PrintTouchedMethods.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2016, 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 @@ -48,6 +48,7 @@ public static void main(String args[]) throws Exception { // UnlockDiagnostic turned off, should fail OutputAnalyzer output = new OutputAnalyzer(pb.start()); + output.shouldNotHaveExitValue(0); output.shouldContain("Error: VM option 'LogTouchedMethods' is diagnostic and must be enabled via -XX:+UnlockDiagnosticVMOptions."); output.shouldContain("Error: Could not create the Java Virtual Machine."); diff --git a/test/hotspot/jtreg/runtime/CommandLine/TestHexArguments.java b/test/hotspot/jtreg/runtime/CommandLine/TestHexArguments.java index 84c3385762d..9d864610c57 100644 --- a/test/hotspot/jtreg/runtime/CommandLine/TestHexArguments.java +++ b/test/hotspot/jtreg/runtime/CommandLine/TestHexArguments.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 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,6 +47,7 @@ public static void main(String args[]) throws Exception { pb = ProcessTools.createJavaProcessBuilder( "-XX:SharedBaseAddress=1D000000", "-version"); output = new OutputAnalyzer(pb.start()); + output.shouldNotHaveExitValue(0); output.shouldContain("Could not create the Java Virtual Machine"); } } diff --git a/test/hotspot/jtreg/runtime/CommandLine/TestVMOptions.java b/test/hotspot/jtreg/runtime/CommandLine/TestVMOptions.java index 4eeedb1bfd2..8d13e1ab50d 100644 --- a/test/hotspot/jtreg/runtime/CommandLine/TestVMOptions.java +++ b/test/hotspot/jtreg/runtime/CommandLine/TestVMOptions.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 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,11 +42,13 @@ public static void main(String[] args) throws Exception { "-XX:+IgnoreUnrecognizedVMOptions", "-XX:+PrintFlagsInitial"); OutputAnalyzer output = new OutputAnalyzer(pb.start()); + output.shouldHaveExitValue(0); output.shouldContain("bool UseSerialGC"); pb = ProcessTools.createJavaProcessBuilder( "-XX:-PrintVMOptions", "-version"); output = new OutputAnalyzer(pb.start()); + output.shouldHaveExitValue(0); output.shouldMatch("(openjdk|java)\\sversion"); File dir = new File(System.getProperty("test.src", ".")); @@ -54,6 +56,7 @@ public static void main(String[] args) throws Exception { String s = file.getAbsolutePath(); pb = ProcessTools.createJavaProcessBuilder("-XX:Flags="+s); output = new OutputAnalyzer(pb.start()); + output.shouldNotHaveExitValue(0); output.shouldContain("VM option '-IgnoreUnrecognizedVMOptions'"); } } diff --git a/test/hotspot/jtreg/runtime/CommandLine/VMOptionWarning.java b/test/hotspot/jtreg/runtime/CommandLine/VMOptionWarning.java index c2c3f8927a9..01305cc9162 100644 --- a/test/hotspot/jtreg/runtime/CommandLine/VMOptionWarning.java +++ b/test/hotspot/jtreg/runtime/CommandLine/VMOptionWarning.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 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 @@ -39,6 +39,7 @@ public class VMOptionWarning { public static void main(String[] args) throws Exception { ProcessBuilder pb = ProcessTools.createJavaProcessBuilder("-XX:+AlwaysSafeConstructors", "-version"); OutputAnalyzer output = new OutputAnalyzer(pb.start()); + output.shouldNotHaveExitValue(0); output.shouldContain("Error: VM option 'AlwaysSafeConstructors' is experimental and must be enabled via -XX:+UnlockExperimentalVMOptions."); if (Platform.isDebugBuild()) { @@ -48,14 +49,17 @@ public static void main(String[] args) throws Exception { pb = ProcessTools.createJavaProcessBuilder("-XX:+PrintInlining", "-version"); output = new OutputAnalyzer(pb.start()); + output.shouldNotHaveExitValue(0); output.shouldContain("Error: VM option 'PrintInlining' is diagnostic and must be enabled via -XX:+UnlockDiagnosticVMOptions."); pb = ProcessTools.createJavaProcessBuilder("-XX:+VerifyStack", "-version"); output = new OutputAnalyzer(pb.start()); + output.shouldNotHaveExitValue(0); output.shouldContain("Error: VM option 'VerifyStack' is develop and is available only in debug version of VM."); pb = ProcessTools.createJavaProcessBuilder("-XX:+CheckCompressedOops", "-version"); output = new OutputAnalyzer(pb.start()); + output.shouldNotHaveExitValue(0); output.shouldContain("Error: VM option 'CheckCompressedOops' is notproduct and is available only in debug version of VM."); } } diff --git a/test/hotspot/jtreg/runtime/StackGuardPages/exeinvoke.c b/test/hotspot/jtreg/runtime/StackGuardPages/exeinvoke.c index a46f1cef44c..50a37001fbf 100644 --- a/test/hotspot/jtreg/runtime/StackGuardPages/exeinvoke.c +++ b/test/hotspot/jtreg/runtime/StackGuardPages/exeinvoke.c @@ -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 @@ -68,8 +68,17 @@ static void handler(int sig, siginfo_t *si, void *unused) { longjmp(context, 1); } +static char* altstack = NULL; + void set_signal_handler() { - static char altstack[SIGSTKSZ]; + if (altstack == NULL) { + // Dynamically allocated in case SIGSTKSZ is not constant + altstack = malloc(SIGSTKSZ); + if (altstack == NULL) { + fprintf(stderr, "Test ERROR. Unable to malloc altstack space\n"); + exit(7); + } + } stack_t ss = { .ss_size = SIGSTKSZ, diff --git a/test/hotspot/jtreg/runtime/Unsafe/InternalErrorTest.java b/test/hotspot/jtreg/runtime/Unsafe/InternalErrorTest.java index f48f47466d3..91703d9590a 100644 --- a/test/hotspot/jtreg/runtime/Unsafe/InternalErrorTest.java +++ b/test/hotspot/jtreg/runtime/Unsafe/InternalErrorTest.java @@ -55,7 +55,7 @@ public class InternalErrorTest { private static final Unsafe unsafe = Unsafe.getUnsafe(); private static final int pageSize = WhiteBox.getWhiteBox().getVMPageSize(); - private static final String expectedErrorMsg = "fault occurred in a recent unsafe memory access"; + private static final String expectedErrorMsg = "fault occurred in an unsafe memory access"; private static final String failureMsg1 = "InternalError not thrown"; private static final String failureMsg2 = "Wrong InternalError: "; diff --git a/test/hotspot/jtreg/serviceability/dcmd/gc/HeapDumpAllTest.java b/test/hotspot/jtreg/serviceability/dcmd/gc/HeapDumpAllTest.java index 1424eee2901..bc8bc1f1f7d 100644 --- a/test/hotspot/jtreg/serviceability/dcmd/gc/HeapDumpAllTest.java +++ b/test/hotspot/jtreg/serviceability/dcmd/gc/HeapDumpAllTest.java @@ -21,6 +21,10 @@ * questions. */ +import java.io.IOException; + +import jdk.test.lib.dcmd.CommandExecutor; + /* * @test * @summary Test of diagnostic command GC.heap_dump -all=true @@ -37,5 +41,13 @@ public HeapDumpAllTest() { heapDumpArgs = "-all=true"; } + @Override + public void run(CommandExecutor executor, boolean overwrite) throws IOException { + // Trigger gc by hand, so the created heap dump isnt't too large and + // takes too long to parse. + System.gc(); + super.run(executor, overwrite); + } + /* See HeapDumpTest for test cases */ } diff --git a/test/jdk/java/awt/event/KeyEvent/KeyTyped/CtrlSpace.java b/test/jdk/java/awt/event/KeyEvent/KeyTyped/CtrlSpace.java new file mode 100644 index 00000000000..7ff8c0badd0 --- /dev/null +++ b/test/jdk/java/awt/event/KeyEvent/KeyTyped/CtrlSpace.java @@ -0,0 +1,100 @@ +/* + * 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. + */ + +/* + @test + @key headful + @bug 8272602 + @summary Ctrl+Space should generate a KeyTyped event on macOS + @run main CtrlSpace + */ + +import java.awt.BorderLayout; +import java.awt.Frame; +import java.awt.Panel; +import java.awt.TextField; +import java.awt.Robot; +import java.awt.event.KeyEvent; +import java.awt.event.KeyListener; + +public class CtrlSpace extends Frame implements KeyListener { + + static volatile boolean testPassed = false; + static volatile Robot robot; + + public static void main(String[] args) throws Exception { + + robot = new Robot(); + robot.setAutoWaitForIdle(true); + robot.setAutoDelay(100); + + Frame frame = createAndShowGUI(robot); + + test(robot); + robot.waitForIdle(); + Thread.sleep(2000); + frame.setVisible(false); + frame.dispose(); + if (!testPassed) { + throw new RuntimeException("No KeyTyped event"); + } + } + + + static Frame createAndShowGUI(Robot robot) { + CtrlSpace win = new CtrlSpace(); + win.setSize(300, 300); + Panel panel = new Panel(new BorderLayout()); + TextField textField = new TextField("abcdefghijk"); + textField.addKeyListener(win); + panel.add(textField, BorderLayout.CENTER); + win.add(panel); + win.setVisible(true); + robot.waitForIdle(); + textField.requestFocusInWindow(); + robot.waitForIdle(); + return win; + } + + public static void test(Robot robot) { + robot.keyPress(KeyEvent.VK_CONTROL); + robot.keyPress(KeyEvent.VK_SPACE); + robot.keyRelease(KeyEvent.VK_SPACE); + robot.keyRelease(KeyEvent.VK_CONTROL); + robot.delay(200); + } + + public void keyPressed(KeyEvent evt) { + System.out.println("Pressed " + evt); + } + + public void keyReleased(KeyEvent evt) { + System.out.println("Released " + evt); + } + + public void keyTyped(KeyEvent evt) { + System.out.println("Typed " + evt); + testPassed = true; + } + +} diff --git a/test/jdk/java/awt/font/JNICheck/FreeTypeScalerJNICheck.java b/test/jdk/java/awt/font/JNICheck/FreeTypeScalerJNICheck.java new file mode 100644 index 00000000000..a71918c2297 --- /dev/null +++ b/test/jdk/java/awt/font/JNICheck/FreeTypeScalerJNICheck.java @@ -0,0 +1,69 @@ +/* + * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, JetBrains s.r.o.. 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. + */ + +/* @test + * @bug 8269223 + * @summary Verifies that -Xcheck:jni issues no warnings from freetypeScaler.c + * @library /test/lib + * @run main FreeTypeScalerJNICheck + */ +import java.awt.Font; +import java.awt.FontMetrics; +import java.awt.GraphicsEnvironment; +import java.awt.Graphics2D; +import java.awt.geom.Rectangle2D; +import java.awt.image.BufferedImage; +import javax.swing.JFrame; +import jdk.test.lib.process.ProcessTools; +import jdk.test.lib.process.OutputAnalyzer; + +public class FreeTypeScalerJNICheck { + public static void main(String[] args) throws Exception { + if (args.length > 0 && args[0].equals("runtest")) { + runTest(); + } else { + ProcessBuilder pb = ProcessTools.createTestJvm("-Xcheck:jni", FreeTypeScalerJNICheck.class.getName(), "runtest"); + OutputAnalyzer oa = ProcessTools.executeProcess(pb); + oa.shouldContain("Done").shouldNotContain("WARNING").shouldHaveExitValue(0); + } + } + + public static void runTest() { + String families[] = GraphicsEnvironment.getLocalGraphicsEnvironment().getAvailableFontFamilyNames(); + BufferedImage bi = new BufferedImage(1, 1, BufferedImage.TYPE_INT_RGB); + Graphics2D g2d = bi.createGraphics(); + + for (String ff : families) + { + Font font = new Font(ff, Font.PLAIN, 12); + Rectangle2D bounds = font.getStringBounds("test", g2d.getFontRenderContext()); + g2d.setFont(font); + FontMetrics metrics = g2d.getFontMetrics(font); + System.out.println(bounds.getHeight() + metrics.getHeight()); // use bounds and metrics + } + + System.out.println("Done"); + } +} + diff --git a/test/jdk/java/awt/im/4959409/bug4959409.html b/test/jdk/java/awt/im/4959409/bug4959409.html deleted file mode 100644 index e2e437b6005..00000000000 --- a/test/jdk/java/awt/im/4959409/bug4959409.html +++ /dev/null @@ -1,47 +0,0 @@ - - - - - - Test for - - - -

Test for KEY_PRESS event for Shift+1: Bug id 4959409

- -This test is for unix platforms only. Press Pass if you are not -testing on those platforms. - -Confirm the following behavior: - - "KEYPRESS received for Shift+1" is displayed when you press "Shift" and "1" (typically "!"). - - - - diff --git a/test/jdk/java/awt/im/4959409/bug4959409.java b/test/jdk/java/awt/im/4959409/bug4959409.java index f10940813fc..41a1e280baa 100644 --- a/test/jdk/java/awt/im/4959409/bug4959409.java +++ b/test/jdk/java/awt/im/4959409/bug4959409.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2007, 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 @@ -21,52 +21,137 @@ * questions. */ -/** - * +/* + * @test * @bug 4959409 - * @author Naoto Sato + * @summary Check whether pressing SHIFT + 1 triggers key event + * @key headful */ -import java.awt.*; -import java.awt.event.*; -import javax.swing.*; +import java.awt.Container; +import java.awt.Robot; +import java.awt.Rectangle; +import java.awt.Point; +import java.awt.BorderLayout; +import java.awt.event.WindowAdapter; +import java.awt.event.WindowEvent; +import java.awt.event.KeyEvent; +import java.awt.event.KeyAdapter; +import java.awt.event.InputEvent; -public class bug4959409 extends javax.swing.JApplet { - public void init() { - new TestFrame(); - } -} +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; -class TestFrame extends JFrame implements KeyListener { - JTextField text; - JLabel label; - - TestFrame () { - text = new JTextField(); - text.addKeyListener(this); - label = new JLabel(" "); - Container c = getContentPane(); - BorderLayout borderLayout1 = new BorderLayout(); - c.setLayout(borderLayout1); - c.add(text, BorderLayout.CENTER); - c.add(label, BorderLayout.SOUTH); - setSize(300, 200); - setVisible(true); - } +import javax.swing.JFrame; +import javax.swing.JTextField; +import javax.swing.JLabel; +import javax.swing.SwingUtilities; + +public class bug4959409 { + + public final static int TIMEOUT = 20; + public final static int DELAY = 300; + private static JFrame frame; + private static JTextField jTextField; + private static JLabel jLabel; + + public static void createUIAndTest() throws Exception { + CountDownLatch frameVisibleLatch = new CountDownLatch(1); + CountDownLatch keyPressedEventLatch = new CountDownLatch(1); + final Point[] points = new Point[1]; + final Rectangle[] rect = new Rectangle[1]; + + SwingUtilities.invokeAndWait(() -> { + frame = new JFrame("Test bug4959409"); + jTextField = new JTextField(); + jLabel = new JLabel(); + frame.setLayout(new BorderLayout()); + frame.addWindowListener(new WindowAdapter() { + @Override + public void windowOpened(WindowEvent e) { + super.windowOpened(e); + frameVisibleLatch.countDown(); + System.out.println("Frame opened"); + } + }); + + jTextField.addKeyListener(new KeyAdapter() { + @Override + public void keyPressed(KeyEvent keyEvent) { + super.keyPressed(keyEvent); + int code = keyEvent.getKeyCode(); + int mod = keyEvent.getModifiersEx(); + if (code == '1' && mod == KeyEvent.SHIFT_DOWN_MASK) { + keyPressedEventLatch.countDown(); + jLabel.setText("keyPressed received for Shift+1"); + System.out.println("keyPressed received for Shift+1"); + } else { + jLabel.setText("Did not receive keyPressed for Shift+1"); + System.out.println("Did not receive keyPressed for Shift+1"); + } + } + }); - public void keyPressed(KeyEvent e) { - int code = e.getKeyCode(); - int mods = e.getModifiers(); - if (code == '1' && mods == KeyEvent.SHIFT_MASK) { - label.setText("KEYPRESS received for Shift+1"); - } else { - label.setText(" "); + Container container = frame.getContentPane(); + container.add(jTextField, BorderLayout.SOUTH); + container.add(jLabel, BorderLayout.CENTER); + frame.setSize(300, 300); + frame.setLocationRelativeTo(null); + frame.setAlwaysOnTop(true); + frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); + frame.setVisible(true); + }); + + Robot robot = new Robot(); + robot.setAutoDelay(DELAY); + robot.waitForIdle(); + + if (!frameVisibleLatch.await(TIMEOUT, TimeUnit.SECONDS)) { + throw new RuntimeException("Frame is not visible after " + TIMEOUT + " seconds"); + } + + SwingUtilities.invokeAndWait(() -> { + points[0] = jTextField.getLocationOnScreen(); + rect[0] = jTextField.getBounds(); + }); + + clickTextField(robot, points[0].x + rect[0].width / 2, + points[0].y + rect[0].height / 2); + + // Press SHIFT + 1 keys + robot.waitForIdle(); + robot.keyPress(KeyEvent.VK_SHIFT); + robot.keyPress(KeyEvent.VK_1); + robot.keyRelease(KeyEvent.VK_1); + robot.keyRelease(KeyEvent.VK_SHIFT); + robot.waitForIdle(); + + if (!keyPressedEventLatch.await(TIMEOUT, TimeUnit.SECONDS)) { + throw new RuntimeException("Did not receive keyPressed for Shift + 1 , test failed"); } } - public void keyTyped(KeyEvent e) { + public static void clickTextField(final Robot robot, final int X, final int Y) { + robot.delay(DELAY); + robot.waitForIdle(); + robot.mouseMove(X, Y); + robot.waitForIdle(); + + robot.mousePress(InputEvent.BUTTON1_DOWN_MASK); + robot.mouseRelease(InputEvent.BUTTON1_DOWN_MASK); + robot.waitForIdle(); } - public void keyReleased(KeyEvent e) { + public static void main(String[] args) throws Exception { + try { + createUIAndTest(); + } finally { + SwingUtilities.invokeAndWait(() -> { + if (frame != null) { + frame.dispose(); + } + }); + } } } + diff --git a/test/jdk/java/net/httpclient/HandshakeFailureTest.java b/test/jdk/java/net/httpclient/HandshakeFailureTest.java index d111d1f7dc3..a6db6be817a 100644 --- a/test/jdk/java/net/httpclient/HandshakeFailureTest.java +++ b/test/jdk/java/net/httpclient/HandshakeFailureTest.java @@ -49,7 +49,7 @@ /** * @test - * @bug 8238990 + * @bug 8238990 8258951 * @run main/othervm -Djdk.internal.httpclient.debug=true HandshakeFailureTest TLSv1.2 * @run main/othervm -Djdk.internal.httpclient.debug=true HandshakeFailureTest TLSv1.3 * @summary Verify SSLHandshakeException is received when the handshake fails, diff --git a/test/jdk/java/nio/file/Files/InterruptCopy.java b/test/jdk/java/nio/file/Files/InterruptCopy.java index 05bdb4d37c1..cfbb1264efe 100644 --- a/test/jdk/java/nio/file/Files/InterruptCopy.java +++ b/test/jdk/java/nio/file/Files/InterruptCopy.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2008, 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,16 +28,25 @@ * @library .. */ -import java.nio.file.*; -import java.io.*; -import java.util.concurrent.*; +import java.io.IOException; +import java.io.OutputStream; +import java.nio.file.Files; +import java.nio.file.FileStore; +import java.nio.file.Path; +import java.nio.file.StandardCopyOption; +import java.util.concurrent.Callable; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.Executors; +import java.util.concurrent.Future; +import java.util.concurrent.ScheduledExecutorService; import com.sun.nio.file.ExtendedCopyOption; public class InterruptCopy { - private static final long FILE_SIZE_TO_COPY = 512L * 1024L * 1024L; - private static final int DELAY_IN_MS = 500; - private static final int DURATION_MAX_IN_MS = 5000; + private static final long FILE_SIZE_TO_COPY = 1024L * 1024L * 1024L; + private static final int INTERRUPT_DELAY_IN_MS = 50; + private static final int DURATION_MAX_IN_MS = 3*INTERRUPT_DELAY_IN_MS; + private static final int CANCEL_DELAY_IN_MS = 10; public static void main(String[] args) throws Exception { Path dir = TestUtil.createTemporaryDirectory(); @@ -74,46 +83,76 @@ static void doTest(Path dir) throws Exception { ScheduledExecutorService pool = Executors.newSingleThreadScheduledExecutor(); + try { - // copy source to target in main thread, interrupting it after a delay + // copy source to target in main thread, interrupting it + // after a delay final Thread me = Thread.currentThread(); - Future wakeup = pool.schedule(new Runnable() { + final CountDownLatch interruptLatch = new CountDownLatch(1); + Future wakeup = pool.submit(new Runnable() { public void run() { + try { + interruptLatch.await(); + Thread.sleep(INTERRUPT_DELAY_IN_MS); + } catch (InterruptedException ignore) { + } + System.out.printf("Interrupting at %d ms...%n", + System.currentTimeMillis()); me.interrupt(); - }}, DELAY_IN_MS, TimeUnit.MILLISECONDS); - System.out.println("Copying file..."); + } + }); try { - long start = System.currentTimeMillis(); + interruptLatch.countDown(); + long theBeginning = System.currentTimeMillis(); + System.out.printf("Copying file at %d ms...%n", theBeginning); Files.copy(source, target, ExtendedCopyOption.INTERRUPTIBLE); - long duration = System.currentTimeMillis() - start; + long theEnd = System.currentTimeMillis(); + System.out.printf("Done copying at %d ms...%n", theEnd); + long duration = theEnd - theBeginning; if (duration > DURATION_MAX_IN_MS) throw new RuntimeException("Copy was not interrupted"); } catch (IOException e) { boolean interrupted = Thread.interrupted(); if (!interrupted) throw new RuntimeException("Interrupt status was not set"); - System.out.println("Copy failed (this is expected)"); + System.out.println("Copy failed (this is expected)."); } try { wakeup.get(); } catch (InterruptedException ignore) { } Thread.interrupted(); - // copy source to target via task in thread pool, interrupting it after - // a delay using cancel(true) + // copy source to target via task in thread pool, interrupting it + // after a delay using cancel(true) + CountDownLatch cancelLatch = new CountDownLatch(1); Future result = pool.submit(new Callable() { public Void call() throws IOException { - System.out.println("Copying file..."); + cancelLatch.countDown(); + System.out.printf("Copying file at %d ms...%n", + System.currentTimeMillis()); Files.copy(source, target, ExtendedCopyOption.INTERRUPTIBLE, StandardCopyOption.REPLACE_EXISTING); + System.out.printf("Done copying at %d ms...%n", + System.currentTimeMillis()); return null; } }); - Thread.sleep(DELAY_IN_MS); - boolean cancelled = result.cancel(true); - if (!cancelled) + try { + cancelLatch.await(); + Thread.sleep(CANCEL_DELAY_IN_MS); + } catch (InterruptedException ignore) { + } + if (result.isDone()) + throw new RuntimeException("Copy finished before cancellation"); + System.out.printf("Cancelling at %d ms...%n", + System.currentTimeMillis()); + boolean cancelled = result.cancel(true); + if (cancelled) + System.out.println("Copy cancelled."); + else { result.get(); - System.out.println("Copy cancelled."); + throw new RuntimeException("Copy was not cancelled"); + } } finally { pool.shutdown(); } diff --git a/test/jdk/security/infra/java/security/cert/CertPathValidator/certification/BuypassCA.java b/test/jdk/security/infra/java/security/cert/CertPathValidator/certification/BuypassCA.java index 452d4db4eda..9ad20271bec 100644 --- a/test/jdk/security/infra/java/security/cert/CertPathValidator/certification/BuypassCA.java +++ b/test/jdk/security/infra/java/security/cert/CertPathValidator/certification/BuypassCA.java @@ -57,18 +57,15 @@ public static void main(String[] args) throws Exception { ValidatePathWithParams pathValidator = new ValidatePathWithParams(null); - boolean ocspEnabled = true; - if (args.length >= 1 && "CRL".equalsIgnoreCase(args[0])) { pathValidator.enableCRLCheck(); - ocspEnabled = false; } else { // OCSP check by default pathValidator.enableOCSPCheck(); } new BuypassClass2().runTest(pathValidator); - new BuypassClass3().runTest(pathValidator, ocspEnabled); + new BuypassClass3().runTest(pathValidator); } } @@ -320,8 +317,7 @@ class BuypassClass3 { "BJmiWd5uUxev0nVw0saqvlo4yAEBq4rI/DieKcQI4qEI8myzoS0R0azMfLM=\n" + "-----END CERTIFICATE-----"; - public void runTest(ValidatePathWithParams pathValidator, boolean ocspEnabled) - throws Exception { + public void runTest(ValidatePathWithParams pathValidator) throws Exception { // Validate valid pathValidator.validate(new String[]{VALID_CLASS_3, INT_CLASS_3}, ValidatePathWithParams.Status.GOOD, null, System.out); diff --git a/test/jdk/sun/security/ssl/SSLSessionImpl/InvalidateSession.java b/test/jdk/sun/security/ssl/SSLSessionImpl/InvalidateSession.java new file mode 100644 index 00000000000..2a13a8cdb8f --- /dev/null +++ b/test/jdk/sun/security/ssl/SSLSessionImpl/InvalidateSession.java @@ -0,0 +1,162 @@ +/* + * 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. + */ + +/* + * @test + * @bug 8270344 + * @library /test/lib /javax/net/ssl/templates + * @summary Session resumption errors + * @run main/othervm InvalidateSession + */ + +import javax.net.*; +import javax.net.ssl.*; +import java.io.*; +import java.net.*; +import java.util.*; + +import jdk.test.lib.security.SecurityUtils; + +public class InvalidateSession implements SSLContextTemplate { + + static ServerSocketFactory serverSsf = null; + static SSLSocketFactory clientSsf = null; + + static Server server; + static SSLSession cacheSession; + static final String[] CLIENT_VERSIONS = {"TLSv1", "TLSv1.1", "TLSv1.2"}; + + public static void main(String args[]) throws Exception { + // drop the supported_versions extension to force test to use the legacy + // TLS protocol version field during handshakes + System.setProperty("jdk.tls.client.disableExtensions", "supported_versions"); + SecurityUtils.removeFromDisabledTlsAlgs("TLSv1", "TLSv1.1"); + + InvalidateSession test = new InvalidateSession(); + test.sessionTest(); + server.go = false; + } + + /** + * 3 test iterations + * 1) Server configured with TLSv1, client with TLSv1, v1.1, v1.2 + * - Handshake should succeed + * - Session "A" established + * 2) 2nd iteration, server configured with TLSv1.2 only + * - Connection should succeed but with a new session due to TLS protocol version change + * - Session "A" should be invalidated + * - Session "B" is created + * 3) 3rd iteration, same server/client config + * - Session "B" should continue to be in use + */ + private void sessionTest() throws Exception { + serverSsf = createServerSSLContext().getServerSocketFactory(); + clientSsf = createClientSSLContext().getSocketFactory(); + server = startServer(); + while (!server.started) { + Thread.yield(); + } + + for (int i = 1; i <= 3; i++) { + clientConnect(i); + Thread.sleep(1000); + } + } + + public void clientConnect(int testIterationCount) throws Exception { + System.out.printf("Connecting to: localhost: %s, iteration count %d%n", + "localhost:" + server.port, testIterationCount); + SSLSocket sslSocket = (SSLSocket) clientSsf.createSocket("localhost", server.port); + sslSocket.setEnabledProtocols(CLIENT_VERSIONS); + sslSocket.startHandshake(); + + System.out.println("Got session: " + sslSocket.getSession()); + + if (testIterationCount == 2 && Objects.equals(cacheSession, sslSocket.getSession())) { + throw new RuntimeException("Same session should not have resumed"); + } + if (testIterationCount == 3 && !Objects.equals(cacheSession, sslSocket.getSession())) { + throw new RuntimeException("Same session should have resumed"); + } + + cacheSession = sslSocket.getSession(); + + try ( + ObjectOutputStream oos = new ObjectOutputStream(sslSocket.getOutputStream()); + ObjectInputStream ois = new ObjectInputStream(sslSocket.getInputStream())) { + oos.writeObject("Hello"); + String serverMsg = (String) ois.readObject(); + System.out.println("Server message : " + serverMsg); + } catch (Exception ex) { + throw new RuntimeException(ex); + } finally { + sslSocket.close(); + } + } + + private static Server startServer() { + Server server = new Server(); + new Thread(server).start(); + return server; + } + + private static class Server implements Runnable { + public volatile boolean go = true; + public volatile int port = 0; + public volatile boolean started = false; + + @Override + public void run() { + try { + SSLServerSocket ssock = (SSLServerSocket) + serverSsf.createServerSocket(0); + this.port = ssock.getLocalPort(); + ssock.setEnabledProtocols(new String[]{"TLSv1"}); + started = true; + while (go) { + try { + System.out.println("Waiting for connection"); + Socket sock = ssock.accept(); + // now flip server to TLSv1.2 mode for successive connections + ssock.setEnabledProtocols(new String[]{"TLSv1.2"}); + try ( + ObjectInputStream ois = new ObjectInputStream(sock.getInputStream()); + ObjectOutputStream oos = new ObjectOutputStream(sock.getOutputStream())) { + String recv = (String) ois.readObject(); + oos.writeObject("Received: " + recv); + } catch (SSLHandshakeException she) { + System.out.println("Server caught :" + she); + } finally { + sock.close(); + } + } catch (Exception ex) { + throw new RuntimeException(ex); + } + } + } catch (Exception ex) { + throw new RuntimeException(ex); + } + } + } +} + diff --git a/test/jdk/tools/jlink/plugins/CDSPluginTest.java b/test/jdk/tools/jlink/plugins/CDSPluginTest.java new file mode 100644 index 00000000000..5a973320951 --- /dev/null +++ b/test/jdk/tools/jlink/plugins/CDSPluginTest.java @@ -0,0 +1,94 @@ +/* + * 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. + */ + +import java.io.File; + +import jdk.test.lib.JDKToolFinder; +import jdk.test.lib.Platform; +import jdk.test.lib.process.*; + +import tests.Helper; + +/* @test + * @bug 8264322 + * @summary Test the --generate-cds-archive plugin + * @requires vm.cds + * @library ../../lib + * @library /test/lib + * @modules java.base/jdk.internal.jimage + * jdk.jdeps/com.sun.tools.classfile + * jdk.jlink/jdk.tools.jlink.internal + * jdk.jlink/jdk.tools.jmod + * jdk.jlink/jdk.tools.jimage + * jdk.compiler + * @build tests.* + * @run main CDSPluginTest + */ + +public class CDSPluginTest { + + public static void main(String[] args) throws Throwable { + + Helper helper = Helper.newHelper(); + if (helper == null) { + System.err.println("Test not run"); + return; + } + + var module = "cds"; + helper.generateDefaultJModule(module); + var image = helper.generateDefaultImage(new String[] { "--generate-cds-archive" }, + module) + .assertSuccess(); + + String subDir; + String sep = File.separator; + if (Platform.isWindows()) { + subDir = "bin" + sep; + } else { + subDir = "lib" + sep; + } + subDir += "server" + sep; + helper.checkImage(image, module, null, null, + new String[] { subDir + "classes.jsa", subDir + "classes_nocoops.jsa" }); + + // Simulate different platforms between current runtime and target image. + if (Platform.isLinux()) { + System.out.println("---- Test different platforms scenario ----"); + String jlinkPath = JDKToolFinder.getJDKTool("jlink"); + String[] cmd = {jlinkPath, "--add-modules", "java.base,java.logging", + "-J-Dos.name=windows", "--generate-cds-archive", + "--output", System.getProperty("test.classes") + sep + module + "-tmp"}; + StringBuilder cmdLine = new StringBuilder(); + for (String s : cmd) { + cmdLine.append(s).append(' '); + } + System.out.println("Command line: [" + cmdLine.toString() + "]"); + ProcessBuilder pb = new ProcessBuilder(cmd); + OutputAnalyzer out = new OutputAnalyzer(pb.start()); + System.out.println(" stdout: " + out.getStdout()); + out.shouldMatch("Error: Cannot generate CDS archives: target image platform linux-.*is different from runtime platform windows-.*"); + out.shouldHaveExitValue(1); + } + } +} diff --git a/test/langtools/jdk/javadoc/doclet/testJavaFX/TestJavaFX.java b/test/langtools/jdk/javadoc/doclet/testJavaFX/TestJavaFX.java index 30f42efb23b..1c46ac12cf4 100644 --- a/test/langtools/jdk/javadoc/doclet/testJavaFX/TestJavaFX.java +++ b/test/langtools/jdk/javadoc/doclet/testJavaFX/TestJavaFX.java @@ -54,6 +54,7 @@ public void test1() { "-sourcepath", testSrc, "-javafx", "--disable-javafx-strict-checks", + "-Xdoclint:all,-missing", "-package", "pkg1"); checkExit(Exit.OK); @@ -71,14 +72,14 @@ public void test1() {
public final <\ span class="return-type">void setRate\ (double value)
-
Sets the value of the property rate.
+
Sets the value of the property rate.
Property description:
""", """
public final <\ span class="return-type">double getRate()<\ /div> -
Gets the value of the property rate.
+
Gets the value of the property rate.
Property description:
""", """ @@ -116,14 +117,14 @@ public void test1() {
public final <\ span class="return-type">double isPaused<\ /span>()
-
Gets the value of the property paused.
""", +
Gets the value of the property paused.
""", """

setPaused

public final <\ span class="return-type">void setPaused(boolean value)
-
Sets the value of the property paused.
+
Sets the value of the property paused.
Property description:
Defines if paused. The second line.
@@ -135,7 +136,7 @@ public void test1() {
public final <\ span class="return-type">double isPaused<\ /span>()
-
Gets the value of the property paused.
+
Gets the value of the property paused.
Property description:
Defines if paused. The second line.
@@ -150,35 +151,39 @@ public void test1() {
Defines the direction/speed at which the Timeline is expected to be played. This is the second line.
""", """ -
-

setRate

-
public final <\ - span class="return-type">void setRate(double value)
-
Sets the value of the property rate.
-
-
Property description:
-
Defines the direction/speed at which the Timeline is expected to - be played. This is the second line.
-
Default value:
-
11
-
Since:
-
JavaFX 8.0
""", +
+

setRate

+
public final <\ + span class="return-type">void setRate(double value)
+
Sets the value of the property rate.
+
+
Property description:
+
Defines the direction/speed at which the Timeline is expected to + be played. This is the second line.
+
Default value:
+
11
+
Parameters:
+
value - the value for the property rate
+
Since:
+
JavaFX 8.0
""", """ -
-

getRate

-
public final <\ - span class="return-type">double getRate()<\ - /div> -
Gets the value of the property rate.
-
-
Property description:
-
Defines the direction/speed at which the Timeline is expected to - be played. This is the second line.
-
Default value:
-
11
-
Since:
-
JavaFX 8.0
""", +
+

getRate

+
public final <\ + span class="return-type">double getRate()<\ + /div> +
Gets the value of the property rate.
+
+
Property description:
+
Defines the direction/speed at which the Timeline is expected to + be played. This is the second line.
+
Default value:
+
11
+
Returns:
+
the value of the property rate
+
Since:
+
JavaFX 8.0
""", """

Property Summary

@@ -221,7 +226,7 @@ public void test1() { checkOutput("index-all.html", true, """ -
Gets the value of the property paused.
""", +
Gets the value of the property paused.
""", """
Defines if paused.
"""); @@ -245,40 +250,65 @@ public void test2() { "-javafx", "--disable-javafx-strict-checks", "--no-platform-links", + "-Xdoclint:all,-missing", "-package", "pkg2"); checkExit(Exit.OK); checkOutput("pkg2/Test.html", true, """ -
-

Property Details

-
    -
  • -
    -

    beta

    -
    public java.lang.Object betaProperty<\ - /span>
    -
    -
  • -
  • -
    -

    gamma

    -
    public final <\ - span class="return-type">java.util.List<java.lang.String> gammaProperty
    -
    -
  • -
  • -
    -

    delta

    -
    public final <\ - span class="return-type">java.util.List<java.util.Set<? super java.lang.Ob\ - ject>> deltaProperty
    -
    -
  • -
-
""", +
+

Property Details

+
    +
  • +
    +

    beta

    +
    public java.lang.Object betaProperty<\ + /span>
    +
    +
    See Also:
    +
    + +
    +
    +
    +
  • +
  • +
    +

    gamma

    +
    public final <\ + span class="return-type">java.util.List<java.lang.String> gammaProperty
    +
    +
    See Also:
    +
    + +
    +
    +
    +
  • +
  • +
    +

    delta

    +
    public final <\ + span class="return-type">java.util.List<java.util.Set<? super java.lang.Ob\ + ject>> deltaProperty
    +
    +
    See Also:
    +
    + +
    +
    +
    +
  • +
+
""", """

Property Summary

diff --git a/test/langtools/jdk/javadoc/doclet/testJavaFX/TestJavaFXCombo.java b/test/langtools/jdk/javadoc/doclet/testJavaFX/TestJavaFXCombo.java new file mode 100644 index 00000000000..e9baeaf6c8f --- /dev/null +++ b/test/langtools/jdk/javadoc/doclet/testJavaFX/TestJavaFXCombo.java @@ -0,0 +1,423 @@ +/* + * 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. + */ + +/* + * @test + * @bug 8270195 + * @summary Add missing links between methods of JavaFX properties + * @library /tools/lib ../../lib + * @modules jdk.javadoc/jdk.javadoc.internal.tool + * @build toolbox.ToolBox javadoc.tester.* + * @run main TestJavaFXCombo + */ + +import java.io.IOException; +import java.nio.file.Path; +import java.util.EnumSet; +import java.util.Set; + +import javadoc.tester.JavadocTester; +import toolbox.ToolBox; + +/** + * Combo-test for JavaFX properties and related methods. + * The test generates instances of a class with various combinations of + * a property field, property method, getter method and setter method, + * each in combinations of with and without doc comments. + * For each instance, it runs javadoc and verifies the generated + * code and any diagnostics are as expected. + */ +public class TestJavaFXCombo extends JavadocTester { + public static void main(String... args) throws Exception { + TestJavaFXCombo tester = new TestJavaFXCombo(args); + tester.runTests(m -> new Object[] { Path.of(m.getName())}); + } + + ToolBox tb = new ToolBox(); + enum Kind { NONE, NO_COMMENT, COMMENT } + + private final Set fieldValues = EnumSet.allOf(Kind.class); + private final Set propertyMethodValues = EnumSet.allOf(Kind.class); + private final Set getterMethodValues = EnumSet.allOf(Kind.class); + private final Set setterMethodValues = EnumSet.allOf(Kind.class); + + TestJavaFXCombo(String... args) { + // for testing, allow subsets of combinations to be specified + for (int i = 0; i < args.length; i++) { + String arg = args[1]; + switch (arg) { + case "-f" -> set(fieldValues, args[++i]); + case "-p" -> set(propertyMethodValues, args[++i]); + case "-g" -> set(getterMethodValues, args[++i]); + case "-s" -> set(setterMethodValues, args[++i]); + } + } + + // A property method is always required for any property, + propertyMethodValues.remove(Kind.NONE); + + } + + private void set(Set set, String values) { + set.clear(); + for (String v : values.split("[, ]")) { + set.add(Kind.valueOf(v)); + } + } + + @Test + public void test(Path base) throws IOException { + for (Kind pk : propertyMethodValues) { + for (Kind fk : fieldValues) { + for (Kind gk : getterMethodValues) { + for (Kind sk: setterMethodValues) { + test(base, fk, pk, gk, sk); + } + } + } + } + } + + void test(Path base, Kind fk, Kind pk, Kind gk, Kind sk) throws IOException { + String description = "Field:" + fk + " Property:" + pk + " Getter:" + gk + " Setter:" + sk; + out.println("Test: " + description); + Path sub = base.resolve(String.format("%s-%s-%s-%s", abbrev(fk), abbrev(pk), abbrev(gk), abbrev(sk))); + Path src = sub.resolve("src"); + tb.writeJavaFiles(src, """ + package p; + /** Dummy property class. */ + public class BooleanProperty { } + """, """ + package p; + /** Class comment. ## */ + public class C { + """.replace("##", description) + + getFieldText(fk) + + getPropertyMethodText(pk) + + getGetterMethodText(gk) + + getSetterMethodText(sk) + + """ + } + """ + ); + + javadoc("-d", sub.resolve("api").toString(), + "-javafx", + "--disable-javafx-strict-checks", + "-Xdoclint:all,-missing", + "-nohelp", "-noindex", + "-sourcepath", src.toString(), + "p"); + checkExit(Exit.OK); + checkField(fk, pk, gk, sk); + checkGetter(fk, pk, gk, sk); + checkSetter(fk, pk, gk, sk); + checkPropertyMethod(fk, pk, gk, sk); + checkDiags(fk, pk, gk, sk); + } + + void checkField(Kind fk, Kind pk, Kind gk, Kind sk) { + // the field is private and so should never show up + checkOutput("p/C.html", false, + "field.detail"); + } + + void checkGetter(Kind fk, Kind pk, Kind gk, Kind sk) { + switch (gk) { + case NONE -> + checkOutput("p/C.html", false, + "getExample"); + + case NO_COMMENT -> + // comment gets auto-created + checkOutput("p/C.html", true, + """ +
+

getExample

+
public boolean getExample()
+
Gets the value of the property example.
+
+
Property description:
+ #DESC# +
Returns:
+
the value of the property example
+ #SEE# +
+
+ """ + .replace("#DESC#", getPropertyDescription(fk, pk)) + .replace("#SEE#", getSee(pk, null, sk)) + .replaceAll("\n\n", "\n") + ); + + case COMMENT -> + // existing comments do not get modified + checkOutput("p/C.html", true, + """ +
+

getExample

+
public boolean getExample()
+
Getter method description. More getter method description.
+
+
Returns:
+
the property example
+
+
+ """); + } + } + + void checkSetter(Kind fk, Kind pk, Kind gk, Kind sk) { + switch (sk) { + case NONE -> + checkOutput("p/C.html", false, + "setExample"); + + case NO_COMMENT -> + // comment gets auto-created + checkOutput("p/C.html", true, + """ +
+

setExample

+
public void setExample(boolean b)
+
Sets the value of the property example.
+
+
Property description:
+ #DESC# +
Parameters:
+
b - the value for the property example
+ #SEE# +
+
+ """ + .replace("#DESC#", getPropertyDescription(fk, pk)) + .replace("#SEE#", getSee(pk, gk, null)) + .replaceAll("\n\n", "\n")); + + case COMMENT -> + // existing comments do not get modified + checkOutput("p/C.html", true, + """ +
+

setExample

+
public void setExample(boolean b)
+
Setter method description. More setter method description.
+
+
Parameters:
+
b - the new value for the property
+
+
+ """); + } + } + + void checkPropertyMethod(Kind fk, Kind pk, Kind gk, Kind sk) { + switch (pk) { + case NONE -> + // should not happen; there is always a property method + throw new IllegalArgumentException(); + + case NO_COMMENT -> + checkOutput("p/C.html", true, + """ +
+

exampleProperty

+
public BooleanProperty exampleProperty()
+ #PCOMM# +
+
Returns:
+
the property example
+ #SEE# +
+
+ """ + .replace("#PCOMM#", getPropertyMethodComment(fk, pk)) + .replace("#SEE#", getSee(null, gk, sk)) + .replaceAll("\n\n", "\n")); + + case COMMENT -> + // @see tags are added to an existing method if it is the primary source of info + // for the property (i.e. there is no comment on a corresponding property field. + checkOutput("p/C.html", true, + """ +
+

exampleProperty

+
public BooleanProperty exampleProperty()
+
Property method description. More property method description.
+
+
Returns:
+
the property example
+ #SEE# +
+
+ """ + .replace("#SEE#", (fk == Kind.COMMENT ? "" : getSee(null, gk, sk))) + .replaceAll("\n\n", "\n")); + } + } + + void checkDiags(Kind fk, Kind pk, Kind gk, Kind sk) { + // A warning is generated if there is a comment on both the property field and property method + checkOutput(Output.OUT, (fk == Kind.COMMENT && pk == Kind.COMMENT), + "warning: Duplicate comment for property", + "Remove the comment on the property field or on this method to suppress this warning."); + } + + String getPropertyComment(Kind fk, Kind pk) { + return switch (fk) { + case NONE, NO_COMMENT -> + switch (pk) { + case NONE, NO_COMMENT -> + ""; + + case COMMENT -> + "Property method description. More property method description."; + }; + + case COMMENT -> + "Field description. More field description."; + }; + } + + String getPropertyDescription(Kind fk, Kind pk) { + String s = getPropertyComment(fk, pk); + return s.isEmpty() ? s : "
" + s + "
"; + } + + String getPropertyMethodComment(Kind fk, Kind pk) { + String s = getPropertyComment(fk, pk); + return s.isEmpty() ? s : "
" + s + "
"; + } + + String getSee(Kind pk, Kind gk, Kind sk) { + StringBuilder sb = new StringBuilder(); + if (gk != null && gk != Kind.NONE) { + sb.append(""" +
  • getExample()
  • + """); + } + if (sk != null && sk != Kind.NONE) { + sb.append(""" +
  • setExample(boolean)
  • + """); + } + if (pk != null && pk != Kind.NONE) { + sb.append(""" +
  • exampleProperty()
  • + """); + } + return sb.isEmpty() ? "" : """ +
    See Also:
    +
    +
      + """ + sb + """ +
    +
    """; + } + + String abbrev(Kind k) { + return k.name().substring(0, 4); + } + + String getFieldText(Kind fk) { + return switch (fk) { + case NONE -> """ + // no field declaration + """; + + case NO_COMMENT -> """ + // no field comment + private BooleanProperty example; + """; + + case COMMENT -> """ + /** Field description. More field description. */ + private BooleanProperty example; + """; + }; + } + + String getPropertyMethodText(Kind fk) { + return switch (fk) { + case NONE -> """ + // no property method declaration + """; + + case NO_COMMENT -> """ + // no property method comment + public BooleanProperty exampleProperty(); + """; + + case COMMENT -> """ + /** + * Property method description. More property method description. + * @return the property {@code example} + */ + public BooleanProperty exampleProperty(); + """; + }; + } + + String getGetterMethodText(Kind fk) { + return switch (fk) { + case NONE -> """ + // no getter method declaration + """; + + case NO_COMMENT -> """ + // no getter method comment + public boolean getExample(); + """; + + case COMMENT -> """ + /** + * Getter method description. More getter method description. + * @return the property {@code example} + */ + public boolean getExample(); + """; + }; + } + + String getSetterMethodText(Kind fk) { + return switch (fk) { + case NONE -> """ + // no setter method declaration + """; + + case NO_COMMENT -> """ + // no setter method comment + public void setExample(boolean b); + """; + + case COMMENT -> """ + /** + * Setter method description. More setter method description. + * @param b the new value for the property + */ + public void setExample(boolean b); + """; + }; + } + +} \ No newline at end of file diff --git a/test/langtools/jdk/javadoc/doclet/testJavaFX/TestJavaFXMissingPropComments.java b/test/langtools/jdk/javadoc/doclet/testJavaFX/TestJavaFXMissingPropComments.java index ae6b50827c2..328ac15e400 100644 --- a/test/langtools/jdk/javadoc/doclet/testJavaFX/TestJavaFXMissingPropComments.java +++ b/test/langtools/jdk/javadoc/doclet/testJavaFX/TestJavaFXMissingPropComments.java @@ -92,10 +92,18 @@ public boolean getValue() {
    public boolean getValue()
    -
    Gets the value of the property value.
    +
    Gets the value of the property value.
    Property description:
    The value property (property method comment).
    +
    Returns:
    +
    the value of the property value
    +
    See Also:
    +
    + +
    """ ); @@ -148,10 +156,18 @@ public boolean getValue() {
    public boolean getValue()
    -
    Gets the value of the property value.
    +
    Gets the value of the property value.
    Property description:
    The value property (field comment).
    +
    Returns:
    +
    the value of the property value
    +
    See Also:
    +
    + +
    """ ); diff --git a/test/langtools/jdk/javadoc/doclet/testJavaFX/pkg2/Test.java b/test/langtools/jdk/javadoc/doclet/testJavaFX/pkg2/Test.java index 9e1973d944c..3d4152999a0 100644 --- a/test/langtools/jdk/javadoc/doclet/testJavaFX/pkg2/Test.java +++ b/test/langtools/jdk/javadoc/doclet/testJavaFX/pkg2/Test.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2014, 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 @@ -26,10 +26,9 @@ import java.util.List; import java.util.Set; - public class Test { public Object alphaProperty(List foo) { return null; } public Object betaProperty() { return null; } - public final List gammaProperty() {return null;} - public final List> deltaProperty() {return null;} + public final List gammaProperty() { return null;} + public final List> deltaProperty() { return null;} } diff --git a/test/langtools/jdk/javadoc/doclet/testProperty/TestProperty.java b/test/langtools/jdk/javadoc/doclet/testProperty/TestProperty.java index b38de9454f8..1d86e50b265 100644 --- a/test/langtools/jdk/javadoc/doclet/testProperty/TestProperty.java +++ b/test/langtools/jdk/javadoc/doclet/testProperty/TestProperty.java @@ -46,6 +46,7 @@ public void testArrays() { "--no-platform-links", "-javafx", "--disable-javafx-strict-checks", + "-Xdoclint:all,-missing", "-sourcepath", testSrc, "pkg"); checkExit(Exit.OK); @@ -63,6 +64,7 @@ public void testArrays() {
    """, @@ -79,6 +81,7 @@ public void testArrays() {
    """, @@ -117,6 +120,7 @@ class in pkg">ObjectProperty<My
    """ diff --git a/test/langtools/jdk/javadoc/doclet/testUnicode/TestUnicode.java b/test/langtools/jdk/javadoc/doclet/testUnicode/TestUnicode.java index db19ef0ffb7..9621c18b760 100644 --- a/test/langtools/jdk/javadoc/doclet/testUnicode/TestUnicode.java +++ b/test/langtools/jdk/javadoc/doclet/testUnicode/TestUnicode.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 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 @@ -23,7 +23,7 @@ /* * @test - * @bug 8203176 + * @bug 8203176 8271258 * @summary javadoc handles non-ASCII characters incorrectly * @library /tools/lib ../../lib * @modules jdk.javadoc/jdk.javadoc.internal.tool @@ -33,7 +33,6 @@ import java.nio.file.Files; import java.nio.file.Path; -import java.nio.file.Paths; import javadoc.tester.JavadocTester; import toolbox.ToolBox; @@ -42,20 +41,20 @@ public class TestUnicode extends JavadocTester { public static void main(String... args) throws Exception { TestUnicode tester = new TestUnicode(); - tester.runTests(); + tester.runTests(m -> new Object[] { Path.of(m.getName())}); } ToolBox tb = new ToolBox(); @Test - public void test() throws Exception { + public void testUnicode(Path base) throws Exception { char ellipsis = '\u2026'; - Path src = Files.createDirectories(Paths.get("src")); + Path src = Files.createDirectories(base.resolve("src")); tb.writeJavaFiles(src, "/** Hel" + ellipsis + "lo {@code World(" + ellipsis + ")}. */\n" + "public class Code { }\n"); - javadoc("-d", "out", + javadoc("-d", base.resolve("out").toString(), "-encoding", "utf-8", src.resolve("Code.java").toString()); checkExit(Exit.OK); @@ -65,4 +64,66 @@ public void test() throws Exception { checkOutput("Code.html", false, "\\u"); } + + @Test + public void testParam(Path base) throws Exception { + String chineseElephant = "\u5927\u8c61"; // taken from JDK-8271258 + Path src = Files.createDirectories(base.resolve("src")); + tb.writeJavaFiles(src, + """ + /** + * Comment. ##. + * @param <##> the ## + */ + public class Code<##> { + /** + * Comment. ##. + * @param ## the ## + */ + public void set##(int ##) { } + }""".replaceAll("##", chineseElephant)); + + javadoc("-d", base.resolve("out").toString(), + "-encoding", "utf-8", + "--no-platform-links", + src.resolve("Code.java").toString()); + checkExit(Exit.OK); + + checkOutput("Code.html", true, + """ +

    Class Code<##>

    + """.replaceAll("##", chineseElephant), + """ +
    java.lang.Object +
    Code<##>
    +
    + """.replaceAll("##", chineseElephant), + """ +
    +
    Type Parameters:
    +
    ## - the ##
    +
    + """.replaceAll("##", chineseElephant), + """ +
    +

    set##

    +
    public void set##\ + (int ##)
    +
    Comment. ##.
    +
    +
    Parameters:
    +
    ## - the ##
    +
    +
    + """.replaceAll("##", chineseElephant) + ); + + // The following checks for the numeric forms of the Unicode characters being tested: + // these numeric forms should not show up as literal character sequences. + checkOutput("Code.html", false, + Integer.toHexString(chineseElephant.charAt(0)), + Integer.toHexString(chineseElephant.charAt(1)) + ); + } } diff --git a/test/langtools/tools/doclint/AnonClassTest.java b/test/langtools/tools/doclint/AnonClassTest.java new file mode 100644 index 00000000000..5e5046f6677 --- /dev/null +++ b/test/langtools/tools/doclint/AnonClassTest.java @@ -0,0 +1,37 @@ +/* + * @test /nodynamiccopyright/ + * @modules jdk.javadoc/jdk.javadoc.internal.doclint + * @build DocLintTester + * @run main DocLintTester -Xmsgs:-missing AnonClassTest.java + * @run main DocLintTester -Xmsgs:missing -ref AnonClassTest.out AnonClassTest.java + */ + +/** Class comment. */ +public enum AnonClassTest { + + /** + * E1 comment. + * This member uses an anonymous class, which should not trigger a warning. + */ + E1 { + // no comment: should give warning + int field; + + // no comment: should give warning + void m() { } + + // no comment required: should not give warning + @java.lang.Override + public void m1() { } + }, + + // This member also uses an anonymous class, + // but there should only be a single warning for the member itself. + E2 { }, + + /** E3 comment. This member does not use an anonymous class. */ + E3; + + /** Method comment. */ + public void m1() { } +} diff --git a/test/langtools/tools/doclint/AnonClassTest.out b/test/langtools/tools/doclint/AnonClassTest.out new file mode 100644 index 00000000000..93079cb7622 --- /dev/null +++ b/test/langtools/tools/doclint/AnonClassTest.out @@ -0,0 +1,10 @@ +AnonClassTest.java:18: warning: no comment + int field; + ^ +AnonClassTest.java:21: warning: no comment + void m() { } + ^ +AnonClassTest.java:30: warning: no comment + E2 { }, + ^ +3 warnings \ No newline at end of file