From 2f7d34f205a6729610eafe035ee30565e1007adb Mon Sep 17 00:00:00 2001 From: Vladimir Kozlov Date: Mon, 2 Nov 2020 16:04:46 +0000 Subject: [PATCH 01/32] 8255616: Disable AOT and Graal in Oracle OpenJDK Reviewed-by: iignatyev, vlivanov, iveresov, ihse --- make/conf/jib-profiles.js | 19 +++++-------------- .../jvmci/compilerToVM/IsCompilableTest.java | 18 ++++++++++++++++++ .../InvocationTests/invocationGraalTests.java | 1 + test/jdk/com/sun/jdi/EATests.java | 2 +- 4 files changed, 25 insertions(+), 15 deletions(-) diff --git a/make/conf/jib-profiles.js b/make/conf/jib-profiles.js index 9085240295a02..36460fee4b487 100644 --- a/make/conf/jib-profiles.js +++ b/make/conf/jib-profiles.js @@ -251,6 +251,8 @@ var getJibProfilesCommon = function (input, data) { configure_args: concat("--enable-jtreg-failure-handler", "--with-exclude-translations=de,es,fr,it,ko,pt_BR,sv,ca,tr,cs,sk,ja_JP_A,ja_JP_HA,ja_JP_HI,ja_JP_I,zh_TW,zh_HK", "--disable-manpages", + "--disable-jvm-feature-aot", + "--disable-jvm-feature-graal", "--disable-jvm-feature-shenandoahgc", versionArgs(input, common)) }; @@ -404,7 +406,7 @@ var getJibProfilesProfiles = function (input, common, data) { "linux-x64": { target_os: "linux", target_cpu: "x64", - dependencies: ["devkit", "gtest", "graphviz", "pandoc", "graalunit_lib"], + dependencies: ["devkit", "gtest", "graphviz", "pandoc"], configure_args: concat(common.configure_args_64bit, "--with-zlib=system", "--disable-dtrace", (isWsl(input) ? [ "--host=x86_64-unknown-linux-gnu", @@ -423,7 +425,7 @@ var getJibProfilesProfiles = function (input, common, data) { "macosx-x64": { target_os: "macosx", target_cpu: "x64", - dependencies: ["devkit", "gtest", "pandoc", "graalunit_lib"], + dependencies: ["devkit", "gtest", "pandoc"], configure_args: concat(common.configure_args_64bit, "--with-zlib=system", "--with-macosx-version-max=10.9.0", // Use system SetFile instead of the one in the devkit as the @@ -434,7 +436,7 @@ var getJibProfilesProfiles = function (input, common, data) { "windows-x64": { target_os: "windows", target_cpu: "x64", - dependencies: ["devkit", "gtest", "pandoc", "graalunit_lib"], + dependencies: ["devkit", "gtest", "pandoc"], configure_args: concat(common.configure_args_64bit), }, @@ -454,8 +456,6 @@ var getJibProfilesProfiles = function (input, common, data) { configure_args: [ "--openjdk-target=aarch64-linux-gnu", "--disable-jvm-feature-jvmci", - "--disable-jvm-feature-graal", - "--disable-jvm-feature-aot", ], }, @@ -1152,15 +1152,6 @@ var getJibProfilesDependencies = function (input, common) { configure_args: "", }, - graalunit_lib: { - organization: common.organization, - ext: "zip", - revision: "619_Apr_12_2018", - module: "graalunit-lib", - configure_args: "--with-graalunit-lib=" + input.get("graalunit_lib", "install_path"), - environment_name: "GRAALUNIT_LIB" - }, - gtest: { organization: common.organization, ext: "tar.gz", diff --git a/test/hotspot/jtreg/compiler/jvmci/compilerToVM/IsCompilableTest.java b/test/hotspot/jtreg/compiler/jvmci/compilerToVM/IsCompilableTest.java index 7b6727515e2f7..e9d38bddde054 100644 --- a/test/hotspot/jtreg/compiler/jvmci/compilerToVM/IsCompilableTest.java +++ b/test/hotspot/jtreg/compiler/jvmci/compilerToVM/IsCompilableTest.java @@ -27,6 +27,7 @@ * @requires vm.jvmci & vm.compMode == "Xmixed" * @library /test/lib / * @library ../common/patches + * @modules jdk.internal.vm.compiler * @modules java.base/jdk.internal.misc * @modules java.base/jdk.internal.org.objectweb.asm * java.base/jdk.internal.org.objectweb.asm.tree @@ -41,6 +42,23 @@ * -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI * -XX:+UnlockExperimentalVMOptions -XX:+EnableJVMCI -XX:+UseJVMCICompiler * compiler.jvmci.compilerToVM.IsCompilableTest + */ + +/** + * @test + * @requires vm.jvmci & vm.compMode == "Xmixed" + * @library /test/lib / + * @library ../common/patches + * @modules java.base/jdk.internal.misc + * @modules java.base/jdk.internal.org.objectweb.asm + * java.base/jdk.internal.org.objectweb.asm.tree + * jdk.internal.vm.ci/jdk.vm.ci.hotspot + * jdk.internal.vm.ci/jdk.vm.ci.code + * jdk.internal.vm.ci/jdk.vm.ci.meta + * jdk.internal.vm.ci/jdk.vm.ci.runtime + * + * @build jdk.internal.vm.ci/jdk.vm.ci.hotspot.CompilerToVMHelper sun.hotspot.WhiteBox + * @run driver ClassFileInstaller sun.hotspot.WhiteBox * @run main/othervm -Xbootclasspath/a:. * -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI * -XX:+UnlockExperimentalVMOptions -XX:+EnableJVMCI -XX:-UseJVMCICompiler diff --git a/test/hotspot/jtreg/runtime/InvocationTests/invocationGraalTests.java b/test/hotspot/jtreg/runtime/InvocationTests/invocationGraalTests.java index 9c60973c67ac0..402b7c669a0d2 100644 --- a/test/hotspot/jtreg/runtime/InvocationTests/invocationGraalTests.java +++ b/test/hotspot/jtreg/runtime/InvocationTests/invocationGraalTests.java @@ -30,6 +30,7 @@ * @library /test/lib * @modules java.base/jdk.internal.org.objectweb.asm * java.base/jdk.internal.misc + * @modules jdk.internal.vm.compiler * @compile shared/AbstractGenerator.java shared/AccessCheck.java shared/AccessType.java * shared/Caller.java shared/ExecutorGenerator.java shared/Utils.java * shared/ByteArrayClassLoader.java shared/Checker.java shared/GenericClassGenerator.java diff --git a/test/jdk/com/sun/jdi/EATests.java b/test/jdk/com/sun/jdi/EATests.java index 8b0af830b62f6..2abba8113bc9c 100644 --- a/test/jdk/com/sun/jdi/EATests.java +++ b/test/jdk/com/sun/jdi/EATests.java @@ -114,7 +114,7 @@ * * @author Richard Reingruber richard DOT reingruber AT sap DOT com * - * @requires ((vm.compMode == "Xmixed") & vm.jvmci) + * @requires ((vm.compMode == "Xmixed") & vm.graal.enabled) * * @library /test/lib /test/hotspot/jtreg * From 6dac8d2780537e885340cb44ae3c4cec8b6991bb Mon Sep 17 00:00:00 2001 From: Naoto Sato Date: Mon, 2 Nov 2020 16:48:16 +0000 Subject: [PATCH 02/32] 8255671: Bidi.reorderVisually has misleading exception messages Reviewed-by: joehw --- .../jdk/internal/icu/text/BidiBase.java | 6 ++-- test/jdk/java/text/Bidi/BidiConformance.java | 32 +++++++++++++++++++ 2 files changed, 35 insertions(+), 3 deletions(-) diff --git a/src/java.base/share/classes/jdk/internal/icu/text/BidiBase.java b/src/java.base/share/classes/jdk/internal/icu/text/BidiBase.java index 40f53990964e9..33dd332d18c7c 100644 --- a/src/java.base/share/classes/jdk/internal/icu/text/BidiBase.java +++ b/src/java.base/share/classes/jdk/internal/icu/text/BidiBase.java @@ -4590,13 +4590,13 @@ public static void reorderVisually(byte[] levels, } if (0 > objectStart || objects.length <= objectStart) { throw new IllegalArgumentException("Value objectStart " + - levelStart + " is out of range 0 to " + + objectStart + " is out of range 0 to " + (objects.length-1)); } if (0 > count || objects.length < (objectStart+count)) { throw new IllegalArgumentException("Value count " + - levelStart + " is out of range 0 to " + - (objects.length - objectStart)); + count + " is less than zero, or objectStart + count" + + " is beyond objects length " + objects.length); } byte[] reorderLevels = new byte[count]; diff --git a/test/jdk/java/text/Bidi/BidiConformance.java b/test/jdk/java/text/Bidi/BidiConformance.java index 8c35936196980..7fc7e61cd2e07 100644 --- a/test/jdk/java/text/Bidi/BidiConformance.java +++ b/test/jdk/java/text/Bidi/BidiConformance.java @@ -1246,6 +1246,11 @@ private void testMethod_reorderVisually2() { "when levelStart is -1."); } catch (IllegalArgumentException e) { + if (!e.getMessage().equals( + "Value levelStart -1 is out of range 0 to " + (llen - 1))) { + errorHandling("reorderVisually() should throw an IAE" + + " mentioning levelStart is beyond the levels range. Message: " + e.getMessage()); + } } catch (ArrayIndexOutOfBoundsException e) { errorHandling("reorderVisually() should not throw an AIOoBE " + @@ -1258,6 +1263,11 @@ private void testMethod_reorderVisually2() { "when levelStart is 6(levels.length)."); } catch (IllegalArgumentException e) { + if (!e.getMessage().equals( + "Value levelStart " + llen + " is out of range 0 to " + (llen - 1))) { + errorHandling("reorderVisually() should throw an IAE" + + " mentioning levelStart is beyond the levels range. Message: " + e.getMessage()); + } } catch (ArrayIndexOutOfBoundsException e) { errorHandling("reorderVisually() should not throw an AIOoBE " + @@ -1278,6 +1288,11 @@ private void testMethod_reorderVisually2() { " when objectStart is -1."); } catch (IllegalArgumentException e) { + if (!e.getMessage().equals( + "Value objectStart -1 is out of range 0 to " + (olen - 1))) { + errorHandling("reorderVisually() should throw an IAE" + + " mentioning objectStart is beyond the objects range. Message: " + e.getMessage()); + } } catch (ArrayIndexOutOfBoundsException e) { errorHandling("reorderVisually() should not throw an AIOoBE " + @@ -1290,6 +1305,11 @@ private void testMethod_reorderVisually2() { "when objectStart is 6(objects.length)."); } catch (IllegalArgumentException e) { + if (!e.getMessage().equals( + "Value objectStart 6 is out of range 0 to " + (olen - 1))) { + errorHandling("reorderVisually() should throw an IAE" + + " mentioning objectStart is beyond the objects range. Message: " + e.getMessage()); + } } try { @@ -1298,6 +1318,12 @@ private void testMethod_reorderVisually2() { "when count is -1."); } catch (IllegalArgumentException e) { + if (!e.getMessage().equals( + "Value count -1 is less than zero, or objectStart + count " + + "is beyond objects length " + olen)) { + errorHandling("reorderVisually() should throw an IAE" + + " mentioning objectStart/count is beyond the objects range. Message: " + e.getMessage()); + } } catch (NegativeArraySizeException e) { errorHandling("reorderVisually() should not throw an NASE " + @@ -1310,6 +1336,12 @@ private void testMethod_reorderVisually2() { "when count is 7(objects.length+1)."); } catch (IllegalArgumentException e) { + if (!e.getMessage().equals( + "Value count " + (count + 1) + " is less than zero, or objectStart + count " + + "is beyond objects length " + olen)) { + errorHandling("reorderVisually() should throw an IAE" + + " mentioning objectStart/count is beyond the objects range. Message: " + e.getMessage()); + } } catch (ArrayIndexOutOfBoundsException e) { errorHandling("reorderVisually() should not throw an AIOoBE " + From 3e89f729af911a4a4c451fca34144dee5a5602bb Mon Sep 17 00:00:00 2001 From: Per Liden Date: Mon, 2 Nov 2020 17:00:34 +0000 Subject: [PATCH 03/32] 8255237: ZGC: Bulk free garbage pages during relocation set selection Co-authored-by: Albert Mingkun Yang Co-authored-by: Per Liden Reviewed-by: ayang, eosterlund --- src/hotspot/share/gc/z/zHeap.cpp | 29 ++++++++- src/hotspot/share/gc/z/zHeap.hpp | 5 ++ src/hotspot/share/gc/z/zPageAllocator.cpp | 14 ++++ src/hotspot/share/gc/z/zPageAllocator.hpp | 2 + .../share/gc/z/zRelocationSetSelector.cpp | 52 +-------------- .../share/gc/z/zRelocationSetSelector.hpp | 5 ++ .../gc/z/zRelocationSetSelector.inline.hpp | 65 +++++++++++++++++++ 7 files changed, 120 insertions(+), 52 deletions(-) diff --git a/src/hotspot/share/gc/z/zHeap.cpp b/src/hotspot/share/gc/z/zHeap.cpp index f328894cee377..867789819479a 100644 --- a/src/hotspot/share/gc/z/zHeap.cpp +++ b/src/hotspot/share/gc/z/zHeap.cpp @@ -24,6 +24,7 @@ #include "precompiled.hpp" #include "gc/shared/locationPrinter.hpp" #include "gc/z/zAddress.inline.hpp" +#include "gc/z/zArray.inline.hpp" #include "gc/z/zGlobals.hpp" #include "gc/z/zHeap.inline.hpp" #include "gc/z/zHeapIterator.hpp" @@ -220,6 +221,17 @@ void ZHeap::free_page(ZPage* page, bool reclaimed) { _page_allocator.free_page(page, reclaimed); } +void ZHeap::free_pages(const ZArray* pages, bool reclaimed) { + // Remove page table entries + ZArrayIterator iter(pages); + for (ZPage* page; iter.next(&page);) { + _page_table.remove(page); + } + + // Free pages + _page_allocator.free_pages(pages, reclaimed); +} + void ZHeap::flip_to_marked() { ZVerifyViewsFlip flip(&_page_allocator); ZAddress::flip_to_marked(); @@ -349,6 +361,16 @@ void ZHeap::process_non_strong_references() { _reference_processor.enqueue_references(); } +void ZHeap::free_garbage_pages(ZRelocationSetSelector* selector, int bulk) { + // Freeing garbage pages in bulk is an optimization to avoid grabbing + // the page allocator lock, and trying to satisfy stalled allocations + // too frequently. + if (selector->should_free_garbage_pages(bulk)) { + free_pages(selector->garbage_pages(), true /* reclaimed */); + selector->clear_garbage_pages(); + } +} + void ZHeap::select_relocation_set() { // Do not allow pages to be deleted _page_allocator.enable_deferred_delete(); @@ -369,11 +391,14 @@ void ZHeap::select_relocation_set() { // Register garbage page selector.register_garbage_page(page); - // Reclaim page immediately - free_page(page, true /* reclaimed */); + // Reclaim garbage pages in bulk + free_garbage_pages(&selector, 64 /* bulk */); } } + // Reclaim remaining garbage pages + free_garbage_pages(&selector, 0 /* bulk */); + // Allow pages to be deleted _page_allocator.disable_deferred_delete(); diff --git a/src/hotspot/share/gc/z/zHeap.hpp b/src/hotspot/share/gc/z/zHeap.hpp index 338002a89c6ff..47bebc745f368 100644 --- a/src/hotspot/share/gc/z/zHeap.hpp +++ b/src/hotspot/share/gc/z/zHeap.hpp @@ -25,6 +25,7 @@ #define SHARE_GC_Z_ZHEAP_HPP #include "gc/z/zAllocationFlags.hpp" +#include "gc/z/zArray.hpp" #include "gc/z/zForwardingTable.hpp" #include "gc/z/zMark.hpp" #include "gc/z/zObjectAllocator.hpp" @@ -40,6 +41,7 @@ class ThreadClosure; class ZPage; +class ZRelocationSetSelector; class ZHeap { friend class VMStructs; @@ -63,6 +65,8 @@ class ZHeap { void flip_to_marked(); void flip_to_remapped(); + void free_garbage_pages(ZRelocationSetSelector* selector, int bulk); + void out_of_memory(); public: @@ -110,6 +114,7 @@ class ZHeap { ZPage* alloc_page(uint8_t type, size_t size, ZAllocationFlags flags); void undo_alloc_page(ZPage* page); void free_page(ZPage* page, bool reclaimed); + void free_pages(const ZArray* pages, bool reclaimed); // Object allocation uintptr_t alloc_tlab(size_t size); diff --git a/src/hotspot/share/gc/z/zPageAllocator.cpp b/src/hotspot/share/gc/z/zPageAllocator.cpp index ebf29596de2c6..371ee2ff75a7b 100644 --- a/src/hotspot/share/gc/z/zPageAllocator.cpp +++ b/src/hotspot/share/gc/z/zPageAllocator.cpp @@ -24,6 +24,7 @@ #include "precompiled.hpp" #include "gc/shared/gcLogPrecious.hpp" #include "gc/shared/suspendibleThreadSet.hpp" +#include "gc/z/zArray.inline.hpp" #include "gc/z/zCollectedHeap.hpp" #include "gc/z/zFuture.inline.hpp" #include "gc/z/zGlobals.hpp" @@ -748,6 +749,19 @@ void ZPageAllocator::free_page(ZPage* page, bool reclaimed) { satisfy_stalled(); } +void ZPageAllocator::free_pages(const ZArray* pages, bool reclaimed) { + ZLocker locker(&_lock); + + // Free pages + ZArrayIterator iter(pages); + for (ZPage* page; iter.next(&page);) { + free_page_inner(page, reclaimed); + } + + // Try satisfy stalled allocations + satisfy_stalled(); +} + size_t ZPageAllocator::uncommit(uint64_t* timeout) { // We need to join the suspendible thread set while manipulating capacity and // used, to make sure GC safepoints will have a consistent view. However, when diff --git a/src/hotspot/share/gc/z/zPageAllocator.hpp b/src/hotspot/share/gc/z/zPageAllocator.hpp index 800ef4d9875d1..9c970350732be 100644 --- a/src/hotspot/share/gc/z/zPageAllocator.hpp +++ b/src/hotspot/share/gc/z/zPageAllocator.hpp @@ -25,6 +25,7 @@ #define SHARE_GC_Z_ZPAGEALLOCATOR_HPP #include "gc/z/zAllocationFlags.hpp" +#include "gc/z/zArray.hpp" #include "gc/z/zList.hpp" #include "gc/z/zLock.hpp" #include "gc/z/zPageCache.hpp" @@ -124,6 +125,7 @@ class ZPageAllocator { ZPage* alloc_page(uint8_t type, size_t size, ZAllocationFlags flags); void free_page(ZPage* page, bool reclaimed); + void free_pages(const ZArray* pages, bool reclaimed); void enable_deferred_delete() const; void disable_deferred_delete() const; diff --git a/src/hotspot/share/gc/z/zRelocationSetSelector.cpp b/src/hotspot/share/gc/z/zRelocationSetSelector.cpp index e3326f0821fd1..3d80286a8940f 100644 --- a/src/hotspot/share/gc/z/zRelocationSetSelector.cpp +++ b/src/hotspot/share/gc/z/zRelocationSetSelector.cpp @@ -54,31 +54,6 @@ ZRelocationSetSelectorGroup::ZRelocationSetSelectorGroup(const char* name, _forwarding_entries(0), _stats() {} -void ZRelocationSetSelectorGroup::register_live_page(ZPage* page) { - const uint8_t type = page->type(); - const size_t size = page->size(); - const size_t live = page->live_bytes(); - const size_t garbage = size - live; - - if (garbage > _fragmentation_limit) { - _registered_pages.append(page); - } - - _stats._npages++; - _stats._total += size; - _stats._live += live; - _stats._garbage += garbage; -} - -void ZRelocationSetSelectorGroup::register_garbage_page(ZPage* page) { - const size_t size = page->size(); - - _stats._npages++; - _stats._total += size; - _stats._garbage += size; - _stats._empty += size; -} - bool ZRelocationSetSelectorGroup::is_disabled() { // Medium pages are disabled when their page size is zero return _page_type == ZPageTypeMedium && _page_size == 0; @@ -205,31 +180,8 @@ void ZRelocationSetSelectorGroup::select() { ZRelocationSetSelector::ZRelocationSetSelector() : _small("Small", ZPageTypeSmall, ZPageSizeSmall, ZObjectSizeLimitSmall), _medium("Medium", ZPageTypeMedium, ZPageSizeMedium, ZObjectSizeLimitMedium), - _large("Large", ZPageTypeLarge, 0 /* page_size */, 0 /* object_size_limit */) {} - -void ZRelocationSetSelector::register_live_page(ZPage* page) { - const uint8_t type = page->type(); - - if (type == ZPageTypeSmall) { - _small.register_live_page(page); - } else if (type == ZPageTypeMedium) { - _medium.register_live_page(page); - } else { - _large.register_live_page(page); - } -} - -void ZRelocationSetSelector::register_garbage_page(ZPage* page) { - const uint8_t type = page->type(); - - if (type == ZPageTypeSmall) { - _small.register_garbage_page(page); - } else if (type == ZPageTypeMedium) { - _medium.register_garbage_page(page); - } else { - _large.register_garbage_page(page); - } -} + _large("Large", ZPageTypeLarge, 0 /* page_size */, 0 /* object_size_limit */), + _garbage_pages() {} void ZRelocationSetSelector::select() { // Select pages to relocate. The resulting relocation set will be diff --git a/src/hotspot/share/gc/z/zRelocationSetSelector.hpp b/src/hotspot/share/gc/z/zRelocationSetSelector.hpp index 2c632a929fad7..164fcd628a0f4 100644 --- a/src/hotspot/share/gc/z/zRelocationSetSelector.hpp +++ b/src/hotspot/share/gc/z/zRelocationSetSelector.hpp @@ -104,6 +104,7 @@ class ZRelocationSetSelector : public StackObj { ZRelocationSetSelectorGroup _small; ZRelocationSetSelectorGroup _medium; ZRelocationSetSelectorGroup _large; + ZArray _garbage_pages; size_t total() const; size_t empty() const; @@ -116,6 +117,10 @@ class ZRelocationSetSelector : public StackObj { void register_live_page(ZPage* page); void register_garbage_page(ZPage* page); + bool should_free_garbage_pages(int bulk) const; + const ZArray* garbage_pages() const; + void clear_garbage_pages(); + void select(); const ZArray* small() const; diff --git a/src/hotspot/share/gc/z/zRelocationSetSelector.inline.hpp b/src/hotspot/share/gc/z/zRelocationSetSelector.inline.hpp index 74f5db89196c0..11c48394fc995 100644 --- a/src/hotspot/share/gc/z/zRelocationSetSelector.inline.hpp +++ b/src/hotspot/share/gc/z/zRelocationSetSelector.inline.hpp @@ -24,6 +24,8 @@ #ifndef SHARE_GC_Z_ZRELOCATIONSETSELECTOR_INLINE_HPP #define SHARE_GC_Z_ZRELOCATIONSETSELECTOR_INLINE_HPP +#include "gc/z/zArray.inline.hpp" +#include "gc/z/zPage.inline.hpp" #include "gc/z/zRelocationSetSelector.hpp" inline size_t ZRelocationSetSelectorGroupStats::npages() const { @@ -66,6 +68,31 @@ inline const ZRelocationSetSelectorGroupStats& ZRelocationSetSelectorStats::larg return _large; } +inline void ZRelocationSetSelectorGroup::register_live_page(ZPage* page) { + const uint8_t type = page->type(); + const size_t size = page->size(); + const size_t live = page->live_bytes(); + const size_t garbage = size - live; + + if (garbage > _fragmentation_limit) { + _registered_pages.append(page); + } + + _stats._npages++; + _stats._total += size; + _stats._live += live; + _stats._garbage += garbage; +} + +inline void ZRelocationSetSelectorGroup::register_garbage_page(ZPage* page) { + const size_t size = page->size(); + + _stats._npages++; + _stats._total += size; + _stats._garbage += size; + _stats._empty += size; +} + inline const ZArray* ZRelocationSetSelectorGroup::selected() const { return &_registered_pages; } @@ -78,6 +105,44 @@ inline const ZRelocationSetSelectorGroupStats& ZRelocationSetSelectorGroup::stat return _stats; } +inline void ZRelocationSetSelector::register_live_page(ZPage* page) { + const uint8_t type = page->type(); + + if (type == ZPageTypeSmall) { + _small.register_live_page(page); + } else if (type == ZPageTypeMedium) { + _medium.register_live_page(page); + } else { + _large.register_live_page(page); + } +} + +inline void ZRelocationSetSelector::register_garbage_page(ZPage* page) { + const uint8_t type = page->type(); + + if (type == ZPageTypeSmall) { + _small.register_garbage_page(page); + } else if (type == ZPageTypeMedium) { + _medium.register_garbage_page(page); + } else { + _large.register_garbage_page(page); + } + + _garbage_pages.append(page); +} + +inline bool ZRelocationSetSelector::should_free_garbage_pages(int bulk) const { + return _garbage_pages.length() >= bulk && _garbage_pages.is_nonempty(); +} + +inline const ZArray* ZRelocationSetSelector::garbage_pages() const { + return &_garbage_pages; +} + +inline void ZRelocationSetSelector::clear_garbage_pages() { + return _garbage_pages.clear(); +} + inline size_t ZRelocationSetSelector::total() const { return _small.stats().total() + _medium.stats().total() + _large.stats().total(); } From d93e3a7d0b3aad5c10843bf8eea2346278dbec8b Mon Sep 17 00:00:00 2001 From: Aleksey Shipilev Date: Mon, 2 Nov 2020 17:34:01 +0000 Subject: [PATCH 04/32] 8255760: Shenandoah: match constants style in ShenandoahMarkTask fallback Reviewed-by: zgu, rkennke --- .../share/gc/shenandoah/shenandoahTaskqueue.hpp | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/src/hotspot/share/gc/shenandoah/shenandoahTaskqueue.hpp b/src/hotspot/share/gc/shenandoah/shenandoahTaskqueue.hpp index 3ad8f779e1f3b..40853015a6520 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahTaskqueue.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahTaskqueue.hpp @@ -225,10 +225,11 @@ class ShenandoahMarkTask class ShenandoahMarkTask { private: - enum { - chunk_bits = 10, - pow_bits = 5, - }; + static const uint8_t chunk_bits = 10; + static const uint8_t pow_bits = 5; + + static const int chunk_max = nth_bit(chunk_bits) - 1; + static const int pow_max = nth_bit(pow_bits) - 1; oop _obj; int _chunk; @@ -237,8 +238,8 @@ class ShenandoahMarkTask public: ShenandoahMarkTask(oop o = NULL, int chunk = 0, int pow = 0): _obj(o), _chunk(chunk), _pow(pow) { - assert(0 <= chunk && chunk < nth_bit(chunk_bits), "chunk is sane: %d", chunk); - assert(0 <= pow && pow < nth_bit(pow_bits), "pow is sane: %d", pow); + assert(0 <= chunk && chunk <= chunk_max, "chunk is in range: %d", chunk); + assert(0 <= pow && pow <= pow_max, "pow is in range: %d", pow); } // Trivially copyable. From 05bcd67e6501f3824020edd1ab036c87888fa229 Mon Sep 17 00:00:00 2001 From: Lance Andersen Date: Mon, 2 Nov 2020 18:24:48 +0000 Subject: [PATCH 05/32] 8255529: Remove unused methods from java.util.zip.ZipFile Reviewed-by: naoto, redestad --- .../share/classes/java/util/zip/ZipFile.java | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/src/java.base/share/classes/java/util/zip/ZipFile.java b/src/java.base/share/classes/java/util/zip/ZipFile.java index 2a2e3534e1876..4c53855abfeed 100644 --- a/src/java.base/share/classes/java/util/zip/ZipFile.java +++ b/src/java.base/share/classes/java/util/zip/ZipFile.java @@ -1335,18 +1335,6 @@ private final void checkEncoding(ZipCoder zc, byte[] a, int pos, int nlen) throw } } - private static final int hashN(byte[] a, int off, int len) { - int h = 1; - while (len-- > 0) { - h = 31 * h + a[off++]; - } - return h; - } - - private static final int hash_append(int hash, byte b) { - return hash * 31 + b; - } - private static class End { int centot; // 4 bytes long cenlen; // 4 bytes From bc6085b06c2c576f689e8370e005c2d43b7c316c Mon Sep 17 00:00:00 2001 From: Tom Rodriguez Date: Mon, 2 Nov 2020 19:19:48 +0000 Subject: [PATCH 06/32] 8255578: [JVMCI] be more careful about reflective reads of Class.componentType. Reviewed-by: kvn, dlong --- src/hotspot/share/classfile/javaClasses.hpp | 2 ++ src/hotspot/share/jvmci/jvmciCompilerToVM.cpp | 15 +++++++++++++++ .../jdk/vm/ci/hotspot/HotSpotJDKReflection.java | 8 ++++++++ 3 files changed, 25 insertions(+) diff --git a/src/hotspot/share/classfile/javaClasses.hpp b/src/hotspot/share/classfile/javaClasses.hpp index 23fa7b64e48f8..a6fc3ad2ff142 100644 --- a/src/hotspot/share/classfile/javaClasses.hpp +++ b/src/hotspot/share/classfile/javaClasses.hpp @@ -322,6 +322,8 @@ class java_lang_Class : AllStatic { static oop class_data(oop java_class); static void set_class_data(oop java_class, oop classData); + static int component_mirror_offset() { return _component_mirror_offset; } + static oop class_loader(oop java_class); static void set_module(oop java_class, oop module); static oop module(oop java_class); diff --git a/src/hotspot/share/jvmci/jvmciCompilerToVM.cpp b/src/hotspot/share/jvmci/jvmciCompilerToVM.cpp index 54f6c5c370e7d..60d8cf40cf278 100644 --- a/src/hotspot/share/jvmci/jvmciCompilerToVM.cpp +++ b/src/hotspot/share/jvmci/jvmciCompilerToVM.cpp @@ -1995,6 +1995,14 @@ C2V_VMENTRY_NULL(jobject, readFieldValue, (JNIEnv* env, jobject, jobject object, JVMCI_THROW_MSG_NULL(IllegalArgumentException, err_msg("Unexpected type: %s", JVMCIENV->klass_name(base))); } + + if (displacement == java_lang_Class::component_mirror_offset() && java_lang_Class::is_instance(obj()) && + !java_lang_Class::as_Klass(obj())->is_array_klass()) { + // Class.componentType for non-array classes can transiently contain an int[] that's + // used for locking so always return null to mimic Class.getComponentType() + return JVMCIENV->get_jobject(JVMCIENV->get_JavaConstant_NULL_POINTER()); + } + jlong value = 0; JVMCIObject kind; switch (constant_type) { @@ -2220,6 +2228,13 @@ C2V_VMENTRY_NULL(jobject, getObject, (JNIEnv* env, jobject, jobject x, long disp JVMCI_THROW_0(NullPointerException); } Handle xobj = JVMCIENV->asConstant(JVMCIENV->wrap(x), JVMCI_CHECK_0); + if (displacement == java_lang_Class::component_mirror_offset() && java_lang_Class::is_instance(xobj()) && + !java_lang_Class::as_Klass(xobj())->is_array_klass()) { + // Class.componentType for non-array classes can transiently contain an int[] that's + // used for locking so always return null to mimic Class.getComponentType() + return JVMCIENV->get_jobject(JVMCIENV->get_JavaConstant_NULL_POINTER()); + } + oop res = xobj->obj_field(displacement); JVMCIObject result = JVMCIENV->get_object_constant(res); return JVMCIENV->get_jobject(result); diff --git a/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotJDKReflection.java b/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotJDKReflection.java index bdccf28d68b0f..a7c2aa5d2034a 100644 --- a/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotJDKReflection.java +++ b/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotJDKReflection.java @@ -404,6 +404,14 @@ JavaConstant readFieldValue(HotSpotResolvedJavaField field, Object obj, boolean assert obj != null; assert !field.isStatic() || obj instanceof Class; long displacement = field.getOffset(); + if (obj instanceof Class && field.getName().equals("componentType")) { + Class clazz = (Class) obj; + if (!clazz.isArray()) { + // Class.componentType for non-array classes can transiently contain an int[] that's + // used for locking so always return null to mimic Class.getComponentType() + return JavaConstant.NULL_POINTER; + } + } assert checkRead(field.getJavaKind(), displacement, (HotSpotResolvedObjectType) runtime().getHostJVMCIBackend().getMetaAccess().lookupJavaType(field.isStatic() ? (Class) obj : obj.getClass()), From acb5f654b1b8c511b0f2c5e7b0bb1b325439642d Mon Sep 17 00:00:00 2001 From: Sergey Bylokhov Date: Mon, 2 Nov 2020 19:32:06 +0000 Subject: [PATCH 07/32] 8211958: Broken links in java.desktop files Reviewed-by: aivanov --- .../share/classes/java/awt/Component.java | 8 ++--- .../share/classes/java/awt/Container.java | 2 +- .../java/awt/DefaultFocusTraversalPolicy.java | 2 +- .../java/awt/DefaultKeyboardFocusManager.java | 2 +- .../java/awt/FocusTraversalPolicy.java | 2 +- .../java/awt/KeyboardFocusManager.java | 4 +-- .../java/awt/doc-files/DesktopProperties.html | 20 +++++------ .../metadata/doc-files/tiff_metadata.html | 34 +++++++++---------- .../share/classes/javax/print/DocFlavor.java | 8 ++--- 9 files changed, 39 insertions(+), 43 deletions(-) diff --git a/src/java.desktop/share/classes/java/awt/Component.java b/src/java.desktop/share/classes/java/awt/Component.java index ad19383cd5864..98a8cdc03b702 100644 --- a/src/java.desktop/share/classes/java/awt/Component.java +++ b/src/java.desktop/share/classes/java/awt/Component.java @@ -207,7 +207,7 @@ * * How to Use the Focus Subsystem, * a section in The Java Tutorial, and the - * Focus Specification + * Focus Specification * for more information. * * @author Arthur van Hoff @@ -7651,7 +7651,7 @@ public void requestFocus(FocusEvent.Cause cause) { * @param temporary true if the focus change is temporary, * such as when the window loses the focus; for * more information on temporary focus changes see the - *Focus Specification + *Focus Specification * @return {@code false} if the focus change request is guaranteed to * fail; {@code true} if it is likely to succeed * @see java.awt.event.FocusEvent @@ -7719,7 +7719,7 @@ protected boolean requestFocus(boolean temporary) { * @param temporary true if the focus change is temporary, * such as when the window loses the focus; for * more information on temporary focus changes see the - *Focus Specification + *Focus Specification * * @param cause the cause why the focus is requested * @return {@code false} if the focus change request is guaranteed to @@ -7886,7 +7886,7 @@ public boolean requestFocusInWindow(FocusEvent.Cause cause) { * @param temporary true if the focus change is temporary, * such as when the window loses the focus; for * more information on temporary focus changes see the - *Focus Specification + *Focus Specification * @return {@code false} if the focus change request is guaranteed to * fail; {@code true} if it is likely to succeed * @see #requestFocus diff --git a/src/java.desktop/share/classes/java/awt/Container.java b/src/java.desktop/share/classes/java/awt/Container.java index ee754201f5e57..557111c07d372 100644 --- a/src/java.desktop/share/classes/java/awt/Container.java +++ b/src/java.desktop/share/classes/java/awt/Container.java @@ -83,7 +83,7 @@ * * How to Use the Focus Subsystem, * a section in The Java Tutorial, and the - * Focus Specification + * Focus Specification * for more information. * * @author Arthur van Hoff diff --git a/src/java.desktop/share/classes/java/awt/DefaultFocusTraversalPolicy.java b/src/java.desktop/share/classes/java/awt/DefaultFocusTraversalPolicy.java index 4a9e10166fafa..ebfa17302ee3e 100644 --- a/src/java.desktop/share/classes/java/awt/DefaultFocusTraversalPolicy.java +++ b/src/java.desktop/share/classes/java/awt/DefaultFocusTraversalPolicy.java @@ -57,7 +57,7 @@ * * How to Use the Focus Subsystem, * a section in The Java Tutorial, and the - * Focus Specification + * Focus Specification * for more information. * * @author David Mendenhall diff --git a/src/java.desktop/share/classes/java/awt/DefaultKeyboardFocusManager.java b/src/java.desktop/share/classes/java/awt/DefaultKeyboardFocusManager.java index de60e1e747cb2..47ddefaabd28e 100644 --- a/src/java.desktop/share/classes/java/awt/DefaultKeyboardFocusManager.java +++ b/src/java.desktop/share/classes/java/awt/DefaultKeyboardFocusManager.java @@ -52,7 +52,7 @@ * * How to Use the Focus Subsystem, * a section in The Java Tutorial, and the - * Focus Specification + * Focus Specification * for more information. * * @author David Mendenhall diff --git a/src/java.desktop/share/classes/java/awt/FocusTraversalPolicy.java b/src/java.desktop/share/classes/java/awt/FocusTraversalPolicy.java index 9bcc326771fd2..551de6a89b819 100644 --- a/src/java.desktop/share/classes/java/awt/FocusTraversalPolicy.java +++ b/src/java.desktop/share/classes/java/awt/FocusTraversalPolicy.java @@ -52,7 +52,7 @@ * * How to Use the Focus Subsystem, * a section in The Java Tutorial, and the - * Focus Specification + * Focus Specification * for more information. * * @author David Mendenhall diff --git a/src/java.desktop/share/classes/java/awt/KeyboardFocusManager.java b/src/java.desktop/share/classes/java/awt/KeyboardFocusManager.java index f6079ede2ecc2..b317513756acf 100644 --- a/src/java.desktop/share/classes/java/awt/KeyboardFocusManager.java +++ b/src/java.desktop/share/classes/java/awt/KeyboardFocusManager.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2020, 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 @@ -88,7 +88,7 @@ * * How to Use the Focus Subsystem, * a section in The Java Tutorial, and the - * Focus Specification + * Focus Specification * for more information. * * @author David Mendenhall diff --git a/src/java.desktop/share/classes/java/awt/doc-files/DesktopProperties.html b/src/java.desktop/share/classes/java/awt/doc-files/DesktopProperties.html index e6790a53bcf70..1e68b086e4e29 100644 --- a/src/java.desktop/share/classes/java/awt/doc-files/DesktopProperties.html +++ b/src/java.desktop/share/classes/java/awt/doc-files/DesktopProperties.html @@ -36,8 +36,8 @@

AWT Desktop Properties

The following refers to standard AWT desktop properties that may be obtained via the - -Toolkit.getDesktopProperty method. +{@link java.awt.Toolkit#getDesktopProperty(java.lang.String) +Toolkit.getDesktopProperty} method.

Each desktop property is named by a unique string, which is the "name" of that property. @@ -86,9 +86,9 @@

Desktop Font Rendering Hints

These are applied by platform-specific heavyweight components. However an application may want to render text using the same text antialiasing on a drawing surface or lightweight (non-platform) component using - Graphics2D methods. +{@link java.awt.Graphics2D Graphics2D} methods. This is particularly important when creating - Swing components which +{@link javax.swing.JComponent Swing components} which are required to appear consistent with native desktop components or other Swing components. @@ -97,9 +97,8 @@

Basic Usage

"awt.font.desktophints" can be used to obtain the rendering hints that best match the desktop settings. -The return value is a - Map of - RenderingHints which +The return value is a {@link java.util.Map Map} of +{@link java.awt.RenderingHints RenderingHints} which can be directly applied to a Graphics2D.

It is a Map as more than one hint may be needed. @@ -116,8 +115,7 @@

Advanced Usage Tips

Listening for changes

An application can listen for changes in the property -using a -PropertyChangeListener : +using a {@link java.beans.PropertyChangeListener PropertyChangeListener}:


 tk.addPropertyChangeListener("awt.font.desktophints", pcl);
 
@@ -134,10 +132,10 @@

Listening for changes

Text Measurement

Text always needs to be measured using the same - FontRenderContext +{@link java.awt.font.FontRenderContext FontRenderContext} as used for rendering. The text anti-aliasing hint is a component of the FontRenderContext. -A FontMetrics +A {@link java.awt.FontMetrics FontMetrics} obtained from the Graphics object on which the hint has been set will measure text appropriately. This is not a unique requirement for clients that specify this hint diff --git a/src/java.desktop/share/classes/javax/imageio/metadata/doc-files/tiff_metadata.html b/src/java.desktop/share/classes/javax/imageio/metadata/doc-files/tiff_metadata.html index cfd7fdfa3ca65..fc918e78eeba7 100644 --- a/src/java.desktop/share/classes/javax/imageio/metadata/doc-files/tiff_metadata.html +++ b/src/java.desktop/share/classes/javax/imageio/metadata/doc-files/tiff_metadata.html @@ -5,7 +5,7 @@ TIFF Metadata Format Specification and Usage Notes @@ -90,7 +90,7 @@

Color Conversion

Color Spaces

The raw color space assigned by default, i.e., in the absence of a -user-supplied ImageTypeSpecifier, +user-supplied {@link javax.imageio.ImageTypeSpecifier ImageTypeSpecifier}, will be the first among the following which applies:
    @@ -158,8 +158,8 @@

    Color Spaces

    ICC Profiles

    If an ICC profile is contained in the image metadata -( -BaselineTIFFTagSet.TAG_ICC_PROFILE, tag number 34675), +({@link javax.imageio.plugins.tiff.BaselineTIFFTagSet BaselineTIFFTagSet}. +TAG_ICC_PROFILE, tag number 34675), an attempt will be made to use it to create the color space of the loaded image. It will be used if the data layout is of component type and the number of samples per pixel equals or is one greater than the number @@ -174,15 +174,13 @@

    ICC Profiles

  • Obtain the image metadata from ImageReader.getImageMetadata
  • Extract the ICC profile field and its value.
  • -
  • Create an -ICC_ColorSpace from an - -ICC_Profile created from the ICC profile field data +
  • Create an {@link java.awt.color.ICC_ColorSpace ICC_ColorSpace} from an +{@link java.awt.color.ICC_Profile ICC_Profile} created from the ICC profile field data using ICC_Profile.getInstance(byte[]).
  • Create an ImageTypeSpecifier from the new color space using one of its factory methods which accepts an ICC_ColorSpace. -
  • Create a compatible ImageReadParam +
  • Create a compatible {@link javax.imageio.ImageReadParam ImageReadParam} and set the ImageTypeSpecifier using ImageReadParam.setDestinationType.
  • Pass the parameter object to the appropriate read method.
  • @@ -206,7 +204,7 @@

    Metadata Issues

    metadata. The reader is informed to disregard all metadata as usual via the ignoreMetadata parameter of ImageReader.setInput(Object,boolean,boolean). It is -informed of which TIFFTags to +informed of which {@link javax.imageio.plugins.tiff.TIFFTag TIFFTag}s to recognize or not to recognize via TIFFImageReadParam.addAllowedTagSet(TIFFTagSet) and TIFFImageReadParam.removeAllowedTagSet(TIFFTagSet). @@ -221,7 +219,7 @@

    Metadata Issues

    TIFFImageReadParam.setReadUnknownTags(boolean) has been invoked with parameter true. -

    Use of a TIFFDirectory +

    Use of a {@link javax.imageio.plugins.tiff.TIFFDirectory TIFFDirectory} object may simplify gaining access to metadata values. An instance of TIFFDirectory may be created from the IIOMetadata object returned by the TIFF reader using the @@ -481,9 +479,9 @@

    Reading Compressed Exif Images

    Writing Images

    -TIFF images are written by a ImageWriter which may be +TIFF images are written by a {@link javax.imageio.ImageWriter ImageWriter} which may be controlled by its public interface as well as via a supplied -ImageWriteParam. For an ImageWriteParam returned +{@link javax.imageio.ImageWriteParam ImageWriteParam}. For an ImageWriteParam returned by the getDefaultWriteParam() method of the TIFF ImageWriter, the canWriteTiles() and canWriteCompressed() methods will return true; the canOffsetTiles() and @@ -631,9 +629,9 @@

    ICC Profiles

    An ICC Profile field will be written if either:
    • one is present in the native image metadata -IIOMetadata instance supplied to the writer, +{@link javax.imageio.metadata.IIOMetadata IIOMetadata} instance supplied to the writer, or
    • -
    • the ColorSpace +
    • the {@link java.awt.color.ColorSpace ColorSpace} of the destination ImageTypeSpecifier is an instance of ICC_ColorSpace which is not one of the standard color spaces defined by the CS_* constants in the @@ -748,7 +746,7 @@

      Metadata Issues

      Setting up the image metadata to write to a TIFF stream may be simplified by using the TIFFDirectory class which represents a TIFF IFD. A field in a TIFF IFD is represented by an -instance of TIFFField. For each +instance of {@link javax.imageio.plugins.tiff.TIFFField TIFFField}. For each field to be written a TIFFField may be added to the TIFFDirectory and the latter converted to an IIOMetadata object by invoking diff --git a/src/java.desktop/share/classes/javax/print/DocFlavor.java b/src/java.desktop/share/classes/javax/print/DocFlavor.java index a52b0e1885254..da3f4f1876207 100644 --- a/src/java.desktop/share/classes/javax/print/DocFlavor.java +++ b/src/java.desktop/share/classes/javax/print/DocFlavor.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2020, 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 @@ -156,9 +156,9 @@ * the primary IANA name but is guaranteed to be understood by this VM. For * common flavors, the pre-defined *HOST {@code DocFlavors} may be used. *

      - * See character - * encodings for more information on the character encodings supported on - * the Java platform. + * See + * character encodings for more information on the character encodings + * supported on the Java platform. * *


      *

      Recommended DocFlavors

      From a250716ad2997e1dad592805a5874421f77dadde Mon Sep 17 00:00:00 2001 From: Chris Plummer Date: Mon, 2 Nov 2020 20:13:32 +0000 Subject: [PATCH 08/32] 8255694: memory leak in JDWP debug agent after calling JVMTI GetAllThreads Reviewed-by: amenkov, sspitsyn --- src/jdk.jdwp.agent/share/native/libjdwp/threadControl.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/jdk.jdwp.agent/share/native/libjdwp/threadControl.c b/src/jdk.jdwp.agent/share/native/libjdwp/threadControl.c index 78ca29796aae1..9f1f3ce3a5d39 100644 --- a/src/jdk.jdwp.agent/share/native/libjdwp/threadControl.c +++ b/src/jdk.jdwp.agent/share/native/libjdwp/threadControl.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2007, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2020, 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 @@ -836,6 +836,7 @@ threadControl_onHook(void) */ node->isStarted = JNI_TRUE; } + jvmtiDeallocate(threads); } } END_WITH_LOCAL_REFS(env) @@ -1549,7 +1550,8 @@ threadControl_suspendAll(void) suspendAllCount++; } - err: ; + err: + jvmtiDeallocate(threads); } END_WITH_LOCAL_REFS(env) From ceba2f8503241e1680e26eddcea6bc628f3bdb78 Mon Sep 17 00:00:00 2001 From: Chris Plummer Date: Mon, 2 Nov 2020 20:23:44 +0000 Subject: [PATCH 09/32] 8255696: JDWP debug agent's canSuspendResumeThreadLists() should be removed Reviewed-by: amenkov, sspitsyn --- .../share/native/libjdwp/threadControl.c | 26 +++---------------- .../share/native/libjdwp/util.c | 10 ------- .../share/native/libjdwp/util.h | 1 - 3 files changed, 4 insertions(+), 33 deletions(-) diff --git a/src/jdk.jdwp.agent/share/native/libjdwp/threadControl.c b/src/jdk.jdwp.agent/share/native/libjdwp/threadControl.c index 9f1f3ce3a5d39..96773392fc375 100644 --- a/src/jdk.jdwp.agent/share/native/libjdwp/threadControl.c +++ b/src/jdk.jdwp.agent/share/native/libjdwp/threadControl.c @@ -1516,22 +1516,9 @@ threadControl_suspendAll(void) error = AGENT_ERROR_OUT_OF_MEMORY; goto err; } - if (canSuspendResumeThreadLists()) { - error = commonSuspendList(env, count, threads); - if (error != JVMTI_ERROR_NONE) { - goto err; - } - } else { - - int i; - - for (i = 0; i < count; i++) { - error = commonSuspend(env, threads[i], JNI_FALSE); - - if (error != JVMTI_ERROR_NONE) { - goto err; - } - } + error = commonSuspendList(env, count, threads); + if (error != JVMTI_ERROR_NONE) { + goto err; } /* @@ -1590,12 +1577,7 @@ threadControl_resumeAll(void) * no need to get the whole thread list from JVMTI (unlike * suspendAll). */ - if (canSuspendResumeThreadLists()) { - error = commonResumeList(env); - } else { - error = enumerateOverThreadList(env, &runningThreads, - resumeHelper, NULL); - } + error = commonResumeList(env); if ((error == JVMTI_ERROR_NONE) && (otherThreads.first != NULL)) { error = enumerateOverThreadList(env, &otherThreads, resumeHelper, NULL); diff --git a/src/jdk.jdwp.agent/share/native/libjdwp/util.c b/src/jdk.jdwp.agent/share/native/libjdwp/util.c index 2f73f33cbbcbf..21f72b51b94b0 100644 --- a/src/jdk.jdwp.agent/share/native/libjdwp/util.c +++ b/src/jdk.jdwp.agent/share/native/libjdwp/util.c @@ -962,16 +962,6 @@ jvmtiMicroVersion(void) >> JVMTI_VERSION_SHIFT_MICRO; } -jboolean -canSuspendResumeThreadLists(void) -{ - jvmtiError error; - jvmtiCapabilities cap; - - error = jvmtiGetCapabilities(&cap); - return (error == JVMTI_ERROR_NONE && cap.can_suspend); -} - jvmtiError getSourceDebugExtension(jclass clazz, char **extensionPtr) { diff --git a/src/jdk.jdwp.agent/share/native/libjdwp/util.h b/src/jdk.jdwp.agent/share/native/libjdwp/util.h index c4d31774c6451..43c4b143471b3 100644 --- a/src/jdk.jdwp.agent/share/native/libjdwp/util.h +++ b/src/jdk.jdwp.agent/share/native/libjdwp/util.h @@ -337,7 +337,6 @@ jint jvmtiMajorVersion(void); jint jvmtiMinorVersion(void); jint jvmtiMicroVersion(void); jvmtiError getSourceDebugExtension(jclass clazz, char **extensionPtr); -jboolean canSuspendResumeThreadLists(void); jrawMonitorID debugMonitorCreate(char *name); void debugMonitorEnter(jrawMonitorID theLock); From bee864fb3ae46032281556d1c164fd819c3e4c25 Mon Sep 17 00:00:00 2001 From: Bernhard Urban-Forster Date: Mon, 2 Nov 2020 20:25:59 +0000 Subject: [PATCH 10/32] 8255766: Fix linux+arm64 build after 8254072 Reviewed-by: kvn, ihse --- src/hotspot/cpu/aarch64/sharedRuntime_aarch64.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/hotspot/cpu/aarch64/sharedRuntime_aarch64.cpp b/src/hotspot/cpu/aarch64/sharedRuntime_aarch64.cpp index eb6195fd6756d..92a07a84d2a94 100644 --- a/src/hotspot/cpu/aarch64/sharedRuntime_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/sharedRuntime_aarch64.cpp @@ -1498,8 +1498,7 @@ nmethod* SharedRuntime::generate_native_wrapper(MacroAssembler* masm, // Generate stack overflow check if (UseStackBanging) { - assert(StackOverflow::stack_shadow_zone_size() == (int)StackOverflow::stack_shadow_zone_size(), "must be same"); - __ bang_stack_with_offset((int)StackOverflow::stack_shadow_zone_size()); + __ bang_stack_with_offset(checked_cast(StackOverflow::stack_shadow_zone_size())); } else { Unimplemented(); } From c7747416557ca8a85b24bac43b7bbc94a2dd5807 Mon Sep 17 00:00:00 2001 From: Chris Plummer Date: Mon, 2 Nov 2020 20:31:49 +0000 Subject: [PATCH 11/32] 8255695: Some JVMTI calls in the jdwp debug agent are using FUNC_PTR instead of JVMTI_FUNC_PTR Reviewed-by: sspitsyn, amenkov --- .../share/native/libjdwp/util.c | 28 +++++++++---------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/src/jdk.jdwp.agent/share/native/libjdwp/util.c b/src/jdk.jdwp.agent/share/native/libjdwp/util.c index 21f72b51b94b0..d40bb32b10192 100644 --- a/src/jdk.jdwp.agent/share/native/libjdwp/util.c +++ b/src/jdk.jdwp.agent/share/native/libjdwp/util.c @@ -699,12 +699,12 @@ methodClass(jmethodID method, jclass *pclazz) jvmtiError error; *pclazz = NULL; - error = FUNC_PTR(gdata->jvmti,GetMethodDeclaringClass) + error = JVMTI_FUNC_PTR(gdata->jvmti,GetMethodDeclaringClass) (gdata->jvmti, method, pclazz); return error; } -/* Returns a local ref to the declaring class for a method, or NULL. */ +/* Returns the start and end locations of the specified method. */ jvmtiError methodLocation(jmethodID method, jlocation *ploc1, jlocation *ploc2) { @@ -727,7 +727,7 @@ methodSignature(jmethodID method, char *signature = NULL; char *generic_signature = NULL; - error = FUNC_PTR(gdata->jvmti,GetMethodName) + error = JVMTI_FUNC_PTR(gdata->jvmti,GetMethodName) (gdata->jvmti, method, &name, &signature, &generic_signature); if ( pname != NULL ) { @@ -1009,7 +1009,7 @@ debugMonitorEnter(jrawMonitorID monitor) { jvmtiError error; while (JNI_TRUE) { - error = FUNC_PTR(gdata->jvmti,RawMonitorEnter) + error = JVMTI_FUNC_PTR(gdata->jvmti,RawMonitorEnter) (gdata->jvmti, monitor); error = ignore_vm_death(error); if (error == JVMTI_ERROR_INTERRUPT) { @@ -1028,7 +1028,7 @@ debugMonitorExit(jrawMonitorID monitor) { jvmtiError error; - error = FUNC_PTR(gdata->jvmti,RawMonitorExit) + error = JVMTI_FUNC_PTR(gdata->jvmti,RawMonitorExit) (gdata->jvmti, monitor); error = ignore_vm_death(error); if (error != JVMTI_ERROR_NONE) { @@ -1040,7 +1040,7 @@ void debugMonitorWait(jrawMonitorID monitor) { jvmtiError error; - error = FUNC_PTR(gdata->jvmti,RawMonitorWait) + error = JVMTI_FUNC_PTR(gdata->jvmti,RawMonitorWait) (gdata->jvmti, monitor, ((jlong)(-1))); /* @@ -1085,7 +1085,7 @@ void debugMonitorTimedWait(jrawMonitorID monitor, jlong millis) { jvmtiError error; - error = FUNC_PTR(gdata->jvmti,RawMonitorWait) + error = JVMTI_FUNC_PTR(gdata->jvmti,RawMonitorWait) (gdata->jvmti, monitor, millis); if (error == JVMTI_ERROR_INTERRUPT) { /* See comment above */ @@ -1103,7 +1103,7 @@ debugMonitorNotify(jrawMonitorID monitor) { jvmtiError error; - error = FUNC_PTR(gdata->jvmti,RawMonitorNotify) + error = JVMTI_FUNC_PTR(gdata->jvmti,RawMonitorNotify) (gdata->jvmti, monitor); error = ignore_vm_death(error); if (error != JVMTI_ERROR_NONE) { @@ -1116,7 +1116,7 @@ debugMonitorNotifyAll(jrawMonitorID monitor) { jvmtiError error; - error = FUNC_PTR(gdata->jvmti,RawMonitorNotifyAll) + error = JVMTI_FUNC_PTR(gdata->jvmti,RawMonitorNotifyAll) (gdata->jvmti, monitor); error = ignore_vm_death(error); if (error != JVMTI_ERROR_NONE) { @@ -1130,7 +1130,7 @@ debugMonitorCreate(char *name) jrawMonitorID monitor; jvmtiError error; - error = FUNC_PTR(gdata->jvmti,CreateRawMonitor) + error = JVMTI_FUNC_PTR(gdata->jvmti,CreateRawMonitor) (gdata->jvmti, name, &monitor); if (error != JVMTI_ERROR_NONE) { EXIT_ERROR(error, "on creation of a raw monitor"); @@ -1143,7 +1143,7 @@ debugMonitorDestroy(jrawMonitorID monitor) { jvmtiError error; - error = FUNC_PTR(gdata->jvmti,DestroyRawMonitor) + error = JVMTI_FUNC_PTR(gdata->jvmti,DestroyRawMonitor) (gdata->jvmti, monitor); error = ignore_vm_death(error); if (error != JVMTI_ERROR_NONE) { @@ -1202,7 +1202,7 @@ classSignature(jclass clazz, char **psignature, char **pgeneric_signature) * pgeneric_signature can be NULL, and GetClassSignature * accepts NULL. */ - error = FUNC_PTR(gdata->jvmti,GetClassSignature) + error = JVMTI_FUNC_PTR(gdata->jvmti,GetClassSignature) (gdata->jvmti, clazz, &signature, pgeneric_signature); if ( psignature != NULL ) { @@ -1774,7 +1774,7 @@ jvmtiAllocate(jint numBytes) if ( numBytes == 0 ) { return NULL; } - error = FUNC_PTR(gdata->jvmti,Allocate) + error = JVMTI_FUNC_PTR(gdata->jvmti,Allocate) (gdata->jvmti, numBytes, (unsigned char**)&ptr); if (error != JVMTI_ERROR_NONE ) { EXIT_ERROR(error, "Can't allocate jvmti memory"); @@ -1789,7 +1789,7 @@ jvmtiDeallocate(void *ptr) if ( ptr == NULL ) { return; } - error = FUNC_PTR(gdata->jvmti,Deallocate) + error = JVMTI_FUNC_PTR(gdata->jvmti,Deallocate) (gdata->jvmti, ptr); if (error != JVMTI_ERROR_NONE ) { EXIT_ERROR(error, "Can't deallocate jvmti memory"); From 184db64dfb711c9cba426fb0b45bea4c962489de Mon Sep 17 00:00:00 2001 From: Erik Joelsson Date: Mon, 2 Nov 2020 21:06:38 +0000 Subject: [PATCH 12/32] 8255732: OpenJDK fails to build if $A is set to a value with spaces Reviewed-by: ihse --- make/common/JavaCompilation.gmk | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/make/common/JavaCompilation.gmk b/make/common/JavaCompilation.gmk index 444ded0fc06b6..bedb971115bae 100644 --- a/make/common/JavaCompilation.gmk +++ b/make/common/JavaCompilation.gmk @@ -311,9 +311,11 @@ define SetupJavaCompilationBody ifneq ($$($1_KEEP_DUPS), true) # Remove duplicate source files by keeping the first found of each duplicate. # This allows for automatic overrides with custom or platform specific versions - # source files. + # source files. Need to call DoubleDollar as we have java classes with '$' in + # their names. $1_SRCS := $$(strip $$(foreach s, $$($1_SRCS), \ - $$(eval relative_src := $$(call remove-prefixes, $$($1_SRC), $$(s))) \ + $$(eval relative_src := $$(call remove-prefixes, $$($1_SRC), \ + $$(call DoubleDollar, $$(s)))) \ $$(if $$($1_$$(relative_src)), \ , \ $$(eval $1_$$(relative_src) := 1) $$(s)))) From f97ec359ec688346956c29002edb28703d3ba032 Mon Sep 17 00:00:00 2001 From: Magnus Ihse Bursie Date: Tue, 3 Nov 2020 01:17:10 +0000 Subject: [PATCH 13/32] 8255785: X11 libraries should not be required by configure for headless only Reviewed-by: mikael, prr --- make/autoconf/libraries.m4 | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/make/autoconf/libraries.m4 b/make/autoconf/libraries.m4 index 5120918aed225..e6aafe01550f3 100644 --- a/make/autoconf/libraries.m4 +++ b/make/autoconf/libraries.m4 @@ -43,9 +43,11 @@ AC_DEFUN_ONCE([LIB_DETERMINE_DEPENDENCIES], if test "x$OPENJDK_TARGET_OS" = xwindows || test "x$OPENJDK_TARGET_OS" = xmacosx; then # No X11 support on windows or macosx NEEDS_LIB_X11=false + elif test "x$ENABLE_HEADLESS_ONLY" = xtrue; then + # No X11 support needed when building headless only + NEEDS_LIB_X11=false else - # All other instances need X11, even if building headless only, libawt still - # needs X11 headers. + # All other instances need X11 NEEDS_LIB_X11=true fi From 50357d136a775872999055bef61057b884d80693 Mon Sep 17 00:00:00 2001 From: Nick Gasson Date: Tue, 3 Nov 2020 01:37:57 +0000 Subject: [PATCH 14/32] 8254723: add diagnostic command to write Linux perf map file Reviewed-by: ysuenaga, sspitsyn --- src/hotspot/os/linux/globals_linux.hpp | 5 +- src/hotspot/os/linux/os_linux.cpp | 6 ++ src/hotspot/share/code/codeCache.cpp | 28 ++++++ src/hotspot/share/code/codeCache.hpp | 7 ++ src/hotspot/share/runtime/java.cpp | 6 ++ .../share/services/diagnosticCommand.cpp | 9 ++ .../share/services/diagnosticCommand.hpp | 24 ++++- .../dcmd/compiler/PerfMapTest.java | 87 +++++++++++++++++++ 8 files changed, 170 insertions(+), 2 deletions(-) create mode 100644 test/hotspot/jtreg/serviceability/dcmd/compiler/PerfMapTest.java diff --git a/src/hotspot/os/linux/globals_linux.hpp b/src/hotspot/os/linux/globals_linux.hpp index 0e5c209c94008..047901c6efae3 100644 --- a/src/hotspot/os/linux/globals_linux.hpp +++ b/src/hotspot/os/linux/globals_linux.hpp @@ -79,7 +79,10 @@ "be dumped into the corefile.") \ \ product(bool, UseCpuAllocPath, false, DIAGNOSTIC, \ - "Use CPU_ALLOC code path in os::active_processor_count ") + "Use CPU_ALLOC code path in os::active_processor_count ") \ + \ + product(bool, DumpPerfMapAtExit, false, DIAGNOSTIC, \ + "Write map file for Linux perf tool at exit") // end of RUNTIME_OS_FLAGS diff --git a/src/hotspot/os/linux/os_linux.cpp b/src/hotspot/os/linux/os_linux.cpp index c9d07dfb0fe98..e7e332c16b580 100644 --- a/src/hotspot/os/linux/os_linux.cpp +++ b/src/hotspot/os/linux/os_linux.cpp @@ -4635,6 +4635,12 @@ jint os::init_2(void) { set_coredump_filter(FILE_BACKED_SHARED_BIT); } + if (DumpPerfMapAtExit && FLAG_IS_DEFAULT(UseCodeCacheFlushing)) { + // Disable code cache flushing to ensure the map file written at + // exit contains all nmethods generated during execution. + FLAG_SET_DEFAULT(UseCodeCacheFlushing, false); + } + return JNI_OK; } diff --git a/src/hotspot/share/code/codeCache.cpp b/src/hotspot/share/code/codeCache.cpp index 3b589844232a3..7e4c88e65e27f 100644 --- a/src/hotspot/share/code/codeCache.cpp +++ b/src/hotspot/share/code/codeCache.cpp @@ -1559,6 +1559,34 @@ void CodeCache::log_state(outputStream* st) { unallocated_capacity()); } +#ifdef LINUX +void CodeCache::write_perf_map() { + MutexLocker mu(CodeCache_lock, Mutex::_no_safepoint_check_flag); + + // Perf expects to find the map file at /tmp/perf-.map. + char fname[32]; + jio_snprintf(fname, sizeof(fname), "/tmp/perf-%d.map", os::current_process_id()); + + fileStream fs(fname, "w"); + if (!fs.is_open()) { + log_warning(codecache)("Failed to create %s for perf map", fname); + return; + } + + AllCodeBlobsIterator iter(AllCodeBlobsIterator::only_alive_and_not_unloading); + while (iter.next()) { + CodeBlob *cb = iter.method(); + ResourceMark rm; + const char* method_name = + cb->is_compiled() ? cb->as_compiled_method()->method()->external_name() + : cb->name(); + fs.print_cr(INTPTR_FORMAT " " INTPTR_FORMAT " %s", + (intptr_t)cb->code_begin(), (intptr_t)cb->code_size(), + method_name); + } +} +#endif // LINUX + //---< BEGIN >--- CodeHeap State Analytics. void CodeCache::aggregate(outputStream *out, size_t granularity) { diff --git a/src/hotspot/share/code/codeCache.hpp b/src/hotspot/share/code/codeCache.hpp index 4a3e29810f389..959396f8699ef 100644 --- a/src/hotspot/share/code/codeCache.hpp +++ b/src/hotspot/share/code/codeCache.hpp @@ -191,6 +191,7 @@ class CodeCache : AllStatic { static void print_trace(const char* event, CodeBlob* cb, int size = 0) PRODUCT_RETURN; static void print_summary(outputStream* st, bool detailed = true); // Prints a summary of the code cache usage static void log_state(outputStream* st); + LINUX_ONLY(static void write_perf_map();) static const char* get_code_heap_name(int code_blob_type) { return (heap_available(code_blob_type) ? get_code_heap(code_blob_type)->name() : "Unused"); } static void report_codemem_full(int code_blob_type, bool print); @@ -409,7 +410,13 @@ struct NMethodFilter { static const GrowableArray* heaps() { return CodeCache::nmethod_heaps(); } }; +struct AllCodeBlobsFilter { + static bool apply(CodeBlob* cb) { return true; } + static const GrowableArray* heaps() { return CodeCache::heaps(); } +}; + typedef CodeBlobIterator CompiledMethodIterator; typedef CodeBlobIterator NMethodIterator; +typedef CodeBlobIterator AllCodeBlobsIterator; #endif // SHARE_CODE_CODECACHE_HPP diff --git a/src/hotspot/share/runtime/java.cpp b/src/hotspot/share/runtime/java.cpp index 3e0a274a247ec..ca559aca4dff3 100644 --- a/src/hotspot/share/runtime/java.cpp +++ b/src/hotspot/share/runtime/java.cpp @@ -478,6 +478,12 @@ void before_exit(JavaThread* thread) { BytecodeHistogram::print(); } +#ifdef LINUX + if (DumpPerfMapAtExit) { + CodeCache::write_perf_map(); + } +#endif + if (JvmtiExport::should_post_thread_life()) { JvmtiExport::post_thread_end(thread); } diff --git a/src/hotspot/share/services/diagnosticCommand.cpp b/src/hotspot/share/services/diagnosticCommand.cpp index 8511156b08ba0..b0be7c312b994 100644 --- a/src/hotspot/share/services/diagnosticCommand.cpp +++ b/src/hotspot/share/services/diagnosticCommand.cpp @@ -110,6 +110,9 @@ void DCmdRegistrant::register_dcmds(){ DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl(full_export, true, false)); DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl(full_export, true, false)); DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl(full_export, true, false)); +#ifdef LINUX + DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl(full_export, true, false)); +#endif // LINUX DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl(full_export, true, false)); DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl(full_export, true, false)); @@ -893,6 +896,12 @@ void CodeCacheDCmd::execute(DCmdSource source, TRAPS) { CodeCache::print_layout(output()); } +#ifdef LINUX +void PerfMapDCmd::execute(DCmdSource source, TRAPS) { + CodeCache::write_perf_map(); +} +#endif // LINUX + //---< BEGIN >--- CodeHeap State Analytics. CodeHeapAnalyticsDCmd::CodeHeapAnalyticsDCmd(outputStream* output, bool heap) : DCmdWithParser(output, heap), diff --git a/src/hotspot/share/services/diagnosticCommand.hpp b/src/hotspot/share/services/diagnosticCommand.hpp index d037b00774a34..16cd14159036c 100644 --- a/src/hotspot/share/services/diagnosticCommand.hpp +++ b/src/hotspot/share/services/diagnosticCommand.hpp @@ -577,6 +577,29 @@ class CompileQueueDCmd : public DCmd { virtual void execute(DCmdSource source, TRAPS); }; +#ifdef LINUX +class PerfMapDCmd : public DCmd { +public: + PerfMapDCmd(outputStream* output, bool heap) : DCmd(output, heap) {} + static const char* name() { + return "Compiler.perfmap"; + } + static const char* description() { + return "Write map file for Linux perf tool."; + } + static const char* impact() { + return "Low"; + } + static const JavaPermission permission() { + JavaPermission p = {"java.lang.management.ManagementPermission", + "monitor", NULL}; + return p; + } + static int num_arguments() { return 0; } + virtual void execute(DCmdSource source, TRAPS); +}; +#endif // LINUX + class CodeListDCmd : public DCmd { public: CodeListDCmd(outputStream* output, bool heap) : DCmd(output, heap) {} @@ -598,7 +621,6 @@ class CodeListDCmd : public DCmd { virtual void execute(DCmdSource source, TRAPS); }; - class CodeCacheDCmd : public DCmd { public: CodeCacheDCmd(outputStream* output, bool heap) : DCmd(output, heap) {} diff --git a/test/hotspot/jtreg/serviceability/dcmd/compiler/PerfMapTest.java b/test/hotspot/jtreg/serviceability/dcmd/compiler/PerfMapTest.java new file mode 100644 index 0000000000000..f4da5e979e300 --- /dev/null +++ b/test/hotspot/jtreg/serviceability/dcmd/compiler/PerfMapTest.java @@ -0,0 +1,87 @@ +/* + * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, Arm Limited. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test PerfMapTest + * @bug 8254723 + * @requires os.family == "linux" + * @library /test/lib + * @modules java.base/jdk.internal.misc + * java.compiler + * java.management + * jdk.internal.jvmstat/sun.jvmstat.monitor + * @run testng/othervm PerfMapTest + * @summary Test of diagnostic command Compiler.perfmap + */ + +import org.testng.annotations.Test; +import org.testng.Assert; + +import jdk.test.lib.process.OutputAnalyzer; +import jdk.test.lib.dcmd.CommandExecutor; +import jdk.test.lib.dcmd.JMXExecutor; + +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +/** + * Call jcmd Compiler.perfmap and check the output file has the expected + * format. + */ +public class PerfMapTest { + + static final Pattern LINE_PATTERN = + Pattern.compile("^((?:0x)?\\p{XDigit}+)\\s+((?:0x)?\\p{XDigit}+)\\s+(.*)$"); + + public void run(CommandExecutor executor) { + OutputAnalyzer output = executor.execute("Compiler.perfmap"); + + output.stderrShouldBeEmpty(); + output.stdoutShouldBeEmpty(); + + final long pid = ProcessHandle.current().pid(); + final Path path = Paths.get(String.format("/tmp/perf-%d.map", pid)); + + Assert.assertTrue(Files.exists(path)); + + // Sanity check the file contents + try { + for (String entry : Files.readAllLines(path)) { + Matcher m = LINE_PATTERN.matcher(entry); + Assert.assertTrue(m.matches(), "Invalid file format: " + entry); + } + } catch (IOException e) { + Assert.fail(e.toString()); + } + } + + @Test + public void jmx() { + run(new JMXExecutor()); + } +} From fe4e6b3e90e05e9dfb9ee1da3726315c6c379f41 Mon Sep 17 00:00:00 2001 From: Prasanta Sadhukhan Date: Tue, 3 Nov 2020 03:16:36 +0000 Subject: [PATCH 15/32] 8196089: javax/swing/Action/8133039/bug8133039.java fails Reviewed-by: jdv --- test/jdk/ProblemList.txt | 1 - test/jdk/javax/swing/Action/8133039/bug8133039.java | 3 ++- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/test/jdk/ProblemList.txt b/test/jdk/ProblemList.txt index f2a94d5975dfc..7c460a7332ef9 100644 --- a/test/jdk/ProblemList.txt +++ b/test/jdk/ProblemList.txt @@ -746,7 +746,6 @@ javax/swing/JSplitPane/4201995/bug4201995.java 8079127 generic-all javax/swing/JTree/DnD/LastNodeLowerHalfDrop.java 8159131 linux-all javax/swing/JTree/4633594/JTreeFocusTest.java 8173125 macosx-all javax/swing/AbstractButton/6711682/bug6711682.java 8060765 windows-all,macosx-all -javax/swing/Action/8133039/bug8133039.java 8196089 windows-all,macosx-all javax/swing/JComboBox/6559152/bug6559152.java 8196090 windows-all,macosx-all javax/swing/JComboBox/8032878/bug8032878.java 8196092,8196439 windows-all,macosx-all,linux-all javax/swing/JComboBox/8072767/bug8072767.java 8196093 windows-all,macosx-all diff --git a/test/jdk/javax/swing/Action/8133039/bug8133039.java b/test/jdk/javax/swing/Action/8133039/bug8133039.java index 766a71204c0ea..f36b1b1ab10f8 100644 --- a/test/jdk/javax/swing/Action/8133039/bug8133039.java +++ b/test/jdk/javax/swing/Action/8133039/bug8133039.java @@ -89,7 +89,7 @@ private static void testPopupAction() throws Exception { SwingUtilities.invokeAndWait(bug8133039::createAndShowGUI); Robot robot = new Robot(); - robot.setAutoDelay(50); + robot.setAutoDelay(100); robot.waitForIdle(); robot.keyPress(KeyEvent.VK_A); @@ -130,6 +130,7 @@ private static void createAndShowGUI() { comboBox.getActionMap().put("showPopup", showPopupAction); frame.getContentPane().add(comboBox); + frame.setLocationRelativeTo(null); frame.setVisible(true); } From 9beb866b1253f02a929da86d7e1f1f67f1e54862 Mon Sep 17 00:00:00 2001 From: Jayathirth D V Date: Tue, 3 Nov 2020 06:38:22 +0000 Subject: [PATCH 16/32] 8233561: [TESTBUG] Swing text test bug8014863.java fails on macos Reviewed-by: psadhukhan --- test/jdk/ProblemList.txt | 1 - test/jdk/javax/swing/text/View/8014863/bug8014863.java | 5 +++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/test/jdk/ProblemList.txt b/test/jdk/ProblemList.txt index 7c460a7332ef9..6b120142b55bd 100644 --- a/test/jdk/ProblemList.txt +++ b/test/jdk/ProblemList.txt @@ -778,7 +778,6 @@ javax/swing/dnd/8139050/NativeErrorsInTableDnD.java 8202765 macosx-all,linux-al javax/swing/Popup/TaskbarPositionTest.java 8065097 macosx-all,linux-all javax/swing/JEditorPane/6917744/bug6917744.java 8213124 macosx-all javax/swing/JTree/6263446/bug6263446.java 8213125 macosx-all -javax/swing/text/View/8014863/bug8014863.java 8233561 macosx-all javax/swing/text/StyledEditorKit/4506788/bug4506788.java 8233562 macosx-all javax/swing/JRootPane/4670486/bug4670486.java 8042381 macosx-all javax/swing/JRadioButton/ButtonGroupFocus/ButtonGroupFocusTest.java 8233555 macosx-all diff --git a/test/jdk/javax/swing/text/View/8014863/bug8014863.java b/test/jdk/javax/swing/text/View/8014863/bug8014863.java index 30e54b69c69ed..fba4fd255c276 100644 --- a/test/jdk/javax/swing/text/View/8014863/bug8014863.java +++ b/test/jdk/javax/swing/text/View/8014863/bug8014863.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2007, 2020, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -59,7 +59,7 @@ public class bug8014863 { public static void main(String[] args) throws Exception { robot = new Robot(); - robot.setAutoDelay(50); + robot.setAutoDelay(100); glyphViews = new ArrayList(); createAndShowGUI(text1); @@ -152,6 +152,7 @@ public void run() { frame.add(editorPane); frame.setSize(200, 200); + frame.setLocationRelativeTo(null); frame.setVisible(true); } }); From f0eeca90804ca2b90c15290f8df07c95dd468363 Mon Sep 17 00:00:00 2001 From: Aleksey Shipilev Date: Tue, 3 Nov 2020 07:04:28 +0000 Subject: [PATCH 17/32] 8255718: Zero: VM should know it runs in interpreter-only mode Reviewed-by: andrew, coleenp --- src/hotspot/share/runtime/arguments.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/hotspot/share/runtime/arguments.cpp b/src/hotspot/share/runtime/arguments.cpp index 088fbe2885e8f..38f0c6c9dc807 100644 --- a/src/hotspot/share/runtime/arguments.cpp +++ b/src/hotspot/share/runtime/arguments.cpp @@ -3213,6 +3213,11 @@ jint Arguments::finalize_vm_init_args(bool patch_mod_javabase) { set_mode_flags(_int); } +#ifdef ZERO + // Zero always runs in interpreted mode + set_mode_flags(_int); +#endif + // eventually fix up InitialTenuringThreshold if only MaxTenuringThreshold is set if (FLAG_IS_DEFAULT(InitialTenuringThreshold) && (InitialTenuringThreshold > MaxTenuringThreshold)) { FLAG_SET_ERGO(InitialTenuringThreshold, MaxTenuringThreshold); From 6d36b4bb799653af7351bfcc4c54fab156562578 Mon Sep 17 00:00:00 2001 From: Aleksey Shipilev Date: Tue, 3 Nov 2020 07:06:14 +0000 Subject: [PATCH 18/32] 8255743: Relax SIGFPE match in in runtime/ErrorHandling/SecondaryErrorTest.java Reviewed-by: stuefe --- .../hotspot/jtreg/runtime/ErrorHandling/SecondaryErrorTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/hotspot/jtreg/runtime/ErrorHandling/SecondaryErrorTest.java b/test/hotspot/jtreg/runtime/ErrorHandling/SecondaryErrorTest.java index 494158b5d9110..7790d069ac3d3 100644 --- a/test/hotspot/jtreg/runtime/ErrorHandling/SecondaryErrorTest.java +++ b/test/hotspot/jtreg/runtime/ErrorHandling/SecondaryErrorTest.java @@ -60,7 +60,7 @@ public static void main(String[] args) throws Exception { // we should have crashed with a SIGFPE output_detail.shouldMatch("# A fatal error has been detected by the Java Runtime Environment:.*"); - output_detail.shouldMatch("# +SIGFPE.*"); + output_detail.shouldMatch("#.+SIGFPE.*"); // extract hs-err file String hs_err_file = output_detail.firstMatch("# *(\\S*hs_err_pid\\d+\\.log)", 1); From e7a2d5c8438446244bed31aa186f81b742b8d72c Mon Sep 17 00:00:00 2001 From: Thomas Stuefe Date: Tue, 3 Nov 2020 07:16:45 +0000 Subject: [PATCH 19/32] 8252533: Signal handlers should run with synchronous error signals unblocked Reviewed-by: gziemski, dholmes --- src/hotspot/os/posix/signals_posix.cpp | 104 +++++++++++++------------ src/hotspot/os/posix/signals_posix.hpp | 7 +- src/hotspot/os/posix/vmError_posix.cpp | 17 +--- 3 files changed, 61 insertions(+), 67 deletions(-) diff --git a/src/hotspot/os/posix/signals_posix.cpp b/src/hotspot/os/posix/signals_posix.cpp index 4eea0664566e5..6b248a969813d 100644 --- a/src/hotspot/os/posix/signals_posix.cpp +++ b/src/hotspot/os/posix/signals_posix.cpp @@ -451,46 +451,62 @@ extern "C" JNIEXPORT int JVM_handle_linux_signal(int signo, siginfo_t* siginfo, int abort_if_unrecognized); #endif -#if defined(AIX) -// Set thread signal mask (for some reason on AIX sigthreadmask() seems -// to be the thing to call; documentation is not terribly clear about whether -// pthread_sigmask also works, and if it does, whether it does the same. -bool set_thread_signal_mask(int how, const sigset_t* set, sigset_t* oset) { - const int rc = ::pthread_sigmask(how, set, oset); - // return value semantics differ slightly for error case: - // pthread_sigmask returns error number, sigthreadmask -1 and sets global errno - // (so, pthread_sigmask is more theadsafe for error handling) - // But success is always 0. - return rc == 0 ? true : false; +///// Synchronous (non-deferrable) error signals (ILL, SEGV, FPE, BUS, TRAP): + +// These signals are special because they cannot be deferred and, if they +// happen while delivery is blocked for the receiving thread, will cause UB +// (in practice typically resulting in sudden process deaths or hangs, see +// JDK-8252533). So we must take care never to block them when we cannot be +// absolutely sure they won't happen. In practice, this is always. +// +// Relevant Posix quote: +// "The behavior of a process is undefined after it ignores a SIGFPE, SIGILL, +// SIGSEGV, or SIGBUS signal that was not generated by kill(), sigqueue(), or +// raise()." +// +// We also include SIGTRAP in that list of never-to-block-signals. While not +// mentioned by the Posix documentation, in our (SAPs) experience blocking it +// causes similar problems. Beside, during normal operation - outside of error +// handling - SIGTRAP may be used for implicit NULL checking, so it makes sense +// to never block it. +// +// We deal with those signals in two ways: +// - we just never explicitly block them, which includes not accidentally blocking +// them via sa_mask when establishing signal handlers. +// - as an additional safety measure, at the entrance of a signal handler, we +// unblock them explicitly. + +static void add_error_signals_to_set(sigset_t* set) { + sigaddset(set, SIGILL); + sigaddset(set, SIGBUS); + sigaddset(set, SIGFPE); + sigaddset(set, SIGSEGV); + sigaddset(set, SIGTRAP); +} + +static void remove_error_signals_from_set(sigset_t* set) { + sigdelset(set, SIGILL); + sigdelset(set, SIGBUS); + sigdelset(set, SIGFPE); + sigdelset(set, SIGSEGV); + sigdelset(set, SIGTRAP); } -// Function to unblock all signals which are, according -// to POSIX, typical program error signals. If they happen while being blocked, -// they typically will bring down the process immediately. -bool unblock_program_error_signals() { +// Unblock all signals whose delivery cannot be deferred and which, if they happen +// while delivery is blocked, would cause crashes or hangs (JDK-8252533). +void PosixSignals::unblock_error_signals() { sigset_t set; sigemptyset(&set); - sigaddset(&set, SIGILL); - sigaddset(&set, SIGBUS); - sigaddset(&set, SIGFPE); - sigaddset(&set, SIGSEGV); - return set_thread_signal_mask(SIG_UNBLOCK, &set, NULL); + add_error_signals_to_set(&set); + ::pthread_sigmask(SIG_UNBLOCK, &set, NULL); } -#endif - // Renamed from 'signalHandler' to avoid collision with other shared libs. static void javaSignalHandler(int sig, siginfo_t* info, void* uc) { assert(info != NULL && uc != NULL, "it must be old kernel"); -// TODO: reconcile the differences between Linux/BSD vs AIX here! -#if defined(AIX) - // Never leave program error signals blocked; - // on all our platforms they would bring down the process immediately when - // getting raised while being blocked. - unblock_program_error_signals(); -#endif + PosixSignals::unblock_error_signals(); int orig_errno = errno; // Preserve errno value over signal handler. #if defined(BSD) @@ -504,6 +520,9 @@ static void javaSignalHandler(int sig, siginfo_t* info, void* uc) { } static void UserHandler(int sig, void *siginfo, void *context) { + + PosixSignals::unblock_error_signals(); + // Ctrl-C is pressed during error reporting, likely because the error // handler fails to abort. Let VM die immediately. if (sig == SIGINT && VMError::is_error_reported()) { @@ -702,23 +721,7 @@ void* os::signal(int signal_number, void* handler) { struct sigaction sigAct, oldSigAct; sigfillset(&(sigAct.sa_mask)); - -#if defined(AIX) - // Do not block out synchronous signals in the signal handler. - // Blocking synchronous signals only makes sense if you can really - // be sure that those signals won't happen during signal handling, - // when the blocking applies. Normal signal handlers are lean and - // do not cause signals. But our signal handlers tend to be "risky" - // - secondary SIGSEGV, SIGILL, SIGBUS' may and do happen. - // On AIX, PASE there was a case where a SIGSEGV happened, followed - // by a SIGILL, which was blocked due to the signal mask. The process - // just hung forever. Better to crash from a secondary signal than to hang. - sigdelset(&(sigAct.sa_mask), SIGSEGV); - sigdelset(&(sigAct.sa_mask), SIGBUS); - sigdelset(&(sigAct.sa_mask), SIGILL); - sigdelset(&(sigAct.sa_mask), SIGFPE); - sigdelset(&(sigAct.sa_mask), SIGTRAP); -#endif + remove_error_signals_from_set(&(sigAct.sa_mask)); sigAct.sa_flags = SA_RESTART|SA_SIGINFO; sigAct.sa_handler = CAST_TO_FN_PTR(sa_handler_t, handler); @@ -1099,6 +1102,7 @@ void set_signal_handler(int sig, bool set_installed) { struct sigaction sigAct; sigfillset(&(sigAct.sa_mask)); + remove_error_signals_from_set(&(sigAct.sa_mask)); sigAct.sa_handler = SIG_DFL; if (!set_installed) { sigAct.sa_flags = SA_SIGINFO|SA_RESTART; @@ -1303,10 +1307,6 @@ bool PosixSignals::is_sig_ignored(int sig) { } } -int PosixSignals::unblock_thread_signal_mask(const sigset_t *set) { - return pthread_sigmask(SIG_UNBLOCK, set, NULL); -} - address PosixSignals::ucontext_get_pc(const ucontext_t* ctx) { #if defined(AIX) return os::Aix::ucontext_get_pc(ctx); @@ -1470,10 +1470,13 @@ static void suspend_save_context(OSThread *osthread, siginfo_t* siginfo, ucontex // Currently only ever called on the VMThread and JavaThreads (PC sampling) // static void SR_handler(int sig, siginfo_t* siginfo, ucontext_t* context) { + // Save and restore errno to avoid confusing native code with EINTR // after sigsuspend. int old_errno = errno; + PosixSignals::unblock_error_signals(); + Thread* thread = Thread::current_or_null_safe(); assert(thread != NULL, "Missing current thread in SR_handler"); @@ -1567,6 +1570,7 @@ int PosixSignals::SR_initialize() { // SR_signum is blocked by default. pthread_sigmask(SIG_BLOCK, NULL, &act.sa_mask); + remove_error_signals_from_set(&(act.sa_mask)); if (sigaction(SR_signum, &act, 0) == -1) { return -1; diff --git a/src/hotspot/os/posix/signals_posix.hpp b/src/hotspot/os/posix/signals_posix.hpp index a2f7d955e1461..7194bd6c57397 100644 --- a/src/hotspot/os/posix/signals_posix.hpp +++ b/src/hotspot/os/posix/signals_posix.hpp @@ -44,8 +44,6 @@ class PosixSignals : public AllStatic { static bool is_sig_ignored(int sig); static void signal_sets_init(); - // unblocks the signal masks for current thread - static int unblock_thread_signal_mask(const sigset_t *set); static void hotspot_sigmask(Thread* thread); static void print_signal_handler(outputStream* st, int sig, char* buf, size_t buflen); @@ -64,6 +62,11 @@ class PosixSignals : public AllStatic { // sun.misc.Signal support static void jdk_misc_signal_init(); + + // Unblock all signals whose delivery cannot be deferred and which, if they happen + // while delivery is blocked, would cause crashes or hangs (see JDK-8252533). + static void unblock_error_signals(); + }; #endif // OS_POSIX_SIGNALS_POSIX_HPP diff --git a/src/hotspot/os/posix/vmError_posix.cpp b/src/hotspot/os/posix/vmError_posix.cpp index 9c83d263e7184..bde46e2874179 100644 --- a/src/hotspot/os/posix/vmError_posix.cpp +++ b/src/hotspot/os/posix/vmError_posix.cpp @@ -101,15 +101,8 @@ address VMError::get_resetted_sighandler(int sig) { } static void crash_handler(int sig, siginfo_t* info, void* ucVoid) { - // unmask current signal - sigset_t newset; - sigemptyset(&newset); - sigaddset(&newset, sig); - // also unmask other synchronous signals - for (int i = 0; i < NUM_SIGNALS; i++) { - sigaddset(&newset, SIGNALS[i]); - } - PosixSignals::unblock_thread_signal_mask(&newset); + + PosixSignals::unblock_error_signals(); // support safefetch faults in error handling ucontext_t* const uc = (ucontext_t*) ucVoid; @@ -139,16 +132,10 @@ static void crash_handler(int sig, siginfo_t* info, void* ucVoid) { } void VMError::reset_signal_handlers() { - // install signal handlers for all synchronous program error signals - sigset_t newset; - sigemptyset(&newset); - for (int i = 0; i < NUM_SIGNALS; i++) { save_signal(i, SIGNALS[i]); os::signal(SIGNALS[i], CAST_FROM_FN_PTR(void *, crash_handler)); - sigaddset(&newset, SIGNALS[i]); } - PosixSignals::unblock_thread_signal_mask(&newset); } // Write a hint to the stream in case siginfo relates to a segv/bus error From 15805741f1cd93a4aa5d96ca5c4420d3fc884459 Mon Sep 17 00:00:00 2001 From: Tobias Hartmann Date: Tue, 3 Nov 2020 07:17:58 +0000 Subject: [PATCH 20/32] 8255672: Replace PhaseTransform::eqv by pointer equality check Reviewed-by: chagedorn, redestad, kvn --- src/hotspot/share/adlc/output_c.cpp | 7 +-- src/hotspot/share/opto/addnode.cpp | 18 +++--- src/hotspot/share/opto/callnode.cpp | 8 ++- src/hotspot/share/opto/cfgnode.cpp | 18 +++--- src/hotspot/share/opto/divnode.cpp | 28 +++++---- src/hotspot/share/opto/memnode.cpp | 6 +- src/hotspot/share/opto/movenode.cpp | 30 +++++----- src/hotspot/share/opto/mulnode.cpp | 19 +++--- src/hotspot/share/opto/phaseX.hpp | 5 -- src/hotspot/share/opto/subnode.cpp | 92 +++++++++++++++-------------- 10 files changed, 123 insertions(+), 108 deletions(-) diff --git a/src/hotspot/share/adlc/output_c.cpp b/src/hotspot/share/adlc/output_c.cpp index 82a3a11bc4619..f4e6e2956039e 100644 --- a/src/hotspot/share/adlc/output_c.cpp +++ b/src/hotspot/share/adlc/output_c.cpp @@ -1150,10 +1150,9 @@ static void check_peepconstraints(FILE *fp, FormDict &globals, PeepMatch *pmatch // // Check for equivalence // - // fprintf(fp, "phase->eqv( "); - // fprintf(fp, "inst%d->in(%d+%d) /* %s */, inst%d->in(%d+%d) /* %s */", - // left_index, left_op_base, left_op_index, left_op, - // right_index, right_op_base, right_op_index, right_op ); + // fprintf(fp, "(inst%d->_opnds[%d]->reg(ra_,inst%d%s) /* %d.%s */ == /* %d.%s */ inst%d->_opnds[%d]->reg(ra_,inst%d%s)", + // left_index, left_op_index, left_index, left_reg_index, left_index, left_op + // right_index, right_op, right_index, right_op_index, right_index, right_reg_index); // fprintf(fp, ")"); // switch( left_interface_type ) { diff --git a/src/hotspot/share/opto/addnode.cpp b/src/hotspot/share/opto/addnode.cpp index 2b66fb79457ea..ed3690e59b5c8 100644 --- a/src/hotspot/share/opto/addnode.cpp +++ b/src/hotspot/share/opto/addnode.cpp @@ -328,10 +328,9 @@ Node *AddINode::Ideal(PhaseGVN *phase, bool can_reshape) { //------------------------------Identity--------------------------------------- // Fold (x-y)+y OR y+(x-y) into x Node* AddINode::Identity(PhaseGVN* phase) { - if( in(1)->Opcode() == Op_SubI && phase->eqv(in(1)->in(2),in(2)) ) { + if (in(1)->Opcode() == Op_SubI && in(1)->in(2) == in(2)) { return in(1)->in(1); - } - else if( in(2)->Opcode() == Op_SubI && phase->eqv(in(2)->in(2),in(1)) ) { + } else if (in(2)->Opcode() == Op_SubI && in(2)->in(2) == in(1)) { return in(2)->in(1); } return AddNode::Identity(phase); @@ -445,10 +444,9 @@ Node *AddLNode::Ideal(PhaseGVN *phase, bool can_reshape) { //------------------------------Identity--------------------------------------- // Fold (x-y)+y OR y+(x-y) into x Node* AddLNode::Identity(PhaseGVN* phase) { - if( in(1)->Opcode() == Op_SubL && phase->eqv(in(1)->in(2),in(2)) ) { + if (in(1)->Opcode() == Op_SubL && in(1)->in(2) == in(2)) { return in(1)->in(1); - } - else if( in(2)->Opcode() == Op_SubL && phase->eqv(in(2)->in(2),in(1)) ) { + } else if (in(2)->Opcode() == Op_SubL && in(2)->in(2) == in(1)) { return in(2)->in(1); } return AddNode::Identity(phase); @@ -736,7 +734,7 @@ uint AddPNode::match_edge(uint idx) const { //------------------------------Identity--------------------------------------- Node* OrINode::Identity(PhaseGVN* phase) { // x | x => x - if (phase->eqv(in(1), in(2))) { + if (in(1) == in(2)) { return in(1); } @@ -823,7 +821,7 @@ const Type *OrINode::add_ring( const Type *t0, const Type *t1 ) const { //------------------------------Identity--------------------------------------- Node* OrLNode::Identity(PhaseGVN* phase) { // x | x => x - if (phase->eqv(in(1), in(2))) { + if (in(1) == in(2)) { return in(1); } @@ -1078,7 +1076,7 @@ Node *MinINode::Ideal(PhaseGVN *phase, bool can_reshape) { // Transform MIN2(x + c0, MIN2(x + c1, z)) into MIN2(x + MIN2(c0, c1), z) // if x == y and the additions can't overflow. - if (phase->eqv(x,y) && tx != NULL && + if (x == y && tx != NULL && !can_overflow(tx, x_off) && !can_overflow(tx, y_off)) { return new MinINode(phase->transform(new AddINode(x, phase->intcon(MIN2(x_off, y_off)))), r->in(2)); @@ -1086,7 +1084,7 @@ Node *MinINode::Ideal(PhaseGVN *phase, bool can_reshape) { } else { // Transform MIN2(x + c0, y + c1) into x + MIN2(c0, c1) // if x == y and the additions can't overflow. - if (phase->eqv(x,y) && tx != NULL && + if (x == y && tx != NULL && !can_overflow(tx, x_off) && !can_overflow(tx, y_off)) { return new AddINode(x,phase->intcon(MIN2(x_off,y_off))); diff --git a/src/hotspot/share/opto/callnode.cpp b/src/hotspot/share/opto/callnode.cpp index b179e42d8eb2c..78a632bf8aca0 100644 --- a/src/hotspot/share/opto/callnode.cpp +++ b/src/hotspot/share/opto/callnode.cpp @@ -1224,8 +1224,12 @@ Node* SafePointNode::Identity(PhaseGVN* phase) { //------------------------------Value------------------------------------------ const Type* SafePointNode::Value(PhaseGVN* phase) const { - if( phase->type(in(0)) == Type::TOP ) return Type::TOP; - if( phase->eqv( in(0), this ) ) return Type::TOP; // Dead infinite loop + if (phase->type(in(0)) == Type::TOP) { + return Type::TOP; + } + if (in(0) == this) { + return Type::TOP; // Dead infinite loop + } return Type::CONTROL; } diff --git a/src/hotspot/share/opto/cfgnode.cpp b/src/hotspot/share/opto/cfgnode.cpp index 57807e23a13ad..ad527082e6336 100644 --- a/src/hotspot/share/opto/cfgnode.cpp +++ b/src/hotspot/share/opto/cfgnode.cpp @@ -344,7 +344,7 @@ bool RegionNode::is_possible_unsafe_loop(const PhaseGVN* phase) const { Node* n = raw_out(i); if (n != NULL && n->is_Phi()) { PhiNode* phi = n->as_Phi(); - assert(phase->eqv(phi->in(0), this), "sanity check phi"); + assert(phi->in(0) == this, "sanity check phi"); if (phi->outcnt() == 0) { continue; // Safe case - no loops } @@ -383,7 +383,7 @@ bool RegionNode::is_unreachable_from_root(const PhaseGVN* phase) const { for (uint i = 0; i < max; i++) { Node* m = n->raw_out(i); if (m != NULL && m->is_CFG()) { - if (phase->eqv(m, this)) { + if (m == this) { return false; // We reached the Region node - it is not dead. } if (!visited.test_set(m->_idx)) @@ -568,7 +568,7 @@ Node *RegionNode::Ideal(PhaseGVN *phase, bool can_reshape) { for (j = outs(); has_out(j); j++) { Node *n = out(j); if( n->is_Phi() ) { - assert( igvn->eqv(n->in(0), this), "" ); + assert(n->in(0) == this, ""); assert( n->req() == 2 && n->in(1) != NULL, "Only one data input expected" ); // Break dead loop data path. // Eagerly replace phis with top to avoid regionless phis. @@ -619,7 +619,7 @@ Node *RegionNode::Ideal(PhaseGVN *phase, bool can_reshape) { // The fallthrough case since we already checked dead loops above. parent_ctrl = in(1); assert(parent_ctrl != NULL, "Region is a copy of some non-null control"); - assert(!igvn->eqv(parent_ctrl, this), "Close dead loop"); + assert(parent_ctrl != this, "Close dead loop"); } if (!add_to_worklist) igvn->add_users_to_worklist(this); // Check for further allowed opts @@ -641,7 +641,7 @@ Node *RegionNode::Ideal(PhaseGVN *phase, bool can_reshape) { igvn->replace_node(n, in); } else if( n->is_Region() ) { // Update all incoming edges - assert( !igvn->eqv(n, this), "Must be removed from DefUse edges"); + assert(n != this, "Must be removed from DefUse edges"); uint uses_found = 0; for( uint k=1; k < n->req(); k++ ) { if( n->in(k) == this ) { @@ -654,12 +654,12 @@ Node *RegionNode::Ideal(PhaseGVN *phase, bool can_reshape) { } } else { - assert( igvn->eqv(n->in(0), this), "Expect RegionNode to be control parent"); + assert(n->in(0) == this, "Expect RegionNode to be control parent"); n->set_req(0, parent_ctrl); } #ifdef ASSERT for( uint k=0; k < n->req(); k++ ) { - assert( !igvn->eqv(n->in(k), this), "All uses of RegionNode should be gone"); + assert(n->in(k) != this, "All uses of RegionNode should be gone"); } #endif } @@ -2078,7 +2078,7 @@ Node *PhiNode::Ideal(PhaseGVN *phase, bool can_reshape) { if (can_reshape) { opt = split_flow_path(phase, this); // This optimization only modifies phi - don't need to check for dead loop. - assert(opt == NULL || phase->eqv(opt, this), "do not elide phi"); + assert(opt == NULL || opt == this, "do not elide phi"); if (opt != NULL) return opt; } @@ -2194,7 +2194,7 @@ Node *PhiNode::Ideal(PhaseGVN *phase, bool can_reshape) { if (ii->is_MergeMem()) { MergeMemNode* n = ii->as_MergeMem(); merge_width = MAX2(merge_width, n->req()); - saw_self = saw_self || phase->eqv(n->base_memory(), this); + saw_self = saw_self || (n->base_memory() == this); } } diff --git a/src/hotspot/share/opto/divnode.cpp b/src/hotspot/share/opto/divnode.cpp index 968b1ddd5f3b8..a79f57f8cb407 100644 --- a/src/hotspot/share/opto/divnode.cpp +++ b/src/hotspot/share/opto/divnode.cpp @@ -505,8 +505,9 @@ const Type* DivINode::Value(PhaseGVN* phase) const { if( t2 == Type::TOP ) return Type::TOP; // x/x == 1 since we always generate the dynamic divisor check for 0. - if( phase->eqv( in(1), in(2) ) ) + if (in(1) == in(2)) { return TypeInt::ONE; + } // Either input is BOTTOM ==> the result is the local BOTTOM const Type *bot = bottom_type(); @@ -610,8 +611,9 @@ const Type* DivLNode::Value(PhaseGVN* phase) const { if( t2 == Type::TOP ) return Type::TOP; // x/x == 1 since we always generate the dynamic divisor check for 0. - if( phase->eqv( in(1), in(2) ) ) + if (in(1) == in(2)) { return TypeLong::ONE; + } // Either input is BOTTOM ==> the result is the local BOTTOM const Type *bot = bottom_type(); @@ -685,9 +687,10 @@ const Type* DivFNode::Value(PhaseGVN* phase) const { // x/x == 1, we ignore 0/0. // Note: if t1 and t2 are zero then result is NaN (JVMS page 213) // Does not work for variables because of NaN's - if( phase->eqv( in(1), in(2) ) && t1->base() == Type::FloatCon) - if (!g_isnan(t1->getf()) && g_isfinite(t1->getf()) && t1->getf() != 0.0) // could be negative ZERO or NaN - return TypeF::ONE; + if (in(1) == in(2) && t1->base() == Type::FloatCon && + !g_isnan(t1->getf()) && g_isfinite(t1->getf()) && t1->getf() != 0.0) { // could be negative ZERO or NaN + return TypeF::ONE; + } if( t2 == TypeF::ONE ) return t1; @@ -773,9 +776,10 @@ const Type* DivDNode::Value(PhaseGVN* phase) const { // x/x == 1, we ignore 0/0. // Note: if t1 and t2 are zero then result is NaN (JVMS page 213) // Does not work for variables because of NaN's - if( phase->eqv( in(1), in(2) ) && t1->base() == Type::DoubleCon) - if (!g_isnan(t1->getd()) && g_isfinite(t1->getd()) && t1->getd() != 0.0) // could be negative ZERO or NaN - return TypeD::ONE; + if (in(1) == in(2) && t1->base() == Type::DoubleCon && + !g_isnan(t1->getd()) && g_isfinite(t1->getd()) && t1->getd() != 0.0) { // could be negative ZERO or NaN + return TypeD::ONE; + } if( t2 == TypeD::ONE ) return t1; @@ -990,7 +994,9 @@ const Type* ModINode::Value(PhaseGVN* phase) const { // 0 MOD X is 0 if( t1 == TypeInt::ZERO ) return TypeInt::ZERO; // X MOD X is 0 - if( phase->eqv( in(1), in(2) ) ) return TypeInt::ZERO; + if (in(1) == in(2)) { + return TypeInt::ZERO; + } // Either input is BOTTOM ==> the result is the local BOTTOM const Type *bot = bottom_type(); @@ -1163,7 +1169,9 @@ const Type* ModLNode::Value(PhaseGVN* phase) const { // 0 MOD X is 0 if( t1 == TypeLong::ZERO ) return TypeLong::ZERO; // X MOD X is 0 - if( phase->eqv( in(1), in(2) ) ) return TypeLong::ZERO; + if (in(1) == in(2)) { + return TypeLong::ZERO; + } // Either input is BOTTOM ==> the result is the local BOTTOM const Type *bot = bottom_type(); diff --git a/src/hotspot/share/opto/memnode.cpp b/src/hotspot/share/opto/memnode.cpp index 09bb0fcd2c0a0..d62c187ccb097 100644 --- a/src/hotspot/share/opto/memnode.cpp +++ b/src/hotspot/share/opto/memnode.cpp @@ -1074,7 +1074,7 @@ Node* MemNode::can_see_stored_value(Node* st, PhaseTransform* phase) const { if (st->is_Store()) { Node* st_adr = st->in(MemNode::Address); - if (!phase->eqv(st_adr, ld_adr)) { + if (st_adr != ld_adr) { // Try harder before giving up. Unify base pointers with casts (e.g., raw/non-raw pointers). intptr_t st_off = 0; Node* st_base = AddPNode::Ideal_base_and_offset(st_adr, phase, st_off); @@ -1523,7 +1523,7 @@ Node *LoadNode::split_through_phi(PhaseGVN *phase) { // Do nothing here if Identity will find a value // (to avoid infinite chain of value phis generation). - if (!phase->eqv(this, this->Identity(phase))) { + if (this != Identity(phase)) { return NULL; } @@ -2737,7 +2737,7 @@ Node* StoreNode::Identity(PhaseGVN* phase) { // Steps (a), (b): Walk past independent stores to find an exact match. if (prev_mem != NULL) { Node* prev_val = can_see_stored_value(prev_mem, phase); - if (prev_val != NULL && phase->eqv(prev_val, val)) { + if (prev_val != NULL && prev_val == val) { // prev_val and val might differ by a cast; it would be good // to keep the more informative of the two. result = mem; diff --git a/src/hotspot/share/opto/movenode.cpp b/src/hotspot/share/opto/movenode.cpp index f5a001d664851..f9b887c3173e5 100644 --- a/src/hotspot/share/opto/movenode.cpp +++ b/src/hotspot/share/opto/movenode.cpp @@ -78,9 +78,9 @@ Node *CMoveNode::Ideal(PhaseGVN *phase, bool can_reshape) { if( in(0) && remove_dead_region(phase, can_reshape) ) return this; // Don't bother trying to transform a dead node if( in(0) && in(0)->is_top() ) return NULL; - assert( !phase->eqv(in(Condition), this) && - !phase->eqv(in(IfFalse), this) && - !phase->eqv(in(IfTrue), this), "dead loop in CMoveNode::Ideal" ); + assert(in(Condition) != this && + in(IfFalse) != this && + in(IfTrue) != this, "dead loop in CMoveNode::Ideal" ); if( phase->type(in(Condition)) == Type::TOP ) return NULL; // return NULL when Condition is dead @@ -98,11 +98,9 @@ Node *CMoveNode::Ideal(PhaseGVN *phase, bool can_reshape) { // Helper function to check for CMOVE identity. Shared with PhiNode::Identity Node *CMoveNode::is_cmove_id( PhaseTransform *phase, Node *cmp, Node *t, Node *f, BoolNode *b ) { // Check for Cmp'ing and CMove'ing same values - if( (phase->eqv(cmp->in(1),f) && - phase->eqv(cmp->in(2),t)) || - // Swapped Cmp is OK - (phase->eqv(cmp->in(2),f) && - phase->eqv(cmp->in(1),t)) ) { + if ((cmp->in(1) == f && cmp->in(2) == t) || + // Swapped Cmp is OK + (cmp->in(2) == f && cmp->in(1) == t)) { // Give up this identity check for floating points because it may choose incorrect // value around 0.0 and -0.0 if ( cmp->Opcode()==Op_CmpF || cmp->Opcode()==Op_CmpD ) @@ -122,12 +120,16 @@ Node *CMoveNode::is_cmove_id( PhaseTransform *phase, Node *cmp, Node *t, Node *f // Conditional-move is an identity if both inputs are the same, or the test // true or false. Node* CMoveNode::Identity(PhaseGVN* phase) { - if( phase->eqv(in(IfFalse),in(IfTrue)) ) // C-moving identical inputs? - return in(IfFalse); // Then it doesn't matter - if( phase->type(in(Condition)) == TypeInt::ZERO ) - return in(IfFalse); // Always pick left(false) input - if( phase->type(in(Condition)) == TypeInt::ONE ) - return in(IfTrue); // Always pick right(true) input + // C-moving identical inputs? + if (in(IfFalse) == in(IfTrue)) { + return in(IfFalse); // Then it doesn't matter + } + if (phase->type(in(Condition)) == TypeInt::ZERO) { + return in(IfFalse); // Always pick left(false) input + } + if (phase->type(in(Condition)) == TypeInt::ONE) { + return in(IfTrue); // Always pick right(true) input + } // Check for CMove'ing a constant after comparing against the constant. // Happens all the time now, since if we compare equality vs a constant in diff --git a/src/hotspot/share/opto/mulnode.cpp b/src/hotspot/share/opto/mulnode.cpp index 3df3f7fa04085..e1db42be16733 100644 --- a/src/hotspot/share/opto/mulnode.cpp +++ b/src/hotspot/share/opto/mulnode.cpp @@ -87,12 +87,13 @@ Node *MulNode::Ideal(PhaseGVN *phase, bool can_reshape) { Node *mul1 = in(1); #ifdef ASSERT // Check for dead loop - int op1 = mul1->Opcode(); - if( phase->eqv( mul1, this ) || phase->eqv( in(2), this ) || - ( ( op1 == mul_opcode() || op1 == add_opcode() ) && - ( phase->eqv( mul1->in(1), this ) || phase->eqv( mul1->in(2), this ) || - phase->eqv( mul1->in(1), mul1 ) || phase->eqv( mul1->in(2), mul1 ) ) ) ) + int op1 = mul1->Opcode(); + if ((mul1 == this) || (in(2) == this) || + ((op1 == mul_opcode() || op1 == add_opcode()) && + ((mul1->in(1) == this) || (mul1->in(2) == this) || + (mul1->in(1) == mul1) || (mul1->in(2) == mul1)))) { assert(false, "dead loop in MulNode::Ideal"); + } #endif if( mul1->Opcode() == mul_opcode() ) { // Left input is a multiply? @@ -436,7 +437,9 @@ const Type *AndINode::mul_ring( const Type *t0, const Type *t1 ) const { Node* AndINode::Identity(PhaseGVN* phase) { // x & x => x - if (phase->eqv(in(1), in(2))) return in(1); + if (in(1) == in(2)) { + return in(1); + } Node* in1 = in(1); uint op = in1->Opcode(); @@ -558,7 +561,9 @@ const Type *AndLNode::mul_ring( const Type *t0, const Type *t1 ) const { Node* AndLNode::Identity(PhaseGVN* phase) { // x & x => x - if (phase->eqv(in(1), in(2))) return in(1); + if (in(1) == in(2)) { + return in(1); + } Node *usr = in(1); const TypeLong *t2 = phase->type( in(2) )->isa_long(); diff --git a/src/hotspot/share/opto/phaseX.hpp b/src/hotspot/share/opto/phaseX.hpp index c297bb76978e7..4a5805093f9a4 100644 --- a/src/hotspot/share/opto/phaseX.hpp +++ b/src/hotspot/share/opto/phaseX.hpp @@ -282,11 +282,6 @@ class PhaseTransform : public Phase { // in a faster or cheaper fashion. virtual Node *transform( Node *n ) = 0; - // Return whether two Nodes are equivalent. - // Must not be recursive, since the recursive version is built from this. - // For pessimistic optimizations this is simply pointer equivalence. - bool eqv(const Node* n1, const Node* n2) const { return n1 == n2; } - // For pessimistic passes, the return type must monotonically narrow. // For optimistic passes, the return type must monotonically widen. // It is possible to get into a "death march" in either type of pass, diff --git a/src/hotspot/share/opto/subnode.cpp b/src/hotspot/share/opto/subnode.cpp index 1bc8e7fe78f46..eaa007d35cb45 100644 --- a/src/hotspot/share/opto/subnode.cpp +++ b/src/hotspot/share/opto/subnode.cpp @@ -61,20 +61,22 @@ Node* SubNode::Identity(PhaseGVN* phase) { } // Convert "(X+Y) - Y" into X and "(X+Y) - X" into Y - if( in(1)->Opcode() == Op_AddI ) { - if( phase->eqv(in(1)->in(2),in(2)) ) + if (in(1)->Opcode() == Op_AddI) { + if (in(1)->in(2) == in(2)) { return in(1)->in(1); - if (phase->eqv(in(1)->in(1),in(2))) + } + if (in(1)->in(1) == in(2)) { return in(1)->in(2); + } // Also catch: "(X + Opaque2(Y)) - Y". In this case, 'Y' is a loop-varying // trip counter and X is likely to be loop-invariant (that's how O2 Nodes // are originally used, although the optimizer sometimes jiggers things). // This folding through an O2 removes a loop-exit use of a loop-varying // value and generally lowers register pressure in and around the loop. - if( in(1)->in(2)->Opcode() == Op_Opaque2 && - phase->eqv(in(1)->in(2)->in(1),in(2)) ) + if (in(1)->in(2)->Opcode() == Op_Opaque2 && in(1)->in(2)->in(1) == in(2)) { return in(1)->in(1); + } } return ( phase->type( in(2) )->higher_equal( zero ) ) ? in(1) : this; @@ -154,11 +156,12 @@ Node *SubINode::Ideal(PhaseGVN *phase, bool can_reshape){ #ifdef ASSERT // Check for dead loop - if( phase->eqv( in1, this ) || phase->eqv( in2, this ) || - ( ( op1 == Op_AddI || op1 == Op_SubI ) && - ( phase->eqv( in1->in(1), this ) || phase->eqv( in1->in(2), this ) || - phase->eqv( in1->in(1), in1 ) || phase->eqv( in1->in(2), in1 ) ) ) ) + if ((in1 == this) || (in2 == this) || + ((op1 == Op_AddI || op1 == Op_SubI) && + ((in1->in(1) == this) || (in1->in(2) == this) || + (in1->in(1) == in1) || (in1->in(2) == in1)))) { assert(false, "dead loop in SubINode::Ideal"); + } #endif const Type *t2 = phase->type( in2 ); @@ -200,24 +203,25 @@ Node *SubINode::Ideal(PhaseGVN *phase, bool can_reshape){ #ifdef ASSERT // Check for dead loop - if( ( op2 == Op_AddI || op2 == Op_SubI ) && - ( phase->eqv( in2->in(1), this ) || phase->eqv( in2->in(2), this ) || - phase->eqv( in2->in(1), in2 ) || phase->eqv( in2->in(2), in2 ) ) ) + if ((op2 == Op_AddI || op2 == Op_SubI) && + ((in2->in(1) == this) || (in2->in(2) == this) || + (in2->in(1) == in2) || (in2->in(2) == in2))) { assert(false, "dead loop in SubINode::Ideal"); + } #endif // Convert "x - (x+y)" into "-y" - if( op2 == Op_AddI && - phase->eqv( in1, in2->in(1) ) ) - return new SubINode( phase->intcon(0),in2->in(2)); + if (op2 == Op_AddI && in1 == in2->in(1)) { + return new SubINode(phase->intcon(0), in2->in(2)); + } // Convert "(x-y) - x" into "-y" - if( op1 == Op_SubI && - phase->eqv( in1->in(1), in2 ) ) - return new SubINode( phase->intcon(0),in1->in(2)); + if (op1 == Op_SubI && in1->in(1) == in2) { + return new SubINode(phase->intcon(0), in1->in(2)); + } // Convert "x - (y+x)" into "-y" - if( op2 == Op_AddI && - phase->eqv( in1, in2->in(2) ) ) - return new SubINode( phase->intcon(0),in2->in(1)); + if (op2 == Op_AddI && in1 == in2->in(2)) { + return new SubINode(phase->intcon(0), in2->in(1)); + } // Convert "0 - (x-y)" into "y-x" if( t1 == TypeInt::ZERO && op2 == Op_SubI ) @@ -296,11 +300,12 @@ Node *SubLNode::Ideal(PhaseGVN *phase, bool can_reshape) { #ifdef ASSERT // Check for dead loop - if( phase->eqv( in1, this ) || phase->eqv( in2, this ) || - ( ( op1 == Op_AddL || op1 == Op_SubL ) && - ( phase->eqv( in1->in(1), this ) || phase->eqv( in1->in(2), this ) || - phase->eqv( in1->in(1), in1 ) || phase->eqv( in1->in(2), in1 ) ) ) ) + if ((in1 == this) || (in2 == this) || + ((op1 == Op_AddL || op1 == Op_SubL) && + ((in1->in(1) == this) || (in1->in(2) == this) || + (in1->in(1) == in1) || (in1->in(2) == in1)))) { assert(false, "dead loop in SubLNode::Ideal"); + } #endif if( phase->type( in2 ) == Type::TOP ) return NULL; @@ -340,20 +345,21 @@ Node *SubLNode::Ideal(PhaseGVN *phase, bool can_reshape) { #ifdef ASSERT // Check for dead loop - if( ( op2 == Op_AddL || op2 == Op_SubL ) && - ( phase->eqv( in2->in(1), this ) || phase->eqv( in2->in(2), this ) || - phase->eqv( in2->in(1), in2 ) || phase->eqv( in2->in(2), in2 ) ) ) + if ((op2 == Op_AddL || op2 == Op_SubL) && + ((in2->in(1) == this) || (in2->in(2) == this) || + (in2->in(1) == in2) || (in2->in(2) == in2))) { assert(false, "dead loop in SubLNode::Ideal"); + } #endif // Convert "x - (x+y)" into "-y" - if( op2 == Op_AddL && - phase->eqv( in1, in2->in(1) ) ) - return new SubLNode( phase->makecon(TypeLong::ZERO), in2->in(2)); + if (op2 == Op_AddL && in1 == in2->in(1)) { + return new SubLNode(phase->makecon(TypeLong::ZERO), in2->in(2)); + } // Convert "x - (y+x)" into "-y" - if( op2 == Op_AddL && - phase->eqv( in1, in2->in(2) ) ) - return new SubLNode( phase->makecon(TypeLong::ZERO),in2->in(1)); + if (op2 == Op_AddL && in1 == in2->in(2)) { + return new SubLNode(phase->makecon(TypeLong::ZERO), in2->in(1)); + } // Convert "0 - (x-y)" into "y-x" if( phase->type( in1 ) == TypeLong::ZERO && op2 == Op_SubL ) @@ -421,8 +427,8 @@ const Type* SubFPNode::Value(PhaseGVN* phase) const { // if both operands are infinity of same sign, the result is NaN; do // not replace with zero - if( (t1->is_finite() && t2->is_finite()) ) { - if( phase->eqv(in1, in2) ) return add_id(); + if (t1->is_finite() && t2->is_finite() && in1 == in2) { + return add_id(); } // Either input is BOTTOM ==> the result is the local BOTTOM @@ -445,11 +451,10 @@ Node *SubFNode::Ideal(PhaseGVN *phase, bool can_reshape) { } // Not associative because of boundary conditions (infinity) - if( IdealizedNumerics && !phase->C->method()->is_strict() ) { + if (IdealizedNumerics && !phase->C->method()->is_strict() && + in(2)->is_Add() && in(1) == in(2)->in(1)) { // Convert "x - (x+y)" into "-y" - if( in(2)->is_Add() && - phase->eqv(in(1),in(2)->in(1) ) ) - return new SubFNode( phase->makecon(TypeF::ZERO),in(2)->in(2)); + return new SubFNode(phase->makecon(TypeF::ZERO), in(2)->in(2)); } // Cannot replace 0.0-X with -X because a 'fsub' bytecode computes @@ -488,11 +493,10 @@ Node *SubDNode::Ideal(PhaseGVN *phase, bool can_reshape){ } // Not associative because of boundary conditions (infinity) - if( IdealizedNumerics && !phase->C->method()->is_strict() ) { + if (IdealizedNumerics && !phase->C->method()->is_strict() && + in(2)->is_Add() && in(1) == in(2)->in(1)) { // Convert "x - (x+y)" into "-y" - if( in(2)->is_Add() && - phase->eqv(in(1),in(2)->in(1) ) ) - return new SubDNode( phase->makecon(TypeD::ZERO),in(2)->in(2)); + return new SubDNode(phase->makecon(TypeD::ZERO), in(2)->in(2)); } // Cannot replace 0.0-X with -X because a 'dsub' bytecode computes From aa2862ad86ede366c15922fa3fbbb94b51225328 Mon Sep 17 00:00:00 2001 From: Aleksey Shipilev Date: Tue, 3 Nov 2020 07:28:06 +0000 Subject: [PATCH 21/32] 8255741: Zero: print signal name in unhandled signal handler Reviewed-by: stuefe --- src/hotspot/os_cpu/linux_zero/os_linux_zero.cpp | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/src/hotspot/os_cpu/linux_zero/os_linux_zero.cpp b/src/hotspot/os_cpu/linux_zero/os_linux_zero.cpp index bbacc5f0029eb..8f2c8b8bc162f 100644 --- a/src/hotspot/os_cpu/linux_zero/os_linux_zero.cpp +++ b/src/hotspot/os_cpu/linux_zero/os_linux_zero.cpp @@ -240,9 +240,16 @@ JVM_handle_linux_signal(int sig, } #endif // !PRODUCT - char buf[64]; - - sprintf(buf, "caught unhandled signal %d", sig); + char buf[128]; + char exc_buf[32]; + + if (os::exception_name(sig, exc_buf, sizeof(exc_buf))) { + bool sent_by_kill = (info != NULL && os::signal_sent_by_kill(info)); + snprintf(buf, sizeof(buf), "caught unhandled signal: %s %s", + exc_buf, sent_by_kill ? "(sent by kill)" : ""); + } else { + snprintf(buf, sizeof(buf), "caught unhandled signal: %d", sig); + } // Silence -Wformat-security warning for fatal() PRAGMA_DIAG_PUSH From c96a914b522f921acf98f6fc9b4964aff168ed08 Mon Sep 17 00:00:00 2001 From: Stefan Karlsson Date: Tue, 3 Nov 2020 07:31:47 +0000 Subject: [PATCH 22/32] 8255662: ZGC: Unify nmethod closures in the heap iterator Reviewed-by: eosterlund, pliden --- src/hotspot/share/gc/z/zHeapIterator.cpp | 29 +++++++----------------- src/hotspot/share/memory/iterator.cpp | 7 ++++++ src/hotspot/share/memory/iterator.hpp | 9 ++++++++ 3 files changed, 24 insertions(+), 21 deletions(-) diff --git a/src/hotspot/share/gc/z/zHeapIterator.cpp b/src/hotspot/share/gc/z/zHeapIterator.cpp index 4fd0d22497f76..4434e53fbb12e 100644 --- a/src/hotspot/share/gc/z/zHeapIterator.cpp +++ b/src/hotspot/share/gc/z/zHeapIterator.cpp @@ -250,9 +250,7 @@ class ZHeapIteratorNMethodClosure : public NMethodClosure { _bs_nm(BarrierSet::barrier_set()->barrier_set_nmethod()) {} virtual void do_nmethod(nmethod* nm) { - assert(!ClassUnloading, "Only used if class unloading is turned off"); - - // ClassUnloading is turned off, all nmethods are considered strong, + // If ClassUnloading is turned off, all nmethods are considered strong, // not only those on the call stacks. The heap iteration might happen // before the concurrent processign of the code cache, make sure that // all nmethods have been processed before visiting the oops. @@ -264,27 +262,16 @@ class ZHeapIteratorNMethodClosure : public NMethodClosure { class ZHeapIteratorThreadClosure : public ThreadClosure { private: - OopClosure* const _cl; - - class NMethodVisitor : public CodeBlobToOopClosure { - public: - NMethodVisitor(OopClosure* cl) : - CodeBlobToOopClosure(cl, false /* fix_oop_relocations */) {} - - void do_code_blob(CodeBlob* cb) { - assert(!cb->is_nmethod() || !ZNMethod::is_armed(cb->as_nmethod()), - "NMethods on stack should have been fixed and disarmed"); - - CodeBlobToOopClosure::do_code_blob(cb); - } - }; + OopClosure* const _cl; + CodeBlobToNMethodClosure _cb_cl; public: - ZHeapIteratorThreadClosure(OopClosure* cl) : _cl(cl) {} + ZHeapIteratorThreadClosure(OopClosure* cl, NMethodClosure* nm_cl) : + _cl(cl), + _cb_cl(nm_cl) {} void do_thread(Thread* thread) { - NMethodVisitor code_cl(_cl); - thread->oops_do(_cl, &code_cl); + thread->oops_do(_cl, &_cb_cl); } }; @@ -292,7 +279,7 @@ void ZHeapIterator::push_strong_roots(const ZHeapIteratorContext& context) { ZHeapIteratorRootOopClosure cl(context); ZHeapIteratorCLDCLosure cld_cl(&cl); ZHeapIteratorNMethodClosure nm_cl(&cl); - ZHeapIteratorThreadClosure thread_cl(&cl); + ZHeapIteratorThreadClosure thread_cl(&cl, &nm_cl); _concurrent_roots.apply(&cl, &cld_cl, diff --git a/src/hotspot/share/memory/iterator.cpp b/src/hotspot/share/memory/iterator.cpp index 51b223c53bb99..f9fbaf51b90f1 100644 --- a/src/hotspot/share/memory/iterator.cpp +++ b/src/hotspot/share/memory/iterator.cpp @@ -64,3 +64,10 @@ void MarkingCodeBlobClosure::do_code_blob(CodeBlob* cb) { do_nmethod(nm); } } + +void CodeBlobToNMethodClosure::do_code_blob(CodeBlob* cb) { + nmethod* nm = cb->as_nmethod_or_null(); + if (nm != NULL) { + _nm_cl->do_nmethod(nm); + } +} diff --git a/src/hotspot/share/memory/iterator.hpp b/src/hotspot/share/memory/iterator.hpp index a5b1d49836bdc..9c2611a24c2bf 100644 --- a/src/hotspot/share/memory/iterator.hpp +++ b/src/hotspot/share/memory/iterator.hpp @@ -261,6 +261,15 @@ class NMethodClosure : public Closure { virtual void do_nmethod(nmethod* n) = 0; }; +class CodeBlobToNMethodClosure : public CodeBlobClosure { + NMethodClosure* const _nm_cl; + + public: + CodeBlobToNMethodClosure(NMethodClosure* nm_cl) : _nm_cl(nm_cl) {} + + virtual void do_code_blob(CodeBlob* cb); +}; + // MonitorClosure is used for iterating over monitors in the monitors cache class ObjectMonitor; From 9a367479279f46494d83356f34eddd29ab0045b1 Mon Sep 17 00:00:00 2001 From: Thomas Stuefe Date: Tue, 3 Nov 2020 07:34:06 +0000 Subject: [PATCH 23/32] 8255780: Remove unused overloads of VMError::report_and_die() Reviewed-by: mdoerr, coleenp --- src/hotspot/share/utilities/vmError.cpp | 13 ------------- src/hotspot/share/utilities/vmError.hpp | 3 --- 2 files changed, 16 deletions(-) diff --git a/src/hotspot/share/utilities/vmError.cpp b/src/hotspot/share/utilities/vmError.cpp index 4a9ecebbec946..9567eabb54daf 100644 --- a/src/hotspot/share/utilities/vmError.cpp +++ b/src/hotspot/share/utilities/vmError.cpp @@ -1321,19 +1321,6 @@ void VMError::report_and_die(Thread* thread, unsigned int sig, address pc, void* report_and_die(thread, sig, pc, siginfo, context, "%s", ""); } -void VMError::report_and_die(const char* message, const char* detail_fmt, ...) -{ - va_list detail_args; - va_start(detail_args, detail_fmt); - report_and_die(INTERNAL_ERROR, message, detail_fmt, detail_args, NULL, NULL, NULL, NULL, NULL, 0, 0); - va_end(detail_args); -} - -void VMError::report_and_die(const char* message) -{ - report_and_die(message, "%s", ""); -} - void VMError::report_and_die(Thread* thread, void* context, const char* filename, int lineno, const char* message, const char* detail_fmt, va_list detail_args) { diff --git a/src/hotspot/share/utilities/vmError.hpp b/src/hotspot/share/utilities/vmError.hpp index 2e7b0c26d720f..172ddb52fb80c 100644 --- a/src/hotspot/share/utilities/vmError.hpp +++ b/src/hotspot/share/utilities/vmError.hpp @@ -118,7 +118,6 @@ class VMError : public AllStatic { static void report_and_die(Thread* thread, unsigned int sig, address pc, void* siginfo, void* context, const char* detail_fmt, ...) ATTRIBUTE_PRINTF(6, 7); - static void report_and_die(const char* message, const char* detail_fmt, ...) ATTRIBUTE_PRINTF(2, 3); // Timeout handling. // Hook functions for platform dependend functionality: @@ -161,8 +160,6 @@ class VMError : public AllStatic { VMErrorType vm_err_type, const char* detail_fmt, va_list detail_args) ATTRIBUTE_PRINTF(6, 0); - static void report_and_die(const char* message); - // reporting OutOfMemoryError static void report_java_out_of_memory(const char* message); From 4107670d6210df16d5afd0ac7b8a7bab04a29c3b Mon Sep 17 00:00:00 2001 From: Jayathirth D V Date: Tue, 3 Nov 2020 07:54:31 +0000 Subject: [PATCH 24/32] 8233562: [TESTBUG] Swing StyledEditorKit test bug4506788.java fails on MacOS Reviewed-by: psadhukhan --- test/jdk/ProblemList.txt | 1 - .../javax/swing/text/StyledEditorKit/4506788/bug4506788.java | 4 ++-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/test/jdk/ProblemList.txt b/test/jdk/ProblemList.txt index 6b120142b55bd..63234eaabbc58 100644 --- a/test/jdk/ProblemList.txt +++ b/test/jdk/ProblemList.txt @@ -778,7 +778,6 @@ javax/swing/dnd/8139050/NativeErrorsInTableDnD.java 8202765 macosx-all,linux-al javax/swing/Popup/TaskbarPositionTest.java 8065097 macosx-all,linux-all javax/swing/JEditorPane/6917744/bug6917744.java 8213124 macosx-all javax/swing/JTree/6263446/bug6263446.java 8213125 macosx-all -javax/swing/text/StyledEditorKit/4506788/bug4506788.java 8233562 macosx-all javax/swing/JRootPane/4670486/bug4670486.java 8042381 macosx-all javax/swing/JRadioButton/ButtonGroupFocus/ButtonGroupFocusTest.java 8233555 macosx-all javax/swing/JRadioButton/8075609/bug8075609.java 8233555 macosx-all diff --git a/test/jdk/javax/swing/text/StyledEditorKit/4506788/bug4506788.java b/test/jdk/javax/swing/text/StyledEditorKit/4506788/bug4506788.java index d2d16f681c391..e7c31a26d0fde 100644 --- a/test/jdk/javax/swing/text/StyledEditorKit/4506788/bug4506788.java +++ b/test/jdk/javax/swing/text/StyledEditorKit/4506788/bug4506788.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2020, 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 @@ -65,6 +65,7 @@ public void start() { Robot robot; try { robot = new Robot(); + robot.setAutoDelay(100); } catch (AWTException e) { throw new RuntimeException("Robot could not be created"); } @@ -78,7 +79,6 @@ public void start() { throw new RuntimeException("Could not get JEditorPane location on screen"); } - robot.setAutoDelay(50); robot.mouseMove(p.x, p.y); robot.mousePress(InputEvent.BUTTON1_MASK); robot.mouseRelease(InputEvent.BUTTON1_MASK); From 36998b006d6a9ee8145004778534d1f35a55e068 Mon Sep 17 00:00:00 2001 From: Patrick Zhang Date: Tue, 3 Nov 2020 09:28:12 +0000 Subject: [PATCH 25/32] 8255716: AArch64: Regression: JVM crashes if manually offline a core Reviewed-by: aph, adinn, akozlov --- src/hotspot/os_cpu/linux_aarch64/vm_version_linux_aarch64.cpp | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/hotspot/os_cpu/linux_aarch64/vm_version_linux_aarch64.cpp b/src/hotspot/os_cpu/linux_aarch64/vm_version_linux_aarch64.cpp index 162951c4317a4..199a096d7f97d 100644 --- a/src/hotspot/os_cpu/linux_aarch64/vm_version_linux_aarch64.cpp +++ b/src/hotspot/os_cpu/linux_aarch64/vm_version_linux_aarch64.cpp @@ -142,7 +142,6 @@ void VM_Version::get_os_cpu_info() { _zva_length = 4 << (dczid_el0 & 0xf); } - int cpu_lines = 0; if (FILE *f = fopen("/proc/cpuinfo", "r")) { // need a large buffer as the flags line may include lots of text char buf[1024], *p; @@ -151,7 +150,6 @@ void VM_Version::get_os_cpu_info() { long v = strtol(p+1, NULL, 0); if (strncmp(buf, "CPU implementer", sizeof "CPU implementer" - 1) == 0) { _cpu = v; - cpu_lines++; } else if (strncmp(buf, "CPU variant", sizeof "CPU variant" - 1) == 0) { _variant = v; } else if (strncmp(buf, "CPU part", sizeof "CPU part" - 1) == 0) { @@ -168,5 +166,4 @@ void VM_Version::get_os_cpu_info() { } fclose(f); } - guarantee(cpu_lines == os::processor_count(), "core count should be consistent"); } From 9bd836e046b397c5c09f9f92c46924093294cb81 Mon Sep 17 00:00:00 2001 From: Aleksey Shipilev Date: Tue, 3 Nov 2020 10:35:20 +0000 Subject: [PATCH 26/32] 8255744: Zero: handle JVM_CONSTANT_DynamicInError Reviewed-by: sgehwolf --- src/hotspot/share/interpreter/zero/bytecodeInterpreter.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/hotspot/share/interpreter/zero/bytecodeInterpreter.cpp b/src/hotspot/share/interpreter/zero/bytecodeInterpreter.cpp index ba162c3570307..78a2c9f199ac8 100644 --- a/src/hotspot/share/interpreter/zero/bytecodeInterpreter.cpp +++ b/src/hotspot/share/interpreter/zero/bytecodeInterpreter.cpp @@ -2266,6 +2266,7 @@ BytecodeInterpreter::run(interpreterState istate) { break; case JVM_CONSTANT_Dynamic: + case JVM_CONSTANT_DynamicInError: { CALL_VM(InterpreterRuntime::resolve_ldc(THREAD, (Bytecodes::Code) opcode), handle_exception); oop result = THREAD->vm_result(); @@ -2307,6 +2308,7 @@ BytecodeInterpreter::run(interpreterState istate) { break; case JVM_CONSTANT_Dynamic: + case JVM_CONSTANT_DynamicInError: { CALL_VM(InterpreterRuntime::resolve_ldc(THREAD, (Bytecodes::Code) opcode), handle_exception); oop result = THREAD->vm_result(); From 904561ebf2240b9ce481e0bc020be8f98b80c89e Mon Sep 17 00:00:00 2001 From: Aleksey Shipilev Date: Tue, 3 Nov 2020 11:02:15 +0000 Subject: [PATCH 27/32] 8255719: Zero: on return path, check for pending exception before attempting to clear it Reviewed-by: sgehwolf --- src/hotspot/share/interpreter/zero/bytecodeInterpreter.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/hotspot/share/interpreter/zero/bytecodeInterpreter.cpp b/src/hotspot/share/interpreter/zero/bytecodeInterpreter.cpp index 78a2c9f199ac8..eb79ec90d08eb 100644 --- a/src/hotspot/share/interpreter/zero/bytecodeInterpreter.cpp +++ b/src/hotspot/share/interpreter/zero/bytecodeInterpreter.cpp @@ -2904,7 +2904,9 @@ BytecodeInterpreter::run(interpreterState istate) { // a NULL oop in it and then overwrite the oop later as needed. This isn't // unfortunately isn't possible. - THREAD->clear_pending_exception(); + if (THREAD->has_pending_exception()) { + THREAD->clear_pending_exception(); + } // // As far as we are concerned we have returned. If we have a pending exception From 9a0cf5872145cc8595ceabb69e6e2b432e186360 Mon Sep 17 00:00:00 2001 From: Aleksey Shipilev Date: Tue, 3 Nov 2020 11:04:47 +0000 Subject: [PATCH 28/32] 8255615: Zero: demote ZeroStack::abi_stack_available guarantee to assert Reviewed-by: sgehwolf --- src/hotspot/cpu/zero/stack_zero.inline.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/hotspot/cpu/zero/stack_zero.inline.hpp b/src/hotspot/cpu/zero/stack_zero.inline.hpp index 0c85af5dfded8..f363de571805a 100644 --- a/src/hotspot/cpu/zero/stack_zero.inline.hpp +++ b/src/hotspot/cpu/zero/stack_zero.inline.hpp @@ -47,7 +47,7 @@ inline void ZeroStack::overflow_check(int required_words, TRAPS) { // to use under normal circumstances. Note that the returned // value can be negative. inline int ZeroStack::abi_stack_available(Thread *thread) const { - guarantee(Thread::current() == thread, "should run in the same thread"); + assert(Thread::current() == thread, "should run in the same thread"); int stack_used = thread->stack_base() - (address) &stack_used + (StackOverflow::stack_guard_zone_size() + StackOverflow::stack_shadow_zone_size()); int stack_free = thread->stack_size() - stack_used; From 1d0bd50624e3fe1c1ecbeac5311994e1e3f42b26 Mon Sep 17 00:00:00 2001 From: Stefan Johansson Date: Tue, 3 Nov 2020 11:07:35 +0000 Subject: [PATCH 29/32] 8254758: Change G1ServiceThread to be task based Reviewed-by: ayang, iwalulya, tschatzl --- src/hotspot/share/gc/g1/g1ServiceThread.cpp | 377 ++++++++++++++---- src/hotspot/share/gc/g1/g1ServiceThread.hpp | 99 ++++- .../gtest/gc/g1/test_g1ServiceThread.cpp | 183 +++++++++ 3 files changed, 563 insertions(+), 96 deletions(-) create mode 100644 test/hotspot/gtest/gc/g1/test_g1ServiceThread.cpp diff --git a/src/hotspot/share/gc/g1/g1ServiceThread.cpp b/src/hotspot/share/gc/g1/g1ServiceThread.cpp index 0c7f91ab6d727..3c3e561a6b438 100644 --- a/src/hotspot/share/gc/g1/g1ServiceThread.cpp +++ b/src/hotspot/share/gc/g1/g1ServiceThread.cpp @@ -36,92 +36,69 @@ #include "runtime/mutexLocker.hpp" #include "runtime/os.hpp" -G1ServiceThread::G1ServiceThread() : - ConcurrentGCThread(), - _monitor(Mutex::nonleaf, - "G1ServiceThread monitor", - true, - Monitor::_safepoint_check_never), - _last_periodic_gc_attempt_s(os::elapsedTime()), - _vtime_accum(0) { - set_name("G1 Service"); - create_and_start(); +G1SentinelTask::G1SentinelTask() : G1ServiceTask("Sentinel Task") { + set_time(max_jlong); + set_next(this); } -void G1ServiceThread::sleep_before_next_cycle() { - MonitorLocker ml(&_monitor, Mutex::_no_safepoint_check_flag); - if (!should_terminate()) { - uintx waitms = G1ConcRefinementServiceIntervalMillis; - ml.wait(waitms); - } +void G1SentinelTask::execute() { + guarantee(false, "Sentinel service task should never be executed."); } -bool G1ServiceThread::should_start_periodic_gc() { - G1CollectedHeap* g1h = G1CollectedHeap::heap(); - // If we are currently in a concurrent mark we are going to uncommit memory soon. - if (g1h->concurrent_mark()->cm_thread()->in_progress()) { - log_debug(gc, periodic)("Concurrent cycle in progress. Skipping."); - return false; - } +// Task handling periodic GCs +class G1PeriodicGCTask : public G1ServiceTask { + bool should_start_periodic_gc() { + G1CollectedHeap* g1h = G1CollectedHeap::heap(); + // If we are currently in a concurrent mark we are going to uncommit memory soon. + if (g1h->concurrent_mark()->cm_thread()->in_progress()) { + log_debug(gc, periodic)("Concurrent cycle in progress. Skipping."); + return false; + } - // Check if enough time has passed since the last GC. - uintx time_since_last_gc = (uintx)g1h->time_since_last_collection().milliseconds(); - if ((time_since_last_gc < G1PeriodicGCInterval)) { - log_debug(gc, periodic)("Last GC occurred " UINTX_FORMAT "ms before which is below threshold " UINTX_FORMAT "ms. Skipping.", - time_since_last_gc, G1PeriodicGCInterval); - return false; - } + // Check if enough time has passed since the last GC. + uintx time_since_last_gc = (uintx)g1h->time_since_last_collection().milliseconds(); + if ((time_since_last_gc < G1PeriodicGCInterval)) { + log_debug(gc, periodic)("Last GC occurred " UINTX_FORMAT "ms before which is below threshold " UINTX_FORMAT "ms. Skipping.", + time_since_last_gc, G1PeriodicGCInterval); + return false; + } - // Check if load is lower than max. - double recent_load; - if ((G1PeriodicGCSystemLoadThreshold > 0.0f) && - (os::loadavg(&recent_load, 1) == -1 || recent_load > G1PeriodicGCSystemLoadThreshold)) { - log_debug(gc, periodic)("Load %1.2f is higher than threshold %1.2f. Skipping.", - recent_load, G1PeriodicGCSystemLoadThreshold); - return false; + // Check if load is lower than max. + double recent_load; + if ((G1PeriodicGCSystemLoadThreshold > 0.0f) && + (os::loadavg(&recent_load, 1) == -1 || recent_load > G1PeriodicGCSystemLoadThreshold)) { + log_debug(gc, periodic)("Load %1.2f is higher than threshold %1.2f. Skipping.", + recent_load, G1PeriodicGCSystemLoadThreshold); + return false; + } + return true; } - return true; -} + void check_for_periodic_gc(){ + // If disabled, just return. + if (G1PeriodicGCInterval == 0) { + return; + } -void G1ServiceThread::check_for_periodic_gc(){ - // If disabled, just return. - if (G1PeriodicGCInterval == 0) { - return; - } - if ((os::elapsedTime() - _last_periodic_gc_attempt_s) > (G1PeriodicGCInterval / 1000.0)) { log_debug(gc, periodic)("Checking for periodic GC."); if (should_start_periodic_gc()) { if (!G1CollectedHeap::heap()->try_collect(GCCause::_g1_periodic_collection)) { log_debug(gc, periodic)("GC request denied. Skipping."); } } - _last_periodic_gc_attempt_s = os::elapsedTime(); } -} - -void G1ServiceThread::run_service() { - double vtime_start = os::elapsedVTime(); - - while (!should_terminate()) { - sample_young_list_rs_length(); - - if (os::supports_vtime()) { - _vtime_accum = (os::elapsedVTime() - vtime_start); - } else { - _vtime_accum = 0.0; - } +public: + G1PeriodicGCTask(const char* name) : G1ServiceTask(name) { } + virtual void execute() { check_for_periodic_gc(); - - sleep_before_next_cycle(); + // G1PeriodicGCInterval is a manageable flag and can be updated + // during runtime. If no value is set, wait a second and run it + // again to see if the value has been updated. Otherwise use the + // real value provided. + schedule(G1PeriodicGCInterval == 0 ? 1000 : G1PeriodicGCInterval); } -} - -void G1ServiceThread::stop_service() { - MutexLocker x(&_monitor, Mutex::_no_safepoint_check_flag); - _monitor.notify(); -} +}; class G1YoungRemSetSamplingClosure : public HeapRegionClosure { SuspendibleThreadSetJoiner* _sts; @@ -155,19 +132,265 @@ class G1YoungRemSetSamplingClosure : public HeapRegionClosure { size_t sampled_rs_length() const { return _sampled_rs_length; } }; -void G1ServiceThread::sample_young_list_rs_length() { - SuspendibleThreadSetJoiner sts; - G1CollectedHeap* g1h = G1CollectedHeap::heap(); - G1Policy* policy = g1h->policy(); +// Task handling young gen remembered set sampling. +class G1RemSetSamplingTask : public G1ServiceTask { + // Sample the current length of remembered sets for young. + // + // At the end of the GC G1 determines the length of the young gen based on + // how much time the next GC can take, and when the next GC may occur + // according to the MMU. + // + // The assumption is that a significant part of the GC is spent on scanning + // the remembered sets (and many other components), so this thread constantly + // reevaluates the prediction for the remembered set scanning costs, and potentially + // G1Policy resizes the young gen. This may do a premature GC or even + // increase the young gen size to keep pause time length goal. + void sample_young_list_rs_length(){ + SuspendibleThreadSetJoiner sts; + G1CollectedHeap* g1h = G1CollectedHeap::heap(); + G1Policy* policy = g1h->policy(); + + if (policy->use_adaptive_young_list_length()) { + G1YoungRemSetSamplingClosure cl(&sts); + + G1CollectionSet* g1cs = g1h->collection_set(); + g1cs->iterate(&cl); + + if (cl.is_complete()) { + policy->revise_young_list_target_length_if_necessary(cl.sampled_rs_length()); + } + } + } +public: + G1RemSetSamplingTask(const char* name) : G1ServiceTask(name) { } + virtual void execute() { + sample_young_list_rs_length(); + schedule(G1ConcRefinementServiceIntervalMillis); + } +}; + +G1ServiceThread::G1ServiceThread() : + ConcurrentGCThread(), + _monitor(Mutex::nonleaf, + "G1ServiceThread monitor", + true, + Monitor::_safepoint_check_never), + _task_queue(), + _vtime_accum(0) { + set_name("G1 Service"); + create_and_start(); +} + +void G1ServiceThread::register_task(G1ServiceTask* task, jlong delay) { + guarantee(!task->is_registered(), "Task already registered"); + guarantee(task->next() == NULL, "Task already in queue"); + + log_debug(gc, task)("G1 Service Thread (%s) (register)", task->name()); + + // Associate the task with the service thread. + task->set_service_thread(this); + + // Schedule the task to run after the given delay. + schedule_task(task, delay); + + // Notify the service thread that there is a new task, thread might + // be waiting and the newly added task might be first in the list. + MonitorLocker ml(&_monitor, Mutex::_no_safepoint_check_flag); + ml.notify(); +} + +void G1ServiceThread::schedule_task(G1ServiceTask* task, jlong delay_ms) { + guarantee(task->is_registered(), "Must be registered before scheduled"); + guarantee(task->next() == NULL, "Task already in queue"); + + // Schedule task by setting the task time and adding it to queue. + jlong delay = TimeHelper::millis_to_counter(delay_ms); + task->set_time(os::elapsed_counter() + delay); + + MutexLocker ml(&_monitor, Mutex::_no_safepoint_check_flag); + _task_queue.add_ordered(task); - if (policy->use_adaptive_young_list_length()) { - G1YoungRemSetSamplingClosure cl(&sts); + log_trace(gc, task)("G1 Service Thread (%s) (schedule) @%1.3fs", + task->name(), TimeHelper::counter_to_seconds(task->time())); +} + +int64_t G1ServiceThread::time_to_next_task_ms() { + assert(_monitor.owned_by_self(), "Must be owner of lock"); + assert(!_task_queue.is_empty(), "Should not be called for empty list"); + + jlong time_diff = _task_queue.peek()->time() - os::elapsed_counter(); + if (time_diff < 0) { + // Run without sleeping. + return 0; + } + + // Return sleep time in milliseconds. + return (int64_t) TimeHelper::counter_to_millis(time_diff); +} + +void G1ServiceThread::sleep_before_next_cycle() { + if (should_terminate()) { + return; + } + + MonitorLocker ml(&_monitor, Mutex::_no_safepoint_check_flag); + if (_task_queue.is_empty()) { + // Sleep until new task is registered if no tasks available. + log_trace(gc, task)("G1 Service Thread (wait for new tasks)"); + ml.wait(0); + } else { + int64_t sleep_ms = time_to_next_task_ms(); + if (sleep_ms > 0) { + log_trace(gc, task)("G1 Service Thread (wait) %1.3fs", sleep_ms / 1000.0); + ml.wait(sleep_ms); + } + } +} + +G1ServiceTask* G1ServiceThread::pop_due_task() { + MutexLocker ml(&_monitor, Mutex::_no_safepoint_check_flag); + if (_task_queue.is_empty() || time_to_next_task_ms() != 0) { + return NULL; + } + + return _task_queue.pop(); +} - G1CollectionSet* g1cs = g1h->collection_set(); - g1cs->iterate(&cl); +void G1ServiceThread::run_task(G1ServiceTask* task) { + double start = os::elapsedTime(); + double vstart = os::elapsedVTime(); - if (cl.is_complete()) { - policy->revise_young_list_target_length_if_necessary(cl.sampled_rs_length()); + log_debug(gc, task, start)("G1 Service Thread (%s) (run)", task->name()); + task->execute(); + + double duration = os::elapsedTime() - start; + double vduration = os::elapsedVTime() - vstart; + log_debug(gc, task)("G1 Service Thread (%s) (run) %1.3fms (cpu: %1.3fms)", + task->name(), duration * MILLIUNITS, vduration * MILLIUNITS); +} + +void G1ServiceThread::run_service() { + double vtime_start = os::elapsedVTime(); + + // Setup the tasks handeled by the service thread and + // add them to the task list. + G1PeriodicGCTask gc_task("Periodic GC Task"); + register_task(&gc_task); + + G1RemSetSamplingTask remset_task("Remembered Set Sampling Task"); + register_task(&remset_task); + + while (!should_terminate()) { + G1ServiceTask* task = pop_due_task(); + if (task != NULL) { + run_task(task); } + + if (os::supports_vtime()) { + _vtime_accum = (os::elapsedVTime() - vtime_start); + } else { + _vtime_accum = 0.0; + } + sleep_before_next_cycle(); + } +} + +void G1ServiceThread::stop_service() { + MonitorLocker ml(&_monitor, Mutex::_no_safepoint_check_flag); + ml.notify(); +} + +G1ServiceTask::G1ServiceTask(const char* name) : + _time(), + _name(name), + _next(NULL), + _service_thread(NULL) { } + +void G1ServiceTask::set_service_thread(G1ServiceThread* thread) { + _service_thread = thread; +} + +bool G1ServiceTask::is_registered() { + return _service_thread != NULL; +} + +void G1ServiceTask::schedule(jlong delay_ms) { + _service_thread->schedule_task(this, delay_ms); +} + +const char* G1ServiceTask::name() { + return _name; +} + +void G1ServiceTask::set_time(jlong time) { + assert(_next == NULL, "Not allowed to update time while in queue"); + _time = time; +} + +jlong G1ServiceTask::time() { + return _time; +} + +void G1ServiceTask::set_next(G1ServiceTask* next) { + _next = next; +} + +G1ServiceTask* G1ServiceTask::next() { + return _next; +} + +G1ServiceTaskQueue::G1ServiceTaskQueue() : _sentinel() { } + +G1ServiceTask* G1ServiceTaskQueue::pop() { + verify_task_queue(); + + G1ServiceTask* task = _sentinel.next(); + _sentinel.set_next(task->next()); + task->set_next(NULL); + + return task; +} + +G1ServiceTask* G1ServiceTaskQueue::peek() { + verify_task_queue(); + return _sentinel.next(); +} + +bool G1ServiceTaskQueue::is_empty() { + return &_sentinel == _sentinel.next(); +} + +void G1ServiceTaskQueue::add_ordered(G1ServiceTask* task) { + assert(task != NULL, "not a valid task"); + assert(task->next() == NULL, "invariant"); + assert(task->time() != max_jlong, "invalid time for task"); + + G1ServiceTask* current = &_sentinel; + while (task->time() >= current->next()->time()) { + assert(task != current, "Task should only be added once."); + current = current->next(); + } + + // Update the links. + task->set_next(current->next()); + current->set_next(task); + + verify_task_queue(); +} + +#ifdef ASSERT +void G1ServiceTaskQueue::verify_task_queue() { + G1ServiceTask* cur = _sentinel.next(); + + assert(cur != &_sentinel, "Should never try to verify empty queue"); + while (cur != &_sentinel) { + G1ServiceTask* next = cur->next(); + assert(cur->time() <= next->time(), + "Tasks out of order, prev: %s (%1.3fs), next: %s (%1.3fs)", + cur->name(), TimeHelper::counter_to_seconds(cur->time()), next->name(), TimeHelper::counter_to_seconds(next->time())); + + assert(cur != next, "Invariant"); + cur = next; } } +#endif diff --git a/src/hotspot/share/gc/g1/g1ServiceThread.hpp b/src/hotspot/share/gc/g1/g1ServiceThread.hpp index 3454f65d02ed4..331e254012e9d 100644 --- a/src/hotspot/share/gc/g1/g1ServiceThread.hpp +++ b/src/hotspot/share/gc/g1/g1ServiceThread.hpp @@ -28,43 +28,104 @@ #include "gc/shared/concurrentGCThread.hpp" #include "runtime/mutex.hpp" +class G1ServiceTaskQueue; +class G1ServiceThread; + +class G1ServiceTask : public CHeapObj { + friend class G1ServiceTaskQueue; + friend class G1ServiceThread; + + // The next absolute time this task should be executed. + jlong _time; + // Name of the task. + const char* _name; + // Next task in the task queue. + G1ServiceTask* _next; + // The service thread this task is registered with. + G1ServiceThread* _service_thread; + + void set_service_thread(G1ServiceThread* thread); + bool is_registered(); + +public: + G1ServiceTask(const char* name); + + jlong time(); + const char* name(); + G1ServiceTask* next(); + + // Do the actual work for the task. To get added back to the + // execution queue a task can call schedule(delay_ms). + virtual void execute() = 0; + +protected: + // Schedule the task on the associated service thread + // using the provided delay in milliseconds. + void schedule(jlong delay_ms); + + // These setters are protected for use by testing and the + // sentinel task only. + void set_time(jlong time); + void set_next(G1ServiceTask* next); +}; + +class G1SentinelTask : public G1ServiceTask { +public: + G1SentinelTask(); + virtual void execute(); +}; + +class G1ServiceTaskQueue { + // The sentinel task is the entry point of this priority queue holding the + // service tasks. The queue is ordered by the time the tasks are scheduled + // to run. To simplify list management the sentinel task has its time set + // to max_jlong, guaranteeing it to be the last task in the queue. + G1SentinelTask _sentinel; + + // Verify that the queue is ordered. + void verify_task_queue() NOT_DEBUG_RETURN; +public: + G1ServiceTaskQueue(); + G1ServiceTask* pop(); + G1ServiceTask* peek(); + void add_ordered(G1ServiceTask* task); + bool is_empty(); +}; + // The G1ServiceThread is used to periodically do a number of different tasks: // - re-assess the validity of the prediction for the // remembered set lengths of the young generation. // - check if a periodic GC should be scheduled. class G1ServiceThread: public ConcurrentGCThread { -private: + friend class G1ServiceTask; + // The monitor is used to ensure thread safety for the task queue + // and allow other threads to signal the service thread to wake up. Monitor _monitor; - - double _last_periodic_gc_attempt_s; + G1ServiceTaskQueue _task_queue; double _vtime_accum; // Accumulated virtual time. - // Sample the current length of remembered sets for young. - // - // At the end of the GC G1 determines the length of the young gen based on - // how much time the next GC can take, and when the next GC may occur - // according to the MMU. - // - // The assumption is that a significant part of the GC is spent on scanning - // the remembered sets (and many other components), so this thread constantly - // reevaluates the prediction for the remembered set scanning costs, and potentially - // G1Policy resizes the young gen. This may do a premature GC or even - // increase the young gen size to keep pause time length goal. - void sample_young_list_rs_length(); - void run_service(); - void check_for_periodic_gc(); - void stop_service(); + // Returns the time in milliseconds until the next task is due. + // Used both to determine if there are tasks ready to run and + // how long to sleep when nothing is ready. + int64_t time_to_next_task_ms(); void sleep_before_next_cycle(); - bool should_start_periodic_gc(); + G1ServiceTask* pop_due_task(); + void run_task(G1ServiceTask* task); + + // Schedule a registered task to run after the given delay. + void schedule_task(G1ServiceTask* task, jlong delay); public: G1ServiceThread(); double vtime_accum() { return _vtime_accum; } + // Register a task with the service thread and schedule it. If + // no delay is specified the task is scheduled to run directly. + void register_task(G1ServiceTask* task, jlong delay = 0); }; #endif // SHARE_GC_G1_G1SERVICETHREAD_HPP diff --git a/test/hotspot/gtest/gc/g1/test_g1ServiceThread.cpp b/test/hotspot/gtest/gc/g1/test_g1ServiceThread.cpp new file mode 100644 index 0000000000000..5fe28daee4d57 --- /dev/null +++ b/test/hotspot/gtest/gc/g1/test_g1ServiceThread.cpp @@ -0,0 +1,183 @@ +/* + * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +#include "precompiled.hpp" +#include "gc/g1/g1ServiceThread.hpp" +#include "runtime/interfaceSupport.inline.hpp" +#include "runtime/os.hpp" +#include "utilities/autoRestore.hpp" +#include "unittest.hpp" + +class CheckTask : public G1ServiceTask { + int _execution_count; + bool _reschedule; + +public: + CheckTask(const char* name) : + G1ServiceTask(name), + _execution_count(0), + _reschedule(true) { } + virtual void execute() { + _execution_count++; + if (_reschedule) { + schedule(100); + } + } + + int execution_count() { return _execution_count;} + void set_reschedule(bool reschedule) { _reschedule = reschedule; } +}; + +static void stop_service_thread(G1ServiceThread* thread) { + ThreadInVMfromNative tvn(JavaThread::current()); + thread->stop(); +} + +// Test that a task that is added during runtime gets run. +TEST_VM(G1ServiceThread, test_add) { + // Create thread and let it start. + G1ServiceThread* st = new G1ServiceThread(); + os::naked_short_sleep(500); + + CheckTask ct("AddAndRun"); + st->register_task(&ct); + + // Give CheckTask time to run. + os::naked_short_sleep(500); + stop_service_thread(st); + + ASSERT_GT(ct.execution_count(), 0); +} + +// Test that a task that is added while the service thread is +// waiting gets run in a timely manner. +TEST_VM(G1ServiceThread, test_add_while_waiting) { + // Make sure default tasks use long intervals so that the service thread + // is doing a long wait for the next execution. + AutoModifyRestore f1(G1PeriodicGCInterval, 100000); + AutoModifyRestore f2(G1ConcRefinementServiceIntervalMillis, 100000); + + // Create thread and let it start. + G1ServiceThread* st = new G1ServiceThread(); + os::naked_short_sleep(500); + + // Register a new task that should run right away. + CheckTask ct("AddWhileWaiting"); + st->register_task(&ct); + + // Give CheckTask time to run. + os::naked_short_sleep(500); + stop_service_thread(st); + + ASSERT_GT(ct.execution_count(), 0); +} + +// Test that a task with negative timeout is not rescheduled. +TEST_VM(G1ServiceThread, test_add_run_once) { + // Create thread and let it start. + G1ServiceThread* st = new G1ServiceThread(); + os::naked_short_sleep(500); + + // Set reschedule to false to only run once. + CheckTask ct("AddRunOnce"); + ct.set_reschedule(false); + st->register_task(&ct); + + // Give CheckTask time to run. + os::naked_short_sleep(500); + stop_service_thread(st); + + // Should be exactly 1 since negative timeout should + // prevent rescheduling. + ASSERT_EQ(ct.execution_count(), 1); +} + +class TestTask : public G1ServiceTask { + jlong _delay_ms; +public: + TestTask(jlong delay) : + G1ServiceTask("TestTask"), + _delay_ms(delay) { + set_time(delay); + } + virtual void execute() {} + void update_time(jlong now, int multiplier) { + set_time(now + (_delay_ms * multiplier)); + } +}; + +TEST_VM(G1ServiceTaskQueue, add_ordered) { + G1ServiceTaskQueue queue; + + int num_test_tasks = 5; + for (int i = 1; i <= num_test_tasks; i++) { + // Create tasks with different timeout. + TestTask* task = new TestTask(100 * i); + queue.add_ordered(task); + } + + // Now fake a run-loop, that reschedules the tasks using a + // random multiplier. + for (jlong now = 0; now < 1000000; now++) { + // Random multiplier is at least 1 to ensure progress. + int multiplier = 1 + os::random() % 10; + while (queue.peek()->time() < now) { + TestTask* task = (TestTask*) queue.pop(); + // Update delay multiplier. + task->execute(); + task->update_time(now, multiplier); + // All additions will verify that the queue is sorted. + queue.add_ordered(task); + } + } + + while (!queue.is_empty()) { + G1ServiceTask* task = queue.pop(); + delete task; + } +} + +#ifdef ASSERT +TEST_VM_ASSERT_MSG(G1ServiceTaskQueue, pop_empty, + "Should never try to verify empty queue") { + G1ServiceTaskQueue queue; + queue.pop(); +} + +TEST_VM_ASSERT_MSG(G1ServiceTaskQueue, peek_empty, + "Should never try to verify empty queue") { + G1ServiceTaskQueue queue; + queue.peek(); +} + +TEST_VM_ASSERT_MSG(G1ServiceTaskQueue, set_time_in_queue, + "Not allowed to update time while in queue") { + G1ServiceTaskQueue queue; + TestTask a(100); + queue.add_ordered(&a); + // Not allowed to update time while in queue. + a.update_time(500, 1); +} + +#endif From b8d4e02ce77367711fda23dd330bd90f0280babd Mon Sep 17 00:00:00 2001 From: Jorn Vernee Date: Tue, 3 Nov 2020 12:10:48 +0000 Subject: [PATCH 30/32] 8255374: Add a dropReturn MethodHandle combinator Reviewed-by: redestad --- .../java/lang/invoke/MethodHandles.java | 23 +++++++ .../invoke/MethodHandles/TestDropReturn.java | 68 +++++++++++++++++++ 2 files changed, 91 insertions(+) create mode 100644 test/jdk/java/lang/invoke/MethodHandles/TestDropReturn.java 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 64698d94a003f..7a615729c4e67 100644 --- a/src/java.base/share/classes/java/lang/invoke/MethodHandles.java +++ b/src/java.base/share/classes/java/lang/invoke/MethodHandles.java @@ -62,6 +62,7 @@ import java.util.stream.Collectors; import java.util.stream.Stream; +import static java.lang.invoke.LambdaForm.BasicType.V_TYPE; import static java.lang.invoke.MethodHandleImpl.Intrinsic; import static java.lang.invoke.MethodHandleNatives.Constants.*; import static java.lang.invoke.MethodHandleStatics.newIllegalArgumentException; @@ -5205,6 +5206,28 @@ public static MethodHandle dropArgumentsToMatch(MethodHandle target, int skip, L return dropArgumentsToMatch(target, skip, newTypes, pos, false); } + /** + * Drop the return value of the target handle (if any). + * The returned method handle will have a {@code void} return type. + * + * @param target the method handle to adapt + * @return a possibly adapted method handle + * @throws NullPointerException if {@code target} is null + * @since 16 + */ + public static MethodHandle dropReturn(MethodHandle target) { + Objects.requireNonNull(target); + MethodType oldType = target.type(); + Class oldReturnType = oldType.returnType(); + if (oldReturnType == void.class) + return target; + MethodType newType = oldType.changeReturnType(void.class); + BoundMethodHandle result = target.rebind(); + LambdaForm lform = result.editor().filterReturnForm(V_TYPE, true); + result = result.copyWith(newType, lform); + return result; + } + /** * Adapts a target method handle by pre-processing * one or more of its arguments, each with its own unary filter function, diff --git a/test/jdk/java/lang/invoke/MethodHandles/TestDropReturn.java b/test/jdk/java/lang/invoke/MethodHandles/TestDropReturn.java new file mode 100644 index 0000000000000..ff31dd63f0ba6 --- /dev/null +++ b/test/jdk/java/lang/invoke/MethodHandles/TestDropReturn.java @@ -0,0 +1,68 @@ +/* + * Copyright (c) 2020, 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 8255398 + * @run testng TestDropReturn + */ + +import org.testng.annotations.DataProvider; +import org.testng.annotations.Test; + +import java.lang.invoke.MethodHandle; +import java.lang.invoke.MethodHandles; + +import static java.lang.invoke.MethodType.methodType; +import static org.testng.Assert.assertEquals; + +public class TestDropReturn { + + @Test(dataProvider = "dropReturnCases") + public void testDropReturn(Class cls, Object testValue) throws Throwable { + MethodHandle mh = MethodHandles.identity(cls); + assertEquals(mh.type(), methodType(cls, cls)); + Object x = mh.invoke(testValue); + assertEquals(x, testValue); + + mh = MethodHandles.dropReturn(mh); + assertEquals(mh.type(), methodType(void.class, cls)); + mh.invoke(testValue); // should at least work + } + + @DataProvider + public static Object[][] dropReturnCases() { + return new Object[][]{ + { boolean.class, true }, + { byte.class, (byte) 10 }, + { char.class, 'x' }, + { short.class, (short) 10 }, + { int.class, 10 }, + { long.class, 10L }, + { float.class, 10F }, + { double.class, 10D }, + { Object.class, new Object() }, + { String.class, "ABCD" }, + }; + } +} From 63461d59a1acc16b6daed0ebceda24f012a7c868 Mon Sep 17 00:00:00 2001 From: Richard Reingruber Date: Tue, 3 Nov 2020 12:36:59 +0000 Subject: [PATCH 31/32] 8255072: [TESTBUG] com/sun/jdi/EATests.java should not fail if expected VMOutOfMemoryException is not thrown Reviewed-by: cjplummer, sspitsyn, kvn --- test/jdk/ProblemList-zgc.txt | 2 - test/jdk/com/sun/jdi/EATests.java | 83 +++++++++++++++++++++---------- 2 files changed, 57 insertions(+), 28 deletions(-) diff --git a/test/jdk/ProblemList-zgc.txt b/test/jdk/ProblemList-zgc.txt index 98343188917bd..8fd7a85d1c468 100644 --- a/test/jdk/ProblemList-zgc.txt +++ b/test/jdk/ProblemList-zgc.txt @@ -26,5 +26,3 @@ # List of quarantined tests for testing with ZGC. # ############################################################################# - -com/sun/jdi/EATests.java#id0 8255072 generic-all diff --git a/test/jdk/com/sun/jdi/EATests.java b/test/jdk/com/sun/jdi/EATests.java index 2abba8113bc9c..11d548ab59398 100644 --- a/test/jdk/com/sun/jdi/EATests.java +++ b/test/jdk/com/sun/jdi/EATests.java @@ -147,6 +147,7 @@ import jdk.test.lib.Asserts; import sun.hotspot.WhiteBox; +import sun.hotspot.gc.GC; // @@ -297,6 +298,7 @@ public static class TargetVMOptions { public final boolean EliminateAllocations; public final boolean DeoptimizeObjectsALot; public final boolean DoEscapeAnalysis; + public final boolean ZGCIsSelected; public TargetVMOptions(EATests env, ClassType testCaseBaseTargetClass) { Value val; @@ -309,6 +311,8 @@ public TargetVMOptions(EATests env, ClassType testCaseBaseTargetClass) { DeoptimizeObjectsALot = ((PrimitiveValue) val).booleanValue(); val = testCaseBaseTargetClass.getValue(testCaseBaseTargetClass.fieldByName("UseJVMCICompiler")); UseJVMCICompiler = ((PrimitiveValue) val).booleanValue(); + val = testCaseBaseTargetClass.getValue(testCaseBaseTargetClass.fieldByName("ZGCIsSelected")); + ZGCIsSelected = ((PrimitiveValue) val).booleanValue(); } } @@ -774,12 +778,14 @@ public static boolean unbox(Boolean value, boolean dflt) { return value == null ? dflt : value; } - public static final boolean UseJVMCICompiler = unbox(WB.getBooleanVMFlag("UseJVMCICompiler"), false); // read by debugger - public static final boolean DoEscapeAnalysis = unbox(WB.getBooleanVMFlag("DoEscapeAnalysis"), UseJVMCICompiler); - public static final boolean EliminateAllocations = unbox(WB.getBooleanVMFlag("EliminateAllocations"), UseJVMCICompiler); // read by debugger - public static final boolean DeoptimizeObjectsALot = WB.getBooleanVMFlag("DeoptimizeObjectsALot"); // read by debugger + // Some of the fields are only read by the debugger + public static final boolean UseJVMCICompiler = unbox(WB.getBooleanVMFlag("UseJVMCICompiler"), false); + public static final boolean DoEscapeAnalysis = unbox(WB.getBooleanVMFlag("DoEscapeAnalysis"), UseJVMCICompiler); + public static final boolean EliminateAllocations = unbox(WB.getBooleanVMFlag("EliminateAllocations"), UseJVMCICompiler); + public static final boolean DeoptimizeObjectsALot = WB.getBooleanVMFlag("DeoptimizeObjectsALot"); public static final long BiasedLockingBulkRebiasThreshold = WB.getIntxVMFlag("BiasedLockingBulkRebiasThreshold"); public static final long BiasedLockingBulkRevokeThreshold = WB.getIntxVMFlag("BiasedLockingBulkRevokeThreshold"); + public static final boolean ZGCIsSelected = GC.Z.isSelected(); public String testMethodName; public int testMethodDepth; @@ -1079,7 +1085,7 @@ static class LinkedList { LinkedList l; public long[] array; public LinkedList(LinkedList l, int size) { - this.array = new long[size]; + this.array = size > 0 ? new long[size] : null; this.l = l; } } @@ -1089,12 +1095,13 @@ public LinkedList(LinkedList l, int size) { public void consumeAllMemory() { msg("consume all memory"); int size = 128 * 1024 * 1024; - while(size > 0) { + while(true) { try { while(true) { consumedMemory = new LinkedList(consumedMemory, size); } } catch(OutOfMemoryError oom) { + if (size == 0) break; } size = size / 2; } @@ -2603,10 +2610,8 @@ public void runTestCase() throws Exception { } freeAllMemory(); // We succeeded to pop just one frame. When we continue, we will call dontinline_brkpt() again. - Asserts.assertTrue(coughtOom || !env.targetVMOptions.EliminateAllocations, - "PopFrame should have triggered an OOM exception in target"); - String expectedTopFrame = - env.targetVMOptions.EliminateAllocations ? "dontinline_consume_all_memory_brkpt" : "dontinline_testMethod"; + Asserts.assertTrue(coughtOom, "PopFrame should have triggered an OOM exception in target"); + String expectedTopFrame = "dontinline_consume_all_memory_brkpt"; Asserts.assertEQ(expectedTopFrame, thread.frame(0).location().method().name()); printStack(thread); } @@ -2615,7 +2620,12 @@ public void runTestCase() throws Exception { public boolean shouldSkip() { // OOMEs because of realloc failures with DeoptimizeObjectsALot are too random. // And Graal currently doesn't provide all information about non-escaping objects in debug info - return super.shouldSkip() || env.targetVMOptions.DeoptimizeObjectsALot || env.targetVMOptions.UseJVMCICompiler; + return super.shouldSkip() || + !env.targetVMOptions.EliminateAllocations || + // With ZGC the OOME is not always thrown as expected + env.targetVMOptions.ZGCIsSelected || + env.targetVMOptions.DeoptimizeObjectsALot || + env.targetVMOptions.UseJVMCICompiler; } } @@ -2655,7 +2665,12 @@ public long getExpectedLResult() { public boolean shouldSkip() { // OOMEs because of realloc failures with DeoptimizeObjectsALot are too random. // And Graal currently doesn't provide all information about non-escaping objects in debug info - return super.shouldSkip() || DeoptimizeObjectsALot || UseJVMCICompiler; + return super.shouldSkip() || + !EliminateAllocations || + // With ZGC the OOME is not always thrown as expected + ZGCIsSelected || + DeoptimizeObjectsALot || + UseJVMCICompiler; } } @@ -2694,10 +2709,8 @@ public void runTestCase() throws Exception { freeAllMemory(); setField(testCase, "loopCount", env.vm().mirrorOf(0)); // terminate loop - Asserts.assertTrue(coughtOom || !env.targetVMOptions.EliminateAllocations, - "PopFrame should have triggered an OOM exception in target"); - String expectedTopFrame = - env.targetVMOptions.EliminateAllocations ? "inlinedCallForcedToReturn" : "dontinline_testMethod"; + Asserts.assertTrue(coughtOom, "PopFrame should have triggered an OOM exception in target"); + String expectedTopFrame = "inlinedCallForcedToReturn"; Asserts.assertEQ(expectedTopFrame, thread.frame(0).location().method().name()); } @@ -2705,7 +2718,12 @@ public void runTestCase() throws Exception { public boolean shouldSkip() { // OOMEs because of realloc failures with DeoptimizeObjectsALot are too random. // And Graal currently doesn't provide all information about non-escaping objects in debug info - return super.shouldSkip() || env.targetVMOptions.DeoptimizeObjectsALot || env.targetVMOptions.UseJVMCICompiler; + return super.shouldSkip() || + !env.targetVMOptions.EliminateAllocations || + // With ZGC the OOME is not always thrown as expected + env.targetVMOptions.ZGCIsSelected || + env.targetVMOptions.DeoptimizeObjectsALot || + env.targetVMOptions.UseJVMCICompiler; } } @@ -2761,7 +2779,12 @@ public void warmupDone() { public boolean shouldSkip() { // OOMEs because of realloc failures with DeoptimizeObjectsALot are too random. // And Graal currently doesn't provide all information about non-escaping objects in debug info - return super.shouldSkip() || DeoptimizeObjectsALot || UseJVMCICompiler; + return super.shouldSkip() || + !EliminateAllocations || + // With ZGC the OOME is not always thrown as expected + ZGCIsSelected || + DeoptimizeObjectsALot || + UseJVMCICompiler; } } @@ -2948,12 +2971,10 @@ public void runTestCase() throws Exception { coughtOom = true; } freeAllMemory(); - if (env.targetVMOptions.EliminateAllocations) { - printStack(thread); - Asserts.assertTrue(coughtOom, "ForceEarlyReturn should have triggered an OOM exception in target"); - msg("ForceEarlyReturn(2)"); - thread.forceEarlyReturn(env.vm().mirrorOf(43)); - } + Asserts.assertTrue(coughtOom, "ForceEarlyReturn should have triggered an OOM exception in target"); + printStack(thread); + msg("ForceEarlyReturn(2)"); + thread.forceEarlyReturn(env.vm().mirrorOf(43)); msg("Step over instruction to do the forced return"); env.stepOverInstruction(thread); printStack(thread); @@ -2964,7 +2985,12 @@ public void runTestCase() throws Exception { public boolean shouldSkip() { // OOMEs because of realloc failures with DeoptimizeObjectsALot are too random. // And Graal currently doesn't support Force Early Return - return super.shouldSkip() || env.targetVMOptions.DeoptimizeObjectsALot || env.targetVMOptions.UseJVMCICompiler; + return super.shouldSkip() || + !env.targetVMOptions.EliminateAllocations || + // With ZGC the OOME is not always thrown as expected + env.targetVMOptions.ZGCIsSelected || + env.targetVMOptions.DeoptimizeObjectsALot || + env.targetVMOptions.UseJVMCICompiler; } } @@ -3021,7 +3047,12 @@ public void warmupDone() { public boolean shouldSkip() { // OOMEs because of realloc failures with DeoptimizeObjectsALot are too random. // And Graal currently doesn't support Force Early Return - return super.shouldSkip() || DeoptimizeObjectsALot || UseJVMCICompiler; + return super.shouldSkip() || + !EliminateAllocations || + // With ZGC the OOME is not always thrown as expected + ZGCIsSelected || + DeoptimizeObjectsALot || + UseJVMCICompiler; } } From 93ef0091dba9426037129bc9676561ae742f0d5c Mon Sep 17 00:00:00 2001 From: Roman Kennke Date: Tue, 3 Nov 2020 12:59:17 +0000 Subject: [PATCH 32/32] 8255762: Shenandoah: Consolidate/streamline interpreter LRBs Reviewed-by: shade --- .../shenandoahBarrierSetAssembler_aarch64.cpp | 149 ++------- .../shenandoahBarrierSetAssembler_aarch64.hpp | 11 +- .../shenandoahBarrierSetAssembler_x86.cpp | 314 +++++------------- .../shenandoahBarrierSetAssembler_x86.hpp | 13 +- 4 files changed, 110 insertions(+), 377 deletions(-) diff --git a/src/hotspot/cpu/aarch64/gc/shenandoah/shenandoahBarrierSetAssembler_aarch64.cpp b/src/hotspot/cpu/aarch64/gc/shenandoah/shenandoahBarrierSetAssembler_aarch64.cpp index e4b62a523dee8..16acaa6797ec4 100644 --- a/src/hotspot/cpu/aarch64/gc/shenandoah/shenandoahBarrierSetAssembler_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/gc/shenandoah/shenandoahBarrierSetAssembler_aarch64.cpp @@ -43,8 +43,6 @@ #define __ masm-> -address ShenandoahBarrierSetAssembler::_shenandoah_lrb = NULL; - void ShenandoahBarrierSetAssembler::arraycopy_prologue(MacroAssembler* masm, DecoratorSet decorators, bool is_oop, Register src, Register dst, Register count, RegSet saved_regs) { if (is_oop) { @@ -227,18 +225,18 @@ void ShenandoahBarrierSetAssembler::resolve_forward_pointer_not_null(MacroAssemb } } -void ShenandoahBarrierSetAssembler::load_reference_barrier_not_null(MacroAssembler* masm, Register dst, Address load_addr) { +void ShenandoahBarrierSetAssembler::load_reference_barrier(MacroAssembler* masm, Register dst, Address load_addr, bool weak) { assert(ShenandoahLoadRefBarrier, "Should be enabled"); assert(dst != rscratch2, "need rscratch2"); assert_different_registers(load_addr.base(), load_addr.index(), rscratch1, rscratch2); - Label done; + Label heap_stable, not_cset; __ enter(); Address gc_state(rthread, in_bytes(ShenandoahThreadLocalData::gc_state_offset())); __ ldrb(rscratch2, gc_state); // Check for heap stability - __ tbz(rscratch2, ShenandoahHeap::HAS_FORWARDED_BITPOS, done); + __ tbz(rscratch2, ShenandoahHeap::HAS_FORWARDED_BITPOS, heap_stable); // use r1 for load address Register result_dst = dst; @@ -253,51 +251,36 @@ void ShenandoahBarrierSetAssembler::load_reference_barrier_not_null(MacroAssembl __ lea(r1, load_addr); __ mov(r0, dst); - __ far_call(RuntimeAddress(CAST_FROM_FN_PTR(address, ShenandoahBarrierSetAssembler::shenandoah_lrb()))); - - __ mov(result_dst, r0); - __ pop(to_save, sp); - - __ bind(done); - __ leave(); -} - -void ShenandoahBarrierSetAssembler::load_reference_barrier_weak(MacroAssembler* masm, Register dst, Address load_addr) { - if (!ShenandoahLoadRefBarrier) { - return; + // Test for in-cset + if (!weak) { + __ mov(rscratch2, ShenandoahHeap::in_cset_fast_test_addr()); + __ lsr(rscratch1, r0, ShenandoahHeapRegion::region_size_bytes_shift_jint()); + __ ldrb(rscratch2, Address(rscratch2, rscratch1)); + __ tbz(rscratch2, 0, not_cset); } - assert(dst != rscratch2, "need rscratch2"); - - Label is_null; - Label done; - - __ block_comment("load_reference_barrier_weak { "); - - __ cbz(dst, is_null); - - __ enter(); - - Address gc_state(rthread, in_bytes(ShenandoahThreadLocalData::gc_state_offset())); - __ ldrb(rscratch2, gc_state); - - // Check for heap in evacuation phase - __ tbz(rscratch2, ShenandoahHeap::HAS_FORWARDED_BITPOS, done); - - __ mov(rscratch2, dst); __ push_call_clobbered_registers(); - __ mov(lr, CAST_FROM_FN_PTR(address, ShenandoahRuntime::load_reference_barrier_weak)); - __ lea(r1, load_addr); - __ mov(r0, rscratch2); + if (weak) { + __ mov(lr, CAST_FROM_FN_PTR(address, ShenandoahRuntime::load_reference_barrier_weak)); + } else { + if (UseCompressedOops) { + __ mov(lr, CAST_FROM_FN_PTR(address, ShenandoahRuntime::load_reference_barrier_narrow)); + } else { + __ mov(lr, CAST_FROM_FN_PTR(address, ShenandoahRuntime::load_reference_barrier)); + } + } __ blr(lr); - __ mov(rscratch2, r0); + __ mov(rscratch1, r0); __ pop_call_clobbered_registers(); - __ mov(dst, rscratch2); + __ mov(r0, rscratch1); - __ bind(done); + __ bind(not_cset); + + __ mov(result_dst, r0); + __ pop(to_save, sp); + + __ bind(heap_stable); __ leave(); - __ bind(is_null); - __ block_comment("} load_reference_barrier_weak"); } void ShenandoahBarrierSetAssembler::storeval_barrier(MacroAssembler* masm, Register dst, Register tmp) { @@ -308,15 +291,6 @@ void ShenandoahBarrierSetAssembler::storeval_barrier(MacroAssembler* masm, Regis } } -void ShenandoahBarrierSetAssembler::load_reference_barrier(MacroAssembler* masm, Register dst, Address load_addr) { - if (ShenandoahLoadRefBarrier) { - Label is_null; - __ cbz(dst, is_null); - load_reference_barrier_not_null(masm, dst, load_addr); - __ bind(is_null); - } -} - // // Arguments: // @@ -352,11 +326,8 @@ void ShenandoahBarrierSetAssembler::load_at(MacroAssembler* masm, DecoratorSet d BarrierSetAssembler::load_at(masm, decorators, type, dst, src, tmp1, tmp_thread); - if (ShenandoahBarrierSet::use_load_reference_barrier_weak(decorators, type)) { - load_reference_barrier_weak(masm, dst, src); - } else { - load_reference_barrier(masm, dst, src); - } + bool weak = ShenandoahBarrierSet::use_load_reference_barrier_weak(decorators, type); + load_reference_barrier(masm, dst, src, weak); if (dst != result_dst) { __ mov(result_dst, dst); @@ -754,67 +725,3 @@ void ShenandoahBarrierSetAssembler::generate_c1_load_reference_barrier_runtime_s #undef __ #endif // COMPILER1 - -address ShenandoahBarrierSetAssembler::shenandoah_lrb() { - assert(_shenandoah_lrb != NULL, "need load reference barrier stub"); - return _shenandoah_lrb; -} - -#define __ cgen->assembler()-> - -// Shenandoah load reference barrier. -// -// Input: -// r0: OOP to evacuate. Not null. -// r1: load address -// -// Output: -// r0: Pointer to evacuated OOP. -// -// Trash rscratch1, rscratch2. Preserve everything else. -address ShenandoahBarrierSetAssembler::generate_shenandoah_lrb(StubCodeGenerator* cgen) { - - __ align(6); - StubCodeMark mark(cgen, "StubRoutines", "shenandoah_lrb"); - address start = __ pc(); - - Label slow_path; - __ mov(rscratch2, ShenandoahHeap::in_cset_fast_test_addr()); - __ lsr(rscratch1, r0, ShenandoahHeapRegion::region_size_bytes_shift_jint()); - __ ldrb(rscratch2, Address(rscratch2, rscratch1)); - __ tbnz(rscratch2, 0, slow_path); - __ ret(lr); - - __ bind(slow_path); - __ enter(); // required for proper stackwalking of RuntimeStub frame - - __ push_call_clobbered_registers(); - - if (UseCompressedOops) { - __ mov(lr, CAST_FROM_FN_PTR(address, ShenandoahRuntime::load_reference_barrier_narrow)); - } else { - __ mov(lr, CAST_FROM_FN_PTR(address, ShenandoahRuntime::load_reference_barrier)); - } - __ blr(lr); - __ mov(rscratch1, r0); - __ pop_call_clobbered_registers(); - __ mov(r0, rscratch1); - - __ leave(); // required for proper stackwalking of RuntimeStub frame - __ ret(lr); - - return start; -} - -#undef __ - -void ShenandoahBarrierSetAssembler::barrier_stubs_init() { - if (ShenandoahLoadRefBarrier) { - int stub_code_size = 2048; - ResourceMark rm; - BufferBlob* bb = BufferBlob::create("shenandoah_barrier_stubs", stub_code_size); - CodeBuffer buf(bb); - StubCodeGenerator cgen(&buf); - _shenandoah_lrb = generate_shenandoah_lrb(&cgen); - } -} diff --git a/src/hotspot/cpu/aarch64/gc/shenandoah/shenandoahBarrierSetAssembler_aarch64.hpp b/src/hotspot/cpu/aarch64/gc/shenandoah/shenandoahBarrierSetAssembler_aarch64.hpp index 30446b65b35e2..823880f85f1c5 100644 --- a/src/hotspot/cpu/aarch64/gc/shenandoah/shenandoahBarrierSetAssembler_aarch64.hpp +++ b/src/hotspot/cpu/aarch64/gc/shenandoah/shenandoahBarrierSetAssembler_aarch64.hpp @@ -38,8 +38,6 @@ class StubCodeGenerator; class ShenandoahBarrierSetAssembler: public BarrierSetAssembler { private: - static address _shenandoah_lrb; - void satb_write_barrier_pre(MacroAssembler* masm, Register obj, Register pre_val, @@ -57,14 +55,9 @@ class ShenandoahBarrierSetAssembler: public BarrierSetAssembler { void resolve_forward_pointer(MacroAssembler* masm, Register dst, Register tmp = noreg); void resolve_forward_pointer_not_null(MacroAssembler* masm, Register dst, Register tmp = noreg); - void load_reference_barrier(MacroAssembler* masm, Register dst, Address load_addr); - void load_reference_barrier_not_null(MacroAssembler* masm, Register dst, Address load_addr); - void load_reference_barrier_weak(MacroAssembler* masm, Register dst, Address load_addr); - - address generate_shenandoah_lrb(StubCodeGenerator* cgen); + void load_reference_barrier(MacroAssembler* masm, Register dst, Address load_addr, bool weak); public: - static address shenandoah_lrb(); void storeval_barrier(MacroAssembler* masm, Register dst, Register tmp); @@ -85,8 +78,6 @@ class ShenandoahBarrierSetAssembler: public BarrierSetAssembler { Register obj, Register tmp, Label& slowpath); void cmpxchg_oop(MacroAssembler* masm, Register addr, Register expected, Register new_val, bool acquire, bool release, bool is_cae, Register result); - - virtual void barrier_stubs_init(); }; #endif // CPU_AARCH64_GC_SHENANDOAH_SHENANDOAHBARRIERSETASSEMBLER_AARCH64_HPP diff --git a/src/hotspot/cpu/x86/gc/shenandoah/shenandoahBarrierSetAssembler_x86.cpp b/src/hotspot/cpu/x86/gc/shenandoah/shenandoahBarrierSetAssembler_x86.cpp index 63ba5434856c5..e47acbea8d595 100644 --- a/src/hotspot/cpu/x86/gc/shenandoah/shenandoahBarrierSetAssembler_x86.cpp +++ b/src/hotspot/cpu/x86/gc/shenandoah/shenandoahBarrierSetAssembler_x86.cpp @@ -32,7 +32,6 @@ #include "gc/shenandoah/shenandoahThreadLocalData.hpp" #include "gc/shenandoah/heuristics/shenandoahHeuristics.hpp" #include "interpreter/interpreter.hpp" -#include "interpreter/interp_masm.hpp" #include "runtime/sharedRuntime.hpp" #include "runtime/thread.hpp" #include "utilities/macros.hpp" @@ -44,8 +43,6 @@ #define __ masm-> -address ShenandoahBarrierSetAssembler::_shenandoah_lrb = NULL; - static void save_xmm_registers(MacroAssembler* masm) { __ subptr(rsp, 64); __ movdbl(Address(rsp, 0), xmm0); @@ -271,11 +268,14 @@ void ShenandoahBarrierSetAssembler::satb_write_barrier_pre(MacroAssembler* masm, __ bind(done); } -void ShenandoahBarrierSetAssembler::load_reference_barrier_not_null(MacroAssembler* masm, Register dst, Address src) { +void ShenandoahBarrierSetAssembler::load_reference_barrier(MacroAssembler* masm, Register dst, Address src, bool weak) { assert(ShenandoahLoadRefBarrier, "Should be enabled"); - Label done; + Label heap_stable, not_cset; + __ block_comment("load_reference_barrier { "); + + // Check if GC is active #ifdef _LP64 Register thread = r15_thread; #else @@ -289,138 +289,98 @@ void ShenandoahBarrierSetAssembler::load_reference_barrier_not_null(MacroAssembl Address gc_state(thread, in_bytes(ShenandoahThreadLocalData::gc_state_offset())); __ testb(gc_state, ShenandoahHeap::HAS_FORWARDED); - __ jccb(Assembler::zero, done); - - // Use rsi for src address - const Register src_addr = rsi; - // Setup address parameter first, if it does not clobber oop in dst - bool need_addr_setup = (src_addr != dst); - - if (need_addr_setup) { - __ push(src_addr); - __ lea(src_addr, src); - - if (dst != rax) { - // Move obj into rax and save rax - __ push(rax); - __ movptr(rax, dst); - } - } else { - // dst == rsi - __ push(rax); - __ movptr(rax, dst); - - // we can clobber it, since it is outgoing register - __ lea(src_addr, src); - } - - save_xmm_registers(masm); - __ call(RuntimeAddress(CAST_FROM_FN_PTR(address, ShenandoahBarrierSetAssembler::shenandoah_lrb()))); - restore_xmm_registers(masm); - - if (need_addr_setup) { - if (dst != rax) { - __ movptr(dst, rax); - __ pop(rax); + __ jcc(Assembler::zero, heap_stable); + + Register tmp1 = noreg; + if (!weak) { + // Test for object in cset + // Allocate tmp-reg. + for (int i = 0; i < 8; i++) { + Register r = as_Register(i); + if (r != rsp && r != rbp && r != dst && r != src.base() && r != src.index()) { + tmp1 = r; + break; + } } - __ pop(src_addr); - } else { - __ movptr(dst, rax); - __ pop(rax); - } - - __ bind(done); - -#ifndef _LP64 - __ pop(thread); -#endif -} - -void ShenandoahBarrierSetAssembler::load_reference_barrier_weak(MacroAssembler* masm, Register dst, Address src) { - if (!ShenandoahLoadRefBarrier) { - return; - } - - Label done; - Label not_null; - Label slow_path; - __ block_comment("load_reference_barrier_weak { "); - - // null check - __ testptr(dst, dst); - __ jcc(Assembler::notZero, not_null); - __ jmp(done); - __ bind(not_null); - + __ push(tmp1); + assert_different_registers(tmp1, src.base(), src.index()); + assert_different_registers(tmp1, dst); -#ifdef _LP64 - Register thread = r15_thread; -#else - Register thread = rcx; - if (thread == dst) { - thread = rbx; + // Optimized cset-test + __ movptr(tmp1, dst); + __ shrptr(tmp1, ShenandoahHeapRegion::region_size_bytes_shift_jint()); + __ movbool(tmp1, Address(tmp1, (intptr_t) ShenandoahHeap::in_cset_fast_test_addr(), Address::times_1)); + __ testbool(tmp1); + __ jcc(Assembler::zero, not_cset); } - __ push(thread); - __ get_thread(thread); -#endif - assert_different_registers(dst, thread); - - Address gc_state(thread, in_bytes(ShenandoahThreadLocalData::gc_state_offset())); - __ testb(gc_state, ShenandoahHeap::HAS_FORWARDED); -#ifndef _LP64 - __ pop(thread); -#endif - __ jccb(Assembler::notZero, slow_path); - __ jmp(done); - __ bind(slow_path); + uint num_saved_regs = 4 + (dst != rax ? 1 : 0) LP64_ONLY(+4); + __ subptr(rsp, num_saved_regs * wordSize); + uint slot = num_saved_regs; if (dst != rax) { - __ push(rax); + __ movptr(Address(rsp, (--slot) * wordSize), rax); } - __ push(rcx); - __ push(rdx); - __ push(rdi); - __ push(rsi); + __ movptr(Address(rsp, (--slot) * wordSize), rcx); + __ movptr(Address(rsp, (--slot) * wordSize), rdx); + __ movptr(Address(rsp, (--slot) * wordSize), rdi); + __ movptr(Address(rsp, (--slot) * wordSize), rsi); #ifdef _LP64 - __ push(r8); - __ push(r9); - __ push(r10); - __ push(r11); - __ push(r12); - __ push(r13); - __ push(r14); - __ push(r15); + __ movptr(Address(rsp, (--slot) * wordSize), r8); + __ movptr(Address(rsp, (--slot) * wordSize), r9); + __ movptr(Address(rsp, (--slot) * wordSize), r10); + __ movptr(Address(rsp, (--slot) * wordSize), r11); + // r12-r15 are callee saved in all calling conventions #endif + assert(slot == 0, "must use all slots"); - assert_different_registers(dst, rsi); - __ lea(rsi, src); + Register tmp2 = (dst == rsi) ? rdx : rsi; + assert_different_registers(dst, tmp2); + __ lea(tmp2, src); save_xmm_registers(masm); - __ call_VM_leaf(CAST_FROM_FN_PTR(address, ShenandoahRuntime::load_reference_barrier_weak), dst, rsi); + if (weak) { + __ super_call_VM_leaf(CAST_FROM_FN_PTR(address, ShenandoahRuntime::load_reference_barrier_weak), dst, tmp2); + } else { + if (UseCompressedOops) { + __ super_call_VM_leaf(CAST_FROM_FN_PTR(address, ShenandoahRuntime::load_reference_barrier_narrow), dst, tmp2); + } else { + __ super_call_VM_leaf(CAST_FROM_FN_PTR(address, ShenandoahRuntime::load_reference_barrier), dst, tmp2); + } + } restore_xmm_registers(masm); #ifdef _LP64 - __ pop(r15); - __ pop(r14); - __ pop(r13); - __ pop(r12); - __ pop(r11); - __ pop(r10); - __ pop(r9); - __ pop(r8); + __ movptr(r11, Address(rsp, (slot++) * wordSize)); + __ movptr(r10, Address(rsp, (slot++) * wordSize)); + __ movptr(r9, Address(rsp, (slot++) * wordSize)); + __ movptr(r8, Address(rsp, (slot++) * wordSize)); #endif - __ pop(rsi); - __ pop(rdi); - __ pop(rdx); - __ pop(rcx); + __ movptr(rsi, Address(rsp, (slot++) * wordSize)); + __ movptr(rdi, Address(rsp, (slot++) * wordSize)); + __ movptr(rdx, Address(rsp, (slot++) * wordSize)); + __ movptr(rcx, Address(rsp, (slot++) * wordSize)); if (dst != rax) { __ movptr(dst, rax); - __ pop(rax); + __ movptr(rax, Address(rsp, (slot++) * wordSize)); } - __ bind(done); - __ block_comment("} load_reference_barrier_weak"); + assert(slot == num_saved_regs, "must use all slots"); + __ addptr(rsp, num_saved_regs * wordSize); + + __ bind(not_cset); + + if (!weak) { + __ pop(tmp1); + } + + __ bind(heap_stable); + + __ block_comment("} load_reference_barrier"); + +#ifndef _LP64 + __ pop(thread); +#endif } void ShenandoahBarrierSetAssembler::storeval_barrier(MacroAssembler* masm, Register dst, Register tmp) { @@ -464,16 +424,6 @@ void ShenandoahBarrierSetAssembler::storeval_barrier_impl(MacroAssembler* masm, } } -void ShenandoahBarrierSetAssembler::load_reference_barrier(MacroAssembler* masm, Register dst, Address src) { - if (ShenandoahLoadRefBarrier) { - Label done; - __ testptr(dst, dst); - __ jcc(Assembler::zero, done); - load_reference_barrier_not_null(masm, dst, src); - __ bind(done); - } -} - // // Arguments: // @@ -504,7 +454,7 @@ void ShenandoahBarrierSetAssembler::load_at(MacroAssembler* masm, DecoratorSet d // Preserve src location for LRB if (dst == src.base() || dst == src.index()) { - // Use tmp1 for dst if possible, as it is not used in BarrierAssembler::load_at() + // Use tmp1 for dst if possible, as it is not used in BarrierAssembler::load_at() if (tmp1->is_valid() && tmp1 != src.base() && tmp1 != src.index()) { dst = tmp1; use_tmp1_for_dst = true; @@ -517,11 +467,8 @@ void ShenandoahBarrierSetAssembler::load_at(MacroAssembler* masm, DecoratorSet d BarrierSetAssembler::load_at(masm, decorators, type, dst, src, tmp1, tmp_thread); - if (ShenandoahBarrierSet::use_load_reference_barrier_weak(decorators, type)) { - load_reference_barrier_weak(masm, dst, src); - } else { - load_reference_barrier(masm, dst, src); - } + bool weak = ShenandoahBarrierSet::use_load_reference_barrier_weak(decorators, type); + load_reference_barrier(masm, dst, src, weak); // Move loaded oop to final destination if (dst != result_dst) { @@ -973,104 +920,3 @@ void ShenandoahBarrierSetAssembler::generate_c1_load_reference_barrier_runtime_s #undef __ #endif // COMPILER1 - -address ShenandoahBarrierSetAssembler::shenandoah_lrb() { - assert(_shenandoah_lrb != NULL, "need load reference barrier stub"); - return _shenandoah_lrb; -} - -#define __ cgen->assembler()-> - -/* - * Incoming parameters: - * rax: oop - * rsi: load address - */ -address ShenandoahBarrierSetAssembler::generate_shenandoah_lrb(StubCodeGenerator* cgen) { - __ align(CodeEntryAlignment); - StubCodeMark mark(cgen, "StubRoutines", "shenandoah_lrb"); - address start = __ pc(); - - Label slow_path; - - // We use RDI, which also serves as argument register for slow call. - // RAX always holds the src object ptr, except after the slow call, - // then it holds the result. R8/RBX is used as temporary register. - - Register tmp1 = rdi; - Register tmp2 = LP64_ONLY(r8) NOT_LP64(rbx); - - __ push(tmp1); - __ push(tmp2); - - // Check for object being in the collection set. - __ mov(tmp1, rax); - __ shrptr(tmp1, ShenandoahHeapRegion::region_size_bytes_shift_jint()); - __ movptr(tmp2, (intptr_t) ShenandoahHeap::in_cset_fast_test_addr()); - __ movbool(tmp2, Address(tmp2, tmp1, Address::times_1)); - __ testbool(tmp2); - __ jccb(Assembler::notZero, slow_path); - __ pop(tmp2); - __ pop(tmp1); - __ ret(0); - - __ bind(slow_path); - - __ push(rcx); - __ push(rdx); - __ push(rdi); -#ifdef _LP64 - __ push(r8); - __ push(r9); - __ push(r10); - __ push(r11); - __ push(r12); - __ push(r13); - __ push(r14); - __ push(r15); -#endif - __ push(rbp); - __ movptr(rbp, rsp); - __ andptr(rsp, -StackAlignmentInBytes); - __ push_FPU_state(); - if (UseCompressedOops) { - __ call_VM_leaf(CAST_FROM_FN_PTR(address, ShenandoahRuntime::load_reference_barrier_narrow), rax, rsi); - } else { - __ call_VM_leaf(CAST_FROM_FN_PTR(address, ShenandoahRuntime::load_reference_barrier), rax, rsi); - } - __ pop_FPU_state(); - __ movptr(rsp, rbp); - __ pop(rbp); -#ifdef _LP64 - __ pop(r15); - __ pop(r14); - __ pop(r13); - __ pop(r12); - __ pop(r11); - __ pop(r10); - __ pop(r9); - __ pop(r8); -#endif - __ pop(rdi); - __ pop(rdx); - __ pop(rcx); - - __ pop(tmp2); - __ pop(tmp1); - __ ret(0); - - return start; -} - -#undef __ - -void ShenandoahBarrierSetAssembler::barrier_stubs_init() { - if (ShenandoahLoadRefBarrier) { - int stub_code_size = 4096; - ResourceMark rm; - BufferBlob* bb = BufferBlob::create("shenandoah_barrier_stubs", stub_code_size); - CodeBuffer buf(bb); - StubCodeGenerator cgen(&buf); - _shenandoah_lrb = generate_shenandoah_lrb(&cgen); - } -} diff --git a/src/hotspot/cpu/x86/gc/shenandoah/shenandoahBarrierSetAssembler_x86.hpp b/src/hotspot/cpu/x86/gc/shenandoah/shenandoahBarrierSetAssembler_x86.hpp index 46f70771da4b1..9793a607e5994 100644 --- a/src/hotspot/cpu/x86/gc/shenandoah/shenandoahBarrierSetAssembler_x86.hpp +++ b/src/hotspot/cpu/x86/gc/shenandoah/shenandoahBarrierSetAssembler_x86.hpp @@ -38,8 +38,6 @@ class StubCodeGenerator; class ShenandoahBarrierSetAssembler: public BarrierSetAssembler { private: - static address _shenandoah_lrb; - void satb_write_barrier_pre(MacroAssembler* masm, Register obj, Register pre_val, @@ -56,15 +54,9 @@ class ShenandoahBarrierSetAssembler: public BarrierSetAssembler { bool tosca_live, bool expand_call); - void load_reference_barrier_not_null(MacroAssembler* masm, Register dst, Address src); - void storeval_barrier_impl(MacroAssembler* masm, Register dst, Register tmp); - address generate_shenandoah_lrb(StubCodeGenerator* cgen); - public: - static address shenandoah_lrb(); - void storeval_barrier(MacroAssembler* masm, Register dst, Register tmp); #ifdef COMPILER1 void gen_pre_barrier_stub(LIR_Assembler* ce, ShenandoahPreBarrierStub* stub); @@ -73,8 +65,7 @@ class ShenandoahBarrierSetAssembler: public BarrierSetAssembler { void generate_c1_load_reference_barrier_runtime_stub(StubAssembler* sasm, bool is_weak); #endif - void load_reference_barrier(MacroAssembler* masm, Register dst, Address src); - void load_reference_barrier_weak(MacroAssembler* masm, Register dst, Address src); + void load_reference_barrier(MacroAssembler* masm, Register dst, Address src, bool weak); void cmpxchg_oop(MacroAssembler* masm, Register res, Address addr, Register oldval, Register newval, @@ -87,8 +78,6 @@ class ShenandoahBarrierSetAssembler: public BarrierSetAssembler { Address dst, Register val, Register tmp1, Register tmp2); virtual void try_resolve_jobject_in_native(MacroAssembler* masm, Register jni_env, Register obj, Register tmp, Label& slowpath); - virtual void barrier_stubs_init(); - }; #endif // CPU_X86_GC_SHENANDOAH_SHENANDOAHBARRIERSETASSEMBLER_X86_HPP