mirror of
https://github.com/openjdk/jdk.git
synced 2026-05-19 18:07:49 +00:00
Merge
This commit is contained in:
commit
ab85038e4a
@ -3425,9 +3425,6 @@ const bool Matcher::misaligned_vectors_ok() {
|
||||
// false => size gets scaled to BytesPerLong, ok.
|
||||
const bool Matcher::init_array_count_is_in_bytes = false;
|
||||
|
||||
// Threshold size for cleararray.
|
||||
const int Matcher::init_array_short_size = 18 * BytesPerLong;
|
||||
|
||||
// Use conditional move (CMOVL)
|
||||
const int Matcher::long_cmove_cost() {
|
||||
// long cmoves are no more expensive than int cmoves
|
||||
|
||||
@ -76,6 +76,8 @@ define_pd_global(bool, CompactStrings, false);
|
||||
// avoid biased locking while we are bootstrapping the aarch64 build
|
||||
define_pd_global(bool, UseBiasedLocking, false);
|
||||
|
||||
define_pd_global(intx, InitArrayShortSize, 18*BytesPerLong);
|
||||
|
||||
#if defined(COMPILER1) || defined(COMPILER2)
|
||||
define_pd_global(intx, InlineSmallCode, 1000);
|
||||
#endif
|
||||
|
||||
@ -76,6 +76,8 @@ define_pd_global(uintx, TypeProfileLevel, 111);
|
||||
|
||||
define_pd_global(bool, CompactStrings, true);
|
||||
|
||||
define_pd_global(intx, InitArrayShortSize, 8*BytesPerLong);
|
||||
|
||||
// Platform dependent flag handling: flags only defined on this platform.
|
||||
#define ARCH_FLAGS(develop, product, diagnostic, experimental, notproduct, range, constraint) \
|
||||
\
|
||||
|
||||
@ -2137,8 +2137,6 @@ MachTypeNode *Matcher::make_decode_node() {
|
||||
return decode;
|
||||
}
|
||||
*/
|
||||
// Threshold size for cleararray.
|
||||
const int Matcher::init_array_short_size = 8 * BytesPerLong;
|
||||
|
||||
// false => size gets scaled to BytesPerLong, ok.
|
||||
const bool Matcher::init_array_count_is_in_bytes = false;
|
||||
|
||||
@ -90,6 +90,8 @@ define_pd_global(uintx, TypeProfileLevel, 111);
|
||||
|
||||
define_pd_global(bool, CompactStrings, true);
|
||||
|
||||
define_pd_global(intx, InitArrayShortSize, 8*BytesPerLong);
|
||||
|
||||
#define ARCH_FLAGS(develop, product, diagnostic, experimental, notproduct, range, constraint) \
|
||||
\
|
||||
product(intx, UseVIS, 99, \
|
||||
|
||||
@ -1980,9 +1980,6 @@ const bool Matcher::isSimpleConstant64(jlong value) {
|
||||
// No scaling for the parameter the ClearArray node.
|
||||
const bool Matcher::init_array_count_is_in_bytes = true;
|
||||
|
||||
// Threshold size for cleararray.
|
||||
const int Matcher::init_array_short_size = 8 * BytesPerLong;
|
||||
|
||||
// No additional cost for CMOVL.
|
||||
const int Matcher::long_cmove_cost() { return 0; }
|
||||
|
||||
|
||||
@ -777,6 +777,7 @@ address Assembler::locate_operand(address inst, WhichOperand which) {
|
||||
case 0x6E: // movd
|
||||
case 0x7E: // movd
|
||||
case 0xAE: // ldmxcsr, stmxcsr, fxrstor, fxsave, clflush
|
||||
case 0xFE: // paddd
|
||||
debug_only(has_disp32 = true);
|
||||
break;
|
||||
|
||||
@ -926,6 +927,7 @@ address Assembler::locate_operand(address inst, WhichOperand which) {
|
||||
ip++; // skip P2, move to opcode
|
||||
// To find the end of instruction (which == end_pc_operand).
|
||||
switch (0xFF & *ip) {
|
||||
case 0x22: // pinsrd r, r/a, #8
|
||||
case 0x61: // pcmpestri r, r/a, #8
|
||||
case 0x70: // pshufd r, r/a, #8
|
||||
case 0x73: // psrldq r, #8
|
||||
@ -3953,6 +3955,83 @@ void Assembler::setb(Condition cc, Register dst) {
|
||||
emit_int8((unsigned char)(0xC0 | encode));
|
||||
}
|
||||
|
||||
void Assembler::palignr(XMMRegister dst, XMMRegister src, int imm8) {
|
||||
assert(VM_Version::supports_ssse3(), "");
|
||||
InstructionAttr attributes(AVX_128bit, /* rex_w */ false, /* legacy_mode */ _legacy_mode_bw, /* no_mask_reg */ false, /* uses_vl */ false);
|
||||
int encode = simd_prefix_and_encode(dst, dst, src, VEX_SIMD_66, VEX_OPCODE_0F_3A, &attributes);
|
||||
emit_int8((unsigned char)0x0F);
|
||||
emit_int8((unsigned char)(0xC0 | encode));
|
||||
emit_int8(imm8);
|
||||
}
|
||||
|
||||
void Assembler::pblendw(XMMRegister dst, XMMRegister src, int imm8) {
|
||||
assert(VM_Version::supports_sse4_1(), "");
|
||||
InstructionAttr attributes(AVX_128bit, /* rex_w */ false, /* legacy_mode */ true, /* no_mask_reg */ false, /* uses_vl */ false);
|
||||
int encode = simd_prefix_and_encode(dst, xnoreg, src, VEX_SIMD_66, VEX_OPCODE_0F_3A, &attributes);
|
||||
emit_int8((unsigned char)0x0E);
|
||||
emit_int8((unsigned char)(0xC0 | encode));
|
||||
emit_int8(imm8);
|
||||
}
|
||||
|
||||
void Assembler::sha1rnds4(XMMRegister dst, XMMRegister src, int imm8) {
|
||||
assert(VM_Version::supports_sha(), "");
|
||||
InstructionAttr attributes(AVX_128bit, /* rex_w */ false, /* legacy_mode */ true, /* no_mask_reg */ false, /* uses_vl */ false);
|
||||
int encode = simd_prefix_and_encode(dst, xnoreg, src, VEX_SIMD_NONE, VEX_OPCODE_0F_3A, &attributes);
|
||||
emit_int8((unsigned char)0xCC);
|
||||
emit_int8((unsigned char)(0xC0 | encode));
|
||||
emit_int8((unsigned char)imm8);
|
||||
}
|
||||
|
||||
void Assembler::sha1nexte(XMMRegister dst, XMMRegister src) {
|
||||
assert(VM_Version::supports_sha(), "");
|
||||
InstructionAttr attributes(AVX_128bit, /* rex_w */ false, /* legacy_mode */ true, /* no_mask_reg */ false, /* uses_vl */ false);
|
||||
int encode = simd_prefix_and_encode(dst, xnoreg, src, VEX_SIMD_NONE, VEX_OPCODE_0F_38, &attributes);
|
||||
emit_int8((unsigned char)0xC8);
|
||||
emit_int8((unsigned char)(0xC0 | encode));
|
||||
}
|
||||
|
||||
void Assembler::sha1msg1(XMMRegister dst, XMMRegister src) {
|
||||
assert(VM_Version::supports_sha(), "");
|
||||
InstructionAttr attributes(AVX_128bit, /* rex_w */ false, /* legacy_mode */ true, /* no_mask_reg */ false, /* uses_vl */ false);
|
||||
int encode = simd_prefix_and_encode(dst, xnoreg, src, VEX_SIMD_NONE, VEX_OPCODE_0F_38, &attributes);
|
||||
emit_int8((unsigned char)0xC9);
|
||||
emit_int8((unsigned char)(0xC0 | encode));
|
||||
}
|
||||
|
||||
void Assembler::sha1msg2(XMMRegister dst, XMMRegister src) {
|
||||
assert(VM_Version::supports_sha(), "");
|
||||
InstructionAttr attributes(AVX_128bit, /* rex_w */ false, /* legacy_mode */ true, /* no_mask_reg */ false, /* uses_vl */ false);
|
||||
int encode = simd_prefix_and_encode(dst, xnoreg, src, VEX_SIMD_NONE, VEX_OPCODE_0F_38, &attributes);
|
||||
emit_int8((unsigned char)0xCA);
|
||||
emit_int8((unsigned char)(0xC0 | encode));
|
||||
}
|
||||
|
||||
// xmm0 is implicit additional source to this instruction.
|
||||
void Assembler::sha256rnds2(XMMRegister dst, XMMRegister src) {
|
||||
assert(VM_Version::supports_sha(), "");
|
||||
InstructionAttr attributes(AVX_128bit, /* rex_w */ false, /* legacy_mode */ true, /* no_mask_reg */ false, /* uses_vl */ false);
|
||||
int encode = simd_prefix_and_encode(dst, xnoreg, src, VEX_SIMD_NONE, VEX_OPCODE_0F_38, &attributes);
|
||||
emit_int8((unsigned char)0xCB);
|
||||
emit_int8((unsigned char)(0xC0 | encode));
|
||||
}
|
||||
|
||||
void Assembler::sha256msg1(XMMRegister dst, XMMRegister src) {
|
||||
assert(VM_Version::supports_sha(), "");
|
||||
InstructionAttr attributes(AVX_128bit, /* rex_w */ false, /* legacy_mode */ true, /* no_mask_reg */ false, /* uses_vl */ false);
|
||||
int encode = simd_prefix_and_encode(dst, xnoreg, src, VEX_SIMD_NONE, VEX_OPCODE_0F_38, &attributes);
|
||||
emit_int8((unsigned char)0xCC);
|
||||
emit_int8((unsigned char)(0xC0 | encode));
|
||||
}
|
||||
|
||||
void Assembler::sha256msg2(XMMRegister dst, XMMRegister src) {
|
||||
assert(VM_Version::supports_sha(), "");
|
||||
InstructionAttr attributes(AVX_128bit, /* rex_w */ false, /* legacy_mode */ true, /* no_mask_reg */ false, /* uses_vl */ false);
|
||||
int encode = simd_prefix_and_encode(dst, xnoreg, src, VEX_SIMD_NONE, VEX_OPCODE_0F_38, &attributes);
|
||||
emit_int8((unsigned char)0xCD);
|
||||
emit_int8((unsigned char)(0xC0 | encode));
|
||||
}
|
||||
|
||||
|
||||
void Assembler::shll(Register dst, int imm8) {
|
||||
assert(isShiftCount(imm8), "illegal shift count");
|
||||
int encode = prefix_and_encode(dst->encoding());
|
||||
@ -4931,6 +5010,15 @@ void Assembler::paddd(XMMRegister dst, XMMRegister src) {
|
||||
emit_int8((unsigned char)(0xC0 | encode));
|
||||
}
|
||||
|
||||
void Assembler::paddd(XMMRegister dst, Address src) {
|
||||
NOT_LP64(assert(VM_Version::supports_sse2(), ""));
|
||||
InstructionMark im(this);
|
||||
InstructionAttr attributes(AVX_128bit, /* rex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ false, /* uses_vl */ true);
|
||||
simd_prefix(dst, xnoreg, src, VEX_SIMD_66, VEX_OPCODE_0F, &attributes);
|
||||
emit_int8((unsigned char)0xFE);
|
||||
emit_operand(dst, src);
|
||||
}
|
||||
|
||||
void Assembler::paddq(XMMRegister dst, XMMRegister src) {
|
||||
NOT_LP64(assert(VM_Version::supports_sse2(), ""));
|
||||
InstructionAttr attributes(AVX_128bit, /* rex_w */ VM_Version::supports_evex(), /* legacy_mode */ false, /* no_mask_reg */ false, /* uses_vl */ true);
|
||||
|
||||
@ -1672,6 +1672,18 @@ private:
|
||||
|
||||
void setb(Condition cc, Register dst);
|
||||
|
||||
void palignr(XMMRegister dst, XMMRegister src, int imm8);
|
||||
void pblendw(XMMRegister dst, XMMRegister src, int imm8);
|
||||
|
||||
void sha1rnds4(XMMRegister dst, XMMRegister src, int imm8);
|
||||
void sha1nexte(XMMRegister dst, XMMRegister src);
|
||||
void sha1msg1(XMMRegister dst, XMMRegister src);
|
||||
void sha1msg2(XMMRegister dst, XMMRegister src);
|
||||
// xmm0 is implicit additional source to the following instruction.
|
||||
void sha256rnds2(XMMRegister dst, XMMRegister src);
|
||||
void sha256msg1(XMMRegister dst, XMMRegister src);
|
||||
void sha256msg2(XMMRegister dst, XMMRegister src);
|
||||
|
||||
void shldl(Register dst, Register src);
|
||||
void shldl(Register dst, Register src, int8_t imm8);
|
||||
|
||||
@ -1868,6 +1880,7 @@ private:
|
||||
void paddb(XMMRegister dst, XMMRegister src);
|
||||
void paddw(XMMRegister dst, XMMRegister src);
|
||||
void paddd(XMMRegister dst, XMMRegister src);
|
||||
void paddd(XMMRegister dst, Address src);
|
||||
void paddq(XMMRegister dst, XMMRegister src);
|
||||
void vpaddb(XMMRegister dst, XMMRegister nds, XMMRegister src, int vector_len);
|
||||
void vpaddw(XMMRegister dst, XMMRegister nds, XMMRegister src, int vector_len);
|
||||
|
||||
@ -97,6 +97,8 @@ define_pd_global(bool, CompactStrings, true);
|
||||
|
||||
define_pd_global(bool, PreserveFramePointer, false);
|
||||
|
||||
define_pd_global(intx, InitArrayShortSize, 8*BytesPerLong);
|
||||
|
||||
#define ARCH_FLAGS(develop, product, diagnostic, experimental, notproduct, range, constraint) \
|
||||
\
|
||||
develop(bool, IEEEPrecision, true, \
|
||||
|
||||
@ -7198,21 +7198,50 @@ void MacroAssembler::verified_entry(int framesize, int stack_bang_size, bool fp_
|
||||
|
||||
}
|
||||
|
||||
void MacroAssembler::clear_mem(Register base, Register cnt, Register tmp) {
|
||||
void MacroAssembler::clear_mem(Register base, Register cnt, Register tmp, bool is_large) {
|
||||
// cnt - number of qwords (8-byte words).
|
||||
// base - start address, qword aligned.
|
||||
// is_large - if optimizers know cnt is larger than InitArrayShortSize
|
||||
assert(base==rdi, "base register must be edi for rep stos");
|
||||
assert(tmp==rax, "tmp register must be eax for rep stos");
|
||||
assert(cnt==rcx, "cnt register must be ecx for rep stos");
|
||||
assert(InitArrayShortSize % BytesPerLong == 0,
|
||||
"InitArrayShortSize should be the multiple of BytesPerLong");
|
||||
|
||||
Label DONE;
|
||||
|
||||
xorptr(tmp, tmp);
|
||||
|
||||
if (!is_large) {
|
||||
Label LOOP, LONG;
|
||||
cmpptr(cnt, InitArrayShortSize/BytesPerLong);
|
||||
jccb(Assembler::greater, LONG);
|
||||
|
||||
NOT_LP64(shlptr(cnt, 1);) // convert to number of 32-bit words for 32-bit VM
|
||||
|
||||
decrement(cnt);
|
||||
jccb(Assembler::negative, DONE); // Zero length
|
||||
|
||||
// Use individual pointer-sized stores for small counts:
|
||||
BIND(LOOP);
|
||||
movptr(Address(base, cnt, Address::times_ptr), tmp);
|
||||
decrement(cnt);
|
||||
jccb(Assembler::greaterEqual, LOOP);
|
||||
jmpb(DONE);
|
||||
|
||||
BIND(LONG);
|
||||
}
|
||||
|
||||
// Use longer rep-prefixed ops for non-small counts:
|
||||
if (UseFastStosb) {
|
||||
shlptr(cnt,3); // convert to number of bytes
|
||||
shlptr(cnt, 3); // convert to number of bytes
|
||||
rep_stosb();
|
||||
} else {
|
||||
NOT_LP64(shlptr(cnt,1);) // convert to number of dwords for 32-bit VM
|
||||
NOT_LP64(shlptr(cnt, 1);) // convert to number of 32-bit words for 32-bit VM
|
||||
rep_stos();
|
||||
}
|
||||
|
||||
BIND(DONE);
|
||||
}
|
||||
|
||||
#ifdef COMPILER2
|
||||
|
||||
@ -48,7 +48,6 @@ class MacroAssembler: public Assembler {
|
||||
// This is the base routine called by the different versions of call_VM_leaf. The interpreter
|
||||
// may customize this version by overriding it for its purposes (e.g., to save/restore
|
||||
// additional registers when doing a VM call).
|
||||
#define COMMA ,
|
||||
|
||||
virtual void call_VM_leaf_base(
|
||||
address entry_point, // the entry point
|
||||
@ -903,35 +902,66 @@ class MacroAssembler: public Assembler {
|
||||
void ldmxcsr(Address src) { Assembler::ldmxcsr(src); }
|
||||
void ldmxcsr(AddressLiteral src);
|
||||
|
||||
void fast_sha1(XMMRegister abcd, XMMRegister e0, XMMRegister e1, XMMRegister msg0,
|
||||
XMMRegister msg1, XMMRegister msg2, XMMRegister msg3, XMMRegister shuf_mask,
|
||||
Register buf, Register state, Register ofs, Register limit, Register rsp,
|
||||
bool multi_block);
|
||||
|
||||
#ifdef _LP64
|
||||
void fast_sha256(XMMRegister msg, XMMRegister state0, XMMRegister state1, XMMRegister msgtmp0,
|
||||
XMMRegister msgtmp1, XMMRegister msgtmp2, XMMRegister msgtmp3, XMMRegister msgtmp4,
|
||||
Register buf, Register state, Register ofs, Register limit, Register rsp,
|
||||
bool multi_block, XMMRegister shuf_mask);
|
||||
#else
|
||||
void fast_sha256(XMMRegister msg, XMMRegister state0, XMMRegister state1, XMMRegister msgtmp0,
|
||||
XMMRegister msgtmp1, XMMRegister msgtmp2, XMMRegister msgtmp3, XMMRegister msgtmp4,
|
||||
Register buf, Register state, Register ofs, Register limit, Register rsp,
|
||||
bool multi_block);
|
||||
#endif
|
||||
|
||||
void fast_exp(XMMRegister xmm0, XMMRegister xmm1, XMMRegister xmm2, XMMRegister xmm3,
|
||||
XMMRegister xmm4, XMMRegister xmm5, XMMRegister xmm6, XMMRegister xmm7,
|
||||
Register rax, Register rcx, Register rdx, Register tmp);
|
||||
|
||||
#ifdef _LP64
|
||||
void fast_log(XMMRegister xmm0, XMMRegister xmm1, XMMRegister xmm2, XMMRegister xmm3,
|
||||
XMMRegister xmm4, XMMRegister xmm5, XMMRegister xmm6, XMMRegister xmm7,
|
||||
Register rax, Register rcx, Register rdx, Register tmp1 LP64_ONLY(COMMA Register tmp2));
|
||||
Register rax, Register rcx, Register rdx, Register tmp1, Register tmp2);
|
||||
|
||||
void fast_pow(XMMRegister xmm0, XMMRegister xmm1, XMMRegister xmm2, XMMRegister xmm3, XMMRegister xmm4,
|
||||
XMMRegister xmm5, XMMRegister xmm6, XMMRegister xmm7, Register rax, Register rcx,
|
||||
Register rdx NOT_LP64(COMMA Register tmp) LP64_ONLY(COMMA Register tmp1)
|
||||
LP64_ONLY(COMMA Register tmp2) LP64_ONLY(COMMA Register tmp3) LP64_ONLY(COMMA Register tmp4));
|
||||
Register rdx, Register tmp1, Register tmp2, Register tmp3, Register tmp4);
|
||||
|
||||
void fast_sin(XMMRegister xmm0, XMMRegister xmm1, XMMRegister xmm2, XMMRegister xmm3,
|
||||
XMMRegister xmm4, XMMRegister xmm5, XMMRegister xmm6, XMMRegister xmm7,
|
||||
Register rax, Register rbx LP64_ONLY(COMMA Register rcx), Register rdx
|
||||
LP64_ONLY(COMMA Register tmp1) LP64_ONLY(COMMA Register tmp2)
|
||||
LP64_ONLY(COMMA Register tmp3) LP64_ONLY(COMMA Register tmp4));
|
||||
Register rax, Register rbx, Register rcx, Register rdx, Register tmp1, Register tmp2,
|
||||
Register tmp3, Register tmp4);
|
||||
|
||||
void fast_cos(XMMRegister xmm0, XMMRegister xmm1, XMMRegister xmm2, XMMRegister xmm3,
|
||||
XMMRegister xmm4, XMMRegister xmm5, XMMRegister xmm6, XMMRegister xmm7,
|
||||
Register rax, Register rcx, Register rdx NOT_LP64(COMMA Register tmp)
|
||||
LP64_ONLY(COMMA Register r8) LP64_ONLY(COMMA Register r9)
|
||||
LP64_ONLY(COMMA Register r10) LP64_ONLY(COMMA Register r11));
|
||||
Register rax, Register rcx, Register rdx, Register tmp1,
|
||||
Register tmp2, Register tmp3, Register tmp4);
|
||||
#else
|
||||
void fast_log(XMMRegister xmm0, XMMRegister xmm1, XMMRegister xmm2, XMMRegister xmm3,
|
||||
XMMRegister xmm4, XMMRegister xmm5, XMMRegister xmm6, XMMRegister xmm7,
|
||||
Register rax, Register rcx, Register rdx, Register tmp1);
|
||||
|
||||
void fast_pow(XMMRegister xmm0, XMMRegister xmm1, XMMRegister xmm2, XMMRegister xmm3, XMMRegister xmm4,
|
||||
XMMRegister xmm5, XMMRegister xmm6, XMMRegister xmm7, Register rax, Register rcx,
|
||||
Register rdx, Register tmp);
|
||||
|
||||
void fast_sin(XMMRegister xmm0, XMMRegister xmm1, XMMRegister xmm2, XMMRegister xmm3,
|
||||
XMMRegister xmm4, XMMRegister xmm5, XMMRegister xmm6, XMMRegister xmm7,
|
||||
Register rax, Register rbx, Register rdx);
|
||||
|
||||
void fast_cos(XMMRegister xmm0, XMMRegister xmm1, XMMRegister xmm2, XMMRegister xmm3,
|
||||
XMMRegister xmm4, XMMRegister xmm5, XMMRegister xmm6, XMMRegister xmm7,
|
||||
Register rax, Register rcx, Register rdx, Register tmp);
|
||||
|
||||
#ifndef _LP64
|
||||
void libm_sincos_huge(XMMRegister xmm0, XMMRegister xmm1, Register eax, Register ecx,
|
||||
Register edx, Register ebx, Register esi, Register edi,
|
||||
Register ebp, Register esp);
|
||||
|
||||
void libm_reduce_pi04l(Register eax, Register ecx, Register edx, Register ebx,
|
||||
Register esi, Register edi, Register ebp, Register esp);
|
||||
#endif
|
||||
@ -1284,8 +1314,9 @@ public:
|
||||
// C2 compiled method's prolog code.
|
||||
void verified_entry(int framesize, int stack_bang_size, bool fp_mode_24b);
|
||||
|
||||
// clear memory of size 'cnt' qwords, starting at 'base'.
|
||||
void clear_mem(Register base, Register cnt, Register rtmp);
|
||||
// clear memory of size 'cnt' qwords, starting at 'base';
|
||||
// if 'is_large' is set, do not try to produce short loop
|
||||
void clear_mem(Register base, Register cnt, Register rtmp, bool is_large);
|
||||
|
||||
#ifdef COMPILER2
|
||||
void string_indexof_char(Register str1, Register cnt1, Register ch, Register result,
|
||||
|
||||
495
hotspot/src/cpu/x86/vm/macroAssembler_x86_sha.cpp
Normal file
495
hotspot/src/cpu/x86/vm/macroAssembler_x86_sha.cpp
Normal file
@ -0,0 +1,495 @@
|
||||
/*
|
||||
* Copyright (c) 2016, Intel Corporation.
|
||||
*
|
||||
* 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 "asm/assembler.hpp"
|
||||
#include "asm/assembler.inline.hpp"
|
||||
#include "runtime/stubRoutines.hpp"
|
||||
#include "macroAssembler_x86.hpp"
|
||||
|
||||
// ofs and limit are used for multi-block byte array.
|
||||
// int com.sun.security.provider.DigestBase.implCompressMultiBlock(byte[] b, int ofs, int limit)
|
||||
void MacroAssembler::fast_sha1(XMMRegister abcd, XMMRegister e0, XMMRegister e1, XMMRegister msg0,
|
||||
XMMRegister msg1, XMMRegister msg2, XMMRegister msg3, XMMRegister shuf_mask,
|
||||
Register buf, Register state, Register ofs, Register limit, Register rsp, bool multi_block) {
|
||||
|
||||
Label start, done_hash, loop0;
|
||||
|
||||
address upper_word_mask = StubRoutines::x86::upper_word_mask_addr();
|
||||
address shuffle_byte_flip_mask = StubRoutines::x86::shuffle_byte_flip_mask_addr();
|
||||
|
||||
bind(start);
|
||||
movdqu(abcd, Address(state, 0));
|
||||
pinsrd(e0, Address(state, 16), 3);
|
||||
movdqu(shuf_mask, ExternalAddress(upper_word_mask)); // 0xFFFFFFFF000000000000000000000000
|
||||
pand(e0, shuf_mask);
|
||||
pshufd(abcd, abcd, 0x1B);
|
||||
movdqu(shuf_mask, ExternalAddress(shuffle_byte_flip_mask)); //0x000102030405060708090a0b0c0d0e0f
|
||||
|
||||
bind(loop0);
|
||||
// Save hash values for addition after rounds
|
||||
movdqu(Address(rsp, 0), e0);
|
||||
movdqu(Address(rsp, 16), abcd);
|
||||
|
||||
|
||||
// Rounds 0 - 3
|
||||
movdqu(msg0, Address(buf, 0));
|
||||
pshufb(msg0, shuf_mask);
|
||||
paddd(e0, msg0);
|
||||
movdqa(e1, abcd);
|
||||
sha1rnds4(abcd, e0, 0);
|
||||
|
||||
// Rounds 4 - 7
|
||||
movdqu(msg1, Address(buf, 16));
|
||||
pshufb(msg1, shuf_mask);
|
||||
sha1nexte(e1, msg1);
|
||||
movdqa(e0, abcd);
|
||||
sha1rnds4(abcd, e1, 0);
|
||||
sha1msg1(msg0, msg1);
|
||||
|
||||
// Rounds 8 - 11
|
||||
movdqu(msg2, Address(buf, 32));
|
||||
pshufb(msg2, shuf_mask);
|
||||
sha1nexte(e0, msg2);
|
||||
movdqa(e1, abcd);
|
||||
sha1rnds4(abcd, e0, 0);
|
||||
sha1msg1(msg1, msg2);
|
||||
pxor(msg0, msg2);
|
||||
|
||||
// Rounds 12 - 15
|
||||
movdqu(msg3, Address(buf, 48));
|
||||
pshufb(msg3, shuf_mask);
|
||||
sha1nexte(e1, msg3);
|
||||
movdqa(e0, abcd);
|
||||
sha1msg2(msg0, msg3);
|
||||
sha1rnds4(abcd, e1, 0);
|
||||
sha1msg1(msg2, msg3);
|
||||
pxor(msg1, msg3);
|
||||
|
||||
// Rounds 16 - 19
|
||||
sha1nexte(e0, msg0);
|
||||
movdqa(e1, abcd);
|
||||
sha1msg2(msg1, msg0);
|
||||
sha1rnds4(abcd, e0, 0);
|
||||
sha1msg1(msg3, msg0);
|
||||
pxor(msg2, msg0);
|
||||
|
||||
// Rounds 20 - 23
|
||||
sha1nexte(e1, msg1);
|
||||
movdqa(e0, abcd);
|
||||
sha1msg2(msg2, msg1);
|
||||
sha1rnds4(abcd, e1, 1);
|
||||
sha1msg1(msg0, msg1);
|
||||
pxor(msg3, msg1);
|
||||
|
||||
// Rounds 24 - 27
|
||||
sha1nexte(e0, msg2);
|
||||
movdqa(e1, abcd);
|
||||
sha1msg2(msg3, msg2);
|
||||
sha1rnds4(abcd, e0, 1);
|
||||
sha1msg1(msg1, msg2);
|
||||
pxor(msg0, msg2);
|
||||
|
||||
// Rounds 28 - 31
|
||||
sha1nexte(e1, msg3);
|
||||
movdqa(e0, abcd);
|
||||
sha1msg2(msg0, msg3);
|
||||
sha1rnds4(abcd, e1, 1);
|
||||
sha1msg1(msg2, msg3);
|
||||
pxor(msg1, msg3);
|
||||
|
||||
// Rounds 32 - 35
|
||||
sha1nexte(e0, msg0);
|
||||
movdqa(e1, abcd);
|
||||
sha1msg2(msg1, msg0);
|
||||
sha1rnds4(abcd, e0, 1);
|
||||
sha1msg1(msg3, msg0);
|
||||
pxor(msg2, msg0);
|
||||
|
||||
// Rounds 36 - 39
|
||||
sha1nexte(e1, msg1);
|
||||
movdqa(e0, abcd);
|
||||
sha1msg2(msg2, msg1);
|
||||
sha1rnds4(abcd, e1, 1);
|
||||
sha1msg1(msg0, msg1);
|
||||
pxor(msg3, msg1);
|
||||
|
||||
// Rounds 40 - 43
|
||||
sha1nexte(e0, msg2);
|
||||
movdqa(e1, abcd);
|
||||
sha1msg2(msg3, msg2);
|
||||
sha1rnds4(abcd, e0, 2);
|
||||
sha1msg1(msg1, msg2);
|
||||
pxor(msg0, msg2);
|
||||
|
||||
// Rounds 44 - 47
|
||||
sha1nexte(e1, msg3);
|
||||
movdqa(e0, abcd);
|
||||
sha1msg2(msg0, msg3);
|
||||
sha1rnds4(abcd, e1, 2);
|
||||
sha1msg1(msg2, msg3);
|
||||
pxor(msg1, msg3);
|
||||
|
||||
// Rounds 48 - 51
|
||||
sha1nexte(e0, msg0);
|
||||
movdqa(e1, abcd);
|
||||
sha1msg2(msg1, msg0);
|
||||
sha1rnds4(abcd, e0, 2);
|
||||
sha1msg1(msg3, msg0);
|
||||
pxor(msg2, msg0);
|
||||
|
||||
// Rounds 52 - 55
|
||||
sha1nexte(e1, msg1);
|
||||
movdqa(e0, abcd);
|
||||
sha1msg2(msg2, msg1);
|
||||
sha1rnds4(abcd, e1, 2);
|
||||
sha1msg1(msg0, msg1);
|
||||
pxor(msg3, msg1);
|
||||
|
||||
// Rounds 56 - 59
|
||||
sha1nexte(e0, msg2);
|
||||
movdqa(e1, abcd);
|
||||
sha1msg2(msg3, msg2);
|
||||
sha1rnds4(abcd, e0, 2);
|
||||
sha1msg1(msg1, msg2);
|
||||
pxor(msg0, msg2);
|
||||
|
||||
// Rounds 60 - 63
|
||||
sha1nexte(e1, msg3);
|
||||
movdqa(e0, abcd);
|
||||
sha1msg2(msg0, msg3);
|
||||
sha1rnds4(abcd, e1, 3);
|
||||
sha1msg1(msg2, msg3);
|
||||
pxor(msg1, msg3);
|
||||
|
||||
// Rounds 64 - 67
|
||||
sha1nexte(e0, msg0);
|
||||
movdqa(e1, abcd);
|
||||
sha1msg2(msg1, msg0);
|
||||
sha1rnds4(abcd, e0, 3);
|
||||
sha1msg1(msg3, msg0);
|
||||
pxor(msg2, msg0);
|
||||
|
||||
// Rounds 68 - 71
|
||||
sha1nexte(e1, msg1);
|
||||
movdqa(e0, abcd);
|
||||
sha1msg2(msg2, msg1);
|
||||
sha1rnds4(abcd, e1, 3);
|
||||
pxor(msg3, msg1);
|
||||
|
||||
// Rounds 72 - 75
|
||||
sha1nexte(e0, msg2);
|
||||
movdqa(e1, abcd);
|
||||
sha1msg2(msg3, msg2);
|
||||
sha1rnds4(abcd, e0, 3);
|
||||
|
||||
// Rounds 76 - 79
|
||||
sha1nexte(e1, msg3);
|
||||
movdqa(e0, abcd);
|
||||
sha1rnds4(abcd, e1, 3);
|
||||
|
||||
// add current hash values with previously saved
|
||||
movdqu(msg0, Address(rsp, 0));
|
||||
sha1nexte(e0, msg0);
|
||||
movdqu(msg0, Address(rsp, 16));
|
||||
paddd(abcd, msg0);
|
||||
|
||||
if (multi_block) {
|
||||
// increment data pointer and loop if more to process
|
||||
addptr(buf, 64);
|
||||
addptr(ofs, 64);
|
||||
cmpptr(ofs, limit);
|
||||
jcc(Assembler::belowEqual, loop0);
|
||||
movptr(rax, ofs); //return ofs
|
||||
}
|
||||
// write hash values back in the correct order
|
||||
pshufd(abcd, abcd, 0x1b);
|
||||
movdqu(Address(state, 0), abcd);
|
||||
pextrd(Address(state, 16), e0, 3);
|
||||
|
||||
bind(done_hash);
|
||||
|
||||
}
|
||||
|
||||
// xmm0 (msg) is used as an implicit argument to sh256rnds2
|
||||
// and state0 and state1 can never use xmm0 register.
|
||||
// ofs and limit are used for multi-block byte array.
|
||||
// int com.sun.security.provider.DigestBase.implCompressMultiBlock(byte[] b, int ofs, int limit)
|
||||
#ifdef _LP64
|
||||
void MacroAssembler::fast_sha256(XMMRegister msg, XMMRegister state0, XMMRegister state1, XMMRegister msgtmp0,
|
||||
XMMRegister msgtmp1, XMMRegister msgtmp2, XMMRegister msgtmp3, XMMRegister msgtmp4,
|
||||
Register buf, Register state, Register ofs, Register limit, Register rsp,
|
||||
bool multi_block, XMMRegister shuf_mask) {
|
||||
#else
|
||||
void MacroAssembler::fast_sha256(XMMRegister msg, XMMRegister state0, XMMRegister state1, XMMRegister msgtmp0,
|
||||
XMMRegister msgtmp1, XMMRegister msgtmp2, XMMRegister msgtmp3, XMMRegister msgtmp4,
|
||||
Register buf, Register state, Register ofs, Register limit, Register rsp,
|
||||
bool multi_block) {
|
||||
#endif
|
||||
Label start, done_hash, loop0;
|
||||
|
||||
address K256 = StubRoutines::x86::k256_addr();
|
||||
address pshuffle_byte_flip_mask = StubRoutines::x86::pshuffle_byte_flip_mask_addr();
|
||||
|
||||
bind(start);
|
||||
movdqu(state0, Address(state, 0));
|
||||
movdqu(state1, Address(state, 16));
|
||||
|
||||
pshufd(state0, state0, 0xB1);
|
||||
pshufd(state1, state1, 0x1B);
|
||||
movdqa(msgtmp4, state0);
|
||||
palignr(state0, state1, 8);
|
||||
pblendw(state1, msgtmp4, 0xF0);
|
||||
|
||||
#ifdef _LP64
|
||||
movdqu(shuf_mask, ExternalAddress(pshuffle_byte_flip_mask));
|
||||
#endif
|
||||
lea(rax, ExternalAddress(K256));
|
||||
|
||||
bind(loop0);
|
||||
movdqu(Address(rsp, 0), state0);
|
||||
movdqu(Address(rsp, 16), state1);
|
||||
|
||||
// Rounds 0-3
|
||||
movdqu(msg, Address(buf, 0));
|
||||
#ifdef _LP64
|
||||
pshufb(msg, shuf_mask);
|
||||
#else
|
||||
pshufb(msg, ExternalAddress(pshuffle_byte_flip_mask));
|
||||
#endif
|
||||
movdqa(msgtmp0, msg);
|
||||
paddd(msg, Address(rax, 0));
|
||||
sha256rnds2(state1, state0);
|
||||
pshufd(msg, msg, 0x0E);
|
||||
sha256rnds2(state0, state1);
|
||||
|
||||
// Rounds 4-7
|
||||
movdqu(msg, Address(buf, 16));
|
||||
#ifdef _LP64
|
||||
pshufb(msg, shuf_mask);
|
||||
#else
|
||||
pshufb(msg, ExternalAddress(pshuffle_byte_flip_mask));
|
||||
#endif
|
||||
movdqa(msgtmp1, msg);
|
||||
paddd(msg, Address(rax, 16));
|
||||
sha256rnds2(state1, state0);
|
||||
pshufd(msg, msg, 0x0E);
|
||||
sha256rnds2(state0, state1);
|
||||
sha256msg1(msgtmp0, msgtmp1);
|
||||
|
||||
// Rounds 8-11
|
||||
movdqu(msg, Address(buf, 32));
|
||||
#ifdef _LP64
|
||||
pshufb(msg, shuf_mask);
|
||||
#else
|
||||
pshufb(msg, ExternalAddress(pshuffle_byte_flip_mask));
|
||||
#endif
|
||||
movdqa(msgtmp2, msg);
|
||||
paddd(msg, Address(rax, 32));
|
||||
sha256rnds2(state1, state0);
|
||||
pshufd(msg, msg, 0x0E);
|
||||
sha256rnds2(state0, state1);
|
||||
sha256msg1(msgtmp1, msgtmp2);
|
||||
|
||||
// Rounds 12-15
|
||||
movdqu(msg, Address(buf, 48));
|
||||
#ifdef _LP64
|
||||
pshufb(msg, shuf_mask);
|
||||
#else
|
||||
pshufb(msg, ExternalAddress(pshuffle_byte_flip_mask));
|
||||
#endif
|
||||
movdqa(msgtmp3, msg);
|
||||
paddd(msg, Address(rax, 48));
|
||||
sha256rnds2(state1, state0);
|
||||
movdqa(msgtmp4, msgtmp3);
|
||||
palignr(msgtmp4, msgtmp2, 4);
|
||||
paddd(msgtmp0, msgtmp4);
|
||||
sha256msg2(msgtmp0, msgtmp3);
|
||||
pshufd(msg, msg, 0x0E);
|
||||
sha256rnds2(state0, state1);
|
||||
sha256msg1(msgtmp2, msgtmp3);
|
||||
|
||||
// Rounds 16-19
|
||||
movdqa(msg, msgtmp0);
|
||||
paddd(msg, Address(rax, 64));
|
||||
sha256rnds2(state1, state0);
|
||||
movdqa(msgtmp4, msgtmp0);
|
||||
palignr(msgtmp4, msgtmp3, 4);
|
||||
paddd(msgtmp1, msgtmp4);
|
||||
sha256msg2(msgtmp1, msgtmp0);
|
||||
pshufd(msg, msg, 0x0E);
|
||||
sha256rnds2(state0, state1);
|
||||
sha256msg1(msgtmp3, msgtmp0);
|
||||
|
||||
// Rounds 20-23
|
||||
movdqa(msg, msgtmp1);
|
||||
paddd(msg, Address(rax, 80));
|
||||
sha256rnds2(state1, state0);
|
||||
movdqa(msgtmp4, msgtmp1);
|
||||
palignr(msgtmp4, msgtmp0, 4);
|
||||
paddd(msgtmp2, msgtmp4);
|
||||
sha256msg2(msgtmp2, msgtmp1);
|
||||
pshufd(msg, msg, 0x0E);
|
||||
sha256rnds2(state0, state1);
|
||||
sha256msg1(msgtmp0, msgtmp1);
|
||||
|
||||
// Rounds 24-27
|
||||
movdqa(msg, msgtmp2);
|
||||
paddd(msg, Address(rax, 96));
|
||||
sha256rnds2(state1, state0);
|
||||
movdqa(msgtmp4, msgtmp2);
|
||||
palignr(msgtmp4, msgtmp1, 4);
|
||||
paddd(msgtmp3, msgtmp4);
|
||||
sha256msg2(msgtmp3, msgtmp2);
|
||||
pshufd(msg, msg, 0x0E);
|
||||
sha256rnds2(state0, state1);
|
||||
sha256msg1(msgtmp1, msgtmp2);
|
||||
|
||||
// Rounds 28-31
|
||||
movdqa(msg, msgtmp3);
|
||||
paddd(msg, Address(rax, 112));
|
||||
sha256rnds2(state1, state0);
|
||||
movdqa(msgtmp4, msgtmp3);
|
||||
palignr(msgtmp4, msgtmp2, 4);
|
||||
paddd(msgtmp0, msgtmp4);
|
||||
sha256msg2(msgtmp0, msgtmp3);
|
||||
pshufd(msg, msg, 0x0E);
|
||||
sha256rnds2(state0, state1);
|
||||
sha256msg1(msgtmp2, msgtmp3);
|
||||
|
||||
// Rounds 32-35
|
||||
movdqa(msg, msgtmp0);
|
||||
paddd(msg, Address(rax, 128));
|
||||
sha256rnds2(state1, state0);
|
||||
movdqa(msgtmp4, msgtmp0);
|
||||
palignr(msgtmp4, msgtmp3, 4);
|
||||
paddd(msgtmp1, msgtmp4);
|
||||
sha256msg2(msgtmp1, msgtmp0);
|
||||
pshufd(msg, msg, 0x0E);
|
||||
sha256rnds2(state0, state1);
|
||||
sha256msg1(msgtmp3, msgtmp0);
|
||||
|
||||
// Rounds 36-39
|
||||
movdqa(msg, msgtmp1);
|
||||
paddd(msg, Address(rax, 144));
|
||||
sha256rnds2(state1, state0);
|
||||
movdqa(msgtmp4, msgtmp1);
|
||||
palignr(msgtmp4, msgtmp0, 4);
|
||||
paddd(msgtmp2, msgtmp4);
|
||||
sha256msg2(msgtmp2, msgtmp1);
|
||||
pshufd(msg, msg, 0x0E);
|
||||
sha256rnds2(state0, state1);
|
||||
sha256msg1(msgtmp0, msgtmp1);
|
||||
|
||||
// Rounds 40-43
|
||||
movdqa(msg, msgtmp2);
|
||||
paddd(msg, Address(rax, 160));
|
||||
sha256rnds2(state1, state0);
|
||||
movdqa(msgtmp4, msgtmp2);
|
||||
palignr(msgtmp4, msgtmp1, 4);
|
||||
paddd(msgtmp3, msgtmp4);
|
||||
sha256msg2(msgtmp3, msgtmp2);
|
||||
pshufd(msg, msg, 0x0E);
|
||||
sha256rnds2(state0, state1);
|
||||
sha256msg1(msgtmp1, msgtmp2);
|
||||
|
||||
// Rounds 44-47
|
||||
movdqa(msg, msgtmp3);
|
||||
paddd(msg, Address(rax, 176));
|
||||
sha256rnds2(state1, state0);
|
||||
movdqa(msgtmp4, msgtmp3);
|
||||
palignr(msgtmp4, msgtmp2, 4);
|
||||
paddd(msgtmp0, msgtmp4);
|
||||
sha256msg2(msgtmp0, msgtmp3);
|
||||
pshufd(msg, msg, 0x0E);
|
||||
sha256rnds2(state0, state1);
|
||||
sha256msg1(msgtmp2, msgtmp3);
|
||||
|
||||
// Rounds 48-51
|
||||
movdqa(msg, msgtmp0);
|
||||
paddd(msg, Address(rax, 192));
|
||||
sha256rnds2(state1, state0);
|
||||
movdqa(msgtmp4, msgtmp0);
|
||||
palignr(msgtmp4, msgtmp3, 4);
|
||||
paddd(msgtmp1, msgtmp4);
|
||||
sha256msg2(msgtmp1, msgtmp0);
|
||||
pshufd(msg, msg, 0x0E);
|
||||
sha256rnds2(state0, state1);
|
||||
sha256msg1(msgtmp3, msgtmp0);
|
||||
|
||||
// Rounds 52-55
|
||||
movdqa(msg, msgtmp1);
|
||||
paddd(msg, Address(rax, 208));
|
||||
sha256rnds2(state1, state0);
|
||||
movdqa(msgtmp4, msgtmp1);
|
||||
palignr(msgtmp4, msgtmp0, 4);
|
||||
paddd(msgtmp2, msgtmp4);
|
||||
sha256msg2(msgtmp2, msgtmp1);
|
||||
pshufd(msg, msg, 0x0E);
|
||||
sha256rnds2(state0, state1);
|
||||
|
||||
// Rounds 56-59
|
||||
movdqa(msg, msgtmp2);
|
||||
paddd(msg, Address(rax, 224));
|
||||
sha256rnds2(state1, state0);
|
||||
movdqa(msgtmp4, msgtmp2);
|
||||
palignr(msgtmp4, msgtmp1, 4);
|
||||
paddd(msgtmp3, msgtmp4);
|
||||
sha256msg2(msgtmp3, msgtmp2);
|
||||
pshufd(msg, msg, 0x0E);
|
||||
sha256rnds2(state0, state1);
|
||||
|
||||
// Rounds 60-63
|
||||
movdqa(msg, msgtmp3);
|
||||
paddd(msg, Address(rax, 240));
|
||||
sha256rnds2(state1, state0);
|
||||
pshufd(msg, msg, 0x0E);
|
||||
sha256rnds2(state0, state1);
|
||||
movdqu(msg, Address(rsp, 0));
|
||||
paddd(state0, msg);
|
||||
movdqu(msg, Address(rsp, 16));
|
||||
paddd(state1, msg);
|
||||
|
||||
if (multi_block) {
|
||||
// increment data pointer and loop if more to process
|
||||
addptr(buf, 64);
|
||||
addptr(ofs, 64);
|
||||
cmpptr(ofs, limit);
|
||||
jcc(Assembler::belowEqual, loop0);
|
||||
movptr(rax, ofs); //return ofs
|
||||
}
|
||||
|
||||
pshufd(state0, state0, 0x1B);
|
||||
pshufd(state1, state1, 0xB1);
|
||||
movdqa(msgtmp4, state0);
|
||||
pblendw(state0, state1, 0xF0);
|
||||
palignr(state1, msgtmp4, 8);
|
||||
|
||||
movdqu(Address(state, 0), state0);
|
||||
movdqu(Address(state, 16), state1);
|
||||
|
||||
bind(done_hash);
|
||||
|
||||
}
|
||||
@ -3068,6 +3068,136 @@ class StubGenerator: public StubCodeGenerator {
|
||||
return start;
|
||||
}
|
||||
|
||||
address generate_upper_word_mask() {
|
||||
__ align(64);
|
||||
StubCodeMark mark(this, "StubRoutines", "upper_word_mask");
|
||||
address start = __ pc();
|
||||
__ emit_data(0x00000000, relocInfo::none, 0);
|
||||
__ emit_data(0x00000000, relocInfo::none, 0);
|
||||
__ emit_data(0x00000000, relocInfo::none, 0);
|
||||
__ emit_data(0xFFFFFFFF, relocInfo::none, 0);
|
||||
return start;
|
||||
}
|
||||
|
||||
address generate_shuffle_byte_flip_mask() {
|
||||
__ align(64);
|
||||
StubCodeMark mark(this, "StubRoutines", "shuffle_byte_flip_mask");
|
||||
address start = __ pc();
|
||||
__ emit_data(0x0c0d0e0f, relocInfo::none, 0);
|
||||
__ emit_data(0x08090a0b, relocInfo::none, 0);
|
||||
__ emit_data(0x04050607, relocInfo::none, 0);
|
||||
__ emit_data(0x00010203, relocInfo::none, 0);
|
||||
return start;
|
||||
}
|
||||
|
||||
// ofs and limit are use for multi-block byte array.
|
||||
// int com.sun.security.provider.DigestBase.implCompressMultiBlock(byte[] b, int ofs, int limit)
|
||||
address generate_sha1_implCompress(bool multi_block, const char *name) {
|
||||
__ align(CodeEntryAlignment);
|
||||
StubCodeMark mark(this, "StubRoutines", name);
|
||||
address start = __ pc();
|
||||
|
||||
Register buf = rax;
|
||||
Register state = rdx;
|
||||
Register ofs = rcx;
|
||||
Register limit = rdi;
|
||||
|
||||
const Address buf_param(rbp, 8 + 0);
|
||||
const Address state_param(rbp, 8 + 4);
|
||||
const Address ofs_param(rbp, 8 + 8);
|
||||
const Address limit_param(rbp, 8 + 12);
|
||||
|
||||
const XMMRegister abcd = xmm0;
|
||||
const XMMRegister e0 = xmm1;
|
||||
const XMMRegister e1 = xmm2;
|
||||
const XMMRegister msg0 = xmm3;
|
||||
|
||||
const XMMRegister msg1 = xmm4;
|
||||
const XMMRegister msg2 = xmm5;
|
||||
const XMMRegister msg3 = xmm6;
|
||||
const XMMRegister shuf_mask = xmm7;
|
||||
|
||||
__ enter();
|
||||
__ subptr(rsp, 8 * wordSize);
|
||||
if (multi_block) {
|
||||
__ push(limit);
|
||||
}
|
||||
__ movptr(buf, buf_param);
|
||||
__ movptr(state, state_param);
|
||||
if (multi_block) {
|
||||
__ movptr(ofs, ofs_param);
|
||||
__ movptr(limit, limit_param);
|
||||
}
|
||||
|
||||
__ fast_sha1(abcd, e0, e1, msg0, msg1, msg2, msg3, shuf_mask,
|
||||
buf, state, ofs, limit, rsp, multi_block);
|
||||
|
||||
if (multi_block) {
|
||||
__ pop(limit);
|
||||
}
|
||||
__ addptr(rsp, 8 * wordSize);
|
||||
__ leave();
|
||||
__ ret(0);
|
||||
return start;
|
||||
}
|
||||
|
||||
address generate_pshuffle_byte_flip_mask() {
|
||||
__ align(64);
|
||||
StubCodeMark mark(this, "StubRoutines", "pshuffle_byte_flip_mask");
|
||||
address start = __ pc();
|
||||
__ emit_data(0x00010203, relocInfo::none, 0);
|
||||
__ emit_data(0x04050607, relocInfo::none, 0);
|
||||
__ emit_data(0x08090a0b, relocInfo::none, 0);
|
||||
__ emit_data(0x0c0d0e0f, relocInfo::none, 0);
|
||||
return start;
|
||||
}
|
||||
|
||||
// ofs and limit are use for multi-block byte array.
|
||||
// int com.sun.security.provider.DigestBase.implCompressMultiBlock(byte[] b, int ofs, int limit)
|
||||
address generate_sha256_implCompress(bool multi_block, const char *name) {
|
||||
__ align(CodeEntryAlignment);
|
||||
StubCodeMark mark(this, "StubRoutines", name);
|
||||
address start = __ pc();
|
||||
|
||||
Register buf = rbx;
|
||||
Register state = rsi;
|
||||
Register ofs = rdx;
|
||||
Register limit = rcx;
|
||||
|
||||
const Address buf_param(rbp, 8 + 0);
|
||||
const Address state_param(rbp, 8 + 4);
|
||||
const Address ofs_param(rbp, 8 + 8);
|
||||
const Address limit_param(rbp, 8 + 12);
|
||||
|
||||
const XMMRegister msg = xmm0;
|
||||
const XMMRegister state0 = xmm1;
|
||||
const XMMRegister state1 = xmm2;
|
||||
const XMMRegister msgtmp0 = xmm3;
|
||||
|
||||
const XMMRegister msgtmp1 = xmm4;
|
||||
const XMMRegister msgtmp2 = xmm5;
|
||||
const XMMRegister msgtmp3 = xmm6;
|
||||
const XMMRegister msgtmp4 = xmm7;
|
||||
|
||||
__ enter();
|
||||
__ subptr(rsp, 8 * wordSize);
|
||||
handleSOERegisters(true /*saving*/);
|
||||
__ movptr(buf, buf_param);
|
||||
__ movptr(state, state_param);
|
||||
if (multi_block) {
|
||||
__ movptr(ofs, ofs_param);
|
||||
__ movptr(limit, limit_param);
|
||||
}
|
||||
|
||||
__ fast_sha256(msg, state0, state1, msgtmp0, msgtmp1, msgtmp2, msgtmp3, msgtmp4,
|
||||
buf, state, ofs, limit, rsp, multi_block);
|
||||
|
||||
handleSOERegisters(false);
|
||||
__ addptr(rsp, 8 * wordSize);
|
||||
__ leave();
|
||||
__ ret(0);
|
||||
return start;
|
||||
}
|
||||
|
||||
// byte swap x86 long
|
||||
address generate_ghash_long_swap_mask() {
|
||||
@ -3772,6 +3902,19 @@ class StubGenerator: public StubCodeGenerator {
|
||||
StubRoutines::_counterMode_AESCrypt = generate_counterMode_AESCrypt_Parallel();
|
||||
}
|
||||
|
||||
if (UseSHA1Intrinsics) {
|
||||
StubRoutines::x86::_upper_word_mask_addr = generate_upper_word_mask();
|
||||
StubRoutines::x86::_shuffle_byte_flip_mask_addr = generate_shuffle_byte_flip_mask();
|
||||
StubRoutines::_sha1_implCompress = generate_sha1_implCompress(false, "sha1_implCompress");
|
||||
StubRoutines::_sha1_implCompressMB = generate_sha1_implCompress(true, "sha1_implCompressMB");
|
||||
}
|
||||
if (UseSHA256Intrinsics) {
|
||||
StubRoutines::x86::_k256_adr = (address)StubRoutines::x86::_k256;
|
||||
StubRoutines::x86::_pshuffle_byte_flip_mask_addr = generate_pshuffle_byte_flip_mask();
|
||||
StubRoutines::_sha256_implCompress = generate_sha256_implCompress(false, "sha256_implCompress");
|
||||
StubRoutines::_sha256_implCompressMB = generate_sha256_implCompress(true, "sha256_implCompressMB");
|
||||
}
|
||||
|
||||
// Generate GHASH intrinsics code
|
||||
if (UseGHASHIntrinsics) {
|
||||
StubRoutines::x86::_ghash_long_swap_mask_addr = generate_ghash_long_swap_mask();
|
||||
|
||||
@ -3695,6 +3695,133 @@ class StubGenerator: public StubCodeGenerator {
|
||||
return start;
|
||||
}
|
||||
|
||||
address generate_upper_word_mask() {
|
||||
__ align(64);
|
||||
StubCodeMark mark(this, "StubRoutines", "upper_word_mask");
|
||||
address start = __ pc();
|
||||
__ emit_data64(0x0000000000000000, relocInfo::none);
|
||||
__ emit_data64(0xFFFFFFFF00000000, relocInfo::none);
|
||||
return start;
|
||||
}
|
||||
|
||||
address generate_shuffle_byte_flip_mask() {
|
||||
__ align(64);
|
||||
StubCodeMark mark(this, "StubRoutines", "shuffle_byte_flip_mask");
|
||||
address start = __ pc();
|
||||
__ emit_data64(0x08090a0b0c0d0e0f, relocInfo::none);
|
||||
__ emit_data64(0x0001020304050607, relocInfo::none);
|
||||
return start;
|
||||
}
|
||||
|
||||
// ofs and limit are use for multi-block byte array.
|
||||
// int com.sun.security.provider.DigestBase.implCompressMultiBlock(byte[] b, int ofs, int limit)
|
||||
address generate_sha1_implCompress(bool multi_block, const char *name) {
|
||||
__ align(CodeEntryAlignment);
|
||||
StubCodeMark mark(this, "StubRoutines", name);
|
||||
address start = __ pc();
|
||||
|
||||
Register buf = c_rarg0;
|
||||
Register state = c_rarg1;
|
||||
Register ofs = c_rarg2;
|
||||
Register limit = c_rarg3;
|
||||
|
||||
const XMMRegister abcd = xmm0;
|
||||
const XMMRegister e0 = xmm1;
|
||||
const XMMRegister e1 = xmm2;
|
||||
const XMMRegister msg0 = xmm3;
|
||||
|
||||
const XMMRegister msg1 = xmm4;
|
||||
const XMMRegister msg2 = xmm5;
|
||||
const XMMRegister msg3 = xmm6;
|
||||
const XMMRegister shuf_mask = xmm7;
|
||||
|
||||
__ enter();
|
||||
|
||||
#ifdef _WIN64
|
||||
// save the xmm registers which must be preserved 6-7
|
||||
__ subptr(rsp, 4 * wordSize);
|
||||
__ movdqu(Address(rsp, 0), xmm6);
|
||||
__ movdqu(Address(rsp, 2 * wordSize), xmm7);
|
||||
#endif
|
||||
|
||||
__ subptr(rsp, 4 * wordSize);
|
||||
|
||||
__ fast_sha1(abcd, e0, e1, msg0, msg1, msg2, msg3, shuf_mask,
|
||||
buf, state, ofs, limit, rsp, multi_block);
|
||||
|
||||
__ addptr(rsp, 4 * wordSize);
|
||||
#ifdef _WIN64
|
||||
// restore xmm regs belonging to calling function
|
||||
__ movdqu(xmm6, Address(rsp, 0));
|
||||
__ movdqu(xmm7, Address(rsp, 2 * wordSize));
|
||||
__ addptr(rsp, 4 * wordSize);
|
||||
#endif
|
||||
|
||||
__ leave();
|
||||
__ ret(0);
|
||||
return start;
|
||||
}
|
||||
|
||||
address generate_pshuffle_byte_flip_mask() {
|
||||
__ align(64);
|
||||
StubCodeMark mark(this, "StubRoutines", "pshuffle_byte_flip_mask");
|
||||
address start = __ pc();
|
||||
__ emit_data64(0x0405060700010203, relocInfo::none);
|
||||
__ emit_data64(0x0c0d0e0f08090a0b, relocInfo::none);
|
||||
return start;
|
||||
}
|
||||
|
||||
// ofs and limit are use for multi-block byte array.
|
||||
// int com.sun.security.provider.DigestBase.implCompressMultiBlock(byte[] b, int ofs, int limit)
|
||||
address generate_sha256_implCompress(bool multi_block, const char *name) {
|
||||
__ align(CodeEntryAlignment);
|
||||
StubCodeMark mark(this, "StubRoutines", name);
|
||||
address start = __ pc();
|
||||
|
||||
Register buf = c_rarg0;
|
||||
Register state = c_rarg1;
|
||||
Register ofs = c_rarg2;
|
||||
Register limit = c_rarg3;
|
||||
|
||||
const XMMRegister msg = xmm0;
|
||||
const XMMRegister state0 = xmm1;
|
||||
const XMMRegister state1 = xmm2;
|
||||
const XMMRegister msgtmp0 = xmm3;
|
||||
|
||||
const XMMRegister msgtmp1 = xmm4;
|
||||
const XMMRegister msgtmp2 = xmm5;
|
||||
const XMMRegister msgtmp3 = xmm6;
|
||||
const XMMRegister msgtmp4 = xmm7;
|
||||
|
||||
const XMMRegister shuf_mask = xmm8;
|
||||
|
||||
__ enter();
|
||||
#ifdef _WIN64
|
||||
// save the xmm registers which must be preserved 6-7
|
||||
__ subptr(rsp, 6 * wordSize);
|
||||
__ movdqu(Address(rsp, 0), xmm6);
|
||||
__ movdqu(Address(rsp, 2 * wordSize), xmm7);
|
||||
__ movdqu(Address(rsp, 4 * wordSize), xmm8);
|
||||
#endif
|
||||
|
||||
__ subptr(rsp, 4 * wordSize);
|
||||
|
||||
__ fast_sha256(msg, state0, state1, msgtmp0, msgtmp1, msgtmp2, msgtmp3, msgtmp4,
|
||||
buf, state, ofs, limit, rsp, multi_block, shuf_mask);
|
||||
|
||||
__ addptr(rsp, 4 * wordSize);
|
||||
#ifdef _WIN64
|
||||
// restore xmm regs belonging to calling function
|
||||
__ movdqu(xmm6, Address(rsp, 0));
|
||||
__ movdqu(xmm7, Address(rsp, 2 * wordSize));
|
||||
__ movdqu(xmm8, Address(rsp, 4 * wordSize));
|
||||
__ addptr(rsp, 6 * wordSize);
|
||||
#endif
|
||||
__ leave();
|
||||
__ ret(0);
|
||||
return start;
|
||||
}
|
||||
|
||||
// This is a version of CTR/AES crypt which does 6 blocks in a loop at a time
|
||||
// to hide instruction latency
|
||||
//
|
||||
@ -4974,6 +5101,19 @@ class StubGenerator: public StubCodeGenerator {
|
||||
StubRoutines::_counterMode_AESCrypt = generate_counterMode_AESCrypt_Parallel();
|
||||
}
|
||||
|
||||
if (UseSHA1Intrinsics) {
|
||||
StubRoutines::x86::_upper_word_mask_addr = generate_upper_word_mask();
|
||||
StubRoutines::x86::_shuffle_byte_flip_mask_addr = generate_shuffle_byte_flip_mask();
|
||||
StubRoutines::_sha1_implCompress = generate_sha1_implCompress(false, "sha1_implCompress");
|
||||
StubRoutines::_sha1_implCompressMB = generate_sha1_implCompress(true, "sha1_implCompressMB");
|
||||
}
|
||||
if (UseSHA256Intrinsics) {
|
||||
StubRoutines::x86::_k256_adr = (address)StubRoutines::x86::_k256;
|
||||
StubRoutines::x86::_pshuffle_byte_flip_mask_addr = generate_pshuffle_byte_flip_mask();
|
||||
StubRoutines::_sha256_implCompress = generate_sha256_implCompress(false, "sha256_implCompress");
|
||||
StubRoutines::_sha256_implCompressMB = generate_sha256_implCompress(true, "sha256_implCompressMB");
|
||||
}
|
||||
|
||||
// Generate GHASH intrinsics code
|
||||
if (UseGHASHIntrinsics) {
|
||||
StubRoutines::x86::_ghash_long_swap_mask_addr = generate_ghash_long_swap_mask();
|
||||
|
||||
@ -29,6 +29,12 @@
|
||||
#include "runtime/thread.inline.hpp"
|
||||
#include "crc32c.h"
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#define ALIGNED_(x) __declspec(align(x))
|
||||
#else
|
||||
#define ALIGNED_(x) __attribute__ ((aligned(x)))
|
||||
#endif
|
||||
|
||||
// Implementation of the platform-specific part of StubRoutines - for
|
||||
// a description of how to extend it, see the stubRoutines.hpp file.
|
||||
|
||||
@ -37,6 +43,10 @@ address StubRoutines::x86::_key_shuffle_mask_addr = NULL;
|
||||
address StubRoutines::x86::_counter_shuffle_mask_addr = NULL;
|
||||
address StubRoutines::x86::_ghash_long_swap_mask_addr = NULL;
|
||||
address StubRoutines::x86::_ghash_byte_swap_mask_addr = NULL;
|
||||
address StubRoutines::x86::_upper_word_mask_addr = NULL;
|
||||
address StubRoutines::x86::_shuffle_byte_flip_mask_addr = NULL;
|
||||
address StubRoutines::x86::_k256_adr = NULL;
|
||||
address StubRoutines::x86::_pshuffle_byte_flip_mask_addr = NULL;
|
||||
|
||||
uint64_t StubRoutines::x86::_crc_by128_masks[] =
|
||||
{
|
||||
@ -236,3 +246,23 @@ void StubRoutines::x86::generate_CRC32C_table(bool is_pclmulqdq_table_supported)
|
||||
_crc32c_table = (juint*)pclmulqdq_table;
|
||||
}
|
||||
}
|
||||
|
||||
ALIGNED_(64) juint StubRoutines::x86::_k256[] =
|
||||
{
|
||||
0x428a2f98UL, 0x71374491UL, 0xb5c0fbcfUL, 0xe9b5dba5UL,
|
||||
0x3956c25bUL, 0x59f111f1UL, 0x923f82a4UL, 0xab1c5ed5UL,
|
||||
0xd807aa98UL, 0x12835b01UL, 0x243185beUL, 0x550c7dc3UL,
|
||||
0x72be5d74UL, 0x80deb1feUL, 0x9bdc06a7UL, 0xc19bf174UL,
|
||||
0xe49b69c1UL, 0xefbe4786UL, 0x0fc19dc6UL, 0x240ca1ccUL,
|
||||
0x2de92c6fUL, 0x4a7484aaUL, 0x5cb0a9dcUL, 0x76f988daUL,
|
||||
0x983e5152UL, 0xa831c66dUL, 0xb00327c8UL, 0xbf597fc7UL,
|
||||
0xc6e00bf3UL, 0xd5a79147UL, 0x06ca6351UL, 0x14292967UL,
|
||||
0x27b70a85UL, 0x2e1b2138UL, 0x4d2c6dfcUL, 0x53380d13UL,
|
||||
0x650a7354UL, 0x766a0abbUL, 0x81c2c92eUL, 0x92722c85UL,
|
||||
0xa2bfe8a1UL, 0xa81a664bUL, 0xc24b8b70UL, 0xc76c51a3UL,
|
||||
0xd192e819UL, 0xd6990624UL, 0xf40e3585UL, 0x106aa070UL,
|
||||
0x19a4c116UL, 0x1e376c08UL, 0x2748774cUL, 0x34b0bcb5UL,
|
||||
0x391c0cb3UL, 0x4ed8aa4aUL, 0x5b9cca4fUL, 0x682e6ff3UL,
|
||||
0x748f82eeUL, 0x78a5636fUL, 0x84c87814UL, 0x8cc70208UL,
|
||||
0x90befffaUL, 0xa4506cebUL, 0xbef9a3f7UL, 0xc67178f2UL
|
||||
};
|
||||
|
||||
@ -46,6 +46,17 @@
|
||||
static address _ghash_long_swap_mask_addr;
|
||||
static address _ghash_byte_swap_mask_addr;
|
||||
|
||||
// upper word mask for sha1
|
||||
static address _upper_word_mask_addr;
|
||||
// byte flip mask for sha1
|
||||
static address _shuffle_byte_flip_mask_addr;
|
||||
|
||||
//k256 table for sha256
|
||||
static juint _k256[];
|
||||
static address _k256_adr;
|
||||
// byte flip mask for sha256
|
||||
static address _pshuffle_byte_flip_mask_addr;
|
||||
|
||||
public:
|
||||
static address verify_mxcsr_entry() { return _verify_mxcsr_entry; }
|
||||
static address key_shuffle_mask_addr() { return _key_shuffle_mask_addr; }
|
||||
@ -53,5 +64,9 @@
|
||||
static address crc_by128_masks_addr() { return (address)_crc_by128_masks; }
|
||||
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; }
|
||||
static address upper_word_mask_addr() { return _upper_word_mask_addr; }
|
||||
static address shuffle_byte_flip_mask_addr() { return _shuffle_byte_flip_mask_addr; }
|
||||
static address k256_addr() { return _k256_adr; }
|
||||
static address pshuffle_byte_flip_mask_addr() { return _pshuffle_byte_flip_mask_addr; }
|
||||
static void generate_CRC32C_table(bool is_pclmulqdq_supported);
|
||||
#endif // CPU_X86_VM_STUBROUTINES_X86_32_HPP
|
||||
|
||||
@ -68,10 +68,11 @@
|
||||
declare_constant(VM_Version::CPU_AVX512DQ) \
|
||||
declare_constant(VM_Version::CPU_AVX512PF) \
|
||||
declare_constant(VM_Version::CPU_AVX512ER) \
|
||||
declare_constant(VM_Version::CPU_AVX512CD) \
|
||||
declare_constant(VM_Version::CPU_AVX512BW)
|
||||
declare_constant(VM_Version::CPU_AVX512CD)
|
||||
|
||||
#define VM_LONG_CONSTANTS_CPU(declare_constant, declare_preprocessor_constant, declare_c1_constant, declare_c2_constant, declare_c2_preprocessor_constant) \
|
||||
declare_preprocessor_constant("VM_Version::CPU_AVX512VL", CPU_AVX512VL)
|
||||
declare_preprocessor_constant("VM_Version::CPU_AVX512BW", CPU_AVX512BW) \
|
||||
declare_preprocessor_constant("VM_Version::CPU_AVX512VL", CPU_AVX512VL) \
|
||||
declare_preprocessor_constant("VM_Version::CPU_SHA", CPU_SHA)
|
||||
|
||||
#endif // CPU_X86_VM_VMSTRUCTS_X86_HPP
|
||||
|
||||
@ -577,7 +577,7 @@ void VM_Version::get_processor_features() {
|
||||
}
|
||||
|
||||
char buf[256];
|
||||
jio_snprintf(buf, sizeof(buf), "(%u cores per cpu, %u threads per core) family %d model %d stepping %d%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s",
|
||||
jio_snprintf(buf, sizeof(buf), "(%u cores per cpu, %u threads per core) family %d model %d stepping %d%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s",
|
||||
cores_per_cpu(), threads_per_core(),
|
||||
cpu_family(), _model, _stepping,
|
||||
(supports_cmov() ? ", cmov" : ""),
|
||||
@ -608,7 +608,8 @@ void VM_Version::get_processor_features() {
|
||||
(supports_bmi1() ? ", bmi1" : ""),
|
||||
(supports_bmi2() ? ", bmi2" : ""),
|
||||
(supports_adx() ? ", adx" : ""),
|
||||
(supports_evex() ? ", evex" : ""));
|
||||
(supports_evex() ? ", evex" : ""),
|
||||
(supports_sha() ? ", sha" : ""));
|
||||
_features_string = os::strdup(buf);
|
||||
|
||||
// UseSSE is set to the smaller of what hardware supports and what
|
||||
@ -730,17 +731,29 @@ void VM_Version::get_processor_features() {
|
||||
FLAG_SET_DEFAULT(UseGHASHIntrinsics, false);
|
||||
}
|
||||
|
||||
if (UseSHA) {
|
||||
if (supports_sha()) {
|
||||
if (FLAG_IS_DEFAULT(UseSHA)) {
|
||||
UseSHA = true;
|
||||
}
|
||||
} else if (UseSHA) {
|
||||
warning("SHA instructions are not available on this CPU");
|
||||
FLAG_SET_DEFAULT(UseSHA, false);
|
||||
}
|
||||
|
||||
if (UseSHA1Intrinsics) {
|
||||
if (UseSHA) {
|
||||
if (FLAG_IS_DEFAULT(UseSHA1Intrinsics)) {
|
||||
FLAG_SET_DEFAULT(UseSHA1Intrinsics, true);
|
||||
}
|
||||
} else if (UseSHA1Intrinsics) {
|
||||
warning("Intrinsics for SHA-1 crypto hash functions not available on this CPU.");
|
||||
FLAG_SET_DEFAULT(UseSHA1Intrinsics, false);
|
||||
}
|
||||
|
||||
if (UseSHA256Intrinsics) {
|
||||
if (UseSHA) {
|
||||
if (FLAG_IS_DEFAULT(UseSHA256Intrinsics)) {
|
||||
FLAG_SET_DEFAULT(UseSHA256Intrinsics, true);
|
||||
}
|
||||
} else if (UseSHA256Intrinsics) {
|
||||
warning("Intrinsics for SHA-224 and SHA-256 crypto hash functions not available on this CPU.");
|
||||
FLAG_SET_DEFAULT(UseSHA256Intrinsics, false);
|
||||
}
|
||||
@ -750,6 +763,10 @@ void VM_Version::get_processor_features() {
|
||||
FLAG_SET_DEFAULT(UseSHA512Intrinsics, false);
|
||||
}
|
||||
|
||||
if (!(UseSHA1Intrinsics || UseSHA256Intrinsics || UseSHA512Intrinsics)) {
|
||||
FLAG_SET_DEFAULT(UseSHA, false);
|
||||
}
|
||||
|
||||
if (UseAdler32Intrinsics) {
|
||||
warning("Adler32Intrinsics not available on this CPU.");
|
||||
FLAG_SET_DEFAULT(UseAdler32Intrinsics, false);
|
||||
|
||||
@ -221,7 +221,7 @@ class VM_Version : public Abstract_VM_Version {
|
||||
avx512pf : 1,
|
||||
avx512er : 1,
|
||||
avx512cd : 1,
|
||||
: 1,
|
||||
sha : 1,
|
||||
avx512bw : 1,
|
||||
avx512vl : 1;
|
||||
} bits;
|
||||
@ -282,11 +282,13 @@ protected:
|
||||
CPU_AVX512DQ = (1 << 27),
|
||||
CPU_AVX512PF = (1 << 28),
|
||||
CPU_AVX512ER = (1 << 29),
|
||||
CPU_AVX512CD = (1 << 30),
|
||||
CPU_AVX512BW = (1 << 31)
|
||||
CPU_AVX512CD = (1 << 30)
|
||||
// Keeping sign bit 31 unassigned.
|
||||
};
|
||||
|
||||
#define CPU_AVX512VL UCONST64(0x100000000) // EVEX instructions with smaller vector length : enums are limited to 32bit
|
||||
#define CPU_AVX512BW ((uint64_t)UCONST64(0x100000000)) // enums are limited to 31 bit
|
||||
#define CPU_AVX512VL ((uint64_t)UCONST64(0x200000000)) // EVEX instructions with smaller vector length
|
||||
#define CPU_SHA ((uint64_t)UCONST64(0x400000000)) // SHA instructions
|
||||
|
||||
enum Extended_Family {
|
||||
// AMD
|
||||
@ -516,6 +518,8 @@ protected:
|
||||
result |= CPU_ADX;
|
||||
if(_cpuid_info.sef_cpuid7_ebx.bits.bmi2 != 0)
|
||||
result |= CPU_BMI2;
|
||||
if (_cpuid_info.sef_cpuid7_ebx.bits.sha != 0)
|
||||
result |= CPU_SHA;
|
||||
if(_cpuid_info.ext_cpuid1_ecx.bits.lzcnt_intel != 0)
|
||||
result |= CPU_LZCNT;
|
||||
// for Intel, ecx.bits.misalignsse bit (bit 8) indicates support for prefetchw
|
||||
@ -721,6 +725,7 @@ public:
|
||||
static bool supports_avx512nobw() { return (supports_evex() && !supports_avx512bw()); }
|
||||
static bool supports_avx256only() { return (supports_avx2() && !supports_evex()); }
|
||||
static bool supports_avxonly() { return ((supports_avx2() || supports_avx()) && !supports_evex()); }
|
||||
static bool supports_sha() { return (_features & CPU_SHA) != 0; }
|
||||
// Intel features
|
||||
static bool is_intel_family_core() { return is_intel() &&
|
||||
extended_cpu_family() == CPU_FAMILY_INTEL_CORE; }
|
||||
|
||||
@ -1420,9 +1420,6 @@ const bool Matcher::isSimpleConstant64(jlong value) {
|
||||
// The ecx parameter to rep stos for the ClearArray node is in dwords.
|
||||
const bool Matcher::init_array_count_is_in_bytes = false;
|
||||
|
||||
// Threshold size for cleararray.
|
||||
const int Matcher::init_array_short_size = 8 * BytesPerLong;
|
||||
|
||||
// Needs 2 CMOV's for longs.
|
||||
const int Matcher::long_cmove_cost() { return 1; }
|
||||
|
||||
@ -11369,27 +11366,54 @@ instruct MoveL2D_reg_reg_sse(regD dst, eRegL src, regD tmp) %{
|
||||
// =======================================================================
|
||||
// fast clearing of an array
|
||||
instruct rep_stos(eCXRegI cnt, eDIRegP base, eAXRegI zero, Universe dummy, eFlagsReg cr) %{
|
||||
predicate(!UseFastStosb);
|
||||
predicate(!((ClearArrayNode*)n)->is_large());
|
||||
match(Set dummy (ClearArray cnt base));
|
||||
effect(USE_KILL cnt, USE_KILL base, KILL zero, KILL cr);
|
||||
format %{ "XOR EAX,EAX\t# ClearArray:\n\t"
|
||||
"SHL ECX,1\t# Convert doublewords to words\n\t"
|
||||
"REP STOS\t# store EAX into [EDI++] while ECX--" %}
|
||||
|
||||
format %{ $$template
|
||||
$$emit$$"XOR EAX,EAX\t# ClearArray:\n\t"
|
||||
$$emit$$"CMP InitArrayShortSize,rcx\n\t"
|
||||
$$emit$$"JG LARGE\n\t"
|
||||
$$emit$$"SHL ECX, 1\n\t"
|
||||
$$emit$$"DEC ECX\n\t"
|
||||
$$emit$$"JS DONE\t# Zero length\n\t"
|
||||
$$emit$$"MOV EAX,(EDI,ECX,4)\t# LOOP\n\t"
|
||||
$$emit$$"DEC ECX\n\t"
|
||||
$$emit$$"JGE LOOP\n\t"
|
||||
$$emit$$"JMP DONE\n\t"
|
||||
$$emit$$"# LARGE:\n\t"
|
||||
if (UseFastStosb) {
|
||||
$$emit$$"SHL ECX,3\t# Convert doublewords to bytes\n\t"
|
||||
$$emit$$"REP STOSB\t# store EAX into [EDI++] while ECX--\n\t"
|
||||
} else {
|
||||
$$emit$$"SHL ECX,1\t# Convert doublewords to words\n\t"
|
||||
$$emit$$"REP STOS\t# store EAX into [EDI++] while ECX--\n\t"
|
||||
}
|
||||
$$emit$$"# DONE"
|
||||
%}
|
||||
ins_encode %{
|
||||
__ clear_mem($base$$Register, $cnt$$Register, $zero$$Register);
|
||||
__ clear_mem($base$$Register, $cnt$$Register, $zero$$Register, false);
|
||||
%}
|
||||
ins_pipe( pipe_slow );
|
||||
%}
|
||||
|
||||
instruct rep_fast_stosb(eCXRegI cnt, eDIRegP base, eAXRegI zero, Universe dummy, eFlagsReg cr) %{
|
||||
predicate(UseFastStosb);
|
||||
instruct rep_stos_large(eCXRegI cnt, eDIRegP base, eAXRegI zero, Universe dummy, eFlagsReg cr) %{
|
||||
predicate(((ClearArrayNode*)n)->is_large());
|
||||
match(Set dummy (ClearArray cnt base));
|
||||
effect(USE_KILL cnt, USE_KILL base, KILL zero, KILL cr);
|
||||
format %{ "XOR EAX,EAX\t# ClearArray:\n\t"
|
||||
"SHL ECX,3\t# Convert doublewords to bytes\n\t"
|
||||
"REP STOSB\t# store EAX into [EDI++] while ECX--" %}
|
||||
format %{ $$template
|
||||
$$emit$$"XOR EAX,EAX\t# ClearArray:\n\t"
|
||||
if (UseFastStosb) {
|
||||
$$emit$$"SHL ECX,3\t# Convert doublewords to bytes\n\t"
|
||||
$$emit$$"REP STOSB\t# store EAX into [EDI++] while ECX--\n\t"
|
||||
} else {
|
||||
$$emit$$"SHL ECX,1\t# Convert doublewords to words\n\t"
|
||||
$$emit$$"REP STOS\t# store EAX into [EDI++] while ECX--\n\t"
|
||||
}
|
||||
$$emit$$"# DONE"
|
||||
%}
|
||||
ins_encode %{
|
||||
__ clear_mem($base$$Register, $cnt$$Register, $zero$$Register);
|
||||
__ clear_mem($base$$Register, $cnt$$Register, $zero$$Register, true);
|
||||
%}
|
||||
ins_pipe( pipe_slow );
|
||||
%}
|
||||
|
||||
@ -1637,9 +1637,6 @@ const bool Matcher::isSimpleConstant64(jlong value) {
|
||||
// The ecx parameter to rep stosq for the ClearArray node is in words.
|
||||
const bool Matcher::init_array_count_is_in_bytes = false;
|
||||
|
||||
// Threshold size for cleararray.
|
||||
const int Matcher::init_array_short_size = 8 * BytesPerLong;
|
||||
|
||||
// No additional cost for CMOVL.
|
||||
const int Matcher::long_cmove_cost() { return 0; }
|
||||
|
||||
@ -10460,31 +10457,55 @@ instruct MoveL2D_reg_reg(regD dst, rRegL src) %{
|
||||
instruct rep_stos(rcx_RegL cnt, rdi_RegP base, rax_RegI zero, Universe dummy,
|
||||
rFlagsReg cr)
|
||||
%{
|
||||
predicate(!UseFastStosb);
|
||||
predicate(!((ClearArrayNode*)n)->is_large());
|
||||
match(Set dummy (ClearArray cnt base));
|
||||
effect(USE_KILL cnt, USE_KILL base, KILL zero, KILL cr);
|
||||
|
||||
format %{ "xorq rax, rax\t# ClearArray:\n\t"
|
||||
"rep stosq\t# Store rax to *rdi++ while rcx--" %}
|
||||
format %{ $$template
|
||||
$$emit$$"xorq rax, rax\t# ClearArray:\n\t"
|
||||
$$emit$$"cmp InitArrayShortSize,rcx\n\t"
|
||||
$$emit$$"jg LARGE\n\t"
|
||||
$$emit$$"dec rcx\n\t"
|
||||
$$emit$$"js DONE\t# Zero length\n\t"
|
||||
$$emit$$"mov rax,(rdi,rcx,8)\t# LOOP\n\t"
|
||||
$$emit$$"dec rcx\n\t"
|
||||
$$emit$$"jge LOOP\n\t"
|
||||
$$emit$$"jmp DONE\n\t"
|
||||
$$emit$$"# LARGE:\n\t"
|
||||
if (UseFastStosb) {
|
||||
$$emit$$"shlq rcx,3\t# Convert doublewords to bytes\n\t"
|
||||
$$emit$$"rep stosb\t# Store rax to *rdi++ while rcx--\n\t"
|
||||
} else {
|
||||
$$emit$$"rep stosq\t# Store rax to *rdi++ while rcx--\n\t"
|
||||
}
|
||||
$$emit$$"# DONE"
|
||||
%}
|
||||
ins_encode %{
|
||||
__ clear_mem($base$$Register, $cnt$$Register, $zero$$Register);
|
||||
__ clear_mem($base$$Register, $cnt$$Register, $zero$$Register, false);
|
||||
%}
|
||||
ins_pipe(pipe_slow);
|
||||
%}
|
||||
|
||||
instruct rep_fast_stosb(rcx_RegL cnt, rdi_RegP base, rax_RegI zero, Universe dummy,
|
||||
rFlagsReg cr)
|
||||
instruct rep_stos_large(rcx_RegL cnt, rdi_RegP base, rax_RegI zero, Universe dummy,
|
||||
rFlagsReg cr)
|
||||
%{
|
||||
predicate(UseFastStosb);
|
||||
predicate(((ClearArrayNode*)n)->is_large());
|
||||
match(Set dummy (ClearArray cnt base));
|
||||
effect(USE_KILL cnt, USE_KILL base, KILL zero, KILL cr);
|
||||
format %{ "xorq rax, rax\t# ClearArray:\n\t"
|
||||
"shlq rcx,3\t# Convert doublewords to bytes\n\t"
|
||||
"rep stosb\t# Store rax to *rdi++ while rcx--" %}
|
||||
ins_encode %{
|
||||
__ clear_mem($base$$Register, $cnt$$Register, $zero$$Register);
|
||||
|
||||
format %{ $$template
|
||||
$$emit$$"xorq rax, rax\t# ClearArray:\n\t"
|
||||
if (UseFastStosb) {
|
||||
$$emit$$"shlq rcx,3\t# Convert doublewords to bytes\n\t"
|
||||
$$emit$$"rep stosb\t# Store rax to *rdi++ while rcx--"
|
||||
} else {
|
||||
$$emit$$"rep stosq\t# Store rax to *rdi++ while rcx--"
|
||||
}
|
||||
%}
|
||||
ins_pipe( pipe_slow );
|
||||
ins_encode %{
|
||||
__ clear_mem($base$$Register, $cnt$$Register, $zero$$Register, true);
|
||||
%}
|
||||
ins_pipe(pipe_slow);
|
||||
%}
|
||||
|
||||
instruct string_compareL(rdi_RegP str1, rcx_RegI cnt1, rsi_RegP str2, rdx_RegI cnt2,
|
||||
|
||||
@ -203,7 +203,8 @@ public class AMD64 extends Architecture {
|
||||
AVX512ER,
|
||||
AVX512CD,
|
||||
AVX512BW,
|
||||
AVX512VL
|
||||
AVX512VL,
|
||||
SHA
|
||||
}
|
||||
|
||||
private final EnumSet<CPUFeature> features;
|
||||
|
||||
@ -122,6 +122,9 @@ public class AMD64HotSpotJVMCIBackendFactory implements HotSpotJVMCIBackendFacto
|
||||
if ((config.vmVersionFeatures & config.amd64AVX512VL) != 0) {
|
||||
features.add(AMD64.CPUFeature.AVX512VL);
|
||||
}
|
||||
if ((config.vmVersionFeatures & config.amd64SHA) != 0) {
|
||||
features.add(AMD64.CPUFeature.SHA);
|
||||
}
|
||||
return features;
|
||||
}
|
||||
|
||||
|
||||
@ -945,6 +945,7 @@ public class HotSpotVMConfig {
|
||||
@HotSpotVMConstant(name = "VM_Version::CPU_AVX512CD", archs = {"amd64"}) @Stable public long amd64AVX512CD;
|
||||
@HotSpotVMConstant(name = "VM_Version::CPU_AVX512BW", archs = {"amd64"}) @Stable public long amd64AVX512BW;
|
||||
@HotSpotVMConstant(name = "VM_Version::CPU_AVX512VL", archs = {"amd64"}) @Stable public long amd64AVX512VL;
|
||||
@HotSpotVMConstant(name = "VM_Version::CPU_SHA", archs = {"amd64"}) @Stable public long amd64SHA;
|
||||
|
||||
// SPARC specific values
|
||||
@HotSpotVMConstant(name = "VM_Version::vis3_instructions_m", archs = {"sparc"}) @Stable public int sparcVis3Instructions;
|
||||
|
||||
@ -471,7 +471,7 @@ void Canonicalizer::do_Intrinsic (Intrinsic* x) {
|
||||
InstanceConstant* c = x->argument_at(0)->type()->as_InstanceConstant();
|
||||
if (c != NULL && !c->value()->is_null_object()) {
|
||||
// ciInstance::java_mirror_type() returns non-NULL only for Java mirrors
|
||||
ciType* t = c->value()->as_instance()->java_mirror_type();
|
||||
ciType* t = c->value()->java_mirror_type();
|
||||
if (t->is_klass()) {
|
||||
// substitute cls.isInstance(obj) of a constant Class into
|
||||
// an InstantOf instruction
|
||||
@ -487,6 +487,17 @@ void Canonicalizer::do_Intrinsic (Intrinsic* x) {
|
||||
}
|
||||
break;
|
||||
}
|
||||
case vmIntrinsics::_isPrimitive : {
|
||||
assert(x->number_of_arguments() == 1, "wrong type");
|
||||
|
||||
// Class.isPrimitive is known on constant classes:
|
||||
InstanceConstant* c = x->argument_at(0)->type()->as_InstanceConstant();
|
||||
if (c != NULL && !c->value()->is_null_object()) {
|
||||
ciType* t = c->value()->java_mirror_type();
|
||||
set_constant(t->is_primitive_type());
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -148,6 +148,7 @@ bool Compiler::is_intrinsic_supported(const methodHandle& method) {
|
||||
case vmIntrinsics::_longBitsToDouble:
|
||||
case vmIntrinsics::_getClass:
|
||||
case vmIntrinsics::_isInstance:
|
||||
case vmIntrinsics::_isPrimitive:
|
||||
case vmIntrinsics::_currentThread:
|
||||
case vmIntrinsics::_dabs:
|
||||
case vmIntrinsics::_dsqrt:
|
||||
|
||||
@ -1293,6 +1293,25 @@ void LIRGenerator::do_getClass(Intrinsic* x) {
|
||||
__ move_wide(new LIR_Address(temp, in_bytes(Klass::java_mirror_offset()), T_OBJECT), result);
|
||||
}
|
||||
|
||||
// java.lang.Class::isPrimitive()
|
||||
void LIRGenerator::do_isPrimitive(Intrinsic* x) {
|
||||
assert(x->number_of_arguments() == 1, "wrong type");
|
||||
|
||||
LIRItem rcvr(x->argument_at(0), this);
|
||||
rcvr.load_item();
|
||||
LIR_Opr temp = new_register(T_METADATA);
|
||||
LIR_Opr result = rlock_result(x);
|
||||
|
||||
CodeEmitInfo* info = NULL;
|
||||
if (x->needs_null_check()) {
|
||||
info = state_for(x);
|
||||
}
|
||||
|
||||
__ move(new LIR_Address(rcvr.result(), java_lang_Class::klass_offset_in_bytes(), T_ADDRESS), temp, info);
|
||||
__ cmp(lir_cond_notEqual, temp, LIR_OprFact::intConst(0));
|
||||
__ cmove(lir_cond_notEqual, LIR_OprFact::intConst(0), LIR_OprFact::intConst(1), result, T_BOOLEAN);
|
||||
}
|
||||
|
||||
|
||||
// Example: Thread.currentThread()
|
||||
void LIRGenerator::do_currentThread(Intrinsic* x) {
|
||||
@ -3132,6 +3151,7 @@ void LIRGenerator::do_Intrinsic(Intrinsic* x) {
|
||||
|
||||
case vmIntrinsics::_Object_init: do_RegisterFinalizer(x); break;
|
||||
case vmIntrinsics::_isInstance: do_isInstance(x); break;
|
||||
case vmIntrinsics::_isPrimitive: do_isPrimitive(x); break;
|
||||
case vmIntrinsics::_getClass: do_getClass(x); break;
|
||||
case vmIntrinsics::_currentThread: do_currentThread(x); break;
|
||||
|
||||
|
||||
@ -246,6 +246,7 @@ class LIRGenerator: public InstructionVisitor, public BlockClosure {
|
||||
|
||||
void do_RegisterFinalizer(Intrinsic* x);
|
||||
void do_isInstance(Intrinsic* x);
|
||||
void do_isPrimitive(Intrinsic* x);
|
||||
void do_getClass(Intrinsic* x);
|
||||
void do_currentThread(Intrinsic* x);
|
||||
void do_MathIntrinsic(Intrinsic* x);
|
||||
|
||||
@ -1035,14 +1035,15 @@
|
||||
do_name( updateByteBuffer_A_name, "updateByteBuffer") \
|
||||
\
|
||||
/* support for Unsafe */ \
|
||||
do_class(sun_misc_Unsafe, "sun/misc/Unsafe") \
|
||||
do_class(jdk_internal_misc_Unsafe, "jdk/internal/misc/Unsafe") \
|
||||
\
|
||||
do_intrinsic(_allocateInstance, jdk_internal_misc_Unsafe, allocateInstance_name, allocateInstance_signature, F_RN) \
|
||||
do_name( allocateInstance_name, "allocateInstance") \
|
||||
do_signature(allocateInstance_signature, "(Ljava/lang/Class;)Ljava/lang/Object;") \
|
||||
do_intrinsic(_allocateUninitializedArray, jdk_internal_misc_Unsafe, allocateUninitializedArray_name, newArray_signature, F_R) \
|
||||
do_name( allocateUninitializedArray_name, "allocateUninitializedArray0") \
|
||||
do_intrinsic(_copyMemory, jdk_internal_misc_Unsafe, copyMemory_name, copyMemory_signature, F_RN) \
|
||||
do_name( copyMemory_name, "copyMemory") \
|
||||
do_name( copyMemory_name, "copyMemory0") \
|
||||
do_signature(copyMemory_signature, "(Ljava/lang/Object;JLjava/lang/Object;JJ)V") \
|
||||
do_intrinsic(_loadFence, jdk_internal_misc_Unsafe, loadFence_name, loadFence_signature, F_RN) \
|
||||
do_name( loadFence_name, "loadFence") \
|
||||
|
||||
@ -639,11 +639,12 @@
|
||||
declare_constant(VM_Version::CPU_AVX512DQ) \
|
||||
declare_constant(VM_Version::CPU_AVX512PF) \
|
||||
declare_constant(VM_Version::CPU_AVX512ER) \
|
||||
declare_constant(VM_Version::CPU_AVX512CD) \
|
||||
declare_constant(VM_Version::CPU_AVX512BW)
|
||||
declare_constant(VM_Version::CPU_AVX512CD)
|
||||
|
||||
#define VM_LONG_CONSTANTS_CPU(declare_constant, declare_preprocessor_constant, declare_c1_constant, declare_c2_constant, declare_c2_preprocessor_constant) \
|
||||
declare_preprocessor_constant("VM_Version::CPU_AVX512VL", CPU_AVX512VL)
|
||||
declare_preprocessor_constant("VM_Version::CPU_AVX512BW", CPU_AVX512BW) \
|
||||
declare_preprocessor_constant("VM_Version::CPU_AVX512VL", CPU_AVX512VL) \
|
||||
declare_preprocessor_constant("VM_Version::CPU_SHA", CPU_SHA)
|
||||
|
||||
#endif // TARGET_ARCH_x86
|
||||
|
||||
|
||||
@ -1338,73 +1338,6 @@ vmSymbols::SID Method::klass_id_for_intrinsics(const Klass* holder) {
|
||||
return vmSymbols::find_sid(klass_name);
|
||||
}
|
||||
|
||||
static bool is_unsafe_alias(vmSymbols::SID name_id) {
|
||||
// All 70 intrinsic candidate methods from sun.misc.Unsafe in 1.8.
|
||||
// Some have the same method name but different signature, e.g.
|
||||
// getByte(long), getByte(Object,long)
|
||||
switch (name_id) {
|
||||
case vmSymbols::VM_SYMBOL_ENUM_NAME(allocateInstance_name):
|
||||
case vmSymbols::VM_SYMBOL_ENUM_NAME(copyMemory_name):
|
||||
case vmSymbols::VM_SYMBOL_ENUM_NAME(loadFence_name):
|
||||
case vmSymbols::VM_SYMBOL_ENUM_NAME(storeFence_name):
|
||||
case vmSymbols::VM_SYMBOL_ENUM_NAME(fullFence_name):
|
||||
case vmSymbols::VM_SYMBOL_ENUM_NAME(getObject_name):
|
||||
case vmSymbols::VM_SYMBOL_ENUM_NAME(getBoolean_name):
|
||||
case vmSymbols::VM_SYMBOL_ENUM_NAME(getByte_name):
|
||||
case vmSymbols::VM_SYMBOL_ENUM_NAME(getShort_name):
|
||||
case vmSymbols::VM_SYMBOL_ENUM_NAME(getChar_name):
|
||||
case vmSymbols::VM_SYMBOL_ENUM_NAME(getInt_name):
|
||||
case vmSymbols::VM_SYMBOL_ENUM_NAME(getLong_name):
|
||||
case vmSymbols::VM_SYMBOL_ENUM_NAME(getFloat_name):
|
||||
case vmSymbols::VM_SYMBOL_ENUM_NAME(getDouble_name):
|
||||
case vmSymbols::VM_SYMBOL_ENUM_NAME(putObject_name):
|
||||
case vmSymbols::VM_SYMBOL_ENUM_NAME(putBoolean_name):
|
||||
case vmSymbols::VM_SYMBOL_ENUM_NAME(putByte_name):
|
||||
case vmSymbols::VM_SYMBOL_ENUM_NAME(putShort_name):
|
||||
case vmSymbols::VM_SYMBOL_ENUM_NAME(putChar_name):
|
||||
case vmSymbols::VM_SYMBOL_ENUM_NAME(putInt_name):
|
||||
case vmSymbols::VM_SYMBOL_ENUM_NAME(putLong_name):
|
||||
case vmSymbols::VM_SYMBOL_ENUM_NAME(putFloat_name):
|
||||
case vmSymbols::VM_SYMBOL_ENUM_NAME(putDouble_name):
|
||||
case vmSymbols::VM_SYMBOL_ENUM_NAME(getObjectVolatile_name):
|
||||
case vmSymbols::VM_SYMBOL_ENUM_NAME(getBooleanVolatile_name):
|
||||
case vmSymbols::VM_SYMBOL_ENUM_NAME(getByteVolatile_name):
|
||||
case vmSymbols::VM_SYMBOL_ENUM_NAME(getShortVolatile_name):
|
||||
case vmSymbols::VM_SYMBOL_ENUM_NAME(getCharVolatile_name):
|
||||
case vmSymbols::VM_SYMBOL_ENUM_NAME(getIntVolatile_name):
|
||||
case vmSymbols::VM_SYMBOL_ENUM_NAME(getLongVolatile_name):
|
||||
case vmSymbols::VM_SYMBOL_ENUM_NAME(getFloatVolatile_name):
|
||||
case vmSymbols::VM_SYMBOL_ENUM_NAME(getDoubleVolatile_name):
|
||||
case vmSymbols::VM_SYMBOL_ENUM_NAME(putObjectVolatile_name):
|
||||
case vmSymbols::VM_SYMBOL_ENUM_NAME(putBooleanVolatile_name):
|
||||
case vmSymbols::VM_SYMBOL_ENUM_NAME(putByteVolatile_name):
|
||||
case vmSymbols::VM_SYMBOL_ENUM_NAME(putShortVolatile_name):
|
||||
case vmSymbols::VM_SYMBOL_ENUM_NAME(putCharVolatile_name):
|
||||
case vmSymbols::VM_SYMBOL_ENUM_NAME(putIntVolatile_name):
|
||||
case vmSymbols::VM_SYMBOL_ENUM_NAME(putLongVolatile_name):
|
||||
case vmSymbols::VM_SYMBOL_ENUM_NAME(putFloatVolatile_name):
|
||||
case vmSymbols::VM_SYMBOL_ENUM_NAME(putDoubleVolatile_name):
|
||||
case vmSymbols::VM_SYMBOL_ENUM_NAME(getAddress_name):
|
||||
case vmSymbols::VM_SYMBOL_ENUM_NAME(putAddress_name):
|
||||
case vmSymbols::VM_SYMBOL_ENUM_NAME(compareAndSwapObject_name):
|
||||
case vmSymbols::VM_SYMBOL_ENUM_NAME(compareAndSwapLong_name):
|
||||
case vmSymbols::VM_SYMBOL_ENUM_NAME(compareAndSwapInt_name):
|
||||
case vmSymbols::VM_SYMBOL_ENUM_NAME(putOrderedObject_name):
|
||||
case vmSymbols::VM_SYMBOL_ENUM_NAME(putOrderedLong_name):
|
||||
case vmSymbols::VM_SYMBOL_ENUM_NAME(putOrderedInt_name):
|
||||
case vmSymbols::VM_SYMBOL_ENUM_NAME(getAndAddInt_name):
|
||||
case vmSymbols::VM_SYMBOL_ENUM_NAME(getAndAddLong_name):
|
||||
case vmSymbols::VM_SYMBOL_ENUM_NAME(getAndSetInt_name):
|
||||
case vmSymbols::VM_SYMBOL_ENUM_NAME(getAndSetLong_name):
|
||||
case vmSymbols::VM_SYMBOL_ENUM_NAME(getAndSetObject_name):
|
||||
case vmSymbols::VM_SYMBOL_ENUM_NAME(park_name):
|
||||
case vmSymbols::VM_SYMBOL_ENUM_NAME(unpark_name):
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void Method::init_intrinsic_id() {
|
||||
assert(_intrinsic_id == vmIntrinsics::_none, "do this just once");
|
||||
const uintptr_t max_id_uint = right_n_bits((int)(sizeof(_intrinsic_id) * BitsPerByte));
|
||||
@ -1457,14 +1390,6 @@ void Method::init_intrinsic_id() {
|
||||
if (is_static() != MethodHandles::is_signature_polymorphic_static(id))
|
||||
id = vmIntrinsics::_none;
|
||||
break;
|
||||
|
||||
case vmSymbols::VM_SYMBOL_ENUM_NAME(sun_misc_Unsafe):
|
||||
// Map sun.misc.Unsafe to jdk.internal.misc.Unsafe
|
||||
if (!is_unsafe_alias(name_id)) break;
|
||||
// pretend it is the corresponding method in the internal Unsafe class:
|
||||
klass_id = vmSymbols::VM_SYMBOL_ENUM_NAME(jdk_internal_misc_Unsafe);
|
||||
id = vmIntrinsics::find_id(klass_id, name_id, sig_id, flags);
|
||||
break;
|
||||
}
|
||||
|
||||
if (id != vmIntrinsics::_none) {
|
||||
|
||||
@ -500,6 +500,7 @@ bool C2Compiler::is_intrinsic_supported(const methodHandle& method, bool is_virt
|
||||
case vmIntrinsics::_currentTimeMillis:
|
||||
case vmIntrinsics::_nanoTime:
|
||||
case vmIntrinsics::_allocateInstance:
|
||||
case vmIntrinsics::_allocateUninitializedArray:
|
||||
case vmIntrinsics::_newArray:
|
||||
case vmIntrinsics::_getLength:
|
||||
case vmIntrinsics::_copyOf:
|
||||
|
||||
@ -48,6 +48,7 @@
|
||||
#include "opto/runtime.hpp"
|
||||
#include "opto/subnode.hpp"
|
||||
#include "prims/nativeLookup.hpp"
|
||||
#include "prims/unsafe.hpp"
|
||||
#include "runtime/sharedRuntime.hpp"
|
||||
#include "trace/traceMacros.hpp"
|
||||
|
||||
@ -246,6 +247,7 @@ class LibraryCallKit : public GraphKit {
|
||||
bool inline_unsafe_access(bool is_native_ptr, bool is_store, BasicType type, AccessKind kind, bool is_unaligned);
|
||||
static bool klass_needs_init_guard(Node* kls);
|
||||
bool inline_unsafe_allocate();
|
||||
bool inline_unsafe_newArray(bool uninitialized);
|
||||
bool inline_unsafe_copyMemory();
|
||||
bool inline_native_currentThread();
|
||||
#ifdef TRACE_HAVE_INTRINSICS
|
||||
@ -256,8 +258,6 @@ class LibraryCallKit : public GraphKit {
|
||||
bool inline_native_isInterrupted();
|
||||
bool inline_native_Class_query(vmIntrinsics::ID id);
|
||||
bool inline_native_subtype_check();
|
||||
|
||||
bool inline_native_newArray();
|
||||
bool inline_native_getLength();
|
||||
bool inline_array_copyOf(bool is_copyOfRange);
|
||||
bool inline_array_equals(StrIntrinsicNode::ArgEnc ae);
|
||||
@ -714,7 +714,6 @@ bool LibraryCallKit::try_to_inline(int predicate) {
|
||||
case vmIntrinsics::_nanoTime: return inline_native_time_funcs(CAST_FROM_FN_PTR(address, os::javaTimeNanos), "nanoTime");
|
||||
case vmIntrinsics::_allocateInstance: return inline_unsafe_allocate();
|
||||
case vmIntrinsics::_copyMemory: return inline_unsafe_copyMemory();
|
||||
case vmIntrinsics::_newArray: return inline_native_newArray();
|
||||
case vmIntrinsics::_getLength: return inline_native_getLength();
|
||||
case vmIntrinsics::_copyOf: return inline_array_copyOf(false);
|
||||
case vmIntrinsics::_copyOfRange: return inline_array_copyOf(true);
|
||||
@ -723,6 +722,9 @@ bool LibraryCallKit::try_to_inline(int predicate) {
|
||||
case vmIntrinsics::_Objects_checkIndex: return inline_objects_checkIndex();
|
||||
case vmIntrinsics::_clone: return inline_native_clone(intrinsic()->is_virtual());
|
||||
|
||||
case vmIntrinsics::_allocateUninitializedArray: return inline_unsafe_newArray(true);
|
||||
case vmIntrinsics::_newArray: return inline_unsafe_newArray(false);
|
||||
|
||||
case vmIntrinsics::_isAssignableFrom: return inline_native_subtype_check();
|
||||
|
||||
case vmIntrinsics::_isInstance:
|
||||
@ -2306,9 +2308,6 @@ void LibraryCallKit::insert_pre_barrier(Node* base_oop, Node* offset,
|
||||
}
|
||||
|
||||
|
||||
// Interpret Unsafe.fieldOffset cookies correctly:
|
||||
extern jlong Unsafe_field_offset_to_byte_offset(jlong field_offset);
|
||||
|
||||
const TypeOopPtr* LibraryCallKit::sharpen_unsafe_type(Compile::AliasType* alias_type, const TypePtr *adr_type, bool is_native_ptr) {
|
||||
// Attempt to infer a sharper value type from the offset and base type.
|
||||
ciKlass* sharpened_klass = NULL;
|
||||
@ -3831,9 +3830,17 @@ Node* LibraryCallKit::generate_array_guard_common(Node* kls, RegionNode* region,
|
||||
|
||||
//-----------------------inline_native_newArray--------------------------
|
||||
// private static native Object java.lang.reflect.newArray(Class<?> componentType, int length);
|
||||
bool LibraryCallKit::inline_native_newArray() {
|
||||
Node* mirror = argument(0);
|
||||
Node* count_val = argument(1);
|
||||
// private native Object Unsafe.allocateUninitializedArray0(Class<?> cls, int size);
|
||||
bool LibraryCallKit::inline_unsafe_newArray(bool uninitialized) {
|
||||
Node* mirror;
|
||||
Node* count_val;
|
||||
if (uninitialized) {
|
||||
mirror = argument(1);
|
||||
count_val = argument(2);
|
||||
} else {
|
||||
mirror = argument(0);
|
||||
count_val = argument(1);
|
||||
}
|
||||
|
||||
mirror = null_check(mirror);
|
||||
// If mirror or obj is dead, only null-path is taken.
|
||||
@ -3878,6 +3885,12 @@ bool LibraryCallKit::inline_native_newArray() {
|
||||
result_val->init_req(_normal_path, obj);
|
||||
result_io ->init_req(_normal_path, i_o());
|
||||
result_mem->init_req(_normal_path, reset_memory());
|
||||
|
||||
if (uninitialized) {
|
||||
// Mark the allocation so that zeroing is skipped
|
||||
AllocateArrayNode* alloc = AllocateArrayNode::Ideal_array_allocation(obj, &_gvn);
|
||||
alloc->maybe_set_complete(&_gvn);
|
||||
}
|
||||
}
|
||||
|
||||
// Return the combined state.
|
||||
@ -4466,7 +4479,7 @@ bool LibraryCallKit::inline_fp_conversions(vmIntrinsics::ID id) {
|
||||
}
|
||||
|
||||
//----------------------inline_unsafe_copyMemory-------------------------
|
||||
// public native void Unsafe.copyMemory(Object srcBase, long srcOffset, Object destBase, long destOffset, long bytes);
|
||||
// public native void Unsafe.copyMemory0(Object srcBase, long srcOffset, Object destBase, long destOffset, long bytes);
|
||||
bool LibraryCallKit::inline_unsafe_copyMemory() {
|
||||
if (callee()->is_static()) return false; // caller must have the capability!
|
||||
null_check_receiver(); // null-check receiver
|
||||
|
||||
@ -399,10 +399,6 @@ public:
|
||||
// Optional scaling for the parameter to the ClearArray/CopyArray node.
|
||||
static const bool init_array_count_is_in_bytes;
|
||||
|
||||
// Threshold small size (in bytes) for a ClearArray/CopyArray node.
|
||||
// Anything this size or smaller may get converted to discrete scalar stores.
|
||||
static const int init_array_short_size;
|
||||
|
||||
// Some hardware needs 2 CMOV's for longs.
|
||||
static const int long_cmove_cost();
|
||||
|
||||
|
||||
@ -2741,6 +2741,9 @@ Node* ClearArrayNode::Identity(PhaseGVN* phase) {
|
||||
//------------------------------Idealize---------------------------------------
|
||||
// Clearing a short array is faster with stores
|
||||
Node *ClearArrayNode::Ideal(PhaseGVN *phase, bool can_reshape){
|
||||
// Already know this is a large node, do not try to ideal it
|
||||
if (_is_large) return NULL;
|
||||
|
||||
const int unit = BytesPerLong;
|
||||
const TypeX* t = phase->type(in(2))->isa_intptr_t();
|
||||
if (!t) return NULL;
|
||||
@ -2753,8 +2756,11 @@ Node *ClearArrayNode::Ideal(PhaseGVN *phase, bool can_reshape){
|
||||
// (see jck test stmt114.stmt11402.val).
|
||||
if (size <= 0 || size % unit != 0) return NULL;
|
||||
intptr_t count = size / unit;
|
||||
// Length too long; use fast hardware clear
|
||||
if (size > Matcher::init_array_short_size) return NULL;
|
||||
// Length too long; communicate this to matchers and assemblers.
|
||||
// Assemblers are responsible to produce fast hardware clears for it.
|
||||
if (size > InitArrayShortSize) {
|
||||
return new ClearArrayNode(in(0), in(1), in(2), in(3), true);
|
||||
}
|
||||
Node *mem = in(1);
|
||||
if( phase->type(mem)==Type::TOP ) return NULL;
|
||||
Node *adr = in(3);
|
||||
@ -2852,7 +2858,7 @@ Node* ClearArrayNode::clear_memory(Node* ctl, Node* mem, Node* dest,
|
||||
// Bulk clear double-words
|
||||
Node* zsize = phase->transform(new SubXNode(zend, zbase) );
|
||||
Node* adr = phase->transform(new AddPNode(dest, dest, start_offset) );
|
||||
mem = new ClearArrayNode(ctl, mem, zsize, adr);
|
||||
mem = new ClearArrayNode(ctl, mem, zsize, adr, false);
|
||||
return phase->transform(mem);
|
||||
}
|
||||
|
||||
@ -3901,7 +3907,7 @@ Node* InitializeNode::complete_stores(Node* rawctl, Node* rawmem, Node* rawptr,
|
||||
zeroes_done, zeroes_needed,
|
||||
phase);
|
||||
zeroes_done = zeroes_needed;
|
||||
if (zsize > Matcher::init_array_short_size && ++big_init_gaps > 2)
|
||||
if (zsize > InitArrayShortSize && ++big_init_gaps > 2)
|
||||
do_zeroing = false; // leave the hole, next time
|
||||
}
|
||||
}
|
||||
|
||||
@ -1013,9 +1013,11 @@ public:
|
||||
|
||||
//------------------------------ClearArray-------------------------------------
|
||||
class ClearArrayNode: public Node {
|
||||
private:
|
||||
bool _is_large;
|
||||
public:
|
||||
ClearArrayNode( Node *ctrl, Node *arymem, Node *word_cnt, Node *base )
|
||||
: Node(ctrl,arymem,word_cnt,base) {
|
||||
ClearArrayNode( Node *ctrl, Node *arymem, Node *word_cnt, Node *base, bool is_large)
|
||||
: Node(ctrl,arymem,word_cnt,base), _is_large(is_large) {
|
||||
init_class_id(Class_ClearArray);
|
||||
}
|
||||
virtual int Opcode() const;
|
||||
@ -1026,6 +1028,7 @@ public:
|
||||
virtual Node* Identity(PhaseGVN* phase);
|
||||
virtual Node *Ideal(PhaseGVN *phase, bool can_reshape);
|
||||
virtual uint match_edge(uint idx) const;
|
||||
bool is_large() const { return _is_large; }
|
||||
|
||||
// Clear the given area of an object or array.
|
||||
// The start offset must always be aligned mod BytesPerInt.
|
||||
|
||||
@ -35,6 +35,7 @@
|
||||
#include "oops/symbol.hpp"
|
||||
#include "prims/jvm_misc.hpp"
|
||||
#include "prims/nativeLookup.hpp"
|
||||
#include "prims/unsafe.hpp"
|
||||
#include "runtime/arguments.hpp"
|
||||
#include "runtime/handles.inline.hpp"
|
||||
#include "runtime/javaCalls.hpp"
|
||||
@ -107,8 +108,6 @@ char* NativeLookup::long_jni_name(const methodHandle& method) {
|
||||
}
|
||||
|
||||
extern "C" {
|
||||
void JNICALL JVM_RegisterJDKInternalMiscUnsafeMethods(JNIEnv *env, jclass unsafecls);
|
||||
void JNICALL JVM_RegisterSunMiscUnsafeMethods(JNIEnv *env, jclass unsafecls);
|
||||
void JNICALL JVM_RegisterMethodHandleMethods(JNIEnv *env, jclass unsafecls);
|
||||
void JNICALL JVM_RegisterPerfMethods(JNIEnv *env, jclass perfclass);
|
||||
void JNICALL JVM_RegisterWhiteBoxMethods(JNIEnv *env, jclass wbclass);
|
||||
@ -123,7 +122,6 @@ extern "C" {
|
||||
|
||||
static JNINativeMethod lookup_special_native_methods[] = {
|
||||
{ CC"Java_jdk_internal_misc_Unsafe_registerNatives", NULL, FN_PTR(JVM_RegisterJDKInternalMiscUnsafeMethods) },
|
||||
{ CC"Java_sun_misc_Unsafe_registerNatives", NULL, FN_PTR(JVM_RegisterSunMiscUnsafeMethods) },
|
||||
{ CC"Java_java_lang_invoke_MethodHandleNatives_registerNatives", NULL, FN_PTR(JVM_RegisterMethodHandleMethods) },
|
||||
{ CC"Java_jdk_internal_perf_Perf_registerNatives", NULL, FN_PTR(JVM_RegisterPerfMethods) },
|
||||
{ CC"Java_sun_hotspot_WhiteBox_registerNatives", NULL, FN_PTR(JVM_RegisterWhiteBoxMethods) },
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
39
hotspot/src/share/vm/prims/unsafe.hpp
Normal file
39
hotspot/src/share/vm/prims/unsafe.hpp
Normal file
@ -0,0 +1,39 @@
|
||||
/*
|
||||
* Copyright (c) 2016, 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_VM_PRIMS_UNSAFE_HPP
|
||||
#define SHARE_VM_PRIMS_UNSAFE_HPP
|
||||
|
||||
#include "jni.h"
|
||||
|
||||
extern "C" {
|
||||
void JNICALL JVM_RegisterJDKInternalMiscUnsafeMethods(JNIEnv *env, jclass unsafecls);
|
||||
}
|
||||
|
||||
jlong Unsafe_field_offset_to_byte_offset(jlong field_offset);
|
||||
|
||||
jlong Unsafe_field_offset_from_byte_offset(jlong byte_offset);
|
||||
|
||||
#endif // SHARE_VM_PRIMS_UNSAFE_HPP
|
||||
@ -42,17 +42,30 @@ void AdvancedThresholdPolicy::print_specific(EventType type, methodHandle mh, me
|
||||
}
|
||||
|
||||
void AdvancedThresholdPolicy::initialize() {
|
||||
int count = CICompilerCount;
|
||||
#ifdef _LP64
|
||||
// Turn on ergonomic compiler count selection
|
||||
if (FLAG_IS_DEFAULT(CICompilerCountPerCPU) && FLAG_IS_DEFAULT(CICompilerCount)) {
|
||||
FLAG_SET_DEFAULT(CICompilerCountPerCPU, true);
|
||||
}
|
||||
int count = CICompilerCount;
|
||||
if (CICompilerCountPerCPU) {
|
||||
// Simple log n seems to grow too slowly for tiered, try something faster: log n * log log n
|
||||
int log_cpu = log2_intptr(os::active_processor_count());
|
||||
int loglog_cpu = log2_intptr(MAX2(log_cpu, 1));
|
||||
count = MAX2(log_cpu * loglog_cpu, 1) * 3 / 2;
|
||||
}
|
||||
#else
|
||||
// On 32-bit systems, the number of compiler threads is limited to 3.
|
||||
// On these systems, the virtual address space available to the JVM
|
||||
// is usually limited to 2-4 GB (the exact value depends on the platform).
|
||||
// As the compilers (especially C2) can consume a large amount of
|
||||
// memory, scaling the number of compiler threads with the number of
|
||||
// available cores can result in the exhaustion of the address space
|
||||
/// available to the VM and thus cause the VM to crash.
|
||||
if (FLAG_IS_DEFAULT(CICompilerCount)) {
|
||||
count = 3;
|
||||
}
|
||||
#endif
|
||||
|
||||
set_c1_count(MAX2(count / 3, 1));
|
||||
set_c2_count(MAX2(count - c1_count(), 1));
|
||||
|
||||
@ -2472,9 +2472,11 @@ bool Arguments::check_vm_args_consistency() {
|
||||
status = false;
|
||||
}
|
||||
|
||||
#ifdef _LP64
|
||||
if (!FLAG_IS_DEFAULT(CICompilerCount) && !FLAG_IS_DEFAULT(CICompilerCountPerCPU) && CICompilerCountPerCPU) {
|
||||
warning("The VM option CICompilerCountPerCPU overrides CICompilerCount.");
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef SUPPORT_RESERVED_STACK_AREA
|
||||
if (StackReservedPages != 0) {
|
||||
|
||||
@ -354,6 +354,14 @@ Flag::Error TypeProfileLevelConstraintFunc(uintx value, bool verbose) {
|
||||
return Flag::SUCCESS;
|
||||
}
|
||||
|
||||
Flag::Error InitArrayShortSizeConstraintFunc(intx value, bool verbose) {
|
||||
if (value % BytesPerLong != 0) {
|
||||
return Flag::VIOLATES_CONSTRAINT;
|
||||
} else {
|
||||
return Flag::SUCCESS;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef COMPILER2
|
||||
Flag::Error InteriorEntryAlignmentConstraintFunc(intx value, bool verbose) {
|
||||
if (InteriorEntryAlignment > CodeEntryAlignment) {
|
||||
|
||||
@ -62,6 +62,8 @@ Flag::Error ArraycopySrcPrefetchDistanceConstraintFunc(uintx value, bool verbose
|
||||
|
||||
Flag::Error TypeProfileLevelConstraintFunc(uintx value, bool verbose);
|
||||
|
||||
Flag::Error InitArrayShortSizeConstraintFunc(intx value, bool verbose);
|
||||
|
||||
#ifdef COMPILER2
|
||||
Flag::Error InteriorEntryAlignmentConstraintFunc(intx value, bool verbose);
|
||||
|
||||
|
||||
@ -725,7 +725,7 @@ public:
|
||||
\
|
||||
product(bool, UseSHA, false, \
|
||||
"Control whether SHA instructions can be used " \
|
||||
"on SPARC and on ARM") \
|
||||
"on SPARC, on ARM and on x86") \
|
||||
\
|
||||
product(bool, UseGHASHIntrinsics, false, \
|
||||
"Use intrinsics for GHASH versions of crypto") \
|
||||
@ -4162,6 +4162,13 @@ public:
|
||||
"in the loaded class C. " \
|
||||
"Check (3) is available only in debug builds.") \
|
||||
\
|
||||
develop_pd(intx, InitArrayShortSize, \
|
||||
"Threshold small size (in bytes) for clearing arrays. " \
|
||||
"Anything this size or smaller may get converted to discrete " \
|
||||
"scalar stores.") \
|
||||
range(0, max_intx) \
|
||||
constraint(InitArrayShortSizeConstraintFunc, AfterErgo) \
|
||||
\
|
||||
diagnostic(bool, CompilerDirectivesIgnoreCompileCommands, false, \
|
||||
"Disable backwards compatibility for compile commands.") \
|
||||
\
|
||||
|
||||
@ -521,9 +521,9 @@ class RuntimeHistogramElement : public HistogramElement {
|
||||
JNI_ENTRY_NO_PRESERVE(result_type, header) \
|
||||
WeakPreserveExceptionMark __wem(thread);
|
||||
|
||||
#define JNI_ENTRY_NO_PRESERVE(result_type, header) \
|
||||
#define JNI_ENTRY_NO_PRESERVE(result_type, header) \
|
||||
extern "C" { \
|
||||
result_type JNICALL header { \
|
||||
result_type JNICALL header { \
|
||||
JavaThread* thread=JavaThread::thread_from_jni_environment(env); \
|
||||
assert( !VerifyJNIEnvThread || (thread == Thread::current()), "JNIEnv is only valid in same thread"); \
|
||||
ThreadInVMfromNative __tiv(thread); \
|
||||
@ -535,7 +535,7 @@ extern "C" { \
|
||||
// a GC, is called outside the NoHandleMark (set via VM_QUICK_ENTRY_BASE).
|
||||
#define JNI_QUICK_ENTRY(result_type, header) \
|
||||
extern "C" { \
|
||||
result_type JNICALL header { \
|
||||
result_type JNICALL header { \
|
||||
JavaThread* thread=JavaThread::thread_from_jni_environment(env); \
|
||||
assert( !VerifyJNIEnvThread || (thread == Thread::current()), "JNIEnv is only valid in same thread"); \
|
||||
ThreadInVMfromNative __tiv(thread); \
|
||||
@ -545,7 +545,7 @@ extern "C" { \
|
||||
|
||||
#define JNI_LEAF(result_type, header) \
|
||||
extern "C" { \
|
||||
result_type JNICALL header { \
|
||||
result_type JNICALL header { \
|
||||
JavaThread* thread=JavaThread::thread_from_jni_environment(env); \
|
||||
assert( !VerifyJNIEnvThread || (thread == Thread::current()), "JNIEnv is only valid in same thread"); \
|
||||
VM_LEAF_BASE(result_type, header)
|
||||
|
||||
@ -138,9 +138,15 @@ void SimpleThresholdPolicy::initialize() {
|
||||
FLAG_SET_DEFAULT(CICompilerCount, 3);
|
||||
}
|
||||
int count = CICompilerCount;
|
||||
#ifdef _LP64
|
||||
// On 64-bit systems, scale the number of compiler threads with
|
||||
// the number of cores available on the system. Scaling is not
|
||||
// performed on 32-bit systems because it can lead to exhaustion
|
||||
// of the virtual memory address space available to the JVM.
|
||||
if (CICompilerCountPerCPU) {
|
||||
count = MAX2(log2_intptr(os::active_processor_count()), 1) * 3 / 2;
|
||||
}
|
||||
#endif
|
||||
set_c1_count(MAX2(count / 3, 1));
|
||||
set_c2_count(MAX2(count - c1_count(), 1));
|
||||
FLAG_SET_ERGO(intx, CICompilerCount, c1_count() + c2_count());
|
||||
|
||||
@ -29,6 +29,7 @@
|
||||
#include "gc/shared/cardTableModRefBS.hpp"
|
||||
#include "memory/resourceArea.hpp"
|
||||
#include "oops/method.hpp"
|
||||
#include "prims/unsafe.hpp"
|
||||
#include "runtime/os.hpp"
|
||||
#include "runtime/synchronizer.hpp"
|
||||
#include "runtime/thread.hpp"
|
||||
@ -326,7 +327,6 @@ Value* SharkBuilder::fabs() {
|
||||
}
|
||||
|
||||
Value* SharkBuilder::unsafe_field_offset_to_byte_offset() {
|
||||
extern jlong Unsafe_field_offset_to_byte_offset(jlong field_offset);
|
||||
return make_function((address) Unsafe_field_offset_to_byte_offset, "l", "l");
|
||||
}
|
||||
|
||||
|
||||
@ -32,74 +32,99 @@ import jdk.test.lib.TimeLimitedRunner;
|
||||
import jdk.test.lib.Utils;
|
||||
import pool.PoolHelper;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Random;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
public abstract class StressAddJcmdBase {
|
||||
private static final int DIRECTIVES_AMOUNT = Integer.getInteger(
|
||||
"compiler.compilercontrol.jcmd.StressAddJcmdBase.directivesAmount",
|
||||
1000);
|
||||
private static final int DIRECTIVE_FILES = Integer.getInteger(
|
||||
"compiler.compilercontrol.jcmd.StressAddJcmdBase.directiveFiles",
|
||||
5);
|
||||
200);
|
||||
private static final int TIMEOUT = Integer.getInteger(
|
||||
"compiler.compilercontrol.jcmd.StressAddJcmdBase.timeout",
|
||||
30);
|
||||
private static final List<MethodDescriptor> DESCRIPTORS = new PoolHelper()
|
||||
.getAllMethods().stream()
|
||||
.map(pair -> AbstractTestBase
|
||||
.getValidMethodDescriptor(pair.first))
|
||||
.collect(Collectors.toList());
|
||||
private static final String DIRECTIVE_FILE = "directives.json";
|
||||
private static final List<String> VM_OPTIONS = new ArrayList<>();
|
||||
private static final Random RANDOM = Utils.getRandomInstance();
|
||||
|
||||
static {
|
||||
VM_OPTIONS.add("-Xmixed");
|
||||
VM_OPTIONS.add("-XX:+UnlockDiagnosticVMOptions");
|
||||
VM_OPTIONS.add("-XX:+LogCompilation");
|
||||
VM_OPTIONS.add("-XX:CompilerDirectivesLimit=1001");
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs test
|
||||
*/
|
||||
public void test() {
|
||||
List<String> commands = prepareCommands();
|
||||
Executor executor = new TimeLimitedExecutor(commands);
|
||||
HugeDirectiveUtil.createHugeFile(DESCRIPTORS, DIRECTIVE_FILE,
|
||||
DIRECTIVES_AMOUNT);
|
||||
Executor executor = new TimeLimitedExecutor();
|
||||
List<OutputAnalyzer> outputAnalyzers = executor.execute();
|
||||
outputAnalyzers.get(0).shouldHaveExitValue(0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Makes connection to the test VM
|
||||
* Makes connection to the test VM and performs a diagnostic command
|
||||
*
|
||||
* @param pid a pid of the VM under test
|
||||
* @param commands a list of jcmd commands to be executed
|
||||
* @param pid a pid of the VM under test
|
||||
* @return true if the test should continue invocation of this method
|
||||
*/
|
||||
protected abstract boolean makeConnection(int pid, List<String> commands);
|
||||
protected abstract boolean makeConnection(int pid);
|
||||
|
||||
/**
|
||||
* Finish test executions
|
||||
*/
|
||||
protected void finish() { }
|
||||
|
||||
private List<String> prepareCommands() {
|
||||
String[] files = new String[DIRECTIVE_FILES];
|
||||
for (int i = 0; i < DIRECTIVE_FILES; i++) {
|
||||
files[i] = "directives" + i + ".json";
|
||||
HugeDirectiveUtil.createHugeFile(DESCRIPTORS, files[i],
|
||||
DIRECTIVES_AMOUNT);
|
||||
protected String nextCommand() {
|
||||
int i = RANDOM.nextInt(JcmdCommand.values().length);
|
||||
JcmdCommand jcmdCommand = JcmdCommand.values()[i];
|
||||
switch (jcmdCommand) {
|
||||
case ADD:
|
||||
return jcmdCommand.command + " " + DIRECTIVE_FILE;
|
||||
case PRINT:
|
||||
case CLEAR:
|
||||
case REMOVE:
|
||||
return jcmdCommand.command;
|
||||
default:
|
||||
throw new Error("TESTBUG: incorrect command: " + jcmdCommand);
|
||||
}
|
||||
}
|
||||
|
||||
private enum JcmdCommand {
|
||||
ADD("Compiler.directives_add"),
|
||||
PRINT("Compiler.directives_print"),
|
||||
CLEAR("Compiler.directives_clear"),
|
||||
REMOVE("Compiler.directives_remove");
|
||||
|
||||
public final String command;
|
||||
|
||||
JcmdCommand(String command) {
|
||||
this.command = command;
|
||||
}
|
||||
return Stream.of(files)
|
||||
.map(file -> "Compiler.directives_add " + file)
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
private class TimeLimitedExecutor extends Executor {
|
||||
private final List<String> jcmdCommands;
|
||||
|
||||
public TimeLimitedExecutor(List<String> jcmdCommands) {
|
||||
public TimeLimitedExecutor() {
|
||||
/* There are no need to check the state */
|
||||
super(true, null, null, jcmdCommands);
|
||||
this.jcmdCommands = jcmdCommands;
|
||||
super(true, VM_OPTIONS, null, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected OutputAnalyzer[] executeJCMD(int pid) {
|
||||
TimeLimitedRunner runner = new TimeLimitedRunner(
|
||||
Utils.DEFAULT_TEST_TIMEOUT,
|
||||
TimeUnit.SECONDS.toMillis(TIMEOUT),
|
||||
Utils.TIMEOUT_FACTOR,
|
||||
() -> makeConnection(pid, jcmdCommands));
|
||||
() -> makeConnection(pid));
|
||||
try {
|
||||
runner.call();
|
||||
} catch (Exception e) {
|
||||
|
||||
@ -27,21 +27,19 @@
|
||||
* @summary Tests jcmd to be able to add a lot of huge directive files with
|
||||
* parallel executed jcmds until timeout has reached
|
||||
* @library /testlibrary /test/lib /compiler/testlibrary ../share /
|
||||
* @ignore 8148563
|
||||
* @build compiler.compilercontrol.jcmd.StressAddMultiThreadedTest
|
||||
* pool.sub.* pool.subpack.* sun.hotspot.WhiteBox
|
||||
* compiler.testlibrary.CompilerUtils
|
||||
* compiler.compilercontrol.share.actions.*
|
||||
* @run main ClassFileInstaller sun.hotspot.WhiteBox
|
||||
* sun.hotspot.WhiteBox$WhiteBoxPermission
|
||||
* @run main/othervm/timeout=360 compiler.compilercontrol.jcmd.StressAddMultiThreadedTest
|
||||
* @run driver compiler.compilercontrol.jcmd.StressAddMultiThreadedTest
|
||||
*/
|
||||
|
||||
package compiler.compilercontrol.jcmd;
|
||||
|
||||
import jdk.test.lib.dcmd.PidJcmdExecutor;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.concurrent.ArrayBlockingQueue;
|
||||
import java.util.concurrent.BlockingQueue;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
@ -49,16 +47,15 @@ import java.util.concurrent.ThreadPoolExecutor;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
public class StressAddMultiThreadedTest extends StressAddJcmdBase {
|
||||
private static final int THREADS;
|
||||
private static final int THREADS = Integer.getInteger(
|
||||
"compiler.compilercontrol.jcmd.StressAddMultiThreadedTest.threads",
|
||||
5);
|
||||
private volatile int commands = Integer.getInteger(
|
||||
"compiler.compilercontrol.jcmd.StressAddMultiThreadedTest.commands",
|
||||
20);
|
||||
private final BlockingQueue<Runnable> queue;
|
||||
private final ExecutorService executor;
|
||||
|
||||
static {
|
||||
THREADS = Runtime.getRuntime().availableProcessors()
|
||||
* Integer.getInteger("compiler.compilercontrol.jcmd" +
|
||||
".StressAddMultiThreadedTest.threadFactor", 10);
|
||||
}
|
||||
|
||||
public StressAddMultiThreadedTest() {
|
||||
queue = new ArrayBlockingQueue<>(THREADS);
|
||||
executor = new ThreadPoolExecutor(THREADS, THREADS, 100,
|
||||
@ -71,14 +68,10 @@ public class StressAddMultiThreadedTest extends StressAddJcmdBase {
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean makeConnection(int pid, List<String> commands) {
|
||||
commands.forEach(command -> {
|
||||
if (!executor.isShutdown()) {
|
||||
executor.submit(() -> new PidJcmdExecutor(String.valueOf(pid))
|
||||
.execute(command));
|
||||
}
|
||||
});
|
||||
return !executor.isShutdown();
|
||||
protected boolean makeConnection(int pid) {
|
||||
executor.submit(() -> new PidJcmdExecutor(String.valueOf(pid))
|
||||
.execute(nextCommand()));
|
||||
return (--commands != 0);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@ -1,55 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2015, 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 8137167
|
||||
* @summary Tests jcmd to be able to add a lot of huge directives
|
||||
* @library /testlibrary /test/lib /compiler/testlibrary ../share /
|
||||
* @build compiler.compilercontrol.jcmd.StressAddSequentiallyTest
|
||||
* pool.sub.* pool.subpack.* sun.hotspot.WhiteBox
|
||||
* compiler.testlibrary.CompilerUtils
|
||||
* compiler.compilercontrol.share.actions.*
|
||||
* @run main ClassFileInstaller sun.hotspot.WhiteBox
|
||||
* sun.hotspot.WhiteBox$WhiteBoxPermission
|
||||
* @run main/othervm/timeout=300 compiler.compilercontrol.jcmd.StressAddSequentiallyTest
|
||||
*/
|
||||
|
||||
package compiler.compilercontrol.jcmd;
|
||||
|
||||
import jdk.test.lib.dcmd.PidJcmdExecutor;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class StressAddSequentiallyTest extends StressAddJcmdBase {
|
||||
public static void main(String[] args) {
|
||||
new StressAddSequentiallyTest().test();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean makeConnection(int pid, List<String> commands) {
|
||||
commands.forEach(command -> new PidJcmdExecutor(String.valueOf(pid))
|
||||
.execute(command));
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@ -33,8 +33,8 @@
|
||||
* -XX:+WhiteBoxAPI
|
||||
* -XX:DisableIntrinsic=_putCharVolatile,_putInt
|
||||
* -XX:DisableIntrinsic=_putIntVolatile
|
||||
* -XX:CompileCommand=option,sun.misc.Unsafe::putChar,ccstrlist,DisableIntrinsic,_getCharVolatile,_getInt
|
||||
* -XX:CompileCommand=option,sun.misc.Unsafe::putCharVolatile,ccstrlist,DisableIntrinsic,_getIntVolatile
|
||||
* -XX:CompileCommand=option,jdk.internal.misc.Unsafe::putChar,ccstrlist,DisableIntrinsic,_getCharVolatile,_getInt
|
||||
* -XX:CompileCommand=option,jdk.internal.misc.Unsafe::putCharVolatile,ccstrlist,DisableIntrinsic,_getIntVolatile
|
||||
* IntrinsicDisabledTest
|
||||
*/
|
||||
|
||||
@ -60,7 +60,7 @@ public class IntrinsicDisabledTest {
|
||||
return Boolean.valueOf(Objects.toString(wb.getVMFlag("TieredCompilation")));
|
||||
}
|
||||
|
||||
/* This test uses several methods from sun.misc.Unsafe. The method
|
||||
/* This test uses several methods from jdk.internal.misc.Unsafe. The method
|
||||
* getMethod() returns a different Executable for each different
|
||||
* combination of its input parameters. There are eight possible
|
||||
* combinations, getMethod can return an Executable representing
|
||||
@ -74,7 +74,7 @@ public class IntrinsicDisabledTest {
|
||||
String methodTypeName = isChar ? "Char" : "Int";
|
||||
|
||||
try {
|
||||
Class aClass = Class.forName("sun.misc.Unsafe");
|
||||
Class aClass = Class.forName("jdk.internal.misc.Unsafe");
|
||||
if (isPut) {
|
||||
aMethod = aClass.getDeclaredMethod("put" + methodTypeName + (isVolatile ? "Volatile" : ""),
|
||||
Object.class,
|
||||
|
||||
166
hotspot/test/compiler/intrinsics/class/TestClassIsPrimitive.java
Normal file
166
hotspot/test/compiler/intrinsics/class/TestClassIsPrimitive.java
Normal file
@ -0,0 +1,166 @@
|
||||
/*
|
||||
* Copyright (c) 2016, 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 8150669
|
||||
* @summary C1 intrinsic for Class.isPrimitive
|
||||
* @modules java.base/jdk.internal.misc
|
||||
* @run main/othervm -ea -Diters=200 -Xint TestClassIsPrimitive
|
||||
* @run main/othervm -ea -Diters=30000 -XX:TieredStopAtLevel=1 TestClassIsPrimitive
|
||||
* @run main/othervm -ea -Diters=30000 -XX:TieredStopAtLevel=4 TestClassIsPrimitive
|
||||
*/
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Array;
|
||||
import java.util.concurrent.Callable;
|
||||
|
||||
public class TestClassIsPrimitive {
|
||||
static final int ITERS = Integer.getInteger("iters", 1);
|
||||
|
||||
public static void main(String... args) throws Exception {
|
||||
testOK(true, InlineConstants::testBoolean);
|
||||
testOK(true, InlineConstants::testByte);
|
||||
testOK(true, InlineConstants::testShort);
|
||||
testOK(true, InlineConstants::testChar);
|
||||
testOK(true, InlineConstants::testInt);
|
||||
testOK(true, InlineConstants::testFloat);
|
||||
testOK(true, InlineConstants::testLong);
|
||||
testOK(true, InlineConstants::testDouble);
|
||||
testOK(false, InlineConstants::testObject);
|
||||
testOK(false, InlineConstants::testArray);
|
||||
|
||||
testOK(true, StaticConstants::testBoolean);
|
||||
testOK(true, StaticConstants::testByte);
|
||||
testOK(true, StaticConstants::testShort);
|
||||
testOK(true, StaticConstants::testChar);
|
||||
testOK(true, StaticConstants::testInt);
|
||||
testOK(true, StaticConstants::testFloat);
|
||||
testOK(true, StaticConstants::testLong);
|
||||
testOK(true, StaticConstants::testDouble);
|
||||
testOK(false, StaticConstants::testObject);
|
||||
testOK(false, StaticConstants::testArray);
|
||||
testNPE( StaticConstants::testNull);
|
||||
|
||||
testOK(true, NoConstants::testBoolean);
|
||||
testOK(true, NoConstants::testByte);
|
||||
testOK(true, NoConstants::testShort);
|
||||
testOK(true, NoConstants::testChar);
|
||||
testOK(true, NoConstants::testInt);
|
||||
testOK(true, NoConstants::testFloat);
|
||||
testOK(true, NoConstants::testLong);
|
||||
testOK(true, NoConstants::testDouble);
|
||||
testOK(false, NoConstants::testObject);
|
||||
testOK(false, NoConstants::testArray);
|
||||
testNPE( NoConstants::testNull);
|
||||
}
|
||||
|
||||
public static void testOK(boolean expected, Callable<Object> test) throws Exception {
|
||||
for (int c = 0; c < ITERS; c++) {
|
||||
Object res = test.call();
|
||||
if (!res.equals(expected)) {
|
||||
throw new IllegalStateException("Wrong result: expected = " + expected + ", but got " + res);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static volatile Object sink;
|
||||
|
||||
public static void testNPE(Callable<Object> test) throws Exception {
|
||||
for (int c = 0; c < ITERS; c++) {
|
||||
try {
|
||||
sink = test.call();
|
||||
throw new IllegalStateException("Expected NPE");
|
||||
} catch (NullPointerException iae) {
|
||||
// expected
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static volatile Class<?> classBoolean = boolean.class;
|
||||
static volatile Class<?> classByte = byte.class;
|
||||
static volatile Class<?> classShort = short.class;
|
||||
static volatile Class<?> classChar = char.class;
|
||||
static volatile Class<?> classInt = int.class;
|
||||
static volatile Class<?> classFloat = float.class;
|
||||
static volatile Class<?> classLong = long.class;
|
||||
static volatile Class<?> classDouble = double.class;
|
||||
static volatile Class<?> classObject = Object.class;
|
||||
static volatile Class<?> classArray = Object[].class;
|
||||
static volatile Class<?> classNull = null;
|
||||
|
||||
static final Class<?> staticClassBoolean = boolean.class;
|
||||
static final Class<?> staticClassByte = byte.class;
|
||||
static final Class<?> staticClassShort = short.class;
|
||||
static final Class<?> staticClassChar = char.class;
|
||||
static final Class<?> staticClassInt = int.class;
|
||||
static final Class<?> staticClassFloat = float.class;
|
||||
static final Class<?> staticClassLong = long.class;
|
||||
static final Class<?> staticClassDouble = double.class;
|
||||
static final Class<?> staticClassObject = Object.class;
|
||||
static final Class<?> staticClassArray = Object[].class;
|
||||
static final Class<?> staticClassNull = null;
|
||||
|
||||
static class InlineConstants {
|
||||
static boolean testBoolean() { return boolean.class.isPrimitive(); }
|
||||
static boolean testByte() { return byte.class.isPrimitive(); }
|
||||
static boolean testShort() { return short.class.isPrimitive(); }
|
||||
static boolean testChar() { return char.class.isPrimitive(); }
|
||||
static boolean testInt() { return int.class.isPrimitive(); }
|
||||
static boolean testFloat() { return float.class.isPrimitive(); }
|
||||
static boolean testLong() { return long.class.isPrimitive(); }
|
||||
static boolean testDouble() { return double.class.isPrimitive(); }
|
||||
static boolean testObject() { return Object.class.isPrimitive(); }
|
||||
static boolean testArray() { return Object[].class.isPrimitive(); }
|
||||
}
|
||||
|
||||
static class StaticConstants {
|
||||
static boolean testBoolean() { return staticClassBoolean.isPrimitive(); }
|
||||
static boolean testByte() { return staticClassByte.isPrimitive(); }
|
||||
static boolean testShort() { return staticClassShort.isPrimitive(); }
|
||||
static boolean testChar() { return staticClassChar.isPrimitive(); }
|
||||
static boolean testInt() { return staticClassInt.isPrimitive(); }
|
||||
static boolean testFloat() { return staticClassFloat.isPrimitive(); }
|
||||
static boolean testLong() { return staticClassLong.isPrimitive(); }
|
||||
static boolean testDouble() { return staticClassDouble.isPrimitive(); }
|
||||
static boolean testObject() { return staticClassObject.isPrimitive(); }
|
||||
static boolean testArray() { return staticClassArray.isPrimitive(); }
|
||||
static boolean testNull() { return staticClassNull.isPrimitive(); }
|
||||
}
|
||||
|
||||
static class NoConstants {
|
||||
static boolean testBoolean() { return classBoolean.isPrimitive(); }
|
||||
static boolean testByte() { return classByte.isPrimitive(); }
|
||||
static boolean testShort() { return classShort.isPrimitive(); }
|
||||
static boolean testChar() { return classChar.isPrimitive(); }
|
||||
static boolean testInt() { return classInt.isPrimitive(); }
|
||||
static boolean testFloat() { return classFloat.isPrimitive(); }
|
||||
static boolean testLong() { return classLong.isPrimitive(); }
|
||||
static boolean testDouble() { return classDouble.isPrimitive(); }
|
||||
static boolean testObject() { return classObject.isPrimitive(); }
|
||||
static boolean testArray() { return classArray.isPrimitive(); }
|
||||
static boolean testNull() { return classNull.isPrimitive(); }
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -0,0 +1,213 @@
|
||||
/*
|
||||
* Copyright (c) 2016, 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 8150465
|
||||
* @summary Unsafe methods to produce uninitialized arrays
|
||||
* @modules java.base/jdk.internal.misc
|
||||
* @run main/othervm -ea -Diters=200 -Xint AllocateUninitializedArray
|
||||
* @run main/othervm -ea -Diters=30000 -XX:TieredStopAtLevel=1 AllocateUninitializedArray
|
||||
* @run main/othervm -ea -Diters=30000 -XX:TieredStopAtLevel=4 AllocateUninitializedArray
|
||||
*/
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Array;
|
||||
import java.util.concurrent.Callable;
|
||||
|
||||
public class AllocateUninitializedArray {
|
||||
static final int ITERS = Integer.getInteger("iters", 1);
|
||||
static final jdk.internal.misc.Unsafe UNSAFE;
|
||||
|
||||
static {
|
||||
try {
|
||||
Field f = jdk.internal.misc.Unsafe.class.getDeclaredField("theUnsafe");
|
||||
f.setAccessible(true);
|
||||
UNSAFE = (jdk.internal.misc.Unsafe) f.get(null);
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException("Unable to get Unsafe instance.", e);
|
||||
}
|
||||
}
|
||||
|
||||
public static void main(String... args) throws Exception {
|
||||
testIAE(AllConstants::testObject);
|
||||
testIAE(LengthIsConstant::testObject);
|
||||
testIAE(ClassIsConstant::testObject);
|
||||
testIAE(NothingIsConstant::testObject);
|
||||
|
||||
testIAE(AllConstants::testArray);
|
||||
testIAE(LengthIsConstant::testArray);
|
||||
testIAE(ClassIsConstant::testArray);
|
||||
testIAE(NothingIsConstant::testArray);
|
||||
|
||||
testIAE(AllConstants::testNull);
|
||||
testIAE(LengthIsConstant::testNull);
|
||||
testIAE(ClassIsConstant::testNull);
|
||||
testIAE(NothingIsConstant::testNull);
|
||||
|
||||
testOK(boolean[].class, 10, AllConstants::testBoolean);
|
||||
testOK(byte[].class, 10, AllConstants::testByte);
|
||||
testOK(short[].class, 10, AllConstants::testShort);
|
||||
testOK(char[].class, 10, AllConstants::testChar);
|
||||
testOK(int[].class, 10, AllConstants::testInt);
|
||||
testOK(float[].class, 10, AllConstants::testFloat);
|
||||
testOK(long[].class, 10, AllConstants::testLong);
|
||||
testOK(double[].class, 10, AllConstants::testDouble);
|
||||
|
||||
testOK(boolean[].class, 10, LengthIsConstant::testBoolean);
|
||||
testOK(byte[].class, 10, LengthIsConstant::testByte);
|
||||
testOK(short[].class, 10, LengthIsConstant::testShort);
|
||||
testOK(char[].class, 10, LengthIsConstant::testChar);
|
||||
testOK(int[].class, 10, LengthIsConstant::testInt);
|
||||
testOK(float[].class, 10, LengthIsConstant::testFloat);
|
||||
testOK(long[].class, 10, LengthIsConstant::testLong);
|
||||
testOK(double[].class, 10, LengthIsConstant::testDouble);
|
||||
|
||||
testOK(boolean[].class, 10, ClassIsConstant::testBoolean);
|
||||
testOK(byte[].class, 10, ClassIsConstant::testByte);
|
||||
testOK(short[].class, 10, ClassIsConstant::testShort);
|
||||
testOK(char[].class, 10, ClassIsConstant::testChar);
|
||||
testOK(int[].class, 10, ClassIsConstant::testInt);
|
||||
testOK(float[].class, 10, ClassIsConstant::testFloat);
|
||||
testOK(long[].class, 10, ClassIsConstant::testLong);
|
||||
testOK(double[].class, 10, ClassIsConstant::testDouble);
|
||||
|
||||
testOK(boolean[].class, 10, NothingIsConstant::testBoolean);
|
||||
testOK(byte[].class, 10, NothingIsConstant::testByte);
|
||||
testOK(short[].class, 10, NothingIsConstant::testShort);
|
||||
testOK(char[].class, 10, NothingIsConstant::testChar);
|
||||
testOK(int[].class, 10, NothingIsConstant::testInt);
|
||||
testOK(float[].class, 10, NothingIsConstant::testFloat);
|
||||
testOK(long[].class, 10, NothingIsConstant::testLong);
|
||||
testOK(double[].class, 10, NothingIsConstant::testDouble);
|
||||
}
|
||||
|
||||
public static void testOK(Class<?> expectClass, int expectLen, Callable<Object> test) throws Exception {
|
||||
for (int c = 0; c < ITERS; c++) {
|
||||
Object res = test.call();
|
||||
Class<?> actualClass = res.getClass();
|
||||
if (!actualClass.equals(expectClass)) {
|
||||
throw new IllegalStateException("Wrong class: expected = " + expectClass + ", but got " + actualClass);
|
||||
}
|
||||
int actualLen = Array.getLength(res);
|
||||
if (actualLen != expectLen) {
|
||||
throw new IllegalStateException("Wrong length: expected = " + expectLen + ", but got " + actualLen);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static volatile Object sink;
|
||||
|
||||
public static void testIAE(Callable<Object> test) throws Exception {
|
||||
for (int c = 0; c < ITERS; c++) {
|
||||
try {
|
||||
sink = test.call();
|
||||
throw new IllegalStateException("Expected IAE");
|
||||
} catch (IllegalArgumentException iae) {
|
||||
// expected
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static volatile int sampleLenNeg = -1;
|
||||
static volatile int sampleLenZero = 0;
|
||||
static volatile int sampleLen = 10;
|
||||
|
||||
|
||||
static volatile Class<?> classBoolean = boolean.class;
|
||||
static volatile Class<?> classByte = byte.class;
|
||||
static volatile Class<?> classShort = short.class;
|
||||
static volatile Class<?> classChar = char.class;
|
||||
static volatile Class<?> classInt = int.class;
|
||||
static volatile Class<?> classFloat = float.class;
|
||||
static volatile Class<?> classLong = long.class;
|
||||
static volatile Class<?> classDouble = double.class;
|
||||
static volatile Class<?> classObject = Object.class;
|
||||
static volatile Class<?> classArray = Object[].class;
|
||||
static volatile Class<?> classNull = null;
|
||||
|
||||
static class AllConstants {
|
||||
static Object testBoolean() { return UNSAFE.allocateUninitializedArray(boolean.class, 10); }
|
||||
static Object testByte() { return UNSAFE.allocateUninitializedArray(byte.class, 10); }
|
||||
static Object testShort() { return UNSAFE.allocateUninitializedArray(short.class, 10); }
|
||||
static Object testChar() { return UNSAFE.allocateUninitializedArray(char.class, 10); }
|
||||
static Object testInt() { return UNSAFE.allocateUninitializedArray(int.class, 10); }
|
||||
static Object testFloat() { return UNSAFE.allocateUninitializedArray(float.class, 10); }
|
||||
static Object testLong() { return UNSAFE.allocateUninitializedArray(long.class, 10); }
|
||||
static Object testDouble() { return UNSAFE.allocateUninitializedArray(double.class, 10); }
|
||||
static Object testObject() { return UNSAFE.allocateUninitializedArray(Object.class, 10); }
|
||||
static Object testArray() { return UNSAFE.allocateUninitializedArray(Object[].class, 10); }
|
||||
static Object testNull() { return UNSAFE.allocateUninitializedArray(null, 10); }
|
||||
static Object testZero() { return UNSAFE.allocateUninitializedArray(int.class, 0); }
|
||||
static Object testNeg() { return UNSAFE.allocateUninitializedArray(int.class, -1); }
|
||||
}
|
||||
|
||||
static class ClassIsConstant {
|
||||
static Object testBoolean() { return UNSAFE.allocateUninitializedArray(boolean.class, sampleLen); }
|
||||
static Object testByte() { return UNSAFE.allocateUninitializedArray(byte.class, sampleLen); }
|
||||
static Object testShort() { return UNSAFE.allocateUninitializedArray(short.class, sampleLen); }
|
||||
static Object testChar() { return UNSAFE.allocateUninitializedArray(char.class, sampleLen); }
|
||||
static Object testInt() { return UNSAFE.allocateUninitializedArray(int.class, sampleLen); }
|
||||
static Object testFloat() { return UNSAFE.allocateUninitializedArray(float.class, sampleLen); }
|
||||
static Object testLong() { return UNSAFE.allocateUninitializedArray(long.class, sampleLen); }
|
||||
static Object testDouble() { return UNSAFE.allocateUninitializedArray(double.class, sampleLen); }
|
||||
static Object testObject() { return UNSAFE.allocateUninitializedArray(Object.class, sampleLen); }
|
||||
static Object testArray() { return UNSAFE.allocateUninitializedArray(Object[].class, sampleLen); }
|
||||
static Object testNull() { return UNSAFE.allocateUninitializedArray(null, sampleLen); }
|
||||
static Object testZero() { return UNSAFE.allocateUninitializedArray(int.class, sampleLenZero); }
|
||||
static Object testNeg() { return UNSAFE.allocateUninitializedArray(int.class, sampleLenNeg); }
|
||||
}
|
||||
|
||||
static class LengthIsConstant {
|
||||
static Object testBoolean() { return UNSAFE.allocateUninitializedArray(classBoolean, 10); }
|
||||
static Object testByte() { return UNSAFE.allocateUninitializedArray(classByte, 10); }
|
||||
static Object testShort() { return UNSAFE.allocateUninitializedArray(classShort, 10); }
|
||||
static Object testChar() { return UNSAFE.allocateUninitializedArray(classChar, 10); }
|
||||
static Object testInt() { return UNSAFE.allocateUninitializedArray(classInt, 10); }
|
||||
static Object testFloat() { return UNSAFE.allocateUninitializedArray(classFloat, 10); }
|
||||
static Object testLong() { return UNSAFE.allocateUninitializedArray(classLong, 10); }
|
||||
static Object testDouble() { return UNSAFE.allocateUninitializedArray(classDouble, 10); }
|
||||
static Object testObject() { return UNSAFE.allocateUninitializedArray(classObject, 10); }
|
||||
static Object testArray() { return UNSAFE.allocateUninitializedArray(classArray, 10); }
|
||||
static Object testNull() { return UNSAFE.allocateUninitializedArray(classNull, 10); }
|
||||
static Object testZero() { return UNSAFE.allocateUninitializedArray(classInt, 0); }
|
||||
static Object testNeg() { return UNSAFE.allocateUninitializedArray(classInt, -1); }
|
||||
}
|
||||
|
||||
static class NothingIsConstant {
|
||||
static Object testBoolean() { return UNSAFE.allocateUninitializedArray(classBoolean, sampleLen); }
|
||||
static Object testByte() { return UNSAFE.allocateUninitializedArray(classByte, sampleLen); }
|
||||
static Object testShort() { return UNSAFE.allocateUninitializedArray(classShort, sampleLen); }
|
||||
static Object testChar() { return UNSAFE.allocateUninitializedArray(classChar, sampleLen); }
|
||||
static Object testInt() { return UNSAFE.allocateUninitializedArray(classInt, sampleLen); }
|
||||
static Object testFloat() { return UNSAFE.allocateUninitializedArray(classFloat, sampleLen); }
|
||||
static Object testLong() { return UNSAFE.allocateUninitializedArray(classLong, sampleLen); }
|
||||
static Object testDouble() { return UNSAFE.allocateUninitializedArray(classDouble, sampleLen); }
|
||||
static Object testObject() { return UNSAFE.allocateUninitializedArray(classObject, sampleLen); }
|
||||
static Object testArray() { return UNSAFE.allocateUninitializedArray(classArray, sampleLen); }
|
||||
static Object testNull() { return UNSAFE.allocateUninitializedArray(classNull, sampleLen); }
|
||||
static Object testZero() { return UNSAFE.allocateUninitializedArray(classInt, sampleLenZero); }
|
||||
static Object testNeg() { return UNSAFE.allocateUninitializedArray(classInt, sampleLenNeg); }
|
||||
}
|
||||
}
|
||||
|
||||
@ -27,6 +27,7 @@
|
||||
* @test
|
||||
* @summary tests on constant folding of unsafe get operations from stable arrays
|
||||
* @library /testlibrary /test/lib
|
||||
* @ignore 8151137
|
||||
*
|
||||
* @requires vm.flavor != "client"
|
||||
*
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user