Wed, 04 Dec 2019 16:23:46 +0000
Merge
1.1 --- a/src/cpu/ppc/vm/vm_version_ppc.cpp Wed Nov 27 05:33:18 2019 +0000 1.2 +++ b/src/cpu/ppc/vm/vm_version_ppc.cpp Wed Dec 04 16:23:46 2019 +0000 1.3 @@ -194,6 +194,11 @@ 1.4 FLAG_SET_DEFAULT(UseAESIntrinsics, false); 1.5 } 1.6 1.7 + if (UseGHASHIntrinsics) { 1.8 + warning("GHASH intrinsics are not available on this CPU"); 1.9 + FLAG_SET_DEFAULT(UseGHASHIntrinsics, false); 1.10 + } 1.11 + 1.12 if (has_vshasig()) { 1.13 if (FLAG_IS_DEFAULT(UseSHA)) { 1.14 UseSHA = true;
2.1 --- a/src/cpu/sparc/vm/assembler_sparc.hpp Wed Nov 27 05:33:18 2019 +0000 2.2 +++ b/src/cpu/sparc/vm/assembler_sparc.hpp Wed Dec 04 16:23:46 2019 +0000 2.3 @@ -1,5 +1,5 @@ 2.4 /* 2.5 - * Copyright (c) 1997, 2014, Oracle and/or its affiliates. All rights reserved. 2.6 + * Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved. 2.7 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 2.8 * 2.9 * This code is free software; you can redistribute it and/or modify it 2.10 @@ -129,6 +129,7 @@ 2.11 flog3_op3 = 0x36, 2.12 edge_op3 = 0x36, 2.13 fsrc_op3 = 0x36, 2.14 + xmulx_op3 = 0x36, 2.15 impdep2_op3 = 0x37, 2.16 stpartialf_op3 = 0x37, 2.17 jmpl_op3 = 0x38, 2.18 @@ -220,6 +221,8 @@ 2.19 mdtox_opf = 0x110, 2.20 mstouw_opf = 0x111, 2.21 mstosw_opf = 0x113, 2.22 + xmulx_opf = 0x115, 2.23 + xmulxhi_opf = 0x116, 2.24 mxtod_opf = 0x118, 2.25 mwtos_opf = 0x119, 2.26 2.27 @@ -1212,6 +1215,9 @@ 2.28 void movwtos( Register s, FloatRegister d ) { vis3_only(); emit_int32( op(arith_op) | fd(d, FloatRegisterImpl::S) | op3(mftoi_op3) | opf(mwtos_opf) | rs2(s)); } 2.29 void movxtod( Register s, FloatRegister d ) { vis3_only(); emit_int32( op(arith_op) | fd(d, FloatRegisterImpl::D) | op3(mftoi_op3) | opf(mxtod_opf) | rs2(s)); } 2.30 2.31 + void xmulx(Register s1, Register s2, Register d) { vis3_only(); emit_int32( op(arith_op) | rd(d) | op3(xmulx_op3) | rs1(s1) | opf(xmulx_opf) | rs2(s2)); } 2.32 + void xmulxhi(Register s1, Register s2, Register d) { vis3_only(); emit_int32( op(arith_op) | rd(d) | op3(xmulx_op3) | rs1(s1) | opf(xmulxhi_opf) | rs2(s2)); } 2.33 + 2.34 // Crypto SHA instructions 2.35 2.36 void sha1() { sha1_only(); emit_int32( op(arith_op) | op3(sha_op3) | opf(sha1_opf)); }
3.1 --- a/src/cpu/sparc/vm/stubGenerator_sparc.cpp Wed Nov 27 05:33:18 2019 +0000 3.2 +++ b/src/cpu/sparc/vm/stubGenerator_sparc.cpp Wed Dec 04 16:23:46 2019 +0000 3.3 @@ -4788,6 +4788,130 @@ 3.4 return start; 3.5 } 3.6 3.7 + /* Single and multi-block ghash operations */ 3.8 + address generate_ghash_processBlocks() { 3.9 + __ align(CodeEntryAlignment); 3.10 + Label L_ghash_loop, L_aligned, L_main; 3.11 + StubCodeMark mark(this, "StubRoutines", "ghash_processBlocks"); 3.12 + address start = __ pc(); 3.13 + 3.14 + Register state = I0; 3.15 + Register subkeyH = I1; 3.16 + Register data = I2; 3.17 + Register len = I3; 3.18 + 3.19 + __ save_frame(0); 3.20 + 3.21 + __ ldx(state, 0, O0); 3.22 + __ ldx(state, 8, O1); 3.23 + 3.24 + // Loop label for multiblock operations 3.25 + __ BIND(L_ghash_loop); 3.26 + 3.27 + // Check if 'data' is unaligned 3.28 + __ andcc(data, 7, G1); 3.29 + __ br(Assembler::zero, false, Assembler::pt, L_aligned); 3.30 + __ delayed()->nop(); 3.31 + 3.32 + Register left_shift = L1; 3.33 + Register right_shift = L2; 3.34 + Register data_ptr = L3; 3.35 + 3.36 + // Get left and right shift values in bits 3.37 + __ sll(G1, LogBitsPerByte, left_shift); 3.38 + __ mov(64, right_shift); 3.39 + __ sub(right_shift, left_shift, right_shift); 3.40 + 3.41 + // Align to read 'data' 3.42 + __ sub(data, G1, data_ptr); 3.43 + 3.44 + // Load first 8 bytes of 'data' 3.45 + __ ldx(data_ptr, 0, O4); 3.46 + __ sllx(O4, left_shift, O4); 3.47 + __ ldx(data_ptr, 8, O5); 3.48 + __ srlx(O5, right_shift, G4); 3.49 + __ bset(G4, O4); 3.50 + 3.51 + // Load second 8 bytes of 'data' 3.52 + __ sllx(O5, left_shift, O5); 3.53 + __ ldx(data_ptr, 16, G4); 3.54 + __ srlx(G4, right_shift, G4); 3.55 + __ ba(L_main); 3.56 + __ delayed()->bset(G4, O5); 3.57 + 3.58 + // If 'data' is aligned, load normally 3.59 + __ BIND(L_aligned); 3.60 + __ ldx(data, 0, O4); 3.61 + __ ldx(data, 8, O5); 3.62 + 3.63 + __ BIND(L_main); 3.64 + __ ldx(subkeyH, 0, O2); 3.65 + __ ldx(subkeyH, 8, O3); 3.66 + 3.67 + __ xor3(O0, O4, O0); 3.68 + __ xor3(O1, O5, O1); 3.69 + 3.70 + __ xmulxhi(O0, O3, G3); 3.71 + __ xmulx(O0, O2, O5); 3.72 + __ xmulxhi(O1, O2, G4); 3.73 + __ xmulxhi(O1, O3, G5); 3.74 + __ xmulx(O0, O3, G1); 3.75 + __ xmulx(O1, O3, G2); 3.76 + __ xmulx(O1, O2, O3); 3.77 + __ xmulxhi(O0, O2, O4); 3.78 + 3.79 + __ mov(0xE1, O0); 3.80 + __ sllx(O0, 56, O0); 3.81 + 3.82 + __ xor3(O5, G3, O5); 3.83 + __ xor3(O5, G4, O5); 3.84 + __ xor3(G5, G1, G1); 3.85 + __ xor3(G1, O3, G1); 3.86 + __ srlx(G2, 63, O1); 3.87 + __ srlx(G1, 63, G3); 3.88 + __ sllx(G2, 63, O3); 3.89 + __ sllx(G2, 58, O2); 3.90 + __ xor3(O3, O2, O2); 3.91 + 3.92 + __ sllx(G1, 1, G1); 3.93 + __ or3(G1, O1, G1); 3.94 + 3.95 + __ xor3(G1, O2, G1); 3.96 + 3.97 + __ sllx(G2, 1, G2); 3.98 + 3.99 + __ xmulxhi(G1, O0, O1); 3.100 + __ xmulx(G1, O0, O2); 3.101 + __ xmulxhi(G2, O0, O3); 3.102 + __ xmulx(G2, O0, G1); 3.103 + 3.104 + __ xor3(O4, O1, O4); 3.105 + __ xor3(O5, O2, O5); 3.106 + __ xor3(O5, O3, O5); 3.107 + 3.108 + __ sllx(O4, 1, O2); 3.109 + __ srlx(O5, 63, O3); 3.110 + 3.111 + __ or3(O2, O3, O0); 3.112 + 3.113 + __ sllx(O5, 1, O1); 3.114 + __ srlx(G1, 63, O2); 3.115 + __ or3(O1, O2, O1); 3.116 + __ xor3(O1, G3, O1); 3.117 + 3.118 + __ deccc(len); 3.119 + __ br(Assembler::notZero, true, Assembler::pt, L_ghash_loop); 3.120 + __ delayed()->add(data, 16, data); 3.121 + 3.122 + __ stx(O0, I0, 0); 3.123 + __ stx(O1, I0, 8); 3.124 + 3.125 + __ ret(); 3.126 + __ delayed()->restore(); 3.127 + 3.128 + return start; 3.129 + } 3.130 + 3.131 void generate_initial() { 3.132 // Generates all stubs and initializes the entry points 3.133 3.134 @@ -4860,6 +4984,10 @@ 3.135 StubRoutines::_cipherBlockChaining_encryptAESCrypt = generate_cipherBlockChaining_encryptAESCrypt(); 3.136 StubRoutines::_cipherBlockChaining_decryptAESCrypt = generate_cipherBlockChaining_decryptAESCrypt_Parallel(); 3.137 } 3.138 + // generate GHASH intrinsics code 3.139 + if (UseGHASHIntrinsics) { 3.140 + StubRoutines::_ghash_processBlocks = generate_ghash_processBlocks(); 3.141 + } 3.142 3.143 // generate SHA1/SHA256/SHA512 intrinsics code 3.144 if (UseSHA1Intrinsics) {
4.1 --- a/src/cpu/sparc/vm/vm_version_sparc.cpp Wed Nov 27 05:33:18 2019 +0000 4.2 +++ b/src/cpu/sparc/vm/vm_version_sparc.cpp Wed Dec 04 16:23:46 2019 +0000 4.3 @@ -319,6 +319,17 @@ 4.4 } 4.5 } 4.6 4.7 + // GHASH/GCM intrinsics 4.8 + if (has_vis3() && (UseVIS > 2)) { 4.9 + if (FLAG_IS_DEFAULT(UseGHASHIntrinsics)) { 4.10 + UseGHASHIntrinsics = true; 4.11 + } 4.12 + } else if (UseGHASHIntrinsics) { 4.13 + if (!FLAG_IS_DEFAULT(UseGHASHIntrinsics)) 4.14 + warning("GHASH intrinsics require VIS3 insructions support. Intriniscs will be disabled"); 4.15 + FLAG_SET_DEFAULT(UseGHASHIntrinsics, false); 4.16 + } 4.17 + 4.18 // SHA1, SHA256, and SHA512 instructions were added to SPARC T-series at different times 4.19 if (has_sha1() || has_sha256() || has_sha512()) { 4.20 if (UseVIS > 0) { // SHA intrinsics use VIS1 instructions
5.1 --- a/src/cpu/x86/vm/assembler_x86.cpp Wed Nov 27 05:33:18 2019 +0000 5.2 +++ b/src/cpu/x86/vm/assembler_x86.cpp Wed Dec 04 16:23:46 2019 +0000 5.3 @@ -2575,6 +2575,15 @@ 5.4 emit_int8(shift); 5.5 } 5.6 5.7 +void Assembler::pslldq(XMMRegister dst, int shift) { 5.8 + // Shift left 128 bit value in xmm register by number of bytes. 5.9 + NOT_LP64(assert(VM_Version::supports_sse2(), "")); 5.10 + int encode = simd_prefix_and_encode(xmm7, dst, dst, VEX_SIMD_66); 5.11 + emit_int8(0x73); 5.12 + emit_int8((unsigned char)(0xC0 | encode)); 5.13 + emit_int8(shift); 5.14 +} 5.15 + 5.16 void Assembler::ptest(XMMRegister dst, Address src) { 5.17 assert(VM_Version::supports_sse4_1(), ""); 5.18 assert((UseAVX > 0), "SSE mode requires address alignment 16 bytes");
6.1 --- a/src/cpu/x86/vm/assembler_x86.hpp Wed Nov 27 05:33:18 2019 +0000 6.2 +++ b/src/cpu/x86/vm/assembler_x86.hpp Wed Dec 04 16:23:46 2019 +0000 6.3 @@ -1527,6 +1527,8 @@ 6.4 6.5 // Shift Right by bytes Logical DoubleQuadword Immediate 6.6 void psrldq(XMMRegister dst, int shift); 6.7 + // Shift Left by bytes Logical DoubleQuadword Immediate 6.8 + void pslldq(XMMRegister dst, int shift); 6.9 6.10 // Logical Compare 128bit 6.11 void ptest(XMMRegister dst, XMMRegister src);
7.1 --- a/src/cpu/x86/vm/stubGenerator_x86_32.cpp Wed Nov 27 05:33:18 2019 +0000 7.2 +++ b/src/cpu/x86/vm/stubGenerator_x86_32.cpp Wed Dec 04 16:23:46 2019 +0000 7.3 @@ -2719,6 +2719,169 @@ 7.4 return start; 7.5 } 7.6 7.7 + // byte swap x86 long 7.8 + address generate_ghash_long_swap_mask() { 7.9 + __ align(CodeEntryAlignment); 7.10 + StubCodeMark mark(this, "StubRoutines", "ghash_long_swap_mask"); 7.11 + address start = __ pc(); 7.12 + __ emit_data(0x0b0a0908, relocInfo::none, 0); 7.13 + __ emit_data(0x0f0e0d0c, relocInfo::none, 0); 7.14 + __ emit_data(0x03020100, relocInfo::none, 0); 7.15 + __ emit_data(0x07060504, relocInfo::none, 0); 7.16 + 7.17 + return start; 7.18 + } 7.19 + 7.20 + // byte swap x86 byte array 7.21 + address generate_ghash_byte_swap_mask() { 7.22 + __ align(CodeEntryAlignment); 7.23 + StubCodeMark mark(this, "StubRoutines", "ghash_byte_swap_mask"); 7.24 + address start = __ pc(); 7.25 + __ emit_data(0x0c0d0e0f, relocInfo::none, 0); 7.26 + __ emit_data(0x08090a0b, relocInfo::none, 0); 7.27 + __ emit_data(0x04050607, relocInfo::none, 0); 7.28 + __ emit_data(0x00010203, relocInfo::none, 0); 7.29 + return start; 7.30 + } 7.31 + 7.32 + /* Single and multi-block ghash operations */ 7.33 + address generate_ghash_processBlocks() { 7.34 + assert(UseGHASHIntrinsics, "need GHASH intrinsics and CLMUL support"); 7.35 + __ align(CodeEntryAlignment); 7.36 + Label L_ghash_loop, L_exit; 7.37 + StubCodeMark mark(this, "StubRoutines", "ghash_processBlocks"); 7.38 + address start = __ pc(); 7.39 + 7.40 + const Register state = rdi; 7.41 + const Register subkeyH = rsi; 7.42 + const Register data = rdx; 7.43 + const Register blocks = rcx; 7.44 + 7.45 + const Address state_param(rbp, 8+0); 7.46 + const Address subkeyH_param(rbp, 8+4); 7.47 + const Address data_param(rbp, 8+8); 7.48 + const Address blocks_param(rbp, 8+12); 7.49 + 7.50 + const XMMRegister xmm_temp0 = xmm0; 7.51 + const XMMRegister xmm_temp1 = xmm1; 7.52 + const XMMRegister xmm_temp2 = xmm2; 7.53 + const XMMRegister xmm_temp3 = xmm3; 7.54 + const XMMRegister xmm_temp4 = xmm4; 7.55 + const XMMRegister xmm_temp5 = xmm5; 7.56 + const XMMRegister xmm_temp6 = xmm6; 7.57 + const XMMRegister xmm_temp7 = xmm7; 7.58 + 7.59 + __ enter(); 7.60 + handleSOERegisters(true); // Save registers 7.61 + 7.62 + __ movptr(state, state_param); 7.63 + __ movptr(subkeyH, subkeyH_param); 7.64 + __ movptr(data, data_param); 7.65 + __ movptr(blocks, blocks_param); 7.66 + 7.67 + __ movdqu(xmm_temp0, Address(state, 0)); 7.68 + __ pshufb(xmm_temp0, ExternalAddress(StubRoutines::x86::ghash_long_swap_mask_addr())); 7.69 + 7.70 + __ movdqu(xmm_temp1, Address(subkeyH, 0)); 7.71 + __ pshufb(xmm_temp1, ExternalAddress(StubRoutines::x86::ghash_long_swap_mask_addr())); 7.72 + 7.73 + __ BIND(L_ghash_loop); 7.74 + __ movdqu(xmm_temp2, Address(data, 0)); 7.75 + __ pshufb(xmm_temp2, ExternalAddress(StubRoutines::x86::ghash_byte_swap_mask_addr())); 7.76 + 7.77 + __ pxor(xmm_temp0, xmm_temp2); 7.78 + 7.79 + // 7.80 + // Multiply with the hash key 7.81 + // 7.82 + __ movdqu(xmm_temp3, xmm_temp0); 7.83 + __ pclmulqdq(xmm_temp3, xmm_temp1, 0); // xmm3 holds a0*b0 7.84 + __ movdqu(xmm_temp4, xmm_temp0); 7.85 + __ pclmulqdq(xmm_temp4, xmm_temp1, 16); // xmm4 holds a0*b1 7.86 + 7.87 + __ movdqu(xmm_temp5, xmm_temp0); 7.88 + __ pclmulqdq(xmm_temp5, xmm_temp1, 1); // xmm5 holds a1*b0 7.89 + __ movdqu(xmm_temp6, xmm_temp0); 7.90 + __ pclmulqdq(xmm_temp6, xmm_temp1, 17); // xmm6 holds a1*b1 7.91 + 7.92 + __ pxor(xmm_temp4, xmm_temp5); // xmm4 holds a0*b1 + a1*b0 7.93 + 7.94 + __ movdqu(xmm_temp5, xmm_temp4); // move the contents of xmm4 to xmm5 7.95 + __ psrldq(xmm_temp4, 8); // shift by xmm4 64 bits to the right 7.96 + __ pslldq(xmm_temp5, 8); // shift by xmm5 64 bits to the left 7.97 + __ pxor(xmm_temp3, xmm_temp5); 7.98 + __ pxor(xmm_temp6, xmm_temp4); // Register pair <xmm6:xmm3> holds the result 7.99 + // of the carry-less multiplication of 7.100 + // xmm0 by xmm1. 7.101 + 7.102 + // We shift the result of the multiplication by one bit position 7.103 + // to the left to cope for the fact that the bits are reversed. 7.104 + __ movdqu(xmm_temp7, xmm_temp3); 7.105 + __ movdqu(xmm_temp4, xmm_temp6); 7.106 + __ pslld (xmm_temp3, 1); 7.107 + __ pslld(xmm_temp6, 1); 7.108 + __ psrld(xmm_temp7, 31); 7.109 + __ psrld(xmm_temp4, 31); 7.110 + __ movdqu(xmm_temp5, xmm_temp7); 7.111 + __ pslldq(xmm_temp4, 4); 7.112 + __ pslldq(xmm_temp7, 4); 7.113 + __ psrldq(xmm_temp5, 12); 7.114 + __ por(xmm_temp3, xmm_temp7); 7.115 + __ por(xmm_temp6, xmm_temp4); 7.116 + __ por(xmm_temp6, xmm_temp5); 7.117 + 7.118 + // 7.119 + // First phase of the reduction 7.120 + // 7.121 + // Move xmm3 into xmm4, xmm5, xmm7 in order to perform the shifts 7.122 + // independently. 7.123 + __ movdqu(xmm_temp7, xmm_temp3); 7.124 + __ movdqu(xmm_temp4, xmm_temp3); 7.125 + __ movdqu(xmm_temp5, xmm_temp3); 7.126 + __ pslld(xmm_temp7, 31); // packed right shift shifting << 31 7.127 + __ pslld(xmm_temp4, 30); // packed right shift shifting << 30 7.128 + __ pslld(xmm_temp5, 25); // packed right shift shifting << 25 7.129 + __ pxor(xmm_temp7, xmm_temp4); // xor the shifted versions 7.130 + __ pxor(xmm_temp7, xmm_temp5); 7.131 + __ movdqu(xmm_temp4, xmm_temp7); 7.132 + __ pslldq(xmm_temp7, 12); 7.133 + __ psrldq(xmm_temp4, 4); 7.134 + __ pxor(xmm_temp3, xmm_temp7); // first phase of the reduction complete 7.135 + 7.136 + // 7.137 + // Second phase of the reduction 7.138 + // 7.139 + // Make 3 copies of xmm3 in xmm2, xmm5, xmm7 for doing these 7.140 + // shift operations. 7.141 + __ movdqu(xmm_temp2, xmm_temp3); 7.142 + __ movdqu(xmm_temp7, xmm_temp3); 7.143 + __ movdqu(xmm_temp5, xmm_temp3); 7.144 + __ psrld(xmm_temp2, 1); // packed left shifting >> 1 7.145 + __ psrld(xmm_temp7, 2); // packed left shifting >> 2 7.146 + __ psrld(xmm_temp5, 7); // packed left shifting >> 7 7.147 + __ pxor(xmm_temp2, xmm_temp7); // xor the shifted versions 7.148 + __ pxor(xmm_temp2, xmm_temp5); 7.149 + __ pxor(xmm_temp2, xmm_temp4); 7.150 + __ pxor(xmm_temp3, xmm_temp2); 7.151 + __ pxor(xmm_temp6, xmm_temp3); // the result is in xmm6 7.152 + 7.153 + __ decrement(blocks); 7.154 + __ jcc(Assembler::zero, L_exit); 7.155 + __ movdqu(xmm_temp0, xmm_temp6); 7.156 + __ addptr(data, 16); 7.157 + __ jmp(L_ghash_loop); 7.158 + 7.159 + __ BIND(L_exit); 7.160 + // Byte swap 16-byte result 7.161 + __ pshufb(xmm_temp6, ExternalAddress(StubRoutines::x86::ghash_long_swap_mask_addr())); 7.162 + __ movdqu(Address(state, 0), xmm_temp6); // store the result 7.163 + 7.164 + handleSOERegisters(false); // restore registers 7.165 + __ leave(); 7.166 + __ ret(0); 7.167 + return start; 7.168 + } 7.169 + 7.170 /** 7.171 * Arguments: 7.172 * 7.173 @@ -3018,6 +3181,13 @@ 7.174 StubRoutines::_cipherBlockChaining_decryptAESCrypt = generate_cipherBlockChaining_decryptAESCrypt(); 7.175 } 7.176 7.177 + // Generate GHASH intrinsics code 7.178 + if (UseGHASHIntrinsics) { 7.179 + StubRoutines::x86::_ghash_long_swap_mask_addr = generate_ghash_long_swap_mask(); 7.180 + StubRoutines::x86::_ghash_byte_swap_mask_addr = generate_ghash_byte_swap_mask(); 7.181 + StubRoutines::_ghash_processBlocks = generate_ghash_processBlocks(); 7.182 + } 7.183 + 7.184 // Safefetch stubs. 7.185 generate_safefetch("SafeFetch32", sizeof(int), &StubRoutines::_safefetch32_entry, 7.186 &StubRoutines::_safefetch32_fault_pc,
8.1 --- a/src/cpu/x86/vm/stubGenerator_x86_64.cpp Wed Nov 27 05:33:18 2019 +0000 8.2 +++ b/src/cpu/x86/vm/stubGenerator_x86_64.cpp Wed Dec 04 16:23:46 2019 +0000 8.3 @@ -3639,6 +3639,175 @@ 8.4 return start; 8.5 } 8.6 8.7 + 8.8 + // byte swap x86 long 8.9 + address generate_ghash_long_swap_mask() { 8.10 + __ align(CodeEntryAlignment); 8.11 + StubCodeMark mark(this, "StubRoutines", "ghash_long_swap_mask"); 8.12 + address start = __ pc(); 8.13 + __ emit_data64(0x0f0e0d0c0b0a0908, relocInfo::none ); 8.14 + __ emit_data64(0x0706050403020100, relocInfo::none ); 8.15 + return start; 8.16 + } 8.17 + 8.18 + // byte swap x86 byte array 8.19 + address generate_ghash_byte_swap_mask() { 8.20 + __ align(CodeEntryAlignment); 8.21 + StubCodeMark mark(this, "StubRoutines", "ghash_byte_swap_mask"); 8.22 + address start = __ pc(); 8.23 + __ emit_data64(0x08090a0b0c0d0e0f, relocInfo::none ); 8.24 + __ emit_data64(0x0001020304050607, relocInfo::none ); 8.25 + return start; 8.26 + } 8.27 + 8.28 + /* Single and multi-block ghash operations */ 8.29 + address generate_ghash_processBlocks() { 8.30 + __ align(CodeEntryAlignment); 8.31 + Label L_ghash_loop, L_exit; 8.32 + StubCodeMark mark(this, "StubRoutines", "ghash_processBlocks"); 8.33 + address start = __ pc(); 8.34 + 8.35 + const Register state = c_rarg0; 8.36 + const Register subkeyH = c_rarg1; 8.37 + const Register data = c_rarg2; 8.38 + const Register blocks = c_rarg3; 8.39 + 8.40 +#ifdef _WIN64 8.41 + const int XMM_REG_LAST = 10; 8.42 +#endif 8.43 + 8.44 + const XMMRegister xmm_temp0 = xmm0; 8.45 + const XMMRegister xmm_temp1 = xmm1; 8.46 + const XMMRegister xmm_temp2 = xmm2; 8.47 + const XMMRegister xmm_temp3 = xmm3; 8.48 + const XMMRegister xmm_temp4 = xmm4; 8.49 + const XMMRegister xmm_temp5 = xmm5; 8.50 + const XMMRegister xmm_temp6 = xmm6; 8.51 + const XMMRegister xmm_temp7 = xmm7; 8.52 + const XMMRegister xmm_temp8 = xmm8; 8.53 + const XMMRegister xmm_temp9 = xmm9; 8.54 + const XMMRegister xmm_temp10 = xmm10; 8.55 + 8.56 + __ enter(); 8.57 + 8.58 +#ifdef _WIN64 8.59 + // save the xmm registers which must be preserved 6-10 8.60 + __ subptr(rsp, -rsp_after_call_off * wordSize); 8.61 + for (int i = 6; i <= XMM_REG_LAST; i++) { 8.62 + __ movdqu(xmm_save(i), as_XMMRegister(i)); 8.63 + } 8.64 +#endif 8.65 + 8.66 + __ movdqu(xmm_temp10, ExternalAddress(StubRoutines::x86::ghash_long_swap_mask_addr())); 8.67 + 8.68 + __ movdqu(xmm_temp0, Address(state, 0)); 8.69 + __ pshufb(xmm_temp0, xmm_temp10); 8.70 + 8.71 + 8.72 + __ BIND(L_ghash_loop); 8.73 + __ movdqu(xmm_temp2, Address(data, 0)); 8.74 + __ pshufb(xmm_temp2, ExternalAddress(StubRoutines::x86::ghash_byte_swap_mask_addr())); 8.75 + 8.76 + __ movdqu(xmm_temp1, Address(subkeyH, 0)); 8.77 + __ pshufb(xmm_temp1, xmm_temp10); 8.78 + 8.79 + __ pxor(xmm_temp0, xmm_temp2); 8.80 + 8.81 + // 8.82 + // Multiply with the hash key 8.83 + // 8.84 + __ movdqu(xmm_temp3, xmm_temp0); 8.85 + __ pclmulqdq(xmm_temp3, xmm_temp1, 0); // xmm3 holds a0*b0 8.86 + __ movdqu(xmm_temp4, xmm_temp0); 8.87 + __ pclmulqdq(xmm_temp4, xmm_temp1, 16); // xmm4 holds a0*b1 8.88 + 8.89 + __ movdqu(xmm_temp5, xmm_temp0); 8.90 + __ pclmulqdq(xmm_temp5, xmm_temp1, 1); // xmm5 holds a1*b0 8.91 + __ movdqu(xmm_temp6, xmm_temp0); 8.92 + __ pclmulqdq(xmm_temp6, xmm_temp1, 17); // xmm6 holds a1*b1 8.93 + 8.94 + __ pxor(xmm_temp4, xmm_temp5); // xmm4 holds a0*b1 + a1*b0 8.95 + 8.96 + __ movdqu(xmm_temp5, xmm_temp4); // move the contents of xmm4 to xmm5 8.97 + __ psrldq(xmm_temp4, 8); // shift by xmm4 64 bits to the right 8.98 + __ pslldq(xmm_temp5, 8); // shift by xmm5 64 bits to the left 8.99 + __ pxor(xmm_temp3, xmm_temp5); 8.100 + __ pxor(xmm_temp6, xmm_temp4); // Register pair <xmm6:xmm3> holds the result 8.101 + // of the carry-less multiplication of 8.102 + // xmm0 by xmm1. 8.103 + 8.104 + // We shift the result of the multiplication by one bit position 8.105 + // to the left to cope for the fact that the bits are reversed. 8.106 + __ movdqu(xmm_temp7, xmm_temp3); 8.107 + __ movdqu(xmm_temp8, xmm_temp6); 8.108 + __ pslld(xmm_temp3, 1); 8.109 + __ pslld(xmm_temp6, 1); 8.110 + __ psrld(xmm_temp7, 31); 8.111 + __ psrld(xmm_temp8, 31); 8.112 + __ movdqu(xmm_temp9, xmm_temp7); 8.113 + __ pslldq(xmm_temp8, 4); 8.114 + __ pslldq(xmm_temp7, 4); 8.115 + __ psrldq(xmm_temp9, 12); 8.116 + __ por(xmm_temp3, xmm_temp7); 8.117 + __ por(xmm_temp6, xmm_temp8); 8.118 + __ por(xmm_temp6, xmm_temp9); 8.119 + 8.120 + // 8.121 + // First phase of the reduction 8.122 + // 8.123 + // Move xmm3 into xmm7, xmm8, xmm9 in order to perform the shifts 8.124 + // independently. 8.125 + __ movdqu(xmm_temp7, xmm_temp3); 8.126 + __ movdqu(xmm_temp8, xmm_temp3); 8.127 + __ movdqu(xmm_temp9, xmm_temp3); 8.128 + __ pslld(xmm_temp7, 31); // packed right shift shifting << 31 8.129 + __ pslld(xmm_temp8, 30); // packed right shift shifting << 30 8.130 + __ pslld(xmm_temp9, 25); // packed right shift shifting << 25 8.131 + __ pxor(xmm_temp7, xmm_temp8); // xor the shifted versions 8.132 + __ pxor(xmm_temp7, xmm_temp9); 8.133 + __ movdqu(xmm_temp8, xmm_temp7); 8.134 + __ pslldq(xmm_temp7, 12); 8.135 + __ psrldq(xmm_temp8, 4); 8.136 + __ pxor(xmm_temp3, xmm_temp7); // first phase of the reduction complete 8.137 + 8.138 + // 8.139 + // Second phase of the reduction 8.140 + // 8.141 + // Make 3 copies of xmm3 in xmm2, xmm4, xmm5 for doing these 8.142 + // shift operations. 8.143 + __ movdqu(xmm_temp2, xmm_temp3); 8.144 + __ movdqu(xmm_temp4, xmm_temp3); 8.145 + __ movdqu(xmm_temp5, xmm_temp3); 8.146 + __ psrld(xmm_temp2, 1); // packed left shifting >> 1 8.147 + __ psrld(xmm_temp4, 2); // packed left shifting >> 2 8.148 + __ psrld(xmm_temp5, 7); // packed left shifting >> 7 8.149 + __ pxor(xmm_temp2, xmm_temp4); // xor the shifted versions 8.150 + __ pxor(xmm_temp2, xmm_temp5); 8.151 + __ pxor(xmm_temp2, xmm_temp8); 8.152 + __ pxor(xmm_temp3, xmm_temp2); 8.153 + __ pxor(xmm_temp6, xmm_temp3); // the result is in xmm6 8.154 + 8.155 + __ decrement(blocks); 8.156 + __ jcc(Assembler::zero, L_exit); 8.157 + __ movdqu(xmm_temp0, xmm_temp6); 8.158 + __ addptr(data, 16); 8.159 + __ jmp(L_ghash_loop); 8.160 + 8.161 + __ BIND(L_exit); 8.162 + __ pshufb(xmm_temp6, xmm_temp10); // Byte swap 16-byte result 8.163 + __ movdqu(Address(state, 0), xmm_temp6); // store the result 8.164 + 8.165 +#ifdef _WIN64 8.166 + // restore xmm regs belonging to calling function 8.167 + for (int i = 6; i <= XMM_REG_LAST; i++) { 8.168 + __ movdqu(as_XMMRegister(i), xmm_save(i)); 8.169 + } 8.170 +#endif 8.171 + __ leave(); 8.172 + __ ret(0); 8.173 + return start; 8.174 + } 8.175 + 8.176 /** 8.177 * Arguments: 8.178 * 8.179 @@ -4077,6 +4246,13 @@ 8.180 StubRoutines::_cipherBlockChaining_decryptAESCrypt = generate_cipherBlockChaining_decryptAESCrypt_Parallel(); 8.181 } 8.182 8.183 + // Generate GHASH intrinsics code 8.184 + if (UseGHASHIntrinsics) { 8.185 + StubRoutines::x86::_ghash_long_swap_mask_addr = generate_ghash_long_swap_mask(); 8.186 + StubRoutines::x86::_ghash_byte_swap_mask_addr = generate_ghash_byte_swap_mask(); 8.187 + StubRoutines::_ghash_processBlocks = generate_ghash_processBlocks(); 8.188 + } 8.189 + 8.190 // Safefetch stubs. 8.191 generate_safefetch("SafeFetch32", sizeof(int), &StubRoutines::_safefetch32_entry, 8.192 &StubRoutines::_safefetch32_fault_pc,
9.1 --- a/src/cpu/x86/vm/stubRoutines_x86.cpp Wed Nov 27 05:33:18 2019 +0000 9.2 +++ b/src/cpu/x86/vm/stubRoutines_x86.cpp Wed Dec 04 16:23:46 2019 +0000 9.3 @@ -1,5 +1,5 @@ 9.4 /* 9.5 - * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. 9.6 + * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved. 9.7 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 9.8 * 9.9 * This code is free software; you can redistribute it and/or modify it 9.10 @@ -33,6 +33,8 @@ 9.11 9.12 address StubRoutines::x86::_verify_mxcsr_entry = NULL; 9.13 address StubRoutines::x86::_key_shuffle_mask_addr = NULL; 9.14 +address StubRoutines::x86::_ghash_long_swap_mask_addr = NULL; 9.15 +address StubRoutines::x86::_ghash_byte_swap_mask_addr = NULL; 9.16 9.17 uint64_t StubRoutines::x86::_crc_by128_masks[] = 9.18 {
10.1 --- a/src/cpu/x86/vm/stubRoutines_x86.hpp Wed Nov 27 05:33:18 2019 +0000 10.2 +++ b/src/cpu/x86/vm/stubRoutines_x86.hpp Wed Dec 04 16:23:46 2019 +0000 10.3 @@ -1,5 +1,5 @@ 10.4 /* 10.5 - * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. 10.6 + * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved. 10.7 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 10.8 * 10.9 * This code is free software; you can redistribute it and/or modify it 10.10 @@ -36,10 +36,15 @@ 10.11 // masks and table for CRC32 10.12 static uint64_t _crc_by128_masks[]; 10.13 static juint _crc_table[]; 10.14 + // swap mask for ghash 10.15 + static address _ghash_long_swap_mask_addr; 10.16 + static address _ghash_byte_swap_mask_addr; 10.17 10.18 public: 10.19 static address verify_mxcsr_entry() { return _verify_mxcsr_entry; } 10.20 static address key_shuffle_mask_addr() { return _key_shuffle_mask_addr; } 10.21 static address crc_by128_masks_addr() { return (address)_crc_by128_masks; } 10.22 + static address ghash_long_swap_mask_addr() { return _ghash_long_swap_mask_addr; } 10.23 + static address ghash_byte_swap_mask_addr() { return _ghash_byte_swap_mask_addr; } 10.24 10.25 #endif // CPU_X86_VM_STUBROUTINES_X86_32_HPP
11.1 --- a/src/cpu/x86/vm/vm_version_x86.cpp Wed Nov 27 05:33:18 2019 +0000 11.2 +++ b/src/cpu/x86/vm/vm_version_x86.cpp Wed Dec 04 16:23:46 2019 +0000 11.3 @@ -594,6 +594,17 @@ 11.4 FLAG_SET_DEFAULT(UseAESIntrinsics, false); 11.5 } 11.6 11.7 + // GHASH/GCM intrinsics 11.8 + if (UseCLMUL && (UseSSE > 2)) { 11.9 + if (FLAG_IS_DEFAULT(UseGHASHIntrinsics)) { 11.10 + UseGHASHIntrinsics = true; 11.11 + } 11.12 + } else if (UseGHASHIntrinsics) { 11.13 + if (!FLAG_IS_DEFAULT(UseGHASHIntrinsics)) 11.14 + warning("GHASH intrinsic requires CLMUL and SSE2 instructions on this CPU"); 11.15 + FLAG_SET_DEFAULT(UseGHASHIntrinsics, false); 11.16 + } 11.17 + 11.18 if (UseSHA) { 11.19 warning("SHA instructions are not available on this CPU"); 11.20 FLAG_SET_DEFAULT(UseSHA, false);
12.1 --- a/src/share/vm/classfile/vmSymbols.hpp Wed Nov 27 05:33:18 2019 +0000 12.2 +++ b/src/share/vm/classfile/vmSymbols.hpp Wed Dec 04 16:23:46 2019 +0000 12.3 @@ -863,6 +863,12 @@ 12.4 do_name( implCompressMB_name, "implCompressMultiBlock0") \ 12.5 do_signature(implCompressMB_signature, "([BII)I") \ 12.6 \ 12.7 + /* support for com.sun.crypto.provider.GHASH */ \ 12.8 + do_class(com_sun_crypto_provider_ghash, "com/sun/crypto/provider/GHASH") \ 12.9 + do_intrinsic(_ghash_processBlocks, com_sun_crypto_provider_ghash, processBlocks_name, ghash_processBlocks_signature, F_S) \ 12.10 + do_name(processBlocks_name, "processBlocks") \ 12.11 + do_signature(ghash_processBlocks_signature, "([BII[J[J)V") \ 12.12 + \ 12.13 /* support for java.util.zip */ \ 12.14 do_class(java_util_zip_CRC32, "java/util/zip/CRC32") \ 12.15 do_intrinsic(_updateCRC32, java_util_zip_CRC32, update_name, int2_int_signature, F_SN) \
13.1 --- a/src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp Wed Nov 27 05:33:18 2019 +0000 13.2 +++ b/src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp Wed Dec 04 16:23:46 2019 +0000 13.3 @@ -2520,6 +2520,12 @@ 13.4 } 13.5 } 13.6 } 13.7 + } else if (GC_locker::should_discard(cause, gc_count_before)) { 13.8 + // Return to be consistent with VMOp failure due to another 13.9 + // collection slipping in after our gc_count but before our 13.10 + // request is processed. _gc_locker collections upgraded by 13.11 + // GCLockerInvokesConcurrent are handled above and never discarded. 13.12 + return; 13.13 } else { 13.14 if (cause == GCCause::_gc_locker || cause == GCCause::_wb_young_gc 13.15 DEBUG_ONLY(|| cause == GCCause::_scavenge_alot)) {
14.1 --- a/src/share/vm/gc_implementation/parallelScavenge/parallelScavengeHeap.cpp Wed Nov 27 05:33:18 2019 +0000 14.2 +++ b/src/share/vm/gc_implementation/parallelScavenge/parallelScavengeHeap.cpp Wed Dec 04 16:23:46 2019 +0000 14.3 @@ -530,6 +530,10 @@ 14.4 full_gc_count = Universe::heap()->total_full_collections(); 14.5 } 14.6 14.7 + if (GC_locker::should_discard(cause, gc_count)) { 14.8 + return; 14.9 + } 14.10 + 14.11 VM_ParallelGCSystemGC op(gc_count, full_gc_count, cause); 14.12 VMThread::execute(&op); 14.13 }
15.1 --- a/src/share/vm/gc_implementation/parallelScavenge/vmPSOperations.cpp Wed Nov 27 05:33:18 2019 +0000 15.2 +++ b/src/share/vm/gc_implementation/parallelScavenge/vmPSOperations.cpp Wed Dec 04 16:23:46 2019 +0000 15.3 @@ -52,11 +52,16 @@ 15.4 } 15.5 } 15.6 15.7 +static bool is_cause_full(GCCause::Cause cause) { 15.8 + return (cause != GCCause::_gc_locker) && (cause != GCCause::_wb_young_gc) 15.9 + DEBUG_ONLY(&& (cause != GCCause::_scavenge_alot)); 15.10 +} 15.11 + 15.12 // Only used for System.gc() calls 15.13 VM_ParallelGCSystemGC::VM_ParallelGCSystemGC(uint gc_count, 15.14 uint full_gc_count, 15.15 GCCause::Cause gc_cause) : 15.16 - VM_GC_Operation(gc_count, gc_cause, full_gc_count, true /* full */) 15.17 + VM_GC_Operation(gc_count, gc_cause, full_gc_count, is_cause_full(gc_cause)) 15.18 { 15.19 } 15.20 15.21 @@ -68,8 +73,7 @@ 15.22 "must be a ParallelScavengeHeap"); 15.23 15.24 GCCauseSetter gccs(heap, _gc_cause); 15.25 - if (_gc_cause == GCCause::_gc_locker || _gc_cause == GCCause::_wb_young_gc 15.26 - DEBUG_ONLY(|| _gc_cause == GCCause::_scavenge_alot)) { 15.27 + if (!_full) { 15.28 // If (and only if) the scavenge fails, this will invoke a full gc. 15.29 heap->invoke_scavenge(); 15.30 } else {
16.1 --- a/src/share/vm/gc_implementation/shared/vmGCOperations.cpp Wed Nov 27 05:33:18 2019 +0000 16.2 +++ b/src/share/vm/gc_implementation/shared/vmGCOperations.cpp Wed Dec 04 16:23:46 2019 +0000 16.3 @@ -201,6 +201,19 @@ 16.4 } 16.5 } 16.6 16.7 +static bool is_full_gc(int max_level) { 16.8 + // Return true if max_level is all generations 16.9 + return (max_level == (GenCollectedHeap::heap()->n_gens() - 1)); 16.10 +} 16.11 + 16.12 +VM_GenCollectFull::VM_GenCollectFull(uint gc_count_before, 16.13 + uint full_gc_count_before, 16.14 + GCCause::Cause gc_cause, 16.15 + int max_level) : 16.16 + VM_GC_Operation(gc_count_before, gc_cause, full_gc_count_before, 16.17 + is_full_gc(max_level) /* full */), 16.18 + _max_level(max_level) { } 16.19 + 16.20 void VM_GenCollectFull::doit() { 16.21 SvcGCMarker sgcm(SvcGCMarker::FULL); 16.22
17.1 --- a/src/share/vm/gc_implementation/shared/vmGCOperations.hpp Wed Nov 27 05:33:18 2019 +0000 17.2 +++ b/src/share/vm/gc_implementation/shared/vmGCOperations.hpp Wed Dec 04 16:23:46 2019 +0000 17.3 @@ -201,9 +201,7 @@ 17.4 VM_GenCollectFull(uint gc_count_before, 17.5 uint full_gc_count_before, 17.6 GCCause::Cause gc_cause, 17.7 - int max_level) 17.8 - : VM_GC_Operation(gc_count_before, gc_cause, full_gc_count_before, true /* full */), 17.9 - _max_level(max_level) { } 17.10 + int max_level); 17.11 ~VM_GenCollectFull() {} 17.12 virtual VMOp_Type type() const { return VMOp_GenCollectFull; } 17.13 virtual void doit();
18.1 --- a/src/share/vm/memory/gcLocker.cpp Wed Nov 27 05:33:18 2019 +0000 18.2 +++ b/src/share/vm/memory/gcLocker.cpp Wed Dec 04 16:23:46 2019 +0000 18.3 @@ -31,6 +31,7 @@ 18.4 volatile jint GC_locker::_jni_lock_count = 0; 18.5 volatile bool GC_locker::_needs_gc = false; 18.6 volatile bool GC_locker::_doing_gc = false; 18.7 +unsigned int GC_locker::_total_collections = 0; 18.8 18.9 #ifdef ASSERT 18.10 volatile jint GC_locker::_debug_jni_lock_count = 0; 18.11 @@ -94,6 +95,11 @@ 18.12 } 18.13 } 18.14 18.15 +bool GC_locker::should_discard(GCCause::Cause cause, uint total_collections) { 18.16 + return (cause == GCCause::_gc_locker) && 18.17 + (_total_collections != total_collections); 18.18 +} 18.19 + 18.20 void GC_locker::jni_lock(JavaThread* thread) { 18.21 assert(!thread->in_critical(), "shouldn't currently be in a critical region"); 18.22 MutexLocker mu(JNICritical_lock); 18.23 @@ -117,7 +123,13 @@ 18.24 decrement_debug_jni_lock_count(); 18.25 thread->exit_critical(); 18.26 if (needs_gc() && !is_active_internal()) { 18.27 - // We're the last thread out. Cause a GC to occur. 18.28 + // We're the last thread out. Request a GC. 18.29 + // Capture the current total collections, to allow detection of 18.30 + // other collections that make this one unnecessary. The value of 18.31 + // total_collections() is only changed at a safepoint, so there 18.32 + // must not be a safepoint between the lock becoming inactive and 18.33 + // getting the count, else there may be unnecessary GCLocker GCs. 18.34 + _total_collections = Universe::heap()->total_collections(); 18.35 _doing_gc = true; 18.36 { 18.37 // Must give up the lock while at a safepoint
19.1 --- a/src/share/vm/memory/gcLocker.hpp Wed Nov 27 05:33:18 2019 +0000 19.2 +++ b/src/share/vm/memory/gcLocker.hpp Wed Dec 04 16:23:46 2019 +0000 19.3 @@ -26,6 +26,7 @@ 19.4 #define SHARE_VM_MEMORY_GCLOCKER_HPP 19.5 19.6 #include "gc_interface/collectedHeap.hpp" 19.7 +#include "gc_interface/gcCause.hpp" 19.8 #include "memory/genCollectedHeap.hpp" 19.9 #include "memory/universe.hpp" 19.10 #include "oops/oop.hpp" 19.11 @@ -57,6 +58,7 @@ 19.12 static volatile bool _needs_gc; // heap is filling, we need a GC 19.13 // note: bool is typedef'd as jint 19.14 static volatile bool _doing_gc; // unlock_critical() is doing a GC 19.15 + static uint _total_collections; // value for _gc_locker collection 19.16 19.17 #ifdef ASSERT 19.18 // This lock count is updated for all operations and is used to 19.19 @@ -116,6 +118,12 @@ 19.20 // Sets _needs_gc if is_active() is true. Returns is_active(). 19.21 static bool check_active_before_gc(); 19.22 19.23 + // Return true if the designated collection is a GCLocker request 19.24 + // that should be discarded. Returns true if cause == GCCause::_gc_locker 19.25 + // and the given total collection value indicates a collection has been 19.26 + // done since the GCLocker request was made. 19.27 + static bool should_discard(GCCause::Cause cause, uint total_collections); 19.28 + 19.29 // Stalls the caller (who should not be in a jni critical section) 19.30 // until needs_gc() clears. Note however that needs_gc() may be 19.31 // set at a subsequent safepoint and/or cleared under the
20.1 --- a/src/share/vm/memory/genCollectedHeap.cpp Wed Nov 27 05:33:18 2019 +0000 20.2 +++ b/src/share/vm/memory/genCollectedHeap.cpp Wed Dec 04 16:23:46 2019 +0000 20.3 @@ -796,8 +796,11 @@ 20.4 #else // INCLUDE_ALL_GCS 20.5 ShouldNotReachHere(); 20.6 #endif // INCLUDE_ALL_GCS 20.7 - } else if (cause == GCCause::_wb_young_gc) { 20.8 - // minor collection for WhiteBox API 20.9 + } else if ((cause == GCCause::_wb_young_gc) || 20.10 + (cause == GCCause::_gc_locker)) { 20.11 + // minor collection for WhiteBox or GCLocker. 20.12 + // _gc_locker collections upgraded by GCLockerInvokesConcurrent 20.13 + // are handled above and never discarded. 20.14 collect(cause, 0); 20.15 } else { 20.16 #ifdef ASSERT 20.17 @@ -835,6 +838,11 @@ 20.18 // Read the GC count while holding the Heap_lock 20.19 unsigned int gc_count_before = total_collections(); 20.20 unsigned int full_gc_count_before = total_full_collections(); 20.21 + 20.22 + if (GC_locker::should_discard(cause, gc_count_before)) { 20.23 + return; 20.24 + } 20.25 + 20.26 { 20.27 MutexUnlocker mu(Heap_lock); // give up heap lock, execute gets it back 20.28 VM_GenCollectFull op(gc_count_before, full_gc_count_before, 20.29 @@ -887,24 +895,16 @@ 20.30 20.31 void GenCollectedHeap::do_full_collection(bool clear_all_soft_refs, 20.32 int max_level) { 20.33 - int local_max_level; 20.34 - if (!incremental_collection_will_fail(false /* don't consult_young */) && 20.35 - gc_cause() == GCCause::_gc_locker) { 20.36 - local_max_level = 0; 20.37 - } else { 20.38 - local_max_level = max_level; 20.39 - } 20.40 20.41 do_collection(true /* full */, 20.42 clear_all_soft_refs /* clear_all_soft_refs */, 20.43 0 /* size */, 20.44 false /* is_tlab */, 20.45 - local_max_level /* max_level */); 20.46 + max_level /* max_level */); 20.47 // Hack XXX FIX ME !!! 20.48 // A scavenge may not have been attempted, or may have 20.49 // been attempted and failed, because the old gen was too full 20.50 - if (local_max_level == 0 && gc_cause() == GCCause::_gc_locker && 20.51 - incremental_collection_will_fail(false /* don't consult_young */)) { 20.52 + if (gc_cause() == GCCause::_gc_locker && incremental_collection_failed()) { 20.53 if (PrintGCDetails) { 20.54 gclog_or_tty->print_cr("GC locker: Trying a full collection " 20.55 "because scavenge failed");
21.1 --- a/src/share/vm/opto/escape.cpp Wed Nov 27 05:33:18 2019 +0000 21.2 +++ b/src/share/vm/opto/escape.cpp Wed Dec 04 16:23:46 2019 +0000 21.3 @@ -952,6 +952,7 @@ 21.4 strcmp(call->as_CallLeaf()->_name, "aescrypt_decryptBlock") == 0 || 21.5 strcmp(call->as_CallLeaf()->_name, "cipherBlockChaining_encryptAESCrypt") == 0 || 21.6 strcmp(call->as_CallLeaf()->_name, "cipherBlockChaining_decryptAESCrypt") == 0 || 21.7 + strcmp(call->as_CallLeaf()->_name, "ghash_processBlocks") == 0 || 21.8 strcmp(call->as_CallLeaf()->_name, "sha1_implCompress") == 0 || 21.9 strcmp(call->as_CallLeaf()->_name, "sha1_implCompressMB") == 0 || 21.10 strcmp(call->as_CallLeaf()->_name, "sha256_implCompress") == 0 ||
22.1 --- a/src/share/vm/opto/library_call.cpp Wed Nov 27 05:33:18 2019 +0000 22.2 +++ b/src/share/vm/opto/library_call.cpp Wed Dec 04 16:23:46 2019 +0000 22.3 @@ -311,6 +311,7 @@ 22.4 Node* inline_cipherBlockChaining_AESCrypt_predicate(bool decrypting); 22.5 Node* get_key_start_from_aescrypt_object(Node* aescrypt_object); 22.6 Node* get_original_key_start_from_aescrypt_object(Node* aescrypt_object); 22.7 + bool inline_ghash_processBlocks(); 22.8 bool inline_sha_implCompress(vmIntrinsics::ID id); 22.9 bool inline_digestBase_implCompressMB(int predicate); 22.10 bool inline_sha_implCompressMB(Node* digestBaseObj, ciInstanceKlass* instklass_SHA, 22.11 @@ -570,6 +571,10 @@ 22.12 predicates = 3; 22.13 break; 22.14 22.15 + case vmIntrinsics::_ghash_processBlocks: 22.16 + if (!UseGHASHIntrinsics) return NULL; 22.17 + break; 22.18 + 22.19 case vmIntrinsics::_updateCRC32: 22.20 case vmIntrinsics::_updateBytesCRC32: 22.21 case vmIntrinsics::_updateByteBufferCRC32: 22.22 @@ -957,6 +962,9 @@ 22.23 case vmIntrinsics::_montgomerySquare: 22.24 return inline_montgomerySquare(); 22.25 22.26 + case vmIntrinsics::_ghash_processBlocks: 22.27 + return inline_ghash_processBlocks(); 22.28 + 22.29 case vmIntrinsics::_encodeISOArray: 22.30 return inline_encodeISOArray(); 22.31 22.32 @@ -6599,6 +6607,35 @@ 22.33 return _gvn.transform(region); 22.34 } 22.35 22.36 +//------------------------------inline_ghash_processBlocks 22.37 +bool LibraryCallKit::inline_ghash_processBlocks() { 22.38 + address stubAddr; 22.39 + const char *stubName; 22.40 + assert(UseGHASHIntrinsics, "need GHASH intrinsics support"); 22.41 + 22.42 + stubAddr = StubRoutines::ghash_processBlocks(); 22.43 + stubName = "ghash_processBlocks"; 22.44 + 22.45 + Node* data = argument(0); 22.46 + Node* offset = argument(1); 22.47 + Node* len = argument(2); 22.48 + Node* state = argument(3); 22.49 + Node* subkeyH = argument(4); 22.50 + 22.51 + Node* state_start = array_element_address(state, intcon(0), T_LONG); 22.52 + assert(state_start, "state is NULL"); 22.53 + Node* subkeyH_start = array_element_address(subkeyH, intcon(0), T_LONG); 22.54 + assert(subkeyH_start, "subkeyH is NULL"); 22.55 + Node* data_start = array_element_address(data, offset, T_BYTE); 22.56 + assert(data_start, "data is NULL"); 22.57 + 22.58 + Node* ghash = make_runtime_call(RC_LEAF|RC_NO_FP, 22.59 + OptoRuntime::ghash_processBlocks_Type(), 22.60 + stubAddr, stubName, TypePtr::BOTTOM, 22.61 + state_start, subkeyH_start, data_start, len); 22.62 + return true; 22.63 +} 22.64 + 22.65 //------------------------------inline_sha_implCompress----------------------- 22.66 // 22.67 // Calculate SHA (i.e., SHA-1) for single-block byte[] array.
23.1 --- a/src/share/vm/opto/runtime.cpp Wed Nov 27 05:33:18 2019 +0000 23.2 +++ b/src/share/vm/opto/runtime.cpp Wed Dec 04 16:23:46 2019 +0000 23.3 @@ -92,7 +92,25 @@ 23.4 // At command line specify the parameters: -XX:+FullGCALot -XX:FullGCALotStart=100000000 23.5 23.6 23.7 +// GHASH block processing 23.8 +const TypeFunc* OptoRuntime::ghash_processBlocks_Type() { 23.9 + int argcnt = 4; 23.10 23.11 + const Type** fields = TypeTuple::fields(argcnt); 23.12 + int argp = TypeFunc::Parms; 23.13 + fields[argp++] = TypePtr::NOTNULL; // state 23.14 + fields[argp++] = TypePtr::NOTNULL; // subkeyH 23.15 + fields[argp++] = TypePtr::NOTNULL; // data 23.16 + fields[argp++] = TypeInt::INT; // blocks 23.17 + assert(argp == TypeFunc::Parms+argcnt, "correct decoding"); 23.18 + const TypeTuple* domain = TypeTuple::make(TypeFunc::Parms+argcnt, fields); 23.19 + 23.20 + // result type needed 23.21 + fields = TypeTuple::fields(1); 23.22 + fields[TypeFunc::Parms+0] = NULL; // void 23.23 + const TypeTuple* range = TypeTuple::make(TypeFunc::Parms, fields); 23.24 + return TypeFunc::make(domain, range); 23.25 +} 23.26 23.27 // Compiled code entry points 23.28 address OptoRuntime::_new_instance_Java = NULL;
24.1 --- a/src/share/vm/opto/runtime.hpp Wed Nov 27 05:33:18 2019 +0000 24.2 +++ b/src/share/vm/opto/runtime.hpp Wed Dec 04 16:23:46 2019 +0000 24.3 @@ -311,6 +311,8 @@ 24.4 static const TypeFunc* montgomeryMultiply_Type(); 24.5 static const TypeFunc* montgomerySquare_Type(); 24.6 24.7 + static const TypeFunc* ghash_processBlocks_Type(); 24.8 + 24.9 static const TypeFunc* updateBytesCRC32_Type(); 24.10 24.11 // leaf on stack replacement interpreter accessor types
25.1 --- a/src/share/vm/runtime/globals.hpp Wed Nov 27 05:33:18 2019 +0000 25.2 +++ b/src/share/vm/runtime/globals.hpp Wed Dec 04 16:23:46 2019 +0000 25.3 @@ -602,6 +602,9 @@ 25.4 product(bool, UseSHA, false, \ 25.5 "Control whether SHA instructions can be used on SPARC") \ 25.6 \ 25.7 + product(bool, UseGHASHIntrinsics, false, \ 25.8 + "Use intrinsics for GHASH versions of crypto") \ 25.9 + \ 25.10 product(uintx, LargePageSizeInBytes, 0, \ 25.11 "Large page size (0 to let VM choose the page size)") \ 25.12 \
26.1 --- a/src/share/vm/runtime/stubRoutines.cpp Wed Nov 27 05:33:18 2019 +0000 26.2 +++ b/src/share/vm/runtime/stubRoutines.cpp Wed Dec 04 16:23:46 2019 +0000 26.3 @@ -124,6 +124,7 @@ 26.4 address StubRoutines::_aescrypt_decryptBlock = NULL; 26.5 address StubRoutines::_cipherBlockChaining_encryptAESCrypt = NULL; 26.6 address StubRoutines::_cipherBlockChaining_decryptAESCrypt = NULL; 26.7 +address StubRoutines::_ghash_processBlocks = NULL; 26.8 26.9 address StubRoutines::_sha1_implCompress = NULL; 26.10 address StubRoutines::_sha1_implCompressMB = NULL;
27.1 --- a/src/share/vm/runtime/stubRoutines.hpp Wed Nov 27 05:33:18 2019 +0000 27.2 +++ b/src/share/vm/runtime/stubRoutines.hpp Wed Dec 04 16:23:46 2019 +0000 27.3 @@ -197,6 +197,7 @@ 27.4 static address _aescrypt_decryptBlock; 27.5 static address _cipherBlockChaining_encryptAESCrypt; 27.6 static address _cipherBlockChaining_decryptAESCrypt; 27.7 + static address _ghash_processBlocks; 27.8 27.9 static address _sha1_implCompress; 27.10 static address _sha1_implCompressMB; 27.11 @@ -359,6 +360,7 @@ 27.12 static address aescrypt_decryptBlock() { return _aescrypt_decryptBlock; } 27.13 static address cipherBlockChaining_encryptAESCrypt() { return _cipherBlockChaining_encryptAESCrypt; } 27.14 static address cipherBlockChaining_decryptAESCrypt() { return _cipherBlockChaining_decryptAESCrypt; } 27.15 + static address ghash_processBlocks() { return _ghash_processBlocks; } 27.16 27.17 static address sha1_implCompress() { return _sha1_implCompress; } 27.18 static address sha1_implCompressMB() { return _sha1_implCompressMB; }
28.1 --- a/src/share/vm/runtime/vmStructs.cpp Wed Nov 27 05:33:18 2019 +0000 28.2 +++ b/src/share/vm/runtime/vmStructs.cpp Wed Dec 04 16:23:46 2019 +0000 28.3 @@ -810,6 +810,7 @@ 28.4 static_field(StubRoutines, _aescrypt_decryptBlock, address) \ 28.5 static_field(StubRoutines, _cipherBlockChaining_encryptAESCrypt, address) \ 28.6 static_field(StubRoutines, _cipherBlockChaining_decryptAESCrypt, address) \ 28.7 + static_field(StubRoutines, _ghash_processBlocks, address) \ 28.8 static_field(StubRoutines, _updateBytesCRC32, address) \ 28.9 static_field(StubRoutines, _crc_table_adr, address) \ 28.10 static_field(StubRoutines, _multiplyToLen, address) \
29.1 --- a/test/compiler/7184394/TestAESBase.java Wed Nov 27 05:33:18 2019 +0000 29.2 +++ b/test/compiler/7184394/TestAESBase.java Wed Dec 04 16:23:46 2019 +0000 29.3 @@ -29,6 +29,7 @@ 29.4 import javax.crypto.Cipher; 29.5 import javax.crypto.KeyGenerator; 29.6 import javax.crypto.SecretKey; 29.7 +import javax.crypto.spec.GCMParameterSpec; 29.8 import javax.crypto.spec.IvParameterSpec; 29.9 import javax.crypto.spec.SecretKeySpec; 29.10 import java.security.AlgorithmParameters; 29.11 @@ -62,8 +63,12 @@ 29.12 Random random = new Random(0); 29.13 Cipher cipher; 29.14 Cipher dCipher; 29.15 - AlgorithmParameters algParams; 29.16 + AlgorithmParameters algParams = null; 29.17 SecretKey key; 29.18 + GCMParameterSpec gcm_spec; 29.19 + byte[] aad = { 0x11, 0x22, 0x33, 0x44, 0x55 }; 29.20 + int tlen = 12; 29.21 + byte[] iv = new byte[16]; 29.22 29.23 static int numThreads = 0; 29.24 int threadId; 29.25 @@ -77,7 +82,10 @@ 29.26 29.27 public void prepare() { 29.28 try { 29.29 - System.out.println("\nalgorithm=" + algorithm + ", mode=" + mode + ", paddingStr=" + paddingStr + ", msgSize=" + msgSize + ", keySize=" + keySize + ", noReinit=" + noReinit + ", checkOutput=" + checkOutput + ", encInputOffset=" + encInputOffset + ", encOutputOffset=" + encOutputOffset + ", decOutputOffset=" + decOutputOffset + ", lastChunkSize=" +lastChunkSize ); 29.30 + System.out.println("\nalgorithm=" + algorithm + ", mode=" + mode + ", paddingStr=" + paddingStr + 29.31 + ", msgSize=" + msgSize + ", keySize=" + keySize + ", noReinit=" + noReinit + 29.32 + ", checkOutput=" + checkOutput + ", encInputOffset=" + encInputOffset + ", encOutputOffset=" + 29.33 + encOutputOffset + ", decOutputOffset=" + decOutputOffset + ", lastChunkSize=" +lastChunkSize ); 29.34 29.35 if (encInputOffset % ALIGN != 0 || encOutputOffset % ALIGN != 0 || decOutputOffset % ALIGN !=0 ) 29.36 testingMisalignment = true; 29.37 @@ -98,16 +106,24 @@ 29.38 cipher = Cipher.getInstance(algorithm + "/" + mode + "/" + paddingStr, "SunJCE"); 29.39 dCipher = Cipher.getInstance(algorithm + "/" + mode + "/" + paddingStr, "SunJCE"); 29.40 29.41 + // CBC init 29.42 if (mode.equals("CBC")) { 29.43 - int ivLen = (algorithm.equals("AES") ? 16 : algorithm.equals("DES") ? 8 : 0); 29.44 - IvParameterSpec initVector = new IvParameterSpec(new byte[ivLen]); 29.45 + IvParameterSpec initVector = new IvParameterSpec(iv); 29.46 cipher.init(Cipher.ENCRYPT_MODE, key, initVector); 29.47 + algParams = cipher.getParameters(); 29.48 + dCipher.init(Cipher.DECRYPT_MODE, key, initVector); 29.49 + 29.50 + // GCM init 29.51 + } else if (mode.equals("GCM")) { 29.52 + gcm_init(true); 29.53 + gcm_init(false); 29.54 + 29.55 + // ECB init 29.56 } else { 29.57 - algParams = cipher.getParameters(); 29.58 cipher.init(Cipher.ENCRYPT_MODE, key, algParams); 29.59 + dCipher.init(Cipher.DECRYPT_MODE, key, algParams); 29.60 } 29.61 - algParams = cipher.getParameters(); 29.62 - dCipher.init(Cipher.DECRYPT_MODE, key, algParams); 29.63 + 29.64 if (threadId == 0) { 29.65 childShowCipher(); 29.66 } 29.67 @@ -188,4 +204,19 @@ 29.68 } 29.69 29.70 abstract void childShowCipher(); 29.71 + 29.72 + void gcm_init(boolean encrypt) throws Exception { 29.73 + gcm_spec = new GCMParameterSpec(tlen * 8, iv); 29.74 + if (encrypt) { 29.75 + // Get a new instance everytime because of reuse IV restrictions 29.76 + cipher = Cipher.getInstance(algorithm + "/" + mode + "/" + paddingStr, "SunJCE"); 29.77 + cipher.init(Cipher.ENCRYPT_MODE, key, gcm_spec); 29.78 + cipher.updateAAD(aad); 29.79 + } else { 29.80 + dCipher.init(Cipher.DECRYPT_MODE, key, gcm_spec); 29.81 + dCipher.updateAAD(aad); 29.82 + 29.83 + 29.84 + } 29.85 + } 29.86 }
30.1 --- a/test/compiler/7184394/TestAESDecode.java Wed Nov 27 05:33:18 2019 +0000 30.2 +++ b/test/compiler/7184394/TestAESDecode.java Wed Dec 04 16:23:46 2019 +0000 30.3 @@ -32,7 +32,11 @@ 30.4 @Override 30.5 public void run() { 30.6 try { 30.7 - if (!noReinit) dCipher.init(Cipher.DECRYPT_MODE, key, algParams); 30.8 + if (mode.equals("GCM")) { 30.9 + gcm_init(false); 30.10 + } else if (!noReinit) { 30.11 + dCipher.init(Cipher.DECRYPT_MODE, key, algParams); 30.12 + } 30.13 decode = new byte[decodeLength]; 30.14 if (testingMisalignment) { 30.15 int tempSize = dCipher.update(encode, encOutputOffset, (decodeMsgSize - lastChunkSize), decode, decOutputOffset);
31.1 --- a/test/compiler/7184394/TestAESEncode.java Wed Nov 27 05:33:18 2019 +0000 31.2 +++ b/test/compiler/7184394/TestAESEncode.java Wed Dec 04 16:23:46 2019 +0000 31.3 @@ -1,5 +1,5 @@ 31.4 /* 31.5 - * Copyright (c) 2012, 2014, Oracle and/or its affiliates. All rights reserved. 31.6 + * Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved. 31.7 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 31.8 * 31.9 * This code is free software; you can redistribute it and/or modify it 31.10 @@ -32,7 +32,11 @@ 31.11 @Override 31.12 public void run() { 31.13 try { 31.14 - if (!noReinit) cipher.init(Cipher.ENCRYPT_MODE, key, algParams); 31.15 + if (mode.equals("GCM")) { 31.16 + gcm_init(true); 31.17 + } else if (!noReinit) { 31.18 + cipher.init(Cipher.ENCRYPT_MODE, key, algParams); 31.19 + } 31.20 encode = new byte[encodeLength]; 31.21 if (testingMisalignment) { 31.22 int tempSize = cipher.update(input, encInputOffset, (msgSize - lastChunkSize), encode, encOutputOffset);
32.1 --- a/test/compiler/7184394/TestAESMain.java Wed Nov 27 05:33:18 2019 +0000 32.2 +++ b/test/compiler/7184394/TestAESMain.java Wed Dec 04 16:23:46 2019 +0000 32.3 @@ -41,6 +41,13 @@ 32.4 * @run main/othervm/timeout=600 -Xbatch -DcheckOutput=true -Dmode=ECB -DencInputOffset=1 -DencOutputOffset=1 TestAESMain 32.5 * @run main/othervm/timeout=600 -Xbatch -DcheckOutput=true -Dmode=ECB -DencInputOffset=1 -DencOutputOffset=1 -DdecOutputOffset=1 TestAESMain 32.6 * @run main/othervm/timeout=600 -Xbatch -DcheckOutput=true -Dmode=ECB -DencInputOffset=1 -DencOutputOffset=1 -DdecOutputOffset=1 -DpaddingStr=NoPadding -DmsgSize=640 TestAESMain 32.7 + * @run main/othervm/timeout=600 -Xbatch -DcheckOutput=true -Dmode=GCM TestAESMain 32.8 + * @run main/othervm/timeout=600 -Xbatch -DcheckOutput=true -Dmode=GCM -DencInputOffset=1 TestAESMain 32.9 + * @run main/othervm/timeout=600 -Xbatch -DcheckOutput=true -Dmode=GCM -DencOutputOffset=1 TestAESMain 32.10 + * @run main/othervm/timeout=600 -Xbatch -DcheckOutput=true -Dmode=GCM -DdecOutputOffset=1 TestAESMain 32.11 + * @run main/othervm/timeout=600 -Xbatch -DcheckOutput=true -Dmode=GCM -DencInputOffset=1 -DencOutputOffset=1 TestAESMain 32.12 + * @run main/othervm/timeout=600 -Xbatch -DcheckOutput=true -Dmode=GCM -DencInputOffset=1 -DencOutputOffset=1 -DdecOutputOffset=1 TestAESMain 32.13 + * @run main/othervm/timeout=600 -Xbatch -DcheckOutput=true -Dmode=GCM -DencInputOffset=1 -DencOutputOffset=1 -DdecOutputOffset=1 -DpaddingStr=NoPadding -DmsgSize=640 TestAESMain 32.14 * 32.15 * @author Tom Deneau 32.16 */
33.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 33.2 +++ b/test/gc/stress/gclocker/TestExcessGCLockerCollections.java Wed Dec 04 16:23:46 2019 +0000 33.3 @@ -0,0 +1,285 @@ 33.4 +/* 33.5 + * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved. 33.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 33.7 + * 33.8 + * This code is free software; you can redistribute it and/or modify it 33.9 + * under the terms of the GNU General Public License version 2 only, as 33.10 + * published by the Free Software Foundation. 33.11 + * 33.12 + * This code is distributed in the hope that it will be useful, but WITHOUT 33.13 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 33.14 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 33.15 + * version 2 for more details (a copy is included in the LICENSE file that 33.16 + * accompanied this code). 33.17 + * 33.18 + * You should have received a copy of the GNU General Public License version 33.19 + * 2 along with this work; if not, write to the Free Software Foundation, 33.20 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 33.21 + * 33.22 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 33.23 + * or visit www.oracle.com if you need additional information or have any 33.24 + * questions. 33.25 + */ 33.26 + 33.27 +package gc.stress.gclocker; 33.28 + 33.29 +// Based on Kim Barrett;s test for JDK-8048556 33.30 + 33.31 +/* 33.32 + * @test TestExcessGCLockerCollections 33.33 + * @key gc 33.34 + * @bug 8048556 33.35 + * @summary Check for GC Locker initiated GCs that immediately follow another 33.36 + * GC and so have very little needing to be collected. 33.37 + * @library /testlibrary 33.38 + * @run driver/timeout=1000 gc.stress.gclocker.TestExcessGCLockerCollections 300 4 2 33.39 + */ 33.40 + 33.41 +import java.util.HashMap; 33.42 +import java.util.Map; 33.43 + 33.44 +import java.util.zip.Deflater; 33.45 + 33.46 +import java.util.ArrayList; 33.47 +import java.util.Arrays; 33.48 + 33.49 +import javax.management.MBeanServer; 33.50 +import javax.management.Notification; 33.51 +import javax.management.NotificationListener; 33.52 +import javax.management.openmbean.CompositeData; 33.53 +import java.lang.management.ManagementFactory; 33.54 +import java.lang.management.GarbageCollectorMXBean; 33.55 +import java.lang.management.MemoryUsage; 33.56 +import java.util.List; 33.57 +import com.sun.management.GarbageCollectionNotificationInfo; 33.58 +import com.sun.management.GcInfo; 33.59 + 33.60 +import com.oracle.java.testlibrary.Asserts; 33.61 +import com.oracle.java.testlibrary.ProcessTools; 33.62 +import com.oracle.java.testlibrary.OutputAnalyzer; 33.63 + 33.64 +class TestExcessGCLockerCollectionsStringConstants { 33.65 + // Some constant strings used in both GC logging and error detection 33.66 + static public final String GCLOCKER_CAUSE = "GCLocker Initiated GC"; 33.67 + static public final String USED_TOO_LOW = "TOO LOW"; 33.68 + static public final String USED_OK = "OK"; 33.69 +} 33.70 + 33.71 +class TestExcessGCLockerCollectionsAux { 33.72 + static private final int LARGE_MAP_SIZE = 64 * 1024; 33.73 + 33.74 + static private final int MAP_ARRAY_LENGTH = 4; 33.75 + static private final int MAP_SIZE = 1024; 33.76 + 33.77 + static private final int BYTE_ARRAY_LENGTH = 128 * 1024; 33.78 + 33.79 + static private void println(String str) { System.out.println(str); } 33.80 + static private void println() { System.out.println(); } 33.81 + 33.82 + static private volatile boolean keepRunning = true; 33.83 + 33.84 + static Map<Integer,String> populateMap(int size) { 33.85 + Map<Integer,String> map = new HashMap<Integer,String>(); 33.86 + for (int i = 0; i < size; i += 1) { 33.87 + Integer keyInt = Integer.valueOf(i); 33.88 + String valStr = "value is [" + i + "]"; 33.89 + map.put(keyInt,valStr); 33.90 + } 33.91 + return map; 33.92 + } 33.93 + 33.94 + static private class AllocatingWorker implements Runnable { 33.95 + private final Object[] array = new Object[MAP_ARRAY_LENGTH]; 33.96 + private int arrayIndex = 0; 33.97 + 33.98 + private void doStep() { 33.99 + Map<Integer,String> map = populateMap(MAP_SIZE); 33.100 + array[arrayIndex] = map; 33.101 + arrayIndex = (arrayIndex + 1) % MAP_ARRAY_LENGTH; 33.102 + } 33.103 + 33.104 + public void run() { 33.105 + while (keepRunning) { 33.106 + doStep(); 33.107 + } 33.108 + } 33.109 + } 33.110 + 33.111 + static private class JNICriticalWorker implements Runnable { 33.112 + private int count; 33.113 + 33.114 + private void doStep() { 33.115 + byte[] inputArray = new byte[BYTE_ARRAY_LENGTH]; 33.116 + for (int i = 0; i < inputArray.length; i += 1) { 33.117 + inputArray[i] = (byte) (count + i); 33.118 + } 33.119 + 33.120 + Deflater deflater = new Deflater(); 33.121 + deflater.setInput(inputArray); 33.122 + deflater.finish(); 33.123 + 33.124 + byte[] outputArray = new byte[2 * inputArray.length]; 33.125 + deflater.deflate(outputArray); 33.126 + 33.127 + count += 1; 33.128 + } 33.129 + 33.130 + public void run() { 33.131 + while (keepRunning) { 33.132 + doStep(); 33.133 + } 33.134 + } 33.135 + } 33.136 + 33.137 + static class GCNotificationListener implements NotificationListener { 33.138 + static private final double MIN_USED_PERCENT = 40.0; 33.139 + 33.140 + static private final List<String> newGenPoolNames = Arrays.asList( 33.141 + "G1 Eden Space", // OpenJDK G1GC: -XX:+UseG1GC 33.142 + "PS Eden Space", // OpenJDK ParallelGC: -XX:+ParallelGC 33.143 + "Par Eden Space", // OpenJDK ConcMarkSweepGC: -XX:+ConcMarkSweepGC 33.144 + "Eden Space" // OpenJDK SerialGC: -XX:+UseSerialGC 33.145 + // OpenJDK ConcMarkSweepGC: -XX:+ConcMarkSweepGC -XX:-UseParNewGC 33.146 + ); 33.147 + 33.148 + @Override 33.149 + public void handleNotification(Notification notification, Object handback) { 33.150 + try { 33.151 + if (notification.getType().equals(GarbageCollectionNotificationInfo.GARBAGE_COLLECTION_NOTIFICATION)) { 33.152 + GarbageCollectionNotificationInfo info = 33.153 + GarbageCollectionNotificationInfo.from((CompositeData) notification.getUserData()); 33.154 + 33.155 + String gc_cause = info.getGcCause(); 33.156 + 33.157 + if (gc_cause.equals(TestExcessGCLockerCollectionsStringConstants.GCLOCKER_CAUSE)) { 33.158 + Map<String, MemoryUsage> memory_before_gc = info.getGcInfo().getMemoryUsageBeforeGc(); 33.159 + 33.160 + for (String newGenPoolName : newGenPoolNames) { 33.161 + MemoryUsage usage = memory_before_gc.get(newGenPoolName); 33.162 + if (usage == null) continue; 33.163 + 33.164 + double startTime = ((double) info.getGcInfo().getStartTime()) / 1000.0; 33.165 + long used = usage.getUsed(); 33.166 + long committed = usage.getCommitted(); 33.167 + long max = usage.getMax(); 33.168 + double used_percent = (((double) used) / Math.max(committed, max)) * 100.0; 33.169 + 33.170 + System.out.printf("%6.3f: (%s) %d/%d/%d, %8.4f%% (%s)\n", 33.171 + startTime, gc_cause, used, committed, max, used_percent, 33.172 + ((used_percent < MIN_USED_PERCENT) ? TestExcessGCLockerCollectionsStringConstants.USED_TOO_LOW 33.173 + : TestExcessGCLockerCollectionsStringConstants.USED_OK)); 33.174 + } 33.175 + } 33.176 + } 33.177 + } catch (RuntimeException ex) { 33.178 + System.err.println("Exception during notification processing:" + ex); 33.179 + ex.printStackTrace(); 33.180 + } 33.181 + } 33.182 + 33.183 + public static boolean register() { 33.184 + try { 33.185 + MBeanServer mbeanServer = ManagementFactory.getPlatformMBeanServer(); 33.186 + 33.187 + // Get the list of MX 33.188 + List<GarbageCollectorMXBean> gc_mxbeans = ManagementFactory.getGarbageCollectorMXBeans(); 33.189 + 33.190 + // Create the notification listener 33.191 + GCNotificationListener gcNotificationListener = new GCNotificationListener(); 33.192 + 33.193 + for (GarbageCollectorMXBean gcbean : gc_mxbeans) { 33.194 + // Add notification listener for the MXBean 33.195 + mbeanServer.addNotificationListener(gcbean.getObjectName(), gcNotificationListener, null, null); 33.196 + } 33.197 + } catch (Exception ex) { 33.198 + System.err.println("Exception during mbean registration:" + ex); 33.199 + ex.printStackTrace(); 33.200 + // We've failed to set up, terminate 33.201 + return false; 33.202 + } 33.203 + 33.204 + return true; 33.205 + } 33.206 + } 33.207 + 33.208 + static public Map<Integer,String> largeMap; 33.209 + 33.210 + static public void main(String args[]) { 33.211 + long durationSec = Long.parseLong(args[0]); 33.212 + int allocThreadNum = Integer.parseInt(args[1]); 33.213 + int jniCriticalThreadNum = Integer.parseInt(args[2]); 33.214 + 33.215 + println("Running for " + durationSec + " secs"); 33.216 + 33.217 + if (!GCNotificationListener.register()) { 33.218 + println("failed to register GC notification listener"); 33.219 + System.exit(-1); 33.220 + } 33.221 + 33.222 + largeMap = populateMap(LARGE_MAP_SIZE); 33.223 + 33.224 + println("Starting " + allocThreadNum + " allocating threads"); 33.225 + for (int i = 0; i < allocThreadNum; i += 1) { 33.226 + new Thread(new AllocatingWorker()).start(); 33.227 + } 33.228 + 33.229 + println("Starting " + jniCriticalThreadNum + " jni critical threads"); 33.230 + for (int i = 0; i < jniCriticalThreadNum; i += 1) { 33.231 + new Thread(new JNICriticalWorker()).start(); 33.232 + } 33.233 + 33.234 + long durationMS = (long) (1000 * durationSec); 33.235 + long start = System.currentTimeMillis(); 33.236 + long now = start; 33.237 + long soFar = now - start; 33.238 + while (soFar < durationMS) { 33.239 + try { 33.240 + Thread.sleep(durationMS - soFar); 33.241 + } catch (Exception e) { 33.242 + } 33.243 + now = System.currentTimeMillis(); 33.244 + soFar = now - start; 33.245 + } 33.246 + println("Done."); 33.247 + keepRunning = false; 33.248 + } 33.249 +} 33.250 + 33.251 +public class TestExcessGCLockerCollections { 33.252 + private static final String USED_OK_LINE = 33.253 + "\\(" + TestExcessGCLockerCollectionsStringConstants.GCLOCKER_CAUSE + "\\)" 33.254 + + " .* " + 33.255 + "\\(" + TestExcessGCLockerCollectionsStringConstants.USED_OK + "\\)"; 33.256 + private static final String USED_TOO_LOW_LINE = 33.257 + "\\(" + TestExcessGCLockerCollectionsStringConstants.GCLOCKER_CAUSE + "\\)" 33.258 + + " .* " + 33.259 + "\\(" + TestExcessGCLockerCollectionsStringConstants.USED_TOO_LOW + "\\)"; 33.260 + 33.261 + private static final String[] COMMON_OPTIONS = new String[] { 33.262 + "-Xmx1G", "-Xms1G", "-Xmn256M" }; 33.263 + 33.264 + public static void main(String args[]) throws Exception { 33.265 + if (args.length < 3) { 33.266 + System.out.println("usage: TestExcessGCLockerCollections" + 33.267 + " <duration sec> <alloc threads>" + 33.268 + " <jni critical threads>"); 33.269 + throw new RuntimeException("Invalid arguments"); 33.270 + } 33.271 + 33.272 + ArrayList<String> finalArgs = new ArrayList<String>(); 33.273 + finalArgs.addAll(Arrays.asList(COMMON_OPTIONS)); 33.274 + finalArgs.add(TestExcessGCLockerCollectionsAux.class.getName()); 33.275 + finalArgs.addAll(Arrays.asList(args)); 33.276 + 33.277 + // GC and other options obtained from test framework. 33.278 + ProcessBuilder pb = ProcessTools.createJavaProcessBuilder( 33.279 + true, finalArgs.toArray(new String[0])); 33.280 + OutputAnalyzer output = new OutputAnalyzer(pb.start()); 33.281 + output.shouldHaveExitValue(0); 33.282 + //System.out.println("------------- begin stdout ----------------"); 33.283 + //System.out.println(output.getStdout()); 33.284 + //System.out.println("------------- end stdout ----------------"); 33.285 + output.stdoutShouldMatch(USED_OK_LINE); 33.286 + output.stdoutShouldNotMatch(USED_TOO_LOW_LINE); 33.287 + } 33.288 +}