From aff41433b6c615811ae6800c25cc16454b546791 Mon Sep 17 00:00:00 2001 From: Tobias Hartmann Date: Tue, 3 Dec 2019 08:29:04 +0100 Subject: [PATCH 01/81] 8234617: C1: Incorrect result of field load due to missing narrowing conversion Emit an explicit conversion to get the correct field value after the write. Reviewed-by: vlivanov, mdoerr --- src/hotspot/share/c1/c1_GraphBuilder.cpp | 17 +++ .../compiler/conversions/Conversion.jasm | 130 ++++++++++++++++++ .../conversions/TestPrimitiveConversions.java | 60 ++++++++ 3 files changed, 207 insertions(+) create mode 100644 test/hotspot/jtreg/compiler/conversions/Conversion.jasm create mode 100644 test/hotspot/jtreg/compiler/conversions/TestPrimitiveConversions.java diff --git a/src/hotspot/share/c1/c1_GraphBuilder.cpp b/src/hotspot/share/c1/c1_GraphBuilder.cpp index 567fd3697e9..68ab481204b 100644 --- a/src/hotspot/share/c1/c1_GraphBuilder.cpp +++ b/src/hotspot/share/c1/c1_GraphBuilder.cpp @@ -1725,6 +1725,23 @@ void GraphBuilder::access_field(Bytecodes::Code code) { Value replacement = !needs_patching ? _memory->load(load) : load; if (replacement != load) { assert(replacement->is_linked() || !replacement->can_be_linked(), "should already by linked"); + // Writing an (integer) value to a boolean, byte, char or short field includes an implicit narrowing + // conversion. Emit an explicit conversion here to get the correct field value after the write. + BasicType bt = field->type()->basic_type(); + switch (bt) { + case T_BOOLEAN: + case T_BYTE: + replacement = append(new Convert(Bytecodes::_i2b, replacement, as_ValueType(bt))); + break; + case T_CHAR: + replacement = append(new Convert(Bytecodes::_i2c, replacement, as_ValueType(bt))); + break; + case T_SHORT: + replacement = append(new Convert(Bytecodes::_i2s, replacement, as_ValueType(bt))); + break; + default: + break; + } push(type, replacement); } else { push(type, append(load)); diff --git a/test/hotspot/jtreg/compiler/conversions/Conversion.jasm b/test/hotspot/jtreg/compiler/conversions/Conversion.jasm new file mode 100644 index 00000000000..3ddd7a78389 --- /dev/null +++ b/test/hotspot/jtreg/compiler/conversions/Conversion.jasm @@ -0,0 +1,130 @@ +/* + * 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. + */ + +package compiler/conversions; + +public class Conversion + version 52:0 +{ + Field booleanFld:Z; + Field byteFld:B; + Field charFld:C; + Field shortFld:S; + Field intFld:I; + + public Method "":"()V" + stack 1 locals 1 + { + aload_0; + invokespecial Method java/lang/Object."":"()V"; + return; + } + + public Method testBooleanConst:"()I" + stack 5 locals 1 + { + aload_0; + ldc_w int 2; // 2^1 (maximum boolean value is 1) + putfield Field booleanFld:"Z"; + aload_0; + getfield Field booleanFld:"Z"; + ireturn; + } + + public Method testBoolean:"(I)I" + stack 5 locals 2 + { + aload_0; + iload_1; + putfield Field booleanFld:"Z"; + aload_0; + getfield Field booleanFld:"Z"; + ireturn; + } + + public Method testByteConst:"()I" + stack 5 locals 1 + { + aload_0; + ldc_w int 256; // 2^8 (maximum byte value is 2^7-1) + putfield Field byteFld:"B"; + aload_0; + getfield Field byteFld:"B"; + ireturn; + } + + public Method testByte:"(I)I" + stack 5 locals 2 + { + aload_0; + iload_1; + putfield Field byteFld:"B"; + aload_0; + getfield Field byteFld:"B"; + ireturn; + } + + public Method testCharConst:"()I" + stack 5 locals 1 + { + aload_0; + ldc_w int 131072; // 2^17 (maximum char value is 2^16-1) + putfield Field charFld:"C"; + aload_0; + getfield Field charFld:"C"; + ireturn; + } + + public Method testChar:"(I)I" + stack 5 locals 2 + { + aload_0; + iload_1; + putfield Field charFld:"C"; + aload_0; + getfield Field charFld:"C"; + ireturn; + } + + public Method testShortConst:"()I" + stack 5 locals 1 + { + aload_0; + ldc_w int 65536; // 2^16 (maximum short value is 2^15-1) + putfield Field shortFld:"S"; + aload_0; + getfield Field shortFld:"S"; + ireturn; + } + + public Method testShort:"(I)I" + stack 5 locals 2 + { + aload_0; + iload_1; + putfield Field shortFld:"S"; + aload_0; + getfield Field shortFld:"S"; + ireturn; + } +} diff --git a/test/hotspot/jtreg/compiler/conversions/TestPrimitiveConversions.java b/test/hotspot/jtreg/compiler/conversions/TestPrimitiveConversions.java new file mode 100644 index 00000000000..9995de59f52 --- /dev/null +++ b/test/hotspot/jtreg/compiler/conversions/TestPrimitiveConversions.java @@ -0,0 +1,60 @@ +/* + * 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. + */ + +package compiler.conversions; + +import jdk.test.lib.Asserts; + +/* + * @test + * @bug 8234617 + * @summary Test implicit narrowing conversion of primivite values at putfield. + * @library /test/lib / + * @compile Conversion.jasm + * @run main/othervm -Xbatch -XX:CompileCommand=dontinline,compiler.conversions.Conversion::* + * compiler.conversions.TestPrimitiveConversions + */ +public class TestPrimitiveConversions { + + public static void main(String[] args) { + Conversion conv = new Conversion(); + for (int i = 0; i < 100_000; ++i) { + int res = conv.testBooleanConst(); + Asserts.assertEquals(res, 0); + res = conv.testBoolean(2); // 2^1 (maximum boolean value is 1) + Asserts.assertEquals(res, 0); + res = conv.testByteConst(); + Asserts.assertEquals(res, 0); + res = conv.testByte(256); // 2^8 (maximum byte value is 2^7-1) + Asserts.assertEquals(res, 0); + res = conv.testCharConst(); + Asserts.assertEquals(res, 0); + res = conv.testChar(131072); // 2^17 (maximum char value is 2^16-1) + Asserts.assertEquals(res, 0); + res = conv.testShortConst(); + Asserts.assertEquals(res, 0); + res = conv.testShort(65536); // 2^16 (maximum short value is 2^15-1) + Asserts.assertEquals(res, 0); + } + } +} From 802580b236f1104f50ce530712e00e3fcf969cea Mon Sep 17 00:00:00 2001 From: Stefan Karlsson Date: Tue, 3 Dec 2019 10:40:58 +0100 Subject: [PATCH 02/81] 8234822: Limit ZGC jtreg-support to Windows 2019 Server Reviewed-by: iignatyev, eosterlund --- test/lib/sun/hotspot/gc/GC.java | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/test/lib/sun/hotspot/gc/GC.java b/test/lib/sun/hotspot/gc/GC.java index 19fb51f26d1..d0c8fdace8a 100644 --- a/test/lib/sun/hotspot/gc/GC.java +++ b/test/lib/sun/hotspot/gc/GC.java @@ -48,11 +48,28 @@ public enum GC { this.name = name; } + private boolean supportsOSVersion() { + if (this != Z) { + return true; + } + + String osName = System.getProperty("os.name"); + + if (!osName.startsWith("Windows")) { + return true; + } + + // ZGC has specific Windows version requirements (>= 1803). + // The following check should be made more precise to + // also catch the corresponding Windows 10 version. + return osName.equals("Windows Server 2019"); + } + /** * @return true if this GC is supported by the VM, i.e., it is built into the VM. */ public boolean isSupported() { - return WB.isGCSupported(name); + return WB.isGCSupported(name) && supportsOSVersion(); } /** From 6ba58f76335a309d7fd729153a59822f6d931e80 Mon Sep 17 00:00:00 2001 From: Stefan Karlsson Date: Thu, 7 Nov 2019 15:29:21 +0100 Subject: [PATCH 03/81] 8233299: Implementation: JEP 365: ZGC on Windows Reviewed-by: pliden, eosterlund --- make/autoconf/hotspot.m4 | 3 +- .../cpu/x86/gc/z/zBarrierSetAssembler_x86.cpp | 5 +- .../os/windows/gc/z/zBackingFile_windows.cpp | 126 +++++++++ .../os/windows/gc/z/zBackingFile_windows.hpp | 56 ++++ .../os/windows/gc/z/zInitialize_windows.cpp | 30 +++ .../os/windows/gc/z/zLargePages_windows.cpp | 29 ++ .../os/windows/gc/z/zMapper_windows.cpp | 254 ++++++++++++++++++ .../os/windows/gc/z/zMapper_windows.hpp | 85 ++++++ src/hotspot/os/windows/gc/z/zNUMA_windows.cpp | 42 +++ .../gc/z/zPhysicalMemoryBacking_windows.cpp | 212 +++++++++++++++ .../gc/z/zPhysicalMemoryBacking_windows.hpp | 63 +++++ .../os/windows/gc/z/zSyscall_windows.cpp | 58 ++++ .../os/windows/gc/z/zSyscall_windows.hpp | 50 ++++ .../os/windows/gc/z/zUtils_windows.cpp | 40 +++ .../windows/gc/z/zVirtualMemory_windows.cpp | 149 ++++++++++ 15 files changed, 1200 insertions(+), 2 deletions(-) create mode 100644 src/hotspot/os/windows/gc/z/zBackingFile_windows.cpp create mode 100644 src/hotspot/os/windows/gc/z/zBackingFile_windows.hpp create mode 100644 src/hotspot/os/windows/gc/z/zInitialize_windows.cpp create mode 100644 src/hotspot/os/windows/gc/z/zLargePages_windows.cpp create mode 100644 src/hotspot/os/windows/gc/z/zMapper_windows.cpp create mode 100644 src/hotspot/os/windows/gc/z/zMapper_windows.hpp create mode 100644 src/hotspot/os/windows/gc/z/zNUMA_windows.cpp create mode 100644 src/hotspot/os/windows/gc/z/zPhysicalMemoryBacking_windows.cpp create mode 100644 src/hotspot/os/windows/gc/z/zPhysicalMemoryBacking_windows.hpp create mode 100644 src/hotspot/os/windows/gc/z/zSyscall_windows.cpp create mode 100644 src/hotspot/os/windows/gc/z/zSyscall_windows.hpp create mode 100644 src/hotspot/os/windows/gc/z/zUtils_windows.cpp create mode 100644 src/hotspot/os/windows/gc/z/zVirtualMemory_windows.cpp diff --git a/make/autoconf/hotspot.m4 b/make/autoconf/hotspot.m4 index f340faebd39..649e48cb675 100644 --- a/make/autoconf/hotspot.m4 +++ b/make/autoconf/hotspot.m4 @@ -347,7 +347,8 @@ AC_DEFUN_ONCE([HOTSPOT_SETUP_JVM_FEATURES], # Only enable ZGC on supported platforms AC_MSG_CHECKING([if zgc can be built]) if (test "x$OPENJDK_TARGET_OS" = "xlinux" && test "x$OPENJDK_TARGET_CPU" = "xx86_64") || \ - (test "x$OPENJDK_TARGET_OS" = "xlinux" && test "x$OPENJDK_TARGET_CPU" = "xaarch64") || + (test "x$OPENJDK_TARGET_OS" = "xlinux" && test "x$OPENJDK_TARGET_CPU" = "xaarch64") || \ + (test "x$OPENJDK_TARGET_OS" = "xwindows" && test "x$OPENJDK_TARGET_CPU" = "xx86_64") || \ (test "x$OPENJDK_TARGET_OS" = "xmacosx" && test "x$OPENJDK_TARGET_CPU" = "xx86_64"); then AC_MSG_RESULT([yes]) else diff --git a/src/hotspot/cpu/x86/gc/z/zBarrierSetAssembler_x86.cpp b/src/hotspot/cpu/x86/gc/z/zBarrierSetAssembler_x86.cpp index 34f3ceaeee6..13883f18d82 100644 --- a/src/hotspot/cpu/x86/gc/z/zBarrierSetAssembler_x86.cpp +++ b/src/hotspot/cpu/x86/gc/z/zBarrierSetAssembler_x86.cpp @@ -517,8 +517,11 @@ private: // Sort by size, largest first _xmm_registers.sort(xmm_compare_register_size); + // On Windows, the caller reserves stack space for spilling register arguments + const int arg_spill_size = frame::arg_reg_save_area_bytes; + // Stack pointer must be 16 bytes aligned for the call - _spill_offset = _spill_size = align_up(xmm_spill_size + gp_spill_size, 16); + _spill_offset = _spill_size = align_up(xmm_spill_size + gp_spill_size + arg_spill_size, 16); } public: diff --git a/src/hotspot/os/windows/gc/z/zBackingFile_windows.cpp b/src/hotspot/os/windows/gc/z/zBackingFile_windows.cpp new file mode 100644 index 00000000000..899c190bb5a --- /dev/null +++ b/src/hotspot/os/windows/gc/z/zBackingFile_windows.cpp @@ -0,0 +1,126 @@ +/* + * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +#include "precompiled.hpp" +#include "gc/z/zBackingFile_windows.hpp" +#include "gc/z/zGlobals.hpp" +#include "gc/z/zGranuleMap.inline.hpp" +#include "gc/z/zMapper_windows.hpp" +#include "logging/log.hpp" +#include "runtime/globals.hpp" +#include "utilities/debug.hpp" + +// The backing file commits and uncommits physical memory, that can be +// multi-mapped into the virtual address space. To support fine-graned +// committing and uncommitting, each ZGranuleSize chunked is mapped to +// a separate paging file mapping. + +ZBackingFile::ZBackingFile() : + _handles(MaxHeapSize), + _size(0) {} + +size_t ZBackingFile::size() const { + return _size; +} + +HANDLE ZBackingFile::get_handle(uintptr_t offset) const { + HANDLE const handle = _handles.get(offset); + assert(handle != 0, "Should be set"); + return handle; +} + +void ZBackingFile::put_handle(uintptr_t offset, HANDLE handle) { + assert(handle != INVALID_HANDLE_VALUE, "Invalid handle"); + assert(_handles.get(offset) == 0, "Should be cleared"); + _handles.put(offset, handle); +} + +void ZBackingFile::clear_handle(uintptr_t offset) { + assert(_handles.get(offset) != 0, "Should be set"); + _handles.put(offset, 0); +} + +size_t ZBackingFile::commit_from_paging_file(size_t offset, size_t size) { + for (size_t i = 0; i < size; i += ZGranuleSize) { + HANDLE const handle = ZMapper::create_and_commit_paging_file_mapping(ZGranuleSize); + if (handle == 0) { + return i; + } + + put_handle(offset + i, handle); + } + + return size; +} + +size_t ZBackingFile::uncommit_from_paging_file(size_t offset, size_t size) { + for (size_t i = 0; i < size; i += ZGranuleSize) { + HANDLE const handle = get_handle(offset + i); + clear_handle(offset + i); + ZMapper::close_paging_file_mapping(handle); + } + + return size; +} + +size_t ZBackingFile::commit(size_t offset, size_t length) { + log_trace(gc, heap)("Committing memory: " SIZE_FORMAT "M-" SIZE_FORMAT "M (" SIZE_FORMAT "M)", + offset / M, (offset + length) / M, length / M); + + const size_t committed = commit_from_paging_file(offset, length); + + const size_t end = offset + committed; + if (end > _size) { + // Update size + _size = end; + } + + return committed; +} + +size_t ZBackingFile::uncommit(size_t offset, size_t length) { + log_trace(gc, heap)("Uncommitting memory: " SIZE_FORMAT "M-" SIZE_FORMAT "M (" SIZE_FORMAT "M)", + offset / M, (offset + length) / M, length / M); + + return uncommit_from_paging_file(offset, length); +} + +void ZBackingFile::map(uintptr_t addr, size_t size, size_t offset) const { + assert(is_aligned(offset, ZGranuleSize), "Misaligned"); + assert(is_aligned(addr, ZGranuleSize), "Misaligned"); + assert(is_aligned(size, ZGranuleSize), "Misaligned"); + + for (size_t i = 0; i < size; i += ZGranuleSize) { + HANDLE const handle = get_handle(offset + i); + ZMapper::map_view_replace_placeholder(handle, 0 /* offset */, addr + i, ZGranuleSize); + } +} + +void ZBackingFile::unmap(uintptr_t addr, size_t size) const { + assert(is_aligned(addr, ZGranuleSize), "Misaligned"); + assert(is_aligned(size, ZGranuleSize), "Misaligned"); + + for (size_t i = 0; i < size; i += ZGranuleSize) { + ZMapper::unmap_view_preserve_placeholder(addr + i, ZGranuleSize); + } +} diff --git a/src/hotspot/os/windows/gc/z/zBackingFile_windows.hpp b/src/hotspot/os/windows/gc/z/zBackingFile_windows.hpp new file mode 100644 index 00000000000..514a3f97f44 --- /dev/null +++ b/src/hotspot/os/windows/gc/z/zBackingFile_windows.hpp @@ -0,0 +1,56 @@ +/* + * 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. + */ + +#ifndef OS_WINDOWS_GC_Z_ZBACKINGFILE_WINDOWS_HPP +#define OS_WINDOWS_GC_Z_ZBACKINGFILE_WINDOWS_HPP + +#include "gc/z/zGranuleMap.hpp" +#include "memory/allocation.hpp" + +#include + +class ZBackingFile { +private: + ZGranuleMap _handles; + size_t _size; + + HANDLE get_handle(uintptr_t offset) const; + void put_handle(uintptr_t offset, HANDLE handle); + void clear_handle(uintptr_t offset); + + size_t commit_from_paging_file(size_t offset, size_t size); + size_t uncommit_from_paging_file(size_t offset, size_t size); + +public: + ZBackingFile(); + + size_t size() const; + + size_t commit(size_t offset, size_t length); + size_t uncommit(size_t offset, size_t length); + + void map(uintptr_t addr, size_t size, size_t offset) const; + void unmap(uintptr_t addr, size_t size) const; +}; + +#endif // OS_WINDOWS_GC_Z_ZBACKINGFILE_WINDOWS_HPP diff --git a/src/hotspot/os/windows/gc/z/zInitialize_windows.cpp b/src/hotspot/os/windows/gc/z/zInitialize_windows.cpp new file mode 100644 index 00000000000..c584f79fde4 --- /dev/null +++ b/src/hotspot/os/windows/gc/z/zInitialize_windows.cpp @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +#include "precompiled.hpp" +#include "gc/z/zInitialize.hpp" +#include "gc/z/zSyscall_windows.hpp" + +void ZInitialize::initialize_os() { + ZSyscall::initialize(); +} diff --git a/src/hotspot/os/windows/gc/z/zLargePages_windows.cpp b/src/hotspot/os/windows/gc/z/zLargePages_windows.cpp new file mode 100644 index 00000000000..231c817952b --- /dev/null +++ b/src/hotspot/os/windows/gc/z/zLargePages_windows.cpp @@ -0,0 +1,29 @@ +/* + * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +#include "precompiled.hpp" +#include "gc/z/zLargePages.hpp" + +void ZLargePages::initialize_platform() { + _state = Disabled; +} diff --git a/src/hotspot/os/windows/gc/z/zMapper_windows.cpp b/src/hotspot/os/windows/gc/z/zMapper_windows.cpp new file mode 100644 index 00000000000..d859d4c42c3 --- /dev/null +++ b/src/hotspot/os/windows/gc/z/zMapper_windows.cpp @@ -0,0 +1,254 @@ +/* + * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +#include "precompiled.hpp" +#include "gc/z/zMapper_windows.hpp" +#include "gc/z/zSyscall_windows.hpp" +#include "logging/log.hpp" +#include "utilities/debug.hpp" + +#include + +// Memory reservation, commit, views, and placeholders. +// +// To be able to up-front reserve address space for the heap views, and later +// multi-map the heap views to the same physical memory, without ever losing the +// reservation of the reserved address space, we use "placeholders". +// +// These placeholders block out the address space from being used by other parts +// of the process. To commit memory in this address space, the placeholder must +// be replaced by anonymous memory, or replaced by mapping a view against a +// paging file mapping. We use the later to support multi-mapping. +// +// We want to be able to dynamically commit and uncommit the physical memory of +// the heap (and also unmap ZPages), in granules of ZGranuleSize bytes. There is +// no way to grow and shrink the committed memory of a paging file mapping. +// Therefore, we create multiple granule-sized page file mappings. The memory is +// committed by creating a page file mapping, map a view against it, commit the +// memory, unmap the view. The memory will stay committed until all views are +// unmapped, and the paging file mapping handle is closed. +// +// When replacing a placeholder address space reservation with a mapped view +// against a paging file mapping, the virtual address space must exactly match +// an existing placeholder's address and size. Therefore we only deal with +// granule-sized placeholders at this layer. Higher layers that keep track of +// reserved available address space can (and will) coalesce placeholders, but +// they will be split before being used. + +#define fatal_error(msg, addr, size) \ + fatal(msg ": " PTR_FORMAT " " SIZE_FORMAT "M (%d)", \ + (addr), (size) / M, GetLastError()) + +uintptr_t ZMapper::reserve(uintptr_t addr, size_t size) { + void* const res = ZSyscall::VirtualAlloc2( + GetCurrentProcess(), // Process + (void*)addr, // BaseAddress + size, // Size + MEM_RESERVE | MEM_RESERVE_PLACEHOLDER, // AllocationType + PAGE_NOACCESS, // PageProtection + NULL, // ExtendedParameters + 0 // ParameterCount + ); + + // Caller responsible for error handling + return (uintptr_t)res; +} + +void ZMapper::unreserve(uintptr_t addr, size_t size) { + const bool res = ZSyscall::VirtualFreeEx( + GetCurrentProcess(), // hProcess + (void*)addr, // lpAddress + size, // dwSize + MEM_RELEASE // dwFreeType + ); + + if (!res) { + fatal_error("Failed to unreserve memory", addr, size); + } +} + +HANDLE ZMapper::create_paging_file_mapping(size_t size) { + // Create mapping with SEC_RESERVE instead of SEC_COMMIT. + // + // We use MapViewOfFile3 for two different reasons: + // 1) When commiting memory for the created paging file + // 2) When mapping a view of the memory created in (2) + // + // The non-platform code is only setup to deal with out-of-memory + // errors in (1). By using SEC_RESERVE, we prevent MapViewOfFile3 + // from failing because of "commit limit" checks. To actually commit + // memory in (1), a call to VirtualAlloc2 is done. + + HANDLE const res = ZSyscall::CreateFileMappingW( + INVALID_HANDLE_VALUE, // hFile + NULL, // lpFileMappingAttribute + PAGE_READWRITE | SEC_RESERVE, // flProtect + size >> 32, // dwMaximumSizeHigh + size & 0xFFFFFFFF, // dwMaximumSizeLow + NULL // lpName + ); + + // Caller responsible for error handling + return res; +} + +bool ZMapper::commit_paging_file_mapping(HANDLE file_handle, uintptr_t file_offset, size_t size) { + const uintptr_t addr = map_view_no_placeholder(file_handle, file_offset, size); + if (addr == 0) { + log_error(gc)("Failed to map view of paging file mapping (%d)", GetLastError()); + return false; + } + + const uintptr_t res = commit(addr, size); + if (res != addr) { + log_error(gc)("Failed to commit memory (%d)", GetLastError()); + } + + unmap_view_no_placeholder(addr, size); + + return res == addr; +} + +uintptr_t ZMapper::map_view_no_placeholder(HANDLE file_handle, uintptr_t file_offset, size_t size) { + void* const res = ZSyscall::MapViewOfFile3( + file_handle, // FileMapping + GetCurrentProcess(), // ProcessHandle + NULL, // BaseAddress + file_offset, // Offset + size, // ViewSize + 0, // AllocationType + PAGE_NOACCESS, // PageProtection + NULL, // ExtendedParameters + 0 // ParameterCount + ); + + // Caller responsible for error handling + return (uintptr_t)res; +} + +void ZMapper::unmap_view_no_placeholder(uintptr_t addr, size_t size) { + const bool res = ZSyscall::UnmapViewOfFile2( + GetCurrentProcess(), // ProcessHandle + (void*)addr, // BaseAddress + 0 // UnmapFlags + ); + + if (!res) { + fatal_error("Failed to unmap memory", addr, size); + } +} + +uintptr_t ZMapper::commit(uintptr_t addr, size_t size) { + void* const res = ZSyscall::VirtualAlloc2( + GetCurrentProcess(), // Process + (void*)addr, // BaseAddress + size, // Size + MEM_COMMIT, // AllocationType + PAGE_NOACCESS, // PageProtection + NULL, // ExtendedParameters + 0 // ParameterCount + ); + + // Caller responsible for error handling + return (uintptr_t)res; +} + +HANDLE ZMapper::create_and_commit_paging_file_mapping(size_t size) { + HANDLE const file_handle = create_paging_file_mapping(size); + if (file_handle == 0) { + log_error(gc)("Failed to create paging file mapping (%d)", GetLastError()); + return 0; + } + + const bool res = commit_paging_file_mapping(file_handle, 0 /* file_offset */, size); + if (!res) { + close_paging_file_mapping(file_handle); + return 0; + } + + return file_handle; +} + +void ZMapper::close_paging_file_mapping(HANDLE file_handle) { + const bool res = CloseHandle( + file_handle // hObject + ); + + if (!res) { + fatal("Failed to close paging file handle (%d)", GetLastError()); + } +} + +void ZMapper::split_placeholder(uintptr_t addr, size_t size) { + const bool res = VirtualFree( + (void*)addr, // lpAddress + size, // dwSize + MEM_RELEASE | MEM_PRESERVE_PLACEHOLDER // dwFreeType + ); + + if (!res) { + fatal_error("Failed to split placeholder", addr, size); + } +} + +void ZMapper::coalesce_placeholders(uintptr_t addr, size_t size) { + const bool res = VirtualFree( + (void*)addr, // lpAddress + size, // dwSize + MEM_RELEASE | MEM_COALESCE_PLACEHOLDERS // dwFreeType + ); + + if (!res) { + fatal_error("Failed to coalesce placeholders", addr, size); + } +} + +void ZMapper::map_view_replace_placeholder(HANDLE file_handle, uintptr_t file_offset, uintptr_t addr, size_t size) { + void* const res = ZSyscall::MapViewOfFile3( + file_handle, // FileMapping + GetCurrentProcess(), // ProcessHandle + (void*)addr, // BaseAddress + file_offset, // Offset + size, // ViewSize + MEM_REPLACE_PLACEHOLDER, // AllocationType + PAGE_READWRITE, // PageProtection + NULL, // ExtendedParameters + 0 // ParameterCount + ); + + if (res == NULL) { + fatal_error("Failed to map memory", addr, size); + } +} + +void ZMapper::unmap_view_preserve_placeholder(uintptr_t addr, size_t size) { + const bool res = ZSyscall::UnmapViewOfFile2( + GetCurrentProcess(), // ProcessHandle + (void*)addr, // BaseAddress + MEM_PRESERVE_PLACEHOLDER // UnmapFlags + ); + + if (!res) { + fatal_error("Failed to unmap memory", addr, size); + } +} diff --git a/src/hotspot/os/windows/gc/z/zMapper_windows.hpp b/src/hotspot/os/windows/gc/z/zMapper_windows.hpp new file mode 100644 index 00000000000..005263ad9f4 --- /dev/null +++ b/src/hotspot/os/windows/gc/z/zMapper_windows.hpp @@ -0,0 +1,85 @@ +/* + * 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. + */ + +#ifndef OS_WINDOWS_GC_Z_ZMAPPER_WINDOWS_HPP +#define OS_WINDOWS_GC_Z_ZMAPPER_WINDOWS_HPP + +#include "memory/allocation.hpp" +#include "utilities/globalDefinitions.hpp" + +#include + +class ZMapper : public AllStatic { +private: + // Create paging file mapping + static HANDLE create_paging_file_mapping(size_t size); + + // Commit paging file mapping + static bool commit_paging_file_mapping(HANDLE file_handle, uintptr_t file_offset, size_t size); + + // Map a view anywhere without a placeholder + static uintptr_t map_view_no_placeholder(HANDLE file_handle, uintptr_t file_offset, size_t size); + + // Unmap a view without preserving a placeholder + static void unmap_view_no_placeholder(uintptr_t addr, size_t size); + + // Commit memory covering the given virtual address range + static uintptr_t commit(uintptr_t addr, size_t size); + +public: + // Reserve memory with a placeholder + static uintptr_t reserve(uintptr_t addr, size_t size); + + // Unreserve memory + static void unreserve(uintptr_t addr, size_t size); + + // Create and commit paging file mapping + static HANDLE create_and_commit_paging_file_mapping(size_t size); + + // Close paging file mapping + static void close_paging_file_mapping(HANDLE file_handle); + + // Split a placeholder + // + // A view can only replace an entire placeholder, so placeholders need to be + // split and coalesced to be the exact size of the new views. + // [addr, addr + size) needs to be a proper sub-placeholder of an existing + // placeholder. + static void split_placeholder(uintptr_t addr, size_t size); + + // Coalesce a placeholder + // + // [addr, addr + size) is the new placeholder. A sub-placeholder needs to + // exist within that range. + static void coalesce_placeholders(uintptr_t addr, size_t size); + + // Map a view of the file handle and replace the placeholder covering the + // given virtual address range + static void map_view_replace_placeholder(HANDLE file_handle, uintptr_t file_offset, uintptr_t addr, size_t size); + + // Unmap the view and reinstate a placeholder covering the given virtual + // address range + static void unmap_view_preserve_placeholder(uintptr_t addr, size_t size); +}; + +#endif // OS_WINDOWS_GC_Z_ZMAPPER_WINDOWS_HPP diff --git a/src/hotspot/os/windows/gc/z/zNUMA_windows.cpp b/src/hotspot/os/windows/gc/z/zNUMA_windows.cpp new file mode 100644 index 00000000000..966ef9b997f --- /dev/null +++ b/src/hotspot/os/windows/gc/z/zNUMA_windows.cpp @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +#include "precompiled.hpp" +#include "gc/z/zNUMA.hpp" + +void ZNUMA::initialize_platform() { + _enabled = false; +} + +uint32_t ZNUMA::count() { + return 1; +} + +uint32_t ZNUMA::id() { + return 0; +} + +uint32_t ZNUMA::memory_id(uintptr_t addr) { + // NUMA support not enabled, assume everything belongs to node zero + return 0; +} diff --git a/src/hotspot/os/windows/gc/z/zPhysicalMemoryBacking_windows.cpp b/src/hotspot/os/windows/gc/z/zPhysicalMemoryBacking_windows.cpp new file mode 100644 index 00000000000..87675e2e14f --- /dev/null +++ b/src/hotspot/os/windows/gc/z/zPhysicalMemoryBacking_windows.cpp @@ -0,0 +1,212 @@ +/* + * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +#include "precompiled.hpp" +#include "gc/z/zAddress.inline.hpp" +#include "gc/z/zGlobals.hpp" +#include "gc/z/zLargePages.inline.hpp" +#include "gc/z/zMapper_windows.hpp" +#include "gc/z/zPhysicalMemory.inline.hpp" +#include "gc/z/zPhysicalMemoryBacking_windows.hpp" +#include "runtime/globals.hpp" +#include "runtime/init.hpp" +#include "runtime/os.hpp" +#include "utilities/align.hpp" +#include "utilities/debug.hpp" + +bool ZPhysicalMemoryBacking::is_initialized() const { + return true; +} + +void ZPhysicalMemoryBacking::warn_commit_limits(size_t max) const { + // Does nothing +} + +bool ZPhysicalMemoryBacking::supports_uncommit() { + assert(!is_init_completed(), "Invalid state"); + assert(_file.size() >= ZGranuleSize, "Invalid size"); + + // Test if uncommit is supported by uncommitting and then re-committing a granule + return commit(uncommit(ZGranuleSize)) == ZGranuleSize; +} + +size_t ZPhysicalMemoryBacking::commit(size_t size) { + size_t committed = 0; + + // Fill holes in the backing file + while (committed < size) { + size_t allocated = 0; + const size_t remaining = size - committed; + const uintptr_t start = _uncommitted.alloc_from_front_at_most(remaining, &allocated); + if (start == UINTPTR_MAX) { + // No holes to commit + break; + } + + // Try commit hole + const size_t filled = _file.commit(start, allocated); + if (filled > 0) { + // Successful or partialy successful + _committed.free(start, filled); + committed += filled; + } + if (filled < allocated) { + // Failed or partialy failed + _uncommitted.free(start + filled, allocated - filled); + return committed; + } + } + + // Expand backing file + if (committed < size) { + const size_t remaining = size - committed; + const uintptr_t start = _file.size(); + const size_t expanded = _file.commit(start, remaining); + if (expanded > 0) { + // Successful or partialy successful + _committed.free(start, expanded); + committed += expanded; + } + } + + return committed; +} + +size_t ZPhysicalMemoryBacking::uncommit(size_t size) { + size_t uncommitted = 0; + + // Punch holes in backing file + while (uncommitted < size) { + size_t allocated = 0; + const size_t remaining = size - uncommitted; + const uintptr_t start = _committed.alloc_from_back_at_most(remaining, &allocated); + assert(start != UINTPTR_MAX, "Allocation should never fail"); + + // Try punch hole + const size_t punched = _file.uncommit(start, allocated); + if (punched > 0) { + // Successful or partialy successful + _uncommitted.free(start, punched); + uncommitted += punched; + } + if (punched < allocated) { + // Failed or partialy failed + _committed.free(start + punched, allocated - punched); + return uncommitted; + } + } + + return uncommitted; +} + +ZPhysicalMemory ZPhysicalMemoryBacking::alloc(size_t size) { + assert(is_aligned(size, ZGranuleSize), "Invalid size"); + + ZPhysicalMemory pmem; + + // Allocate segments + for (size_t allocated = 0; allocated < size; allocated += ZGranuleSize) { + const uintptr_t start = _committed.alloc_from_front(ZGranuleSize); + assert(start != UINTPTR_MAX, "Allocation should never fail"); + pmem.add_segment(ZPhysicalMemorySegment(start, ZGranuleSize)); + } + + return pmem; +} + +void ZPhysicalMemoryBacking::free(const ZPhysicalMemory& pmem) { + const size_t nsegments = pmem.nsegments(); + + // Free segments + for (size_t i = 0; i < nsegments; i++) { + const ZPhysicalMemorySegment& segment = pmem.segment(i); + _committed.free(segment.start(), segment.size()); + } +} + +void ZPhysicalMemoryBacking::pretouch_view(uintptr_t addr, size_t size) const { + const size_t page_size = ZLargePages::is_explicit() ? os::large_page_size() : os::vm_page_size(); + os::pretouch_memory((void*)addr, (void*)(addr + size), page_size); +} + +void ZPhysicalMemoryBacking::map_view(const ZPhysicalMemory& pmem, uintptr_t addr, bool pretouch) const { + const size_t nsegments = pmem.nsegments(); + size_t size = 0; + + // Map segments + for (size_t i = 0; i < nsegments; i++) { + const ZPhysicalMemorySegment& segment = pmem.segment(i); + _file.map(addr + size, segment.size(), segment.start()); + size += segment.size(); + } + + // Pre-touch memory + if (pretouch) { + pretouch_view(addr, size); + } +} + +void ZPhysicalMemoryBacking::unmap_view(const ZPhysicalMemory& pmem, uintptr_t addr) const { + _file.unmap(addr, pmem.size()); +} + +uintptr_t ZPhysicalMemoryBacking::nmt_address(uintptr_t offset) const { + // From an NMT point of view we treat the first heap view (marked0) as committed + return ZAddress::marked0(offset); +} + +void ZPhysicalMemoryBacking::map(const ZPhysicalMemory& pmem, uintptr_t offset) const { + if (ZVerifyViews) { + // Map good view + map_view(pmem, ZAddress::good(offset), AlwaysPreTouch); + } else { + // Map all views + map_view(pmem, ZAddress::marked0(offset), AlwaysPreTouch); + map_view(pmem, ZAddress::marked1(offset), AlwaysPreTouch); + map_view(pmem, ZAddress::remapped(offset), AlwaysPreTouch); + } +} + +void ZPhysicalMemoryBacking::unmap(const ZPhysicalMemory& pmem, uintptr_t offset) const { + if (ZVerifyViews) { + // Unmap good view + unmap_view(pmem, ZAddress::good(offset)); + } else { + // Unmap all views + unmap_view(pmem, ZAddress::marked0(offset)); + unmap_view(pmem, ZAddress::marked1(offset)); + unmap_view(pmem, ZAddress::remapped(offset)); + } +} + +void ZPhysicalMemoryBacking::debug_map(const ZPhysicalMemory& pmem, uintptr_t offset) const { + // Map good view + assert(ZVerifyViews, "Should be enabled"); + map_view(pmem, ZAddress::good(offset), false /* pretouch */); +} + +void ZPhysicalMemoryBacking::debug_unmap(const ZPhysicalMemory& pmem, uintptr_t offset) const { + // Unmap good view + assert(ZVerifyViews, "Should be enabled"); + unmap_view(pmem, ZAddress::good(offset)); +} diff --git a/src/hotspot/os/windows/gc/z/zPhysicalMemoryBacking_windows.hpp b/src/hotspot/os/windows/gc/z/zPhysicalMemoryBacking_windows.hpp new file mode 100644 index 00000000000..3f105d671e8 --- /dev/null +++ b/src/hotspot/os/windows/gc/z/zPhysicalMemoryBacking_windows.hpp @@ -0,0 +1,63 @@ +/* + * 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. + */ + +#ifndef OS_WINDOWS_GC_Z_ZPHYSICALMEMORYBACKING_WINDOWS_HPP +#define OS_WINDOWS_GC_Z_ZPHYSICALMEMORYBACKING_WINDOWS_HPP + +#include "gc/z/zBackingFile_windows.hpp" +#include "gc/z/zMemory.hpp" + +class ZPhysicalMemory; + +class ZPhysicalMemoryBacking { +private: + ZBackingFile _file; + ZMemoryManager _committed; + ZMemoryManager _uncommitted; + + void pretouch_view(uintptr_t addr, size_t size) const; + void map_view(const ZPhysicalMemory& pmem, uintptr_t addr, bool pretouch) const; + void unmap_view(const ZPhysicalMemory& pmem, uintptr_t addr) const; + +public: + bool is_initialized() const; + + void warn_commit_limits(size_t max) const; + bool supports_uncommit(); + + size_t commit(size_t size); + size_t uncommit(size_t size); + + ZPhysicalMemory alloc(size_t size); + void free(const ZPhysicalMemory& pmem); + + uintptr_t nmt_address(uintptr_t offset) const; + + void map(const ZPhysicalMemory& pmem, uintptr_t offset) const; + void unmap(const ZPhysicalMemory& pmem, uintptr_t offset) const; + + void debug_map(const ZPhysicalMemory& pmem, uintptr_t offset) const; + void debug_unmap(const ZPhysicalMemory& pmem, uintptr_t offset) const; +}; + +#endif // OS_WINDOWS_GC_Z_ZPHYSICALMEMORYBACKING_WINDOWS_HPP diff --git a/src/hotspot/os/windows/gc/z/zSyscall_windows.cpp b/src/hotspot/os/windows/gc/z/zSyscall_windows.cpp new file mode 100644 index 00000000000..b00e45fb962 --- /dev/null +++ b/src/hotspot/os/windows/gc/z/zSyscall_windows.cpp @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +#include "precompiled.hpp" +#include "gc/z/zSyscall_windows.hpp" +#include "logging/log.hpp" +#include "runtime/java.hpp" +#include "runtime/os.hpp" + +ZSyscall::CreateFileMappingWFn ZSyscall::CreateFileMappingW; +ZSyscall::VirtualAlloc2Fn ZSyscall::VirtualAlloc2; +ZSyscall::VirtualFreeExFn ZSyscall::VirtualFreeEx; +ZSyscall::MapViewOfFile3Fn ZSyscall::MapViewOfFile3; +ZSyscall::UnmapViewOfFile2Fn ZSyscall::UnmapViewOfFile2; + +template +static void lookup_symbol(Fn*& fn, const char* library, const char* symbol) { + char ebuf[1024]; + void* const handle = os::dll_load(library, ebuf, sizeof(ebuf)); + if (handle == NULL) { + log_error(gc)("Failed to load library: %s", library); + vm_exit_during_initialization("ZGC requires Windows version 1803 or later"); + } + + fn = reinterpret_cast(os::dll_lookup(handle, symbol)); + if (fn == NULL) { + log_error(gc)("Failed to lookup symbol: %s", symbol); + vm_exit_during_initialization("ZGC requires Windows version 1803 or later"); + } +} + +void ZSyscall::initialize() { + lookup_symbol(CreateFileMappingW, "KernelBase", "CreateFileMappingW"); + lookup_symbol(VirtualAlloc2, "KernelBase", "VirtualAlloc2"); + lookup_symbol(VirtualFreeEx, "KernelBase", "VirtualFreeEx"); + lookup_symbol(MapViewOfFile3, "KernelBase", "MapViewOfFile3"); + lookup_symbol(UnmapViewOfFile2, "KernelBase", "UnmapViewOfFile2"); +} diff --git a/src/hotspot/os/windows/gc/z/zSyscall_windows.hpp b/src/hotspot/os/windows/gc/z/zSyscall_windows.hpp new file mode 100644 index 00000000000..1fc4f678271 --- /dev/null +++ b/src/hotspot/os/windows/gc/z/zSyscall_windows.hpp @@ -0,0 +1,50 @@ +/* + * 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. + */ + +#ifndef OS_WINDOWS_GC_Z_ZSYSCALL_WINDOWS_HPP +#define OS_WINDOWS_GC_Z_ZSYSCALL_WINDOWS_HPP + +#include "utilities/globalDefinitions.hpp" + +#include +#include + +class ZSyscall { +private: + typedef HANDLE (*CreateFileMappingWFn)(HANDLE, LPSECURITY_ATTRIBUTES, DWORD, DWORD, DWORD, LPCWSTR); + typedef PVOID (*VirtualAlloc2Fn)(HANDLE, PVOID, SIZE_T, ULONG, ULONG, MEM_EXTENDED_PARAMETER*, ULONG); + typedef BOOL (*VirtualFreeExFn)(HANDLE, LPVOID, SIZE_T, DWORD); + typedef PVOID (*MapViewOfFile3Fn)(HANDLE, HANDLE, PVOID, ULONG64, SIZE_T, ULONG, ULONG, MEM_EXTENDED_PARAMETER*, ULONG); + typedef BOOL (*UnmapViewOfFile2Fn)(HANDLE, PVOID, ULONG); + +public: + static CreateFileMappingWFn CreateFileMappingW; + static VirtualAlloc2Fn VirtualAlloc2; + static VirtualFreeExFn VirtualFreeEx; + static MapViewOfFile3Fn MapViewOfFile3; + static UnmapViewOfFile2Fn UnmapViewOfFile2; + + static void initialize(); +}; + +#endif // OS_WINDOWS_GC_Z_ZSYSCALL_WINDOWS_HPP diff --git a/src/hotspot/os/windows/gc/z/zUtils_windows.cpp b/src/hotspot/os/windows/gc/z/zUtils_windows.cpp new file mode 100644 index 00000000000..633727b6f73 --- /dev/null +++ b/src/hotspot/os/windows/gc/z/zUtils_windows.cpp @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +#include "precompiled.hpp" +#include "gc/z/zUtils.hpp" +#include "utilities/debug.hpp" + +#include + +uintptr_t ZUtils::alloc_aligned(size_t alignment, size_t size) { + void* const res = _aligned_malloc(size, alignment); + + if (res == NULL) { + fatal("_aligned_malloc failed"); + } + + memset(res, 0, size); + + return (uintptr_t)res; +} diff --git a/src/hotspot/os/windows/gc/z/zVirtualMemory_windows.cpp b/src/hotspot/os/windows/gc/z/zVirtualMemory_windows.cpp new file mode 100644 index 00000000000..e54c2ce5373 --- /dev/null +++ b/src/hotspot/os/windows/gc/z/zVirtualMemory_windows.cpp @@ -0,0 +1,149 @@ +/* + * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +#include "precompiled.hpp" +#include "gc/z/zAddress.inline.hpp" +#include "gc/z/zGlobals.hpp" +#include "gc/z/zMapper_windows.hpp" +#include "gc/z/zVirtualMemory.hpp" +#include "utilities/align.hpp" +#include "utilities/debug.hpp" + +static void split_placeholder(uintptr_t start, size_t size) { + ZMapper::split_placeholder(ZAddress::marked0(start), size); + ZMapper::split_placeholder(ZAddress::marked1(start), size); + ZMapper::split_placeholder(ZAddress::remapped(start), size); +} + +static void coalesce_placeholders(uintptr_t start, size_t size) { + ZMapper::coalesce_placeholders(ZAddress::marked0(start), size); + ZMapper::coalesce_placeholders(ZAddress::marked1(start), size); + ZMapper::coalesce_placeholders(ZAddress::remapped(start), size); +} + +static void split_into_placeholder_granules(uintptr_t start, size_t size) { + for (uintptr_t addr = start; addr < start + size; addr += ZGranuleSize) { + split_placeholder(addr, ZGranuleSize); + } +} + +static void coalesce_into_one_placeholder(uintptr_t start, size_t size) { + assert(is_aligned(size, ZGranuleSize), "Must be granule aligned"); + + if (size > ZGranuleSize) { + coalesce_placeholders(start, size); + } +} + +static void create_callback(const ZMemory* area) { + assert(is_aligned(area->size(), ZGranuleSize), "Must be granule aligned"); + coalesce_into_one_placeholder(area->start(), area->size()); +} + +static void destroy_callback(const ZMemory* area) { + assert(is_aligned(area->size(), ZGranuleSize), "Must be granule aligned"); + // Don't try split the last granule - VirtualFree will fail + split_into_placeholder_granules(area->start(), area->size() - ZGranuleSize); +} + +static void shrink_from_front_callback(const ZMemory* area, size_t size) { + assert(is_aligned(size, ZGranuleSize), "Must be granule aligned"); + split_into_placeholder_granules(area->start(), size); +} + +static void shrink_from_back_callback(const ZMemory* area, size_t size) { + assert(is_aligned(size, ZGranuleSize), "Must be granule aligned"); + // Don't try split the last granule - VirtualFree will fail + split_into_placeholder_granules(area->end() - size, size - ZGranuleSize); +} + +static void grow_from_front_callback(const ZMemory* area, size_t size) { + assert(is_aligned(area->size(), ZGranuleSize), "Must be granule aligned"); + coalesce_into_one_placeholder(area->start() - size, area->size() + size); +} + +static void grow_from_back_callback(const ZMemory* area, size_t size) { + assert(is_aligned(area->size(), ZGranuleSize), "Must be granule aligned"); + coalesce_into_one_placeholder(area->start(), area->size() + size); +} + +void ZVirtualMemoryManager::initialize_os() { + // Each reserved virtual memory address area registered in _manager is + // exactly covered by a single placeholder. Callbacks are installed so + // that whenever a memory area changes, the corresponding placeholder + // is adjusted. + // + // The create and grow callbacks are called when virtual memory is + // returned to the memory manager. The new memory area is then covered + // by a new single placeholder. + // + // The destroy and shrink callbacks are called when virtual memory is + // allocated from the memory manager. The memory area is then is split + // into granule-sized placeholders. + // + // See comment in zMapper_windows.cpp explaining why placeholders are + // split into ZGranuleSize sized placeholders. + + ZMemoryManager::Callbacks callbacks; + + callbacks._create = &create_callback; + callbacks._destroy = &destroy_callback; + callbacks._shrink_from_front = &shrink_from_front_callback; + callbacks._shrink_from_back = &shrink_from_back_callback; + callbacks._grow_from_front = &grow_from_front_callback; + callbacks._grow_from_back = &grow_from_back_callback; + + _manager.register_callbacks(callbacks); +} + +bool ZVirtualMemoryManager::reserve_contiguous_platform(uintptr_t start, size_t size) { + assert(is_aligned(size, ZGranuleSize), "Must be granule aligned"); + + // Reserve address views + const uintptr_t marked0 = ZAddress::marked0(start); + const uintptr_t marked1 = ZAddress::marked1(start); + const uintptr_t remapped = ZAddress::remapped(start); + + // Reserve address space + if (ZMapper::reserve(marked0, size) != marked0) { + return false; + } + + if (ZMapper::reserve(marked1, size) != marked1) { + ZMapper::unreserve(marked0, size); + return false; + } + + if (ZMapper::reserve(remapped, size) != remapped) { + ZMapper::unreserve(marked0, size); + ZMapper::unreserve(marked1, size); + return false; + } + + // Register address views with native memory tracker + nmt_reserve(marked0, size); + nmt_reserve(marked1, size); + nmt_reserve(remapped, size); + + return true; +} From fec6f8a1e42e65e6be455ca36ea67baca8585037 Mon Sep 17 00:00:00 2001 From: Matthias Baesken Date: Fri, 29 Nov 2019 09:52:50 +0100 Subject: [PATCH 04/81] 8234741: enhance os::get_core_path on macOS Reviewed-by: clanger, gziemski --- src/hotspot/os/bsd/os_bsd.cpp | 23 +++++++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-) diff --git a/src/hotspot/os/bsd/os_bsd.cpp b/src/hotspot/os/bsd/os_bsd.cpp index e4823aeb61b..b8774e9b32c 100644 --- a/src/hotspot/os/bsd/os_bsd.cpp +++ b/src/hotspot/os/bsd/os_bsd.cpp @@ -3763,11 +3763,30 @@ int os::fork_and_exec(char* cmd, bool use_vfork_if_available) { } } -// Get the default path to the core file +// Get the kern.corefile setting, or otherwise the default path to the core file // Returns the length of the string int os::get_core_path(char* buffer, size_t bufferSize) { - int n = jio_snprintf(buffer, bufferSize, "/cores/core.%d", current_process_id()); + int n = 0; +#ifdef __APPLE__ + char coreinfo[MAX_PATH]; + size_t sz = sizeof(coreinfo); + int ret = sysctlbyname("kern.corefile", coreinfo, &sz, NULL, 0); + if (ret == 0) { + char *pid_pos = strstr(coreinfo, "%P"); + // skip over the "%P" to preserve any optional custom user pattern + const char* tail = (pid_pos != NULL) ? (pid_pos + 2) : ""; + if (pid_pos != NULL) { + *pid_pos = '\0'; + n = jio_snprintf(buffer, bufferSize, "%s%d%s", coreinfo, os::current_process_id(), tail); + } else { + n = jio_snprintf(buffer, bufferSize, "%s", coreinfo); + } + } else +#endif + { + n = jio_snprintf(buffer, bufferSize, "/cores/core.%d", os::current_process_id()); + } // Truncate if theoretical string was longer than bufferSize n = MIN2(n, (int)bufferSize); From 6864634fb1de8283559ccfb35f4cb237814f444b Mon Sep 17 00:00:00 2001 From: Igor Ignatyev Date: Tue, 3 Dec 2019 12:41:45 +0100 Subject: [PATCH 05/81] 8216041: [Event Request] - Deoptimization Reviewed-by: iignatyev, vlivanov, egahlin --- src/hotspot/share/code/codeBlob.hpp | 1 + src/hotspot/share/compiler/compileBroker.cpp | 4 +- src/hotspot/share/jfr/metadata/metadata.xml | 32 ++++- .../jfr/recorder/checkpoint/types/jfrType.cpp | 19 +++ .../jfr/recorder/checkpoint/types/jfrType.hpp | 10 ++ .../checkpoint/types/jfrTypeManager.cpp | 2 + src/hotspot/share/runtime/deoptimization.cpp | 73 ++++++++++- src/jdk.jfr/share/conf/jfr/default.jfc | 5 + src/jdk.jfr/share/conf/jfr/profile.jfc | 4 + .../event/compiler/TestDeoptimization.java | 124 ++++++++++++++++++ test/lib/jdk/test/lib/jfr/EventNames.java | 1 + 11 files changed, 270 insertions(+), 5 deletions(-) create mode 100644 test/jdk/jdk/jfr/event/compiler/TestDeoptimization.java diff --git a/src/hotspot/share/code/codeBlob.hpp b/src/hotspot/share/code/codeBlob.hpp index 08f83cf267f..77c331a7969 100644 --- a/src/hotspot/share/code/codeBlob.hpp +++ b/src/hotspot/share/code/codeBlob.hpp @@ -147,6 +147,7 @@ public: inline bool is_compiled_by_c2() const { return _type == compiler_c2; }; inline bool is_compiled_by_jvmci() const { return _type == compiler_jvmci; }; const char* compiler_name() const; + CompilerType compiler_type() const { return _type; } // Casting nmethod* as_nmethod_or_null() { return is_nmethod() ? (nmethod*) this : NULL; } diff --git a/src/hotspot/share/compiler/compileBroker.cpp b/src/hotspot/share/compiler/compileBroker.cpp index 3d88195939c..ed4b36aa1ff 100644 --- a/src/hotspot/share/compiler/compileBroker.cpp +++ b/src/hotspot/share/compiler/compileBroker.cpp @@ -2019,8 +2019,10 @@ void CompileBroker::post_compile(CompilerThread* thread, CompileTask* task, bool static void post_compilation_event(EventCompilation* event, CompileTask* task) { assert(event != NULL, "invariant"); assert(event->should_commit(), "invariant"); - event->set_method(task->method()); + assert(task != NULL, "invariant"); event->set_compileId(task->compile_id()); + event->set_compiler(task->compiler()->type()); + event->set_method(task->method()); event->set_compileLevel(task->comp_level()); event->set_succeded(task->is_success()); event->set_isOsr(task->osr_bci() != CompileBroker::standard_entry_bci); diff --git a/src/hotspot/share/jfr/metadata/metadata.xml b/src/hotspot/share/jfr/metadata/metadata.xml index 77e2578ab3d..9a039e2ac53 100644 --- a/src/hotspot/share/jfr/metadata/metadata.xml +++ b/src/hotspot/share/jfr/metadata/metadata.xml @@ -465,8 +465,9 @@ - + + @@ -497,7 +498,7 @@ - + @@ -519,6 +520,17 @@ + + + + + + + + + + + @@ -1041,6 +1053,22 @@ + + + + + + + + + + + + + + + + diff --git a/src/hotspot/share/jfr/recorder/checkpoint/types/jfrType.cpp b/src/hotspot/share/jfr/recorder/checkpoint/types/jfrType.cpp index 48ace4d6762..b11ef50113f 100644 --- a/src/hotspot/share/jfr/recorder/checkpoint/types/jfrType.cpp +++ b/src/hotspot/share/jfr/recorder/checkpoint/types/jfrType.cpp @@ -26,6 +26,7 @@ #include "classfile/javaClasses.inline.hpp" #include "code/codeBlob.hpp" #include "code/codeCache.hpp" +#include "compiler/compilerDefinitions.hpp" #include "gc/shared/gcCause.hpp" #include "gc/shared/gcName.hpp" #include "gc/shared/gcTrace.hpp" @@ -293,3 +294,21 @@ void JfrThreadConstant::serialize(JfrCheckpointWriter& writer) { writer.write((traceid)0); // java thread id writer.write((traceid)0); // java thread group } + +void BytecodeConstant::serialize(JfrCheckpointWriter& writer) { + static const u4 nof_entries = Bytecodes::number_of_codes; + writer.write_count(nof_entries); + for (u4 i = 0; i < nof_entries; ++i) { + writer.write_key(i); + writer.write(Bytecodes::name((Bytecodes::Code)i)); + } +} + +void CompilerTypeConstant::serialize(JfrCheckpointWriter& writer) { + static const u4 nof_entries = compiler_number_of_types; + writer.write_count(nof_entries); + for (u4 i = 0; i < nof_entries; ++i) { + writer.write_key(i); + writer.write(compilertype2name((CompilerType)i)); + } +} diff --git a/src/hotspot/share/jfr/recorder/checkpoint/types/jfrType.hpp b/src/hotspot/share/jfr/recorder/checkpoint/types/jfrType.hpp index 2ee315d8e8b..ae15c2ac274 100644 --- a/src/hotspot/share/jfr/recorder/checkpoint/types/jfrType.hpp +++ b/src/hotspot/share/jfr/recorder/checkpoint/types/jfrType.hpp @@ -115,4 +115,14 @@ class JfrThreadConstant : public JfrSerializer { void serialize(JfrCheckpointWriter& writer); }; +class BytecodeConstant : public JfrSerializer { + public: + void serialize(JfrCheckpointWriter& writer); +}; + +class CompilerTypeConstant : public JfrSerializer { + public: + void serialize(JfrCheckpointWriter& writer); +}; + #endif // SHARE_JFR_RECORDER_CHECKPOINT_TYPES_JFRTYPE_HPP diff --git a/src/hotspot/share/jfr/recorder/checkpoint/types/jfrTypeManager.cpp b/src/hotspot/share/jfr/recorder/checkpoint/types/jfrTypeManager.cpp index 8a894e482e4..da674861b74 100644 --- a/src/hotspot/share/jfr/recorder/checkpoint/types/jfrTypeManager.cpp +++ b/src/hotspot/share/jfr/recorder/checkpoint/types/jfrTypeManager.cpp @@ -222,6 +222,8 @@ bool JfrTypeManager::initialize() { register_static_type(TYPE_CODEBLOBTYPE, true, new CodeBlobTypeConstant()); register_static_type(TYPE_VMOPERATIONTYPE, true, new VMOperationTypeConstant()); register_static_type(TYPE_THREADSTATE, true, new ThreadStateConstant()); + register_static_type(TYPE_BYTECODE, true, new BytecodeConstant()); + register_static_type(TYPE_COMPILERTYPE, true, new CompilerTypeConstant()); return true; } diff --git a/src/hotspot/share/runtime/deoptimization.cpp b/src/hotspot/share/runtime/deoptimization.cpp index 5d9dc73ec4b..bc25f8db400 100644 --- a/src/hotspot/share/runtime/deoptimization.cpp +++ b/src/hotspot/share/runtime/deoptimization.cpp @@ -56,9 +56,9 @@ #include "runtime/fieldDescriptor.hpp" #include "runtime/fieldDescriptor.inline.hpp" #include "runtime/frame.inline.hpp" -#include "runtime/jniHandles.inline.hpp" #include "runtime/handles.inline.hpp" #include "runtime/interfaceSupport.inline.hpp" +#include "runtime/jniHandles.inline.hpp" #include "runtime/safepointVerifiers.hpp" #include "runtime/sharedRuntime.hpp" #include "runtime/signature.hpp" @@ -69,9 +69,13 @@ #include "runtime/vframeArray.hpp" #include "runtime/vframe_hp.hpp" #include "utilities/events.hpp" +#include "utilities/macros.hpp" #include "utilities/preserveException.hpp" #include "utilities/xmlstream.hpp" - +#if INCLUDE_JFR +#include "jfr/jfrEvents.hpp" +#include "jfr/metadata/jfrSerializer.hpp" +#endif bool DeoptimizationMarker::_is_active = false; @@ -1652,6 +1656,69 @@ void Deoptimization::load_class_by_index(const constantPoolHandle& constant_pool } } +#if INCLUDE_JFR + +class DeoptReasonSerializer : public JfrSerializer { + public: + void serialize(JfrCheckpointWriter& writer) { + writer.write_count((u4)(Deoptimization::Reason_LIMIT + 1)); // + Reason::many (-1) + for (int i = -1; i < Deoptimization::Reason_LIMIT; ++i) { + writer.write_key((u8)i); + writer.write(Deoptimization::trap_reason_name(i)); + } + } +}; + +class DeoptActionSerializer : public JfrSerializer { + public: + void serialize(JfrCheckpointWriter& writer) { + static const u4 nof_actions = Deoptimization::Action_LIMIT; + writer.write_count(nof_actions); + for (u4 i = 0; i < Deoptimization::Action_LIMIT; ++i) { + writer.write_key(i); + writer.write(Deoptimization::trap_action_name((int)i)); + } + } +}; + +static void register_serializers() { + static int critical_section = 0; + if (1 == critical_section || Atomic::cmpxchg(&critical_section, 0, 1) == 1) { + return; + } + JfrSerializer::register_serializer(TYPE_DEOPTIMIZATIONREASON, true, new DeoptReasonSerializer()); + JfrSerializer::register_serializer(TYPE_DEOPTIMIZATIONACTION, true, new DeoptActionSerializer()); +} + +static void post_deoptimization_event(CompiledMethod* nm, + const Method* method, + int trap_bci, + int instruction, + Deoptimization::DeoptReason reason, + Deoptimization::DeoptAction action) { + assert(nm != NULL, "invariant"); + assert(method != NULL, "invariant"); + if (EventDeoptimization::is_enabled()) { + static bool serializers_registered = false; + if (!serializers_registered) { + register_serializers(); + serializers_registered = true; + } + EventDeoptimization event; + event.set_compileId(nm->compile_id()); + event.set_compiler(nm->compiler_type()); + event.set_method(method); + event.set_lineNumber(method->line_number_from_bci(trap_bci)); + event.set_bci(trap_bci); + event.set_instruction(instruction); + event.set_reason(reason); + event.set_action(action); + event.commit(); + } +} + +#endif // INCLUDE_JFR + JRT_ENTRY(void, Deoptimization::uncommon_trap_inner(JavaThread* thread, jint trap_request)) { HandleMark hm; @@ -1746,6 +1813,8 @@ JRT_ENTRY(void, Deoptimization::uncommon_trap_inner(JavaThread* thread, jint tra MethodData* trap_mdo = get_method_data(thread, profiled_method, create_if_missing); + JFR_ONLY(post_deoptimization_event(nm, trap_method(), trap_bci, trap_bc, reason, action);) + // Log a message Events::log_deopt_message(thread, "Uncommon trap: reason=%s action=%s pc=" INTPTR_FORMAT " method=%s @ %d %s", trap_reason_name(reason), trap_action_name(action), p2i(fr.pc()), diff --git a/src/jdk.jfr/share/conf/jfr/default.jfc b/src/jdk.jfr/share/conf/jfr/default.jfc index 04a09f5d596..d67cf5e9bb7 100644 --- a/src/jdk.jfr/share/conf/jfr/default.jfc +++ b/src/jdk.jfr/share/conf/jfr/default.jfc @@ -728,6 +728,11 @@ 0 ms + + true + false + + diff --git a/src/jdk.jfr/share/conf/jfr/profile.jfc b/src/jdk.jfr/share/conf/jfr/profile.jfc index cbf43cd32e1..c25e2facbf9 100644 --- a/src/jdk.jfr/share/conf/jfr/profile.jfc +++ b/src/jdk.jfr/share/conf/jfr/profile.jfc @@ -728,6 +728,10 @@ 0 ms + + true + true + diff --git a/test/jdk/jdk/jfr/event/compiler/TestDeoptimization.java b/test/jdk/jdk/jfr/event/compiler/TestDeoptimization.java new file mode 100644 index 00000000000..8296ab4291b --- /dev/null +++ b/test/jdk/jdk/jfr/event/compiler/TestDeoptimization.java @@ -0,0 +1,124 @@ +/* + * 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. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.jfr.event.compiler; + +import java.util.List; +import java.util.stream.Collectors; + +import jdk.jfr.Recording; +import jdk.jfr.consumer.RecordedEvent; +import jdk.test.lib.Asserts; +import jdk.test.lib.jfr.EventNames; +import jdk.test.lib.jfr.Events; + +// THIS TEST IS LINE NUMBER SENSITIVE + +// Careful if moving this class or method somewhere since verifyDeoptimizationEventFields asserts the linenumber +class Dummy { + static void dummyMethod(boolean b) { + if (b) { + return; + } + } +} + +/** + * @test + * @key jfr + * @summary sanity test for Deoptimization event, depends on Compilation event + * @requires vm.hasJFR + * @requires vm.compMode != "Xint" + * @requires vm.flavor == "server" & (vm.opt.TieredStopAtLevel == 4 | vm.opt.TieredStopAtLevel == null) + * @library /test/lib + * @run main/othervm -XX:-BackgroundCompilation jdk.jfr.event.compiler.TestDeoptimization + */ +public class TestDeoptimization { + private final static String TYPE_NAME = Dummy.class.getName().replace(".", "/"); + private final static String METHOD_NAME = "dummyMethod"; + private static final String METHOD_DESCRIPTOR = "(Z)V"; + private static final String COMPILER = "c2"; + + public static void main(String[] args) throws Throwable { + new TestDeoptimization().doTest(); + } + + public void doTest() throws Throwable { + Recording recording = new Recording(); + recording.enable(EventNames.Deoptimization); + recording.enable(EventNames.Compilation); + recording.start(); + + long start = System.currentTimeMillis(); + // compile dummyMethod + for (int i = 0; i < 20000; i++) { + Dummy.dummyMethod(false); + } + // provoke deoptimization by executing the uncommon trap in dummyMethod + Dummy.dummyMethod(true); + System.out.println("Time to load, compile and deoptimize dummyMethod: " + (System.currentTimeMillis() - start)); + recording.stop(); + + List events = Events.fromRecording(recording); + Events.hasEvents(events); + + // get compile ids for all compilations of dummyMethod + List compileIds = events.stream() + .filter(e -> e.getEventType().getName().equals(EventNames.Compilation)) + .filter(TestDeoptimization::isForDummyMethod) + .map(e -> Events.assertField(e, "compileId").getValue()) + .collect(Collectors.toList()); + Asserts.assertFalse(compileIds.isEmpty(), + "couldn't find any " + EventNames.Compilation + " for " + METHOD_NAME); + + // get all deoptimization events associated with the compile ids + List deoptEventsForCompileIds = events.stream() + .filter(e -> e.getEventType().getName().equals(EventNames.Deoptimization)) + .filter(e -> compileIds.contains(Events.assertField(e, "compileId").getValue())) + .collect(Collectors.toList()); + Asserts.assertFalse(deoptEventsForCompileIds.isEmpty(), + "couldn't find any " + EventNames.Deoptimization + " for ids : " + compileIds); + + // verify deoptimization event fields + deoptEventsForCompileIds.forEach(this::verifyDeoptimizationEventFields); + } + + static boolean isForDummyMethod(RecordedEvent e) { + return TYPE_NAME.equals(Events.assertField(e, "method.type.name").getValue()) + && METHOD_NAME.equals(Events.assertField(e, "method.name").getValue()) + && METHOD_DESCRIPTOR.equals(Events.assertField(e, "method.descriptor").getValue()); + } + + private void verifyDeoptimizationEventFields(RecordedEvent event) { + Events.assertEventThread(event); + Events.assertField(event, "compileId").atLeast(0); + Events.assertField(event, "compiler").equal(COMPILER); + Events.assertField(event, "lineNumber").equal(42); + Events.assertField(event, "bci").equal(1); + Events.assertField(event, "instruction").equal("ifeq"); + Events.assertField(event, "action").notEmpty().equal("reinterpret"); + Events.assertField(event, "reason").notEmpty().equal("unstable_if"); + } +} \ No newline at end of file diff --git a/test/lib/jdk/test/lib/jfr/EventNames.java b/test/lib/jdk/test/lib/jfr/EventNames.java index 0a8a15bfd43..70ec8aed45f 100644 --- a/test/lib/jdk/test/lib/jfr/EventNames.java +++ b/test/lib/jdk/test/lib/jfr/EventNames.java @@ -153,6 +153,7 @@ public class EventNames { public final static String CodeCacheFull = PREFIX + "CodeCacheFull"; public final static String ObjectAllocationInNewTLAB = PREFIX + "ObjectAllocationInNewTLAB"; public final static String ObjectAllocationOutsideTLAB = PREFIX + "ObjectAllocationOutsideTLAB"; + public final static String Deoptimization = PREFIX + "Deoptimization"; // OS public final static String OSInformation = PREFIX + "OSInformation"; From a2fad13ce29e6de9b9dead7da49de7c0544d32c6 Mon Sep 17 00:00:00 2001 From: Michael McMahon Date: Tue, 3 Dec 2019 11:55:47 +0000 Subject: [PATCH 06/81] 8234823: java/net/Socket/Timeouts.java testcase testTimedConnect2() fails on Windows 10 Reviewed-by: alanb --- test/jdk/java/net/Socket/Timeouts.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/jdk/java/net/Socket/Timeouts.java b/test/jdk/java/net/Socket/Timeouts.java index bd74d454677..c2f2bf48eac 100644 --- a/test/jdk/java/net/Socket/Timeouts.java +++ b/test/jdk/java/net/Socket/Timeouts.java @@ -74,7 +74,7 @@ public class Timeouts { try (Socket s = new Socket()) { SocketAddress remote = Utils.refusingEndpoint(); try { - s.connect(remote, 2000); + s.connect(remote, 10000); } catch (ConnectException expected) { } } } From 7afaaf1229b262ebcc5ddd8a6e6792a06438f307 Mon Sep 17 00:00:00 2001 From: Michael McMahon Date: Tue, 3 Dec 2019 11:57:10 +0000 Subject: [PATCH 07/81] 8234824: java/nio/channels/SocketChannel/AdaptSocket.java fails on Windows 10 Reviewed-by: alanb --- test/jdk/java/nio/channels/SocketChannel/AdaptSocket.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/jdk/java/nio/channels/SocketChannel/AdaptSocket.java b/test/jdk/java/nio/channels/SocketChannel/AdaptSocket.java index 66cf4a663cf..965e051a07a 100644 --- a/test/jdk/java/nio/channels/SocketChannel/AdaptSocket.java +++ b/test/jdk/java/nio/channels/SocketChannel/AdaptSocket.java @@ -202,6 +202,6 @@ public class AdaptSocket { TestServers.RefusingServer refuser = TestServers.RefusingServer.newRefusingServer(); testConnect(refuser, 0, true); - testConnect(refuser, 2000, true); + testConnect(refuser, 10000, true); } } From 234f326d79fcd030cd051cd036af6a8866f0a934 Mon Sep 17 00:00:00 2001 From: Jim Laskey Date: Tue, 3 Dec 2019 08:35:21 -0400 Subject: [PATCH 08/81] 8233116: Escape Sequences For Line Continuation and White Space (Preview) Reviewed-by: vromero, jlahoda, bchristi, mcimadamore --- .../share/classes/java/lang/String.java | 20 ++ .../sun/tools/javac/parser/JavaTokenizer.java | 196 ++++++++---------- .../sun/tools/javac/parser/UnicodeReader.java | 9 + .../java/lang/String/TranslateEscapes.java | 22 +- test/langtools/tools/javac/TextBlockAPI.java | 114 +++++++--- test/langtools/tools/javac/TextBlockLang.java | 26 +++ 6 files changed, 249 insertions(+), 138 deletions(-) diff --git a/src/java.base/share/classes/java/lang/String.java b/src/java.base/share/classes/java/lang/String.java index 21c286c4790..68aa207ce72 100644 --- a/src/java.base/share/classes/java/lang/String.java +++ b/src/java.base/share/classes/java/lang/String.java @@ -3062,6 +3062,11 @@ public final class String * {@code U+000D} * * + * {@code \u005Cs} + * space + * {@code U+0020} + * + * * {@code \u005C"} * double quote * {@code U+0022} @@ -3081,6 +3086,11 @@ public final class String * octal escape * code point equivalents * + * + * {@code \u005C} + * continuation + * discard + * * * * @@ -3124,6 +3134,9 @@ public final class String case 'r': ch = '\r'; break; + case 's': + ch = ' '; + break; case 't': ch = '\t'; break; @@ -3146,6 +3159,13 @@ public final class String } ch = (char)code; break; + case '\n': + continue; + case '\r': + if (from < length && chars[from] == '\n') { + from++; + } + continue; default: { String msg = String.format( "Invalid escape sequence: \\%c \\\\u%04X", diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/parser/JavaTokenizer.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/parser/JavaTokenizer.java index d4030ce418b..f0f796a8735 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/parser/JavaTokenizer.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/parser/JavaTokenizer.java @@ -91,17 +91,13 @@ public class JavaTokenizer { */ protected UnicodeReader reader; - /** Should the string stripped of indentation? + /** If is a text block */ - protected boolean shouldStripIndent; + protected boolean isTextBlock; - /** Should the string's escapes be translated? + /** If contains escape sequences */ - protected boolean shouldTranslateEscapes; - - /** Has the string broken escapes? - */ - protected boolean hasBrokenEscapes; + protected boolean hasEscapeSequences; protected ScannerFactory fac; @@ -181,91 +177,72 @@ public class JavaTokenizer { } /** Read next character in character or string literal and copy into sbuf. + * pos - start of literal offset + * translateEscapesNow - true if String::translateEscapes is not available + * in the java.base libs. Occurs during bootstrapping. + * multiline - true if scanning a text block. Allows newlines to be embedded + * in the result. */ - private void scanLitChar(int pos) { - if (reader.ch == '\\') { + private void scanLitChar(int pos, boolean translateEscapesNow, boolean multiline) { + if (reader.ch == '\\') { if (reader.peekChar() == '\\' && !reader.isUnicode()) { reader.skipChar(); - reader.putChar('\\', true); + if (!translateEscapesNow) { + reader.putChar(false); + } + reader.putChar(true); } else { - reader.scanChar(); + reader.nextChar(translateEscapesNow); switch (reader.ch) { case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': char leadch = reader.ch; int oct = reader.digit(pos, 8); - reader.scanChar(); + reader.nextChar(translateEscapesNow); if ('0' <= reader.ch && reader.ch <= '7') { oct = oct * 8 + reader.digit(pos, 8); - reader.scanChar(); + reader.nextChar(translateEscapesNow); if (leadch <= '3' && '0' <= reader.ch && reader.ch <= '7') { oct = oct * 8 + reader.digit(pos, 8); - reader.scanChar(); + reader.nextChar(translateEscapesNow); } } - reader.putChar((char)oct); - break; - case 'b': - reader.putChar('\b', true); break; - case 't': - reader.putChar('\t', true); break; - case 'n': - reader.putChar('\n', true); break; - case 'f': - reader.putChar('\f', true); break; - case 'r': - reader.putChar('\r', true); break; - case '\'': - reader.putChar('\'', true); break; - case '\"': - reader.putChar('\"', true); break; - case '\\': - reader.putChar('\\', true); break; - default: - lexError(reader.bp, Errors.IllegalEscChar); - } - } - } else if (reader.bp != reader.buflen) { - reader.putChar(true); - } - } - - /** Read next character in character or string literal and copy into sbuf - * without translating escapes. Used by text blocks to preflight verify - * escapes sequences. - */ - private void scanLitCharRaw(int pos) { - if (reader.ch == '\\') { - if (reader.peekChar() == '\\' && !reader.isUnicode()) { - reader.skipChar(); - reader.putChar('\\', false); - reader.putChar('\\', true); - } else { - reader.putChar('\\', true); - switch (reader.ch) { - case '0': case '1': case '2': case '3': - case '4': case '5': case '6': case '7': - char leadch = reader.ch; - reader.putChar(true); - if ('0' <= reader.ch && reader.ch <= '7') { - reader.putChar(true); - if (leadch <= '3' && '0' <= reader.ch && reader.ch <= '7') { - reader.putChar(true); - } + if (translateEscapesNow) { + reader.putChar((char)oct); } break; - // Effectively list of valid escape sequences. case 'b': + reader.putChar(translateEscapesNow ? '\b' : 'b', true); break; case 't': + reader.putChar(translateEscapesNow ? '\t' : 't', true); break; case 'n': + reader.putChar(translateEscapesNow ? '\n' : 'n', true); break; case 'f': + reader.putChar(translateEscapesNow ? '\f' : 'f', true); break; case 'r': + reader.putChar(translateEscapesNow ? '\r' : 'r', true); break; case '\'': case '\"': case '\\': reader.putChar(true); break; + case 's': + checkSourceLevel(reader.bp, Feature.TEXT_BLOCKS); + reader.putChar(translateEscapesNow ? ' ' : 's', true); break; + case '\n': + case '\r': + if (!multiline) { + lexError(reader.bp, Errors.IllegalEscChar); + } else { + int start = reader.bp; + checkSourceLevel(reader.bp, Feature.TEXT_BLOCKS); + if (reader.ch == '\r' && reader.peekChar() == '\n') { + reader.nextChar(translateEscapesNow); + } + reader.nextChar(translateEscapesNow); + processLineTerminator(start, reader.bp); + } + break; default: - hasBrokenEscapes = true; lexError(reader.bp, Errors.IllegalEscChar); } } @@ -276,7 +253,7 @@ public class JavaTokenizer { /** Interim access to String methods used to support text blocks. * Required to handle bootstrapping with pre-text block jdks. - * Could be reworked in the 'next' jdk. + * Should be replaced with direct calls in the 'next' jdk. */ static class TextBlockSupport { /** Reflection method to remove incidental indentation. @@ -429,11 +406,8 @@ public class JavaTokenizer { */ private void scanString(int pos) { // Clear flags. - shouldStripIndent = false; - shouldTranslateEscapes = false; - hasBrokenEscapes = false; - // Check if text block string methods are present. - boolean hasTextBlockSupport = TextBlockSupport.hasSupport(); + isTextBlock = false; + hasEscapeSequences = false; // Track the end of first line for error recovery. int firstEOLN = -1; // Attempt to scan for up to 3 double quotes. @@ -449,36 +423,28 @@ public class JavaTokenizer { case 3: // Starting a text block. // Check if preview feature is enabled for text blocks. checkSourceLevel(pos, Feature.TEXT_BLOCKS); - // Only proceed if text block string methods are present. - if (hasTextBlockSupport) { - // Indicate that the final string should have incidental indentation removed. - shouldStripIndent = true; - // Verify the open delimiter sequence. - boolean hasOpenEOLN = false; - while (reader.bp < reader.buflen && Character.isWhitespace(reader.ch)) { - hasOpenEOLN = isEOLN(); - if (hasOpenEOLN) { - break; - } - reader.scanChar(); - } - // Error if the open delimiter sequence not is """*. - if (!hasOpenEOLN) { - lexError(reader.bp, Errors.IllegalTextBlockOpen); - return; - } - // Skip line terminator. - int start = reader.bp; - if (isCRLF()) { - reader.scanChar(); + isTextBlock = true; + // Verify the open delimiter sequence. + boolean hasOpenEOLN = false; + while (reader.bp < reader.buflen && Character.isWhitespace(reader.ch)) { + hasOpenEOLN = isEOLN(); + if (hasOpenEOLN) { + break; } reader.scanChar(); - processLineTerminator(start, reader.bp); - } else { - // No text block string methods are present, so reset and treat like string literal. - reader.reset(pos); - openCount = countChar('\"', 1); } + // Error if the open delimiter sequence not is """*. + if (!hasOpenEOLN) { + lexError(reader.bp, Errors.IllegalTextBlockOpen); + return; + } + // Skip line terminator. + int start = reader.bp; + if (isCRLF()) { + reader.scanChar(); + } + reader.scanChar(); + processLineTerminator(start, reader.bp); break; } // While characters are available. @@ -513,15 +479,11 @@ public class JavaTokenizer { } } else if (reader.ch == '\\') { // Handle escape sequences. - if (hasTextBlockSupport) { - // Indicate that the final string should have escapes translated. - shouldTranslateEscapes = true; - // Validate escape sequence and add to string buffer. - scanLitCharRaw(pos); - } else { - // Translate escape sequence and add result to string buffer. - scanLitChar(pos); - } + hasEscapeSequences = true; + // Translate escapes immediately if TextBlockSupport is not available + // during bootstrapping. + boolean translateEscapesNow = !TextBlockSupport.hasSupport(); + scanLitChar(pos, translateEscapesNow, openCount != 1); } else { // Add character to string buffer. reader.putChar(true); @@ -961,7 +923,7 @@ public class JavaTokenizer { } else { if (isEOLN()) lexError(pos, Errors.IllegalLineEndInCharLit); - scanLitChar(pos); + scanLitChar(pos, true, false); if (reader.ch == '\'') { reader.scanChar(); tk = TokenKind.CHARLITERAL; @@ -1026,7 +988,7 @@ public class JavaTokenizer { // Get characters from string buffer. String string = reader.chars(); // If a text block. - if (shouldStripIndent) { + if (isTextBlock && TextBlockSupport.hasSupport()) { // Verify that the incidental indentation is consistent. if (lint.isEnabled(LintCategory.TEXT_BLOCKS)) { Set checks = @@ -1041,11 +1003,19 @@ public class JavaTokenizer { } } // Remove incidental indentation. - string = TextBlockSupport.stripIndent(string); + try { + string = TextBlockSupport.stripIndent(string); + } catch (Exception ex) { + // Error already reported, just use unstripped string. + } } // Translate escape sequences if present. - if (shouldTranslateEscapes && !hasBrokenEscapes) { - string = TextBlockSupport.translateEscapes(string); + if (hasEscapeSequences && TextBlockSupport.hasSupport()) { + try { + string = TextBlockSupport.translateEscapes(string); + } catch (Exception ex) { + // Error already reported, just use untranslated string. + } } // Build string token. return new StringToken(tk, pos, endPos, string, comments); diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/parser/UnicodeReader.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/parser/UnicodeReader.java index 4561ed90e75..409a9fdc93d 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/parser/UnicodeReader.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/parser/UnicodeReader.java @@ -146,6 +146,15 @@ public class UnicodeReader { putChar(ch, scan); } + protected void nextChar(boolean skip) { + if (!skip) { + sbuf = ArrayUtils.ensureCapacity(sbuf, sp); + sbuf[sp++] = ch; + } + + scanChar(); + } + Name name() { return names.fromChars(sbuf, 0, sp); } diff --git a/test/jdk/java/lang/String/TranslateEscapes.java b/test/jdk/java/lang/String/TranslateEscapes.java index 67ded3eaa62..f4f4a0077de 100644 --- a/test/jdk/java/lang/String/TranslateEscapes.java +++ b/test/jdk/java/lang/String/TranslateEscapes.java @@ -34,6 +34,7 @@ public class TranslateEscapes { test1(); test2(); test3(); + test4(); } /* @@ -44,6 +45,7 @@ public class TranslateEscapes { verifyEscape("f", '\f'); verifyEscape("n", '\n'); verifyEscape("r", '\r'); + verifyEscape("s", '\s'); verifyEscape("t", '\t'); verifyEscape("'", '\''); verifyEscape("\"", '\"'); @@ -72,7 +74,16 @@ public class TranslateEscapes { */ static void test3() { exceptionThrown("+"); - exceptionThrown("\n"); + exceptionThrown("q"); + } + + /* + * Escape line terminator. + */ + static void test4() { + verifyLineTerminator("\n"); + verifyLineTerminator("\r\n"); + verifyLineTerminator("\r"); } static void verifyEscape(String string, char ch) { @@ -102,4 +113,13 @@ public class TranslateEscapes { // okay } } + + static void verifyLineTerminator(String string) { + String escapes = "\\" + string; + if (!escapes.translateEscapes().isEmpty()) { + System.err.format("escape for line terminator not handled %s%n", + string.replace("\n", "\\n").replace("\r", "\\r")); + throw new RuntimeException(); + } + } } diff --git a/test/langtools/tools/javac/TextBlockAPI.java b/test/langtools/tools/javac/TextBlockAPI.java index eb46952f249..080ac67f2b0 100644 --- a/test/langtools/tools/javac/TextBlockAPI.java +++ b/test/langtools/tools/javac/TextBlockAPI.java @@ -46,7 +46,10 @@ public class TextBlockAPI { test2(); test3(); test4(); - } + test5(); + test6(); + test7(); + } /* * Check that correct/incorrect syntax is properly detected @@ -72,35 +75,35 @@ public class TextBlockAPI { * Check that use of \u0022 is properly detected */ static void test2() { - compPass("public class UnicodeDelimiterTest {\n" + - " public static void main(String... args) {\n" + - " String xxx = \\u0022\\u0022\\u0022\nabc\n\\u0022\\u0022\\u0022;\n" + - " }\n" + - "}\n"); + compPass("public class UnicodeDelimiterTest {", + " public static void main(String... args) {", + " String xxx = \\u0022\\u0022\\u0022\nabc\n\\u0022\\u0022\\u0022;", + " }", + "}"); } /* * Check edge cases of text blocks as last token */ static void test3() { - compFail("public class EndTest {\n" + - " public static void main(String... args) {\n" + - " String xxx = \"\"\"\nabc\"\"\""); - compFail("public class TwoQuoteClose {\n" + - " public static void main(String... args) {\n" + - " String xxx = \"\"\"\nabc\"\""); - compFail("public class OneQuoteClose {\n" + - " public static void main(String... args) {\n" + - " String xxx = \"\"\"\nabc\""); - compFail("public class NoClose {\n" + - " public static void main(String... args) {\n" + - " String xxx = \"\"\"\nabc"); - compFail("public class ZeroTerminator {\n" + - " public static void main(String... args) {\n" + - " String xxx = \"\"\"\nabc\\u0000"); - compFail("public class NonBreakingSpace {\n" + - " public static void main(String... args) {\n" + - " String xxx = \"\"\"\nabc\\u001A"); + compFail("public class EndTest {", + " public static void main(String... args) {", + " String xxx = \"\"\"\nabc\"\"\""); + compFail("public class TwoQuoteClose {", + " public static void main(String... args) {", + " String xxx = \"\"\"\nabc\"\""); + compFail("public class OneQuoteClose {", + " public static void main(String... args) {", + " String xxx = \"\"\"\nabc\""); + compFail("public class NoClose {", + " public static void main(String... args) {", + " String xxx = \"\"\"\nabc"); + compFail("public class ZeroTerminator {", + " public static void main(String... args) {", + " String xxx = \"\"\"\nabc\\u0000"); + compFail("public class NonBreakingSpace {", + " public static void main(String... args) {", + " String xxx = \"\"\"\nabc\\u001A"); } /* @@ -137,6 +140,61 @@ public class TextBlockAPI { } } + /* + * Check escape space + */ + static void test5() { + compPass("public class EscapeSChar {", + " public static void main(String... args) {", + " char xxx = '\\s';", + " }", + "}"); + compPass("public class EscapeSString {", + " public static void main(String... args) {", + " String xxx = \"\\s\";", + " }", + "}"); + compPass("public class EscapeSTextBlock {", + " public static void main(String... args) {", + " String xxx = \"\"\"", + " \\s", + " \"\"\";", + " }", + "}"); + } + + /* + * Check escape line terminator + */ + static void test6() { + String[] terminators = new String[] { "\n", "\r\n", "\r" }; + for (String terminator : terminators) { + compPass("public class EscapeLineTerminator {", + " public static void main(String... args) {", + " String xxx = \"\"\"", + " \\" + terminator + + " \"\"\";", + " }", + "}"); + } + } + + /* + * Check incorrect escape line terminator cases + */ + static void test7() { + compFail("public class EscapeLineTerminatorChar {", + " public static void main(String... args) {", + " char xxx = '\\\n';", + " }", + "}"); + compFail("public class EscapeLineTerminatorString {", + " public static void main(String... args) {", + " String xxx = \"\\\n\";", + " }", + "}"); + } + /* * Test source for successful compile. */ @@ -154,6 +212,10 @@ public class TextBlockAPI { } } + static void compPass(String... lines) { + compPass(String.join("\n", lines) + "\n"); + } + /* * Test source for unsuccessful compile and specific error. */ @@ -170,4 +232,8 @@ public class TextBlockAPI { throw new RuntimeException("No error detected"); } } + + static void compFail(String... lines) { + compFail(String.join("\n", lines) + "\n"); + } } diff --git a/test/langtools/tools/javac/TextBlockLang.java b/test/langtools/tools/javac/TextBlockLang.java index b53601ff33c..238386ca8db 100644 --- a/test/langtools/tools/javac/TextBlockLang.java +++ b/test/langtools/tools/javac/TextBlockLang.java @@ -32,6 +32,8 @@ public class TextBlockLang { public static void main(String... args) { test1(); + test2(); + test3(); } /* @@ -75,6 +77,30 @@ public class TextBlockLang { """, 4); } + /* + * Test escape-S. + */ + static void test2() { + if ('\s' != ' ') { + throw new RuntimeException("Failed character escape-S"); + } + EQ("\s", " "); + EQ(""" + \s + """, " \n"); + } + + /* + * Test escape line terminator. + */ + static void test3() { + EQ(""" + abc \ + """, "abc "); + EQ("\\\n".translateEscapes(), ""); + EQ("\\\r\n".translateEscapes(), ""); + EQ("\\\r".translateEscapes(), ""); + } /* * Raise an exception if the string is not the expected length. From 5e758d2368b58ceef5092e74d481b60867b5ab93 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Per=20Lid=C3=A9n?= Date: Tue, 3 Dec 2019 13:51:29 +0100 Subject: [PATCH 09/81] 8234543: ZGC: Parallel pre-touch Reviewed-by: eosterlund, stefank --- .../bsd/gc/z/zPhysicalMemoryBacking_bsd.cpp | 29 +++++++----- .../bsd/gc/z/zPhysicalMemoryBacking_bsd.hpp | 4 +- .../gc/z/zPhysicalMemoryBacking_linux.cpp | 29 +++++++----- .../gc/z/zPhysicalMemoryBacking_linux.hpp | 4 +- .../gc/z/zPhysicalMemoryBacking_windows.cpp | 29 +++++++----- .../gc/z/zPhysicalMemoryBacking_windows.hpp | 4 +- src/hotspot/share/gc/z/zHeap.cpp | 2 +- src/hotspot/share/gc/z/zPageAllocator.cpp | 44 +++++++++++++++++-- src/hotspot/share/gc/z/zPageAllocator.hpp | 6 ++- src/hotspot/share/gc/z/zPhysicalMemory.cpp | 4 ++ src/hotspot/share/gc/z/zPhysicalMemory.hpp | 2 + src/hotspot/share/gc/z/zWorkers.cpp | 1 - .../jtreg/gc/z/TestAlwaysPreTouch.java | 41 +++++++++++++++++ 13 files changed, 156 insertions(+), 43 deletions(-) create mode 100644 test/hotspot/jtreg/gc/z/TestAlwaysPreTouch.java diff --git a/src/hotspot/os/bsd/gc/z/zPhysicalMemoryBacking_bsd.cpp b/src/hotspot/os/bsd/gc/z/zPhysicalMemoryBacking_bsd.cpp index 4967043da2e..0964a6589a8 100644 --- a/src/hotspot/os/bsd/gc/z/zPhysicalMemoryBacking_bsd.cpp +++ b/src/hotspot/os/bsd/gc/z/zPhysicalMemoryBacking_bsd.cpp @@ -148,7 +148,7 @@ void ZPhysicalMemoryBacking::pretouch_view(uintptr_t addr, size_t size) const { os::pretouch_memory((void*)addr, (void*)(addr + size), page_size); } -void ZPhysicalMemoryBacking::map_view(const ZPhysicalMemory& pmem, uintptr_t addr, bool pretouch) const { +void ZPhysicalMemoryBacking::map_view(const ZPhysicalMemory& pmem, uintptr_t addr) const { const size_t nsegments = pmem.nsegments(); size_t size = 0; @@ -159,11 +159,6 @@ void ZPhysicalMemoryBacking::map_view(const ZPhysicalMemory& pmem, uintptr_t add _file.map(segment_addr, segment.size(), segment.start()); size += segment.size(); } - - // Pre-touch memory - if (pretouch) { - pretouch_view(addr, size); - } } void ZPhysicalMemoryBacking::unmap_view(const ZPhysicalMemory& pmem, uintptr_t addr) const { @@ -175,15 +170,27 @@ uintptr_t ZPhysicalMemoryBacking::nmt_address(uintptr_t offset) const { return ZAddress::marked0(offset); } +void ZPhysicalMemoryBacking::pretouch(uintptr_t offset, size_t size) const { + if (ZVerifyViews) { + // Pre-touch good view + pretouch_view(ZAddress::good(offset), size); + } else { + // Pre-touch all views + pretouch_view(ZAddress::marked0(offset), size); + pretouch_view(ZAddress::marked1(offset), size); + pretouch_view(ZAddress::remapped(offset), size); + } +} + void ZPhysicalMemoryBacking::map(const ZPhysicalMemory& pmem, uintptr_t offset) const { if (ZVerifyViews) { // Map good view - map_view(pmem, ZAddress::good(offset), AlwaysPreTouch); + map_view(pmem, ZAddress::good(offset)); } else { // Map all views - map_view(pmem, ZAddress::marked0(offset), AlwaysPreTouch); - map_view(pmem, ZAddress::marked1(offset), AlwaysPreTouch); - map_view(pmem, ZAddress::remapped(offset), AlwaysPreTouch); + map_view(pmem, ZAddress::marked0(offset)); + map_view(pmem, ZAddress::marked1(offset)); + map_view(pmem, ZAddress::remapped(offset)); } } @@ -202,7 +209,7 @@ void ZPhysicalMemoryBacking::unmap(const ZPhysicalMemory& pmem, uintptr_t offset void ZPhysicalMemoryBacking::debug_map(const ZPhysicalMemory& pmem, uintptr_t offset) const { // Map good view assert(ZVerifyViews, "Should be enabled"); - map_view(pmem, ZAddress::good(offset), false /* pretouch */); + map_view(pmem, ZAddress::good(offset)); } void ZPhysicalMemoryBacking::debug_unmap(const ZPhysicalMemory& pmem, uintptr_t offset) const { diff --git a/src/hotspot/os/bsd/gc/z/zPhysicalMemoryBacking_bsd.hpp b/src/hotspot/os/bsd/gc/z/zPhysicalMemoryBacking_bsd.hpp index 9d51ff70df2..05bc6553f6e 100644 --- a/src/hotspot/os/bsd/gc/z/zPhysicalMemoryBacking_bsd.hpp +++ b/src/hotspot/os/bsd/gc/z/zPhysicalMemoryBacking_bsd.hpp @@ -36,7 +36,7 @@ private: ZMemoryManager _uncommitted; void pretouch_view(uintptr_t addr, size_t size) const; - void map_view(const ZPhysicalMemory& pmem, uintptr_t addr, bool pretouch) const; + void map_view(const ZPhysicalMemory& pmem, uintptr_t addr) const; void unmap_view(const ZPhysicalMemory& pmem, uintptr_t addr) const; public: @@ -53,6 +53,8 @@ public: uintptr_t nmt_address(uintptr_t offset) const; + void pretouch(uintptr_t offset, size_t size) const; + void map(const ZPhysicalMemory& pmem, uintptr_t offset) const; void unmap(const ZPhysicalMemory& pmem, uintptr_t offset) const; diff --git a/src/hotspot/os/linux/gc/z/zPhysicalMemoryBacking_linux.cpp b/src/hotspot/os/linux/gc/z/zPhysicalMemoryBacking_linux.cpp index 7268f927ea3..6d0470ffc2b 100644 --- a/src/hotspot/os/linux/gc/z/zPhysicalMemoryBacking_linux.cpp +++ b/src/hotspot/os/linux/gc/z/zPhysicalMemoryBacking_linux.cpp @@ -249,7 +249,7 @@ void ZPhysicalMemoryBacking::pretouch_view(uintptr_t addr, size_t size) const { os::pretouch_memory((void*)addr, (void*)(addr + size), page_size); } -void ZPhysicalMemoryBacking::map_view(const ZPhysicalMemory& pmem, uintptr_t addr, bool pretouch) const { +void ZPhysicalMemoryBacking::map_view(const ZPhysicalMemory& pmem, uintptr_t addr) const { const size_t nsegments = pmem.nsegments(); size_t size = 0; @@ -273,11 +273,6 @@ void ZPhysicalMemoryBacking::map_view(const ZPhysicalMemory& pmem, uintptr_t add // NUMA interleave memory before touching it ZNUMA::memory_interleave(addr, size); - - // Pre-touch memory - if (pretouch) { - pretouch_view(addr, size); - } } void ZPhysicalMemoryBacking::unmap_view(const ZPhysicalMemory& pmem, uintptr_t addr) const { @@ -296,15 +291,27 @@ uintptr_t ZPhysicalMemoryBacking::nmt_address(uintptr_t offset) const { return ZAddress::marked0(offset); } +void ZPhysicalMemoryBacking::pretouch(uintptr_t offset, size_t size) const { + if (ZVerifyViews) { + // Pre-touch good view + pretouch_view(ZAddress::good(offset), size); + } else { + // Pre-touch all views + pretouch_view(ZAddress::marked0(offset), size); + pretouch_view(ZAddress::marked1(offset), size); + pretouch_view(ZAddress::remapped(offset), size); + } +} + void ZPhysicalMemoryBacking::map(const ZPhysicalMemory& pmem, uintptr_t offset) const { if (ZVerifyViews) { // Map good view - map_view(pmem, ZAddress::good(offset), AlwaysPreTouch); + map_view(pmem, ZAddress::good(offset)); } else { // Map all views - map_view(pmem, ZAddress::marked0(offset), AlwaysPreTouch); - map_view(pmem, ZAddress::marked1(offset), AlwaysPreTouch); - map_view(pmem, ZAddress::remapped(offset), AlwaysPreTouch); + map_view(pmem, ZAddress::marked0(offset)); + map_view(pmem, ZAddress::marked1(offset)); + map_view(pmem, ZAddress::remapped(offset)); } } @@ -323,7 +330,7 @@ void ZPhysicalMemoryBacking::unmap(const ZPhysicalMemory& pmem, uintptr_t offset void ZPhysicalMemoryBacking::debug_map(const ZPhysicalMemory& pmem, uintptr_t offset) const { // Map good view assert(ZVerifyViews, "Should be enabled"); - map_view(pmem, ZAddress::good(offset), false /* pretouch */); + map_view(pmem, ZAddress::good(offset)); } void ZPhysicalMemoryBacking::debug_unmap(const ZPhysicalMemory& pmem, uintptr_t offset) const { diff --git a/src/hotspot/os/linux/gc/z/zPhysicalMemoryBacking_linux.hpp b/src/hotspot/os/linux/gc/z/zPhysicalMemoryBacking_linux.hpp index 6847d9ac1e0..8fa785aa336 100644 --- a/src/hotspot/os/linux/gc/z/zPhysicalMemoryBacking_linux.hpp +++ b/src/hotspot/os/linux/gc/z/zPhysicalMemoryBacking_linux.hpp @@ -43,7 +43,7 @@ private: void advise_view(uintptr_t addr, size_t size, int advice) const; void pretouch_view(uintptr_t addr, size_t size) const; - void map_view(const ZPhysicalMemory& pmem, uintptr_t addr, bool pretouch) const; + void map_view(const ZPhysicalMemory& pmem, uintptr_t addr) const; void unmap_view(const ZPhysicalMemory& pmem, uintptr_t addr) const; public: @@ -60,6 +60,8 @@ public: uintptr_t nmt_address(uintptr_t offset) const; + void pretouch(uintptr_t offset, size_t size) const; + void map(const ZPhysicalMemory& pmem, uintptr_t offset) const; void unmap(const ZPhysicalMemory& pmem, uintptr_t offset) const; diff --git a/src/hotspot/os/windows/gc/z/zPhysicalMemoryBacking_windows.cpp b/src/hotspot/os/windows/gc/z/zPhysicalMemoryBacking_windows.cpp index 87675e2e14f..b03bce0324e 100644 --- a/src/hotspot/os/windows/gc/z/zPhysicalMemoryBacking_windows.cpp +++ b/src/hotspot/os/windows/gc/z/zPhysicalMemoryBacking_windows.cpp @@ -149,7 +149,7 @@ void ZPhysicalMemoryBacking::pretouch_view(uintptr_t addr, size_t size) const { os::pretouch_memory((void*)addr, (void*)(addr + size), page_size); } -void ZPhysicalMemoryBacking::map_view(const ZPhysicalMemory& pmem, uintptr_t addr, bool pretouch) const { +void ZPhysicalMemoryBacking::map_view(const ZPhysicalMemory& pmem, uintptr_t addr) const { const size_t nsegments = pmem.nsegments(); size_t size = 0; @@ -159,11 +159,6 @@ void ZPhysicalMemoryBacking::map_view(const ZPhysicalMemory& pmem, uintptr_t add _file.map(addr + size, segment.size(), segment.start()); size += segment.size(); } - - // Pre-touch memory - if (pretouch) { - pretouch_view(addr, size); - } } void ZPhysicalMemoryBacking::unmap_view(const ZPhysicalMemory& pmem, uintptr_t addr) const { @@ -175,15 +170,27 @@ uintptr_t ZPhysicalMemoryBacking::nmt_address(uintptr_t offset) const { return ZAddress::marked0(offset); } +void ZPhysicalMemoryBacking::pretouch(uintptr_t offset, size_t size) const { + if (ZVerifyViews) { + // Pre-touch good view + pretouch_view(ZAddress::good(offset), size); + } else { + // Pre-touch all views + pretouch_view(ZAddress::marked0(offset), size); + pretouch_view(ZAddress::marked1(offset), size); + pretouch_view(ZAddress::remapped(offset), size); + } +} + void ZPhysicalMemoryBacking::map(const ZPhysicalMemory& pmem, uintptr_t offset) const { if (ZVerifyViews) { // Map good view - map_view(pmem, ZAddress::good(offset), AlwaysPreTouch); + map_view(pmem, ZAddress::good(offset)); } else { // Map all views - map_view(pmem, ZAddress::marked0(offset), AlwaysPreTouch); - map_view(pmem, ZAddress::marked1(offset), AlwaysPreTouch); - map_view(pmem, ZAddress::remapped(offset), AlwaysPreTouch); + map_view(pmem, ZAddress::marked0(offset)); + map_view(pmem, ZAddress::marked1(offset)); + map_view(pmem, ZAddress::remapped(offset)); } } @@ -202,7 +209,7 @@ void ZPhysicalMemoryBacking::unmap(const ZPhysicalMemory& pmem, uintptr_t offset void ZPhysicalMemoryBacking::debug_map(const ZPhysicalMemory& pmem, uintptr_t offset) const { // Map good view assert(ZVerifyViews, "Should be enabled"); - map_view(pmem, ZAddress::good(offset), false /* pretouch */); + map_view(pmem, ZAddress::good(offset)); } void ZPhysicalMemoryBacking::debug_unmap(const ZPhysicalMemory& pmem, uintptr_t offset) const { diff --git a/src/hotspot/os/windows/gc/z/zPhysicalMemoryBacking_windows.hpp b/src/hotspot/os/windows/gc/z/zPhysicalMemoryBacking_windows.hpp index 3f105d671e8..bc7af9caee9 100644 --- a/src/hotspot/os/windows/gc/z/zPhysicalMemoryBacking_windows.hpp +++ b/src/hotspot/os/windows/gc/z/zPhysicalMemoryBacking_windows.hpp @@ -36,7 +36,7 @@ private: ZMemoryManager _uncommitted; void pretouch_view(uintptr_t addr, size_t size) const; - void map_view(const ZPhysicalMemory& pmem, uintptr_t addr, bool pretouch) const; + void map_view(const ZPhysicalMemory& pmem, uintptr_t addr) const; void unmap_view(const ZPhysicalMemory& pmem, uintptr_t addr) const; public: @@ -53,6 +53,8 @@ public: uintptr_t nmt_address(uintptr_t offset) const; + void pretouch(uintptr_t offset, size_t size) const; + void map(const ZPhysicalMemory& pmem, uintptr_t offset) const; void unmap(const ZPhysicalMemory& pmem, uintptr_t offset) const; diff --git a/src/hotspot/share/gc/z/zHeap.cpp b/src/hotspot/share/gc/z/zHeap.cpp index c6c3c0ca6c0..e4b8bf924b4 100644 --- a/src/hotspot/share/gc/z/zHeap.cpp +++ b/src/hotspot/share/gc/z/zHeap.cpp @@ -57,7 +57,7 @@ ZHeap* ZHeap::_heap = NULL; ZHeap::ZHeap() : _workers(), _object_allocator(), - _page_allocator(heap_min_size(), heap_initial_size(), heap_max_size(), heap_max_reserve_size()), + _page_allocator(&_workers, heap_min_size(), heap_initial_size(), heap_max_size(), heap_max_reserve_size()), _page_table(), _forwarding_table(), _mark(&_workers, &_page_table), diff --git a/src/hotspot/share/gc/z/zPageAllocator.cpp b/src/hotspot/share/gc/z/zPageAllocator.cpp index c92abdc7910..3849f5f02d7 100644 --- a/src/hotspot/share/gc/z/zPageAllocator.cpp +++ b/src/hotspot/share/gc/z/zPageAllocator.cpp @@ -33,7 +33,9 @@ #include "gc/z/zPageCache.inline.hpp" #include "gc/z/zSafeDelete.inline.hpp" #include "gc/z/zStat.hpp" +#include "gc/z/zTask.hpp" #include "gc/z/zTracer.inline.hpp" +#include "gc/z/zWorkers.hpp" #include "runtime/globals.hpp" #include "runtime/init.hpp" #include "runtime/java.hpp" @@ -95,7 +97,8 @@ public: ZPage* const ZPageAllocator::gc_marker = (ZPage*)-1; -ZPageAllocator::ZPageAllocator(size_t min_capacity, +ZPageAllocator::ZPageAllocator(ZWorkers* workers, + size_t min_capacity, size_t initial_capacity, size_t max_capacity, size_t max_reserve) : @@ -150,13 +153,42 @@ ZPageAllocator::ZPageAllocator(size_t min_capacity, } // Pre-map initial capacity - prime_cache(initial_capacity); + prime_cache(workers, initial_capacity); // Successfully initialized _initialized = true; } -void ZPageAllocator::prime_cache(size_t size) { +class ZPreTouchTask : public ZTask { +private: + const ZPhysicalMemoryManager* const _physical; + volatile uintptr_t _start; + const uintptr_t _end; + +public: + ZPreTouchTask(const ZPhysicalMemoryManager* physical, uintptr_t start, uintptr_t end) : + ZTask("ZPreTouchTask"), + _physical(physical), + _start(start), + _end(end) {} + + virtual void work() { + for (;;) { + // Get granule offset + const size_t size = ZGranuleSize; + const uintptr_t offset = Atomic::add(&_start, size) - size; + if (offset >= _end) { + // Done + break; + } + + // Pre-touch granule + _physical->pretouch(offset, size); + } + } +}; + +void ZPageAllocator::prime_cache(ZWorkers* workers, size_t size) { // Allocate physical memory const ZPhysicalMemory pmem = _physical.alloc(size); guarantee(!pmem.is_null(), "Invalid size"); @@ -172,6 +204,12 @@ void ZPageAllocator::prime_cache(size_t size) { map_page(page); page->set_pre_mapped(); + if (AlwaysPreTouch) { + // Pre-touch page + ZPreTouchTask task(&_physical, page->start(), page->end()); + workers->run_parallel(&task); + } + // Add page to cache page->set_last_used(); _cache.free_page(page); diff --git a/src/hotspot/share/gc/z/zPageAllocator.hpp b/src/hotspot/share/gc/z/zPageAllocator.hpp index 9bcd08cb6c7..c97a70fd028 100644 --- a/src/hotspot/share/gc/z/zPageAllocator.hpp +++ b/src/hotspot/share/gc/z/zPageAllocator.hpp @@ -34,6 +34,7 @@ #include "memory/allocation.hpp" class ZPageAllocRequest; +class ZWorkers; class ZPageAllocator { friend class VMStructs; @@ -61,7 +62,7 @@ private: static ZPage* const gc_marker; - void prime_cache(size_t size); + void prime_cache(ZWorkers* workers, size_t size); void increase_used(size_t size, bool relocation); void decrease_used(size_t size, bool reclaimed); @@ -86,7 +87,8 @@ private: void satisfy_alloc_queue(); public: - ZPageAllocator(size_t min_capacity, + ZPageAllocator(ZWorkers* workers, + size_t min_capacity, size_t initial_capacity, size_t max_capacity, size_t max_reserve); diff --git a/src/hotspot/share/gc/z/zPhysicalMemory.cpp b/src/hotspot/share/gc/z/zPhysicalMemory.cpp index ab878636566..c42ead0306b 100644 --- a/src/hotspot/share/gc/z/zPhysicalMemory.cpp +++ b/src/hotspot/share/gc/z/zPhysicalMemory.cpp @@ -173,6 +173,10 @@ void ZPhysicalMemoryManager::free(const ZPhysicalMemory& pmem) { _backing.free(pmem); } +void ZPhysicalMemoryManager::pretouch(uintptr_t offset, size_t size) const { + _backing.pretouch(offset, size); +} + void ZPhysicalMemoryManager::map(const ZPhysicalMemory& pmem, uintptr_t offset) const { _backing.map(pmem, offset); nmt_commit(pmem, offset); diff --git a/src/hotspot/share/gc/z/zPhysicalMemory.hpp b/src/hotspot/share/gc/z/zPhysicalMemory.hpp index e3701066a4f..de7ab41b628 100644 --- a/src/hotspot/share/gc/z/zPhysicalMemory.hpp +++ b/src/hotspot/share/gc/z/zPhysicalMemory.hpp @@ -82,6 +82,8 @@ public: ZPhysicalMemory alloc(size_t size); void free(const ZPhysicalMemory& pmem); + void pretouch(uintptr_t offset, size_t size) const; + void map(const ZPhysicalMemory& pmem, uintptr_t offset) const; void unmap(const ZPhysicalMemory& pmem, uintptr_t offset) const; diff --git a/src/hotspot/share/gc/z/zWorkers.cpp b/src/hotspot/share/gc/z/zWorkers.cpp index 4bbe9675dd9..e7d1d0db7be 100644 --- a/src/hotspot/share/gc/z/zWorkers.cpp +++ b/src/hotspot/share/gc/z/zWorkers.cpp @@ -100,7 +100,6 @@ void ZWorkers::run(ZTask* task, uint nworkers) { } void ZWorkers::run_parallel(ZTask* task) { - assert(SafepointSynchronize::is_at_safepoint(), "Should be at a safepoint"); run(task, nparallel()); } diff --git a/test/hotspot/jtreg/gc/z/TestAlwaysPreTouch.java b/test/hotspot/jtreg/gc/z/TestAlwaysPreTouch.java new file mode 100644 index 00000000000..8a100a51677 --- /dev/null +++ b/test/hotspot/jtreg/gc/z/TestAlwaysPreTouch.java @@ -0,0 +1,41 @@ +/* + * 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. + */ + +package gc.z; + +/* + * @test TestAlwaysPreTouch + * @requires vm.gc.Z & !vm.graal.enabled + * @summary Test ZGC parallel pre-touch + * @run main/othervm -XX:+UnlockExperimentalVMOptions -XX:+UseZGC -Xlog:gc* -XX:-AlwaysPreTouch -Xms128M -Xmx128M gc.z.TestAlwaysPreTouch + * @run main/othervm -XX:+UnlockExperimentalVMOptions -XX:+UseZGC -Xlog:gc* -XX:+AlwaysPreTouch -XX:ParallelGCThreads=1 -Xms2M -Xmx128M gc.z.TestAlwaysPreTouch + * @run main/othervm -XX:+UnlockExperimentalVMOptions -XX:+UseZGC -Xlog:gc* -XX:+AlwaysPreTouch -XX:ParallelGCThreads=8 -Xms2M -Xmx128M gc.z.TestAlwaysPreTouch + * @run main/othervm -XX:+UnlockExperimentalVMOptions -XX:+UseZGC -Xlog:gc* -XX:+AlwaysPreTouch -XX:ParallelGCThreads=1 -Xms128M -Xmx128M gc.z.TestAlwaysPreTouch + * @run main/othervm -XX:+UnlockExperimentalVMOptions -XX:+UseZGC -Xlog:gc* -XX:+AlwaysPreTouch -XX:ParallelGCThreads=8 -Xms128M -Xmx128M gc.z.TestAlwaysPreTouch + */ + +public class TestAlwaysPreTouch { + public static void main(String[] args) throws Exception { + System.out.println("Success"); + } +} From f91513a7b0b11f80bdcd554500852b6500f66a51 Mon Sep 17 00:00:00 2001 From: Harold Seigel Date: Tue, 3 Dec 2019 14:10:53 +0000 Subject: [PATCH 10/81] 8234656: Improve granularity of verifier logging Print brief output for log level 'info'. Print detailed output for 'debug' and 'trace'. Reviewed-by: iklam, lfoltan, dholmes --- src/hotspot/share/classfile/verifier.cpp | 8 +++--- .../runtime/logging/VerificationTest.java | 26 +++++++++++++++---- .../jtreg/runtime/verifier/TraceClassRes.java | 8 +++--- 3 files changed, 29 insertions(+), 13 deletions(-) diff --git a/src/hotspot/share/classfile/verifier.cpp b/src/hotspot/share/classfile/verifier.cpp index 267ab322137..d1de0bc35de 100644 --- a/src/hotspot/share/classfile/verifier.cpp +++ b/src/hotspot/share/classfile/verifier.cpp @@ -739,7 +739,7 @@ void ClassVerifier::verify_method(const methodHandle& m, TRAPS) { StackMapTable stackmap_table(&reader, ¤t_frame, max_locals, max_stack, code_data, code_length, CHECK_VERIFY(this)); - LogTarget(Info, verification) lt; + LogTarget(Debug, verification) lt; if (lt.is_enabled()) { ResourceMark rm(THREAD); LogStream ls(lt); @@ -783,7 +783,7 @@ void ClassVerifier::verify_method(const methodHandle& m, TRAPS) { VerificationType type, type2; VerificationType atype; - LogTarget(Info, verification) lt; + LogTarget(Debug, verification) lt; if (lt.is_enabled()) { ResourceMark rm(THREAD); LogStream ls(lt); @@ -2648,9 +2648,9 @@ void ClassVerifier::verify_invoke_init( verify_error(ErrorContext::bad_code(bci), "Bad method call from after the start of a try block"); return; - } else if (log_is_enabled(Info, verification)) { + } else if (log_is_enabled(Debug, verification)) { ResourceMark rm(THREAD); - log_info(verification)("Survived call to ends_in_athrow(): %s", + log_debug(verification)("Survived call to ends_in_athrow(): %s", current_class()->name()->as_C_string()); } } diff --git a/test/hotspot/jtreg/runtime/logging/VerificationTest.java b/test/hotspot/jtreg/runtime/logging/VerificationTest.java index a20bd37c715..61140aaae32 100644 --- a/test/hotspot/jtreg/runtime/logging/VerificationTest.java +++ b/test/hotspot/jtreg/runtime/logging/VerificationTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 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,8 +23,8 @@ /* * @test - * @bug 8150083 - * @summary verification=info output should have output from the code + * @bug 8150083 8234656 + * @summary test enabling and disabling verification logging and verification log levels * @library /test/lib * @modules java.base/jdk.internal.misc * java.management @@ -35,12 +35,23 @@ import jdk.test.lib.process.OutputAnalyzer; import jdk.test.lib.process.ProcessTools; public class VerificationTest { - static void analyzeOutputOn(ProcessBuilder pb) throws Exception { + + static void analyzeOutputOn(ProcessBuilder pb, boolean isLogLevelInfo) throws Exception { OutputAnalyzer output = new OutputAnalyzer(pb.start()); output.shouldContain("[verification]"); output.shouldContain("Verifying class VerificationTest$InternalClass with new format"); output.shouldContain("Verifying method VerificationTest$InternalClass.()V"); output.shouldContain("End class verification for: VerificationTest$InternalClass"); + + if (isLogLevelInfo) { + // logging level 'info' should not output stack map and opcode data. + output.shouldNotContain("[verification] StackMapTable: frame_count"); + output.shouldNotContain("[verification] offset = 0, opcode ="); + + } else { // log level debug + output.shouldContain("[debug][verification] StackMapTable: frame_count"); + output.shouldContain("[debug][verification] offset = 0, opcode ="); + } output.shouldHaveExitValue(0); } @@ -53,11 +64,16 @@ public class VerificationTest { public static void main(String[] args) throws Exception { ProcessBuilder pb = ProcessTools.createJavaProcessBuilder("-Xlog:verification=info", InternalClass.class.getName()); - analyzeOutputOn(pb); + analyzeOutputOn(pb, true); pb = ProcessTools.createJavaProcessBuilder("-Xlog:verification=off", InternalClass.class.getName()); analyzeOutputOff(pb); + + // logging level 'debug' should output stackmaps and bytecode data. + pb = ProcessTools.createJavaProcessBuilder("-Xlog:verification=debug", + InternalClass.class.getName()); + analyzeOutputOn(pb, false); } public static class InternalClass { diff --git a/test/hotspot/jtreg/runtime/verifier/TraceClassRes.java b/test/hotspot/jtreg/runtime/verifier/TraceClassRes.java index dbfe16c6f2b..152a8f62eb2 100644 --- a/test/hotspot/jtreg/runtime/verifier/TraceClassRes.java +++ b/test/hotspot/jtreg/runtime/verifier/TraceClassRes.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 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 @@ -24,7 +24,7 @@ /* * @test * @bug 8076318 - * @summary split verifier needs to add TraceClassResolution + * @summary split verifier needs to add class resolution tracing * @modules java.base/jdk.internal.misc * @library /test/lib */ @@ -32,12 +32,12 @@ import jdk.test.lib.process.ProcessTools; import jdk.test.lib.process.OutputAnalyzer; -// Test that the verifier outputs the classes it loads if -XX:+TraceClassResolution is specified" +// Test that the verifier outputs the classes it loads if -Xlog:class+resove=debug is specified" public class TraceClassRes { public static void main(String[] args) throws Exception { ProcessBuilder pb = ProcessTools.createJavaProcessBuilder( - "-XX:+TraceClassResolution", "-verify", "-Xshare:off", "-version"); + "-Xlog:class+resolve=debug", "-verify", "-Xshare:off", "-version"); OutputAnalyzer output = new OutputAnalyzer(pb.start()); output.shouldContain("[class,resolve] java.lang.ClassLoader java.lang.Throwable ClassLoader.java (verification)"); From 095d77acf0376ab6649c5b3fc509157981572e26 Mon Sep 17 00:00:00 2001 From: Julia Boes Date: Tue, 3 Dec 2019 12:44:50 +0000 Subject: [PATCH 11/81] 8234964: failure_handler: gather more environment information on Windows, Solaris and Linux Add 'ifconfig -a' on Solaris and Linux, 'ipconfig /all' on Windows Reviewed-by: iignatyev, vtewari --- .../src/share/conf/linux.properties | 9 ++++++--- .../src/share/conf/mac.properties | 20 +++++++++---------- .../src/share/conf/solaris.properties | 16 ++++++++------- .../src/share/conf/windows.properties | 6 ++++-- 4 files changed, 28 insertions(+), 23 deletions(-) diff --git a/test/failure_handler/src/share/conf/linux.properties b/test/failure_handler/src/share/conf/linux.properties index b3ef553b6f7..bb7eef38d12 100644 --- a/test/failure_handler/src/share/conf/linux.properties +++ b/test/failure_handler/src/share/conf/linux.properties @@ -1,5 +1,5 @@ # -# Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2015, 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 @@ -68,7 +68,7 @@ environment=\ memory.vmstat.slabinfo memory.vmstat.disk \ files \ locks \ - net.sockets net.statistics + net.sockets net.statistics net.ifconfig ################################################################################ users.current.app=id users.current.args=-a @@ -103,8 +103,11 @@ files.app=lsof locks.app=lslocks locks.args=-u -net.app=netstat +net.sockets.app=netstat net.sockets.args=-aeeopv +net.statistics.app=netstat net.statistics.args=-sv +net.ifconfig.app=ifconfig +net.ifconfig.args=-a ################################################################################ diff --git a/test/failure_handler/src/share/conf/mac.properties b/test/failure_handler/src/share/conf/mac.properties index 53b5858591d..401901610fd 100644 --- a/test/failure_handler/src/share/conf/mac.properties +++ b/test/failure_handler/src/share/conf/mac.properties @@ -1,5 +1,5 @@ # -# Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2015, 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 @@ -75,8 +75,7 @@ environment=\ process.ps process.top \ memory.vmstat \ files \ - netstat.av netstat.aL netstat.m netstat.s \ - ifconfig \ + net.netstat.av net.netstat.aL net.netstat.m net.netstat.s net.ifconfig \ scutil.nwi scutil.proxy ################################################################################ users.current.app=id @@ -105,14 +104,13 @@ memory.vmstat.args=-c 3 3 files.app=lsof -netstat.app=netstat -netstat.av.args=-av -netstat.aL.args=-aL -netstat.m.args=-m -netstat.s.args=-s - -ifconfig.app=ifconfig -ifconfig.args=-a +net.netstat.app=netstat +net.netstat.av.args=-av +net.netstat.aL.args=-aL +net.netstat.m.args=-m +net.netstat.s.args=-s +net.ifconfig.app=ifconfig +net.ifconfig.args=-a scutil.app=scutil scutil.nwi.args=--nwi diff --git a/test/failure_handler/src/share/conf/solaris.properties b/test/failure_handler/src/share/conf/solaris.properties index 69c12cfc614..1fd967669d6 100644 --- a/test/failure_handler/src/share/conf/solaris.properties +++ b/test/failure_handler/src/share/conf/solaris.properties @@ -1,5 +1,5 @@ # -# Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2015, 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 @@ -64,7 +64,7 @@ environment=\ system.dmesg system.prtconf system.sysdef \ process.ps process.top \ memory.swap memory.vmstat.default memory.vmstat.statistics memory.pagesize \ - netstat.av netstat.m netstat.s netstat.i + net.netstat.av net.netstat.m net.netstat.s net.netstat.i net.ifconfig ################################################################################ # common unix ################################################################################ @@ -103,9 +103,11 @@ memory.pagesize.app=pagesize # prstat.app=prstat # prstat.args=-a -netstat.app=netstat -netstat.av.args=-av -netstat.m.args=-m -netstat.s.args=-s -netstat.i.args=-i 1 5 +net.netstat.app=netstat +net.netstat.av.args=-av +net.netstat.m.args=-m +net.netstat.s.args=-s +net.netstat.i.args=-i 1 5 +net.ifconfig.app=/sbin/ifconfig +net.ifconfig.args=-a ################################################################################ diff --git a/test/failure_handler/src/share/conf/windows.properties b/test/failure_handler/src/share/conf/windows.properties index ed5385cba83..0c76ac2c476 100644 --- a/test/failure_handler/src/share/conf/windows.properties +++ b/test/failure_handler/src/share/conf/windows.properties @@ -1,5 +1,5 @@ # -# Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2015, 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 @@ -71,7 +71,7 @@ environment=\ memory.free memory.vmstat.default memory.vmstat.statistics \ memory.vmstat.slabinfo memory.vmstat.disk \ files \ - net.sockets net.statistics + net.sockets net.statistics net.ipconfig ################################################################################ users.current.app=id users.current.args=-a @@ -112,4 +112,6 @@ net.sockets.args=-c\0netstat -b -a -t -o || netstat -a -t -o net.sockets.args.delimiter=\0 net.statistics.app=netstat net.statistics.args=-s -e +net.ipconfig.app=ipconfig +net.ipconfig.args=/all ################################################################################ From 21e03e71aa35d2d2bf5f959ea9af8e6f256a9a3d Mon Sep 17 00:00:00 2001 From: Robbin Ehn Date: Tue, 3 Dec 2019 15:32:41 +0100 Subject: [PATCH 12/81] 8234796: Refactor Handshake::execute to take a more complex type than ThreadClosure Reviewed-by: dholmes, pliden, coleenp --- src/hotspot/share/gc/g1/g1ConcurrentMark.cpp | 1 + src/hotspot/share/gc/g1/g1ConcurrentMark.hpp | 1 + .../share/gc/g1/g1ConcurrentRefine.cpp | 1 + src/hotspot/share/gc/g1/g1DirtyCardQueue.cpp | 1 + src/hotspot/share/gc/g1/g1RemSetSummary.cpp | 1 + .../gc/parallel/parallelScavengeHeap.cpp | 1 + src/hotspot/share/gc/parallel/psScavenge.cpp | 1 + .../share/gc/shared/genCollectedHeap.cpp | 1 + .../gc/shared/stringdedup/stringDedup.cpp | 1 + .../gc/shared/stringdedup/stringDedup.hpp | 2 ++ src/hotspot/share/gc/shared/workgroup.cpp | 1 + src/hotspot/share/gc/shared/workgroup.hpp | 1 + .../share/gc/shenandoah/shenandoahUnload.cpp | 3 ++- src/hotspot/share/gc/z/zCollectedHeap.cpp | 1 + src/hotspot/share/gc/z/zHeap.cpp | 7 ++++-- src/hotspot/share/gc/z/zHeap.hpp | 2 ++ src/hotspot/share/gc/z/zMark.cpp | 3 ++- src/hotspot/share/gc/z/zRootsIterator.cpp | 1 + src/hotspot/share/gc/z/zRuntimeWorkers.hpp | 4 +++- src/hotspot/share/gc/z/zWorkers.hpp | 3 ++- .../checkpoint/jfrCheckpointManager.cpp | 1 + .../jfr/recorder/checkpoint/types/jfrType.cpp | 1 + .../share/jfr/writers/jfrJavaEventWriter.cpp | 1 + src/hotspot/share/memory/iterator.hpp | 7 ++++++ src/hotspot/share/prims/jvmtiEnvBase.cpp | 1 + src/hotspot/share/prims/whitebox.cpp | 4 ++-- src/hotspot/share/runtime/biasedLocking.cpp | 6 +++-- src/hotspot/share/runtime/deoptimization.cpp | 10 ++++----- src/hotspot/share/runtime/handshake.cpp | 22 +++++++++---------- src/hotspot/share/runtime/handshake.hpp | 18 +++++++++++---- src/hotspot/share/runtime/sweeper.cpp | 14 ++++++------ src/hotspot/share/runtime/thread.cpp | 1 + src/hotspot/share/runtime/thread.hpp | 7 ------ .../share/runtime/threadSMR.inline.hpp | 1 + src/hotspot/share/runtime/vmThread.cpp | 9 ++++---- src/hotspot/share/utilities/globalCounter.cpp | 5 +++-- 36 files changed, 95 insertions(+), 50 deletions(-) diff --git a/src/hotspot/share/gc/g1/g1ConcurrentMark.cpp b/src/hotspot/share/gc/g1/g1ConcurrentMark.cpp index 8f78a8419ce..8b8c84771eb 100644 --- a/src/hotspot/share/gc/g1/g1ConcurrentMark.cpp +++ b/src/hotspot/share/gc/g1/g1ConcurrentMark.cpp @@ -55,6 +55,7 @@ #include "include/jvm.h" #include "logging/log.hpp" #include "memory/allocation.hpp" +#include "memory/iterator.hpp" #include "memory/resourceArea.hpp" #include "memory/universe.hpp" #include "oops/access.inline.hpp" diff --git a/src/hotspot/share/gc/g1/g1ConcurrentMark.hpp b/src/hotspot/share/gc/g1/g1ConcurrentMark.hpp index f862ec10713..c99df841920 100644 --- a/src/hotspot/share/gc/g1/g1ConcurrentMark.hpp +++ b/src/hotspot/share/gc/g1/g1ConcurrentMark.hpp @@ -45,6 +45,7 @@ class G1ConcurrentMark; class G1OldTracer; class G1RegionToSpaceMapper; class G1SurvivorRegions; +class ThreadClosure; PRAGMA_DIAG_PUSH // warning C4522: multiple assignment operators specified diff --git a/src/hotspot/share/gc/g1/g1ConcurrentRefine.cpp b/src/hotspot/share/gc/g1/g1ConcurrentRefine.cpp index 2b5153ec094..d502f3522cf 100644 --- a/src/hotspot/share/gc/g1/g1ConcurrentRefine.cpp +++ b/src/hotspot/share/gc/g1/g1ConcurrentRefine.cpp @@ -29,6 +29,7 @@ #include "gc/g1/g1DirtyCardQueue.hpp" #include "logging/log.hpp" #include "memory/allocation.inline.hpp" +#include "memory/iterator.hpp" #include "runtime/java.hpp" #include "runtime/thread.hpp" #include "utilities/debug.hpp" diff --git a/src/hotspot/share/gc/g1/g1DirtyCardQueue.cpp b/src/hotspot/share/gc/g1/g1DirtyCardQueue.cpp index 6b167400fbd..c7f2c76cf08 100644 --- a/src/hotspot/share/gc/g1/g1DirtyCardQueue.cpp +++ b/src/hotspot/share/gc/g1/g1DirtyCardQueue.cpp @@ -34,6 +34,7 @@ #include "gc/g1/heapRegionRemSet.hpp" #include "gc/shared/suspendibleThreadSet.hpp" #include "gc/shared/workgroup.hpp" +#include "memory/iterator.hpp" #include "runtime/flags/flagSetting.hpp" #include "runtime/mutexLocker.hpp" #include "runtime/orderAccess.hpp" diff --git a/src/hotspot/share/gc/g1/g1RemSetSummary.cpp b/src/hotspot/share/gc/g1/g1RemSetSummary.cpp index 3aaeec583ee..f78971fcc5f 100644 --- a/src/hotspot/share/gc/g1/g1RemSetSummary.cpp +++ b/src/hotspot/share/gc/g1/g1RemSetSummary.cpp @@ -34,6 +34,7 @@ #include "gc/g1/heapRegion.hpp" #include "gc/g1/heapRegionRemSet.hpp" #include "memory/allocation.inline.hpp" +#include "memory/iterator.hpp" #include "runtime/thread.inline.hpp" void G1RemSetSummary::update() { diff --git a/src/hotspot/share/gc/parallel/parallelScavengeHeap.cpp b/src/hotspot/share/gc/parallel/parallelScavengeHeap.cpp index dc6c52ce8a6..02f0e8b7de4 100644 --- a/src/hotspot/share/gc/parallel/parallelScavengeHeap.cpp +++ b/src/hotspot/share/gc/parallel/parallelScavengeHeap.cpp @@ -44,6 +44,7 @@ #include "gc/shared/locationPrinter.inline.hpp" #include "gc/shared/scavengableNMethods.hpp" #include "logging/log.hpp" +#include "memory/iterator.hpp" #include "memory/metaspaceCounters.hpp" #include "memory/universe.hpp" #include "oops/oop.inline.hpp" diff --git a/src/hotspot/share/gc/parallel/psScavenge.cpp b/src/hotspot/share/gc/parallel/psScavenge.cpp index 65c24bf6d17..621a4b83ba8 100644 --- a/src/hotspot/share/gc/parallel/psScavenge.cpp +++ b/src/hotspot/share/gc/parallel/psScavenge.cpp @@ -52,6 +52,7 @@ #include "gc/shared/weakProcessor.hpp" #include "gc/shared/workerPolicy.hpp" #include "gc/shared/workgroup.hpp" +#include "memory/iterator.hpp" #include "memory/resourceArea.hpp" #include "memory/universe.hpp" #include "logging/log.hpp" diff --git a/src/hotspot/share/gc/shared/genCollectedHeap.cpp b/src/hotspot/share/gc/shared/genCollectedHeap.cpp index 2a190f6606b..f80fc126e2c 100644 --- a/src/hotspot/share/gc/shared/genCollectedHeap.cpp +++ b/src/hotspot/share/gc/shared/genCollectedHeap.cpp @@ -55,6 +55,7 @@ #include "gc/shared/weakProcessor.hpp" #include "gc/shared/workgroup.hpp" #include "memory/filemap.hpp" +#include "memory/iterator.hpp" #include "memory/metaspaceCounters.hpp" #include "memory/resourceArea.hpp" #include "memory/universe.hpp" diff --git a/src/hotspot/share/gc/shared/stringdedup/stringDedup.cpp b/src/hotspot/share/gc/shared/stringdedup/stringDedup.cpp index c98c045fd09..c10902cb7dc 100644 --- a/src/hotspot/share/gc/shared/stringdedup/stringDedup.cpp +++ b/src/hotspot/share/gc/shared/stringdedup/stringDedup.cpp @@ -27,6 +27,7 @@ #include "gc/shared/stringdedup/stringDedupQueue.hpp" #include "gc/shared/stringdedup/stringDedupTable.hpp" #include "gc/shared/stringdedup/stringDedupThread.hpp" +#include "memory/iterator.hpp" bool StringDedup::_enabled = false; diff --git a/src/hotspot/share/gc/shared/stringdedup/stringDedup.hpp b/src/hotspot/share/gc/shared/stringdedup/stringDedup.hpp index f9aba809b57..eb79ec79c15 100644 --- a/src/hotspot/share/gc/shared/stringdedup/stringDedup.hpp +++ b/src/hotspot/share/gc/shared/stringdedup/stringDedup.hpp @@ -69,6 +69,8 @@ #include "memory/allocation.hpp" #include "runtime/thread.hpp" +class ThreadClosure; + // // Main interface for interacting with string deduplication. // diff --git a/src/hotspot/share/gc/shared/workgroup.cpp b/src/hotspot/share/gc/shared/workgroup.cpp index 396eda29292..e457301f6bf 100644 --- a/src/hotspot/share/gc/shared/workgroup.cpp +++ b/src/hotspot/share/gc/shared/workgroup.cpp @@ -28,6 +28,7 @@ #include "gc/shared/workerManager.hpp" #include "memory/allocation.hpp" #include "memory/allocation.inline.hpp" +#include "memory/iterator.hpp" #include "runtime/atomic.hpp" #include "runtime/os.hpp" #include "runtime/semaphore.hpp" diff --git a/src/hotspot/share/gc/shared/workgroup.hpp b/src/hotspot/share/gc/shared/workgroup.hpp index dbf84ba922e..a2455c01114 100644 --- a/src/hotspot/share/gc/shared/workgroup.hpp +++ b/src/hotspot/share/gc/shared/workgroup.hpp @@ -50,6 +50,7 @@ class AbstractGangWorker; class Semaphore; +class ThreadClosure; class WorkGang; // An abstract task to be worked on by a gang. diff --git a/src/hotspot/share/gc/shenandoah/shenandoahUnload.cpp b/src/hotspot/share/gc/shenandoah/shenandoahUnload.cpp index 429c20c9d6c..1022cdd5b90 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahUnload.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahUnload.cpp @@ -158,8 +158,9 @@ void ShenandoahUnload::purge() { CodeCache::purge_exception_caches(); } -class ShenandoahUnloadRendezvousClosure : public ThreadClosure { +class ShenandoahUnloadRendezvousClosure : public HandshakeClosure { public: + ShenandoahUnloadRendezvousClosure() : HandshakeClosure("ShenandoahUnloadRendezvous") {} void do_thread(Thread* thread) {} }; diff --git a/src/hotspot/share/gc/z/zCollectedHeap.cpp b/src/hotspot/share/gc/z/zCollectedHeap.cpp index 75fd677ee24..5652ff61d19 100644 --- a/src/hotspot/share/gc/z/zCollectedHeap.cpp +++ b/src/hotspot/share/gc/z/zCollectedHeap.cpp @@ -33,6 +33,7 @@ #include "gc/z/zServiceability.hpp" #include "gc/z/zStat.hpp" #include "gc/z/zUtils.inline.hpp" +#include "memory/iterator.hpp" #include "memory/universe.hpp" #include "runtime/mutexLocker.hpp" #include "utilities/align.hpp" diff --git a/src/hotspot/share/gc/z/zHeap.cpp b/src/hotspot/share/gc/z/zHeap.cpp index e4b8bf924b4..bb10f7066b4 100644 --- a/src/hotspot/share/gc/z/zHeap.cpp +++ b/src/hotspot/share/gc/z/zHeap.cpp @@ -326,9 +326,12 @@ void ZHeap::set_soft_reference_policy(bool clear) { _reference_processor.set_soft_reference_policy(clear); } -class ZRendezvousClosure : public ThreadClosure { +class ZRendezvousClosure : public HandshakeClosure { public: - virtual void do_thread(Thread* thread) {} + ZRendezvousClosure() : + HandshakeClosure("ZRendezvous") {} + + void do_thread(Thread* thread) {} }; void ZHeap::process_non_strong_references() { diff --git a/src/hotspot/share/gc/z/zHeap.hpp b/src/hotspot/share/gc/z/zHeap.hpp index 7c7c92b8d83..b45f1ddc788 100644 --- a/src/hotspot/share/gc/z/zHeap.hpp +++ b/src/hotspot/share/gc/z/zHeap.hpp @@ -39,6 +39,8 @@ #include "gc/z/zUnload.hpp" #include "gc/z/zWorkers.hpp" +class ThreadClosure; + class ZHeap { friend class VMStructs; diff --git a/src/hotspot/share/gc/z/zMark.cpp b/src/hotspot/share/gc/z/zMark.cpp index e9cb3b63a52..798b60f7a14 100644 --- a/src/hotspot/share/gc/z/zMark.cpp +++ b/src/hotspot/share/gc/z/zMark.cpp @@ -413,13 +413,14 @@ void ZMark::idle() const { os::naked_short_sleep(1); } -class ZMarkFlushAndFreeStacksClosure : public ThreadClosure { +class ZMarkFlushAndFreeStacksClosure : public HandshakeClosure { private: ZMark* const _mark; bool _flushed; public: ZMarkFlushAndFreeStacksClosure(ZMark* mark) : + HandshakeClosure("ZMarkFlushAndFreeStacks"), _mark(mark), _flushed(false) {} diff --git a/src/hotspot/share/gc/z/zRootsIterator.cpp b/src/hotspot/share/gc/z/zRootsIterator.cpp index 4d297e26ad5..438e467c5f6 100644 --- a/src/hotspot/share/gc/z/zRootsIterator.cpp +++ b/src/hotspot/share/gc/z/zRootsIterator.cpp @@ -39,6 +39,7 @@ #include "gc/z/zRootsIterator.hpp" #include "gc/z/zStat.hpp" #include "gc/z/zThreadLocalData.hpp" +#include "memory/iterator.hpp" #include "memory/resourceArea.hpp" #include "memory/universe.hpp" #include "prims/jvmtiExport.hpp" diff --git a/src/hotspot/share/gc/z/zRuntimeWorkers.hpp b/src/hotspot/share/gc/z/zRuntimeWorkers.hpp index 99095c5b7a0..a201c79fa23 100644 --- a/src/hotspot/share/gc/z/zRuntimeWorkers.hpp +++ b/src/hotspot/share/gc/z/zRuntimeWorkers.hpp @@ -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 @@ -26,6 +26,8 @@ #include "gc/shared/workgroup.hpp" +class ThreadClosure; + class ZRuntimeWorkers { private: WorkGang _workers; diff --git a/src/hotspot/share/gc/z/zWorkers.hpp b/src/hotspot/share/gc/z/zWorkers.hpp index 7176c40e4da..329a1a21c42 100644 --- a/src/hotspot/share/gc/z/zWorkers.hpp +++ b/src/hotspot/share/gc/z/zWorkers.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 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 @@ -27,6 +27,7 @@ #include "gc/shared/workgroup.hpp" #include "memory/allocation.hpp" +class ThreadClosure; class ZTask; class ZWorkers { diff --git a/src/hotspot/share/jfr/recorder/checkpoint/jfrCheckpointManager.cpp b/src/hotspot/share/jfr/recorder/checkpoint/jfrCheckpointManager.cpp index 244387f19de..12858f88abe 100644 --- a/src/hotspot/share/jfr/recorder/checkpoint/jfrCheckpointManager.cpp +++ b/src/hotspot/share/jfr/recorder/checkpoint/jfrCheckpointManager.cpp @@ -42,6 +42,7 @@ #include "jfr/utilities/jfrTypes.hpp" #include "jfr/writers/jfrJavaEventWriter.hpp" #include "logging/log.hpp" +#include "memory/iterator.hpp" #include "memory/resourceArea.hpp" #include "runtime/handles.inline.hpp" #include "runtime/mutex.hpp" diff --git a/src/hotspot/share/jfr/recorder/checkpoint/types/jfrType.cpp b/src/hotspot/share/jfr/recorder/checkpoint/types/jfrType.cpp index b11ef50113f..6b6229fc162 100644 --- a/src/hotspot/share/jfr/recorder/checkpoint/types/jfrType.cpp +++ b/src/hotspot/share/jfr/recorder/checkpoint/types/jfrType.cpp @@ -40,6 +40,7 @@ #include "jfr/support/jfrThreadLocal.hpp" #include "jfr/writers/jfrJavaEventWriter.hpp" #include "jfr/utilities/jfrThreadIterator.hpp" +#include "memory/iterator.hpp" #include "memory/metaspaceGCThresholdUpdater.hpp" #include "memory/referenceType.hpp" #include "memory/universe.hpp" diff --git a/src/hotspot/share/jfr/writers/jfrJavaEventWriter.cpp b/src/hotspot/share/jfr/writers/jfrJavaEventWriter.cpp index 162a44f287f..32162fc399b 100644 --- a/src/hotspot/share/jfr/writers/jfrJavaEventWriter.cpp +++ b/src/hotspot/share/jfr/writers/jfrJavaEventWriter.cpp @@ -32,6 +32,7 @@ #include "jfr/support/jfrThreadId.hpp" #include "jfr/utilities/jfrTypes.hpp" #include "jfr/writers/jfrJavaEventWriter.hpp" +#include "memory/iterator.hpp" #include "oops/instanceKlass.hpp" #include "oops/oop.inline.hpp" #include "runtime/fieldDescriptor.inline.hpp" diff --git a/src/hotspot/share/memory/iterator.hpp b/src/hotspot/share/memory/iterator.hpp index 73f1b41ebc6..520acf30d0f 100644 --- a/src/hotspot/share/memory/iterator.hpp +++ b/src/hotspot/share/memory/iterator.hpp @@ -37,11 +37,18 @@ class KlassClosure; class ClassLoaderData; class Symbol; class Metadata; +class Thread; // The following classes are C++ `closures` for iterating over objects, roots and spaces class Closure : public StackObj { }; +// Thread iterator +class ThreadClosure: public Closure { + public: + virtual void do_thread(Thread* thread) = 0; +}; + // OopClosure is used for iterating through references to Java objects. class OopClosure : public Closure { public: diff --git a/src/hotspot/share/prims/jvmtiEnvBase.cpp b/src/hotspot/share/prims/jvmtiEnvBase.cpp index bc21bebed43..60746be5e2f 100644 --- a/src/hotspot/share/prims/jvmtiEnvBase.cpp +++ b/src/hotspot/share/prims/jvmtiEnvBase.cpp @@ -27,6 +27,7 @@ #include "classfile/moduleEntry.hpp" #include "classfile/systemDictionary.hpp" #include "jvmtifiles/jvmtiEnv.hpp" +#include "memory/iterator.hpp" #include "memory/resourceArea.hpp" #include "oops/objArrayKlass.hpp" #include "oops/objArrayOop.hpp" diff --git a/src/hotspot/share/prims/whitebox.cpp b/src/hotspot/share/prims/whitebox.cpp index ac7855c62ee..88fee05f46a 100644 --- a/src/hotspot/share/prims/whitebox.cpp +++ b/src/hotspot/share/prims/whitebox.cpp @@ -2011,7 +2011,7 @@ WB_END #endif // INCLUDE_CDS WB_ENTRY(jint, WB_HandshakeWalkStack(JNIEnv* env, jobject wb, jobject thread_handle, jboolean all_threads)) - class TraceSelfClosure : public ThreadClosure { + class TraceSelfClosure : public HandshakeClosure { jint _num_threads_completed; void do_thread(Thread* th) { @@ -2026,7 +2026,7 @@ WB_ENTRY(jint, WB_HandshakeWalkStack(JNIEnv* env, jobject wb, jobject thread_han } public: - TraceSelfClosure() : _num_threads_completed(0) {} + TraceSelfClosure() : HandshakeClosure("WB_TraceSelf"), _num_threads_completed(0) {} jint num_threads_completed() const { return _num_threads_completed; } }; diff --git a/src/hotspot/share/runtime/biasedLocking.cpp b/src/hotspot/share/runtime/biasedLocking.cpp index 15aff755e1e..5609fe63f46 100644 --- a/src/hotspot/share/runtime/biasedLocking.cpp +++ b/src/hotspot/share/runtime/biasedLocking.cpp @@ -35,6 +35,7 @@ #include "runtime/basicLock.hpp" #include "runtime/biasedLocking.hpp" #include "runtime/handles.inline.hpp" +#include "runtime/handshake.hpp" #include "runtime/task.hpp" #include "runtime/threadSMR.hpp" #include "runtime/vframe.hpp" @@ -500,7 +501,7 @@ public: }; -class RevokeOneBias : public ThreadClosure { +class RevokeOneBias : public HandshakeClosure { protected: Handle _obj; JavaThread* _requesting_thread; @@ -510,7 +511,8 @@ protected: public: RevokeOneBias(Handle obj, JavaThread* requesting_thread, JavaThread* biased_locker) - : _obj(obj) + : HandshakeClosure("RevokeOneBias") + , _obj(obj) , _requesting_thread(requesting_thread) , _biased_locker(biased_locker) , _status_code(BiasedLocking::NOT_BIASED) diff --git a/src/hotspot/share/runtime/deoptimization.cpp b/src/hotspot/share/runtime/deoptimization.cpp index bc25f8db400..ca7d3d7358f 100644 --- a/src/hotspot/share/runtime/deoptimization.cpp +++ b/src/hotspot/share/runtime/deoptimization.cpp @@ -805,10 +805,10 @@ JRT_LEAF(BasicType, Deoptimization::unpack_frames(JavaThread* thread, int exec_m return bt; JRT_END -class DeoptimizeMarkedTC : public ThreadClosure { +class DeoptimizeMarkedClosure : public HandshakeClosure { public: - virtual void do_thread(Thread* thread) { - assert(thread->is_Java_thread(), "must be"); + DeoptimizeMarkedClosure() : HandshakeClosure("Deoptimize") {} + void do_thread(Thread* thread) { JavaThread* jt = (JavaThread*)thread; jt->deoptimize_marked_methods(); } @@ -819,7 +819,7 @@ void Deoptimization::deoptimize_all_marked() { DeoptimizationMarker dm; if (SafepointSynchronize::is_at_safepoint()) { - DeoptimizeMarkedTC deopt; + DeoptimizeMarkedClosure deopt; // Make the dependent methods not entrant CodeCache::make_marked_nmethods_not_entrant(); Threads::java_threads_do(&deopt); @@ -829,7 +829,7 @@ void Deoptimization::deoptimize_all_marked() { MutexLocker mu(CodeCache_lock, Mutex::_no_safepoint_check_flag); CodeCache::make_marked_nmethods_not_entrant(); } - DeoptimizeMarkedTC deopt; + DeoptimizeMarkedClosure deopt; Handshake::execute(&deopt); } } diff --git a/src/hotspot/share/runtime/handshake.cpp b/src/hotspot/share/runtime/handshake.cpp index ce4bf697ddb..d2ec54669ff 100644 --- a/src/hotspot/share/runtime/handshake.cpp +++ b/src/hotspot/share/runtime/handshake.cpp @@ -45,10 +45,10 @@ public: class HandshakeThreadsOperation: public HandshakeOperation { static Semaphore _done; - ThreadClosure* _thread_cl; + HandshakeClosure* _handshake_cl; bool _executed; public: - HandshakeThreadsOperation(ThreadClosure* cl) : _thread_cl(cl), _executed(false) {} + HandshakeThreadsOperation(HandshakeClosure* cl) : _handshake_cl(cl), _executed(false) {} void do_handshake(JavaThread* thread); bool thread_has_completed() { return _done.trywait(); } bool executed() const { return _executed; } @@ -206,15 +206,15 @@ class VM_HandshakeAllThreads: public VM_Handshake { }; class VM_HandshakeFallbackOperation : public VM_Operation { - ThreadClosure* _thread_cl; + HandshakeClosure* _handshake_cl; Thread* _target_thread; bool _all_threads; bool _executed; public: - VM_HandshakeFallbackOperation(ThreadClosure* cl) : - _thread_cl(cl), _target_thread(NULL), _all_threads(true), _executed(false) {} - VM_HandshakeFallbackOperation(ThreadClosure* cl, Thread* target) : - _thread_cl(cl), _target_thread(target), _all_threads(false), _executed(false) {} + VM_HandshakeFallbackOperation(HandshakeClosure* cl) : + _handshake_cl(cl), _target_thread(NULL), _all_threads(true), _executed(false) {} + VM_HandshakeFallbackOperation(HandshakeClosure* cl, Thread* target) : + _handshake_cl(cl), _target_thread(target), _all_threads(false), _executed(false) {} void doit() { log_trace(handshake)("VMThread executing VM_HandshakeFallbackOperation"); @@ -223,7 +223,7 @@ public: if (t == _target_thread) { _executed = true; } - _thread_cl->do_thread(t); + _handshake_cl->do_thread(t); } } } @@ -240,7 +240,7 @@ void HandshakeThreadsOperation::do_handshake(JavaThread* thread) { // Only actually execute the operation for non terminated threads. if (!thread->is_terminated()) { - _thread_cl->do_thread(thread); + _handshake_cl->do_thread(thread); _executed = true; } @@ -248,7 +248,7 @@ void HandshakeThreadsOperation::do_handshake(JavaThread* thread) { _done.signal(); } -void Handshake::execute(ThreadClosure* thread_cl) { +void Handshake::execute(HandshakeClosure* thread_cl) { if (ThreadLocalHandshakes) { HandshakeThreadsOperation cto(thread_cl); VM_HandshakeAllThreads handshake(&cto); @@ -259,7 +259,7 @@ void Handshake::execute(ThreadClosure* thread_cl) { } } -bool Handshake::execute(ThreadClosure* thread_cl, JavaThread* target) { +bool Handshake::execute(HandshakeClosure* thread_cl, JavaThread* target) { if (ThreadLocalHandshakes) { HandshakeThreadsOperation cto(thread_cl); VM_HandshakeOneThread handshake(&cto, target); diff --git a/src/hotspot/share/runtime/handshake.hpp b/src/hotspot/share/runtime/handshake.hpp index 21600757f86..449164c8ee2 100644 --- a/src/hotspot/share/runtime/handshake.hpp +++ b/src/hotspot/share/runtime/handshake.hpp @@ -26,22 +26,32 @@ #define SHARE_RUNTIME_HANDSHAKE_HPP #include "memory/allocation.hpp" +#include "memory/iterator.hpp" #include "runtime/flags/flagSetting.hpp" #include "runtime/semaphore.hpp" -class ThreadClosure; class JavaThread; -// A handshake operation is a callback that is executed for each JavaThread +// A handshake closure is a callback that is executed for each JavaThread // while that thread is in a safepoint safe state. The callback is executed // either by the thread itself or by the VM thread while keeping the thread // in a blocked state. A handshake can be performed with a single // JavaThread as well. +class HandshakeClosure : public ThreadClosure { + const char* const _name; + public: + HandshakeClosure(const char* name) : _name(name) {} + const char* name() const { + return _name; + } + virtual void do_thread(Thread* thread) = 0; +}; + class Handshake : public AllStatic { public: // Execution of handshake operation - static void execute(ThreadClosure* thread_cl); - static bool execute(ThreadClosure* thread_cl, JavaThread* target); + static void execute(HandshakeClosure* hs_cl); + static bool execute(HandshakeClosure* hs_cl, JavaThread* target); }; class HandshakeOperation; diff --git a/src/hotspot/share/runtime/sweeper.cpp b/src/hotspot/share/runtime/sweeper.cpp index 9cae6bfe467..837c60db834 100644 --- a/src/hotspot/share/runtime/sweeper.cpp +++ b/src/hotspot/share/runtime/sweeper.cpp @@ -197,11 +197,11 @@ bool NMethodSweeper::wait_for_stack_scanning() { return _current.end(); } -class NMethodMarkingThreadClosure : public ThreadClosure { +class NMethodMarkingClosure : public HandshakeClosure { private: CodeBlobClosure* _cl; public: - NMethodMarkingThreadClosure(CodeBlobClosure* cl) : _cl(cl) {} + NMethodMarkingClosure(CodeBlobClosure* cl) : HandshakeClosure("NMethodMarking"), _cl(cl) {} void do_thread(Thread* thread) { if (thread->is_Java_thread() && ! thread->is_Code_cache_sweeper_thread()) { JavaThread* jt = (JavaThread*) thread; @@ -212,9 +212,9 @@ public: class NMethodMarkingTask : public AbstractGangTask { private: - NMethodMarkingThreadClosure* _cl; + NMethodMarkingClosure* _cl; public: - NMethodMarkingTask(NMethodMarkingThreadClosure* cl) : + NMethodMarkingTask(NMethodMarkingClosure* cl) : AbstractGangTask("Parallel NMethod Marking"), _cl(cl) { Threads::change_thread_claim_token(); @@ -239,7 +239,7 @@ void NMethodSweeper::mark_active_nmethods() { if (cl != NULL) { WorkGang* workers = Universe::heap()->get_safepoint_workers(); if (workers != NULL) { - NMethodMarkingThreadClosure tcl(cl); + NMethodMarkingClosure tcl(cl); NMethodMarkingTask task(&tcl); workers->run_task(&task); } else { @@ -324,8 +324,8 @@ void NMethodSweeper::do_stack_scanning() { code_cl = prepare_mark_active_nmethods(); } if (code_cl != NULL) { - NMethodMarkingThreadClosure tcl(code_cl); - Handshake::execute(&tcl); + NMethodMarkingClosure nm_cl(code_cl); + Handshake::execute(&nm_cl); } } else { VM_MarkActiveNMethods op; diff --git a/src/hotspot/share/runtime/thread.cpp b/src/hotspot/share/runtime/thread.cpp index 40eac88db21..e168dd80e4b 100644 --- a/src/hotspot/share/runtime/thread.cpp +++ b/src/hotspot/share/runtime/thread.cpp @@ -47,6 +47,7 @@ #include "logging/logConfiguration.hpp" #include "logging/logStream.hpp" #include "memory/allocation.inline.hpp" +#include "memory/iterator.hpp" #include "memory/metaspaceShared.hpp" #include "memory/oopFactory.hpp" #include "memory/resourceArea.hpp" diff --git a/src/hotspot/share/runtime/thread.hpp b/src/hotspot/share/runtime/thread.hpp index c74993e037c..4a002185b7b 100644 --- a/src/hotspot/share/runtime/thread.hpp +++ b/src/hotspot/share/runtime/thread.hpp @@ -2286,13 +2286,6 @@ class Threads: AllStatic { struct Test; // For private gtest access. }; - -// Thread iterator -class ThreadClosure: public StackObj { - public: - virtual void do_thread(Thread* thread) = 0; -}; - class SignalHandlerMark: public StackObj { private: Thread* _thread; diff --git a/src/hotspot/share/runtime/threadSMR.inline.hpp b/src/hotspot/share/runtime/threadSMR.inline.hpp index c65584b1be1..fb5f9105ca1 100644 --- a/src/hotspot/share/runtime/threadSMR.inline.hpp +++ b/src/hotspot/share/runtime/threadSMR.inline.hpp @@ -26,6 +26,7 @@ #define SHARE_RUNTIME_THREADSMR_INLINE_HPP #include "runtime/atomic.hpp" +#include "memory/iterator.hpp" #include "runtime/prefetch.inline.hpp" #include "runtime/thread.inline.hpp" #include "runtime/threadSMR.hpp" diff --git a/src/hotspot/share/runtime/vmThread.cpp b/src/hotspot/share/runtime/vmThread.cpp index 077450c480d..d8d2d3a7cb5 100644 --- a/src/hotspot/share/runtime/vmThread.cpp +++ b/src/hotspot/share/runtime/vmThread.cpp @@ -413,9 +413,10 @@ void VMThread::evaluate_operation(VM_Operation* op) { static VM_None safepointALot_op("SafepointALot"); static VM_Cleanup cleanup_op; -class HandshakeALotTC : public ThreadClosure { +class HandshakeALotClosure : public HandshakeClosure { public: - virtual void do_thread(Thread* thread) { + HandshakeALotClosure() : HandshakeClosure("HandshakeALot") {} + void do_thread(Thread* thread) { #ifdef ASSERT assert(thread->is_Java_thread(), "must be"); JavaThread* jt = (JavaThread*)thread; @@ -432,8 +433,8 @@ void VMThread::check_for_forced_cleanup() { VM_Operation* VMThread::no_op_safepoint() { // Check for handshakes first since we may need to return a VMop. if (HandshakeALot) { - HandshakeALotTC haltc; - Handshake::execute(&haltc); + HandshakeALotClosure hal_cl; + Handshake::execute(&hal_cl); } // Check for a cleanup before SafepointALot to keep stats correct. long interval_ms = SafepointTracing::time_since_last_safepoint_ms(); diff --git a/src/hotspot/share/utilities/globalCounter.cpp b/src/hotspot/share/utilities/globalCounter.cpp index 57cf3df4df8..26b5eb96218 100644 --- a/src/hotspot/share/utilities/globalCounter.cpp +++ b/src/hotspot/share/utilities/globalCounter.cpp @@ -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 @@ -23,11 +23,12 @@ */ #include "precompiled.hpp" -#include "utilities/globalCounter.hpp" +#include "memory/iterator.hpp" #include "runtime/atomic.hpp" #include "runtime/thread.hpp" #include "runtime/threadSMR.inline.hpp" #include "runtime/vmThread.hpp" +#include "utilities/globalCounter.hpp" #include "utilities/spinYield.hpp" GlobalCounter::PaddedCounter GlobalCounter::_global_counter; From 3cb74bd7ee97c01779f112a53f5a5913879b1b27 Mon Sep 17 00:00:00 2001 From: John Jiang Date: Wed, 4 Dec 2019 00:06:41 +0800 Subject: [PATCH 13/81] 8235255: ProblemList javax/net/ssl/templates/SSLSocketSSLEngineTemplate.java Reviewed-by: mullan --- test/jdk/ProblemList.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/test/jdk/ProblemList.txt b/test/jdk/ProblemList.txt index 98943dd32c4..4f6e48a7d6b 100644 --- a/test/jdk/ProblemList.txt +++ b/test/jdk/ProblemList.txt @@ -681,6 +681,7 @@ javax/net/ssl/ServerName/SSLEngineExplorerMatchedSNI.java 8212096 generic- javax/net/ssl/DTLS/PacketLossRetransmission.java 8169086 macosx-x64 javax/net/ssl/DTLS/RespondToRetransmit.java 8169086 macosx-x64 javax/net/ssl/DTLS/CipherSuite.java 8202059 macosx-x64 +javax/net/ssl/templates/SSLSocketSSLEngineTemplate.java 8231810 generic-all sun/security/provider/KeyStore/DKSTest.sh 8180266 windows-all From 03521f465cf8aff624dcf75062e4416b46a233ad Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Erik=20=C3=96sterlund?= Date: Tue, 3 Dec 2019 16:13:37 +0000 Subject: [PATCH 14/81] 8234426: Sweeper should not CompiledIC::set_to_clean with ICStubs for is_unloading() nmethods Reviewed-by: stefank, thartmann --- src/hotspot/share/code/compiledMethod.cpp | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/src/hotspot/share/code/compiledMethod.cpp b/src/hotspot/share/code/compiledMethod.cpp index e4bacf31e11..edb5c7f05f9 100644 --- a/src/hotspot/share/code/compiledMethod.cpp +++ b/src/hotspot/share/code/compiledMethod.cpp @@ -489,7 +489,20 @@ static bool clean_if_nmethod_is_unloaded(CompiledICorStaticCall *ic, address add if (nm != NULL) { // Clean inline caches pointing to both zombie and not_entrant methods if (clean_all || !nm->is_in_use() || nm->is_unloading() || (nm->method()->code() != nm)) { - if (!ic->set_to_clean(from->is_alive())) { + // Inline cache cleaning should only be initiated on CompiledMethods that have been + // observed to be is_alive(). However, with concurrent code cache unloading, it is + // possible that by now, the state has been racingly flipped to unloaded if the nmethod + // being cleaned is_unloading(). This is fine, because if that happens, then the inline + // caches have already been cleaned under the same CompiledICLocker that we now hold during + // inline cache cleaning, and we will simply walk the inline caches again, and likely not + // find much of interest to clean. However, this race prevents us from asserting that the + // nmethod is_alive(). The is_unloading() function is completely monotonic; once set due + // to an oop dying, it remains set forever until freed. Because of that, all unloaded + // nmethods are is_unloading(), but notably, an unloaded nmethod may also subsequently + // become zombie (when the sweeper converts it to zombie). Therefore, the most precise + // sanity check we can check for in this context is to not allow zombies. + assert(!from->is_zombie(), "should not clean inline caches on zombies"); + if (!ic->set_to_clean(!from->is_unloading())) { return false; } assert(ic->is_clean(), "nmethod " PTR_FORMAT "not clean %s", p2i(from), from->method()->name_and_sig_as_C_string()); From 22ea33cf7a8d964fedb93e479ad22dc49cb897bf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Erik=20=C3=96sterlund?= Date: Tue, 3 Dec 2019 16:13:37 +0000 Subject: [PATCH 15/81] 8234662: Sweeper should keep current nmethod alive before yielding for ICStub refills Reviewed-by: pliden, stefank --- src/hotspot/share/code/compiledMethod.cpp | 13 +++++++++++++ src/hotspot/share/gc/shared/barrierSetNMethod.hpp | 4 +--- 2 files changed, 14 insertions(+), 3 deletions(-) diff --git a/src/hotspot/share/code/compiledMethod.cpp b/src/hotspot/share/code/compiledMethod.cpp index edb5c7f05f9..042215d0931 100644 --- a/src/hotspot/share/code/compiledMethod.cpp +++ b/src/hotspot/share/code/compiledMethod.cpp @@ -30,6 +30,7 @@ #include "code/codeCache.hpp" #include "code/icBuffer.hpp" #include "gc/shared/barrierSet.hpp" +#include "gc/shared/barrierSetNMethod.hpp" #include "gc/shared/gcBehaviours.hpp" #include "interpreter/bytecode.inline.hpp" #include "logging/log.hpp" @@ -556,6 +557,18 @@ void CompiledMethod::cleanup_inline_caches(bool clean_all) { return; } } + BarrierSetNMethod* bs_nm = BarrierSet::barrier_set()->barrier_set_nmethod(); + if (bs_nm != NULL) { + // We want to keep an invariant that nmethods found through iterations of a Thread's + // nmethods found in safepoints have gone through an entry barrier and are not armed. + // By calling this nmethod entry barrier from the sweeper, it plays along and acts + // like any other nmethod found on the stack of a thread (fewer surprises). + nmethod* nm = as_nmethod_or_null(); + if (nm != NULL) { + bool alive = bs_nm->nmethod_entry_barrier(nm); + assert(alive, "should be alive"); + } + } InlineCacheBuffer::refill_ic_stubs(); } } diff --git a/src/hotspot/share/gc/shared/barrierSetNMethod.hpp b/src/hotspot/share/gc/shared/barrierSetNMethod.hpp index 0d081cbaade..0d68b8cdfe9 100644 --- a/src/hotspot/share/gc/shared/barrierSetNMethod.hpp +++ b/src/hotspot/share/gc/shared/barrierSetNMethod.hpp @@ -36,10 +36,8 @@ class BarrierSetNMethod: public CHeapObj { void deoptimize(nmethod* nm, address* return_addr_ptr); int disarmed_value() const; -protected: - virtual bool nmethod_entry_barrier(nmethod* nm) = 0; - public: + virtual bool nmethod_entry_barrier(nmethod* nm) = 0; virtual ByteSize thread_disarmed_offset() const = 0; virtual int* disarmed_value_address() const = 0; From c7bc0f7a12d1797baa2f5fe014febb32453a7a12 Mon Sep 17 00:00:00 2001 From: Vladimir Ivanov Date: Tue, 3 Dec 2019 20:13:16 +0300 Subject: [PATCH 16/81] 8231430: C2: Memory stomp in max_array_length() for T_ILLEGAL type Reviewed-by: kvn, thartmann --- src/hotspot/share/opto/type.cpp | 32 +++++++++++--------------------- src/hotspot/share/opto/type.hpp | 3 ++- 2 files changed, 13 insertions(+), 22 deletions(-) diff --git a/src/hotspot/share/opto/type.cpp b/src/hotspot/share/opto/type.cpp index 8f3d9cd20f4..50b9acaec27 100644 --- a/src/hotspot/share/opto/type.cpp +++ b/src/hotspot/share/opto/type.cpp @@ -4104,32 +4104,22 @@ const TypeOopPtr *TypeAryPtr::cast_to_nonconst() const { } -//-----------------------------narrow_size_type------------------------------- -// Local cache for arrayOopDesc::max_array_length(etype), -// which is kind of slow (and cached elsewhere by other users). -static jint max_array_length_cache[T_CONFLICT+1]; -static jint max_array_length(BasicType etype) { - jint& cache = max_array_length_cache[etype]; - jint res = cache; - if (res == 0) { - switch (etype) { - case T_NARROWOOP: +//-----------------------------max_array_length------------------------------- +// A wrapper around arrayOopDesc::max_array_length(etype) with some input normalization. +jint TypeAryPtr::max_array_length(BasicType etype) { + if (!is_java_primitive(etype) && !is_reference_type(etype)) { + if (etype == T_NARROWOOP) { etype = T_OBJECT; - break; - case T_NARROWKLASS: - case T_CONFLICT: - case T_ILLEGAL: - case T_VOID: - etype = T_BYTE; // will produce conservatively high value - break; - default: - break; + } else if (etype == T_ILLEGAL) { // bottom[] + etype = T_BYTE; // will produce conservatively high value + } else { + fatal("not an element type: %s", type2name(etype)); } - cache = res = arrayOopDesc::max_array_length(etype); } - return res; + return arrayOopDesc::max_array_length(etype); } +//-----------------------------narrow_size_type------------------------------- // Narrow the given size type to the index range for the given array base type. // Return NULL if the resulting int type becomes empty. const TypeInt* TypeAryPtr::narrow_size_type(const TypeInt* size) const { diff --git a/src/hotspot/share/opto/type.hpp b/src/hotspot/share/opto/type.hpp index 57ace034f14..4917254bfd0 100644 --- a/src/hotspot/share/opto/type.hpp +++ b/src/hotspot/share/opto/type.hpp @@ -455,7 +455,6 @@ public: private: // support arrays - static const BasicType _basic_type[]; static const Type* _zero_type[T_CONFLICT+1]; static const Type* _const_basic_type[T_CONFLICT+1]; }; @@ -1225,6 +1224,8 @@ public: const TypeAryPtr* cast_to_autobox_cache(bool cache) const; + static jint max_array_length(BasicType etype) ; + // Convenience common pre-built types. static const TypeAryPtr *RANGE; static const TypeAryPtr *OOPS; From a6daef527edfb9fbc0f2f4db14dd3054c63e085a Mon Sep 17 00:00:00 2001 From: Vladimir Ivanov Date: Tue, 3 Dec 2019 20:13:21 +0300 Subject: [PATCH 17/81] 8234923: Missed call_site_target nmethod dependency for non-fully initialized ConstantCallSite instance Reviewed-by: jrose --- src/hotspot/share/c1/c1_GraphBuilder.cpp | 2 +- src/hotspot/share/ci/ciCallSite.cpp | 14 +++++++++-- src/hotspot/share/ci/ciCallSite.hpp | 9 +++++--- src/hotspot/share/classfile/javaClasses.cpp | 18 +++++++++++++++ src/hotspot/share/classfile/javaClasses.hpp | 23 +++++++++++++++++++ .../share/classfile/javaClasses.inline.hpp | 8 +++++++ src/hotspot/share/opto/type.cpp | 2 +- .../java/lang/invoke/ConstantCallSite.java | 2 +- test/jdk/java/lang/invoke/CallSiteTest.java | 4 +++- 9 files changed, 73 insertions(+), 9 deletions(-) diff --git a/src/hotspot/share/c1/c1_GraphBuilder.cpp b/src/hotspot/share/c1/c1_GraphBuilder.cpp index 68ab481204b..2ddf577252b 100644 --- a/src/hotspot/share/c1/c1_GraphBuilder.cpp +++ b/src/hotspot/share/c1/c1_GraphBuilder.cpp @@ -1707,7 +1707,7 @@ void GraphBuilder::access_field(Bytecodes::Code code) { // For CallSite objects add a dependency for invalidation of the optimization. if (field->is_call_site_target()) { ciCallSite* call_site = const_oop->as_call_site(); - if (!call_site->is_constant_call_site()) { + if (!call_site->is_fully_initialized_constant_call_site()) { ciMethodHandle* target = field_value.as_object()->as_method_handle(); dependency_recorder()->assert_call_site_target_value(call_site, target); } diff --git a/src/hotspot/share/ci/ciCallSite.cpp b/src/hotspot/share/ci/ciCallSite.cpp index f3d2ca1071d..8be8c4abeab 100644 --- a/src/hotspot/share/ci/ciCallSite.cpp +++ b/src/hotspot/share/ci/ciCallSite.cpp @@ -29,8 +29,18 @@ // ciCallSite -bool ciCallSite::is_constant_call_site() { - return klass()->is_subclass_of(CURRENT_ENV->ConstantCallSite_klass()); +bool ciCallSite::is_fully_initialized_constant_call_site() { + if (klass()->is_subclass_of(CURRENT_ENV->ConstantCallSite_klass())) { + bool is_fully_initialized = _is_fully_initialized_cache; + if (!is_fully_initialized) { // changes monotonically: false => true + VM_ENTRY_MARK; + is_fully_initialized = (java_lang_invoke_ConstantCallSite::is_frozen(get_oop()) != JNI_FALSE); + _is_fully_initialized_cache = is_fully_initialized; // cache updated value + } + return is_fully_initialized; + } else { + return false; + } } // ------------------------------------------------------------------ diff --git a/src/hotspot/share/ci/ciCallSite.hpp b/src/hotspot/share/ci/ciCallSite.hpp index b7f6a27584e..2204636d02f 100644 --- a/src/hotspot/share/ci/ciCallSite.hpp +++ b/src/hotspot/share/ci/ciCallSite.hpp @@ -31,13 +31,16 @@ // // The class represents a java.lang.invoke.CallSite object. class ciCallSite : public ciInstance { -public: - ciCallSite(instanceHandle h_i) : ciInstance(h_i) {} + private: + bool _is_fully_initialized_cache; + + public: + ciCallSite(instanceHandle h_i) : ciInstance(h_i), _is_fully_initialized_cache(false) {} // What kind of ciObject is this? bool is_call_site() const { return true; } - bool is_constant_call_site(); + bool is_fully_initialized_constant_call_site(); // Return the target MethodHandle of this CallSite. ciMethodHandle* get_target() const; diff --git a/src/hotspot/share/classfile/javaClasses.cpp b/src/hotspot/share/classfile/javaClasses.cpp index c0e3a573b72..77a931a0021 100644 --- a/src/hotspot/share/classfile/javaClasses.cpp +++ b/src/hotspot/share/classfile/javaClasses.cpp @@ -3918,6 +3918,24 @@ oop java_lang_invoke_CallSite::context_no_keepalive(oop call_site) { return dep_oop; } +// Support for java_lang_invoke_ConstantCallSite + +int java_lang_invoke_ConstantCallSite::_is_frozen_offset; + +#define CONSTANTCALLSITE_FIELDS_DO(macro) \ + macro(_is_frozen_offset, k, "isFrozen", bool_signature, false) + +void java_lang_invoke_ConstantCallSite::compute_offsets() { + InstanceKlass* k = SystemDictionary::ConstantCallSite_klass(); + CONSTANTCALLSITE_FIELDS_DO(FIELD_COMPUTE_OFFSET); +} + +#if INCLUDE_CDS +void java_lang_invoke_ConstantCallSite::serialize_offsets(SerializeClosure* f) { + CONSTANTCALLSITE_FIELDS_DO(FIELD_SERIALIZE_OFFSET); +} +#endif + // Support for java_lang_invoke_MethodHandleNatives_CallSiteContext int java_lang_invoke_MethodHandleNatives_CallSiteContext::_vmdependencies_offset; diff --git a/src/hotspot/share/classfile/javaClasses.hpp b/src/hotspot/share/classfile/javaClasses.hpp index 185e3fdb2ac..b1fea1f293a 100644 --- a/src/hotspot/share/classfile/javaClasses.hpp +++ b/src/hotspot/share/classfile/javaClasses.hpp @@ -66,6 +66,7 @@ f(java_lang_invoke_LambdaForm) \ f(java_lang_invoke_MethodType) \ f(java_lang_invoke_CallSite) \ + f(java_lang_invoke_ConstantCallSite) \ f(java_lang_invoke_MethodHandleNatives_CallSiteContext) \ f(java_security_AccessControlContext) \ f(java_lang_reflect_AccessibleObject) \ @@ -1226,6 +1227,28 @@ public: static int target_offset_in_bytes() { return _target_offset; } }; +// Interface to java.lang.invoke.ConstantCallSite objects + +class java_lang_invoke_ConstantCallSite: AllStatic { + friend class JavaClasses; + +private: + static int _is_frozen_offset; + + static void compute_offsets(); + +public: + static void serialize_offsets(SerializeClosure* f) NOT_CDS_RETURN; + // Accessors + static jboolean is_frozen(oop site); + + // Testers + static bool is_subclass(Klass* klass) { + return klass->is_subclass_of(SystemDictionary::ConstantCallSite_klass()); + } + static bool is_instance(oop obj); +}; + // Interface to java.lang.invoke.MethodHandleNatives$CallSiteContext objects #define CALLSITECONTEXT_INJECTED_FIELDS(macro) \ diff --git a/src/hotspot/share/classfile/javaClasses.inline.hpp b/src/hotspot/share/classfile/javaClasses.inline.hpp index 18176fcfb44..a003943bde4 100644 --- a/src/hotspot/share/classfile/javaClasses.inline.hpp +++ b/src/hotspot/share/classfile/javaClasses.inline.hpp @@ -179,6 +179,14 @@ inline bool java_lang_invoke_CallSite::is_instance(oop obj) { return obj != NULL && is_subclass(obj->klass()); } +inline jboolean java_lang_invoke_ConstantCallSite::is_frozen(oop site) { + return site->bool_field(_is_frozen_offset); +} + +inline bool java_lang_invoke_ConstantCallSite::is_instance(oop obj) { + return obj != NULL && is_subclass(obj->klass()); +} + inline bool java_lang_invoke_MethodHandleNatives_CallSiteContext::is_instance(oop obj) { return obj != NULL && is_subclass(obj->klass()); } diff --git a/src/hotspot/share/opto/type.cpp b/src/hotspot/share/opto/type.cpp index 50b9acaec27..6098be845f2 100644 --- a/src/hotspot/share/opto/type.cpp +++ b/src/hotspot/share/opto/type.cpp @@ -375,7 +375,7 @@ const Type* Type::make_constant_from_field(ciField* field, ciInstance* holder, field->is_autobox_cache()); if (con_type != NULL && field->is_call_site_target()) { ciCallSite* call_site = holder->as_call_site(); - if (!call_site->is_constant_call_site()) { + if (!call_site->is_fully_initialized_constant_call_site()) { ciMethodHandle* target = con.as_object()->as_method_handle(); Compile::current()->dependencies()->assert_call_site_target_value(call_site, target); } diff --git a/src/java.base/share/classes/java/lang/invoke/ConstantCallSite.java b/src/java.base/share/classes/java/lang/invoke/ConstantCallSite.java index c8a027844c5..e2e3f478a3c 100644 --- a/src/java.base/share/classes/java/lang/invoke/ConstantCallSite.java +++ b/src/java.base/share/classes/java/lang/invoke/ConstantCallSite.java @@ -39,7 +39,7 @@ public class ConstantCallSite extends CallSite { private static final Unsafe UNSAFE = Unsafe.getUnsafe(); @Stable // should NOT be constant folded during instance initialization (isFrozen == false) - /*final*/ private boolean isFrozen; + /*final*/ private boolean isFrozen; // Note: This field is known to the JVM. /** * Creates a call site with a permanent target. diff --git a/test/jdk/java/lang/invoke/CallSiteTest.java b/test/jdk/java/lang/invoke/CallSiteTest.java index 408c49739d0..7caf8ac85cc 100644 --- a/test/jdk/java/lang/invoke/CallSiteTest.java +++ b/test/jdk/java/lang/invoke/CallSiteTest.java @@ -128,7 +128,9 @@ public class CallSiteTest { if (ccs != holder[0]) { throw new AssertionError("different call site instances"); } - test(false); // should not throw + for (int i = 0; i < 20_000; i++) { + test(false); // should not throw + } } private static void testMutableCallSite() throws Throwable { From 7204086e7e40ba674b6b26de76b492e344ed8081 Mon Sep 17 00:00:00 2001 From: Serguei Spitsyn Date: Tue, 3 Dec 2019 19:45:38 +0000 Subject: [PATCH 18/81] 8235280: UnProblemList vmTestbase/nsk/jvmti/GetThreadState/thrstat001/TestDescription.java Remove test from ProblemList.txt. Reviewed-by: iignatyev --- test/hotspot/jtreg/ProblemList.txt | 1 - 1 file changed, 1 deletion(-) diff --git a/test/hotspot/jtreg/ProblemList.txt b/test/hotspot/jtreg/ProblemList.txt index 3c125b7eb3b..e2a93b79304 100644 --- a/test/hotspot/jtreg/ProblemList.txt +++ b/test/hotspot/jtreg/ProblemList.txt @@ -182,7 +182,6 @@ vmTestbase/nsk/jvmti/AttachOnDemand/attach045/TestDescription.java 8202971 gener vmTestbase/nsk/jvmti/scenarios/jni_interception/JI05/ji05t001/TestDescription.java 8219652 aix-ppc64 vmTestbase/nsk/jvmti/scenarios/jni_interception/JI06/ji06t001/TestDescription.java 8219652 aix-ppc64 vmTestbase/nsk/jvmti/SetJNIFunctionTable/setjniftab001/TestDescription.java 8219652 aix-ppc64 -vmTestbase/nsk/jvmti/GetThreadState/thrstat001/TestDescription.java 8221372 windows-x64 vmTestbase/gc/lock/jni/jnilock002/TestDescription.java 8208243,8192647 generic-all From e70386f23ad05493cd554e4ca75e9b22ce6a0996 Mon Sep 17 00:00:00 2001 From: Kim Barrett Date: Tue, 3 Dec 2019 15:12:56 -0500 Subject: [PATCH 19/81] 8213415: BitMap::word_index_round_up overflow problems Limit BitMap sizes so to-word round-up can't overflow. Reviewed-by: tschatzl, stuefe --- .../share/gc/parallel/parMarkBitMap.cpp | 12 +-- .../share/gc/parallel/parMarkBitMap.hpp | 4 + .../gc/parallel/parMarkBitMap.inline.hpp | 13 ++- .../share/gc/parallel/psParallelCompact.cpp | 4 +- src/hotspot/share/utilities/bitMap.cpp | 83 +++++++++------- src/hotspot/share/utilities/bitMap.hpp | 96 ++++++++++++------- src/hotspot/share/utilities/bitMap.inline.hpp | 21 ++-- .../gtest/utilities/test_bitMap_setops.cpp | 17 ++-- 8 files changed, 149 insertions(+), 101 deletions(-) diff --git a/src/hotspot/share/gc/parallel/parMarkBitMap.cpp b/src/hotspot/share/gc/parallel/parMarkBitMap.cpp index 8b4a5d8d8cc..a6e3acbe20a 100644 --- a/src/hotspot/share/gc/parallel/parMarkBitMap.cpp +++ b/src/hotspot/share/gc/parallel/parMarkBitMap.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 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,7 @@ ParMarkBitMap::initialize(MemRegion covered_region) const idx_t bits = bits_required(covered_region); // The bits will be divided evenly between two bitmaps; each of them should be // an integral number of words. - assert(bits % (BitsPerWord * 2) == 0, "region size unaligned"); + assert(is_aligned(bits, (BitsPerWord * 2)), "region size unaligned"); const size_t words = bits / BitsPerWord; const size_t raw_bytes = words * sizeof(idx_t); @@ -118,7 +118,7 @@ ParMarkBitMap::live_words_in_range_helper(HeapWord* beg_addr, oop end_obj) const // The bitmap routines require the right boundary to be word-aligned. const idx_t end_bit = addr_to_bit((HeapWord*)end_obj); - const idx_t range_end = BitMap::word_align_up(end_bit); + const idx_t range_end = align_range_end(end_bit); idx_t beg_bit = find_obj_beg(addr_to_bit(beg_addr), range_end); while (beg_bit < end_bit) { @@ -177,7 +177,7 @@ ParMarkBitMap::iterate(ParMarkBitMapClosure* live_closure, assert(range_beg <= range_end, "live range invalid"); // The bitmap routines require the right boundary to be word-aligned. - const idx_t search_end = BitMap::word_align_up(range_end); + const idx_t search_end = align_range_end(range_end); idx_t cur_beg = find_obj_beg(range_beg, search_end); while (cur_beg < range_end) { @@ -216,8 +216,8 @@ ParMarkBitMap::iterate(ParMarkBitMapClosure* live_closure, assert(range_end <= dead_range_end, "dead range invalid"); // The bitmap routines require the right boundary to be word-aligned. - const idx_t live_search_end = BitMap::word_align_up(range_end); - const idx_t dead_search_end = BitMap::word_align_up(dead_range_end); + const idx_t live_search_end = align_range_end(range_end); + const idx_t dead_search_end = align_range_end(dead_range_end); idx_t cur_beg = range_beg; if (range_beg < range_end && is_unmarked(range_beg)) { diff --git a/src/hotspot/share/gc/parallel/parMarkBitMap.hpp b/src/hotspot/share/gc/parallel/parMarkBitMap.hpp index 17e8be8dc50..ed08fed4eb7 100644 --- a/src/hotspot/share/gc/parallel/parMarkBitMap.hpp +++ b/src/hotspot/share/gc/parallel/parMarkBitMap.hpp @@ -138,8 +138,12 @@ public: inline idx_t addr_to_bit(HeapWord* addr) const; inline HeapWord* bit_to_addr(idx_t bit) const; + // Return word-aligned up range_end, which must not be greater than size(). + inline idx_t align_range_end(idx_t range_end) const; + // Return the bit index of the first marked object that begins (or ends, // respectively) in the range [beg, end). If no object is found, return end. + // end must be word-aligned. inline idx_t find_obj_beg(idx_t beg, idx_t end) const; inline idx_t find_obj_end(idx_t beg, idx_t end) const; diff --git a/src/hotspot/share/gc/parallel/parMarkBitMap.inline.hpp b/src/hotspot/share/gc/parallel/parMarkBitMap.inline.hpp index cf9bbe82f52..055148e42a6 100644 --- a/src/hotspot/share/gc/parallel/parMarkBitMap.inline.hpp +++ b/src/hotspot/share/gc/parallel/parMarkBitMap.inline.hpp @@ -26,6 +26,7 @@ #define SHARE_GC_PARALLEL_PARMARKBITMAP_INLINE_HPP #include "gc/parallel/parMarkBitMap.hpp" +#include "utilities/align.hpp" #include "utilities/bitMap.inline.hpp" inline ParMarkBitMap::ParMarkBitMap(): @@ -146,7 +147,7 @@ inline bool ParMarkBitMap::mark_obj(oop obj, int size) { return mark_obj((HeapWord*)obj, (size_t)size); } -inline BitMap::idx_t ParMarkBitMap::addr_to_bit(HeapWord* addr) const { +inline ParMarkBitMap::idx_t ParMarkBitMap::addr_to_bit(HeapWord* addr) const { DEBUG_ONLY(verify_addr(addr);) return words_to_bits(pointer_delta(addr, region_start())); } @@ -156,6 +157,12 @@ inline HeapWord* ParMarkBitMap::bit_to_addr(idx_t bit) const { return region_start() + bits_to_words(bit); } +inline ParMarkBitMap::idx_t ParMarkBitMap::align_range_end(idx_t range_end) const { + // size is aligned, so if range_end <= size then so is aligned result. + assert(range_end <= size(), "range end out of range"); + return align_up(range_end, BitsPerWord); +} + inline ParMarkBitMap::idx_t ParMarkBitMap::find_obj_beg(idx_t beg, idx_t end) const { return _beg_bits.get_next_one_offset_aligned_right(beg, end); } @@ -167,7 +174,7 @@ inline ParMarkBitMap::idx_t ParMarkBitMap::find_obj_end(idx_t beg, idx_t end) co inline HeapWord* ParMarkBitMap::find_obj_beg(HeapWord* beg, HeapWord* end) const { const idx_t beg_bit = addr_to_bit(beg); const idx_t end_bit = addr_to_bit(end); - const idx_t search_end = BitMap::word_align_up(end_bit); + const idx_t search_end = align_range_end(end_bit); const idx_t res_bit = MIN2(find_obj_beg(beg_bit, search_end), end_bit); return bit_to_addr(res_bit); } @@ -175,7 +182,7 @@ inline HeapWord* ParMarkBitMap::find_obj_beg(HeapWord* beg, HeapWord* end) const inline HeapWord* ParMarkBitMap::find_obj_end(HeapWord* beg, HeapWord* end) const { const idx_t beg_bit = addr_to_bit(beg); const idx_t end_bit = addr_to_bit(end); - const idx_t search_end = BitMap::word_align_up(end_bit); + const idx_t search_end = align_range_end(end_bit); const idx_t res_bit = MIN2(find_obj_end(beg_bit, search_end), end_bit); return bit_to_addr(res_bit); } diff --git a/src/hotspot/share/gc/parallel/psParallelCompact.cpp b/src/hotspot/share/gc/parallel/psParallelCompact.cpp index f68ba635ce9..b979321ec8b 100644 --- a/src/hotspot/share/gc/parallel/psParallelCompact.cpp +++ b/src/hotspot/share/gc/parallel/psParallelCompact.cpp @@ -961,7 +961,7 @@ PSParallelCompact::clear_data_covering_space(SpaceId id) HeapWord* const max_top = MAX2(top, _space_info[id].new_top()); const idx_t beg_bit = _mark_bitmap.addr_to_bit(bot); - const idx_t end_bit = BitMap::word_align_up(_mark_bitmap.addr_to_bit(top)); + const idx_t end_bit = _mark_bitmap.align_range_end(_mark_bitmap.addr_to_bit(top)); _mark_bitmap.clear_range(beg_bit, end_bit); const size_t beg_region = _summary_data.addr_to_region_idx(bot); @@ -2849,7 +2849,7 @@ PSParallelCompact::skip_live_words(HeapWord* beg, HeapWord* end, size_t count) ParMarkBitMap* m = mark_bitmap(); idx_t bits_to_skip = m->words_to_bits(count); idx_t cur_beg = m->addr_to_bit(beg); - const idx_t search_end = BitMap::word_align_up(m->addr_to_bit(end)); + const idx_t search_end = m->align_range_end(m->addr_to_bit(end)); do { cur_beg = m->find_obj_beg(cur_beg, search_end); diff --git a/src/hotspot/share/utilities/bitMap.cpp b/src/hotspot/share/utilities/bitMap.cpp index 78478f32c6e..83bbd20958a 100644 --- a/src/hotspot/share/utilities/bitMap.cpp +++ b/src/hotspot/share/utilities/bitMap.cpp @@ -174,14 +174,27 @@ void CHeapBitMap::reinitialize(idx_t size_in_bits, bool clear) { } #ifdef ASSERT -void BitMap::verify_index(idx_t index) const { - assert(index < _size, "BitMap index out of bounds"); +void BitMap::verify_size(idx_t size_in_bits) { + assert(size_in_bits <= max_size_in_bits(), + "out of bounds: " SIZE_FORMAT, size_in_bits); } -void BitMap::verify_range(idx_t beg_index, idx_t end_index) const { - assert(beg_index <= end_index, "BitMap range error"); - // Note that [0,0) and [size,size) are both valid ranges. - if (end_index != _size) verify_index(end_index); +void BitMap::verify_index(idx_t bit) const { + assert(bit < _size, + "BitMap index out of bounds: " SIZE_FORMAT " >= " SIZE_FORMAT, + bit, _size); +} + +void BitMap::verify_limit(idx_t bit) const { + assert(bit <= _size, + "BitMap limit out of bounds: " SIZE_FORMAT " > " SIZE_FORMAT, + bit, _size); +} + +void BitMap::verify_range(idx_t beg, idx_t end) const { + assert(beg <= end, + "BitMap range error: " SIZE_FORMAT " > " SIZE_FORMAT, beg, end); + verify_limit(end); } #endif // #ifdef ASSERT @@ -228,8 +241,8 @@ void BitMap::par_put_range_within_word(idx_t beg, idx_t end, bool value) { void BitMap::set_range(idx_t beg, idx_t end) { verify_range(beg, end); - idx_t beg_full_word = word_index_round_up(beg); - idx_t end_full_word = word_index(end); + idx_t beg_full_word = to_words_align_up(beg); + idx_t end_full_word = to_words_align_down(end); if (beg_full_word < end_full_word) { // The range includes at least one full word. @@ -247,8 +260,8 @@ void BitMap::set_range(idx_t beg, idx_t end) { void BitMap::clear_range(idx_t beg, idx_t end) { verify_range(beg, end); - idx_t beg_full_word = word_index_round_up(beg); - idx_t end_full_word = word_index(end); + idx_t beg_full_word = to_words_align_up(beg); + idx_t end_full_word = to_words_align_down(end); if (beg_full_word < end_full_word) { // The range includes at least one full word. @@ -265,17 +278,19 @@ void BitMap::clear_range(idx_t beg, idx_t end) { bool BitMap::is_small_range_of_words(idx_t beg_full_word, idx_t end_full_word) { // There is little point to call large version on small ranges. - // Need to check carefully, keeping potential idx_t underflow in mind. + // Need to check carefully, keeping potential idx_t over/underflow in mind, + // because beg_full_word > end_full_word can occur when beg and end are in + // the same word. // The threshold should be at least one word. STATIC_ASSERT(small_range_words >= 1); - return (beg_full_word + small_range_words >= end_full_word); + return beg_full_word + small_range_words >= end_full_word; } void BitMap::set_large_range(idx_t beg, idx_t end) { verify_range(beg, end); - idx_t beg_full_word = word_index_round_up(beg); - idx_t end_full_word = word_index(end); + idx_t beg_full_word = to_words_align_up(beg); + idx_t end_full_word = to_words_align_down(end); if (is_small_range_of_words(beg_full_word, end_full_word)) { set_range(beg, end); @@ -291,8 +306,8 @@ void BitMap::set_large_range(idx_t beg, idx_t end) { void BitMap::clear_large_range(idx_t beg, idx_t end) { verify_range(beg, end); - idx_t beg_full_word = word_index_round_up(beg); - idx_t end_full_word = word_index(end); + idx_t beg_full_word = to_words_align_up(beg); + idx_t end_full_word = to_words_align_down(end); if (is_small_range_of_words(beg_full_word, end_full_word)) { clear_range(beg, end); @@ -343,8 +358,8 @@ void BitMap::at_put_range(idx_t start_offset, idx_t end_offset, bool value) { void BitMap::par_at_put_range(idx_t beg, idx_t end, bool value) { verify_range(beg, end); - idx_t beg_full_word = word_index_round_up(beg); - idx_t end_full_word = word_index(end); + idx_t beg_full_word = to_words_align_up(beg); + idx_t end_full_word = to_words_align_down(end); if (beg_full_word < end_full_word) { // The range includes at least one full word. @@ -375,8 +390,8 @@ void BitMap::at_put_large_range(idx_t beg, idx_t end, bool value) { void BitMap::par_at_put_large_range(idx_t beg, idx_t end, bool value) { verify_range(beg, end); - idx_t beg_full_word = word_index_round_up(beg); - idx_t end_full_word = word_index(end); + idx_t beg_full_word = to_words_align_up(beg); + idx_t end_full_word = to_words_align_down(end); if (is_small_range_of_words(beg_full_word, end_full_word)) { par_at_put_range(beg, end, value); @@ -420,7 +435,7 @@ bool BitMap::contains(const BitMap& other) const { assert(size() == other.size(), "must have same size"); const bm_word_t* dest_map = map(); const bm_word_t* other_map = other.map(); - idx_t limit = word_index(size()); + idx_t limit = to_words_align_down(size()); for (idx_t index = 0; index < limit; ++index) { // false if other bitmap has bits set which are clear in this bitmap. if ((~dest_map[index] & other_map[index]) != 0) return false; @@ -435,7 +450,7 @@ bool BitMap::intersects(const BitMap& other) const { assert(size() == other.size(), "must have same size"); const bm_word_t* dest_map = map(); const bm_word_t* other_map = other.map(); - idx_t limit = word_index(size()); + idx_t limit = to_words_align_down(size()); for (idx_t index = 0; index < limit; ++index) { if ((dest_map[index] & other_map[index]) != 0) return true; } @@ -448,7 +463,7 @@ void BitMap::set_union(const BitMap& other) { assert(size() == other.size(), "must have same size"); bm_word_t* dest_map = map(); const bm_word_t* other_map = other.map(); - idx_t limit = word_index(size()); + idx_t limit = to_words_align_down(size()); for (idx_t index = 0; index < limit; ++index) { dest_map[index] |= other_map[index]; } @@ -463,7 +478,7 @@ void BitMap::set_difference(const BitMap& other) { assert(size() == other.size(), "must have same size"); bm_word_t* dest_map = map(); const bm_word_t* other_map = other.map(); - idx_t limit = word_index(size()); + idx_t limit = to_words_align_down(size()); for (idx_t index = 0; index < limit; ++index) { dest_map[index] &= ~other_map[index]; } @@ -478,7 +493,7 @@ void BitMap::set_intersection(const BitMap& other) { assert(size() == other.size(), "must have same size"); bm_word_t* dest_map = map(); const bm_word_t* other_map = other.map(); - idx_t limit = word_index(size()); + idx_t limit = to_words_align_down(size()); for (idx_t index = 0; index < limit; ++index) { dest_map[index] &= other_map[index]; } @@ -494,7 +509,7 @@ bool BitMap::set_union_with_result(const BitMap& other) { bool changed = false; bm_word_t* dest_map = map(); const bm_word_t* other_map = other.map(); - idx_t limit = word_index(size()); + idx_t limit = to_words_align_down(size()); for (idx_t index = 0; index < limit; ++index) { bm_word_t orig = dest_map[index]; bm_word_t temp = orig | other_map[index]; @@ -516,7 +531,7 @@ bool BitMap::set_difference_with_result(const BitMap& other) { bool changed = false; bm_word_t* dest_map = map(); const bm_word_t* other_map = other.map(); - idx_t limit = word_index(size()); + idx_t limit = to_words_align_down(size()); for (idx_t index = 0; index < limit; ++index) { bm_word_t orig = dest_map[index]; bm_word_t temp = orig & ~other_map[index]; @@ -538,7 +553,7 @@ bool BitMap::set_intersection_with_result(const BitMap& other) { bool changed = false; bm_word_t* dest_map = map(); const bm_word_t* other_map = other.map(); - idx_t limit = word_index(size()); + idx_t limit = to_words_align_down(size()); for (idx_t index = 0; index < limit; ++index) { bm_word_t orig = dest_map[index]; bm_word_t temp = orig & other_map[index]; @@ -559,7 +574,7 @@ void BitMap::set_from(const BitMap& other) { assert(size() == other.size(), "must have same size"); bm_word_t* dest_map = map(); const bm_word_t* other_map = other.map(); - idx_t copy_words = word_index(size()); + idx_t copy_words = to_words_align_down(size()); Copy::disjoint_words((HeapWord*)other_map, (HeapWord*)dest_map, copy_words); idx_t rest = bit_in_word(size()); if (rest > 0) { @@ -573,7 +588,7 @@ bool BitMap::is_same(const BitMap& other) const { assert(size() == other.size(), "must have same size"); const bm_word_t* dest_map = map(); const bm_word_t* other_map = other.map(); - idx_t limit = word_index(size()); + idx_t limit = to_words_align_down(size()); for (idx_t index = 0; index < limit; ++index) { if (dest_map[index] != other_map[index]) return false; } @@ -583,7 +598,7 @@ bool BitMap::is_same(const BitMap& other) const { bool BitMap::is_full() const { const bm_word_t* words = map(); - idx_t limit = word_index(size()); + idx_t limit = to_words_align_down(size()); for (idx_t index = 0; index < limit; ++index) { if (~words[index] != 0) return false; } @@ -593,7 +608,7 @@ bool BitMap::is_full() const { bool BitMap::is_empty() const { const bm_word_t* words = map(); - idx_t limit = word_index(size()); + idx_t limit = to_words_align_down(size()); for (idx_t index = 0; index < limit; ++index) { if (words[index] != 0) return false; } @@ -612,8 +627,8 @@ void BitMap::clear_large() { bool BitMap::iterate(BitMapClosure* blk, idx_t leftOffset, idx_t rightOffset) { verify_range(leftOffset, rightOffset); - idx_t startIndex = word_index(leftOffset); - idx_t endIndex = MIN2(word_index(rightOffset) + 1, size_in_words()); + idx_t startIndex = to_words_align_down(leftOffset); + idx_t endIndex = to_words_align_up(rightOffset); for (idx_t index = startIndex, offset = leftOffset; offset < rightOffset && index < endIndex; offset = (++index) << LogBitsPerWord) { diff --git a/src/hotspot/share/utilities/bitMap.hpp b/src/hotspot/share/utilities/bitMap.hpp index 664f672c6b9..148dab5d9df 100644 --- a/src/hotspot/share/utilities/bitMap.hpp +++ b/src/hotspot/share/utilities/bitMap.hpp @@ -27,13 +27,12 @@ #include "memory/allocation.hpp" #include "runtime/atomic.hpp" -#include "utilities/align.hpp" // Forward decl; class BitMapClosure; // Operations for bitmaps represented as arrays of unsigned integers. -// Bit offsets are numbered from 0 to size-1. +// Bits are numbered from 0 to size-1. // The "abstract" base BitMap class. // @@ -50,8 +49,10 @@ class BitMap { public: typedef size_t idx_t; // Type used for bit and word indices. - typedef uintptr_t bm_word_t; // Element type of array that represents - // the bitmap. + typedef uintptr_t bm_word_t; // Element type of array that represents the + // bitmap, with BitsPerWord bits per element. + // If this were to fail, there are lots of places that would need repair. + STATIC_ASSERT((sizeof(bm_word_t) * BitsPerByte) == BitsPerWord); // Hints for range sizes. typedef enum { @@ -62,6 +63,35 @@ class BitMap { bm_word_t* _map; // First word in bitmap idx_t _size; // Size of bitmap (in bits) + // The maximum allowable size of a bitmap, in words or bits. + // Limit max_size_in_bits so aligning up to a word boundary never overflows. + static idx_t max_size_in_words() { return raw_to_words_align_down(~idx_t(0)); } + static idx_t max_size_in_bits() { return max_size_in_words() * BitsPerWord; } + + // Assumes relevant validity checking for bit has already been done. + static idx_t raw_to_words_align_up(idx_t bit) { + return raw_to_words_align_down(bit + (BitsPerWord - 1)); + } + + // Assumes relevant validity checking for bit has already been done. + static idx_t raw_to_words_align_down(idx_t bit) { + return bit >> LogBitsPerWord; + } + + // Word-aligns bit and converts it to a word offset. + // precondition: bit <= size() + idx_t to_words_align_up(idx_t bit) const { + verify_limit(bit); + return raw_to_words_align_up(bit); + } + + // Word-aligns bit and converts it to a word offset. + // precondition: bit <= size() + inline idx_t to_words_align_down(idx_t bit) const { + verify_limit(bit); + return raw_to_words_align_down(bit); + } + // Helper for get_next_{zero,one}_bit variants. // - flip designates whether searching for 1s or 0s. Must be one of // find_{zeros,ones}_flip. @@ -77,6 +107,8 @@ class BitMap { // operation was requested. Measured in words. static const size_t small_range_words = 32; + static bool is_small_range_of_words(idx_t beg_full_word, idx_t end_full_word); + protected: // Return the position of bit within the word that contains it (e.g., if // bitmap words are 32 bits, return a number 0 <= n <= 31). @@ -86,9 +118,6 @@ class BitMap { // containing the bit. static bm_word_t bit_mask(idx_t bit) { return (bm_word_t)1 << bit_in_word(bit); } - // Return the index of the word containing the specified bit. - static idx_t word_index(idx_t bit) { return bit >> LogBitsPerWord; } - // Return the bit number of the first bit in the specified word. static idx_t bit_index(idx_t word) { return word << LogBitsPerWord; } @@ -98,8 +127,12 @@ class BitMap { bm_word_t map(idx_t word) const { return _map[word]; } // Return a pointer to the word containing the specified bit. - bm_word_t* word_addr(idx_t bit) { return map() + word_index(bit); } - const bm_word_t* word_addr(idx_t bit) const { return map() + word_index(bit); } + bm_word_t* word_addr(idx_t bit) { + return map() + to_words_align_down(bit); + } + const bm_word_t* word_addr(idx_t bit) const { + return map() + to_words_align_down(bit); + } // Set a word to a specified value or to all ones; clear a word. void set_word (idx_t word, bm_word_t val) { _map[word] = val; } @@ -124,14 +157,16 @@ class BitMap { static void clear_range_of_words(bm_word_t* map, idx_t beg, idx_t end); - static bool is_small_range_of_words(idx_t beg_full_word, idx_t end_full_word); - - // The index of the first full word in a range. - idx_t word_index_round_up(idx_t bit) const; - // Verification. - void verify_index(idx_t index) const NOT_DEBUG_RETURN; - void verify_range(idx_t beg_index, idx_t end_index) const NOT_DEBUG_RETURN; + + // Verify size_in_bits does not exceed max_size_in_bits(). + static void verify_size(idx_t size_in_bits) NOT_DEBUG_RETURN; + // Verify bit is less than size(). + void verify_index(idx_t bit) const NOT_DEBUG_RETURN; + // Verify bit is not greater than size(). + void verify_limit(idx_t bit) const NOT_DEBUG_RETURN; + // Verify [beg,end) is a valid range, e.g. beg <= end <= size(). + void verify_range(idx_t beg, idx_t end) const NOT_DEBUG_RETURN; // Statistics. static const idx_t* _pop_count_table; @@ -182,7 +217,9 @@ class BitMap { } // Protected constructor and destructor. - BitMap(bm_word_t* map, idx_t size_in_bits) : _map(map), _size(size_in_bits) {} + BitMap(bm_word_t* map, idx_t size_in_bits) : _map(map), _size(size_in_bits) { + verify_size(size_in_bits); + } ~BitMap() {} public: @@ -191,16 +228,13 @@ class BitMap { // Accessing static idx_t calc_size_in_words(size_t size_in_bits) { - return word_index(size_in_bits + BitsPerWord - 1); - } - - static idx_t calc_size_in_bytes(size_t size_in_bits) { - return calc_size_in_words(size_in_bits) * BytesPerWord; + verify_size(size_in_bits); + return raw_to_words_align_up(size_in_bits); } idx_t size() const { return _size; } idx_t size_in_words() const { return calc_size_in_words(size()); } - idx_t size_in_bytes() const { return calc_size_in_bytes(size()); } + idx_t size_in_bytes() const { return size_in_words() * BytesPerWord; } bool at(idx_t index) const { verify_index(index); @@ -210,18 +244,6 @@ class BitMap { // memory_order must be memory_order_relaxed or memory_order_acquire. bool par_at(idx_t index, atomic_memory_order memory_order = memory_order_acquire) const; - // Align bit index up or down to the next bitmap word boundary, or check - // alignment. - static idx_t word_align_up(idx_t bit) { - return align_up(bit, BitsPerWord); - } - static idx_t word_align_down(idx_t bit) { - return align_down(bit, BitsPerWord); - } - static bool is_word_aligned(idx_t bit) { - return word_align_up(bit) == bit; - } - // Set or clear the specified bit. inline void set_bit(idx_t bit); inline void clear_bit(idx_t bit); @@ -235,7 +257,7 @@ class BitMap { inline bool par_set_bit(idx_t bit, atomic_memory_order memory_order = memory_order_conservative); inline bool par_clear_bit(idx_t bit, atomic_memory_order memory_order = memory_order_conservative); - // Put the given value at the given offset. The parallel version + // Put the given value at the given index. The parallel version // will CAS the value into the bitmap and is quite a bit slower. // The parallel version also returns a value indicating if the // calling thread was the one that changed the value of the bit. @@ -454,7 +476,7 @@ class BitMapClosure { public: // Callback when bit in map is set. Should normally return "true"; // return of false indicates that the bitmap iteration should terminate. - virtual bool do_bit(BitMap::idx_t offset) = 0; + virtual bool do_bit(BitMap::idx_t index) = 0; }; #endif // SHARE_UTILITIES_BITMAP_HPP diff --git a/src/hotspot/share/utilities/bitMap.inline.hpp b/src/hotspot/share/utilities/bitMap.inline.hpp index 993fcafc554..d8747dfbc5c 100644 --- a/src/hotspot/share/utilities/bitMap.inline.hpp +++ b/src/hotspot/share/utilities/bitMap.inline.hpp @@ -26,6 +26,7 @@ #define SHARE_UTILITIES_BITMAP_INLINE_HPP #include "runtime/atomic.hpp" +#include "utilities/align.hpp" #include "utilities/bitMap.hpp" #include "utilities/count_trailing_zeros.hpp" @@ -167,7 +168,7 @@ template inline BitMap::idx_t BitMap::get_next_bit_impl(idx_t l_index, idx_t r_index) const { STATIC_ASSERT(flip == find_ones_flip || flip == find_zeros_flip); verify_range(l_index, r_index); - assert(!aligned_right || is_word_aligned(r_index), "r_index not aligned"); + assert(!aligned_right || is_aligned(r_index, BitsPerWord), "r_index not aligned"); // The first word often contains an interesting bit, either due to // density or because of features of the calling algorithm. So it's @@ -176,8 +177,8 @@ inline BitMap::idx_t BitMap::get_next_bit_impl(idx_t l_index, idx_t r_index) con // first word is indeed interesting. // The benefit from aligned_right being true is relatively small. - // It saves a couple instructions in the setup for the word search - // loop. It also eliminates the range check on the final result. + // It saves an operation in the setup for the word search loop. + // It also eliminates the range check on the final result. // However, callers often have a comparison with r_index, and // inlining often allows the two comparisons to be combined; it is // important when !aligned_right that return paths either return @@ -188,7 +189,7 @@ inline BitMap::idx_t BitMap::get_next_bit_impl(idx_t l_index, idx_t r_index) con if (l_index < r_index) { // Get the word containing l_index, and shift out low bits. - idx_t index = word_index(l_index); + idx_t index = to_words_align_down(l_index); bm_word_t cword = (map(index) ^ flip) >> bit_in_word(l_index); if ((cword & 1) != 0) { // The first bit is similarly often interesting. When it matters @@ -208,8 +209,8 @@ inline BitMap::idx_t BitMap::get_next_bit_impl(idx_t l_index, idx_t r_index) con // Flipped and shifted first word is zero. Word search through // aligned up r_index for a non-zero flipped word. idx_t limit = aligned_right - ? word_index(r_index) - : (word_index(r_index - 1) + 1); // Align up, knowing r_index > 0. + ? to_words_align_down(r_index) // Miniscule savings when aligned. + : to_words_align_up(r_index); while (++index < limit) { cword = map(index) ^ flip; if (cword != 0) { @@ -248,7 +249,7 @@ BitMap::get_next_one_offset_aligned_right(idx_t l_offset, idx_t r_offset) const inline BitMap::bm_word_t BitMap::inverted_bit_mask_for_range(idx_t beg, idx_t end) const { assert(end != 0, "does not work when end == 0"); - assert(beg == end || word_index(beg) == word_index(end - 1), + assert(beg == end || to_words_align_down(beg) == to_words_align_down(end - 1), "must be a single-word range"); bm_word_t mask = bit_mask(beg) - 1; // low (right) bits if (bit_in_word(end) != 0) { @@ -267,12 +268,6 @@ inline void BitMap::clear_large_range_of_words(idx_t beg, idx_t end) { memset(_map + beg, 0, (end - beg) * sizeof(bm_word_t)); } -inline BitMap::idx_t BitMap::word_index_round_up(idx_t bit) const { - idx_t bit_rounded_up = bit + (BitsPerWord - 1); - // Check for integer arithmetic overflow. - return bit_rounded_up > bit ? word_index(bit_rounded_up) : size_in_words(); -} - inline bool BitMap2D::is_valid_index(idx_t slot_index, idx_t bit_within_slot_index) { verify_bit_within_slot_index(bit_within_slot_index); return (bit_index(slot_index, bit_within_slot_index) < size_in_bits()); diff --git a/test/hotspot/gtest/utilities/test_bitMap_setops.cpp b/test/hotspot/gtest/utilities/test_bitMap_setops.cpp index d7448bbf3b9..5cc59def9d4 100644 --- a/test/hotspot/gtest/utilities/test_bitMap_setops.cpp +++ b/test/hotspot/gtest/utilities/test_bitMap_setops.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 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 @@ -22,6 +22,7 @@ */ #include "precompiled.hpp" +#include "utilities/align.hpp" #include "utilities/bitMap.inline.hpp" #include "utilities/copy.hpp" #include "utilities/debug.hpp" @@ -32,6 +33,10 @@ typedef BitMap::idx_t idx_t; typedef BitMap::bm_word_t bm_word_t; +inline idx_t word_align_down(idx_t bit) { + return align_down(bit, BitsPerWord); +} + class BitMapMemory { private: idx_t _words; @@ -147,7 +152,7 @@ TEST(BitMap, is_same__unaligned) { // Check that a difference in the final partial word does count. { idx_t index = unaligned_size - 2; - ASSERT_LE(BitMap::word_align_down(unaligned_size), index); + ASSERT_LE(word_align_down(unaligned_size), index); WithBitClear wbc(y, index); EXPECT_FALSE(x.is_same(y)); @@ -261,7 +266,7 @@ TEST(BitMap, contains__unaligned) { // Check that a missing bit in the final partial word does count. { idx_t index = unaligned_size - 2; - ASSERT_LE(BitMap::word_align_down(unaligned_size), index); + ASSERT_LE(word_align_down(unaligned_size), index); WithBitClear wbc(x, index); EXPECT_FALSE(x.contains(y)); @@ -307,7 +312,7 @@ TEST(BitMap, intersects__unaligned) { // Check that adding a bit in the final partial word does count. { idx_t index = unaligned_size - 2; - ASSERT_LE(BitMap::word_align_down(unaligned_size), index); + ASSERT_LE(word_align_down(unaligned_size), index); ASSERT_TRUE(x.at(index)); WithBitSet wbs(y, index); @@ -328,8 +333,8 @@ TEST(BitMap, intersects__unaligned) { static void check_tail_unmodified(BitMapMemory& mem, idx_t bits, bm_word_t fill_word) { - if (!BitMap::is_word_aligned(bits)) { - idx_t last_word_bit_index = BitMap::word_align_down(bits); + if (!is_aligned(bits, BitsPerWord)) { + idx_t last_word_bit_index = word_align_down(bits); idx_t last_word_index = BitMap::calc_size_in_words(last_word_bit_index); bm_word_t last_word = mem.memory()[last_word_index]; idx_t shift = bits - last_word_bit_index; From 3e0a5245473d4eb313787f6877304499f9ce9636 Mon Sep 17 00:00:00 2001 From: Roman Kennke Date: Tue, 3 Dec 2019 21:23:27 +0100 Subject: [PATCH 20/81] 8235260: Shenandoah: Don't allow recycle-assist until concurrent roots are done Reviewed-by: zgu --- .../share/gc/shenandoah/shenandoahFreeSet.cpp | 12 ++++++------ .../share/gc/shenandoah/shenandoahFreeSet.hpp | 2 +- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/hotspot/share/gc/shenandoah/shenandoahFreeSet.cpp b/src/hotspot/share/gc/shenandoah/shenandoahFreeSet.cpp index 7c2e8897503..13e9877885c 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahFreeSet.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahFreeSet.cpp @@ -115,7 +115,7 @@ HeapWord* ShenandoahFreeSet::allocate_single(ShenandoahAllocRequest& req, bool& size_t idx = c - 1; if (is_mutator_free(idx)) { ShenandoahHeapRegion* r = _heap->get_region(idx); - if (is_empty_or_trash(r)) { + if (can_allocate_from(r)) { flip_to_gc(r); HeapWord *result = try_allocate_in(r, req, in_new_region); if (result != NULL) { @@ -279,7 +279,7 @@ HeapWord* ShenandoahFreeSet::allocate_contiguous(ShenandoahAllocRequest& req) { // If regions are not adjacent, then current [beg; end] is useless, and we may fast-forward. // If region is not completely free, the current [beg; end] is useless, and we may fast-forward. - if (!is_mutator_free(end) || !is_empty_or_trash(_heap->get_region(end))) { + if (!is_mutator_free(end) || !can_allocate_from(_heap->get_region(end))) { end++; beg = end; continue; @@ -342,8 +342,8 @@ HeapWord* ShenandoahFreeSet::allocate_contiguous(ShenandoahAllocRequest& req) { return _heap->get_region(beg)->bottom(); } -bool ShenandoahFreeSet::is_empty_or_trash(ShenandoahHeapRegion *r) { - return r->is_empty() || r->is_trash(); +bool ShenandoahFreeSet::can_allocate_from(ShenandoahHeapRegion *r) { + return r->is_empty() || (r->is_trash() && !_heap->is_concurrent_root_in_progress()); } size_t ShenandoahFreeSet::alloc_capacity(ShenandoahHeapRegion *r) { @@ -384,7 +384,7 @@ void ShenandoahFreeSet::flip_to_gc(ShenandoahHeapRegion* r) { size_t idx = r->region_number(); assert(_mutator_free_bitmap.at(idx), "Should be in mutator view"); - assert(is_empty_or_trash(r), "Should not be allocated"); + assert(can_allocate_from(r), "Should not be allocated"); _mutator_free_bitmap.clear_bit(idx); _collector_free_bitmap.set_bit(idx); @@ -443,7 +443,7 @@ void ShenandoahFreeSet::rebuild() { if (reserved >= to_reserve) break; ShenandoahHeapRegion* region = _heap->get_region(idx); - if (_mutator_free_bitmap.at(idx) && is_empty_or_trash(region)) { + if (_mutator_free_bitmap.at(idx) && can_allocate_from(region)) { _mutator_free_bitmap.clear_bit(idx); _collector_free_bitmap.set_bit(idx); size_t ac = alloc_capacity(region); diff --git a/src/hotspot/share/gc/shenandoah/shenandoahFreeSet.hpp b/src/hotspot/share/gc/shenandoah/shenandoahFreeSet.hpp index 546b46448d2..0f24c38cdc3 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahFreeSet.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahFreeSet.hpp @@ -67,7 +67,7 @@ private: void try_recycle_trashed(ShenandoahHeapRegion *r); - bool is_empty_or_trash(ShenandoahHeapRegion *r); + bool can_allocate_from(ShenandoahHeapRegion *r); size_t alloc_capacity(ShenandoahHeapRegion *r); bool has_no_alloc_capacity(ShenandoahHeapRegion *r); From 577e87e5b27a3f4c590258b370a42c511f724cbc Mon Sep 17 00:00:00 2001 From: Kim Barrett Date: Tue, 3 Dec 2019 19:09:30 -0500 Subject: [PATCH 21/81] 8234779: Provide idiom for declaring classes noncopyable Add NONCOPYABLE macro and uses. Reviewed-by: dholmes, pliden, coleenp --- src/hotspot/os/aix/os_perf_aix.cpp | 4 ++-- src/hotspot/os/bsd/os_perf_bsd.cpp | 11 +++++------ src/hotspot/os/bsd/semaphore_bsd.hpp | 6 +++--- src/hotspot/os/linux/os_perf_linux.cpp | 4 ++-- src/hotspot/os/linux/waitBarrier_linux.hpp | 5 ++--- src/hotspot/os/posix/os_posix.hpp | 10 +++------- src/hotspot/os/posix/semaphore_posix.hpp | 5 ++--- src/hotspot/os/solaris/os_perf_solaris.cpp | 4 ++-- src/hotspot/os/solaris/os_solaris.hpp | 9 +++------ src/hotspot/os/windows/os_perf_windows.cpp | 4 ++-- src/hotspot/os/windows/os_windows.hpp | 8 ++------ src/hotspot/os/windows/semaphore_windows.hpp | 5 ++--- src/hotspot/share/gc/g1/g1FreeIdSet.hpp | 4 +--- src/hotspot/share/gc/g1/g1SharedDirtyCardQueue.hpp | 4 +--- src/hotspot/share/gc/shared/oopStorage.hpp | 4 +--- src/hotspot/share/gc/shared/oopStorage.inline.hpp | 12 +++--------- src/hotspot/share/gc/shared/oopStorageParState.hpp | 6 ++---- src/hotspot/share/gc/shared/ptrQueue.hpp | 13 +++++++------ src/hotspot/share/gc/shared/taskqueue.hpp | 6 +++--- .../share/gc/shenandoah/shenandoahCodeRoots.hpp | 7 +++---- src/hotspot/share/gc/shenandoah/shenandoahHeap.hpp | 4 ++-- .../share/gc/shenandoah/shenandoahHeapRegionSet.hpp | 6 +++--- src/hotspot/share/gc/z/zArray.hpp | 5 ++--- src/hotspot/share/gc/z/zList.hpp | 5 ++--- src/hotspot/share/jfr/jni/jfrJavaCall.hpp | 4 ++-- src/hotspot/share/memory/metaspaceClosure.hpp | 6 +++--- src/hotspot/share/oops/array.hpp | 5 ++--- src/hotspot/share/runtime/os_perf.hpp | 10 +++++----- src/hotspot/share/runtime/semaphore.hpp | 5 ++--- src/hotspot/share/runtime/thread.hpp | 5 ++--- src/hotspot/share/utilities/bitMap.hpp | 8 +++----- src/hotspot/share/utilities/globalDefinitions.hpp | 13 +++++++++++++ src/hotspot/share/utilities/lockFreeStack.hpp | 6 ++---- src/hotspot/share/utilities/ostream.hpp | 3 +-- .../share/utilities/singleWriterSynchronizer.hpp | 6 ++---- src/hotspot/share/utilities/waitBarrier.hpp | 5 ++--- src/hotspot/share/utilities/waitBarrier_generic.hpp | 5 ++--- 37 files changed, 101 insertions(+), 131 deletions(-) diff --git a/src/hotspot/os/aix/os_perf_aix.cpp b/src/hotspot/os/aix/os_perf_aix.cpp index deed59e742b..f66c60d1e61 100644 --- a/src/hotspot/os/aix/os_perf_aix.cpp +++ b/src/hotspot/os/aix/os_perf_aix.cpp @@ -28,6 +28,7 @@ #include "os_aix.inline.hpp" #include "runtime/os.hpp" #include "runtime/os_perf.hpp" +#include "utilities/globalDefinitions.hpp" #include CPU_HEADER(vm_version_ext) @@ -884,8 +885,7 @@ class NetworkPerformanceInterface::NetworkPerformance : public CHeapObj { int cpu_load_total_process(double* cpu_load); int cpu_loads_process(double* pjvmUserLoad, double* pjvmKernelLoad, double* psystemTotalLoad); - CPUPerformance(const CPUPerformance& rhs); // no impl - CPUPerformance& operator=(const CPUPerformance& rhs); // no impl + NONCOPYABLE(CPUPerformance); + public: CPUPerformance(); bool initialize(); @@ -264,8 +265,7 @@ class SystemProcessInterface::SystemProcesses : public CHeapObj { private: SystemProcesses(); bool initialize(); - SystemProcesses(const SystemProcesses& rhs); // no impl - SystemProcesses& operator=(const SystemProcesses& rhs); // no impl + NONCOPYABLE(SystemProcesses); ~SystemProcesses(); //information about system processes @@ -407,8 +407,7 @@ class NetworkPerformanceInterface::NetworkPerformance : public CHeapObj{ semaphore_t _semaphore; - // Prevent copying and assignment. - OSXSemaphore(const OSXSemaphore&); - OSXSemaphore& operator=(const OSXSemaphore&); + NONCOPYABLE(OSXSemaphore); public: OSXSemaphore(uint value = 0); diff --git a/src/hotspot/os/linux/os_perf_linux.cpp b/src/hotspot/os/linux/os_perf_linux.cpp index f7e5eef084a..28273615a7c 100644 --- a/src/hotspot/os/linux/os_perf_linux.cpp +++ b/src/hotspot/os/linux/os_perf_linux.cpp @@ -28,6 +28,7 @@ #include "os_linux.inline.hpp" #include "runtime/os.hpp" #include "runtime/os_perf.hpp" +#include "utilities/globalDefinitions.hpp" #include CPU_HEADER(vm_version_ext) @@ -948,8 +949,7 @@ class NetworkPerformanceInterface::NetworkPerformance : public CHeapObj { volatile int _futex_barrier; - // Prevent copying and assignment of LinuxWaitBarrier instances. - LinuxWaitBarrier(const LinuxWaitBarrier&); - LinuxWaitBarrier& operator=(const LinuxWaitBarrier&); + NONCOPYABLE(LinuxWaitBarrier); public: LinuxWaitBarrier() : _futex_barrier(0) {}; diff --git a/src/hotspot/os/posix/os_posix.hpp b/src/hotspot/os/posix/os_posix.hpp index d9950765532..74dcbd1d64e 100644 --- a/src/hotspot/os/posix/os_posix.hpp +++ b/src/hotspot/os/posix/os_posix.hpp @@ -285,10 +285,8 @@ class PlatformMutex : public CHeapObj { #endif // PLATFORM_MONITOR_IMPL_INDIRECT -private: - // Disable copying - PlatformMutex(const PlatformMutex&); - PlatformMutex& operator=(const PlatformMutex&); + private: + NONCOPYABLE(PlatformMutex); public: void lock(); @@ -329,9 +327,7 @@ class PlatformMonitor : public PlatformMutex { #endif // PLATFORM_MONITOR_IMPL_INDIRECT private: - // Disable copying - PlatformMonitor(const PlatformMonitor&); - PlatformMonitor& operator=(const PlatformMonitor&); + NONCOPYABLE(PlatformMonitor); public: int wait(jlong millis); diff --git a/src/hotspot/os/posix/semaphore_posix.hpp b/src/hotspot/os/posix/semaphore_posix.hpp index 2e408f7a111..1a267e9d0f6 100644 --- a/src/hotspot/os/posix/semaphore_posix.hpp +++ b/src/hotspot/os/posix/semaphore_posix.hpp @@ -26,15 +26,14 @@ #define OS_POSIX_SEMAPHORE_POSIX_HPP #include "memory/allocation.hpp" +#include "utilities/globalDefinitions.hpp" #include class PosixSemaphore : public CHeapObj { sem_t _semaphore; - // Prevent copying and assignment. - PosixSemaphore(const PosixSemaphore&); - PosixSemaphore& operator=(const PosixSemaphore&); + NONCOPYABLE(PosixSemaphore); public: PosixSemaphore(uint value = 0); diff --git a/src/hotspot/os/solaris/os_perf_solaris.cpp b/src/hotspot/os/solaris/os_perf_solaris.cpp index 80b37c2312e..bd33979a335 100644 --- a/src/hotspot/os/solaris/os_perf_solaris.cpp +++ b/src/hotspot/os/solaris/os_perf_solaris.cpp @@ -28,6 +28,7 @@ #include "runtime/os.hpp" #include "runtime/os_perf.hpp" #include "os_solaris.inline.hpp" +#include "utilities/globalDefinitions.hpp" #include "utilities/macros.hpp" #include CPU_HEADER(vm_version_ext) @@ -737,8 +738,7 @@ class NetworkPerformanceInterface::NetworkPerformance : public CHeapObj { // Platform specific implementations that underpin VM Mutex/Monitor classes class PlatformMutex : public CHeapObj { - // Disable copying - PlatformMutex(const PlatformMutex&); - PlatformMutex& operator=(const PlatformMutex&); + NONCOPYABLE(PlatformMutex); protected: mutex_t _mutex; // Native mutex for locking @@ -352,9 +350,8 @@ class PlatformMutex : public CHeapObj { class PlatformMonitor : public PlatformMutex { private: cond_t _cond; // Native condition variable for blocking - // Disable copying - PlatformMonitor(const PlatformMonitor&); - PlatformMonitor& operator=(const PlatformMonitor&); + + NONCOPYABLE(PlatformMonitor); public: PlatformMonitor(); diff --git a/src/hotspot/os/windows/os_perf_windows.cpp b/src/hotspot/os/windows/os_perf_windows.cpp index 3921dc37dd2..9a0e35b0592 100644 --- a/src/hotspot/os/windows/os_perf_windows.cpp +++ b/src/hotspot/os/windows/os_perf_windows.cpp @@ -30,6 +30,7 @@ #include "pdh_interface.hpp" #include "runtime/os_perf.hpp" #include "runtime/os.hpp" +#include "utilities/globalDefinitions.hpp" #include "utilities/macros.hpp" #include CPU_HEADER(vm_version_ext) #include @@ -1355,8 +1356,7 @@ class NetworkPerformanceInterface::NetworkPerformance : public CHeapObj { // Platform specific implementations that underpin VM Mutex/Monitor classes class PlatformMutex : public CHeapObj { - // Disable copying - PlatformMutex(const PlatformMutex&); - PlatformMutex& operator=(const PlatformMutex&); + NONCOPYABLE(PlatformMutex); protected: CRITICAL_SECTION _mutex; // Native mutex for locking @@ -208,9 +206,7 @@ class PlatformMutex : public CHeapObj { class PlatformMonitor : public PlatformMutex { private: CONDITION_VARIABLE _cond; // Native condition variable for blocking - // Disable copying - PlatformMonitor(const PlatformMonitor&); - PlatformMonitor& operator=(const PlatformMonitor&); + NONCOPYABLE(PlatformMonitor); public: PlatformMonitor(); diff --git a/src/hotspot/os/windows/semaphore_windows.hpp b/src/hotspot/os/windows/semaphore_windows.hpp index c72fa52350e..db05d49536d 100644 --- a/src/hotspot/os/windows/semaphore_windows.hpp +++ b/src/hotspot/os/windows/semaphore_windows.hpp @@ -26,15 +26,14 @@ #define OS_WINDOWS_SEMAPHORE_WINDOWS_HPP #include "memory/allocation.hpp" +#include "utilities/globalDefinitions.hpp" #include class WindowsSemaphore : public CHeapObj { HANDLE _semaphore; - // Prevent copying and assignment. - WindowsSemaphore(const WindowsSemaphore&); - WindowsSemaphore& operator=(const WindowsSemaphore&); + NONCOPYABLE(WindowsSemaphore); public: WindowsSemaphore(uint value = 0); diff --git a/src/hotspot/share/gc/g1/g1FreeIdSet.hpp b/src/hotspot/share/gc/g1/g1FreeIdSet.hpp index 270a98169f6..3cc7a4ed1af 100644 --- a/src/hotspot/share/gc/g1/g1FreeIdSet.hpp +++ b/src/hotspot/share/gc/g1/g1FreeIdSet.hpp @@ -44,9 +44,7 @@ class G1FreeIdSet { uint head_index(uintx head) const; uintx make_head(uint index, uintx old_head) const; - // Noncopyable. - G1FreeIdSet(const G1FreeIdSet&); - G1FreeIdSet& operator=(const G1FreeIdSet&); + NONCOPYABLE(G1FreeIdSet); public: G1FreeIdSet(uint start, uint size); diff --git a/src/hotspot/share/gc/g1/g1SharedDirtyCardQueue.hpp b/src/hotspot/share/gc/g1/g1SharedDirtyCardQueue.hpp index d921b881714..2f28e2f6300 100644 --- a/src/hotspot/share/gc/g1/g1SharedDirtyCardQueue.hpp +++ b/src/hotspot/share/gc/g1/g1SharedDirtyCardQueue.hpp @@ -37,9 +37,7 @@ class G1SharedDirtyCardQueue { void** _buffer; size_t _index; - // Noncopyable - G1SharedDirtyCardQueue(const G1SharedDirtyCardQueue&); - G1SharedDirtyCardQueue& operator=(const G1SharedDirtyCardQueue&); + NONCOPYABLE(G1SharedDirtyCardQueue); public: G1SharedDirtyCardQueue(G1DirtyCardQueueSet* qset); diff --git a/src/hotspot/share/gc/shared/oopStorage.hpp b/src/hotspot/share/gc/shared/oopStorage.hpp index 3cf529a6a7b..36862f954a0 100644 --- a/src/hotspot/share/gc/shared/oopStorage.hpp +++ b/src/hotspot/share/gc/shared/oopStorage.hpp @@ -193,9 +193,7 @@ private: const Block* _head; const Block* _tail; - // Noncopyable. - AllocationList(const AllocationList&); - AllocationList& operator=(const AllocationList&); + NONCOPYABLE(AllocationList); public: AllocationList(); diff --git a/src/hotspot/share/gc/shared/oopStorage.inline.hpp b/src/hotspot/share/gc/shared/oopStorage.inline.hpp index 618e7c93339..d0b11c4973c 100644 --- a/src/hotspot/share/gc/shared/oopStorage.inline.hpp +++ b/src/hotspot/share/gc/shared/oopStorage.inline.hpp @@ -48,9 +48,7 @@ class OopStorage::ActiveArray { ActiveArray(size_t size); ~ActiveArray(); - // Noncopyable - ActiveArray(const ActiveArray&); - ActiveArray& operator=(const ActiveArray&); + NONCOPYABLE(ActiveArray); static size_t blocks_offset(); Block* const* base_ptr() const; @@ -118,9 +116,7 @@ class OopStorage::AllocationListEntry { mutable const Block* _prev; mutable const Block* _next; - // Noncopyable. - AllocationListEntry(const AllocationListEntry&); - AllocationListEntry& operator=(const AllocationListEntry&); + NONCOPYABLE(AllocationListEntry); public: AllocationListEntry(); @@ -153,9 +149,7 @@ class OopStorage::Block /* No base class, to avoid messing up alignment. */ { template static bool iterate_impl(F f, BlockPtr b); - // Noncopyable. - Block(const Block&); - Block& operator=(const Block&); + NONCOPYABLE(Block); public: const AllocationListEntry& allocation_list_entry() const; diff --git a/src/hotspot/share/gc/shared/oopStorageParState.hpp b/src/hotspot/share/gc/shared/oopStorageParState.hpp index 32cc53a637a..010b5bea156 100644 --- a/src/hotspot/share/gc/shared/oopStorageParState.hpp +++ b/src/hotspot/share/gc/shared/oopStorageParState.hpp @@ -26,7 +26,7 @@ #define SHARE_GC_SHARED_OOPSTORAGEPARSTATE_HPP #include "gc/shared/oopStorage.hpp" -#include "utilities/macros.hpp" +#include "utilities/globalDefinitions.hpp" ////////////////////////////////////////////////////////////////////////////// // Support for parallel and optionally concurrent state iteration. @@ -134,9 +134,7 @@ class OopStorage::BasicParState { uint _estimated_thread_count; bool _concurrent; - // Noncopyable. - BasicParState(const BasicParState&); - BasicParState& operator=(const BasicParState&); + NONCOPYABLE(BasicParState); struct IterationData; diff --git a/src/hotspot/share/gc/shared/ptrQueue.hpp b/src/hotspot/share/gc/shared/ptrQueue.hpp index d2fe07ece69..3c48fa86b72 100644 --- a/src/hotspot/share/gc/shared/ptrQueue.hpp +++ b/src/hotspot/share/gc/shared/ptrQueue.hpp @@ -28,6 +28,7 @@ #include "memory/padded.hpp" #include "utilities/align.hpp" #include "utilities/debug.hpp" +#include "utilities/globalDefinitions.hpp" #include "utilities/lockFreeStack.hpp" #include "utilities/sizes.hpp" @@ -44,9 +45,7 @@ class PtrQueueSet; class PtrQueue { friend class VMStructs; - // Noncopyable - not defined. - PtrQueue(const PtrQueue&); - PtrQueue& operator=(const PtrQueue&); + NONCOPYABLE(PtrQueue); // The ptr queue set to which this queue belongs. PtrQueueSet* const _qset; @@ -205,6 +204,8 @@ class BufferNode { BufferNode() : _index(0), _next(NULL) { } ~BufferNode() { } + NONCOPYABLE(BufferNode); + static size_t buffer_offset() { return offset_of(BufferNode, _buffer); } @@ -273,6 +274,8 @@ class BufferNode::Allocator { void delete_list(BufferNode* list); bool try_transfer_pending(); + NONCOPYABLE(Allocator); + public: Allocator(const char* name, size_t buffer_size); ~Allocator(); @@ -295,9 +298,7 @@ public: class PtrQueueSet { BufferNode::Allocator* _allocator; - // Noncopyable - not defined. - PtrQueueSet(const PtrQueueSet&); - PtrQueueSet& operator=(const PtrQueueSet&); + NONCOPYABLE(PtrQueueSet); protected: bool _all_active; diff --git a/src/hotspot/share/gc/shared/taskqueue.hpp b/src/hotspot/share/gc/shared/taskqueue.hpp index 6abe35e3085..f8dc3d0416b 100644 --- a/src/hotspot/share/gc/shared/taskqueue.hpp +++ b/src/hotspot/share/gc/shared/taskqueue.hpp @@ -28,6 +28,7 @@ #include "memory/allocation.hpp" #include "memory/padded.hpp" #include "oops/oopsHierarchy.hpp" +#include "utilities/globalDefinitions.hpp" #include "utilities/ostream.hpp" #include "utilities/stack.hpp" @@ -514,9 +515,8 @@ class TaskTerminator : public StackObj { private: ParallelTaskTerminator* _terminator; - // Noncopyable. - TaskTerminator(const TaskTerminator&); - TaskTerminator& operator=(const TaskTerminator&); + NONCOPYABLE(TaskTerminator); + public: TaskTerminator(uint n_threads, TaskQueueSetSuper* queue_set); ~TaskTerminator(); diff --git a/src/hotspot/share/gc/shenandoah/shenandoahCodeRoots.hpp b/src/hotspot/share/gc/shenandoah/shenandoahCodeRoots.hpp index d02713ab41b..42661f4f870 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahCodeRoots.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahCodeRoots.hpp @@ -30,6 +30,7 @@ #include "gc/shenandoah/shenandoahNMethod.hpp" #include "memory/allocation.hpp" #include "memory/iterator.hpp" +#include "utilities/globalDefinitions.hpp" class ShenandoahHeap; class ShenandoahHeapRegion; @@ -53,10 +54,8 @@ private: ShenandoahParallelCodeHeapIterator* _iters; int _length; -private: - // Noncopyable. - ShenandoahParallelCodeCacheIterator(const ShenandoahParallelCodeCacheIterator& o); - ShenandoahParallelCodeCacheIterator& operator=(const ShenandoahParallelCodeCacheIterator& o); + NONCOPYABLE(ShenandoahParallelCodeCacheIterator); + public: ShenandoahParallelCodeCacheIterator(const GrowableArray* heaps); ~ShenandoahParallelCodeCacheIterator(); diff --git a/src/hotspot/share/gc/shenandoah/shenandoahHeap.hpp b/src/hotspot/share/gc/shenandoah/shenandoahHeap.hpp index 5b1ed5af5e1..ca962d1aa0a 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahHeap.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahHeap.hpp @@ -34,6 +34,7 @@ #include "gc/shenandoah/shenandoahSharedVariables.hpp" #include "gc/shenandoah/shenandoahUnload.hpp" #include "services/memoryManager.hpp" +#include "utilities/globalDefinitions.hpp" class ConcurrentGCTimer; class ReferenceProcessor; @@ -70,8 +71,7 @@ private: DEFINE_PAD_MINUS_SIZE(1, DEFAULT_CACHE_LINE_SIZE, 0); // No implicit copying: iterators should be passed by reference to capture the state - ShenandoahRegionIterator(const ShenandoahRegionIterator& that); - ShenandoahRegionIterator& operator=(const ShenandoahRegionIterator& o); + NONCOPYABLE(ShenandoahRegionIterator); public: ShenandoahRegionIterator(); diff --git a/src/hotspot/share/gc/shenandoah/shenandoahHeapRegionSet.hpp b/src/hotspot/share/gc/shenandoah/shenandoahHeapRegionSet.hpp index efec2af8bad..5b15e7589b6 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahHeapRegionSet.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahHeapRegionSet.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2018, Red Hat, Inc. All rights reserved. + * Copyright (c) 2013, 2019, Red Hat, Inc. All rights reserved. * * 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 @@ -27,6 +27,7 @@ #include "memory/allocation.hpp" #include "gc/shenandoah/shenandoahHeap.hpp" #include "gc/shenandoah/shenandoahHeapRegion.hpp" +#include "utilities/globalDefinitions.hpp" class ShenandoahHeapRegionSet; @@ -40,8 +41,7 @@ private: DEFINE_PAD_MINUS_SIZE(1, DEFAULT_CACHE_LINE_SIZE, 0); // No implicit copying: iterators should be passed by reference to capture the state - ShenandoahHeapRegionSetIterator(const ShenandoahHeapRegionSetIterator& that); - ShenandoahHeapRegionSetIterator& operator=(const ShenandoahHeapRegionSetIterator& o); + NONCOPYABLE(ShenandoahHeapRegionSetIterator); public: ShenandoahHeapRegionSetIterator(const ShenandoahHeapRegionSet* const set); diff --git a/src/hotspot/share/gc/z/zArray.hpp b/src/hotspot/share/gc/z/zArray.hpp index 378e45032c2..ec1ff3ce6ac 100644 --- a/src/hotspot/share/gc/z/zArray.hpp +++ b/src/hotspot/share/gc/z/zArray.hpp @@ -25,6 +25,7 @@ #define SHARE_GC_Z_ZARRAY_HPP #include "memory/allocation.hpp" +#include "utilities/globalDefinitions.hpp" template class ZArray { @@ -35,9 +36,7 @@ private: size_t _size; size_t _capacity; - // Copy and assignment are not allowed - ZArray(const ZArray& array); - ZArray& operator=(const ZArray& array); + NONCOPYABLE(ZArray); void expand(size_t new_capacity); diff --git a/src/hotspot/share/gc/z/zList.hpp b/src/hotspot/share/gc/z/zList.hpp index 6fc1a11758e..143540b4aaf 100644 --- a/src/hotspot/share/gc/z/zList.hpp +++ b/src/hotspot/share/gc/z/zList.hpp @@ -25,6 +25,7 @@ #define SHARE_GC_Z_ZLIST_HPP #include "memory/allocation.hpp" +#include "utilities/globalDefinitions.hpp" template class ZList; @@ -55,9 +56,7 @@ private: ZListNode _head; size_t _size; - // Passing by value and assignment is not allowed - ZList(const ZList& list); - ZList& operator=(const ZList& list); + NONCOPYABLE(ZList); void verify() const; diff --git a/src/hotspot/share/jfr/jni/jfrJavaCall.hpp b/src/hotspot/share/jfr/jni/jfrJavaCall.hpp index b140ee846a9..8011b289ad3 100644 --- a/src/hotspot/share/jfr/jni/jfrJavaCall.hpp +++ b/src/hotspot/share/jfr/jni/jfrJavaCall.hpp @@ -28,6 +28,7 @@ #include "jni.h" #include "jfr/utilities/jfrAllocation.hpp" #include "utilities/exceptions.hpp" +#include "utilities/globalDefinitions.hpp" class JavaCallArguments; class JavaThread; @@ -86,8 +87,7 @@ class JfrJavaArguments : public StackObj { int _java_stack_slots; Parameters(); - Parameters(const Parameters&); // no impl - Parameters& operator=(const Parameters&); // no impl + NONCOPYABLE(Parameters); void push(const JavaValue& value); void push_large(const JavaValue& value); diff --git a/src/hotspot/share/memory/metaspaceClosure.hpp b/src/hotspot/share/memory/metaspaceClosure.hpp index 0bc8948283c..879b89df99c 100644 --- a/src/hotspot/share/memory/metaspaceClosure.hpp +++ b/src/hotspot/share/memory/metaspaceClosure.hpp @@ -28,6 +28,7 @@ #include "logging/log.hpp" #include "memory/allocation.hpp" #include "oops/array.hpp" +#include "utilities/globalDefinitions.hpp" #include "utilities/growableArray.hpp" #include "utilities/hashtable.inline.hpp" @@ -108,9 +109,8 @@ public: class Ref : public CHeapObj { Writability _writability; Ref* _next; - // Noncopyable. - Ref(const Ref&); - Ref& operator=(const Ref&); + NONCOPYABLE(Ref); + protected: virtual void** mpp() const = 0; Ref(Writability w) : _writability(w), _next(NULL) {} diff --git a/src/hotspot/share/oops/array.hpp b/src/hotspot/share/oops/array.hpp index 543907e21ad..f383564ac84 100644 --- a/src/hotspot/share/oops/array.hpp +++ b/src/hotspot/share/oops/array.hpp @@ -29,6 +29,7 @@ #include "memory/metaspace.hpp" #include "runtime/atomic.hpp" #include "utilities/align.hpp" +#include "utilities/globalDefinitions.hpp" // Array for metadata allocation @@ -49,9 +50,7 @@ protected: } private: - // Turn off copy constructor and assignment operator. - Array(const Array&); - void operator=(const Array&); + NONCOPYABLE(Array); void* operator new(size_t size, ClassLoaderData* loader_data, int length, TRAPS) throw() { size_t word_size = Array::size(length); diff --git a/src/hotspot/share/runtime/os_perf.hpp b/src/hotspot/share/runtime/os_perf.hpp index 8526c8d8024..00f801e99fc 100644 --- a/src/hotspot/share/runtime/os_perf.hpp +++ b/src/hotspot/share/runtime/os_perf.hpp @@ -26,6 +26,7 @@ #define SHARE_RUNTIME_OS_PERF_HPP #include "memory/allocation.hpp" +#include "utilities/globalDefinitions.hpp" #include "utilities/macros.hpp" #define FUNCTIONALITY_NOT_IMPLEMENTED -8 @@ -190,9 +191,8 @@ class NetworkInterface : public ResourceObj { uint64_t _bytes_out; NetworkInterface* _next; - NetworkInterface(); // no impl - NetworkInterface(const NetworkInterface& rhs); // no impl - NetworkInterface& operator=(const NetworkInterface& rhs); // no impl + NONCOPYABLE(NetworkInterface); + public: NetworkInterface(const char* name, uint64_t bytes_in, uint64_t bytes_out, NetworkInterface* next) : _name(NULL), @@ -268,8 +268,8 @@ class NetworkPerformanceInterface : public CHeapObj { private: class NetworkPerformance; NetworkPerformance* _impl; - NetworkPerformanceInterface(const NetworkPerformanceInterface& rhs); // no impl - NetworkPerformanceInterface& operator=(const NetworkPerformanceInterface& rhs); // no impl + NONCOPYABLE(NetworkPerformanceInterface); + public: NetworkPerformanceInterface(); bool initialize(); diff --git a/src/hotspot/share/runtime/semaphore.hpp b/src/hotspot/share/runtime/semaphore.hpp index f94a41cf12b..c56e9c9a26a 100644 --- a/src/hotspot/share/runtime/semaphore.hpp +++ b/src/hotspot/share/runtime/semaphore.hpp @@ -26,6 +26,7 @@ #define SHARE_RUNTIME_SEMAPHORE_HPP #include "memory/allocation.hpp" +#include "utilities/globalDefinitions.hpp" #if defined(LINUX) || defined(SOLARIS) || defined(AIX) # include "semaphore_posix.hpp" @@ -43,9 +44,7 @@ class JavaThread; class Semaphore : public CHeapObj { SemaphoreImpl _impl; - // Prevent copying and assignment of Semaphore instances. - Semaphore(const Semaphore&); - Semaphore& operator=(const Semaphore&); + NONCOPYABLE(Semaphore); public: Semaphore(uint value = 0) : _impl(value) {} diff --git a/src/hotspot/share/runtime/thread.hpp b/src/hotspot/share/runtime/thread.hpp index 4a002185b7b..2cde8dce697 100644 --- a/src/hotspot/share/runtime/thread.hpp +++ b/src/hotspot/share/runtime/thread.hpp @@ -48,6 +48,7 @@ #include "runtime/unhandledOops.hpp" #include "utilities/align.hpp" #include "utilities/exceptions.hpp" +#include "utilities/globalDefinitions.hpp" #include "utilities/macros.hpp" #ifdef ZERO # include "stack_zero.hpp" @@ -875,9 +876,7 @@ class NonJavaThread::Iterator : public StackObj { uint _protect_enter; NonJavaThread* _current; - // Noncopyable. - Iterator(const Iterator&); - Iterator& operator=(const Iterator&); + NONCOPYABLE(Iterator); public: Iterator(); diff --git a/src/hotspot/share/utilities/bitMap.hpp b/src/hotspot/share/utilities/bitMap.hpp index 148dab5d9df..d849389e337 100644 --- a/src/hotspot/share/utilities/bitMap.hpp +++ b/src/hotspot/share/utilities/bitMap.hpp @@ -27,6 +27,7 @@ #include "memory/allocation.hpp" #include "runtime/atomic.hpp" +#include "utilities/globalDefinitions.hpp" // Forward decl; class BitMapClosure; @@ -390,9 +391,7 @@ class ArenaBitMap : public BitMap { ArenaBitMap(Arena* arena, idx_t size_in_bits); private: - // Don't allow copy or assignment. - ArenaBitMap(const ArenaBitMap&); - ArenaBitMap& operator=(const ArenaBitMap&); + NONCOPYABLE(ArenaBitMap); }; // A BitMap with storage in the CHeap. @@ -401,8 +400,7 @@ class CHeapBitMap : public BitMap { private: // Don't allow copy or assignment, to prevent the // allocated memory from leaking out to other instances. - CHeapBitMap(const CHeapBitMap&); - CHeapBitMap& operator=(const CHeapBitMap&); + NONCOPYABLE(CHeapBitMap); // NMT memory type MEMFLAGS _flags; diff --git a/src/hotspot/share/utilities/globalDefinitions.hpp b/src/hotspot/share/utilities/globalDefinitions.hpp index 193628d32f1..d65758c2199 100644 --- a/src/hotspot/share/utilities/globalDefinitions.hpp +++ b/src/hotspot/share/utilities/globalDefinitions.hpp @@ -69,6 +69,19 @@ // This file holds all globally used constants & types, class (forward) // declarations and a few frequently used utility functions. +// Declare the named class to be noncopyable. This macro must be used in +// a private part of the class's definition, followed by a semi-colon. +// Doing so provides private declarations for the class's copy constructor +// and assignment operator. Because these operations are private, most +// potential callers will fail to compile because they are inaccessible. +// The operations intentionally lack a definition, to provoke link-time +// failures for calls from contexts where they are accessible, e.g. from +// within the class or from a friend of the class. +// Note: The lack of definitions is still not completely bullet-proof, as +// an apparent call might be optimized away by copy elision. +// For C++11 the declarations should be changed to deleted definitions. +#define NONCOPYABLE(C) C(C const&); C& operator=(C const&) /* next token must be ; */ + //---------------------------------------------------------------------------------------------------- // Printf-style formatters for fixed- and variable-width types as pointers and // integers. These are derived from the definitions in inttypes.h. If the platform diff --git a/src/hotspot/share/utilities/lockFreeStack.hpp b/src/hotspot/share/utilities/lockFreeStack.hpp index 24a1a8de4d5..50c4ad9fc8e 100644 --- a/src/hotspot/share/utilities/lockFreeStack.hpp +++ b/src/hotspot/share/utilities/lockFreeStack.hpp @@ -27,7 +27,7 @@ #include "runtime/atomic.hpp" #include "utilities/debug.hpp" -#include "utilities/macros.hpp" +#include "utilities/globalDefinitions.hpp" // The LockFreeStack class template provides a lock-free LIFO. The objects // in the sequence are intrusively linked via a member in the objects. As @@ -69,9 +69,7 @@ class LockFreeStack { } while (old != cur); } - // Noncopyable. - LockFreeStack(const LockFreeStack&); - LockFreeStack& operator=(const LockFreeStack&); + NONCOPYABLE(LockFreeStack); public: LockFreeStack() : _top(NULL) {} diff --git a/src/hotspot/share/utilities/ostream.hpp b/src/hotspot/share/utilities/ostream.hpp index f0b58408375..f737a53c965 100644 --- a/src/hotspot/share/utilities/ostream.hpp +++ b/src/hotspot/share/utilities/ostream.hpp @@ -43,8 +43,7 @@ DEBUG_ONLY(class ResourceMark;) // -XX:+DisplayVMOutputToStderr class outputStream : public ResourceObj { private: - outputStream(const outputStream&); - outputStream& operator=(const outputStream&); + NONCOPYABLE(outputStream); protected: int _indentation; // current indentation diff --git a/src/hotspot/share/utilities/singleWriterSynchronizer.hpp b/src/hotspot/share/utilities/singleWriterSynchronizer.hpp index d1d47af3666..b49e75ffe90 100644 --- a/src/hotspot/share/utilities/singleWriterSynchronizer.hpp +++ b/src/hotspot/share/utilities/singleWriterSynchronizer.hpp @@ -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 @@ -55,9 +55,7 @@ class SingleWriterSynchronizer { DEBUG_ONLY(volatile uint _writers;) - // Noncopyable. - SingleWriterSynchronizer(const SingleWriterSynchronizer&); - SingleWriterSynchronizer& operator=(const SingleWriterSynchronizer&); + NONCOPYABLE(SingleWriterSynchronizer); public: SingleWriterSynchronizer(); diff --git a/src/hotspot/share/utilities/waitBarrier.hpp b/src/hotspot/share/utilities/waitBarrier.hpp index 86c662ec04a..09f7eab926f 100644 --- a/src/hotspot/share/utilities/waitBarrier.hpp +++ b/src/hotspot/share/utilities/waitBarrier.hpp @@ -28,6 +28,7 @@ #include "memory/allocation.hpp" #include "runtime/thread.hpp" #include "utilities/debug.hpp" +#include "utilities/globalDefinitions.hpp" #include "utilities/waitBarrier_generic.hpp" #if defined(LINUX) @@ -81,9 +82,7 @@ template class WaitBarrierType : public CHeapObj { WaitBarrierImpl _impl; - // Prevent copying and assignment of WaitBarrier instances. - WaitBarrierType(const WaitBarrierDefault&); - WaitBarrierType& operator=(const WaitBarrierDefault&); + NONCOPYABLE(WaitBarrierType); #ifdef ASSERT int _last_arm_tag; diff --git a/src/hotspot/share/utilities/waitBarrier_generic.hpp b/src/hotspot/share/utilities/waitBarrier_generic.hpp index f5ca2d3a230..50bfea6aebf 100644 --- a/src/hotspot/share/utilities/waitBarrier_generic.hpp +++ b/src/hotspot/share/utilities/waitBarrier_generic.hpp @@ -27,6 +27,7 @@ #include "memory/allocation.hpp" #include "runtime/semaphore.hpp" +#include "utilities/globalDefinitions.hpp" // In addition to the barrier tag, it uses two counters to keep the semaphore // count correct and not leave any late thread waiting. @@ -39,9 +40,7 @@ class GenericWaitBarrier : public CHeapObj { volatile int _barrier_threads; Semaphore _sem_barrier; - // Prevent copying and assignment of GenericWaitBarrier instances. - GenericWaitBarrier(const GenericWaitBarrier&); - GenericWaitBarrier& operator=(const GenericWaitBarrier&); + NONCOPYABLE(GenericWaitBarrier); int wake_if_needed(); From 96a8b9796db9ed15bf1397800d27c99c3514f000 Mon Sep 17 00:00:00 2001 From: Xue-Lei Andrew Fan Date: Tue, 3 Dec 2019 17:15:02 -0800 Subject: [PATCH 22/81] 8235263: Revert TLS 1.3 change that wrapped IOExceptions Reviewed-by: mullan --- .../share/classes/sun/security/ssl/SSLSocketImpl.java | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/java.base/share/classes/sun/security/ssl/SSLSocketImpl.java b/src/java.base/share/classes/sun/security/ssl/SSLSocketImpl.java index 9adeae9979b..dee10ca85ba 100644 --- a/src/java.base/share/classes/sun/security/ssl/SSLSocketImpl.java +++ b/src/java.base/share/classes/sun/security/ssl/SSLSocketImpl.java @@ -1254,9 +1254,11 @@ public final class SSLSocketImpl } catch (SSLHandshakeException she) { // may be record sequence number overflow throw conContext.fatal(Alert.HANDSHAKE_FAILURE, she); - } catch (IOException e) { - throw conContext.fatal(Alert.UNEXPECTED_MESSAGE, e); - } + } catch (SSLException ssle) { + throw conContext.fatal(Alert.UNEXPECTED_MESSAGE, ssle); + } // re-throw other IOException, which should be caused by + // the underlying plain socket and could be handled by + // applications (for example, re-try the connection). // Is the sequence number is nearly overflow, or has the key usage // limit been reached? From b1c42a1d4698df6870c0c5c4782eafebef5258df Mon Sep 17 00:00:00 2001 From: Chris Plummer Date: Tue, 3 Dec 2019 20:08:37 -0800 Subject: [PATCH 23/81] 8235221: Fix ProblemList.txt for sun/tools/jhsdb/HeapDumpTestWithActiveProcess.java Reviewed-by: iignatyev --- test/jdk/ProblemList.txt | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/test/jdk/ProblemList.txt b/test/jdk/ProblemList.txt index 4f6e48a7d6b..d75b0bcbda2 100644 --- a/test/jdk/ProblemList.txt +++ b/test/jdk/ProblemList.txt @@ -915,8 +915,7 @@ com/sun/jdi/NashornPopFrameTest.java 8225620 generic- sun/tools/jhsdb/BasicLauncherTest.java 8193639,8211767 solaris-all,linux-ppc64,linux-ppc64le sun/tools/jhsdb/HeapDumpTest.java 8193639 solaris-all -sun/tools/jhsdb/HeapDumpTestWithActiveProcess.java 8230731,8001227 windows-all -sun/tools/jhsdb/HeapDumpTestWithActiveProcess.java 8231635,8231634 generic-all +sun/tools/jhsdb/HeapDumpTestWithActiveProcess.java 8231634,8230731,8001227 generic-all,windows-all ############################################################################ From 503a960e7d8c2ad8affa9264370cc9498778fa1d Mon Sep 17 00:00:00 2001 From: Igor Ignatyev Date: Tue, 3 Dec 2019 20:23:53 -0800 Subject: [PATCH 24/81] 8129092: compiler/intrinsics/classcast/NullCheckDroppingsTest.java testVarClassCast() can fail Reviewed-by: kvn --- .../klass/CastNullCheckDroppingsTest.java | 100 ++++++++++++------ 1 file changed, 68 insertions(+), 32 deletions(-) diff --git a/test/hotspot/jtreg/compiler/intrinsics/klass/CastNullCheckDroppingsTest.java b/test/hotspot/jtreg/compiler/intrinsics/klass/CastNullCheckDroppingsTest.java index c31a87a46a2..5fd41842e3a 100644 --- a/test/hotspot/jtreg/compiler/intrinsics/klass/CastNullCheckDroppingsTest.java +++ b/test/hotspot/jtreg/compiler/intrinsics/klass/CastNullCheckDroppingsTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 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 @@ -25,6 +25,7 @@ * @test NullCheckDroppingsTest * @bug 8054492 * @summary Casting can result in redundant null checks in generated code + * @requires vm.hasJFR * @requires vm.flavor == "server" & !vm.emulatedClient & !vm.graal.enabled * @library /test/lib * @modules java.base/jdk.internal.misc @@ -41,14 +42,20 @@ package compiler.intrinsics.klass; +import jdk.jfr.Recording; +import jdk.jfr.consumer.RecordedEvent; import jdk.test.lib.Platform; +import jdk.test.lib.jfr.EventNames; +import jdk.test.lib.jfr.Events; import sun.hotspot.WhiteBox; import sun.hotspot.code.NMethod; +import java.io.IOException; import java.lang.invoke.MethodHandle; import java.lang.invoke.MethodHandles; import java.lang.invoke.MethodType; import java.lang.reflect.Method; +import java.util.List; import java.util.function.BiFunction; public class CastNullCheckDroppingsTest { @@ -73,7 +80,7 @@ public class CastNullCheckDroppingsTest { } static volatile String svalue = "A"; - static volatile String snull = null; + static volatile Object onull = null; static volatile Integer iobj = new Integer(0); static volatile int[] arr = new int[2]; static volatile Class objClass = String.class; @@ -102,35 +109,35 @@ public class CastNullCheckDroppingsTest { Method methodFunction = CastNullCheckDroppingsTest.class.getDeclaredMethod("testFunction", String.class); CastNullCheckDroppingsTest t = new CastNullCheckDroppingsTest(); - t.runTest(methodClassCast, false); - t.runTest(methodMHCast, false); - t.runTest(methodMHSetter, false); - t.runTest(methodFunction, false); + t.runTest(methodClassCast, false, svalue); + t.runTest(methodMHCast, false, svalue); + t.runTest(methodMHSetter, false, svalue); + t.runTest(methodFunction, false, svalue); // Edge cases Method methodClassCastNull = CastNullCheckDroppingsTest.class.getDeclaredMethod("testClassCastNull", String.class); Method methodNullClassCast = CastNullCheckDroppingsTest.class.getDeclaredMethod("testNullClassCast", String.class); Method methodClassCastObj = CastNullCheckDroppingsTest.class.getDeclaredMethod("testClassCastObj", Object.class); Method methodObjClassCast = CastNullCheckDroppingsTest.class.getDeclaredMethod("testObjClassCast", String.class); - Method methodVarClassCast = CastNullCheckDroppingsTest.class.getDeclaredMethod("testVarClassCast", String.class); Method methodClassCastInt = CastNullCheckDroppingsTest.class.getDeclaredMethod("testClassCastInt", Object.class); Method methodIntClassCast = CastNullCheckDroppingsTest.class.getDeclaredMethod("testIntClassCast", Object.class); Method methodClassCastint = CastNullCheckDroppingsTest.class.getDeclaredMethod("testClassCastint", Object.class); Method methodintClassCast = CastNullCheckDroppingsTest.class.getDeclaredMethod("testintClassCast", Object.class); Method methodClassCastPrim = CastNullCheckDroppingsTest.class.getDeclaredMethod("testClassCastPrim", Object.class); Method methodPrimClassCast = CastNullCheckDroppingsTest.class.getDeclaredMethod("testPrimClassCast", Object.class); + Method methodVarClassCast = CastNullCheckDroppingsTest.class.getDeclaredMethod("testVarClassCast", Class.class); - t.runTest(methodClassCastNull, false); - t.runTest(methodNullClassCast, false); - t.runTest(methodClassCastObj, false); - t.runTest(methodObjClassCast, true); - t.runTest(methodVarClassCast, true); - t.runTest(methodClassCastInt, false); - t.runTest(methodIntClassCast, true); - t.runTest(methodClassCastint, false); - t.runTest(methodintClassCast, false); - t.runTest(methodClassCastPrim, false); - t.runTest(methodPrimClassCast, true); + t.runTest(methodClassCastNull, false, svalue); + t.runTest(methodNullClassCast, false, svalue); + t.runTest(methodClassCastObj, false, svalue); + t.runTest(methodObjClassCast, true, svalue); + t.runTest(methodClassCastInt, false, svalue); + t.runTest(methodIntClassCast, true, svalue); + t.runTest(methodClassCastint, false, svalue); + t.runTest(methodintClassCast, false, svalue); + t.runTest(methodClassCastPrim, false, svalue); + t.runTest(methodPrimClassCast, true, svalue); + t.runTest(methodVarClassCast, true, objClass); } void testClassCast(String s) { @@ -176,11 +183,10 @@ public class CastNullCheckDroppingsTest { } } - void testVarClassCast(String s) { - Class cl = (s == null) ? null : String.class; + void testVarClassCast(Class cl) { try { ssink = (String)cl.cast(svalue); - if (s == null) { + if (cl == null) { throw new AssertionError("NullPointerException is not thrown"); } } catch (NullPointerException t) { @@ -286,15 +292,19 @@ public class CastNullCheckDroppingsTest { } } - void runTest(Method method, boolean deopt) { + void runTest(Method method, boolean deopt, Object value) { if (method == null) { throw new AssertionError("method was not found"); } // Ensure method is compiled WHITE_BOX.testSetDontInlineMethod(method, true); + Recording recording = new Recording(); + recording.enable(EventNames.Deoptimization); + recording.start(); + for (int i = 0; i < 3000; i++) { try { - method.invoke(this, svalue); + method.invoke(this, value); } catch (Exception e) { throw new Error("Unexpected exception: ", e); } @@ -304,11 +314,23 @@ public class CastNullCheckDroppingsTest { // Passing null should cause a de-optimization // if method is compiled with a null-check. try { - method.invoke(this, snull); + method.invoke(this, onull); } catch (Exception e) { throw new Error("Unexpected exception: ", e); } - checkDeoptimization(method, nm, deopt); + recording.stop(); + List events; + try { + events = Events.fromRecording(recording); + } catch (IOException e) { + throw new Error("failed to read jfr events", e); + } + + checkDeoptimization(events, nm.compile_id, deopt); + + if (!deopt) { + checkNoRecompilation(method, nm); + } } static NMethod getNMethod(Method test) { @@ -327,15 +349,29 @@ public class CastNullCheckDroppingsTest { return nm; } - static void checkDeoptimization(Method method, NMethod nmOrig, boolean deopt) { - // Check deoptimization event (intrinsic Class.cast() works). - if (WHITE_BOX.isMethodCompiled(method) == deopt) { - throw new AssertionError(method + " was" + (deopt ? " not" : "") + " deoptimized"); + static void checkDeoptimization(List events, int compilerId, boolean mustExist) { + boolean exist = events.stream() + .filter(e -> e.getEventType().getName().equals(EventNames.Deoptimization)) + .anyMatch(e -> compilerId == Events.assertField(e, "compileId").getValue()); + + if (exist != mustExist) { + System.err.println("events:"); + System.err.println(events); + throw new AssertionError("compilation must " + (mustExist ? "" : " not ") + " got deoptimized"); } - if (deopt) { - return; + + if (mustExist && events.stream() + .filter(e -> e.getEventType().getName().equals(EventNames.Deoptimization)) + .filter(e -> compilerId == Events.assertField(e, "compileId").getValue()) + .noneMatch(e -> "null_check".equals(Events.assertField(e, "reason").getValue()))) { + System.err.println("events:"); + System.err.println(events); + throw new AssertionError("no deoptimizations due to null_check found"); } - // Ensure no recompilation when no deoptimization is expected. + + } + + static void checkNoRecompilation(Method method, NMethod nmOrig) { NMethod nm = NMethod.get(method, false); // not OSR nmethod if (nm == null) { throw new AssertionError(method + " missing nmethod?"); From b0812b2802e3b46f966d43266fe2f5ec41cd1669 Mon Sep 17 00:00:00 2001 From: Tobias Hartmann Date: Wed, 4 Dec 2019 07:07:21 +0100 Subject: [PATCH 25/81] 8234616: assert(0 <= i && i < _len) failed: illegal index in PhaseMacroExpand::expand_macro_nodes() Make sure the index into the macro node array is decremented on removal. Reviewed-by: vlivanov, kvn --- src/hotspot/share/opto/macro.cpp | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/src/hotspot/share/opto/macro.cpp b/src/hotspot/share/opto/macro.cpp index 11180e47958..ef49737bb27 100644 --- a/src/hotspot/share/opto/macro.cpp +++ b/src/hotspot/share/opto/macro.cpp @@ -2533,7 +2533,7 @@ bool PhaseMacroExpand::expand_macro_nodes() { while (progress) { progress = false; for (int i = C->macro_count(); i > 0; i--) { - Node * n = C->macro_node(i-1); + Node* n = C->macro_node(i-1); bool success = false; debug_only(int old_macro_count = C->macro_count();); if (n->Opcode() == Op_LoopLimit) { @@ -2578,7 +2578,7 @@ bool PhaseMacroExpand::expand_macro_nodes() { C->remove_macro_node(n); success = true; } - assert(success == (C->macro_count() < old_macro_count), "elimination reduces macro count"); + assert(!success || (C->macro_count() == (old_macro_count - 1)), "elimination must have deleted one node from macro list"); progress = progress || success; } } @@ -2586,32 +2586,30 @@ bool PhaseMacroExpand::expand_macro_nodes() { // expand arraycopy "macro" nodes first // For ReduceBulkZeroing, we must first process all arraycopy nodes // before the allocate nodes are expanded. - int macro_idx = C->macro_count() - 1; - while (macro_idx >= 0) { - Node * n = C->macro_node(macro_idx); + for (int i = C->macro_count(); i > 0; i--) { + Node* n = C->macro_node(i-1); assert(n->is_macro(), "only macro nodes expected here"); if (_igvn.type(n) == Type::TOP || (n->in(0) != NULL && n->in(0)->is_top())) { // node is unreachable, so don't try to expand it C->remove_macro_node(n); continue; } - int macro_count = C->macro_count(); + debug_only(int old_macro_count = C->macro_count();); switch (n->class_id()) { case Node::Class_Lock: expand_lock_node(n->as_Lock()); - assert(C->macro_count() < macro_count, "must have deleted a node from macro list"); + assert(C->macro_count() == (old_macro_count - 1), "expansion must have deleted one node from macro list"); break; case Node::Class_Unlock: expand_unlock_node(n->as_Unlock()); - assert(C->macro_count() < macro_count, "must have deleted a node from macro list"); + assert(C->macro_count() == (old_macro_count - 1), "expansion must have deleted one node from macro list"); break; case Node::Class_ArrayCopy: expand_arraycopy_node(n->as_ArrayCopy()); - assert(C->macro_count() < macro_count, "must have deleted a node from macro list"); + assert(C->macro_count() == (old_macro_count - 1), "expansion must have deleted one node from macro list"); break; } if (C->failing()) return true; - macro_idx --; } // All nodes except Allocate nodes are expanded now. There could be From ddb989de3dd5d534cae33e1cb0a7cb78ee7af075 Mon Sep 17 00:00:00 2001 From: Pengfei Li Date: Fri, 29 Nov 2019 03:48:30 +0000 Subject: [PATCH 26/81] 8234791: Fix Client VM build for x86_64 and AArch64 Reviewed-by: adinn, aph, thartmann --- src/hotspot/cpu/aarch64/sharedRuntime_aarch64.cpp | 1 + src/hotspot/share/runtime/arguments.cpp | 2 -- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/src/hotspot/cpu/aarch64/sharedRuntime_aarch64.cpp b/src/hotspot/cpu/aarch64/sharedRuntime_aarch64.cpp index 63dcc21d533..2edf719823c 100644 --- a/src/hotspot/cpu/aarch64/sharedRuntime_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/sharedRuntime_aarch64.cpp @@ -33,6 +33,7 @@ #include "interpreter/interp_masm.hpp" #include "logging/log.hpp" #include "memory/resourceArea.hpp" +#include "nativeInst_aarch64.hpp" #include "oops/compiledICHolder.hpp" #include "oops/klass.inline.hpp" #include "runtime/safepointMechanism.hpp" diff --git a/src/hotspot/share/runtime/arguments.cpp b/src/hotspot/share/runtime/arguments.cpp index c35641ad44b..f1676fbd99a 100644 --- a/src/hotspot/share/runtime/arguments.cpp +++ b/src/hotspot/share/runtime/arguments.cpp @@ -1693,11 +1693,9 @@ void Arguments::set_use_compressed_oops() { size_t max_heap_size = MAX3(MaxHeapSize, InitialHeapSize, MinHeapSize); if (max_heap_size <= max_heap_for_compressed_oops()) { -#if !defined(COMPILER1) || defined(TIERED) if (FLAG_IS_DEFAULT(UseCompressedOops)) { FLAG_SET_ERGO(UseCompressedOops, true); } -#endif } else { if (UseCompressedOops && !FLAG_IS_DEFAULT(UseCompressedOops)) { warning("Max heap size too large for Compressed Oops"); From fb830f6a533acc321d6ef7cf268fd88abba870f2 Mon Sep 17 00:00:00 2001 From: Matthias Baesken Date: Tue, 3 Dec 2019 11:41:20 +0100 Subject: [PATCH 27/81] 8235243: handle VS2017 15.9 and VS2019 in abstract_vm_version Reviewed-by: dholmes, mdoerr --- src/hotspot/share/runtime/abstract_vm_version.cpp | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/hotspot/share/runtime/abstract_vm_version.cpp b/src/hotspot/share/runtime/abstract_vm_version.cpp index 1d616a9cdab..fc9003859f9 100644 --- a/src/hotspot/share/runtime/abstract_vm_version.cpp +++ b/src/hotspot/share/runtime/abstract_vm_version.cpp @@ -227,6 +227,16 @@ const char* Abstract_VM_Version::internal_vm_info_string() { #define HOTSPOT_BUILD_COMPILER "MS VC++ 15.7 (VS2017)" #elif _MSC_VER == 1915 #define HOTSPOT_BUILD_COMPILER "MS VC++ 15.8 (VS2017)" + #elif _MSC_VER == 1916 + #define HOTSPOT_BUILD_COMPILER "MS VC++ 15.9 (VS2017)" + #elif _MSC_VER == 1920 + #define HOTSPOT_BUILD_COMPILER "MS VC++ 16.0 (VS2019)" + #elif _MSC_VER == 1921 + #define HOTSPOT_BUILD_COMPILER "MS VC++ 16.1 (VS2019)" + #elif _MSC_VER == 1922 + #define HOTSPOT_BUILD_COMPILER "MS VC++ 16.2 (VS2019)" + #elif _MSC_VER == 1923 + #define HOTSPOT_BUILD_COMPILER "MS VC++ 16.3 (VS2019) #else #define HOTSPOT_BUILD_COMPILER "unknown MS VC++:" XSTR(_MSC_VER) #endif From f26bdf847692104dbfd0190295f61000de8626a2 Mon Sep 17 00:00:00 2001 From: Jan Lahoda Date: Wed, 4 Dec 2019 09:38:31 +0100 Subject: [PATCH 28/81] 8234899: Compiler reports AssertionError for conditional operator ? : and pattern matching for instanceof Reviewed-by: mcimadamore --- .../sun/tools/javac/api/JavacTaskPool.java | 14 ++ .../classes/com/sun/tools/javac/jvm/Gen.java | 4 + .../ConditionalExpressionResolvePending.java | 219 ++++++++++++++++++ .../tools/javac/patterns/BindingsTest1.java | 3 + 4 files changed, 240 insertions(+) create mode 100644 test/langtools/tools/javac/ConditionalExpressionResolvePending.java diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/api/JavacTaskPool.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/api/JavacTaskPool.java index 643d778eec9..0b61d4f0c4e 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/api/JavacTaskPool.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/api/JavacTaskPool.java @@ -46,6 +46,7 @@ import javax.tools.JavaFileObject; import com.sun.source.tree.ClassTree; import com.sun.source.tree.CompilationUnitTree; +import com.sun.source.tree.Tree; import com.sun.source.util.JavacTask; import com.sun.source.util.TaskEvent; import com.sun.source.util.TaskEvent.Kind; @@ -68,6 +69,7 @@ import com.sun.tools.javac.main.Arguments; import com.sun.tools.javac.main.JavaCompiler; import com.sun.tools.javac.model.JavacElements; import com.sun.tools.javac.tree.JCTree.JCClassDecl; +import com.sun.tools.javac.tree.JCTree.LetExpr; import com.sun.tools.javac.util.Context; import com.sun.tools.javac.util.DefinedBy; import com.sun.tools.javac.util.DefinedBy.Api; @@ -278,6 +280,18 @@ public class JavacTaskPool { * (typically because of cyclic inheritance) the symbol kind of a core class has been touched. */ TreeScanner pollutionScanner = new TreeScanner() { + @Override @DefinedBy(Api.COMPILER_TREE) + public Void scan(Tree tree, Symtab syms) { + if (tree instanceof LetExpr) { + LetExpr le = (LetExpr) tree; + scan(le.defs, syms); + scan(le.expr, syms); + return null; + } else { + return super.scan(tree, syms); + } + } + @Override @DefinedBy(Api.COMPILER_TREE) public Void visitClass(ClassTree node, Symtab syms) { Symbol sym = ((JCClassDecl)node).sym; diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/Gen.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/Gen.java index df7c4528c95..1bc0b248f42 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/Gen.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/Gen.java @@ -727,6 +727,8 @@ public class Gen extends JCTree.Visitor { if (markBranches) result.tree = tree.falsepart; return result; } else if (inner_tree.hasTag(SWITCH_EXPRESSION)) { + code.resolvePending(); + boolean prevInCondSwitchExpression = inCondSwitchExpression; Chain prevSwitchExpressionTrueChain = switchExpressionTrueChain; Chain prevSwitchExpressionFalseChain = switchExpressionFalseChain; @@ -751,6 +753,8 @@ public class Gen extends JCTree.Visitor { switchExpressionFalseChain = prevSwitchExpressionFalseChain; } } else if (inner_tree.hasTag(LETEXPR) && ((LetExpr) inner_tree).needsCond) { + code.resolvePending(); + LetExpr tree = (LetExpr) inner_tree; int limit = code.nextreg; int prevLetExprStart = code.setLetExprStackPos(code.state.stacksize); diff --git a/test/langtools/tools/javac/ConditionalExpressionResolvePending.java b/test/langtools/tools/javac/ConditionalExpressionResolvePending.java new file mode 100644 index 00000000000..2b562738f99 --- /dev/null +++ b/test/langtools/tools/javac/ConditionalExpressionResolvePending.java @@ -0,0 +1,219 @@ +/* + * 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 8234899 + * @summary Verify behavior w.r.t. preview feature API errors and warnings + * @library /tools/lib /tools/javac/lib + * @modules + * java.base/jdk.internal + * jdk.compiler/com.sun.tools.javac.api + * jdk.compiler/com.sun.tools.javac.file + * jdk.compiler/com.sun.tools.javac.main + * jdk.compiler/com.sun.tools.javac.util + * @build toolbox.ToolBox toolbox.JavacTask + * @build combo.ComboTestHelper + * @compile --enable-preview -source ${jdk.version} ConditionalExpressionResolvePending.java + * @run main/othervm --enable-preview ConditionalExpressionResolvePending + */ + +import combo.ComboInstance; +import combo.ComboParameter; +import combo.ComboTask; +import combo.ComboTestHelper; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.Iterator; +import java.util.Objects; +import java.util.function.BiPredicate; +import toolbox.ToolBox; + +import javax.tools.JavaFileObject; + +public class ConditionalExpressionResolvePending extends ComboInstance { + protected ToolBox tb; + + ConditionalExpressionResolvePending() { + super(); + tb = new ToolBox(); + } + + public static void main(String... args) throws Exception { + new ComboTestHelper() + .withDimension("METHOD", (x, method) -> x.method = method, Method.values()) + .withDimension("EXPRESSION", (x, expression) -> x.expression = expression, Expression.values()) + .withDimension("TRUE", (x, True) -> x.True = True, TestOrDummy.values()) + .withDimension("FALSE", (x, False) -> x.False = False, TestOrDummy.values()) + .withDimension("SNIPPET", (x, snippet) -> x.snippet = snippet, Snippet.values()) + .run(ConditionalExpressionResolvePending::new); + } + + private Method method; + private Expression expression; + private TestOrDummy True; + private TestOrDummy False; + private Snippet snippet; + + private static final String MAIN_TEMPLATE = + """ + public class Test { + public static boolean doTest(boolean c, Object input) { + String clazzName = input.getClass().getName(); + int len = clazzName.length(); + #{METHOD} + } + } + """; + + @Override + protected void doWork() throws Throwable { + Path base = Paths.get("."); + + ComboTask task = newCompilationTask() + .withSourceFromTemplate(MAIN_TEMPLATE, pname -> switch (pname) { + case "METHOD" -> method; + case "EXPRESSION" -> expression; + case "TRUE" -> True; + case "FALSE" -> False; + case "SNIPPET" -> snippet; + default -> throw new UnsupportedOperationException(pname); + }) + .withOption("--enable-preview") + .withOption("-source") + .withOption(String.valueOf(Runtime.version().feature())); + + task.generate(result -> { + try { + Iterator filesIt = result.get().iterator(); + JavaFileObject file = filesIt.next(); + if (filesIt.hasNext()) { + throw new IllegalStateException("More than one classfile returned!"); + } + byte[] data = file.openInputStream().readAllBytes(); + ClassLoader inMemoryLoader = new ClassLoader() { + protected Class findClass(String name) throws ClassNotFoundException { + if ("Test".equals(name)) { + return defineClass(name, data, 0, data.length); + } + return super.findClass(name); + } + }; + Class test = Class.forName("Test", false, inMemoryLoader); + java.lang.reflect.Method doTest = test.getDeclaredMethod("doTest", boolean.class, Object.class); + runTest((c, input) -> { + try { + return (boolean) doTest.invoke(null, c, input); + } catch (Exception ex) { + throw new IllegalStateException(ex); + } + }); + } catch (Throwable ex) { + throw new IllegalStateException(ex); + } + }); + } + + private void runTest(BiPredicate test) { + assertEquals(false, test.test(true, "")); + assertEquals(true, test.test(true, 1)); + assertEquals(false, test.test(false, "")); + assertEquals(true, test.test(false, 1)); + } + + private void assertEquals(Object o1, Object o2) { + if (!Objects.equals(o1, o2)) { + throw new AssertionError(); + } + } + + public enum Method implements ComboParameter { + VARIABLE(""" + boolean b = #{EXPRESSION}; + return b; + """), + IF(""" + boolean b; + if (#{EXPRESSION}) b = true; + else b = false; + return b; + """), + RETURN(""" + return #{EXPRESSION}; + """); + private final String body; + + private Method(String body) { + this.body = body; + } + + @Override + public String expand(String optParameter) { + return body; + } + + } + public enum Expression implements ComboParameter { + CONDITIONAL("c ? #{TRUE} : #{FALSE}"), + AND("(c && #{TRUE}) || (!c && #{FALSE})"); + private final String expression; + + private Expression(String expression) { + this.expression = expression; + } + + @Override + public String expand(String optParameter) { + return expression; + } + } + public enum TestOrDummy implements ComboParameter { + TEST("!(#{SNIPPET})"), + DUMMY("input.getClass() == Integer.class"); + private final String code; + private TestOrDummy(String code) { + this.code = code; + } + @Override + public String expand(String optParameter) { + return code; + } + } + public enum Snippet implements ComboParameter { + PATTERN("input instanceof String sX"), + SWITCH_EXPRESSION("switch (len) { case 16 -> {boolean r = true; yield r; } default -> {boolean r = false; yield r; } }"), + SWITCH_EXPRESSION_STRING("switch (clazzName) { case \"java.lang.String\"-> {boolean r = true; yield r; } default -> {boolean r = false; yield r; } }"); + private static int idx; + private final String snippet; + + private Snippet(String snippet) { + this.snippet = snippet; + } + + @Override + public String expand(String optParameter) { + return snippet.replace("sX", "s" + idx++); + } + + } +} diff --git a/test/langtools/tools/javac/patterns/BindingsTest1.java b/test/langtools/tools/javac/patterns/BindingsTest1.java index 8e4e7adce84..d6f864e4ad4 100644 --- a/test/langtools/tools/javac/patterns/BindingsTest1.java +++ b/test/langtools/tools/javac/patterns/BindingsTest1.java @@ -161,6 +161,9 @@ public class BindingsTest1 { String s2 = s; } + boolean result = (o1 instanceof String a1) ? (o1 instanceof String a2) : (!(o1 instanceof String a3)); + boolean result2 = (o1 instanceof String a1) ? (o1 instanceof String a2) : (!(switch (0) { default -> false; })); + System.out.println("BindingsTest1 complete"); } } From 07be23513b057de06363efce38b78dc2334597f2 Mon Sep 17 00:00:00 2001 From: Jan Lahoda Date: Wed, 4 Dec 2019 09:38:32 +0100 Subject: [PATCH 29/81] 8234922: No compilation error reported not reported for a binding variable when loop broken with label Any break outside of a loop should confine the binding variables from the loop's condition to the loop Reviewed-by: mcimadamore --- .../com/sun/tools/javac/comp/Flow.java | 41 ++- .../tools/javac/patterns/BindingsTest1.java | 24 ++ .../tools/javac/patterns/BindingsTest2.java | 54 ++++ .../tools/javac/patterns/BindingsTest2.out | 8 +- .../tools/javac/patterns/BreakAndLoops.java | 233 ++++++++++++++++++ 5 files changed, 353 insertions(+), 7 deletions(-) create mode 100644 test/langtools/tools/javac/patterns/BreakAndLoops.java diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Flow.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Flow.java index 6f8ac782669..3cc7c1a7003 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Flow.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Flow.java @@ -280,8 +280,7 @@ public class Flow { //related errors, which will allow for more errors to be detected Log.DiagnosticHandler diagHandler = new Log.DiscardDiagnosticHandler(log); try { - boolean[] breaksOut = new boolean[1]; - SnippetBreakAnalyzer analyzer = new SnippetBreakAnalyzer(loop); + SnippetBreakAnalyzer analyzer = new SnippetBreakAnalyzer(); analyzer.analyzeTree(env, body, make); return analyzer.breaksOut(); @@ -1515,16 +1514,46 @@ public class Flow { } class SnippetBreakAnalyzer extends AliveAnalyzer { - private final JCTree loop; + private final Set seenTrees = new HashSet<>(); private boolean breaksOut; - public SnippetBreakAnalyzer(JCTree loop) { - this.loop = loop; + public SnippetBreakAnalyzer() { + } + + @Override + public void visitLabelled(JCTree.JCLabeledStatement tree) { + seenTrees.add(tree); + super.visitLabelled(tree); + } + + @Override + public void visitWhileLoop(JCTree.JCWhileLoop tree) { + seenTrees.add(tree); + super.visitWhileLoop(tree); + } + + @Override + public void visitForLoop(JCTree.JCForLoop tree) { + seenTrees.add(tree); + super.visitForLoop(tree); + } + + @Override + public void visitForeachLoop(JCTree.JCEnhancedForLoop tree) { + seenTrees.add(tree); + super.visitForeachLoop(tree); + } + + @Override + public void visitDoLoop(JCTree.JCDoWhileLoop tree) { + seenTrees.add(tree); + super.visitDoLoop(tree); } @Override public void visitBreak(JCBreak tree) { - breaksOut |= (super.alive == Liveness.ALIVE && tree.target == loop); + breaksOut |= (super.alive == Liveness.ALIVE && + !seenTrees.contains(tree.target)); super.visitBreak(tree); } diff --git a/test/langtools/tools/javac/patterns/BindingsTest1.java b/test/langtools/tools/javac/patterns/BindingsTest1.java index d6f864e4ad4..2e12cd95aef 100644 --- a/test/langtools/tools/javac/patterns/BindingsTest1.java +++ b/test/langtools/tools/javac/patterns/BindingsTest1.java @@ -146,6 +146,30 @@ public class BindingsTest1 { s.length(); } + { + while (!(o1 instanceof String s)) { + L8: break L8; + } + + s.length(); + } + + { + for ( ;!(o1 instanceof String s); ) { + L9: break L9; + } + + s.length(); + } + + { + do { + L10: break L10; + } while (!(o1 instanceof String s)); + + s.length(); + } + if (o1 instanceof String s) { Runnable r1 = new Runnable() { @Override diff --git a/test/langtools/tools/javac/patterns/BindingsTest2.java b/test/langtools/tools/javac/patterns/BindingsTest2.java index f6c32e0e09d..be0af3458a9 100644 --- a/test/langtools/tools/javac/patterns/BindingsTest2.java +++ b/test/langtools/tools/javac/patterns/BindingsTest2.java @@ -187,5 +187,59 @@ public class BindingsTest2 { s.length(); } + + { + L: while (!(o1 instanceof String s)) { + break L; + } + + s.length(); + } + + { + L: for (; !(o1 instanceof String s); ) { + break L; + } + + s.length(); + } + + { + L: do { + break L; + } while (!(o1 instanceof String s)); + + s.length(); + } + + { + L: { + while (!(o1 instanceof String s)) { + break L; + } + + s.length(); + } + } + + { + L: { + for (; !(o1 instanceof String s); ) { + break L; + } + + s.length(); + } + } + + { + L: { + do { + break L; + } while (!(o1 instanceof String s)); + + s.length(); + } + } } } diff --git a/test/langtools/tools/javac/patterns/BindingsTest2.out b/test/langtools/tools/javac/patterns/BindingsTest2.out index e60a75fe6e6..c9c179e1f97 100644 --- a/test/langtools/tools/javac/patterns/BindingsTest2.out +++ b/test/langtools/tools/javac/patterns/BindingsTest2.out @@ -40,9 +40,15 @@ BindingsTest2.java:146:13: compiler.err.cant.resolve.location: kindname.variable BindingsTest2.java:154:13: compiler.err.cant.resolve.location: kindname.variable, s, , , (compiler.misc.location: kindname.class, BindingsTest2, null) BindingsTest2.java:171:13: compiler.err.cant.resolve.location: kindname.variable, s, , , (compiler.misc.location: kindname.class, BindingsTest2, null) BindingsTest2.java:179:13: compiler.err.cant.resolve.location: kindname.variable, s, , , (compiler.misc.location: kindname.class, BindingsTest2, null) +BindingsTest2.java:196:13: compiler.err.cant.resolve.location: kindname.variable, s, , , (compiler.misc.location: kindname.class, BindingsTest2, null) +BindingsTest2.java:204:13: compiler.err.cant.resolve.location: kindname.variable, s, , , (compiler.misc.location: kindname.class, BindingsTest2, null) +BindingsTest2.java:212:13: compiler.err.cant.resolve.location: kindname.variable, s, , , (compiler.misc.location: kindname.class, BindingsTest2, null) +BindingsTest2.java:221:17: compiler.err.cant.resolve.location: kindname.variable, s, , , (compiler.misc.location: kindname.class, BindingsTest2, null) +BindingsTest2.java:231:17: compiler.err.cant.resolve.location: kindname.variable, s, , , (compiler.misc.location: kindname.class, BindingsTest2, null) +BindingsTest2.java:241:17: compiler.err.cant.resolve.location: kindname.variable, s, , , (compiler.misc.location: kindname.class, BindingsTest2, null) BindingsTest2.java:135:17: compiler.err.unreachable.stmt BindingsTest2.java:160:17: compiler.err.unreachable.stmt BindingsTest2.java:185:17: compiler.err.unreachable.stmt - compiler.note.preview.filename: BindingsTest2.java - compiler.note.preview.recompile -45 errors \ No newline at end of file +51 errors \ No newline at end of file diff --git a/test/langtools/tools/javac/patterns/BreakAndLoops.java b/test/langtools/tools/javac/patterns/BreakAndLoops.java new file mode 100644 index 00000000000..70782ee1252 --- /dev/null +++ b/test/langtools/tools/javac/patterns/BreakAndLoops.java @@ -0,0 +1,233 @@ +/* + * 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 8234922 + * @summary Verify proper scope of binding related to loops and breaks. + * @library /tools/lib /tools/javac/lib + * @modules + * java.base/jdk.internal + * jdk.compiler/com.sun.tools.javac.api + * jdk.compiler/com.sun.tools.javac.file + * jdk.compiler/com.sun.tools.javac.main + * jdk.compiler/com.sun.tools.javac.util + * @build toolbox.ToolBox toolbox.JavacTask + * @build combo.ComboTestHelper + * @compile --enable-preview -source ${jdk.version} BreakAndLoops.java + * @run main/othervm --enable-preview BreakAndLoops + */ + +import combo.ComboInstance; +import combo.ComboParameter; +import combo.ComboTask; +import combo.ComboTestHelper; +import java.nio.file.Path; +import java.nio.file.Paths; +import toolbox.ToolBox; + +public class BreakAndLoops extends ComboInstance { + protected ToolBox tb; + + BreakAndLoops() { + super(); + tb = new ToolBox(); + } + + public static void main(String... args) throws Exception { + new ComboTestHelper() + .withDimension("OUTTER_LABEL", (x, outterLabel) -> x.outterLabel = outterLabel, OutterLabel.values()) + .withDimension("OUTTER_LOOP", (x, outterLoop) -> x.outterLoop = outterLoop, OutterLoop.values()) + .withDimension("MAIN_LOOP", (x, mainLoop) -> x.mainLoop = mainLoop, MainLoop.values()) + .withDimension("INNER_LABEL", (x, innerLabel) -> x.innerLabel = innerLabel, Label.values()) + .withDimension("INNER_LOOP", (x, innerLoop) -> x.innerLoop = innerLoop, Loop.values()) + .withDimension("BREAK", (x, brk) -> x.brk = brk, Break.values()) + .withFilter(bal -> bal.outterLabel != OutterLabel.LABEL || bal.innerLabel != Label.LABEL) + .run(BreakAndLoops::new); + } + + private OutterLabel outterLabel; + private OutterLoop outterLoop; + private MainLoop mainLoop; + private Label innerLabel; + private Loop innerLoop; + private Break brk; + + private static final String MAIN_TEMPLATE = + """ + public class Test { + public static void doTest(Object o, int i, Object[] arr) { + #{OUTTER_LABEL} + } + } + """; + + @Override + protected void doWork() throws Throwable { + Path base = Paths.get("."); + + ComboTask task = newCompilationTask() + .withSourceFromTemplate(MAIN_TEMPLATE, pname -> switch (pname) { + case "OUTTER_LABEL" -> outterLabel; + case "OUTTER_LOOP" -> outterLoop; + case "MAIN_LOOP" -> mainLoop; + case "NESTED_LOOP" -> innerLoop; + case "NESTED" -> brk; + case "BODY" -> innerLabel; + default -> throw new UnsupportedOperationException(pname); + }) + .withOption("--enable-preview") + .withOption("-source") + .withOption(String.valueOf(Runtime.version().feature())); + + task.generate(result -> { + boolean shouldPass; + if (brk == Break.NONE) { + shouldPass = true; + } else if (innerLabel == Label.LABEL && brk == Break.BREAK_LABEL) { + shouldPass = true; + } else if (innerLoop.supportsAnonymousBreak && brk == Break.BREAK) { + shouldPass = true; + } else { + shouldPass = false; + } + if (!(shouldPass ^ result.hasErrors())) { + throw new AssertionError("Unexpected result: " + result.compilationInfo()); + } + }); + } + + public enum MainLoop implements ComboParameter { + WHILE(""" + while (!(o instanceof String s)) { + #{BODY} + } + """), + FOR(""" + for( ; !(o instanceof String s) ; ) { + #{BODY} + } + """), + DO_WHILE(""" + do { + #{BODY} + } while (!(o instanceof String s)); + """); + private final String body; + + private MainLoop(String body) { + this.body = body; + } + + @Override + public String expand(String optParameter) { + return body; + } + } + + public enum OutterLabel implements ComboParameter { + NONE("#{OUTTER_LOOP}"), + LABEL("LABEL: #{OUTTER_LOOP}"); + private final String code; + + private OutterLabel(String code) { + this.code = code; + } + + @Override + public String expand(String optParameter) { + return code; + } + } + + public enum OutterLoop implements ComboParameter { + NONE("#{MAIN_LOOP} System.err.println(s);"), + BLOCK("{ #{MAIN_LOOP} System.err.println(s); }"), + WHILE("while (i-- > 0) { #{MAIN_LOOP} System.err.println(s); }"), + FOR("for ( ; i-- > 0; ) { #{MAIN_LOOP} System.err.println(s); }"), + FOR_EACH("for (Object outterO : arr) { #{MAIN_LOOP} System.err.println(s); }"), + DO_WHILE("do { #{MAIN_LOOP} System.err.println(s); } while (i-- > 0);"); + private final String code; + + private OutterLoop(String code) { + this.code = code; + } + + @Override + public String expand(String optParameter) { + return code; + } + } + + public enum Label implements ComboParameter { + NONE("#{NESTED_LOOP}"), + LABEL("LABEL: #{NESTED_LOOP}"); + private final String code; + + private Label(String code) { + this.code = code; + } + + @Override + public String expand(String optParameter) { + return code; + } + } + + public enum Loop implements ComboParameter { + NONE("#{NESTED}", false), + BLOCK("{ #{NESTED} }", false), + WHILE("while (i-- > 0) { #{NESTED} }", true), + FOR("for ( ; i-- > 0; ) { #{NESTED} }", true), + FOR_EACH("for (Object innerO : arr) { #{NESTED} }", true), + DO_WHILE("do { #{NESTED} } while (i-- > 0);", true); + private final String code; + private final boolean supportsAnonymousBreak; + + private Loop(String code, boolean supportsAnonymousBreak) { + this.code = code; + this.supportsAnonymousBreak = supportsAnonymousBreak; + } + + @Override + public String expand(String optParameter) { + return code; + } + } + + public enum Break implements ComboParameter { + NONE(";"), + BREAK("break;"), + BREAK_LABEL("break LABEL;"); + private final String code; + + private Break(String code) { + this.code = code; + } + + @Override + public String expand(String optParameter) { + return code; + } + } +} \ No newline at end of file From e230c1ce5df3539b0118eec0dd989627e4b1ea1a Mon Sep 17 00:00:00 2001 From: Matthias Baesken Date: Wed, 4 Dec 2019 09:43:54 +0100 Subject: [PATCH 30/81] 8235325: build failure on Linux after 8235243 Reviewed-by: clanger --- src/hotspot/share/runtime/abstract_vm_version.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/hotspot/share/runtime/abstract_vm_version.cpp b/src/hotspot/share/runtime/abstract_vm_version.cpp index fc9003859f9..6647442b69b 100644 --- a/src/hotspot/share/runtime/abstract_vm_version.cpp +++ b/src/hotspot/share/runtime/abstract_vm_version.cpp @@ -236,7 +236,7 @@ const char* Abstract_VM_Version::internal_vm_info_string() { #elif _MSC_VER == 1922 #define HOTSPOT_BUILD_COMPILER "MS VC++ 16.2 (VS2019)" #elif _MSC_VER == 1923 - #define HOTSPOT_BUILD_COMPILER "MS VC++ 16.3 (VS2019) + #define HOTSPOT_BUILD_COMPILER "MS VC++ 16.3 (VS2019)" #else #define HOTSPOT_BUILD_COMPILER "unknown MS VC++:" XSTR(_MSC_VER) #endif From c0ea1e647e12f1367709182aac5d31a28a302e64 Mon Sep 17 00:00:00 2001 From: Stefan Karlsson Date: Wed, 4 Dec 2019 10:26:32 +0100 Subject: [PATCH 31/81] 8235257: Split 'assert(loader != NULL && oopDesc::is_oop(loader), "loader must be oop")' Reviewed-by: dcubed, hseigel --- src/hotspot/share/classfile/javaClasses.cpp | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/hotspot/share/classfile/javaClasses.cpp b/src/hotspot/share/classfile/javaClasses.cpp index 77a931a0021..fbacc81d9ec 100644 --- a/src/hotspot/share/classfile/javaClasses.cpp +++ b/src/hotspot/share/classfile/javaClasses.cpp @@ -4013,17 +4013,20 @@ int java_lang_ClassLoader::nameAndId_offset = -1; int java_lang_ClassLoader::unnamedModule_offset = -1; ClassLoaderData* java_lang_ClassLoader::loader_data_acquire(oop loader) { - assert(loader != NULL && oopDesc::is_oop(loader), "loader must be oop"); + assert(loader != NULL, "loader must not be NULL"); + assert(oopDesc::is_oop(loader), "loader must be oop"); return HeapAccess::load_at(loader, _loader_data_offset); } ClassLoaderData* java_lang_ClassLoader::loader_data_raw(oop loader) { - assert(loader != NULL && oopDesc::is_oop(loader), "loader must be oop"); + assert(loader != NULL, "loader must not be NULL"); + assert(oopDesc::is_oop(loader), "loader must be oop"); return RawAccess<>::load_at(loader, _loader_data_offset); } void java_lang_ClassLoader::release_set_loader_data(oop loader, ClassLoaderData* new_data) { - assert(loader != NULL && oopDesc::is_oop(loader), "loader must be oop"); + assert(loader != NULL, "loader must not be NULL"); + assert(oopDesc::is_oop(loader), "loader must be oop"); HeapAccess::store_at(loader, _loader_data_offset, new_data); } From b31e91cd8d5430eeca382bcb9cf9b67f77b3d0a8 Mon Sep 17 00:00:00 2001 From: Robbin Ehn Date: Wed, 4 Dec 2019 11:57:58 +0100 Subject: [PATCH 32/81] 8234742: Improve handshake logging Reviewed-by: dholmes, pchilanomate --- src/hotspot/share/runtime/handshake.cpp | 77 ++++++++++++++++++------- src/hotspot/share/runtime/handshake.hpp | 2 +- src/hotspot/share/runtime/thread.hpp | 4 +- 3 files changed, 60 insertions(+), 23 deletions(-) diff --git a/src/hotspot/share/runtime/handshake.cpp b/src/hotspot/share/runtime/handshake.cpp index d2ec54669ff..a85dde450d0 100644 --- a/src/hotspot/share/runtime/handshake.cpp +++ b/src/hotspot/share/runtime/handshake.cpp @@ -32,7 +32,6 @@ #include "runtime/osThread.hpp" #include "runtime/semaphore.inline.hpp" #include "runtime/task.hpp" -#include "runtime/timerTrace.hpp" #include "runtime/thread.hpp" #include "runtime/vmThread.hpp" #include "utilities/formatBuffer.hpp" @@ -52,6 +51,7 @@ public: void do_handshake(JavaThread* thread); bool thread_has_completed() { return _done.trywait(); } bool executed() const { return _executed; } + const char* name() { return _handshake_cl->name(); } #ifdef ASSERT void check_state() { @@ -106,6 +106,18 @@ void VM_Handshake::handle_timeout() { fatal("Handshake operation timed out"); } +static void log_handshake_info(jlong start_time_ns, const char* name, int targets, int vmt_executed, const char* extra = NULL) { + if (start_time_ns != 0) { + jlong completion_time = os::javaTimeNanos() - start_time_ns; + log_info(handshake)("Handshake \"%s\", Targeted threads: %d, Executed by targeted threads: %d, Total completion time: " JLONG_FORMAT " ns%s%s", + name, targets, + targets - vmt_executed, + completion_time, + extra != NULL ? ", " : "", + extra != NULL ? extra : ""); + } +} + class VM_HandshakeOneThread: public VM_Handshake { JavaThread* _target; public: @@ -114,20 +126,25 @@ class VM_HandshakeOneThread: public VM_Handshake { void doit() { DEBUG_ONLY(_op->check_state();) - TraceTime timer("Finished executing single-target operation (VM_HandshakeOneThread::doit)", TRACETIME_LOG(Info, handshake)); + + jlong start_time_ns = 0; + if (log_is_enabled(Info, handshake)) { + start_time_ns = os::javaTimeNanos(); + } ThreadsListHandle tlh; if (tlh.includes(_target)) { set_handshake(_target); } else { - log_trace(handshake)("JavaThread " INTPTR_FORMAT " is not alive", p2i(_target)); + log_handshake_info(start_time_ns, _op->name(), 0, 0, "(thread dead)"); return; } log_trace(handshake)("JavaThread " INTPTR_FORMAT " signaled, begin attempt to process by VMThtread", p2i(_target)); - jlong start_time = os::elapsed_counter(); + jlong timeout_start_time = os::elapsed_counter(); + bool by_vm_thread = false; do { - if (handshake_has_timed_out(start_time)) { + if (handshake_has_timed_out(timeout_start_time)) { handle_timeout(); } @@ -136,10 +153,11 @@ class VM_HandshakeOneThread: public VM_Handshake { // locked during certain phases. { MutexLocker ml(Threads_lock); - _target->handshake_process_by_vmthread(); + by_vm_thread = _target->handshake_try_process_by_vmThread(); } } while (!poll_for_completed_thread()); DEBUG_ONLY(_op->check_state();) + log_handshake_info(start_time_ns, _op->name(), 1, by_vm_thread ? 1 : 0); } VMOp_Type type() const { return VMOp_HandshakeOneThread; } @@ -153,7 +171,12 @@ class VM_HandshakeAllThreads: public VM_Handshake { void doit() { DEBUG_ONLY(_op->check_state();) - TraceTime timer("Finished executing multi-target operation (VM_HandshakeAllThreads::doit)", TRACETIME_LOG(Info, handshake)); + + jlong start_time_ns = 0; + if (log_is_enabled(Info, handshake)) { + start_time_ns = os::javaTimeNanos(); + } + int handshake_executed_by_vm_thread = 0; JavaThreadIteratorWithHandle jtiwh; int number_of_threads_issued = 0; @@ -163,11 +186,11 @@ class VM_HandshakeAllThreads: public VM_Handshake { } if (number_of_threads_issued < 1) { - log_debug(handshake)("No threads to handshake."); + log_handshake_info(start_time_ns, _op->name(), 0, 0); return; } - log_debug(handshake)("Threads signaled, begin processing blocked threads by VMThtread"); + log_trace(handshake)("Threads signaled, begin processing blocked threads by VMThread"); const jlong start_time = os::elapsed_counter(); int number_of_threads_completed = 0; do { @@ -188,7 +211,9 @@ class VM_HandshakeAllThreads: public VM_Handshake { for (JavaThread *thr = jtiwh.next(); thr != NULL; thr = jtiwh.next()) { // A new thread on the ThreadsList will not have an operation, // hence it is skipped in handshake_process_by_vmthread. - thr->handshake_process_by_vmthread(); + if (thr->handshake_try_process_by_vmThread()) { + handshake_executed_by_vm_thread++; + } } } @@ -200,6 +225,8 @@ class VM_HandshakeAllThreads: public VM_Handshake { } while (number_of_threads_issued > number_of_threads_completed); assert(number_of_threads_issued == number_of_threads_completed, "Must be the same"); DEBUG_ONLY(_op->check_state();) + + log_handshake_info(start_time_ns, _op->name(), number_of_threads_issued, handshake_executed_by_vm_thread); } VMOp_Type type() const { return VMOp_HandshakeAllThreads; } @@ -217,7 +244,7 @@ public: _handshake_cl(cl), _target_thread(target), _all_threads(false), _executed(false) {} void doit() { - log_trace(handshake)("VMThread executing VM_HandshakeFallbackOperation"); + log_trace(handshake)("VMThread executing VM_HandshakeFallbackOperation, operation: %s", name()); for (JavaThreadIteratorWithHandle jtiwh; JavaThread *t = jtiwh.next(); ) { if (_all_threads || t == _target_thread) { if (t == _target_thread) { @@ -233,10 +260,10 @@ public: }; void HandshakeThreadsOperation::do_handshake(JavaThread* thread) { - ResourceMark rm; - FormatBufferResource message("Operation for thread " PTR_FORMAT ", is_vm_thread: %s", - p2i(thread), BOOL_TO_STR(Thread::current()->is_VM_thread())); - TraceTime timer(message, TRACETIME_LOG(Debug, handshake, task)); + jlong start_time_ns = 0; + if (log_is_enabled(Debug, handshake, task)) { + start_time_ns = os::javaTimeNanos(); + } // Only actually execute the operation for non terminated threads. if (!thread->is_terminated()) { @@ -246,6 +273,12 @@ void HandshakeThreadsOperation::do_handshake(JavaThread* thread) { // Use the semaphore to inform the VM thread that we have completed the operation _done.signal(); + + if (start_time_ns != 0) { + jlong completion_time = os::javaTimeNanos() - start_time_ns; + log_debug(handshake, task)("Operation: %s for thread " PTR_FORMAT ", is_vm_thread: %s, completed in " JLONG_FORMAT " ns", + name(), p2i(thread), BOOL_TO_STR(Thread::current()->is_VM_thread()), completion_time); + } } void Handshake::execute(HandshakeClosure* thread_cl) { @@ -348,37 +381,41 @@ bool HandshakeState::claim_handshake_for_vmthread() { return false; } -void HandshakeState::process_by_vmthread(JavaThread* target) { +bool HandshakeState::try_process_by_vmThread(JavaThread* target) { assert(Thread::current()->is_VM_thread(), "should call from vm thread"); // Threads_lock must be held here, but that is assert()ed in // possibly_vmthread_can_process_handshake(). if (!has_operation()) { // JT has already cleared its handshake - return; + return false; } if (!possibly_vmthread_can_process_handshake(target)) { // JT is observed in an unsafe state, it must notice the handshake itself - return; + return false; } // Claim the semaphore if there still an operation to be executed. if (!claim_handshake_for_vmthread()) { - return; + return false; } // If we own the semaphore at this point and while owning the semaphore // can observe a safe state the thread cannot possibly continue without // getting caught by the semaphore. + bool executed = false; if (vmthread_can_process_handshake(target)) { guarantee(!_semaphore.trywait(), "we should already own the semaphore"); log_trace(handshake)("Processing handshake by VMThtread"); _operation->do_handshake(target); // Disarm after VM thread have executed the operation. clear_handshake(target); - // Release the thread + executed = true; } + // Release the thread _semaphore.signal(); + + return executed; } diff --git a/src/hotspot/share/runtime/handshake.hpp b/src/hotspot/share/runtime/handshake.hpp index 449164c8ee2..daa53df124b 100644 --- a/src/hotspot/share/runtime/handshake.hpp +++ b/src/hotspot/share/runtime/handshake.hpp @@ -88,7 +88,7 @@ public: } } - void process_by_vmthread(JavaThread* target); + bool try_process_by_vmThread(JavaThread* target); }; #endif // SHARE_RUNTIME_HANDSHAKE_HPP diff --git a/src/hotspot/share/runtime/thread.hpp b/src/hotspot/share/runtime/thread.hpp index 2cde8dce697..18e41e3ecb4 100644 --- a/src/hotspot/share/runtime/thread.hpp +++ b/src/hotspot/share/runtime/thread.hpp @@ -1329,8 +1329,8 @@ class JavaThread: public Thread { _handshake.process_by_self(this); } - void handshake_process_by_vmthread() { - _handshake.process_by_vmthread(this); + bool handshake_try_process_by_vmThread() { + return _handshake.try_process_by_vmThread(this); } // Suspend/resume support for JavaThread From f67111067e843ffc7af4528d552bd4eaf931018f Mon Sep 17 00:00:00 2001 From: Arno Zeller Date: Mon, 2 Dec 2019 17:10:02 +0100 Subject: [PATCH 33/81] 8234696: tools/jlink/plugins/VendorInfoPluginsTest.java times out Reviewed-by: mchung, clanger --- test/jdk/tools/jlink/plugins/VendorInfoPluginsTest.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/test/jdk/tools/jlink/plugins/VendorInfoPluginsTest.java b/test/jdk/tools/jlink/plugins/VendorInfoPluginsTest.java index 686ffdc55d4..8eee849851b 100644 --- a/test/jdk/tools/jlink/plugins/VendorInfoPluginsTest.java +++ b/test/jdk/tools/jlink/plugins/VendorInfoPluginsTest.java @@ -83,6 +83,7 @@ public class VendorInfoPluginsTest { + (System.getProperty("os.name").startsWith("Windows") ? ".exe" : "")).toString(); var oa = ProcessTools.executeProcess(launcher, + "-Xmx64m", "-XshowSettings:properties", "--version"); oa.stderrShouldMatch("^ +java.vendor.url.bug = " + BUG_URL + "$"); @@ -92,6 +93,8 @@ public class VendorInfoPluginsTest { // VM error log oa = ProcessTools.executeProcess(launcher, + "-Xmx64m", + "-XX:-CreateCoredumpOnCrash", "--class-path", System.getProperty("test.classes"), "VendorInfoPluginsTest$Crasher"); From 14391e8046d8cc256502ba63a3db14a68977e7cb Mon Sep 17 00:00:00 2001 From: Matthias Baesken Date: Tue, 3 Dec 2019 15:17:59 +0100 Subject: [PATCH 34/81] 8234397: add OS uptime information to os::print_os_info output Reviewed-by: clanger, dholmes, lucy --- src/hotspot/os/aix/os_aix.cpp | 2 ++ src/hotspot/os/bsd/os_bsd.cpp | 18 ++++++++++++++++++ src/hotspot/os/bsd/os_bsd.hpp | 2 ++ src/hotspot/os/linux/os_linux.cpp | 11 +++++++++++ src/hotspot/os/linux/os_linux.hpp | 1 + src/hotspot/os/posix/os_posix.cpp | 22 ++++++++++++++++++++++ src/hotspot/os/posix/os_posix.hpp | 1 + src/hotspot/os/solaris/os_solaris.cpp | 2 ++ src/hotspot/os/windows/os_windows.cpp | 7 +++++++ src/hotspot/os/windows/os_windows.hpp | 1 + src/hotspot/share/runtime/os.cpp | 8 ++++++++ src/hotspot/share/runtime/os.hpp | 3 +++ 12 files changed, 78 insertions(+) diff --git a/src/hotspot/os/aix/os_aix.cpp b/src/hotspot/os/aix/os_aix.cpp index 928d467657b..47f0ba29901 100644 --- a/src/hotspot/os/aix/os_aix.cpp +++ b/src/hotspot/os/aix/os_aix.cpp @@ -1384,6 +1384,8 @@ void os::print_os_info(outputStream* st) { st->print_cr("AIX kernel version %u.%u.%u.%u", (ver >> 24) & 0xFF, (ver >> 16) & 0xFF, (ver >> 8) & 0xFF, ver & 0xFF); + os::Posix::print_uptime_info(st); + os::Posix::print_rlimit_info(st); os::Posix::print_load_average(st); diff --git a/src/hotspot/os/bsd/os_bsd.cpp b/src/hotspot/os/bsd/os_bsd.cpp index b8774e9b32c..5c6ddf4f117 100644 --- a/src/hotspot/os/bsd/os_bsd.cpp +++ b/src/hotspot/os/bsd/os_bsd.cpp @@ -168,6 +168,22 @@ julong os::Bsd::available_memory() { return available; } +// for more info see : +// https://man.openbsd.org/sysctl.2 +void os::Bsd::print_uptime_info(outputStream* st) { + struct timeval boottime; + size_t len = sizeof(boottime); + int mib[2]; + mib[0] = CTL_KERN; + mib[1] = KERN_BOOTTIME; + + if (sysctl(mib, 2, &boottime, &len, NULL, 0) >= 0) { + time_t bootsec = boottime.tv_sec; + time_t currsec = time(NULL); + os::print_dhm(st, "OS uptime:", (long) difftime(currsec, bootsec)); + } +} + julong os::physical_memory() { return Bsd::physical_memory(); } @@ -1569,6 +1585,8 @@ void os::print_os_info(outputStream* st) { os::Posix::print_uname_info(st); + os::Bsd::print_uptime_info(st); + os::Posix::print_rlimit_info(st); os::Posix::print_load_average(st); diff --git a/src/hotspot/os/bsd/os_bsd.hpp b/src/hotspot/os/bsd/os_bsd.hpp index 590f7423321..c9afcdad10f 100644 --- a/src/hotspot/os/bsd/os_bsd.hpp +++ b/src/hotspot/os/bsd/os_bsd.hpp @@ -155,6 +155,8 @@ class Bsd { } } static int get_node_by_cpu(int cpu_id); + + static void print_uptime_info(outputStream* st); }; #endif // OS_BSD_OS_BSD_HPP diff --git a/src/hotspot/os/linux/os_linux.cpp b/src/hotspot/os/linux/os_linux.cpp index 3ca7497539b..56941bbf1ce 100644 --- a/src/hotspot/os/linux/os_linux.cpp +++ b/src/hotspot/os/linux/os_linux.cpp @@ -2119,6 +2119,8 @@ void os::print_os_info(outputStream* st) { os::Posix::print_uname_info(st); + os::Linux::print_uptime_info(st); + // Print warning if unsafe chroot environment detected if (unsafe_chroot_detected) { st->print("WARNING!! "); @@ -2304,6 +2306,15 @@ void os::Linux::print_ld_preload_file(outputStream* st) { st->cr(); } +void os::Linux::print_uptime_info(outputStream* st) { + struct sysinfo sinfo; + int ret = sysinfo(&sinfo); + if (ret == 0) { + os::print_dhm(st, "OS uptime:", (long) sinfo.uptime); + } +} + + void os::Linux::print_container_info(outputStream* st) { if (!OSContainer::is_containerized()) { return; diff --git a/src/hotspot/os/linux/os_linux.hpp b/src/hotspot/os/linux/os_linux.hpp index 20d3ef331a6..798755d6e8d 100644 --- a/src/hotspot/os/linux/os_linux.hpp +++ b/src/hotspot/os/linux/os_linux.hpp @@ -103,6 +103,7 @@ class Linux { static void print_libversion_info(outputStream* st); static void print_proc_sys_info(outputStream* st); static void print_ld_preload_file(outputStream* st); + static void print_uptime_info(outputStream* st); public: struct CPUPerfTicks { diff --git a/src/hotspot/os/posix/os_posix.cpp b/src/hotspot/os/posix/os_posix.cpp index 4a1f207ef8d..811a9cd2b39 100644 --- a/src/hotspot/os/posix/os_posix.cpp +++ b/src/hotspot/os/posix/os_posix.cpp @@ -49,6 +49,7 @@ #include #include #include +#include // Todo: provide a os::get_max_process_id() or similar. Number of processes // may have been configured, can be read more accurately from proc fs etc. @@ -379,6 +380,27 @@ void os::Posix::print_load_average(outputStream* st) { st->cr(); } +// boot/uptime information; +// unfortunately it does not work on macOS and Linux because the utx chain has no entry +// for reboot at least on my test machines +void os::Posix::print_uptime_info(outputStream* st) { + int bootsec = -1; + int currsec = time(NULL); + struct utmpx* ent; + setutxent(); + while ((ent = getutxent())) { + if (!strcmp("system boot", ent->ut_line)) { + bootsec = ent->ut_tv.tv_sec; + break; + } + } + + if (bootsec != -1) { + os::print_dhm(st, "OS uptime:", (long) (currsec-bootsec)); + } +} + + void os::Posix::print_rlimit_info(outputStream* st) { st->print("rlimit:"); struct rlimit rlim; diff --git a/src/hotspot/os/posix/os_posix.hpp b/src/hotspot/os/posix/os_posix.hpp index 74dcbd1d64e..e036c98d27c 100644 --- a/src/hotspot/os/posix/os_posix.hpp +++ b/src/hotspot/os/posix/os_posix.hpp @@ -41,6 +41,7 @@ protected: static void print_uname_info(outputStream* st); static void print_libversion_info(outputStream* st); static void print_load_average(outputStream* st); + static void print_uptime_info(outputStream* st); // Minimum stack size a thread can be created with (allowing // the VM to completely create the thread and enter user code). diff --git a/src/hotspot/os/solaris/os_solaris.cpp b/src/hotspot/os/solaris/os_solaris.cpp index 512e9cd31ec..cdaf66c2594 100644 --- a/src/hotspot/os/solaris/os_solaris.cpp +++ b/src/hotspot/os/solaris/os_solaris.cpp @@ -1584,6 +1584,8 @@ void os::print_os_info(outputStream* st) { os::Posix::print_uname_info(st); + os::Posix::print_uptime_info(st); + os::Solaris::print_libversion_info(st); os::Posix::print_rlimit_info(st); diff --git a/src/hotspot/os/windows/os_windows.cpp b/src/hotspot/os/windows/os_windows.cpp index 53188344669..b2532500d98 100644 --- a/src/hotspot/os/windows/os_windows.cpp +++ b/src/hotspot/os/windows/os_windows.cpp @@ -1591,6 +1591,11 @@ void os::print_os_info_brief(outputStream* st) { os::print_os_info(st); } +void os::win32::print_uptime_info(outputStream* st) { + unsigned long long ticks = GetTickCount64(); + os::print_dhm(st, "OS uptime:", ticks/1000); +} + void os::print_os_info(outputStream* st) { #ifdef ASSERT char buffer[1024]; @@ -1604,6 +1609,8 @@ void os::print_os_info(outputStream* st) { st->print("OS:"); os::win32::print_windows_version(st); + os::win32::print_uptime_info(st); + #ifdef _LP64 VM_Version::print_platform_virtualization_info(st); #endif diff --git a/src/hotspot/os/windows/os_windows.hpp b/src/hotspot/os/windows/os_windows.hpp index 3d0a9d62328..e09e2ca2b59 100644 --- a/src/hotspot/os/windows/os_windows.hpp +++ b/src/hotspot/os/windows/os_windows.hpp @@ -55,6 +55,7 @@ class win32 { static bool _has_exit_bug; static void print_windows_version(outputStream* st); + static void print_uptime_info(outputStream* st); public: // Windows-specific interface: diff --git a/src/hotspot/share/runtime/os.cpp b/src/hotspot/share/runtime/os.cpp index cfc10978703..6632615edd1 100644 --- a/src/hotspot/share/runtime/os.cpp +++ b/src/hotspot/share/runtime/os.cpp @@ -928,6 +928,14 @@ void os::print_hex_dump(outputStream* st, address start, address end, int unitsi st->cr(); } +void os::print_dhm(outputStream* st, const char* startStr, long sec) { + long days = sec/86400; + long hours = (sec/3600) - (days * 24); + long minutes = (sec/60) - (days * 1440) - (hours * 60); + if (startStr == NULL) startStr = ""; + st->print_cr("%s %ld days %ld:%02ld hours", startStr, days, hours, minutes); +} + void os::print_instructions(outputStream* st, address pc, int unitsize) { st->print_cr("Instructions: (pc=" PTR_FORMAT ")", p2i(pc)); print_hex_dump(st, pc - 256, pc + 256, unitsize); diff --git a/src/hotspot/share/runtime/os.hpp b/src/hotspot/share/runtime/os.hpp index cb0aa864573..b4d8ec0ca33 100644 --- a/src/hotspot/share/runtime/os.hpp +++ b/src/hotspot/share/runtime/os.hpp @@ -632,6 +632,9 @@ class os: AllStatic { static void print_date_and_time(outputStream* st, char* buf, size_t buflen); static void print_instructions(outputStream* st, address pc, int unitsize); + // helper for output of seconds in days , hours and months + static void print_dhm(outputStream* st, const char* startStr, long sec); + static void print_location(outputStream* st, intptr_t x, bool verbose = false); static size_t lasterror(char *buf, size_t len); static int get_last_error(); From 1a4d4ff1d83bc2ae8c8b4d9aedaaa91481f2664a Mon Sep 17 00:00:00 2001 From: Thomas Schatzl Date: Wed, 4 Dec 2019 16:58:35 +0100 Subject: [PATCH 35/81] 8235247: WorkerDataArray leaks C heap memory for associated work items Reviewed-by: lkorinth, kbarrett --- src/hotspot/share/gc/shared/workerDataArray.inline.hpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/hotspot/share/gc/shared/workerDataArray.inline.hpp b/src/hotspot/share/gc/shared/workerDataArray.inline.hpp index eeedd50e557..64f468ba83a 100644 --- a/src/hotspot/share/gc/shared/workerDataArray.inline.hpp +++ b/src/hotspot/share/gc/shared/workerDataArray.inline.hpp @@ -59,6 +59,9 @@ T WorkerDataArray::get(uint worker_i) const { template WorkerDataArray::~WorkerDataArray() { + for (uint i = 0; i < MaxThreadWorkItems; i++) { + delete _thread_work_items[i]; + } FREE_C_HEAP_ARRAY(T, _data); } From 386b387ef2ad8fe43f35e776e8725f7f8baec1b6 Mon Sep 17 00:00:00 2001 From: Coleen Phillimore Date: Wed, 4 Dec 2019 11:09:15 -0500 Subject: [PATCH 36/81] 8234355: Buffer overflow in jcmd GC.class_stats due to too many classes Remove use of GC.class_stats in testing and failure analysis (plan to deprecate) Reviewed-by: dcubed --- test/failure_handler/src/share/conf/common.properties | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/test/failure_handler/src/share/conf/common.properties b/test/failure_handler/src/share/conf/common.properties index 80f4efa3a72..b0bbe9b5303 100644 --- a/test/failure_handler/src/share/conf/common.properties +++ b/test/failure_handler/src/share/conf/common.properties @@ -1,5 +1,5 @@ # -# Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2015, 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 @@ -34,7 +34,7 @@ onTimeout=\ jcmd.vm.classloader_stats jcmd.vm.stringtable \ jcmd.vm.symboltable jcmd.vm.uptime jcmd.vm.dynlibs \ jcmd.vm.system_properties \ - jcmd.gc.heap_info jcmd.gc.class_stats jcmd.gc.class_histogram jcmd.gc.finalizer_info \ + jcmd.gc.heap_info jcmd.gc.class_histogram jcmd.gc.finalizer_info \ jstack jinfo.app=jinfo @@ -52,7 +52,6 @@ jcmd.vm.uptime.args=%p VM.uptime jcmd.vm.dynlibs.args=%p VM.dynlibs jcmd.vm.system_properties.args=%p VM.system_properties -jcmd.gc.class_stats.args=%p GC.class_stats jcmd.gc.class_histogram.args=%p GC.class_histogram jcmd.gc.finalizer_info.args=%p GC.finalizer_info jcmd.gc.heap_info.args=%p GC.heap_info From e7d68cd13b288199a421bf33d307f3ded8ae47d8 Mon Sep 17 00:00:00 2001 From: Alan Bateman Date: Wed, 4 Dec 2019 16:37:00 +0000 Subject: [PATCH 37/81] 8235193: (dc) Remove JNI overhead from DatagramChannel.send implementation Reviewed-by: chegar --- .../share/classes/java/net/Inet4Address.java | 7 + .../share/classes/java/net/Inet6Address.java | 12 +- .../share/classes/java/net/InetAddress.java | 10 +- .../access/JavaNetInetAddressAccess.java | 14 +- .../sun/nio/ch/DatagramChannelImpl.java | 206 ++++++++++------- .../sun/nio/ch/NativeSocketAddress.java | 211 ++++++++++++++---- .../native/libnio/ch/NativeSocketAddress.c | 22 +- .../native/libnio/ch/DatagramChannelImpl.c | 19 +- .../native/libnio/ch/DatagramChannelImpl.c | 20 +- ...enders.java => ManySourcesAndTargets.java} | 76 ++++++- 10 files changed, 438 insertions(+), 159 deletions(-) rename test/jdk/java/nio/channels/DatagramChannel/{ManySenders.java => ManySourcesAndTargets.java} (60%) diff --git a/src/java.base/share/classes/java/net/Inet4Address.java b/src/java.base/share/classes/java/net/Inet4Address.java index 46d7a6e3239..c74458bd7bb 100644 --- a/src/java.base/share/classes/java/net/Inet4Address.java +++ b/src/java.base/share/classes/java/net/Inet4Address.java @@ -310,6 +310,13 @@ class Inet4Address extends InetAddress { return addr; } + /** + * Returns the 32-bit IPv4 address. + */ + int addressValue() { + return holder().getAddress(); + } + /** * Returns the IP address string in textual presentation form. * diff --git a/src/java.base/share/classes/java/net/Inet6Address.java b/src/java.base/share/classes/java/net/Inet6Address.java index 2043343bd87..f00c9a47bdc 100644 --- a/src/java.base/share/classes/java/net/Inet6Address.java +++ b/src/java.base/share/classes/java/net/Inet6Address.java @@ -793,6 +793,7 @@ class Inet6Address extends InetAddress { public boolean isMCOrgLocal() { return holder6.isMCOrgLocal(); } + /** * Returns the raw IP address of this {@code InetAddress} object. The result * is in network byte order: the highest order byte of the address is in @@ -805,6 +806,13 @@ class Inet6Address extends InetAddress { return holder6.ipaddress.clone(); } + /** + * Returns a reference to the byte[] with the IPv6 address. + */ + byte[] addressBytes() { + return holder6.ipaddress; + } + /** * Returns the numeric scopeId, if this instance is associated with * an interface. If no scoped_id is set, the returned value is zero. @@ -814,7 +822,7 @@ class Inet6Address extends InetAddress { * @since 1.5 */ public int getScopeId() { - return holder6.scope_id; + return holder6.scope_id; } /** @@ -825,7 +833,7 @@ class Inet6Address extends InetAddress { * @since 1.5 */ public NetworkInterface getScopedInterface() { - return holder6.scope_ifname; + return holder6.scope_ifname; } /** diff --git a/src/java.base/share/classes/java/net/InetAddress.java b/src/java.base/share/classes/java/net/InetAddress.java index e967032f541..b6b152fd037 100644 --- a/src/java.base/share/classes/java/net/InetAddress.java +++ b/src/java.base/share/classes/java/net/InetAddress.java @@ -326,10 +326,18 @@ public class InetAddress implements java.io.Serializable { public InetAddress getByName(String hostName, InetAddress hostAddress) - throws UnknownHostException + throws UnknownHostException { return InetAddress.getByName(hostName, hostAddress); } + + public int addressValue(Inet4Address inet4Address) { + return inet4Address.addressValue(); + } + + public byte[] addressBytes(Inet6Address inet6Address) { + return inet6Address.addressBytes(); + } } ); init(); diff --git a/src/java.base/share/classes/jdk/internal/access/JavaNetInetAddressAccess.java b/src/java.base/share/classes/jdk/internal/access/JavaNetInetAddressAccess.java index 5c2d6cdeba2..70b6afeaa7c 100644 --- a/src/java.base/share/classes/jdk/internal/access/JavaNetInetAddressAccess.java +++ b/src/java.base/share/classes/jdk/internal/access/JavaNetInetAddressAccess.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 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 @@ -25,6 +25,8 @@ package jdk.internal.access; +import java.net.Inet4Address; +import java.net.Inet6Address; import java.net.InetAddress; import java.net.UnknownHostException; @@ -43,4 +45,14 @@ public interface JavaNetInetAddressAccess { */ InetAddress getByName(String hostName, InetAddress hostAddress) throws UnknownHostException; + + /** + * Returns the 32-bit IPv4 address. + */ + int addressValue(Inet4Address inet4Address); + + /** + * Returns a reference to the byte[] with the IPv6 address. + */ + byte[] addressBytes(Inet6Address inet6Address); } diff --git a/src/java.base/share/classes/sun/nio/ch/DatagramChannelImpl.java b/src/java.base/share/classes/sun/nio/ch/DatagramChannelImpl.java index 85e92c0cc03..31d3c1bbf33 100644 --- a/src/java.base/share/classes/sun/nio/ch/DatagramChannelImpl.java +++ b/src/java.base/share/classes/sun/nio/ch/DatagramChannelImpl.java @@ -91,8 +91,15 @@ class DatagramChannelImpl private final FileDescriptor fd; private final int fdVal; - // Native buffer for socket address used by receive0, protected by readLock - private final NativeSocketAddress socketAddress; + // Native sockaddrs and cached InetSocketAddress for receive, protected by readLock + private NativeSocketAddress sourceSockAddr; + private NativeSocketAddress cachedSockAddr; + private InetSocketAddress cachedInetSocketAddress; + + // Native sockaddr and cached objects for send, protected by writeLock + private final NativeSocketAddress targetSockAddr; + private InetSocketAddress previousTarget; + private int previousSockAddrLength; // Cleaner to close file descriptor and free native socket address private final Cleanable cleaner; @@ -150,59 +157,57 @@ class DatagramChannelImpl // -- End of fields protected by stateLock - public DatagramChannelImpl(SelectorProvider sp) - throws IOException - { - super(sp); - this.socketAddress = new NativeSocketAddress(); - - ResourceManager.beforeUdpCreate(); - try { - this.family = Net.isIPv6Available() - ? StandardProtocolFamily.INET6 - : StandardProtocolFamily.INET; - this.fd = Net.socket(family, false); - this.fdVal = IOUtil.fdVal(fd); - } catch (IOException ioe) { - ResourceManager.afterUdpClose(); - socketAddress.free(); - throw ioe; - } - - Runnable releaser = releaserFor(fd, socketAddress); - this.cleaner = CleanerFactory.cleaner().register(this, releaser); + public DatagramChannelImpl(SelectorProvider sp) throws IOException { + this(sp, (Net.isIPv6Available() + ? StandardProtocolFamily.INET6 + : StandardProtocolFamily.INET)); } public DatagramChannelImpl(SelectorProvider sp, ProtocolFamily family) throws IOException { super(sp); + Objects.requireNonNull(family, "'family' is null"); if ((family != StandardProtocolFamily.INET) && - (family != StandardProtocolFamily.INET6)) { + (family != StandardProtocolFamily.INET6)) { throw new UnsupportedOperationException("Protocol family not supported"); } - if (family == StandardProtocolFamily.INET6) { - if (!Net.isIPv6Available()) { - throw new UnsupportedOperationException("IPv6 not available"); + if (family == StandardProtocolFamily.INET6 && !Net.isIPv6Available()) { + throw new UnsupportedOperationException("IPv6 not available"); + } + + FileDescriptor fd = null; + NativeSocketAddress[] sockAddrs = null; + + ResourceManager.beforeUdpCreate(); + boolean initialized = false; + try { + this.family = family; + this.fd = fd = Net.socket(family, false); + this.fdVal = IOUtil.fdVal(fd); + + sockAddrs = NativeSocketAddress.allocate(3); + readLock.lock(); + try { + this.sourceSockAddr = sockAddrs[0]; + this.cachedSockAddr = sockAddrs[1]; + } finally { + readLock.unlock(); + } + this.targetSockAddr = sockAddrs[2]; + + initialized = true; + } finally { + if (!initialized) { + if (sockAddrs != null) NativeSocketAddress.freeAll(sockAddrs); + if (fd != null) nd.close(fd); + ResourceManager.afterUdpClose(); } } - this.socketAddress = new NativeSocketAddress(); - - ResourceManager.beforeUdpCreate(); - try { - this.family = family; - this.fd = Net.socket(family, false); - this.fdVal = IOUtil.fdVal(fd); - } catch (IOException ioe) { - ResourceManager.afterUdpClose(); - socketAddress.free(); - throw ioe; - } - - Runnable releaser = releaserFor(fd, socketAddress); + Runnable releaser = releaserFor(fd, sockAddrs); this.cleaner = CleanerFactory.cleaner().register(this, releaser); } @@ -211,23 +216,37 @@ class DatagramChannelImpl { super(sp); + NativeSocketAddress[] sockAddrs = null; + + ResourceManager.beforeUdpCreate(); + boolean initialized = false; try { - this.socketAddress = new NativeSocketAddress(); - } catch (OutOfMemoryError e) { - nd.close(fd); - throw e; + this.family = Net.isIPv6Available() + ? StandardProtocolFamily.INET6 + : StandardProtocolFamily.INET; + this.fd = fd; + this.fdVal = IOUtil.fdVal(fd); + + sockAddrs = NativeSocketAddress.allocate(3); + readLock.lock(); + try { + this.sourceSockAddr = sockAddrs[0]; + this.cachedSockAddr = sockAddrs[1]; + } finally { + readLock.unlock(); + } + this.targetSockAddr = sockAddrs[2]; + + initialized = true; + } finally { + if (!initialized) { + if (sockAddrs != null) NativeSocketAddress.freeAll(sockAddrs); + nd.close(fd); + ResourceManager.afterUdpClose(); + } } - // increment UDP count to match decrement when closing - ResourceManager.beforeUdpCreate(); - - this.family = Net.isIPv6Available() - ? StandardProtocolFamily.INET6 - : StandardProtocolFamily.INET; - this.fd = fd; - this.fdVal = IOUtil.fdVal(fd); - - Runnable releaser = releaserFor(fd, socketAddress); + Runnable releaser = releaserFor(fd, sockAddrs); this.cleaner = CleanerFactory.cleaner().register(this, releaser); synchronized (stateLock) { @@ -494,7 +513,7 @@ class DatagramChannelImpl } if (n >= 0) { // sender address is in socket address buffer - sender = socketAddress.toInetSocketAddress(); + sender = sourceSocketAddress(); } } else { // security manager and unconnected @@ -534,7 +553,7 @@ class DatagramChannelImpl } if (n >= 0) { // sender address is in socket address buffer - InetSocketAddress isa = socketAddress.toInetSocketAddress(); + InetSocketAddress isa = sourceSocketAddress(); try { sm.checkAccept(isa.getAddress().getHostAddress(), isa.getPort()); bb.flip(); @@ -613,7 +632,7 @@ class DatagramChannelImpl } if (n >= 0) { // sender address is in socket address buffer - sender = socketAddress.toInetSocketAddress(); + sender = sourceSocketAddress(); } return sender; } finally { @@ -650,7 +669,7 @@ class DatagramChannelImpl } if (n >= 0) { // sender address is in socket address buffer - sender = socketAddress.toInetSocketAddress(); + sender = sourceSocketAddress(); } return sender; } finally { @@ -692,13 +711,32 @@ class DatagramChannelImpl { int n = receive0(fd, ((DirectBuffer)bb).address() + pos, rem, - socketAddress.address(), + sourceSockAddr.address(), connected); if (n > 0) bb.position(pos + n); return n; } + /** + * Return an InetSocketAddress to represent the source/sender socket address + * in sourceSockAddr. Returns the cached InetSocketAddress if the source + * address is the same as the cached address. + */ + private InetSocketAddress sourceSocketAddress() throws IOException { + assert readLock.isHeldByCurrentThread(); + if (cachedInetSocketAddress != null && sourceSockAddr.equals(cachedSockAddr)) { + return cachedInetSocketAddress; + } + InetSocketAddress isa = sourceSockAddr.decode(); + // swap sourceSockAddr and cachedSockAddr + NativeSocketAddress tmp = cachedSockAddr; + cachedSockAddr = sourceSockAddr; + sourceSockAddr = tmp; + cachedInetSocketAddress = isa; + return isa; + } + @Override public int send(ByteBuffer src, SocketAddress target) throws IOException @@ -709,7 +747,8 @@ class DatagramChannelImpl writeLock.lock(); try { boolean blocking = isBlocking(); - int n = 0; + int n; + boolean completed = false; try { SocketAddress remote = beginWrite(blocking, false); if (remote != null) { @@ -724,6 +763,7 @@ class DatagramChannelImpl n = IOUtil.write(fd, src, -1, nd); } } + completed = (n > 0); } else { // not connected SecurityManager sm = System.getSecurityManager(); @@ -744,11 +784,12 @@ class DatagramChannelImpl n = send(fd, src, isa); } } + completed = (n >= 0); } } finally { - endWrite(blocking, n > 0); - assert IOStatus.check(n); + endWrite(blocking, completed); } + assert n >= 0 || n == IOStatus.UNAVAILABLE; return IOStatus.normalize(n); } finally { writeLock.unlock(); @@ -813,11 +854,11 @@ class DatagramChannelImpl assert (pos <= lim); int rem = (pos <= lim ? lim - pos : 0); - boolean preferIPv6 = (family != StandardProtocolFamily.INET); int written; try { - written = send0(preferIPv6, fd, ((DirectBuffer)bb).address() + pos, - rem, target.getAddress(), target.getPort()); + int addressLen = targetSocketAddress(target); + written = send0(fd, ((DirectBuffer)bb).address() + pos, rem, + targetSockAddr.address(), addressLen); } catch (PortUnreachableException pue) { if (isConnected()) throw pue; @@ -828,6 +869,23 @@ class DatagramChannelImpl return written; } + /** + * Encodes the given InetSocketAddress into targetSockAddr, returning the + * length of the sockaddr structure (sizeof struct sockaddr or sockaddr6). + */ + private int targetSocketAddress(InetSocketAddress isa) { + assert writeLock.isHeldByCurrentThread(); + // Nothing to do if target address is already in the buffer. Use + // identity rather than equals as Inet6Address.equals ignores scope_id. + if (isa == previousTarget) + return previousSockAddrLength; + previousTarget = null; + int len = targetSockAddr.encode(family, isa); + previousTarget = isa; + previousSockAddrLength = len; + return len; + } + @Override public int read(ByteBuffer buf) throws IOException { Objects.requireNonNull(buf); @@ -1488,8 +1546,7 @@ class DatagramChannelImpl } /** - * Block datagrams from given source if a memory to receive all - * datagrams. + * Block datagrams from the given source. */ void block(MembershipKeyImpl key, InetAddress source) throws IOException @@ -1527,7 +1584,7 @@ class DatagramChannelImpl } /** - * Unblock given source. + * Unblock the given source. */ void unblock(MembershipKeyImpl key, InetAddress source) { assert key.channel() == this; @@ -1731,10 +1788,9 @@ class DatagramChannelImpl } /** - * Returns an action to release a the given file descriptor and free the - * given native socket address. + * Returns an action to release the given file descriptor and socket addresses. */ - private static Runnable releaserFor(FileDescriptor fd, NativeSocketAddress sa) { + private static Runnable releaserFor(FileDescriptor fd, NativeSocketAddress... sockAddrs) { return () -> { try { nd.close(fd); @@ -1743,7 +1799,7 @@ class DatagramChannelImpl } finally { // decrement socket count and release memory ResourceManager.afterUdpClose(); - sa.free(); + NativeSocketAddress.freeAll(sockAddrs); } }; } @@ -1757,8 +1813,8 @@ class DatagramChannelImpl long senderAddress, boolean connected) throws IOException; - private static native int send0(boolean preferIPv6, FileDescriptor fd, - long address, int len, InetAddress addr, int port) + private static native int send0(FileDescriptor fd, long address, int len, + long targetAddress, int targetAddressLen) throws IOException; static { diff --git a/src/java.base/share/classes/sun/nio/ch/NativeSocketAddress.java b/src/java.base/share/classes/sun/nio/ch/NativeSocketAddress.java index 862001add23..c1f813ec524 100644 --- a/src/java.base/share/classes/sun/nio/ch/NativeSocketAddress.java +++ b/src/java.base/share/classes/sun/nio/ch/NativeSocketAddress.java @@ -25,12 +25,18 @@ package sun.nio.ch; +import java.net.Inet4Address; import java.net.Inet6Address; import java.net.InetAddress; import java.net.InetSocketAddress; +import java.net.ProtocolFamily; import java.net.SocketException; +import java.net.StandardProtocolFamily; import java.net.UnknownHostException; +import java.nio.channels.UnsupportedAddressTypeException; +import jdk.internal.access.JavaNetInetAddressAccess; +import jdk.internal.access.SharedSecrets; import jdk.internal.misc.Unsafe; import jdk.internal.util.ArraysSupport; @@ -41,13 +47,16 @@ import jdk.internal.util.ArraysSupport; * This class is not thread safe. */ class NativeSocketAddress { + private static final JavaNetInetAddressAccess JNINA = SharedSecrets.getJavaNetInetAddressAccess(); private static final Unsafe UNSAFE = Unsafe.getUnsafe(); private static final long ARRAY_BASE_OFFSET = UNSAFE.arrayBaseOffset(byte[].class); private static final int AF_INET = AFINET(); private static final int AF_INET6 = AFINET6(); - private static final int SIZEOF_SOCKETADDRESS = sizeofSOCKETADDRESS(); + private static final int SIZEOF_SOCKADDR4 = sizeofSockAddr4(); + private static final int SIZEOF_SOCKADDR6 = sizeofSockAddr6(); + private static final int SIZEOF_SOCKETADDRESS = Math.max(SIZEOF_SOCKADDR4, SIZEOF_SOCKADDR6); private static final int SIZEOF_FAMILY = sizeofFamily(); private static final int OFFSET_FAMILY = offsetFamily(); private static final int OFFSET_SIN4_PORT = offsetSin4Port(); @@ -55,77 +64,127 @@ class NativeSocketAddress { private static final int OFFSET_SIN6_PORT = offsetSin6Port(); private static final int OFFSET_SIN6_ADDR = offsetSin6Addr(); private static final int OFFSET_SIN6_SCOPE_ID = offsetSin6ScopeId(); + private static final int OFFSET_SIN6_FLOWINFO = offsetSin6FlowInfo(); // SOCKETADDRESS private final long address; - // cached copy of SOCKETADDRESS and the corresponding InetSocketAddress - private final long cachedSocketAddress; - private InetSocketAddress cachedInetSocketAddress; - - NativeSocketAddress() { - // allocate 2 * SOCKETADDRESS - int size = SIZEOF_SOCKETADDRESS << 1; - long base = UNSAFE.allocateMemory(size); - UNSAFE.setMemory(base, size, (byte) 0); - - this.address = base; - this.cachedSocketAddress = base + SIZEOF_SOCKETADDRESS; - } - long address() { return address; } - void free() { - UNSAFE.freeMemory(address); + NativeSocketAddress() { + long base = UNSAFE.allocateMemory(SIZEOF_SOCKETADDRESS); + UNSAFE.setMemory(base, SIZEOF_SOCKETADDRESS, (byte) 0); + this.address = base; + } + + /** + * Allocate an array of native socket addresses. + */ + static NativeSocketAddress[] allocate(int count) { + NativeSocketAddress[] array = new NativeSocketAddress[count]; + for (int i = 0; i < count; i++) { + try { + array[i] = new NativeSocketAddress(); + } catch (OutOfMemoryError e) { + freeAll(array); + throw e; + } + } + return array; + } + + /** + * Free all non-null native socket addresses in the given array. + */ + static void freeAll(NativeSocketAddress[] array) { + for (int i = 0; i < array.length; i++) { + NativeSocketAddress sa = array[i]; + if (sa != null) { + UNSAFE.freeMemory(sa.address); + } + } + } + + /** + * Encodes the given InetSocketAddress into this socket address. + * @param protocolFamily protocol family + * @param isa the InetSocketAddress to encode + * @return the size of the socket address (sizeof sockaddr or sockaddr6) + * @throws UnsupportedAddressTypeException if the address type is not supported + */ + int encode(ProtocolFamily protocolFamily, InetSocketAddress isa) { + if (protocolFamily == StandardProtocolFamily.INET) { + // struct sockaddr + InetAddress ia = isa.getAddress(); + if (!(ia instanceof Inet4Address)) + throw new UnsupportedAddressTypeException(); + putFamily(AF_INET); + putAddress(AF_INET, ia); + putPort(AF_INET, isa.getPort()); + return SIZEOF_SOCKADDR4; + } else { + // struct sockaddr6 + putFamily(AF_INET6); + putAddress(AF_INET6, isa.getAddress()); + putPort(AF_INET6, isa.getPort()); + UNSAFE.putInt(address + OFFSET_SIN6_FLOWINFO, 0); + return SIZEOF_SOCKADDR6; + } } /** * Return an InetSocketAddress to represent the socket address in this buffer. * @throws SocketException if the socket address is not AF_INET or AF_INET6 */ - InetSocketAddress toInetSocketAddress() throws SocketException { - // return cached InetSocketAddress if the SOCKETADDRESS bytes match - if (cachedInetSocketAddress != null && mismatch() < 0) { - return cachedInetSocketAddress; - } - - // decode SOCKETADDRESS to InetSocketAddress + InetSocketAddress decode() throws SocketException { int family = family(); if (family != AF_INET && family != AF_INET6) throw new SocketException("Socket family not recognized"); - var isa = new InetSocketAddress(address(family), port(family)); - - // copy SOCKETADDRESS and InetSocketAddress - UNSAFE.copyMemory(null, address, null, cachedSocketAddress, SIZEOF_SOCKETADDRESS); - this.cachedInetSocketAddress = isa; - return isa; + return new InetSocketAddress(address(family), port(family)); } /** - * Find a mismatch between the SOCKETADDRESS structures stored at address - * and cachedSocketAddress. + * Find a mismatch between this and another socket address * @return the byte offset of the first mismatch or -1 if no mismatch */ - private int mismatch() { + private int mismatch(NativeSocketAddress other) { int i = ArraysSupport.vectorizedMismatch(null, - address, + this.address, null, - cachedSocketAddress, + other.address, SIZEOF_SOCKETADDRESS, ArraysSupport.LOG2_ARRAY_BYTE_INDEX_SCALE); if (i >= 0) return i; i = SIZEOF_SOCKETADDRESS - ~i; for (; i < SIZEOF_SOCKETADDRESS; i++) { - if (UNSAFE.getByte(address + i) != UNSAFE.getByte(cachedSocketAddress + i)) { + if (UNSAFE.getByte(this.address + i) != UNSAFE.getByte(other.address + i)) { return i; } } return -1; } + @Override + public boolean equals(Object other) { + if (other instanceof NativeSocketAddress) { + return mismatch((NativeSocketAddress) other) < 0; + } else { + return false; + } + } + + @Override + public int hashCode() { + int h = 0; + for (int offset = 0; offset < SIZEOF_SOCKETADDRESS; offset++) { + h = 31 * h + UNSAFE.getByte(address + offset); + } + return h; + } + @Override public String toString() { int family = family(); @@ -151,7 +210,20 @@ class NativeSocketAddress { } /** - * Return the value of the sin4_port or sin6_port field. These fields are + * Stores the given family in the sa_family field. + */ + private void putFamily(int family) { + if (SIZEOF_FAMILY == 1) { + UNSAFE.putByte(address + OFFSET_FAMILY, (byte) family); + } else if (SIZEOF_FAMILY == 2) { + UNSAFE.putShort(address + OFFSET_FAMILY, (short) family); + } else { + throw new InternalError(); + } + } + + /** + * Return the value of the sin_port or sin6_port field. These fields are * stored in network order. */ private int port(int family) { @@ -166,9 +238,26 @@ class NativeSocketAddress { return (Byte.toUnsignedInt(b1) << 8) + Byte.toUnsignedInt(b2); } + /** + * Stores the given port number in the sin_port or sin6_port field. The + * port is stored in network order. + */ + private void putPort(int family, int port) { + byte b1 = (byte) ((port >> 8) & 0xff); + byte b2 = (byte) ((port >> 0) & 0xff); + if (family == AF_INET) { + UNSAFE.putByte(address + OFFSET_SIN4_PORT, b1); + UNSAFE.putByte(address + OFFSET_SIN4_PORT + 1, b2); + } else { + UNSAFE.putByte(address + OFFSET_SIN6_PORT, b1); + UNSAFE.putByte(address + OFFSET_SIN6_PORT + 1, b2); + } + } + /** * Return an InetAddress to represent the value of the address in the - * sin4_addr or sin6_addr fields. + * sin4_addr or sin6_addr fields. For IPv6 addresses, the Inet6Address is + * created with the sin6_scope_id in the sockaddr_in6 structure. */ private InetAddress address(int family) { int len; @@ -196,9 +285,52 @@ class NativeSocketAddress { } } + /** + * Stores the given InetAddress in the sin_addr or sin6_addr/sin6_scope_id + * fields. For IPv6 addresses, the sin6_addr will be popluated with an + * IPv4-mapped IPv6 address when the given InetAddress is an IPv4 address. + */ + private void putAddress(int family, InetAddress ia) { + if (family == AF_INET) { + // IPv4 address + putAddress(address + OFFSET_SIN4_ADDR, (Inet4Address) ia); + } else { + int scope_id; + if (ia instanceof Inet4Address) { + // IPv4-mapped IPv6 address + UNSAFE.setMemory(address + OFFSET_SIN6_ADDR, 10, (byte) 0); + UNSAFE.putByte(address + OFFSET_SIN6_ADDR + 10, (byte) 0xff); + UNSAFE.putByte(address + OFFSET_SIN6_ADDR + 11, (byte) 0xff); + putAddress(address + OFFSET_SIN6_ADDR + 12, (Inet4Address) ia); + scope_id = 0; + } else { + // IPv6 address + var inet6Address = (Inet6Address) ia; + putAddress(address + OFFSET_SIN6_ADDR, inet6Address); + scope_id = inet6Address.getScopeId(); + } + UNSAFE.putInt(address + OFFSET_SIN6_SCOPE_ID, scope_id); + } + } + + private static void putAddress(long address, Inet4Address ia) { + int ipAddress = JNINA.addressValue(ia); + // network order + UNSAFE.putByte(address + 0, (byte) ((ipAddress >>> 24) & 0xFF)); + UNSAFE.putByte(address + 1, (byte) ((ipAddress >>> 16) & 0xFF)); + UNSAFE.putByte(address + 2, (byte) ((ipAddress >>> 8) & 0xFF)); + UNSAFE.putByte(address + 3, (byte) (ipAddress & 0xFF)); + } + + private static void putAddress(long address, Inet6Address ia) { + byte[] bytes = JNINA.addressBytes(ia); + UNSAFE.copyMemory(bytes, ARRAY_BASE_OFFSET, null, address, 16); + } + private static native int AFINET(); private static native int AFINET6(); - private static native int sizeofSOCKETADDRESS(); + private static native int sizeofSockAddr4(); + private static native int sizeofSockAddr6(); private static native int sizeofFamily(); private static native int offsetFamily(); private static native int offsetSin4Port(); @@ -206,6 +338,7 @@ class NativeSocketAddress { private static native int offsetSin6Port(); private static native int offsetSin6Addr(); private static native int offsetSin6ScopeId(); + private static native int offsetSin6FlowInfo(); static { IOUtil.load(); diff --git a/src/java.base/share/native/libnio/ch/NativeSocketAddress.c b/src/java.base/share/native/libnio/ch/NativeSocketAddress.c index 12bc0b1d33b..7c1c79d79e1 100644 --- a/src/java.base/share/native/libnio/ch/NativeSocketAddress.c +++ b/src/java.base/share/native/libnio/ch/NativeSocketAddress.c @@ -40,11 +40,17 @@ return AF_INET6; } - JNIEXPORT jint JNICALL - Java_sun_nio_ch_NativeSocketAddress_sizeofSOCKETADDRESS(JNIEnv* env, jclass clazz) - { - return sizeof(SOCKETADDRESS); - } +JNIEXPORT jint JNICALL +Java_sun_nio_ch_NativeSocketAddress_sizeofSockAddr4(JNIEnv* env, jclass clazz) +{ + return sizeof(struct sockaddr_in); +} + +JNIEXPORT jint JNICALL +Java_sun_nio_ch_NativeSocketAddress_sizeofSockAddr6(JNIEnv* env, jclass clazz) +{ + return sizeof(struct sockaddr_in6); +} JNIEXPORT jint JNICALL Java_sun_nio_ch_NativeSocketAddress_sizeofFamily(JNIEnv* env, jclass clazz) @@ -88,3 +94,9 @@ Java_sun_nio_ch_NativeSocketAddress_sizeofFamily(JNIEnv* env, jclass clazz) { return offsetof(struct sockaddr_in6, sin6_scope_id); } + + JNIEXPORT jint JNICALL + Java_sun_nio_ch_NativeSocketAddress_offsetSin6FlowInfo(JNIEnv* env, jclass clazz) + { + return offsetof(struct sockaddr_in6, sin6_flowinfo); + } diff --git a/src/java.base/unix/native/libnio/ch/DatagramChannelImpl.c b/src/java.base/unix/native/libnio/ch/DatagramChannelImpl.c index 86458564383..71cf2fc7d70 100644 --- a/src/java.base/unix/native/libnio/ch/DatagramChannelImpl.c +++ b/src/java.base/unix/native/libnio/ch/DatagramChannelImpl.c @@ -129,25 +129,20 @@ Java_sun_nio_ch_DatagramChannelImpl_receive0(JNIEnv *env, jclass clazz, JNIEXPORT jint JNICALL Java_sun_nio_ch_DatagramChannelImpl_send0(JNIEnv *env, jclass clazz, - jboolean preferIPv6, jobject fdo, jlong address, - jint len, jobject destAddress, jint destPort) + jobject fdo, jlong bufAddress, jint len, + jlong targetAddress, jint targetAddressLen) { jint fd = fdval(env, fdo); - void *buf = (void *)jlong_to_ptr(address); - SOCKETADDRESS sa; - int sa_len = 0; - jint n = 0; + void *buf = (void *)jlong_to_ptr(bufAddress); + SOCKETADDRESS *sa = (SOCKETADDRESS *)jlong_to_ptr(targetAddress); + socklen_t sa_len = (socklen_t) targetAddressLen; + jint n; if (len > MAX_PACKET_LEN) { len = MAX_PACKET_LEN; } - if (NET_InetAddressToSockaddr(env, destAddress, destPort, &sa, - &sa_len, preferIPv6) != 0) { - return IOS_THROWN; - } - - n = sendto(fd, buf, len, 0, &sa.sa, sa_len); + n = sendto(fd, buf, len, 0, (struct sockaddr *)sa, sa_len); if (n < 0) { if (errno == EAGAIN || errno == EWOULDBLOCK) { return IOS_UNAVAILABLE; diff --git a/src/java.base/windows/native/libnio/ch/DatagramChannelImpl.c b/src/java.base/windows/native/libnio/ch/DatagramChannelImpl.c index 3d97e586981..25c0370f66e 100644 --- a/src/java.base/windows/native/libnio/ch/DatagramChannelImpl.c +++ b/src/java.base/windows/native/libnio/ch/DatagramChannelImpl.c @@ -145,22 +145,16 @@ Java_sun_nio_ch_DatagramChannelImpl_receive0(JNIEnv *env, jclass clazz, JNIEXPORT jint JNICALL Java_sun_nio_ch_DatagramChannelImpl_send0(JNIEnv *env, jclass clazz, - jboolean preferIPv6, jobject fdo, - jlong address, jint len, - jobject destAddress, jint destPort) + jobject fdo, jlong bufAddress, jint len, + jlong targetAddress, jint targetAddressLen) { jint fd = fdval(env, fdo); - void *buf = (void *)jlong_to_ptr(address); - SOCKETADDRESS sa; - int sa_len = 0; - jint rv = 0; + void *buf = (void *)jlong_to_ptr(bufAddress); + SOCKETADDRESS *sa = (SOCKETADDRESS *)jlong_to_ptr(targetAddress); + int sa_len = targetAddressLen; + jint rv; - if (NET_InetAddressToSockaddr(env, destAddress, destPort, &sa, - &sa_len, preferIPv6) != 0) { - return IOS_THROWN; - } - - rv = sendto((SOCKET)fd, buf, len, 0, &sa.sa, sa_len); + rv = sendto((SOCKET)fd, buf, len, 0,(struct sockaddr *)sa, sa_len); if (rv == SOCKET_ERROR) { int theErr = (jint)WSAGetLastError(); if (theErr == WSAEWOULDBLOCK) { diff --git a/test/jdk/java/nio/channels/DatagramChannel/ManySenders.java b/test/jdk/java/nio/channels/DatagramChannel/ManySourcesAndTargets.java similarity index 60% rename from test/jdk/java/nio/channels/DatagramChannel/ManySenders.java rename to test/jdk/java/nio/channels/DatagramChannel/ManySourcesAndTargets.java index 04d9eb46f93..5caefd07383 100644 --- a/test/jdk/java/nio/channels/DatagramChannel/ManySenders.java +++ b/test/jdk/java/nio/channels/DatagramChannel/ManySourcesAndTargets.java @@ -22,10 +22,11 @@ */ /* @test - * @bug 8234805 - * @summary Test that DatagramChannel.receive returns the expected sender address - * @run main ManySenders - * @run main/othervm -Djava.net.preferIPv4Stack=true ManySenders + * @bug 8234805 8235193 + * @summary Test DatagramChannel send/receive and that receive returns the expected + * sender address + * @run main ManySourcesAndTargets + * @run main/othervm -Djava.net.preferIPv4Stack=true ManySourcesAndTargets */ import java.io.ByteArrayInputStream; @@ -36,38 +37,59 @@ import java.net.InetAddress; import java.net.InetSocketAddress; import java.net.NetworkInterface; import java.net.SocketAddress; +import java.net.SocketException; import java.nio.ByteBuffer; import java.nio.channels.DatagramChannel; import java.util.List; +import java.util.Optional; import java.util.stream.Collectors; import java.util.stream.Stream; -public class ManySenders { +public class ManySourcesAndTargets { public static void main(String[] args) throws Exception { // use addresses on interfaces that have the loopback and local host InetAddress lh = InetAddress.getLocalHost(); InetAddress lb = InetAddress.getLoopbackAddress(); - List addresses = Stream.concat( - NetworkInterface.getByInetAddress(lh).inetAddresses(), - NetworkInterface.getByInetAddress(lb).inetAddresses()) + List addresses = Stream.of(lh, lb) + .map(ManySourcesAndTargets::networkInterface) + .flatMap(Optional::stream) + .flatMap(NetworkInterface::inetAddresses) .filter(ia -> !ia.isAnyLocalAddress()) .distinct() .collect(Collectors.toList()); - // bind DatagramChannel to wildcard address so it can receive from any address + // Test DatagramChannel.send try (DatagramChannel reader = DatagramChannel.open()) { + // bind reader to wildcard address so it can receive from any address reader.bind(new InetSocketAddress(0)); for (InetAddress address : addresses) { System.out.format("%n-- %s --%n", address.getHostAddress()); // send 3 datagrams from the given address to the reader - test(3, address, reader); + testSend(3, address, reader); + } + } + + // Test DatagramChannel.receive + try (DatagramChannel sender = DatagramChannel.open()) { + // bind sender to wildcard address so it can send to any address + sender.bind(new InetSocketAddress(0)); + for (InetAddress address : addresses) { + System.out.format("%n-- %s --%n", address.getHostAddress()); + + // send 3 datagrams to a datagram bound to the given address + testReceive(3, sender, address); } } } - static void test(int count, InetAddress address, DatagramChannel reader) throws Exception { + /** + * Creates a sender DatagramChannel bound to the given address and uses it to + * sends datagrams to the given reader. The reader receives the datagrams and + * checks the source/sender address. + */ + static void testSend(int count, InetAddress address, DatagramChannel reader) throws Exception { int remotePort = reader.socket().getLocalPort(); InetSocketAddress remote = new InetSocketAddress(address, remotePort); @@ -103,6 +125,30 @@ public class ManySenders { } } + /** + * Creates a reader DatagramChannel bound to the given address uses the given + * sender to send datagrams to that reader. The reader receives the datagrams. + */ + static void testReceive(int count, DatagramChannel sender, InetAddress address) throws Exception { + SocketAddress local = sender.getLocalAddress(); + + try (DatagramChannel reader = DatagramChannel.open()) { + // bind to the given address + reader.bind(new InetSocketAddress(address, 0)); + + SocketAddress remote = reader.getLocalAddress(); + + for (int i = 0; i < count; i++) { + System.out.format("send %s -> %s%n", local, remote); + reader.send(ByteBuffer.allocate(32), remote); + + ByteBuffer bb = ByteBuffer.allocate(1000); + SocketAddress source = reader.receive(bb); + System.out.format("received datagram from %s%n", source); + } + } + } + private static byte[] serialize(SocketAddress address) throws Exception { ByteArrayOutputStream baos = new ByteArrayOutputStream(); ObjectOutputStream oos = new ObjectOutputStream(baos); @@ -116,4 +162,12 @@ public class ManySenders { ObjectInputStream ois = new ObjectInputStream(bais); return (SocketAddress) ois.readObject(); } + + private static Optional networkInterface(InetAddress ia) { + try { + return Optional.ofNullable(NetworkInterface.getByInetAddress(ia)); + } catch (SocketException e) { + return Optional.empty(); + } + } } \ No newline at end of file From 72f42efcd958a7c699d183228e73cb2d7399dfb2 Mon Sep 17 00:00:00 2001 From: Thomas Schatzl Date: Wed, 4 Dec 2019 18:54:29 +0100 Subject: [PATCH 38/81] 8235347: [Backout] 8235247: WorkerDataArray leaks C heap memory for associated work items Backout of earlier change due to unexpected crashes. Reviewed-by: sjohanss --- src/hotspot/share/gc/shared/workerDataArray.inline.hpp | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/hotspot/share/gc/shared/workerDataArray.inline.hpp b/src/hotspot/share/gc/shared/workerDataArray.inline.hpp index 64f468ba83a..eeedd50e557 100644 --- a/src/hotspot/share/gc/shared/workerDataArray.inline.hpp +++ b/src/hotspot/share/gc/shared/workerDataArray.inline.hpp @@ -59,9 +59,6 @@ T WorkerDataArray::get(uint worker_i) const { template WorkerDataArray::~WorkerDataArray() { - for (uint i = 0; i < MaxThreadWorkItems; i++) { - delete _thread_work_items[i]; - } FREE_C_HEAP_ARRAY(T, _data); } From a445b66e58a30577dee29cacb636d4c14f0574a2 Mon Sep 17 00:00:00 2001 From: Mandy Chung Date: Wed, 4 Dec 2019 10:46:49 -0800 Subject: [PATCH 39/81] 8233527: Update Lookup::hasPrivateAccess and Lookup::defineClass spec w.r.t. full power lookup Add a new Lookup::hasFullPrivilegeAccess method and document the capabilities requiring full privileges Reviewed-by: alanb, plevart --- .../lang/invoke/BootstrapMethodInvoker.java | 2 +- .../java/lang/invoke/LambdaMetafactory.java | 10 +- .../java/lang/invoke/MethodHandles.java | 153 +++++++++++------- .../java/lang/invoke/StringConcatFactory.java | 8 +- .../test/p/PrivateLookupInTests.java | 7 +- 5 files changed, 112 insertions(+), 68 deletions(-) diff --git a/src/java.base/share/classes/java/lang/invoke/BootstrapMethodInvoker.java b/src/java.base/share/classes/java/lang/invoke/BootstrapMethodInvoker.java index 515abb9bf9f..bd14bb81b05 100644 --- a/src/java.base/share/classes/java/lang/invoke/BootstrapMethodInvoker.java +++ b/src/java.base/share/classes/java/lang/invoke/BootstrapMethodInvoker.java @@ -364,7 +364,7 @@ final class BootstrapMethodInvoker { VM_BSCI(MethodHandle bsm, String name, T type, Lookup lookup, int[] indexInfo) { super(bsm, name, type, indexInfo[0]); - if (!lookup.hasPrivateAccess()) //D.I.D. + if (!lookup.hasFullPrivilegeAccess()) //D.I.D. throw new AssertionError("bad Lookup object"); this.caller = lookup.lookupClass(); this.indexInfo = indexInfo; diff --git a/src/java.base/share/classes/java/lang/invoke/LambdaMetafactory.java b/src/java.base/share/classes/java/lang/invoke/LambdaMetafactory.java index 7e4b57ae7e4..f27d66aed2c 100644 --- a/src/java.base/share/classes/java/lang/invoke/LambdaMetafactory.java +++ b/src/java.base/share/classes/java/lang/invoke/LambdaMetafactory.java @@ -276,9 +276,8 @@ public final class LambdaMetafactory { * * @param caller Represents a lookup context with the accessibility * privileges of the caller. Specifically, the lookup context - * must have - * private access - * privileges. + * must have {@linkplain MethodHandles.Lookup#hasFullPrivilegeAccess() + * full privilege access}. * When used with {@code invokedynamic}, this is stacked * automatically by the VM. * @param invokedName The name of the method to implement. When used with @@ -422,9 +421,8 @@ public final class LambdaMetafactory { * * @param caller Represents a lookup context with the accessibility * privileges of the caller. Specifically, the lookup context - * must have - * private access - * privileges. + * must have {@linkplain MethodHandles.Lookup#hasFullPrivilegeAccess() + * full privilege access}. * When used with {@code invokedynamic}, this is stacked * automatically by the VM. * @param invokedName The name of the method to implement. When used with diff --git a/src/java.base/share/classes/java/lang/invoke/MethodHandles.java b/src/java.base/share/classes/java/lang/invoke/MethodHandles.java index 70843c9b15a..45631cfecd9 100644 --- a/src/java.base/share/classes/java/lang/invoke/MethodHandles.java +++ b/src/java.base/share/classes/java/lang/invoke/MethodHandles.java @@ -92,7 +92,7 @@ public class MethodHandles { /** * Returns a {@link Lookup lookup object} with * full capabilities to emulate all supported bytecode behaviors of the caller. - * These capabilities include private access to the caller. + * These capabilities include {@linkplain Lookup#hasFullPrivilegeAccess() full privilege access} to the caller. * Factory methods on the lookup object can create * direct method handles * for any member that the caller has access to via bytecodes, @@ -102,7 +102,8 @@ public class MethodHandles { *

* This method is caller sensitive, which means that it may return different * values to different callers. - * @return a lookup object for the caller of this method, with private access + * @return a lookup object for the caller of this method, with + * {@linkplain Lookup#hasFullPrivilegeAccess() full privilege access} */ @CallerSensitive @ForceInline // to ensure Reflection.getCallerClass optimization @@ -157,7 +158,7 @@ public class MethodHandles { /** * Returns a {@link Lookup lookup} object on a target class to emulate all supported - * bytecode behaviors, including private access. + * bytecode behaviors, including private access. * The returned lookup object can provide access to classes in modules and packages, * and members of those classes, outside the normal rules of Java access control, * instead conforming to the more permissive rules for modular deep reflection. @@ -169,14 +170,18 @@ public class MethodHandles { *

  • If there is a security manager, its {@code checkPermission} method is * called to check {@code ReflectPermission("suppressAccessChecks")} and * that must return normally. - *
  • The caller lookup object must have the {@link Lookup#MODULE MODULE} lookup mode. - * (This is because otherwise there would be no way to ensure the original lookup - * creator was a member of any particular module, and so any subsequent checks - * for readability and qualified exports would become ineffective.) - *
  • The caller lookup object must have {@link Lookup#PRIVATE PRIVATE} access. - * (This is because an application intending to share intra-module access - * using {@link Lookup#MODULE MODULE} alone will inadvertently also share - * deep reflection to its own module.) + *
  • The caller lookup object must have {@linkplain Lookup#hasFullPrivilegeAccess() + * full privilege access}. Specifically: + *
      + *
    • The caller lookup object must have the {@link Lookup#MODULE MODULE} lookup mode. + * (This is because otherwise there would be no way to ensure the original lookup + * creator was a member of any particular module, and so any subsequent checks + * for readability and qualified exports would become ineffective.) + *
    • The caller lookup object must have {@link Lookup#PRIVATE PRIVATE} access. + * (This is because an application intending to share intra-module access + * using {@link Lookup#MODULE MODULE} alone will inadvertently also share + * deep reflection to its own module.) + *
    *
  • The target class must be a proper class, not a primitive or array class. * (Thus, {@code M2} is well-defined.) *
  • If the caller module {@code M1} differs from @@ -192,13 +197,14 @@ public class MethodHandles { * exception. *

    * Otherwise, if {@code M1} and {@code M2} are the same module, this method - * returns a {@code Lookup} on {@code targetClass} with full capabilities and + * returns a {@code Lookup} on {@code targetClass} with + * {@linkplain Lookup#hasFullPrivilegeAccess() full privilege access} and * {@code null} previous lookup class. *

    * Otherwise, {@code M1} and {@code M2} are two different modules. This method * returns a {@code Lookup} on {@code targetClass} that records * the lookup class of the caller as the new previous lookup class and - * drops {@code MODULE} access from the full capabilities mode. + * drops {@code MODULE} access from the full privilege access. * * @param targetClass the target class * @param caller the caller lookup object @@ -220,10 +226,8 @@ public class MethodHandles { if (targetClass.isArray()) throw new IllegalArgumentException(targetClass + " is an array class"); // Ensure that we can reason accurately about private and module access. - if ((caller.lookupModes() & Lookup.PRIVATE) == 0) - throw new IllegalAccessException("caller does not have PRIVATE lookup mode"); - if ((caller.lookupModes() & Lookup.MODULE) == 0) - throw new IllegalAccessException("caller does not have MODULE lookup mode"); + if (!caller.hasFullPrivilegeAccess()) + throw new IllegalAccessException("caller does not have PRIVATE and MODULE lookup mode"); // previous lookup class is never set if it has MODULE access assert caller.previousLookupClass() == null; @@ -551,7 +555,7 @@ public class MethodHandles { * *

    * - * Discussion of private access: + * Discussion of private and module access: * We say that a lookup has private access * if its {@linkplain #lookupModes lookup modes} * include the possibility of accessing {@code private} members @@ -560,8 +564,6 @@ public class MethodHandles { * only lookups with private access possess the following capabilities: *

      *
    • access private fields, methods, and constructors of the lookup class and its nestmates - *
    • create method handles which invoke caller sensitive methods, - * such as {@code Class.forName} *
    • create method handles which {@link Lookup#findSpecial emulate invokespecial} instructions *
    • avoid package access checks * for classes accessible to the lookup class @@ -569,6 +571,18 @@ public class MethodHandles { * within the same package member *
    *

    + * Similarly, a lookup with module access ensures that the original lookup creator was + * a member in the same module as the lookup class. + *

    + * Private and module access are independently determined modes; a lookup may have + * either or both or neither. A lookup which possesses both access modes is said to + * possess {@linkplain #hasFullPrivilegeAccess() full privilege access}. Such a lookup has + * the following additional capability: + *

      + *
    • create method handles which invoke caller sensitive methods, + * such as {@code Class.forName} + *
    + *

    * Each of these permissions is a consequence of the fact that a lookup object * with private access can be securely traced back to an originating class, * whose bytecode behaviors and Java language access permissions @@ -643,7 +657,7 @@ public class MethodHandles { *

    * {@link MethodHandles#privateLookupIn(Class, Lookup) MethodHandles.privateLookupIn(T.class, lookup)} * can be used to teleport a {@code lookup} from class {@code C} to class {@code T} - * and create a new {@code Lookup} with private access + * and create a new {@code Lookup} with private access * if the lookup class is allowed to do deep reflection on {@code T}. * The {@code lookup} must have {@link #MODULE} and {@link #PRIVATE} access * to call {@code privateLookupIn}. @@ -1109,7 +1123,7 @@ public class MethodHandles { * the {@code refc} and {@code defc} values are the class itself.) * The value {@code lookc} is defined as not present * if the current lookup object does not have - * private access. + * {@linkplain #hasFullPrivilegeAccess() full privilege access}. * The calls are made according to the following rules: *