--- a/make/autoconf/basics.m4 Mon Sep 30 21:16:42 2019 +0200
+++ b/make/autoconf/basics.m4 Tue Oct 01 18:47:30 2019 +0200
@@ -213,8 +213,10 @@
if test "x[$]$1" != x; then
new_path="[$]$1"
- if [ [[ "$new_path" = ~* ]] ]; then
- # Use eval to expand a potential ~
+ # Use eval to expand a potential ~. This technique does not work if there
+ # are spaces in the path (which is valid at this point on Windows), so only
+ # try to apply it if there is an actual ~ first in the path.
+ if [ [[ "$new_path" = "~"* ]] ]; then
eval new_path="$new_path"
if test ! -f "$new_path" && test ! -d "$new_path"; then
AC_MSG_ERROR([The new_path of $1, which resolves as "$new_path", is not found.])
--- a/src/hotspot/cpu/x86/assembler_x86.cpp Mon Sep 30 21:16:42 2019 +0200
+++ b/src/hotspot/cpu/x86/assembler_x86.cpp Tue Oct 01 18:47:30 2019 +0200
@@ -4742,6 +4742,25 @@
emit_int8((unsigned char)0xA5);
}
+void Assembler::roundsd(XMMRegister dst, XMMRegister src, int32_t rmode) {
+ assert(VM_Version::supports_sse4_1(), "");
+ InstructionAttr attributes(AVX_128bit, /* rex_w */ false, /* legacy_mode */ true, /* no_mask_reg */ true, /* uses_vl */ false);
+ int encode = simd_prefix_and_encode(dst, dst, src, VEX_SIMD_66, VEX_OPCODE_0F_3A, &attributes);
+ emit_int8(0x0B);
+ emit_int8((unsigned char)(0xC0 | encode));
+ emit_int8((unsigned char)rmode);
+}
+
+void Assembler::roundsd(XMMRegister dst, Address src, int32_t rmode) {
+ assert(VM_Version::supports_sse4_1(), "");
+ InstructionMark im(this);
+ InstructionAttr attributes(AVX_128bit, /* rex_w */ false, /* legacy_mode */ true, /* no_mask_reg */ true, /* uses_vl */ false);
+ simd_prefix(dst, dst, src, VEX_SIMD_66, VEX_OPCODE_0F_3A, &attributes);
+ emit_int8(0x0B);
+ emit_operand(dst, src);
+ emit_int8((unsigned char)rmode);
+}
+
void Assembler::sqrtsd(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 */ true, /* uses_vl */ false);
@@ -5539,6 +5558,49 @@
emit_operand(dst, src);
}
+void Assembler::vroundpd(XMMRegister dst, XMMRegister src, int32_t rmode, int vector_len) {
+ assert(VM_Version::supports_avx(), "");
+ InstructionAttr attributes(vector_len, /* vex_w */ false, /* legacy_mode */ true, /* no_mask_reg */ true, /* uses_vl */ false);
+ int encode = vex_prefix_and_encode(dst->encoding(), 0, src->encoding(), VEX_SIMD_66, VEX_OPCODE_0F_3A, &attributes);
+ emit_int8(0x09);
+ emit_int8((unsigned char)(0xC0 | encode));
+ emit_int8((unsigned char)(rmode));
+}
+
+void Assembler::vroundpd(XMMRegister dst, Address src, int32_t rmode, int vector_len) {
+ assert(VM_Version::supports_avx(), "");
+ InstructionMark im(this);
+ InstructionAttr attributes(vector_len, /* vex_w */ false, /* legacy_mode */ true, /* no_mask_reg */ true, /* uses_vl */ false);
+ vex_prefix(src, 0, dst->encoding(), VEX_SIMD_66, VEX_OPCODE_0F_3A, &attributes);
+ emit_int8(0x09);
+ emit_operand(dst, src);
+ emit_int8((unsigned char)(rmode));
+}
+
+void Assembler::vrndscalepd(XMMRegister dst, XMMRegister src, int32_t rmode, int vector_len) {
+ assert(VM_Version::supports_evex(), "requires EVEX support");
+ InstructionAttr attributes(vector_len, /* vex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ true);
+ attributes.set_is_evex_instruction();
+ int encode = vex_prefix_and_encode(dst->encoding(), 0, src->encoding(), VEX_SIMD_66, VEX_OPCODE_0F_3A, &attributes);
+ emit_int8((unsigned char)0x09);
+ emit_int8((unsigned char)(0xC0 | encode));
+ emit_int8((unsigned char)(rmode));
+}
+
+void Assembler::vrndscalepd(XMMRegister dst, Address src, int32_t rmode, int vector_len) {
+ assert(VM_Version::supports_evex(), "requires EVEX support");
+ assert(dst != xnoreg, "sanity");
+ InstructionMark im(this);
+ InstructionAttr attributes(vector_len, /* vex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ true);
+ attributes.set_is_evex_instruction();
+ attributes.set_address_attributes(/* tuple_type */ EVEX_FV, /* input_size_in_bits */ EVEX_64bit);
+ vex_prefix(src, 0, dst->encoding(), VEX_SIMD_66, VEX_OPCODE_0F_3A, &attributes);
+ emit_int8((unsigned char)0x09);
+ emit_operand(dst, src);
+ emit_int8((unsigned char)(rmode));
+}
+
+
void Assembler::vsqrtpd(XMMRegister dst, XMMRegister src, int vector_len) {
assert(VM_Version::supports_avx(), "");
InstructionAttr attributes(vector_len, /* vex_w */ VM_Version::supports_evex(), /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ true);
--- a/src/hotspot/cpu/x86/assembler_x86.hpp Mon Sep 30 21:16:42 2019 +0200
+++ b/src/hotspot/cpu/x86/assembler_x86.hpp Tue Oct 01 18:47:30 2019 +0200
@@ -1856,6 +1856,9 @@
void sqrtsd(XMMRegister dst, Address src);
void sqrtsd(XMMRegister dst, XMMRegister src);
+ void roundsd(XMMRegister dst, Address src, int32_t rmode);
+ void roundsd(XMMRegister dst, XMMRegister src, int32_t rmode);
+
// Compute Square Root of Scalar Single-Precision Floating-Point Value
void sqrtss(XMMRegister dst, Address src);
void sqrtss(XMMRegister dst, XMMRegister src);
@@ -2020,6 +2023,12 @@
void vsqrtps(XMMRegister dst, XMMRegister src, int vector_len);
void vsqrtps(XMMRegister dst, Address src, int vector_len);
+ // Round Packed Double precision value.
+ void vroundpd(XMMRegister dst, XMMRegister src, int32_t rmode, int vector_len);
+ void vroundpd(XMMRegister dst, Address src, int32_t rmode, int vector_len);
+ void vrndscalepd(XMMRegister dst, XMMRegister src, int32_t rmode, int vector_len);
+ void vrndscalepd(XMMRegister dst, Address src, int32_t rmode, int vector_len);
+
// Bitwise Logical AND of Packed Floating-Point Values
void andpd(XMMRegister dst, XMMRegister src);
void andps(XMMRegister dst, XMMRegister src);
--- a/src/hotspot/cpu/x86/macroAssembler_x86.cpp Mon Sep 30 21:16:42 2019 +0200
+++ b/src/hotspot/cpu/x86/macroAssembler_x86.cpp Tue Oct 01 18:47:30 2019 +0200
@@ -3661,6 +3661,15 @@
}
}
+void MacroAssembler::roundsd(XMMRegister dst, AddressLiteral src, int32_t rmode, Register scratch_reg) {
+ if (reachable(src)) {
+ Assembler::roundsd(dst, as_Address(src), rmode);
+ } else {
+ lea(scratch_reg, src);
+ Assembler::roundsd(dst, Address(scratch_reg, 0), rmode);
+ }
+}
+
void MacroAssembler::subss(XMMRegister dst, AddressLiteral src) {
if (reachable(src)) {
Assembler::subss(dst, as_Address(src));
--- a/src/hotspot/cpu/x86/macroAssembler_x86.hpp Mon Sep 30 21:16:42 2019 +0200
+++ b/src/hotspot/cpu/x86/macroAssembler_x86.hpp Tue Oct 01 18:47:30 2019 +0200
@@ -1180,6 +1180,10 @@
void sqrtsd(XMMRegister dst, Address src) { Assembler::sqrtsd(dst, src); }
void sqrtsd(XMMRegister dst, AddressLiteral src);
+ void roundsd(XMMRegister dst, XMMRegister src, int32_t rmode) { Assembler::roundsd(dst, src, rmode); }
+ void roundsd(XMMRegister dst, Address src, int32_t rmode) { Assembler::roundsd(dst, src, rmode); }
+ void roundsd(XMMRegister dst, AddressLiteral src, int32_t rmode, Register scratch_reg);
+
void sqrtss(XMMRegister dst, XMMRegister src) { Assembler::sqrtss(dst, src); }
void sqrtss(XMMRegister dst, Address src) { Assembler::sqrtss(dst, src); }
void sqrtss(XMMRegister dst, AddressLiteral src);
--- a/src/hotspot/cpu/x86/x86.ad Mon Sep 30 21:16:42 2019 +0200
+++ b/src/hotspot/cpu/x86/x86.ad Tue Oct 01 18:47:30 2019 +0200
@@ -1485,6 +1485,10 @@
ret_value = false;
}
break;
+ case Op_RoundDoubleMode:
+ if (UseSSE < 4)
+ ret_value = false;
+ break;
}
return ret_value; // Per default match rules are supported.
@@ -1536,6 +1540,10 @@
if (vlen != 4)
ret_value = false;
break;
+ case Op_RoundDoubleModeV:
+ if (VM_Version::supports_avx() == false)
+ ret_value = false;
+ break;
}
}
@@ -2854,6 +2862,108 @@
ins_pipe(pipe_slow);
%}
+
+instruct roundD_reg(legRegD dst, legRegD src, immU8 rmode) %{
+ predicate(UseSSE>=4);
+ match(Set dst (RoundDoubleMode src rmode));
+ format %{ "roundsd $dst, $src" %}
+ ins_cost(150);
+ ins_encode %{
+ __ roundsd($dst$$XMMRegister, $src$$XMMRegister, $rmode$$constant);
+ %}
+ ins_pipe(pipe_slow);
+%}
+
+instruct roundD_mem(legRegD dst, memory src, immU8 rmode) %{
+ predicate(UseSSE>=4);
+ match(Set dst (RoundDoubleMode (LoadD src) rmode));
+ format %{ "roundsd $dst, $src" %}
+ ins_cost(150);
+ ins_encode %{
+ __ roundsd($dst$$XMMRegister, $src$$Address, $rmode$$constant);
+ %}
+ ins_pipe(pipe_slow);
+%}
+
+instruct roundD_imm(legRegD dst, immD con, immU8 rmode, rRegI scratch_reg) %{
+ predicate(UseSSE>=4);
+ match(Set dst (RoundDoubleMode con rmode));
+ effect(TEMP scratch_reg);
+ format %{ "roundsd $dst, [$constantaddress]\t# load from constant table: double=$con" %}
+ ins_cost(150);
+ ins_encode %{
+ __ roundsd($dst$$XMMRegister, $constantaddress($con), $rmode$$constant, $scratch_reg$$Register);
+ %}
+ ins_pipe(pipe_slow);
+%}
+
+instruct vround2D_reg(legVecX dst, legVecX src, immU8 rmode) %{
+ predicate(UseAVX > 0 && n->as_Vector()->length() == 2);
+ match(Set dst (RoundDoubleModeV src rmode));
+ format %{ "vroundpd $dst, $src, $rmode\t! round packed2D" %}
+ ins_encode %{
+ int vector_len = 0;
+ __ vroundpd($dst$$XMMRegister, $src$$XMMRegister, $rmode$$constant, vector_len);
+ %}
+ ins_pipe( pipe_slow );
+%}
+
+instruct vround2D_mem(legVecX dst, memory mem, immU8 rmode) %{
+ predicate(UseAVX > 0 && n->as_Vector()->length() == 2);
+ match(Set dst (RoundDoubleModeV (LoadVector mem) rmode));
+ format %{ "vroundpd $dst, $mem, $rmode\t! round packed2D" %}
+ ins_encode %{
+ int vector_len = 0;
+ __ vroundpd($dst$$XMMRegister, $mem$$Address, $rmode$$constant, vector_len);
+ %}
+ ins_pipe( pipe_slow );
+%}
+
+instruct vround4D_reg(legVecY dst, legVecY src, legVecY rmode) %{
+ predicate(UseAVX > 0 && n->as_Vector()->length() == 4);
+ match(Set dst (RoundDoubleModeV src rmode));
+ format %{ "vroundpd $dst, $src, $rmode\t! round packed4D" %}
+ ins_encode %{
+ int vector_len = 1;
+ __ vroundpd($dst$$XMMRegister, $src$$XMMRegister, $rmode$$constant, vector_len);
+ %}
+ ins_pipe( pipe_slow );
+%}
+
+instruct vround4D_mem(legVecY dst, memory mem, immU8 rmode) %{
+ predicate(UseAVX > 0 && n->as_Vector()->length() == 4);
+ match(Set dst (RoundDoubleModeV (LoadVector mem) rmode));
+ format %{ "vroundpd $dst, $mem, $rmode\t! round packed4D" %}
+ ins_encode %{
+ int vector_len = 1;
+ __ vroundpd($dst$$XMMRegister, $mem$$Address, $rmode$$constant, vector_len);
+ %}
+ ins_pipe( pipe_slow );
+%}
+
+
+instruct vround8D_reg(vecZ dst, vecZ src, immU8 rmode) %{
+ predicate(UseAVX > 2 && n->as_Vector()->length() == 8);
+ match(Set dst (RoundDoubleModeV src rmode));
+ format %{ "vrndscalepd $dst, $src, $rmode\t! round packed8D" %}
+ ins_encode %{
+ int vector_len = 2;
+ __ vrndscalepd($dst$$XMMRegister, $src$$XMMRegister, $rmode$$constant, vector_len);
+ %}
+ ins_pipe( pipe_slow );
+%}
+
+instruct vround8D_mem(vecZ dst, memory mem, immU8 rmode) %{
+ predicate(UseAVX > 2 && n->as_Vector()->length() == 8);
+ match(Set dst (RoundDoubleModeV (LoadVector mem) rmode));
+ format %{ "vrndscalepd $dst, $mem, $rmode\t! round packed8D" %}
+ ins_encode %{
+ int vector_len = 2;
+ __ vrndscalepd($dst$$XMMRegister, $mem$$Address, $rmode$$constant, vector_len);
+ %}
+ ins_pipe( pipe_slow );
+%}
+
instruct onspinwait() %{
match(OnSpinWait);
ins_cost(200);
--- a/src/hotspot/os/windows/os_windows.cpp Mon Sep 30 21:16:42 2019 +0200
+++ b/src/hotspot/os/windows/os_windows.cpp Tue Oct 01 18:47:30 2019 +0200
@@ -4159,128 +4159,137 @@
}
}
-// The following function is adapted from java.base/windows/native/libjava/canonicalize_md.c
-// Creates an UNC path from a single byte path. Return buffer is
-// allocated in C heap and needs to be freed by the caller.
-// Returns NULL on error.
-static wchar_t* create_unc_path(const char* path, errno_t &err) {
- wchar_t* wpath = NULL;
- size_t converted_chars = 0;
- size_t path_len = strlen(path) + 1; // includes the terminating NULL
- if (path[0] == '\\' && path[1] == '\\') {
- if (path[2] == '?' && path[3] == '\\'){
- // if it already has a \\?\ don't do the prefix
- wpath = (wchar_t*)os::malloc(path_len * sizeof(wchar_t), mtInternal);
- if (wpath != NULL) {
- err = ::mbstowcs_s(&converted_chars, wpath, path_len, path, path_len);
+// Returns the given path as an absolute wide path in unc format. The returned path is NULL
+// on error (with err being set accordingly) and should be freed via os::free() otherwise.
+// additional_space is the number of additionally allocated wchars after the terminating L'\0'.
+// This is based on pathToNTPath() in io_util_md.cpp, but omits the optimizations for
+// short paths.
+static wchar_t* wide_abs_unc_path(char const* path, errno_t & err, int additional_space = 0) {
+ if ((path == NULL) || (path[0] == '\0')) {
+ err = ENOENT;
+ return NULL;
+ }
+
+ size_t path_len = strlen(path);
+ // Need to allocate at least room for 3 characters, since os::native_path transforms C: to C:.
+ char* buf = (char*) os::malloc(1 + MAX2((size_t) 3, path_len), mtInternal);
+ wchar_t* result = NULL;
+
+ if (buf == NULL) {
+ err = ENOMEM;
+ } else {
+ memcpy(buf, path, path_len + 1);
+ os::native_path(buf);
+
+ wchar_t* prefix;
+ int prefix_off = 0;
+ bool is_abs = true;
+ bool needs_fullpath = true;
+
+ if (::isalpha(buf[0]) && !::IsDBCSLeadByte(buf[0]) && buf[1] == ':' && buf[2] == '\\') {
+ prefix = L"\\\\?\\";
+ } else if (buf[0] == '\\' && buf[1] == '\\') {
+ assert(buf[2] != '\\');
+
+ if (buf[2] == '?' && buf[3] == '\\') {
+ prefix = L"";
+ needs_fullpath = false;
} else {
- err = ENOMEM;
+ prefix = L"\\\\?\\UNC";
+ prefix_off = 1; // Overwrite the first char with the prefix, so \\share\path becomes \\?\UNC\share\path
}
} else {
- // only UNC pathname includes double slashes here
- wpath = (wchar_t*)os::malloc((path_len + 7) * sizeof(wchar_t), mtInternal);
- if (wpath != NULL) {
- ::wcscpy(wpath, L"\\\\?\\UNC\0");
- err = ::mbstowcs_s(&converted_chars, &wpath[7], path_len, path, path_len);
- } else {
- err = ENOMEM;
+ is_abs = false;
+ prefix = L"\\\\?\\";
+ }
+
+ size_t buf_len = strlen(buf);
+ size_t prefix_len = wcslen(prefix);
+ size_t full_path_size = is_abs ? 1 + buf_len : JVM_MAXPATHLEN;
+ size_t result_size = prefix_len + full_path_size - prefix_off;
+ result = (wchar_t*) os::malloc(sizeof(wchar_t) * (additional_space + result_size), mtInternal);
+
+ if (result == NULL) {
+ err = ENOMEM;
+ } else {
+ size_t converted_chars;
+ wchar_t* path_start = result + prefix_len - prefix_off;
+ err = ::mbstowcs_s(&converted_chars, path_start, buf_len + 1, buf, buf_len);
+
+ if ((err == ERROR_SUCCESS) && needs_fullpath) {
+ wchar_t* tmp = (wchar_t*) os::malloc(sizeof(wchar_t) * full_path_size, mtInternal);
+
+ if (tmp == NULL) {
+ err = ENOMEM;
+ } else {
+ if (!_wfullpath(tmp, path_start, full_path_size)) {
+ err = ENOENT;
+ } else {
+ ::memcpy(path_start, tmp, (1 + wcslen(tmp)) * sizeof(wchar_t));
+ }
+
+ os::free(tmp);
+ }
+ }
+
+ memcpy(result, prefix, sizeof(wchar_t) * prefix_len);
+
+ // Remove trailing pathsep (not for \\?\<DRIVE>:\, since it would make it relative)
+ size_t result_len = wcslen(result);
+
+ if (result[result_len - 1] == L'\\') {
+ if (!(::iswalpha(result[4]) && result[5] == L':' && result_len == 7)) {
+ result[result_len - 1] = L'\0';
+ }
}
}
- } else {
- wpath = (wchar_t*)os::malloc((path_len + 4) * sizeof(wchar_t), mtInternal);
- if (wpath != NULL) {
- ::wcscpy(wpath, L"\\\\?\\\0");
- err = ::mbstowcs_s(&converted_chars, &wpath[4], path_len, path, path_len);
- } else {
- err = ENOMEM;
- }
- }
- return wpath;
-}
-
-static void destroy_unc_path(wchar_t* wpath) {
- os::free(wpath);
+ }
+
+ os::free(buf);
+
+ if (err != ERROR_SUCCESS) {
+ os::free(result);
+ result = NULL;
+ }
+
+ return result;
}
int os::stat(const char *path, struct stat *sbuf) {
- char* pathbuf = (char*)os::strdup(path, mtInternal);
- if (pathbuf == NULL) {
- errno = ENOMEM;
+ errno_t err;
+ wchar_t* wide_path = wide_abs_unc_path(path, err);
+
+ if (wide_path == NULL) {
+ errno = err;
return -1;
}
- os::native_path(pathbuf);
- int ret;
- WIN32_FILE_ATTRIBUTE_DATA file_data;
- // Not using stat() to avoid the problem described in JDK-6539723
- if (strlen(path) < MAX_PATH) {
- BOOL bret = ::GetFileAttributesExA(pathbuf, GetFileExInfoStandard, &file_data);
- if (!bret) {
- errno = ::GetLastError();
- ret = -1;
- }
- else {
- file_attribute_data_to_stat(sbuf, file_data);
- ret = 0;
- }
- } else {
- errno_t err = ERROR_SUCCESS;
- wchar_t* wpath = create_unc_path(pathbuf, err);
- if (err != ERROR_SUCCESS) {
- if (wpath != NULL) {
- destroy_unc_path(wpath);
- }
- os::free(pathbuf);
- errno = err;
- return -1;
- }
- BOOL bret = ::GetFileAttributesExW(wpath, GetFileExInfoStandard, &file_data);
- if (!bret) {
- errno = ::GetLastError();
- ret = -1;
- } else {
- file_attribute_data_to_stat(sbuf, file_data);
- ret = 0;
- }
- destroy_unc_path(wpath);
- }
- os::free(pathbuf);
- return ret;
+
+ WIN32_FILE_ATTRIBUTE_DATA file_data;;
+ BOOL bret = ::GetFileAttributesExW(wide_path, GetFileExInfoStandard, &file_data);
+ os::free(wide_path);
+
+ if (!bret) {
+ errno = ::GetLastError();
+ return -1;
+ }
+
+ file_attribute_data_to_stat(sbuf, file_data);
+ return 0;
}
static HANDLE create_read_only_file_handle(const char* file) {
- if (file == NULL) {
- return INVALID_HANDLE_VALUE;
- }
-
- char* nativepath = (char*)os::strdup(file, mtInternal);
- if (nativepath == NULL) {
- errno = ENOMEM;
+ errno_t err;
+ wchar_t* wide_path = wide_abs_unc_path(file, err);
+
+ if (wide_path == NULL) {
+ errno = err;
return INVALID_HANDLE_VALUE;
}
- os::native_path(nativepath);
-
- size_t len = strlen(nativepath);
- HANDLE handle = INVALID_HANDLE_VALUE;
-
- if (len < MAX_PATH) {
- handle = ::CreateFile(nativepath, 0, FILE_SHARE_READ,
- NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
- } else {
- errno_t err = ERROR_SUCCESS;
- wchar_t* wfile = create_unc_path(nativepath, err);
- if (err != ERROR_SUCCESS) {
- if (wfile != NULL) {
- destroy_unc_path(wfile);
- }
- os::free(nativepath);
- return INVALID_HANDLE_VALUE;
- }
- handle = ::CreateFileW(wfile, 0, FILE_SHARE_READ,
- NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
- destroy_unc_path(wfile);
- }
-
- os::free(nativepath);
+
+ HANDLE handle = ::CreateFileW(wide_path, 0, FILE_SHARE_READ,
+ NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
+ os::free(wide_path);
+
return handle;
}
@@ -4329,7 +4338,6 @@
return result;
}
-
#define FT2INT64(ft) \
((jlong)((jlong)(ft).dwHighDateTime << 32 | (julong)(ft).dwLowDateTime))
@@ -4434,38 +4442,22 @@
return DontYieldALot;
}
-// This method is a slightly reworked copy of JDK's sysOpen
-// from src/windows/hpi/src/sys_api_md.c
-
int os::open(const char *path, int oflag, int mode) {
- char* pathbuf = (char*)os::strdup(path, mtInternal);
- if (pathbuf == NULL) {
- errno = ENOMEM;
+ errno_t err;
+ wchar_t* wide_path = wide_abs_unc_path(path, err);
+
+ if (wide_path == NULL) {
+ errno = err;
return -1;
}
- os::native_path(pathbuf);
- int ret;
- if (strlen(path) < MAX_PATH) {
- ret = ::open(pathbuf, oflag | O_BINARY | O_NOINHERIT, mode);
- } else {
- errno_t err = ERROR_SUCCESS;
- wchar_t* wpath = create_unc_path(pathbuf, err);
- if (err != ERROR_SUCCESS) {
- if (wpath != NULL) {
- destroy_unc_path(wpath);
- }
- os::free(pathbuf);
- errno = err;
- return -1;
- }
- ret = ::_wopen(wpath, oflag | O_BINARY | O_NOINHERIT, mode);
- if (ret == -1) {
- errno = ::GetLastError();
- }
- destroy_unc_path(wpath);
- }
- os::free(pathbuf);
- return ret;
+ int fd = ::_wopen(wide_path, oflag | O_BINARY | O_NOINHERIT, mode);
+ os::free(wide_path);
+
+ if (fd == -1) {
+ errno = ::GetLastError();
+ }
+
+ return fd;
}
FILE* os::open(int fd, const char* mode) {
@@ -4474,37 +4466,26 @@
// Is a (classpath) directory empty?
bool os::dir_is_empty(const char* path) {
- char* search_path = (char*)os::malloc(strlen(path) + 3, mtInternal);
- if (search_path == NULL) {
- errno = ENOMEM;
- return false;
- }
- strcpy(search_path, path);
- os::native_path(search_path);
- // Append "*", or possibly "\\*", to path
- if (search_path[1] == ':' &&
- (search_path[2] == '\0' ||
- (search_path[2] == '\\' && search_path[3] == '\0'))) {
- // No '\\' needed for cases like "Z:" or "Z:\"
- strcat(search_path, "*");
- }
- else {
- strcat(search_path, "\\*");
- }
- errno_t err = ERROR_SUCCESS;
- wchar_t* wpath = create_unc_path(search_path, err);
- if (err != ERROR_SUCCESS) {
- if (wpath != NULL) {
- destroy_unc_path(wpath);
- }
- os::free(search_path);
+ errno_t err;
+ wchar_t* wide_path = wide_abs_unc_path(path, err, 2);
+
+ if (wide_path == NULL) {
errno = err;
return false;
}
+
+ // Make sure we end with "\\*"
+ if (wide_path[wcslen(wide_path) - 1] == L'\\') {
+ wcscat(wide_path, L"*");
+ } else {
+ wcscat(wide_path, L"\\*");
+ }
+
WIN32_FIND_DATAW fd;
- HANDLE f = ::FindFirstFileW(wpath, &fd);
- destroy_unc_path(wpath);
+ HANDLE f = ::FindFirstFileW(wide_path, &fd);
+ os::free(wide_path);
bool is_empty = true;
+
if (f != INVALID_HANDLE_VALUE) {
while (is_empty && ::FindNextFileW(f, &fd)) {
// An empty directory contains only the current directory file
@@ -4515,8 +4496,10 @@
}
}
FindClose(f);
- }
- os::free(search_path);
+ } else {
+ errno = ::GetLastError();
+ }
+
return is_empty;
}
--- a/src/hotspot/share/adlc/formssel.cpp Mon Sep 30 21:16:42 2019 +0200
+++ b/src/hotspot/share/adlc/formssel.cpp Tue Oct 01 18:47:30 2019 +0200
@@ -4047,6 +4047,7 @@
strcmp(opType,"FmaD") == 0 ||
strcmp(opType,"FmaF") == 0 ||
strcmp(opType,"RoundDouble")==0 ||
+ strcmp(opType,"RoundDoubleMode")==0 ||
strcmp(opType,"RoundFloat")==0 ||
strcmp(opType,"ReverseBytesI")==0 ||
strcmp(opType,"ReverseBytesL")==0 ||
@@ -4175,7 +4176,7 @@
"URShiftVB","URShiftVS","URShiftVI","URShiftVL",
"MaxReductionV", "MinReductionV",
"ReplicateB","ReplicateS","ReplicateI","ReplicateL","ReplicateF","ReplicateD",
- "LoadVector","StoreVector",
+ "RoundDoubleModeV","LoadVector","StoreVector",
"FmaVD", "FmaVF","PopCountVI",
// Next are not supported currently.
"PackB","PackS","PackI","PackL","PackF","PackD","Pack2L","Pack2D",
--- a/src/hotspot/share/classfile/vmSymbols.cpp Mon Sep 30 21:16:42 2019 +0200
+++ b/src/hotspot/share/classfile/vmSymbols.cpp Tue Oct 01 18:47:30 2019 +0200
@@ -575,6 +575,9 @@
case vmIntrinsics::_intBitsToFloat:
case vmIntrinsics::_doubleToRawLongBits:
case vmIntrinsics::_longBitsToDouble:
+ case vmIntrinsics::_ceil:
+ case vmIntrinsics::_floor:
+ case vmIntrinsics::_rint:
case vmIntrinsics::_dabs:
case vmIntrinsics::_fabs:
case vmIntrinsics::_iabs:
--- a/src/hotspot/share/classfile/vmSymbols.hpp Mon Sep 30 21:16:42 2019 +0200
+++ b/src/hotspot/share/classfile/vmSymbols.hpp Tue Oct 01 18:47:30 2019 +0200
@@ -766,6 +766,7 @@
do_name(tan_name,"tan") do_name(atan2_name,"atan2") do_name(sqrt_name,"sqrt") \
do_name(log_name,"log") do_name(log10_name,"log10") do_name(pow_name,"pow") \
do_name(exp_name,"exp") do_name(min_name,"min") do_name(max_name,"max") \
+ do_name(floor_name, "floor") do_name(ceil_name, "ceil") do_name(rint_name, "rint") \
\
do_name(addExact_name,"addExact") \
do_name(decrementExact_name,"decrementExact") \
@@ -781,6 +782,9 @@
do_intrinsic(_iabs, java_lang_Math, abs_name, int_int_signature, F_S) \
do_intrinsic(_labs, java_lang_Math, abs_name, long_long_signature, F_S) \
do_intrinsic(_dsin, java_lang_Math, sin_name, double_double_signature, F_S) \
+ do_intrinsic(_floor, java_lang_Math, floor_name, double_double_signature, F_S) \
+ do_intrinsic(_ceil, java_lang_Math, ceil_name, double_double_signature, F_S) \
+ do_intrinsic(_rint, java_lang_Math, rint_name, double_double_signature, F_S) \
do_intrinsic(_dcos, java_lang_Math, cos_name, double_double_signature, F_S) \
do_intrinsic(_dtan, java_lang_Math, tan_name, double_double_signature, F_S) \
do_intrinsic(_datan2, java_lang_Math, atan2_name, double2_double_signature, F_S) \
--- a/src/hotspot/share/gc/shenandoah/shenandoahMarkCompact.cpp Mon Sep 30 21:16:42 2019 +0200
+++ b/src/hotspot/share/gc/shenandoah/shenandoahMarkCompact.cpp Tue Oct 01 18:47:30 2019 +0200
@@ -327,14 +327,25 @@
ShenandoahHeapRegion* next_from_region(ShenandoahHeapRegionSet* slice) {
ShenandoahHeapRegion* from_region = _heap_regions.next();
- while (from_region != NULL && (!from_region->is_move_allowed() || from_region->is_humongous())) {
+ // Look for next candidate for this slice:
+ while (from_region != NULL) {
+ // Empty region: get it into the slice to defragment the slice itself.
+ // We could have skipped this without violating correctness, but we really
+ // want to compact all live regions to the start of the heap, which sometimes
+ // means moving them into the fully empty regions.
+ if (from_region->is_empty()) break;
+
+ // Can move the region, and this is not the humongous region. Humongous
+ // moves are special cased here, because their moves are handled separately.
+ if (from_region->is_move_allowed() && !from_region->is_humongous()) break;
+
from_region = _heap_regions.next();
}
if (from_region != NULL) {
assert(slice != NULL, "sanity");
assert(!from_region->is_humongous(), "this path cannot handle humongous regions");
- assert(from_region->is_move_allowed(), "only regions that can be moved in mark-compact");
+ assert(from_region->is_empty() || from_region->is_move_allowed(), "only regions that can be moved in mark-compact");
slice->add_region(from_region);
}
--- a/src/hotspot/share/opto/c2compiler.cpp Mon Sep 30 21:16:42 2019 +0200
+++ b/src/hotspot/share/opto/c2compiler.cpp Tue Oct 01 18:47:30 2019 +0200
@@ -462,6 +462,11 @@
case vmIntrinsics::_writebackPostSync0:
if (!Matcher::match_rule_supported(Op_CacheWBPostSync)) return false;
break;
+ case vmIntrinsics::_rint:
+ case vmIntrinsics::_ceil:
+ case vmIntrinsics::_floor:
+ if (!Matcher::match_rule_supported(Op_RoundDoubleMode)) return false;
+ break;
case vmIntrinsics::_hashCode:
case vmIntrinsics::_identityHashCode:
case vmIntrinsics::_getClass:
--- a/src/hotspot/share/opto/classes.hpp Mon Sep 30 21:16:42 2019 +0200
+++ b/src/hotspot/share/opto/classes.hpp Tue Oct 01 18:47:30 2019 +0200
@@ -274,6 +274,8 @@
macro(Return)
macro(Root)
macro(RoundDouble)
+macro(RoundDoubleMode)
+macro(RoundDoubleModeV)
macro(RoundFloat)
macro(SafePoint)
macro(SafePointScalarObject)
--- a/src/hotspot/share/opto/convertnode.cpp Mon Sep 30 21:16:42 2019 +0200
+++ b/src/hotspot/share/opto/convertnode.cpp Tue Oct 01 18:47:30 2019 +0200
@@ -531,4 +531,16 @@
return phase->type( in(1) );
}
-
+//=============================================================================
+//------------------------------Identity---------------------------------------
+// Remove redundant roundings.
+Node* RoundDoubleModeNode::Identity(PhaseGVN* phase) {
+ int op = in(1)->Opcode();
+ // Redundant rounding e.g. floor(ceil(n)) -> ceil(n)
+ if(op == Op_RoundDoubleMode) return in(1);
+ return this;
+}
+const Type* RoundDoubleModeNode::Value(PhaseGVN* phase) const {
+ return Type::DOUBLE;
+}
+//=============================================================================
--- a/src/hotspot/share/opto/convertnode.hpp Mon Sep 30 21:16:42 2019 +0200
+++ b/src/hotspot/share/opto/convertnode.hpp Tue Oct 01 18:47:30 2019 +0200
@@ -212,5 +212,16 @@
virtual const Type* Value(PhaseGVN* phase) const;
};
+//-----------------------------RoundDoubleModeNode-----------------------------
+class RoundDoubleModeNode: public Node {
+ public:
+ RoundDoubleModeNode(Node *in1, Node * rmode): Node(0, in1, rmode) {}
+ virtual int Opcode() const;
+ virtual const Type *bottom_type() const { return Type::DOUBLE; }
+ virtual uint ideal_reg() const { return Op_RegD; }
+ virtual Node* Identity(PhaseGVN* phase);
+ virtual const Type* Value(PhaseGVN* phase) const;
+};
+
#endif // SHARE_OPTO_CONVERTNODE_HPP
--- a/src/hotspot/share/opto/library_call.cpp Mon Sep 30 21:16:42 2019 +0200
+++ b/src/hotspot/share/opto/library_call.cpp Tue Oct 01 18:47:30 2019 +0200
@@ -534,6 +534,9 @@
case vmIntrinsics::_identityHashCode: return inline_native_hashcode(/*!virtual*/ false, is_static);
case vmIntrinsics::_getClass: return inline_native_getClass();
+ case vmIntrinsics::_ceil:
+ case vmIntrinsics::_floor:
+ case vmIntrinsics::_rint:
case vmIntrinsics::_dsin:
case vmIntrinsics::_dcos:
case vmIntrinsics::_dtan:
@@ -1818,6 +1821,9 @@
switch (id) {
case vmIntrinsics::_dabs: n = new AbsDNode( arg); break;
case vmIntrinsics::_dsqrt: n = new SqrtDNode(C, control(), arg); break;
+ case vmIntrinsics::_ceil: n = new RoundDoubleModeNode(arg, makecon(TypeInt::make(2))); break;
+ case vmIntrinsics::_floor: n = new RoundDoubleModeNode(arg, makecon(TypeInt::make(1))); break;
+ case vmIntrinsics::_rint: n = new RoundDoubleModeNode(arg, makecon(TypeInt::make(0))); break;
default: fatal_unexpected_iid(id); break;
}
set_result(_gvn.transform(n));
@@ -1891,6 +1897,9 @@
runtime_math(OptoRuntime::Math_D_D_Type(), FN_PTR(SharedRuntime::dlog10), "LOG10");
// These intrinsics are supported on all hardware
+ case vmIntrinsics::_ceil:
+ case vmIntrinsics::_floor:
+ case vmIntrinsics::_rint: return Matcher::match_rule_supported(Op_RoundDoubleMode) ? inline_double_math(id) : false;
case vmIntrinsics::_dsqrt: return Matcher::match_rule_supported(Op_SqrtD) ? inline_double_math(id) : false;
case vmIntrinsics::_dabs: return Matcher::has_match_rule(Op_AbsD) ? inline_double_math(id) : false;
case vmIntrinsics::_fabs: return Matcher::match_rule_supported(Op_AbsF) ? inline_math(id) : false;
--- a/src/hotspot/share/opto/superword.cpp Mon Sep 30 21:16:42 2019 +0200
+++ b/src/hotspot/share/opto/superword.cpp Tue Oct 01 18:47:30 2019 +0200
@@ -2401,6 +2401,12 @@
const TypePtr* atyp = n->adr_type();
vn = StoreVectorNode::make(opc, ctl, mem, adr, atyp, val, vlen);
vlen_in_bytes = vn->as_StoreVector()->memory_size();
+ } else if (VectorNode::is_roundopD(n)) {
+ Node* in1 = vector_opd(p, 1);
+ Node* in2 = low_adr->in(2);
+ assert(in2->is_Con(), "Constant rounding mode expected.");
+ vn = VectorNode::make(opc, in1, in2, vlen, velt_basic_type(n));
+ vlen_in_bytes = vn->as_Vector()->length_in_bytes();
} else if (VectorNode::is_muladds2i(n)) {
assert(n->req() == 5u, "MulAddS2I should have 4 operands.");
Node* in1 = vector_opd(p, 1);
--- a/src/hotspot/share/opto/vectornode.cpp Mon Sep 30 21:16:42 2019 +0200
+++ b/src/hotspot/share/opto/vectornode.cpp Tue Oct 01 18:47:30 2019 +0200
@@ -128,6 +128,9 @@
case Op_NegD:
assert(bt == T_DOUBLE, "must be");
return Op_NegVD;
+ case Op_RoundDoubleMode:
+ assert(bt == T_DOUBLE, "must be");
+ return Op_RoundDoubleModeV;
case Op_SqrtF:
assert(bt == T_FLOAT, "must be");
return Op_SqrtVF;
@@ -259,6 +262,13 @@
return false;
}
+bool VectorNode::is_roundopD(Node *n) {
+ if (n->Opcode() == Op_RoundDoubleMode) {
+ return true;
+ }
+ return false;
+}
+
bool VectorNode::is_shift(Node* n) {
switch (n->Opcode()) {
case Op_LShiftI:
@@ -407,6 +417,8 @@
case Op_MinV: return new MinVNode(n1, n2, vt);
case Op_MaxV: return new MaxVNode(n1, n2, vt);
+ case Op_RoundDoubleModeV: return new RoundDoubleModeVNode(n1, n2, vt);
+
case Op_MulAddVS2VI: return new MulAddVS2VINode(n1, n2, vt);
default:
fatal("Missed vector creation for '%s'", NodeClassNames[vopc]);
--- a/src/hotspot/share/opto/vectornode.hpp Mon Sep 30 21:16:42 2019 +0200
+++ b/src/hotspot/share/opto/vectornode.hpp Tue Oct 01 18:47:30 2019 +0200
@@ -70,6 +70,7 @@
static bool is_type_transition_short_to_int(Node* n);
static bool is_type_transition_to_int(Node* n);
static bool is_muladds2i(Node* n);
+ static bool is_roundopD(Node * n);
static bool is_invariant_vector(Node* n);
// [Start, end) half-open range defining which operands are vectors
static void vector_operands(Node* n, uint* start, uint* end);
@@ -447,6 +448,13 @@
SqrtVFNode(Node* in, const TypeVect* vt) : VectorNode(in,vt) {}
virtual int Opcode() const;
};
+//------------------------------RoundDoubleVNode--------------------------------
+// Vector round double
+class RoundDoubleModeVNode : public VectorNode {
+ public:
+ RoundDoubleModeVNode(Node* in1, Node* in2, const TypeVect* vt) : VectorNode(in1, in2, vt) {}
+ virtual int Opcode() const;
+};
//------------------------------SqrtVDNode--------------------------------------
// Vector Sqrt double
--- a/src/java.base/share/classes/java/lang/Math.java Mon Sep 30 21:16:42 2019 +0200
+++ b/src/java.base/share/classes/java/lang/Math.java Tue Oct 01 18:47:30 2019 +0200
@@ -440,6 +440,7 @@
* floating-point value that is greater than or equal to
* the argument and is equal to a mathematical integer.
*/
+ @HotSpotIntrinsicCandidate
public static double ceil(double a) {
return StrictMath.ceil(a); // default impl. delegates to StrictMath
}
@@ -459,6 +460,7 @@
* floating-point value that less than or equal to the argument
* and is equal to a mathematical integer.
*/
+ @HotSpotIntrinsicCandidate
public static double floor(double a) {
return StrictMath.floor(a); // default impl. delegates to StrictMath
}
@@ -478,6 +480,7 @@
* @return the closest floating-point value to {@code a} that is
* equal to a mathematical integer.
*/
+ @HotSpotIntrinsicCandidate
public static double rint(double a) {
return StrictMath.rint(a); // default impl. delegates to StrictMath
}
--- a/src/java.base/share/classes/sun/net/www/http/HttpClient.java Mon Sep 30 21:16:42 2019 +0200
+++ b/src/java.base/share/classes/sun/net/www/http/HttpClient.java Tue Oct 01 18:47:30 2019 +0200
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1994, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1994, 2019, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -707,11 +707,7 @@
} else {
// try once more
openServer();
- if (needsTunneling()) {
- MessageHeader origRequests = requests;
- httpuc.doTunneling();
- requests = origRequests;
- }
+ checkTunneling(httpuc);
afterConnect();
writeRequests(requests, poster);
return parseHTTP(responses, pi, httpuc);
@@ -722,6 +718,18 @@
}
+ // Check whether tunnel must be open and open it if necessary
+ // (in the case of HTTPS with proxy)
+ private void checkTunneling(HttpURLConnection httpuc) throws IOException {
+ if (needsTunneling()) {
+ MessageHeader origRequests = requests;
+ PosterOutputStream origPoster = poster;
+ httpuc.doTunneling();
+ requests = origRequests;
+ poster = origPoster;
+ }
+ }
+
private boolean parseHTTPHeader(MessageHeader responses, ProgressSource pi, HttpURLConnection httpuc)
throws IOException {
/* If "HTTP/*" is found in the beginning, return true. Let
@@ -849,11 +857,7 @@
closeServer();
cachedHttpClient = false;
openServer();
- if (needsTunneling()) {
- MessageHeader origRequests = requests;
- httpuc.doTunneling();
- requests = origRequests;
- }
+ checkTunneling(httpuc);
afterConnect();
writeRequests(requests, poster);
return parseHTTP(responses, pi, httpuc);
--- a/test/hotspot/gtest/runtime/test_os_windows.cpp Mon Sep 30 21:16:42 2019 +0200
+++ b/test/hotspot/gtest/runtime/test_os_windows.cpp Tue Oct 01 18:47:30 2019 +0200
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2018, 2019, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -85,4 +85,595 @@
<< "Failed to allocate memory at requested location " << expected_location << " of size " << expected_allocation_size;
}
+// The types of path modifications we randomly apply to a path. They should not change the file designated by the path.
+enum ModsFilter {
+ Allow_None = 0, // No modifications
+ Allow_Sep_Mods = 1, // Replace '\\' by any sequence of '/' or '\\' or at least length 1.
+ Allow_Dot_Path = 2, // Add /. segments at random positions
+ Allow_Dot_Dot_Path = 4, // Add /../<correct-dir> segments at random positions.
+ Allow_All = Allow_Sep_Mods | Allow_Dot_Path | Allow_Dot_Dot_Path
+};
+
+// The mode in which to run.
+enum Mode {
+ TEST, // Runs the test. This is the normal modus.
+ EXAMPLES, // Runs example which document the behaviour of the Windows system calls.
+ BENCH // Runs a small benchmark which tries to show the costs of using the *W variants/_wfullpath.
+};
+
+// Parameters of the test.
+static ModsFilter mods_filter = Allow_All;
+static int mods_per_path = 50; // The number of variants of a path we try.
+static Mode mode = TEST;
+
+
+// Utility methods
+static void get_current_dir_w(wchar_t* path, size_t size) {
+ DWORD count = GetCurrentDirectoryW((DWORD) size, path);
+ EXPECT_GT((int) count, 0) << "Failed to get current directory: " << GetLastError();
+ EXPECT_LT((size_t) count, size) << "Buffer too small for current directory: " << size;
+}
+
+#define WITH_ABS_PATH(path) \
+ wchar_t abs_path[JVM_MAXPATHLEN]; \
+ wchar_t cwd[JVM_MAXPATHLEN]; \
+ get_current_dir_w(cwd, JVM_MAXPATHLEN); \
+ wsprintfW(abs_path, L"\\\\?\\%ls\\%ls", cwd, (path))
+
+static bool file_exists_w(const wchar_t* path) {
+ WIN32_FILE_ATTRIBUTE_DATA file_data;
+ return ::GetFileAttributesExW(path, GetFileExInfoStandard, &file_data);
+}
+
+static void create_rel_directory_w(const wchar_t* path) {
+ WITH_ABS_PATH(path);
+ EXPECT_FALSE(file_exists_w(abs_path)) << "Can't create directory: \"" << path << "\" already exists";
+ BOOL result = CreateDirectoryW(abs_path, NULL);
+ EXPECT_TRUE(result) << "Failed to create directory \"" << path << "\" " << GetLastError();
+}
+
+static void delete_empty_rel_directory_w(const wchar_t* path) {
+ WITH_ABS_PATH(path);
+ EXPECT_TRUE(file_exists_w(abs_path)) << "Can't delete directory: \"" << path << "\" does not exists";
+ BOOL result = RemoveDirectoryW(abs_path);
+ EXPECT_TRUE(result) << "Failed to delete directory \"" << path << "\": " << GetLastError();
+}
+
+static void create_rel_file_w(const wchar_t* path) {
+ WITH_ABS_PATH(path);
+ EXPECT_FALSE(file_exists_w(abs_path)) << "Can't create file: \"" << path << "\" already exists";
+ HANDLE h = CreateFileW(abs_path, 0, 0, NULL, CREATE_NEW, FILE_ATTRIBUTE_NORMAL, NULL);
+ EXPECT_NE(h, INVALID_HANDLE_VALUE) << "Failed to create file \"" << path << "\": " << GetLastError();
+ CloseHandle(h);
+}
+
+static void delete_rel_file_w(const wchar_t* path) {
+ WITH_ABS_PATH(path);
+ EXPECT_TRUE(file_exists_w(abs_path)) << "Can't delete file: \"" << path << "\" does not exists";
+ BOOL result = DeleteFileW(abs_path);
+ EXPECT_TRUE(result) << "Failed to delete file \"" << path << "\": " << GetLastError();
+}
+
+static bool convert_to_cstring(char* c_str, size_t size, wchar_t* w_str) {
+ size_t converted;
+ errno_t err = wcstombs_s(&converted, c_str, size, w_str, size - 1);
+ EXPECT_EQ(err, ERROR_SUCCESS) << "Could not convert \"" << w_str << "\" to c-string";
+
+ return err == ERROR_SUCCESS;
+}
+
+static wchar_t* my_wcscpy_s(wchar_t* dest, size_t size, wchar_t* start, const wchar_t* to_copy) {
+ size_t already_used = dest - start;
+ size_t len = wcslen(to_copy);
+
+ if (already_used + len < size) {
+ wcscpy_s(dest, size - already_used, to_copy);
+ }
+
+ return dest + wcslen(to_copy);
+}
+
+// The currently finite list of seperator sequences we might use instead of '\\'.
+static const wchar_t* sep_replacements[] = {
+ L"\\", L"\\/", L"/", L"//", L"\\\\/\\", L"//\\/"
+};
+
+// Takes a path and modifies it in a way that it should still designate the same file.
+static bool unnormalize_path(wchar_t* result, size_t size, bool is_dir, const wchar_t* path) {
+ wchar_t* dest = result;
+ const wchar_t* src = path;
+ const wchar_t* path_start;
+
+ if (wcsncmp(src, L"\\\\?\\UNC\\", 8) == 0) {
+ path_start = src + 8;
+ } else if (wcsncmp(src, L"\\\\?\\", 4) == 0) {
+ if (src[5] == L':') {
+ path_start = src + 6;
+ } else {
+ path_start = wcschr(src + 4, L'\\');
+ }
+ } else if (wcsncmp(src, L"\\\\", 2) == 0) {
+ path_start = wcschr(src + 2, L'?');
+
+ if (path_start == NULL) {
+ path_start = wcschr(src + 2, L'\\');
+ } else {
+ path_start = wcschr(path_start, L'\\');
+ }
+ } else {
+ path_start = wcschr(src + 1, L'\\');
+ }
+
+ bool allow_sep_change = (mods_filter & Allow_Sep_Mods) && (os::random() & 1) == 0;
+ bool allow_dot_change = (mods_filter & Allow_Dot_Path) && (os::random() & 1) == 0;
+ bool allow_dotdot_change = (mods_filter & Allow_Dot_Dot_Path) && (os::random() & 1) == 0;
+
+ while ((*src != L'\0') && (result + size > dest)) {
+ wchar_t c = *src;
+ *dest = c;
+ ++src;
+ ++dest;
+
+ if (c == L'\\') {
+ if (allow_sep_change && (os::random() & 3) == 3) {
+ int i = os::random() % (sizeof(sep_replacements) / sizeof(sep_replacements[0]));
+
+ if (i >= 0) {
+ const wchar_t* replacement = sep_replacements[i];
+ dest = my_wcscpy_s(dest - 1, size, result, replacement);
+ }
+ } else if (path_start != NULL) {
+ if (allow_dotdot_change && (src > path_start + 1) && ((os::random() & 7) == 7)) {
+ wchar_t const* last_sep = src - 2;
+
+ while (last_sep[0] != L'\\') {
+ --last_sep;
+ }
+
+ if (last_sep > path_start) {
+ dest = my_wcscpy_s(dest, size, result, L"../");
+ src = last_sep + 1;
+ }
+ } else if (allow_dot_change && (src > path_start + 1) && ((os::random() & 7) == 7)) {
+ dest = my_wcscpy_s(dest, size, result, L"./");
+ }
+ }
+ }
+ }
+
+ while (is_dir && ((os::random() & 15) == 1)) {
+ dest = my_wcscpy_s(dest, size, result, L"/");
+ }
+
+ if (result + size > dest) {
+ *dest = L'\0';
+ }
+
+ // Use this modification only if not too close to the max size.
+ return result + size - 10 > dest;
+}
+
+static void check_dir_impl(wchar_t* path, bool should_be_empty) {
+ char buf[JVM_MAXPATHLEN];
+
+ if (convert_to_cstring(buf, JVM_MAXPATHLEN, path)) {
+ struct stat st;
+ EXPECT_EQ(os::stat(buf, &st), 0) << "os::stat failed for \"" << path << "\"";
+ EXPECT_EQ(st.st_mode & S_IFMT, S_IFDIR) << "\"" << path << "\" is not a directory according to os::stat";
+ errno = ERROR_SUCCESS;
+ bool is_empty = os::dir_is_empty(buf);
+ errno_t err = errno;
+ EXPECT_EQ(is_empty, should_be_empty) << "os::dir_is_empty assumed \"" << path << "\" is "
+ << (should_be_empty ? "not ": "") << "empty";
+ EXPECT_EQ(err, ERROR_SUCCESS) << "os::dir_is_empty failed for \"" << path << "\"with errno " << err;
+ }
+}
+
+static void check_file_impl(wchar_t* path) {
+ char buf[JVM_MAXPATHLEN];
+
+ if (convert_to_cstring(buf, JVM_MAXPATHLEN, path)) {
+ struct stat st;
+ EXPECT_EQ(os::stat(buf, &st), 0) << "os::stat failed for \"" << path << "\"";
+ EXPECT_EQ(st.st_mode & S_IFMT, S_IFREG) << "\"" << path << "\" is not a regular file according to os::stat";
+ int fd = os::open(buf, O_RDONLY, 0);
+ EXPECT_NE(fd, -1) << "os::open failed for \"" << path << "\" with errno " << errno;
+ if (fd >= 0) {
+ ::close(fd);
+ }
+ }
+}
+
+static void check_file_not_present_impl(wchar_t* path) {
+ char buf[JVM_MAXPATHLEN];
+
+ if (convert_to_cstring(buf, JVM_MAXPATHLEN, path)) {
+ struct stat st;
+ int stat_ret;
+ EXPECT_EQ(stat_ret = os::stat(buf, &st), -1) << "os::stat did not fail for \"" << path << "\"";
+ if (stat_ret != -1) {
+ // Only check open if stat not already failed.
+ int fd = os::open(buf, O_RDONLY, 0);
+ EXPECT_EQ(fd, -1) << "os::open did not fail for \"" << path << "\"";
+ if (fd >= 0) {
+ ::close(fd);
+ }
+ }
+ }
+}
+
+static void check_dir(wchar_t* path, bool should_be_empty) {
+ check_dir_impl(path, should_be_empty);
+
+ for (int i = 0; mods_filter != Allow_None && i < mods_per_path; ++i) {
+ wchar_t tmp[JVM_MAXPATHLEN];
+ if (unnormalize_path(tmp, JVM_MAXPATHLEN, true, path)) {
+ check_dir_impl(tmp, should_be_empty);
+ }
+ }
+}
+
+static void check_file(wchar_t* path) {
+ check_file_impl(path);
+
+ // Check os::same_files at least somewhat.
+ char buf[JVM_MAXPATHLEN];
+
+ if (convert_to_cstring(buf, JVM_MAXPATHLEN, path)) {
+ wchar_t mod[JVM_MAXPATHLEN];
+
+ if (unnormalize_path(mod, JVM_MAXPATHLEN, false, path)) {
+ char mod_c[JVM_MAXPATHLEN];
+ if (convert_to_cstring(mod_c, JVM_MAXPATHLEN, mod)) {
+ EXPECT_EQ(os::same_files(buf, mod_c), true) << "os::same files failed for \\" << path << "\" and \"" << mod_c << "\"";
+ }
+ }
+ }
+
+ for (int i = 0; mods_filter != Allow_None && i < mods_per_path; ++i) {
+ wchar_t tmp[JVM_MAXPATHLEN];
+ if (unnormalize_path(tmp, JVM_MAXPATHLEN, false, path)) {
+ check_file_impl(tmp);
+ }
+ }
+}
+
+static void check_file_not_present(wchar_t* path) {
+ check_file_not_present_impl(path);
+
+ for (int i = 0; mods_filter != Allow_None && i < mods_per_path; ++i) {
+ wchar_t tmp[JVM_MAXPATHLEN];
+ if (unnormalize_path(tmp, JVM_MAXPATHLEN, false, path)) {
+ check_file_not_present_impl(tmp);
+ }
+ }
+}
+
+static void record_path(char const* name, char const* len_name, wchar_t* path) {
+ char buf[JVM_MAXPATHLEN];
+
+ if (convert_to_cstring(buf, JVM_MAXPATHLEN, path)) {
+ ::testing::Test::RecordProperty(name, buf);
+ snprintf(buf, JVM_MAXPATHLEN, "%d", (int) wcslen(path));
+ ::testing::Test::RecordProperty(len_name, buf);
+ }
+}
+
+static void bench_path(wchar_t* path) {
+ char buf[JVM_MAXPATHLEN];
+ int reps = 100000;
+
+ if (convert_to_cstring(buf, JVM_MAXPATHLEN, path)) {
+ jlong wtime[2];
+
+ for (int t = 0; t < 2; ++t) {
+ wtime[t] = os::javaTimeNanos();
+
+ for (int i = 0; i < reps; ++i) {
+ bool succ = false;
+ size_t buf_len = strlen(buf);
+ wchar_t* w_path = (wchar_t*) os::malloc(sizeof(wchar_t) * (buf_len + 1), mtInternal);
+
+ if (w_path != NULL) {
+ size_t converted_chars;
+ if (::mbstowcs_s(&converted_chars, w_path, buf_len + 1, buf, buf_len) == ERROR_SUCCESS) {
+ if (t == 1) {
+ wchar_t* tmp = (wchar_t*) os::malloc(sizeof(wchar_t) * JVM_MAXPATHLEN, mtInternal);
+
+ if (tmp) {
+ if (_wfullpath(tmp, w_path, JVM_MAXPATHLEN)) {
+ succ = true;
+ }
+
+ // Note that we really don't use the full path name, but just add the cost of running _wfullpath.
+ os::free(tmp);
+ }
+ if (!succ) {
+ printf("Failed fullpathing \"%s\"\n", buf);
+ return;
+ }
+ succ = false;
+ }
+ HANDLE h = ::CreateFileW(w_path, 0, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL);
+
+ if (h != INVALID_HANDLE_VALUE) {
+ ::CloseHandle(h);
+ succ = true;
+ }
+ }
+ }
+
+ os::free(w_path);
+ if (!succ) {
+ printf("Failed getting W*attr. \"%s\"\n", buf);
+ return;
+ }
+ }
+
+ wtime[t] = os::javaTimeNanos() - wtime[t];
+ }
+
+ jlong ctime = os::javaTimeNanos();
+
+ for (int i = 0; i < reps; ++i) {
+ HANDLE h = ::CreateFileA(buf, 0, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL);
+
+ if (h == INVALID_HANDLE_VALUE) {
+ return;
+ }
+
+ ::CloseHandle(h);
+ }
+
+ ctime = os::javaTimeNanos() - ctime;
+
+ printf("\"%s\" %f us for *A, %f us for *W, %f us for *W with fullpath\n", buf,
+ 0.001 * ctime / reps, 0.001 * wtime[0] / reps, 0.001 * wtime[1] / reps);
+ }
+}
+
+static void print_attr_result_for_path(wchar_t* path) {
+ WIN32_FILE_ATTRIBUTE_DATA file_data;
+ struct stat st;
+ char buf[JVM_MAXPATHLEN];
+ wchar_t abs[JVM_MAXPATHLEN];
+
+ _wfullpath(abs, path, JVM_MAXPATHLEN);
+ printf("Checking \"%ls\" (%d chars):\n", path, (int) wcslen(path));
+ printf("_wfullpath %ls (%d chars)\n", abs, (int) wcslen(abs));
+ BOOL bret = ::GetFileAttributesExW(path, GetFileExInfoStandard, &file_data);
+ printf("GetFileAttributesExW() %s\n", bret ? "success" : "failed");
+
+ if (convert_to_cstring(buf, JVM_MAXPATHLEN, path)) {
+ bret = ::GetFileAttributesExA(buf, GetFileExInfoStandard, &file_data);
+ printf("GetFileAttributesExA() %s\n", bret ? "success" : "failed");
+
+ bool succ = os::stat(buf, &st) != -1;
+ printf("os::stat() %s\n", succ ? "success" : "failed");
+ }
+}
+
+static void print_attr_result(wchar_t* format, ...) {
+ va_list argptr;
+ wchar_t buf[JVM_MAXPATHLEN];
+
+ va_start(argptr, format);
+ wvsprintfW(buf, format, argptr);
+ print_attr_result_for_path(buf);
+ va_end(argptr);
+}
+
+#define RECORD_PATH(name) record_path(#name, #name "Len", name)
+#define NAME_PART_50 L"01234567890123456789012345678901234567890123456789"
+#define NAME_PART_250 NAME_PART_50 NAME_PART_50 NAME_PART_50 NAME_PART_50 NAME_PART_50
+
+// Test which tries to find out if the os::stat, os::open, os::same_files and os::dir_is_empty methods
+// can handle long path names correctly.
+TEST_VM(os_windows, handle_long_paths) {
+ static wchar_t cwd[JVM_MAXPATHLEN];
+ static wchar_t nearly_long_rel_path[JVM_MAXPATHLEN];
+ static wchar_t long_rel_path[JVM_MAXPATHLEN];
+ static wchar_t empty_dir_rel_path[JVM_MAXPATHLEN];
+ static wchar_t not_empty_dir_rel_path[JVM_MAXPATHLEN];
+ static wchar_t file_rel_path[JVM_MAXPATHLEN];
+ static wchar_t nearly_long_file_rel_path[JVM_MAXPATHLEN];
+ static wchar_t nearly_long_path[JVM_MAXPATHLEN];
+ static wchar_t empty_dir_path[JVM_MAXPATHLEN];
+ static wchar_t not_empty_dir_path[JVM_MAXPATHLEN];
+ static wchar_t nearly_long_file_path[JVM_MAXPATHLEN];
+ static wchar_t file_path[JVM_MAXPATHLEN];
+ static wchar_t nearly_long_unc_path[JVM_MAXPATHLEN];
+ static wchar_t empty_dir_unc_path[JVM_MAXPATHLEN];
+ static wchar_t not_empty_dir_unc_path[JVM_MAXPATHLEN];
+ static wchar_t nearly_long_file_unc_path[JVM_MAXPATHLEN];
+ static wchar_t file_unc_path[JVM_MAXPATHLEN];
+ static wchar_t root_dir_path[JVM_MAXPATHLEN];
+ static wchar_t root_rel_dir_path[JVM_MAXPATHLEN];
+
+ wchar_t* dir_prefix = L"os_windows_long_paths_dir_";
+ wchar_t* empty_dir_name = L"empty_directory_with_long_path";
+ wchar_t* not_empty_dir_name = L"not_empty_directory_with_long_path";
+ wchar_t* file_name = L"file";
+ wchar_t dir_letter;
+ WIN32_FILE_ATTRIBUTE_DATA file_data;
+ bool can_test_unc = false;
+
+ get_current_dir_w(cwd, sizeof(cwd) / sizeof(wchar_t));
+ dir_letter = (cwd[1] == L':' ? cwd[0] : L'\0');
+ int cwd_len = (int) wcslen(cwd);
+ int dir_prefix_len = (int) wcslen(dir_prefix);
+ int rel_path_len = MAX2(dir_prefix_len, 235 - cwd_len);
+
+ memcpy(nearly_long_rel_path, dir_prefix, sizeof(wchar_t) * dir_prefix_len);
+
+ for (int i = dir_prefix_len; i < rel_path_len; ++i) {
+ nearly_long_rel_path[i] = L'L';
+ }
+
+ nearly_long_rel_path[rel_path_len] = L'\0';
+
+ wsprintfW(long_rel_path, L"%ls\\%ls", nearly_long_rel_path, NAME_PART_250);
+ wsprintfW(empty_dir_rel_path, L"%ls\\%ls", nearly_long_rel_path, empty_dir_name);
+ wsprintfW(not_empty_dir_rel_path, L"%ls\\%ls", nearly_long_rel_path, not_empty_dir_name);
+ wsprintfW(nearly_long_file_rel_path, L"%ls\\%ls", nearly_long_rel_path, file_name);
+ wsprintfW(file_rel_path, L"%ls\\%ls\\%ls", nearly_long_rel_path, not_empty_dir_name, file_name);
+ wsprintfW(nearly_long_path, L"\\\\?\\%ls\\%ls", cwd, nearly_long_rel_path);
+ wsprintfW(empty_dir_path, L"%ls\\%ls", nearly_long_path, empty_dir_name);
+ wsprintfW(not_empty_dir_path, L"%ls\\%ls", nearly_long_path, not_empty_dir_name);
+ wsprintfW(nearly_long_file_path, L"%ls\\%ls", nearly_long_path, file_name);
+ wsprintfW(file_path, L"%ls\\%ls\\%ls", nearly_long_path, not_empty_dir_name, file_name);
+ wsprintfW(nearly_long_unc_path, L"\\\\localhost\\%lc$\\%s", dir_letter, nearly_long_path + 7);
+ wsprintfW(empty_dir_unc_path, L"%s\\%s", nearly_long_unc_path, empty_dir_name);
+ wsprintfW(not_empty_dir_unc_path, L"%s\\%s", nearly_long_unc_path, not_empty_dir_name);
+ wsprintfW(nearly_long_file_unc_path, L"%ls\\%ls", nearly_long_unc_path, file_name);
+ wsprintfW(file_unc_path, L"%s\\%s\\%s", nearly_long_unc_path, not_empty_dir_name, file_name);
+ wsprintfW(root_dir_path, L"%lc:\\", dir_letter);
+ wsprintfW(root_rel_dir_path, L"%lc:", dir_letter);
+
+ RECORD_PATH(long_rel_path);
+ RECORD_PATH(nearly_long_rel_path);
+ RECORD_PATH(nearly_long_path);
+ RECORD_PATH(nearly_long_unc_path);
+ RECORD_PATH(empty_dir_rel_path);
+ RECORD_PATH(empty_dir_path);
+ RECORD_PATH(empty_dir_unc_path);
+ RECORD_PATH(not_empty_dir_rel_path);
+ RECORD_PATH(not_empty_dir_path);
+ RECORD_PATH(not_empty_dir_unc_path);
+ RECORD_PATH(nearly_long_file_rel_path);
+ RECORD_PATH(nearly_long_file_path);
+ RECORD_PATH(nearly_long_file_unc_path);
+ RECORD_PATH(file_rel_path);
+ RECORD_PATH(file_path);
+ RECORD_PATH(file_unc_path);
+
+ create_rel_directory_w(nearly_long_rel_path);
+ create_rel_directory_w(long_rel_path);
+ create_rel_directory_w(empty_dir_rel_path);
+ create_rel_directory_w(not_empty_dir_rel_path);
+ create_rel_file_w(nearly_long_file_rel_path);
+ create_rel_file_w(file_rel_path);
+
+ // For UNC path test we assume that the current DRIVE has a share
+ // called "<DRIVELETTER>$" (so for D: we expect \\localhost\D$ to be
+ // the same). Since this is only an assumption, we have to skip
+ // the UNC tests if the share is missing.
+ if (dir_letter && !::GetFileAttributesExW(nearly_long_unc_path, GetFileExInfoStandard, &file_data)) {
+ printf("Disabled UNC path test, since %lc: is not mapped as share %lc$.\n", dir_letter, dir_letter);
+ } else {
+ can_test_unc = true;
+ }
+
+ if (mode == BENCH) {
+ bench_path(nearly_long_path + 4);
+ bench_path(nearly_long_rel_path);
+ bench_path(nearly_long_file_path + 4);
+ bench_path(nearly_long_file_rel_path);
+ } else if (mode == EXAMPLES) {
+ printf("Working directory: %ls", cwd);
+
+ if (dir_letter) {
+ static wchar_t top_buf[JVM_MAXPATHLEN];
+ wchar_t* top_path = wcschr(cwd + 3, L'\\');
+
+ if (top_path) {
+ size_t top_len = (top_path - cwd) - 3;
+
+ memcpy(top_buf, cwd + 3, top_len * 2);
+ top_buf[top_len] = L'\0';
+ top_path = top_buf;
+ }
+
+ print_attr_result(L"%lc:\\", dir_letter);
+ print_attr_result(L"%lc:\\.\\", dir_letter);
+
+ if (top_path) {
+ print_attr_result(L"%lc:\\%ls\\..\\%ls\\", dir_letter, top_path, top_path);
+ }
+
+ print_attr_result(L"%lc:", dir_letter);
+ print_attr_result(L"%lc:.", dir_letter);
+ print_attr_result(L"%lc:\\COM1", dir_letter);
+ print_attr_result(L"%lc:\\PRN", dir_letter);
+ print_attr_result(L"%lc:\\PRN\\COM1", dir_letter);
+ print_attr_result(L"\\\\?\\UNC\\localhost\\%lc$\\", dir_letter);
+ print_attr_result(L"\\\\?\\UNC\\\\localhost\\%lc$\\", dir_letter);
+ print_attr_result(nearly_long_unc_path);
+ print_attr_result(L"%ls\\.\\", nearly_long_unc_path);
+ print_attr_result(L"%ls\\..\\%ls", nearly_long_unc_path, nearly_long_rel_path);
+ print_attr_result(L"\\\\?\\UNC\\%ls", nearly_long_unc_path + 2);
+ print_attr_result(file_unc_path);
+ print_attr_result(L"%ls\\%ls\\..\\%ls\\%ls", nearly_long_unc_path, not_empty_dir_name, not_empty_dir_name, file_name);
+ print_attr_result(L"%ls\\%ls\\.\\%ls", nearly_long_unc_path, not_empty_dir_name, file_name);
+ print_attr_result(L"\\\\?\\UNC\\%ls", file_unc_path + 2);
+ print_attr_result(L"\\\\?\\UNC\\%ls\\%ls\\.\\%ls", nearly_long_unc_path + 2, not_empty_dir_name, file_name);
+ print_attr_result(L"\\\\?\\UNC\\%ls\\%ls\\..\\%ls\\%ls", nearly_long_unc_path + 2, not_empty_dir_name, not_empty_dir_name, file_name);
+ }
+
+ print_attr_result(nearly_long_rel_path);
+ print_attr_result(L"%ls\\.\\", nearly_long_rel_path);
+ print_attr_result(L"%ls\\..\\%ls", nearly_long_rel_path, nearly_long_rel_path);
+ print_attr_result(L"%\\\\?\\%ls", nearly_long_rel_path);
+ print_attr_result(L"\\\\?\\%ls\\.\\", nearly_long_rel_path);
+ print_attr_result(L"\\\\?\\%ls\\..\\%ls", nearly_long_rel_path, nearly_long_rel_path);
+
+ print_attr_result(nearly_long_path + 4);
+ print_attr_result(L"%ls\\.\\", nearly_long_path + 4);
+ print_attr_result(L"%ls\\..\\%ls", nearly_long_path + 4, nearly_long_rel_path);
+ print_attr_result(nearly_long_path);
+ print_attr_result(L"%ls\\.\\", nearly_long_path);
+ print_attr_result(L"%ls\\..\\%ls", nearly_long_path, nearly_long_rel_path);
+ } else {
+ check_file_not_present(L"");
+
+ // Check relative paths
+ check_dir(nearly_long_rel_path, false);
+ check_dir(long_rel_path, true);
+ check_dir(empty_dir_rel_path, true);
+ check_dir(not_empty_dir_rel_path, false);
+ check_file(nearly_long_file_rel_path);
+ check_file(file_rel_path);
+
+ // Check absolute paths
+ if (dir_letter) {
+ check_dir(root_dir_path, false);
+ check_dir(root_rel_dir_path, false);
+ }
+
+ check_dir(cwd, false);
+ check_dir(nearly_long_path + 4, false);
+ check_dir(empty_dir_path + 4, true);
+ check_dir(not_empty_dir_path + 4, false);
+ check_file(nearly_long_file_path + 4);
+ check_file(file_path + 4);
+
+ // Check UNC paths
+ if (can_test_unc) {
+ check_dir(nearly_long_unc_path, false);
+ check_dir(empty_dir_unc_path, true);
+ check_dir(not_empty_dir_unc_path, false);
+ check_file(nearly_long_file_unc_path);
+ check_file(file_unc_path);
+ }
+
+ // Check handling of <DRIVE>:/../<OTHER_DRIVE>:/path/...
+ // The other drive letter should not overwrite the original one.
+ if (dir_letter) {
+ static wchar_t tmp[JVM_MAXPATHLEN];
+ wchar_t* other_letter = dir_letter == L'D' ? L"C" : L"D";
+ wsprintfW(tmp, L"%2ls\\..\\%ls:%ls", nearly_long_file_path, other_letter, nearly_long_file_path + 2);
+ check_file_not_present(tmp);
+ wsprintfW(tmp, L"%2ls\\..\\%ls:%ls", file_path, other_letter, file_path + 2);
+ check_file_not_present(tmp);
+ }
+ }
+
+ delete_rel_file_w(file_rel_path);
+ delete_rel_file_w(nearly_long_file_rel_path);
+ delete_empty_rel_directory_w(not_empty_dir_rel_path);
+ delete_empty_rel_directory_w(empty_dir_rel_path);
+ delete_empty_rel_directory_w(long_rel_path);
+ delete_empty_rel_directory_w(nearly_long_rel_path);
+}
+
#endif
--- a/test/hotspot/jtreg/compiler/c2/cr6340864/TestDoubleVect.java Mon Sep 30 21:16:42 2019 +0200
+++ b/test/hotspot/jtreg/compiler/c2/cr6340864/TestDoubleVect.java Tue Oct 01 18:47:30 2019 +0200
@@ -87,6 +87,9 @@
test_divv(a0, a1, -VALUE);
test_diva(a0, a1, a3);
test_negc(a0, a1);
+ test_rint(a0, a1);
+ test_ceil(a0, a1);
+ test_floor(a0, a1);
}
// Test and verify results
System.out.println("Verification");
@@ -351,6 +354,56 @@
errn += verify("test_negc: ", i, a0[i], (double)(-((double)(ADD_INIT+i))));
}
+ // To test -ve and +ve Zero scenarios.
+ double [] other_corner_cases = { -0.0, 0.0, 9.007199254740992E15 };
+ double [] other_corner_cases_res = new double[3];
+ test_floor(a0, a1);
+ errn += verify("test_floor: ", 0, a0[0], Double.NaN);
+ errn += verify("test_floor: ", 1, a0[1], Double.POSITIVE_INFINITY);
+ errn += verify("test_floor: ", 2, a0[2], Double.NEGATIVE_INFINITY);
+ errn += verify("test_floor: ", 3, a0[3], Double.MAX_VALUE);
+ errn += verify("test_floor: ", 4, a0[4], 0.0);
+ errn += verify("test_floor: ", 5, a0[5], 0.0);
+ for (int i=6; i<ARRLEN; i++) {
+ errn += verify("test_floor: ", i, a0[i], ((double)(ADD_INIT+i)));
+ }
+ test_floor_cc(other_corner_cases_res, other_corner_cases);
+ errn += verify("test_floor_cc: ", 0, other_corner_cases_res[0], -0.0);
+ errn += verify("test_floor_cc: ", 1, other_corner_cases_res[1], 0.0);
+ errn += verify("test_floor_cc: ", 2, other_corner_cases_res[2], 9.007199254740992E15);
+
+ test_ceil(a0, a1);
+ errn += verify("test_ceil: ", 0, a0[0], Double.NaN);
+ errn += verify("test_ceil: ", 1, a0[1], Double.POSITIVE_INFINITY);
+ errn += verify("test_ceil: ", 2, a0[2], Double.NEGATIVE_INFINITY);
+ errn += verify("test_ceil: ", 3, a0[3], Double.MAX_VALUE);
+ errn += verify("test_ceil: ", 4, a0[4], 1.0);
+ errn += verify("test_ceil: ", 5, a0[5], 1.0);
+ for (int i=6; i<ARRLEN; i++) {
+ errn += verify("test_ceil: ", i, a0[i], ((double)(ADD_INIT+i+1.0)));
+ }
+ test_ceil_cc(other_corner_cases_res, other_corner_cases);
+ errn += verify("test_ceil_cc: ", 0, other_corner_cases_res[0], -0.0);
+ errn += verify("test_ceil_cc: ", 1, other_corner_cases_res[1], 0.0);
+ errn += verify("test_ceil_cc: ", 2, other_corner_cases_res[2], 9.007199254740992E15);
+
+ test_rint(a0, a1);
+ errn += verify("test_rint: ", 0, a0[0], Double.NaN);
+ errn += verify("test_rint: ", 1, a0[1], Double.POSITIVE_INFINITY);
+ errn += verify("test_rint: ", 2, a0[2], Double.NEGATIVE_INFINITY);
+ errn += verify("test_rint: ", 3, a0[3], Double.MAX_VALUE);
+ errn += verify("test_rint: ", 4, a0[4], 0.0);
+ errn += verify("test_rint: ", 5, a0[5], 0.0);
+ for (int i=6; i<ARRLEN; i++) {
+ if ( i <= 500 )
+ errn += verify("test_rint: ", i, a0[i], ((double)(ADD_INIT+i)));
+ else
+ errn += verify("test_rint: ", i, a0[i], ((double)(ADD_INIT+i+1.0)));
+ }
+ test_rint_cc(other_corner_cases_res, other_corner_cases);
+ errn += verify("test_rint_cc: ", 0, other_corner_cases_res[0], -0.0);
+ errn += verify("test_rint_cc: ", 1, other_corner_cases_res[1], 0.0);
+ errn += verify("test_rint_cc: ", 2, other_corner_cases_res[2], 9.007199254740992E15);
}
if (errn > 0)
@@ -577,6 +630,37 @@
}
}
+ static void test_rint(double[] a0, double[] a1) {
+ for (int i = 0; i < a0.length; i+=1) {
+ a0[i] = Math.rint(a1[i] + ((double)(i))/1000);
+ }
+ }
+ static void test_ceil(double[] a0, double[] a1) {
+ for (int i = 0; i < a0.length; i+=1) {
+ a0[i] = Math.ceil(a1[i] + ((double)(i))/1000);
+ }
+ }
+ static void test_floor(double[] a0, double[] a1) {
+ for (int i = 0; i < a0.length; i+=1) {
+ a0[i] = Math.floor(a1[i] + ((double)(i))/1000);
+ }
+ }
+ static void test_rint_cc(double[] a0, double[] a1) {
+ for (int i = 0; i < a0.length; i+=1) {
+ a0[i] = Math.rint(a1[i]);
+ }
+ }
+ static void test_ceil_cc(double[] a0, double[] a1) {
+ for (int i = 0; i < a0.length; i+=1) {
+ a0[i] = Math.ceil(a1[i]);
+ }
+ }
+ static void test_floor_cc(double[] a0, double[] a1) {
+ for (int i = 0; i < a0.length; i+=1) {
+ a0[i] = Math.floor(a1[i]);
+ }
+ }
+
static int verify(String text, int i, double elem, double val) {
if (elem != val && !(Double.isNaN(elem) && Double.isNaN(val))) {
System.err.println(text + "[" + i + "] = " + elem + " != " + val);
--- a/test/hotspot/jtreg/compiler/escapeAnalysis/TestSelfArrayCopy.java Mon Sep 30 21:16:42 2019 +0200
+++ b/test/hotspot/jtreg/compiler/escapeAnalysis/TestSelfArrayCopy.java Tue Oct 01 18:47:30 2019 +0200
@@ -26,7 +26,7 @@
* @bug 8229016 8231055
* @summary Test correct elimination of array allocation with arraycopy to itself.
* @library /test/lib
- * @run main/othervm -Xbatch -XX:CompileCommand=compileonly,compiler.escapeAnalysis.TestSelfArrayCopy::test
+ * @run main/othervm -Xbatch -XX:CompileCommand=compileonly,compiler.escapeAnalysis.TestSelfArrayCopy::test*
* compiler.escapeAnalysis.TestSelfArrayCopy
*/
--- a/test/hotspot/jtreg/runtime/LoadClass/LongBCP.java Mon Sep 30 21:16:42 2019 +0200
+++ b/test/hotspot/jtreg/runtime/LoadClass/LongBCP.java Tue Oct 01 18:47:30 2019 +0200
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2017, 2019, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -39,7 +39,6 @@
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Arrays;
-import jdk.test.lib.Platform;
import jdk.test.lib.compiler.CompilerUtils;
import jdk.test.lib.process.ProcessTools;
import jdk.test.lib.process.OutputAnalyzer;
@@ -126,13 +125,8 @@
bootCP, "Hello");
output = new OutputAnalyzer(pb.start());
- if (!Platform.isWindows()) {
- output.shouldContain("Hello World")
- .shouldHaveExitValue(0);
- } else {
- output.shouldContain("Could not find or load main class Hello")
- .shouldHaveExitValue(1);
- }
+ output.shouldContain("Hello World")
+ .shouldHaveExitValue(0);
// total relative path length exceeds MAX_PATH
destDir = Paths.get(destDir.toString(), "yyyyyyyy");
@@ -144,12 +138,7 @@
bootCP, "Hello");
output = new OutputAnalyzer(pb.start());
- if (!Platform.isWindows()) {
- output.shouldContain("Hello World")
- .shouldHaveExitValue(0);
- } else {
- output.shouldContain("Could not find or load main class Hello")
- .shouldHaveExitValue(1);
- }
+ output.shouldContain("Hello World")
+ .shouldHaveExitValue(0);
}
}
--- a/test/hotspot/jtreg/vmTestbase/nsk/jvmti/Allocate/alloc001/TestDescription.java Mon Sep 30 21:16:42 2019 +0200
+++ b/test/hotspot/jtreg/vmTestbase/nsk/jvmti/Allocate/alloc001/TestDescription.java Tue Oct 01 18:47:30 2019 +0200
@@ -42,6 +42,8 @@
* @library /vmTestbase
* /test/lib
* @requires os.family != "aix"
+ * @comment Test is incompatible with ZGC, due to ZGC's address space requirements.
+ * @requires vm.gc != "Z"
* @run driver jdk.test.lib.FileInstaller . .
* @build nsk.jvmti.Allocate.alloc001
* @run shell alloc001.sh
--- a/test/jdk/ProblemList.txt Mon Sep 30 21:16:42 2019 +0200
+++ b/test/jdk/ProblemList.txt Tue Oct 01 18:47:30 2019 +0200
@@ -250,7 +250,7 @@
java/awt/font/TextLayout/TextLayoutBounds.java 8169188 generic-all
java/awt/font/StyledMetrics/BoldSpace.java 8198422 linux-all
java/awt/FontMetrics/FontCrash.java 8198336 windows-all
-java/awt/FontMetrics/MaxAdvanceIsMax.java 8221305 solaris-all,macosx-all
+java/awt/FontMetrics/MaxAdvanceIsMax.java 8221305,8231495 solaris-all,macosx-all,linux-all
java/awt/image/DrawImage/IncorrectAlphaSurface2SW.java 8056077 generic-all
java/awt/image/DrawImage/IncorrectClipXorModeSW2Surface.java 8196025 windows-all
java/awt/image/DrawImage/IncorrectClipXorModeSurface2Surface.java 8196025 windows-all
--- a/test/jdk/java/io/File/SetLastModified.java Mon Sep 30 21:16:42 2019 +0200
+++ b/test/jdk/java/io/File/SetLastModified.java Tue Oct 01 18:47:30 2019 +0200
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1998, 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1998, 2019, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -23,6 +23,7 @@
/* @test
@bug 4091757 6652379 8177809
+ @requires os.maxMemory >= 16G
@summary Basic test for setLastModified method
*/
--- a/test/jdk/java/net/MulticastSocket/UnreferencedMulticastSockets.java Mon Sep 30 21:16:42 2019 +0200
+++ b/test/jdk/java/net/MulticastSocket/UnreferencedMulticastSockets.java Tue Oct 01 18:47:30 2019 +0200
@@ -50,6 +50,7 @@
import java.util.ArrayDeque;
import java.util.List;
import java.util.Optional;
+import java.util.concurrent.Phaser;
import java.util.concurrent.TimeUnit;
import jdk.test.lib.net.IPSupport;
@@ -72,11 +73,14 @@
static class Server implements Runnable {
MulticastSocket ss;
-
+ final int port;
+ final Phaser phaser = new Phaser(2);
Server() throws IOException {
+ InetAddress loopback = InetAddress.getLoopbackAddress();
InetSocketAddress serverAddress =
- new InetSocketAddress(InetAddress.getLoopbackAddress(), 0);
+ new InetSocketAddress(loopback, 0);
ss = new MulticastSocket(serverAddress);
+ port = ss.getLocalPort();
System.out.printf(" DatagramServer addr: %s: %d%n",
this.getHost(), this.getPort());
pendingSockets.add(new NamedWeak(ss, pendingQueue, "serverMulticastSocket"));
@@ -89,7 +93,7 @@
}
int getPort() {
- return ss.getLocalPort();
+ return port;
}
// Receive a byte and send back a byte
@@ -98,12 +102,18 @@
byte[] buffer = new byte[50];
DatagramPacket p = new DatagramPacket(buffer, buffer.length);
ss.receive(p);
+ System.out.printf("Server: ping received from: %s%n", p.getSocketAddress());
+ phaser.arriveAndAwaitAdvance(); // await the client...
buffer[0] += 1;
+ System.out.printf("Server: sending echo to: %s%n", p.getSocketAddress());
ss.send(p); // send back +1
+ System.out.printf("Server: awaiting client%n");
+ phaser.arriveAndAwaitAdvance(); // await the client...
// do NOT close but 'forget' the socket reference
+ System.out.printf("Server: forgetting socket...%n");
ss = null;
- } catch (Exception ioe) {
+ } catch (Throwable ioe) {
ioe.printStackTrace();
}
}
@@ -112,8 +122,11 @@
public static void main(String args[]) throws Exception {
IPSupport.throwSkippedExceptionIfNonOperational();
+ InetSocketAddress clientAddress =
+ new InetSocketAddress(InetAddress.getLoopbackAddress(), 0);
+
// Create and close a MulticastSocket to warm up the FD count for side effects.
- try (MulticastSocket s = new MulticastSocket(0)) {
+ try (MulticastSocket s = new MulticastSocket(clientAddress)) {
// no-op; close immediately
s.getLocalPort(); // no-op
}
@@ -126,8 +139,33 @@
Thread thr = new Thread(svr);
thr.start();
- MulticastSocket client = new MulticastSocket(0);
- System.out.printf(" client bound port: %d%n", client.getLocalPort());
+ // It is possible under some circumstances that the client
+ // might get bound to the same port than the server: this
+ // would make the test fail - so if this happen we try to
+ // bind to a specific port by incrementing the server port.
+ MulticastSocket client = null;
+ int serverPort = svr.getPort();
+ int maxtries = 20;
+ for (int i = 0; i < maxtries; i++) {
+ try {
+ System.out.printf("Trying to bind client to: %s%n", clientAddress);
+ client = new MulticastSocket(clientAddress);
+ if (client.getLocalPort() != svr.getPort()) break;
+ client.close();
+ } catch (IOException x) {
+ System.out.printf("Couldn't create client after %d attempts: %s%n", i, x);
+ if (i == maxtries) throw x;
+ }
+ if (i == maxtries) {
+ String msg = String.format("Couldn't create client after %d attempts", i);
+ System.out.println(msg);
+ throw new AssertionError(msg);
+ }
+ clientAddress = new InetSocketAddress(clientAddress.getAddress(), serverPort + i);
+ }
+
+ System.out.printf(" client bound port: %s:%d%n",
+ client.getLocalAddress(), client.getLocalPort());
client.connect(svr.getHost(), svr.getPort());
pendingSockets.add(new NamedWeak(client, pendingQueue, "clientMulticastSocket"));
extractRefs(client, "clientMulticastSocket");
@@ -136,14 +174,17 @@
msg[0] = 1;
DatagramPacket p = new DatagramPacket(msg, msg.length, svr.getHost(), svr.getPort());
client.send(p);
+ System.out.printf(" ping sent to: %s:%d%n", svr.getHost(), svr.getPort());
+ svr.phaser.arriveAndAwaitAdvance(); // wait until the server has received its packet
p = new DatagramPacket(msg, msg.length);
client.receive(p);
- System.out.printf("echo received from: %s%n", p.getSocketAddress());
+ System.out.printf(" echo received from: %s%n", p.getSocketAddress());
if (msg[0] != 2) {
throw new AssertionError("incorrect data received: expected: 2, actual: " + msg[0]);
}
+ svr.phaser.arriveAndAwaitAdvance(); // let the server null out its socket
// Do NOT close the MulticastSocket; forget it
--- a/test/jdk/java/net/SocketImpl/SocketImplCombinations.java Mon Sep 30 21:16:42 2019 +0200
+++ b/test/jdk/java/net/SocketImpl/SocketImplCombinations.java Tue Oct 01 18:47:30 2019 +0200
@@ -68,7 +68,7 @@
* Test creating a connected Socket, it should be created with a platform SocketImpl.
*/
public void testNewSocket2() throws IOException {
- try (ServerSocket ss = new ServerSocket(0)) {
+ try (ServerSocket ss = boundServerSocket()) {
try (Socket s = new Socket(ss.getInetAddress(), ss.getLocalPort())) {
SocketImpl si = getSocketImpl(s);
assertTrue(isSocksSocketImpl(si));
@@ -127,7 +127,7 @@
Socket s = new Socket((SocketImpl) null) { };
try (s) {
assertTrue(getSocketImpl(s) == null);
- s.bind(new InetSocketAddress(0)); // force SocketImpl to be created
+ s.bind(loopbackSocketAddress()); // force SocketImpl to be created
SocketImpl si = getSocketImpl(s);
assertTrue(isSocksSocketImpl(si));
SocketImpl delegate = getDelegate(si);
@@ -218,7 +218,7 @@
Socket s = new Socket((SocketImpl) null) { };
try (s) {
assertTrue(getSocketImpl(s) == null);
- s.bind(new InetSocketAddress(0)); // force SocketImpl to be created
+ s.bind(loopbackSocketAddress()); // force SocketImpl to be created
assertTrue(getSocketImpl(s) instanceof CustomSocketImpl);
}
} finally {
@@ -378,7 +378,7 @@
public void testServerSocketAccept5a() throws IOException {
SocketImpl serverImpl = new CustomSocketImpl(true);
try (ServerSocket ss = new ServerSocket(serverImpl) { }) {
- ss.bind(new InetSocketAddress(0));
+ ss.bind(loopbackSocketAddress());
expectThrows(IOException.class, ss::accept);
}
}
@@ -566,16 +566,36 @@
}
/**
+ * Returns a new InetSocketAddress with the loopback interface
+ * and port 0.
+ */
+ static InetSocketAddress loopbackSocketAddress() {
+ InetAddress loopback = InetAddress.getLoopbackAddress();
+ return new InetSocketAddress(loopback, 0);
+ }
+
+ /**
+ * Returns a ServerSocket bound to a port on the loopback address
+ */
+ static ServerSocket boundServerSocket() throws IOException {
+ ServerSocket ss = new ServerSocket();
+ ss.bind(loopbackSocketAddress());
+ return ss;
+ }
+
+ /**
* Creates a ServerSocket that returns the given Socket from accept.
*/
static ServerSocket serverSocketToAccept(Socket s) throws IOException {
- return new ServerSocket(0) {
+ ServerSocket ss = new ServerSocket() {
@Override
public Socket accept() throws IOException {
implAccept(s);
return s;
}
};
+ ss.bind(loopbackSocketAddress());
+ return ss;
}
/**
@@ -590,7 +610,7 @@
return s;
}
};
- ss.bind(new InetSocketAddress(0));
+ ss.bind(loopbackSocketAddress());
return ss;
}
--- a/test/jdk/java/net/httpclient/DigestEchoServer.java Mon Sep 30 21:16:42 2019 +0200
+++ b/test/jdk/java/net/httpclient/DigestEchoServer.java Tue Oct 01 18:47:30 2019 +0200
@@ -26,6 +26,8 @@
import com.sun.net.httpserver.HttpsConfigurator;
import com.sun.net.httpserver.HttpsParameters;
import com.sun.net.httpserver.HttpsServer;
+
+import java.io.Closeable;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
@@ -1568,8 +1570,8 @@
@Override
public void run() {
try {
+ int c = 0;
try {
- int c;
while ((c = is.read()) != -1) {
os.write(c);
os.flush();
@@ -1578,11 +1580,13 @@
if (DEBUG) System.out.print(tag);
}
is.close();
+ } catch (IOException ex) {
+ if (DEBUG || !stopped && c > -1)
+ ex.printStackTrace(System.out);
+ end.completeExceptionally(ex);
} finally {
- os.close();
+ try {os.close();} catch (Throwable t) {}
}
- } catch (IOException ex) {
- if (DEBUG) ex.printStackTrace(System.out);
} finally {
end.complete(null);
}
@@ -1632,10 +1636,12 @@
@Override
public void run() {
Socket clientConnection = null;
+ Socket targetConnection = null;
try {
while (!stopped) {
System.out.println(now() + "Tunnel: Waiting for client");
Socket toClose;
+ targetConnection = clientConnection = null;
try {
toClose = clientConnection = ss.accept();
if (NO_LINGER) {
@@ -1649,7 +1655,6 @@
}
System.out.println(now() + "Tunnel: Client accepted");
StringBuilder headers = new StringBuilder();
- Socket targetConnection = null;
InputStream ccis = clientConnection.getInputStream();
OutputStream ccos = clientConnection.getOutputStream();
Writer w = new OutputStreamWriter(
@@ -1769,28 +1774,44 @@
end1 = new CompletableFuture<>());
Thread t2 = pipe(targetConnection.getInputStream(), ccos, '-',
end2 = new CompletableFuture<>());
- end = CompletableFuture.allOf(end1, end2);
+ var end11 = end1.whenComplete((r, t) -> exceptionally(end2, t));
+ var end22 = end2.whenComplete((r, t) -> exceptionally(end1, t));
+ end = CompletableFuture.allOf(end11, end22);
+ Socket tc = targetConnection;
end.whenComplete(
(r,t) -> {
try { toClose.close(); } catch (IOException x) { }
+ try { tc.close(); } catch (IOException x) { }
finally {connectionCFs.remove(end);}
});
connectionCFs.add(end);
+ targetConnection = clientConnection = null;
t1.start();
t2.start();
}
} catch (Throwable ex) {
- try {
- ss.close();
- } catch (IOException ex1) {
- ex.addSuppressed(ex1);
- }
+ close(clientConnection, ex);
+ close(targetConnection, ex);
+ close(ss, ex);
ex.printStackTrace(System.err);
} finally {
System.out.println(now() + "Tunnel: exiting (stopped=" + stopped + ")");
connectionCFs.forEach(cf -> cf.complete(null));
}
}
+
+ void exceptionally(CompletableFuture<?> cf, Throwable t) {
+ if (t != null) cf.completeExceptionally(t);
+ }
+
+ void close(Closeable c, Throwable e) {
+ if (c == null) return;
+ try {
+ c.close();
+ } catch (IOException x) {
+ e.addSuppressed(x);
+ }
+ }
}
/**
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/sun/net/www/http/HttpClient/B8209178.java Tue Oct 01 18:47:30 2019 +0200
@@ -0,0 +1,409 @@
+/*
+ * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @bug 8209178
+ * @modules java.base/sun.net.www java.base/sun.security.x509 java.base/sun.security.tools.keytool
+ * @library /test/lib
+ * @run main/othervm -Dsun.net.http.retryPost=true B8209178
+ * @run main/othervm -Dsun.net.http.retryPost=false B8209178
+ * @summary Proxied HttpsURLConnection doesn't send BODY when retrying POST request
+ */
+
+import java.io.*;
+import java.net.*;
+import java.nio.charset.StandardCharsets;
+import java.security.KeyStore;
+import java.security.NoSuchAlgorithmException;
+import java.security.cert.X509Certificate;
+import java.util.HashMap;
+import javax.net.ssl.*;
+
+import com.sun.net.httpserver.*;
+import jdk.test.lib.net.URIBuilder;
+import sun.security.tools.keytool.CertAndKeyGen;
+import sun.security.x509.X500Name;
+
+public class B8209178 {
+ static {
+ try {
+ HttpsURLConnection.setDefaultHostnameVerifier((hostname, session) -> true);
+ SSLContext.setDefault(new TestSSLContext().get());
+ } catch (Exception ex) {
+ throw new ExceptionInInitializerError(ex);
+ }
+ }
+
+ static final String RESPONSE = "<html><body><p>Hello World!</body></html>";
+ static final String PATH = "/foo/";
+ static final String RETRYPOST = System.getProperty("sun.net.http.retryPost");
+
+ static HttpServer createHttpsServer() throws IOException, NoSuchAlgorithmException {
+ HttpsServer server = HttpsServer.create();
+ HttpContext context = server.createContext(PATH);
+ context.setHandler(new HttpHandler() {
+
+ boolean simulateError = true;
+
+ @Override
+ public void handle(HttpExchange he) throws IOException {
+
+ System.out.printf("%s - received request on : %s%n",
+ Thread.currentThread().getName(),
+ he.getRequestURI());
+ System.out.printf("%s - received request headers : %s%n",
+ Thread.currentThread().getName(),
+ new HashMap(he.getRequestHeaders()));
+
+ InputStream requestBody = he.getRequestBody();
+ String body = B8209178.toString(requestBody);
+
+ System.out.printf("%s - received request body : %s%n",
+ Thread.currentThread().getName(), body);
+
+ if (simulateError) {
+ simulateError = false;
+
+ System.out.printf("%s - closing connection unexpectedly ... %n",
+ Thread.currentThread().getName(), he.getRequestHeaders());
+
+ he.close(); // try not to respond anything the first time ...
+ return;
+ }
+
+ he.getResponseHeaders().add("encoding", "UTF-8");
+ he.sendResponseHeaders(200, RESPONSE.length());
+ he.getResponseBody().write(RESPONSE.getBytes(StandardCharsets.UTF_8));
+ he.close();
+ }
+ });
+
+ server.setHttpsConfigurator(new Configurator(SSLContext.getDefault()));
+ server.bind(new InetSocketAddress(InetAddress.getLoopbackAddress(), 0), 0);
+ return server;
+ }
+
+ public static void main(String[] args) throws IOException, NoSuchAlgorithmException {
+ HttpServer server = createHttpsServer();
+ server.start();
+ try {
+ new B8209178().test(server);
+
+ } finally {
+ server.stop(0);
+ System.out.println("Server stopped");
+ }
+ }
+
+ public void test(HttpServer server /*, HttpClient.Version version*/) throws IOException {
+ System.out.println("System property retryPost: " + RETRYPOST);
+ System.out.println("Server is: " + server.getAddress());
+ System.out.println("Verifying communication with server");
+ URI uri = URIBuilder.newBuilder()
+ .scheme("https")
+ .host(server.getAddress().getAddress())
+ .port(server.getAddress().getPort())
+ .path(PATH + "x")
+ .buildUnchecked();
+
+ TunnelingProxy proxy = new TunnelingProxy(server);
+ proxy.start();
+
+ try {
+ System.out.println("Proxy started");
+ Proxy p = new Proxy(Proxy.Type.HTTP,
+ InetSocketAddress.createUnresolved("localhost", proxy.getAddress().getPort()));
+ System.out.println("Verifying communication with proxy");
+
+ callHttpsServerThroughProxy(uri, p);
+
+ } finally {
+ System.out.println("Stopping proxy");
+ proxy.stop();
+ System.out.println("Proxy stopped");
+ }
+ }
+
+ private void callHttpsServerThroughProxy(URI uri, Proxy p) throws IOException {
+ HttpsURLConnection urlConnection = (HttpsURLConnection) uri.toURL().openConnection(p);
+
+ urlConnection.setConnectTimeout(1000);
+ urlConnection.setReadTimeout(3000);
+ urlConnection.setDoInput(true);
+ urlConnection.setDoOutput(true);
+ urlConnection.setRequestMethod("POST");
+ urlConnection.setUseCaches(false);
+
+ urlConnection.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
+ urlConnection.setRequestProperty("charset", "utf-8");
+ urlConnection.setRequestProperty("Connection", "keep-alive");
+
+ String urlParameters = "param1=a¶m2=b¶m3=c";
+ byte[] postData = urlParameters.getBytes(StandardCharsets.UTF_8);
+
+ OutputStream outputStream = urlConnection.getOutputStream();
+ outputStream.write(postData);
+ outputStream.close();
+
+ int responseCode;
+
+ try {
+ responseCode = urlConnection.getResponseCode();
+ System.out.printf(" ResponseCode : %s%n", responseCode);
+ String output;
+ InputStream inputStream = (responseCode < 400) ? urlConnection.getInputStream() : urlConnection.getErrorStream();
+ output = toString(inputStream);
+ inputStream.close();
+ System.out.printf(" Output from server : %s%n", output);
+
+ if (responseCode == 200) { // OK !
+ } else {
+ throw new RuntimeException("Bad response Code : " + responseCode);
+ }
+ } catch (SocketException se) {
+ if (RETRYPOST.equals("true")) { // Should not get here with the fix
+ throw new RuntimeException("Unexpected Socket Exception: " + se);
+ } else {
+ System.out.println("Socket Exception received as expected: " + se);
+ }
+ }
+ }
+
+ static class TunnelingProxy {
+ final Thread accept;
+ final ServerSocket ss;
+ final boolean DEBUG = false;
+ final HttpServer serverImpl;
+
+ TunnelingProxy(HttpServer serverImpl) throws IOException {
+ this.serverImpl = serverImpl;
+ ss = new ServerSocket();
+ accept = new Thread(this::accept);
+ }
+
+ void start() throws IOException {
+ ss.bind(new InetSocketAddress(InetAddress.getLoopbackAddress(), 0));
+ accept.start();
+ }
+
+ // Pipe the input stream to the output stream
+ private synchronized Thread pipe(InputStream is, OutputStream os, char tag) {
+ return new Thread("TunnelPipe(" + tag + ")") {
+ @Override
+ public void run() {
+ try {
+ try {
+ int c;
+ while ((c = is.read()) != -1) {
+ os.write(c);
+ os.flush();
+ // if DEBUG prints a + or a - for each transferred
+ // character.
+ if (DEBUG) System.out.print(tag);
+ }
+ is.close();
+ } finally {
+ os.close();
+ }
+ } catch (IOException ex) {
+ if (DEBUG) ex.printStackTrace(System.out);
+ }
+ }
+ };
+ }
+
+ public InetSocketAddress getAddress() {
+ return new InetSocketAddress(ss.getInetAddress(), ss.getLocalPort());
+ }
+
+ // This is a bit shaky. It doesn't handle continuation
+ // lines, but our client shouldn't send any.
+ // Read a line from the input stream, swallowing the final
+ // \r\n sequence. Stops at the first \n, doesn't complain
+ // if it wasn't preceded by '\r'.
+ //
+ String readLine(InputStream r) throws IOException {
+ StringBuilder b = new StringBuilder();
+ int c;
+ while ((c = r.read()) != -1) {
+ if (c == '\n') {
+ break;
+ }
+ b.appendCodePoint(c);
+ }
+ if (b.codePointAt(b.length() - 1) == '\r') {
+ b.delete(b.length() - 1, b.length());
+ }
+ return b.toString();
+ }
+
+ public void accept() {
+ Socket clientConnection = null;
+ try {
+ while (true) {
+ System.out.println("Tunnel: Waiting for client");
+ Socket previous = clientConnection;
+ try {
+ clientConnection = ss.accept();
+ } catch (IOException io) {
+ if (DEBUG) io.printStackTrace(System.out);
+ break;
+ } finally {
+ // we have only 1 client at a time, so it is safe
+ // to close the previous connection here
+ if (previous != null) previous.close();
+ }
+ System.out.println("Tunnel: Client accepted");
+ Socket targetConnection = null;
+ InputStream ccis = clientConnection.getInputStream();
+ OutputStream ccos = clientConnection.getOutputStream();
+ Writer w = new OutputStreamWriter(ccos, "UTF-8");
+ PrintWriter pw = new PrintWriter(w);
+ System.out.println("Tunnel: Reading request line");
+ String requestLine = readLine(ccis);
+ System.out.println("Tunnel: Request status line: " + requestLine);
+ if (requestLine.startsWith("CONNECT ")) {
+ // We should probably check that the next word following
+ // CONNECT is the host:port of our HTTPS serverImpl.
+ // Some improvement for a followup!
+
+ // Read all headers until we find the empty line that
+ // signals the end of all headers.
+ while (!requestLine.equals("")) {
+ System.out.println("Tunnel: Reading header: "
+ + (requestLine = readLine(ccis)));
+ }
+
+ // Open target connection
+ targetConnection = new Socket(
+ serverImpl.getAddress().getAddress(),
+ serverImpl.getAddress().getPort());
+
+ // Then send the 200 OK response to the client
+ System.out.println("Tunnel: Sending "
+ + "HTTP/1.1 200 OK\r\n\r\n");
+ pw.print("HTTP/1.1 200 OK\r\nContent-Length: 0\r\n\r\n");
+ pw.flush();
+ } else {
+ // This should not happen
+ throw new IOException("Tunnel: Unexpected status line: "
+ + requestLine);
+ }
+
+ // Pipe the input stream of the client connection to the
+ // output stream of the target connection and conversely.
+ // Now the client and target will just talk to each other.
+ System.out.println("Tunnel: Starting tunnel pipes");
+ Thread t1 = pipe(ccis, targetConnection.getOutputStream(), '+');
+ Thread t2 = pipe(targetConnection.getInputStream(), ccos, '-');
+ t1.start();
+ t2.start();
+
+ // We have only 1 client... wait until it has finished before
+ // accepting a new connection request.
+ System.out.println("Tunnel: Waiting for pipes to close");
+ t1.join();
+ t2.join();
+ System.out.println("Tunnel: Done - waiting for next client");
+ }
+ } catch (Throwable ex) {
+ try {
+ ss.close();
+ } catch (IOException ex1) {
+ ex.addSuppressed(ex1);
+ }
+ ex.printStackTrace(System.err);
+ }
+ }
+
+ void stop() throws IOException {
+ ss.close();
+ }
+ }
+
+ static class Configurator extends HttpsConfigurator {
+ public Configurator(SSLContext ctx) {
+ super(ctx);
+ }
+
+ @Override
+ public void configure(HttpsParameters params) {
+ params.setSSLParameters(getSSLContext().getSupportedSSLParameters());
+ }
+ }
+
+
+ static class TestSSLContext {
+
+ SSLContext ssl;
+
+ public TestSSLContext() throws Exception {
+ init();
+ }
+
+ private void init() throws Exception {
+
+ CertAndKeyGen keyGen = new CertAndKeyGen("RSA", "SHA1WithRSA", null);
+ keyGen.generate(1024);
+
+ //Generate self signed certificate
+ X509Certificate[] chain = new X509Certificate[1];
+ chain[0] = keyGen.getSelfCertificate(new X500Name("CN=ROOT"), (long) 365 * 24 * 3600);
+
+ char[] passphrase = "passphrase".toCharArray();
+
+ KeyStore ks = KeyStore.getInstance("JKS");
+ ks.load(null, passphrase); // must be "initialized" ...
+
+ ks.setKeyEntry("server", keyGen.getPrivateKey(), passphrase, chain);
+
+ KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509");
+ kmf.init(ks, passphrase);
+
+ TrustManagerFactory tmf = TrustManagerFactory.getInstance("SunX509");
+ tmf.init(ks);
+
+ ssl = SSLContext.getInstance("TLS");
+ ssl.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null);
+ }
+
+ public SSLContext get() {
+ return ssl;
+ }
+ }
+
+ // ###############################################################################################
+
+ private static String toString(InputStream inputStream) throws IOException {
+ StringBuilder sb = new StringBuilder();
+ BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream, StandardCharsets.UTF_8));
+ int i = bufferedReader.read();
+ while (i != -1) {
+ sb.append((char) i);
+ i = bufferedReader.read();
+ }
+ bufferedReader.close();
+ return sb.toString();
+ }
+}
--- a/test/jdk/sun/security/pkcs11/Cipher/TestKATForGCM.java Mon Sep 30 21:16:42 2019 +0200
+++ b/test/jdk/sun/security/pkcs11/Cipher/TestKATForGCM.java Tue Oct 01 18:47:30 2019 +0200
@@ -30,12 +30,13 @@
* @summary Known Answer Test for AES cipher with GCM mode support in
* PKCS11 provider.
*/
-import java.security.*;
-import javax.crypto.*;
-import javax.crypto.spec.*;
-import java.math.*;
-
-import java.util.*;
+import java.security.GeneralSecurityException;
+import java.security.Provider;
+import java.util.Arrays;
+import javax.crypto.Cipher;
+import javax.crypto.SecretKey;
+import javax.crypto.spec.GCMParameterSpec;
+import javax.crypto.spec.SecretKeySpec;
public class TestKATForGCM extends PKCS11Test {
@@ -319,15 +320,21 @@
System.out.println("Test Passed!");
}
} catch (Exception e) {
- double ver = getNSSInfo("nss");
- if (ver < 3.251d && p.getName().contains("SunPKCS11-NSS") &&
- System.getProperty("os.name").equals("SunOS")) {
- // buggy behaviour from solaris on 11.2 OS (nss < 3.251)
- System.out.println("Skipping: SunPKCS11-NSS: Old NSS: " + ver);
- return; // OK
- } else {
- throw e;
+ System.out.println("Exception occured using " + p.getName() + " version " + p.getVersionStr());
+
+ if (isNSS(p)) {
+ double ver = getNSSInfo("nss");
+ String osName = System.getProperty("os.name");
+ if (ver < 3.251d && osName.equals("SunOS")) {
+ // buggy behaviour from solaris on 11.2 OS (nss < 3.251)
+ System.out.println("Skipping: SunPKCS11-NSS: Old NSS: " + ver);
+ return; // OK
+ } else if (ver > 3.139 && ver < 3.15 && osName.equals("Linux")) {
+ // warn about buggy behaviour on Linux with nss 3.14
+ System.out.println("Warning: old NSS " + ver + " might be problematic, consider upgrading it");
+ }
}
+ throw e;
}
}
}
--- a/test/jtreg-ext/requires/VMProps.java Mon Sep 30 21:16:42 2019 +0200
+++ b/test/jtreg-ext/requires/VMProps.java Tue Oct 01 18:47:30 2019 +0200
@@ -235,7 +235,22 @@
*/
protected String vmJvmci() {
// builds with jvmci have this flag
- return "" + (WB.getBooleanVMFlag("EnableJVMCI") != null);
+ if (WB.getBooleanVMFlag("EnableJVMCI") == null) {
+ return "false";
+ }
+
+ switch (GC.selected()) {
+ case Serial:
+ case Parallel:
+ case G1:
+ // These GCs are supported with JVMCI
+ return "true";
+ default:
+ break;
+ }
+
+ // Every other GC is not supported
+ return "false";
}
/**
@@ -356,7 +371,24 @@
} else {
jaotc = bin.resolve("jaotc");
}
- return "" + Files.exists(jaotc);
+
+ if (!Files.exists(jaotc)) {
+ // No jaotc => no AOT
+ return "false";
+ }
+
+ switch (GC.selected()) {
+ case Serial:
+ case Parallel:
+ case G1:
+ // These GCs are supported with AOT
+ return "true";
+ default:
+ break;
+ }
+
+ // Every other GC is not supported
+ return "false";
}
/*
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/micro/org/openjdk/bench/java/math/FpRoundingBenchmark.java Tue Oct 01 18:47:30 2019 +0200
@@ -0,0 +1,78 @@
+//
+// Copyright (c) 2003, 2019, Oracle and/or its affiliates. All rights reserved.
+// DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+//
+// This code is free software; you can redistribute it and/or modify it
+// under the terms of the GNU General Public License version 2 only, as
+// published by the Free Software Foundation.
+//
+// This code is distributed in the hope that it will be useful, but WITHOUT
+// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+// version 2 for more details (a copy is included in the LICENSE file that
+// accompanied this code).
+//
+// You should have received a copy of the GNU General Public License version
+// 2 along with this work; if not, write to the Free Software Foundation,
+// Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+// or visit www.oracle.com if you need additional information or have any
+// questions.
+//
+//
+package org.openjdk.bench.java.math;
+
+import java.util.Random;
+import java.util.concurrent.TimeUnit;
+import org.openjdk.jmh.annotations.*;
+import org.openjdk.jmh.infra.Blackhole;
+
+@OutputTimeUnit(TimeUnit.MILLISECONDS)
+@State(Scope.Thread)
+public class FpRoundingBenchmark {
+
+ @Param({"1024"})
+ public int TESTSIZE;
+
+ public double[] DargV1;
+
+ public double[] Res;
+
+ public final double[] DspecialVals = {
+ 0.0, -0.0, Double.NaN, Double.NEGATIVE_INFINITY, Double.POSITIVE_INFINITY};
+
+ @Setup(Level.Trial)
+ public void BmSetup() {
+ int i = 0;
+ Random r = new Random(1024);
+ DargV1 = new double[TESTSIZE];
+ Res = new double[TESTSIZE];
+
+ for (; i < DspecialVals.length; i++) {
+ DargV1[i] = DspecialVals[i];
+ }
+
+ for (; i < TESTSIZE; i++) {
+ DargV1[i] = r.nextDouble()*TESTSIZE;
+ }
+ }
+
+ @Benchmark
+ public void testceil(Blackhole bh) {
+ for (int i = 0; i < TESTSIZE; i++)
+ Res[i] = Math.ceil(DargV1[i]);
+ }
+
+ @Benchmark
+ public void testfloor(Blackhole bh) {
+ for (int i = 0; i < TESTSIZE; i++)
+ Res[i] = Math.floor(DargV1[i]);
+ }
+
+ @Benchmark
+ public void testrint(Blackhole bh) {
+ for (int i = 0; i < TESTSIZE; i++)
+ Res[i] = Math.rint(DargV1[i]);
+ }
+}