From 8cdf74718787ac91aad73a00ebdefd740c1180cf Mon Sep 17 00:00:00 2001 From: Lutz Schmidt Date: Wed, 3 Apr 2019 16:55:41 +0200 Subject: [PATCH 01/73] 8221482: Initialize VMRegImpl::regName[] earlier to prevent assert during PrintStubCode Reviewed-by: kvn --- src/hotspot/share/runtime/init.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/hotspot/share/runtime/init.cpp b/src/hotspot/share/runtime/init.cpp index 2149aef1173..229185bf702 100644 --- a/src/hotspot/share/runtime/init.cpp +++ b/src/hotspot/share/runtime/init.cpp @@ -122,6 +122,7 @@ jint init_globals() { accessFlags_init(); templateTable_init(); InterfaceSupport_init(); + VMRegImpl::set_regName(); // need this before generate_stubs (for printing oop maps). SharedRuntime::generate_stubs(); universe2_init(); // dependent on codeCache_init and stubRoutines_init1 javaClasses_init();// must happen after vtable initialization, before referenceProcessor_init @@ -139,7 +140,6 @@ jint init_globals() { if (!compileBroker_init()) { return JNI_EINVAL; } - VMRegImpl::set_regName(); if (!universe_post_init()) { return JNI_ERR; From 5c06e0a9124cbef9786db898796d5e1045577020 Mon Sep 17 00:00:00 2001 From: Claes Redestad Date: Wed, 3 Apr 2019 17:06:35 +0200 Subject: [PATCH 02/73] 8221701: Archive constant BaseLocales Reviewed-by: naoto --- src/hotspot/share/memory/heapShared.cpp | 1 + .../share/classes/java/util/Locale.java | 145 +++++++++++------- .../classes/sun/util/locale/BaseLocale.java | 139 +++++++++++------ .../classes/sun/util/locale/LocaleUtils.java | 8 +- .../provider/JRELocaleProviderAdapter.java | 5 +- .../util/locale/provider/LocaleResources.java | 3 +- 6 files changed, 188 insertions(+), 113 deletions(-) diff --git a/src/hotspot/share/memory/heapShared.cpp b/src/hotspot/share/memory/heapShared.cpp index 3ec6830d2e9..546ab452510 100644 --- a/src/hotspot/share/memory/heapShared.cpp +++ b/src/hotspot/share/memory/heapShared.cpp @@ -69,6 +69,7 @@ static ArchivableStaticFieldInfo closed_archive_subgraph_entry_fields[] = { {"java/lang/Short$ShortCache", "archivedCache"}, {"java/lang/Character$CharacterCache", "archivedCache"}, {"java/util/jar/Attributes$Name", "KNOWN_NAMES"}, + {"sun/util/locale/BaseLocale", "constantBaseLocales"}, }; // Entry fields for subgraphs archived in the open archive heap region. static ArchivableStaticFieldInfo open_archive_subgraph_entry_fields[] = { diff --git a/src/java.base/share/classes/java/util/Locale.java b/src/java.base/share/classes/java/util/Locale.java index 7719012bf51..7777aed2cdd 100644 --- a/src/java.base/share/classes/java/util/Locale.java +++ b/src/java.base/share/classes/java/util/Locale.java @@ -484,63 +484,111 @@ import sun.util.locale.provider.TimeZoneNameUtility; */ public final class Locale implements Cloneable, Serializable { - private static final Cache LOCALECACHE = new Cache(); + /** Useful constant for language. + */ + public static final Locale ENGLISH; /** Useful constant for language. */ - public static final Locale ENGLISH = createConstant("en", ""); + public static final Locale FRENCH; /** Useful constant for language. */ - public static final Locale FRENCH = createConstant("fr", ""); + public static final Locale GERMAN; /** Useful constant for language. */ - public static final Locale GERMAN = createConstant("de", ""); + public static final Locale ITALIAN; /** Useful constant for language. */ - public static final Locale ITALIAN = createConstant("it", ""); + public static final Locale JAPANESE; /** Useful constant for language. */ - public static final Locale JAPANESE = createConstant("ja", ""); + public static final Locale KOREAN; /** Useful constant for language. */ - public static final Locale KOREAN = createConstant("ko", ""); + public static final Locale CHINESE; /** Useful constant for language. */ - public static final Locale CHINESE = createConstant("zh", ""); + public static final Locale SIMPLIFIED_CHINESE; /** Useful constant for language. */ - public static final Locale SIMPLIFIED_CHINESE = createConstant("zh", "CN"); - - /** Useful constant for language. - */ - public static final Locale TRADITIONAL_CHINESE = createConstant("zh", "TW"); + public static final Locale TRADITIONAL_CHINESE; /** Useful constant for country. */ - public static final Locale FRANCE = createConstant("fr", "FR"); + public static final Locale FRANCE; /** Useful constant for country. */ - public static final Locale GERMANY = createConstant("de", "DE"); + public static final Locale GERMANY; /** Useful constant for country. */ - public static final Locale ITALY = createConstant("it", "IT"); + public static final Locale ITALY; /** Useful constant for country. */ - public static final Locale JAPAN = createConstant("ja", "JP"); + public static final Locale JAPAN; /** Useful constant for country. */ - public static final Locale KOREA = createConstant("ko", "KR"); + public static final Locale KOREA; + + /** Useful constant for country. + */ + public static final Locale UK; + + /** Useful constant for country. + */ + public static final Locale US; + + /** Useful constant for country. + */ + public static final Locale CANADA; + + /** Useful constant for country. + */ + public static final Locale CANADA_FRENCH; + + /** + * Useful constant for the root locale. The root locale is the locale whose + * language, country, and variant are empty ("") strings. This is regarded + * as the base locale of all locales, and is used as the language/country + * neutral locale for the locale sensitive operations. + * + * @since 1.6 + */ + public static final Locale ROOT; + + private static final Map CONSTANT_LOCALES = new HashMap<>(); + + static { + ENGLISH = createConstant(BaseLocale.ENGLISH); + FRENCH = createConstant(BaseLocale.FRENCH); + GERMAN = createConstant(BaseLocale.GERMAN); + ITALIAN = createConstant(BaseLocale.ITALIAN); + JAPANESE = createConstant(BaseLocale.JAPANESE); + KOREAN = createConstant(BaseLocale.KOREAN); + CHINESE = createConstant(BaseLocale.CHINESE); + SIMPLIFIED_CHINESE = createConstant(BaseLocale.SIMPLIFIED_CHINESE); + TRADITIONAL_CHINESE = createConstant(BaseLocale.TRADITIONAL_CHINESE); + FRANCE = createConstant(BaseLocale.FRANCE); + GERMANY = createConstant(BaseLocale.GERMANY); + ITALY = createConstant(BaseLocale.ITALY); + JAPAN = createConstant(BaseLocale.JAPAN); + KOREA = createConstant(BaseLocale.KOREA); + UK = createConstant(BaseLocale.UK); + US = createConstant(BaseLocale.US); + CANADA = createConstant(BaseLocale.CANADA); + CANADA_FRENCH = createConstant(BaseLocale.CANADA_FRENCH); + ROOT = createConstant(BaseLocale.ROOT); + } /** Useful constant for country. */ @@ -554,31 +602,16 @@ public final class Locale implements Cloneable, Serializable { */ public static final Locale TAIWAN = TRADITIONAL_CHINESE; - /** Useful constant for country. - */ - public static final Locale UK = createConstant("en", "GB"); - - /** Useful constant for country. - */ - public static final Locale US = createConstant("en", "US"); - - /** Useful constant for country. - */ - public static final Locale CANADA = createConstant("en", "CA"); - - /** Useful constant for country. - */ - public static final Locale CANADA_FRENCH = createConstant("fr", "CA"); - /** - * Useful constant for the root locale. The root locale is the locale whose - * language, country, and variant are empty ("") strings. This is regarded - * as the base locale of all locales, and is used as the language/country - * neutral locale for the locale sensitive operations. - * - * @since 1.6 + * This method must be called only for creating the Locale.* + * constants due to making shortcuts. */ - public static final Locale ROOT = createConstant("", ""); + private static Locale createConstant(byte baseType) { + BaseLocale base = BaseLocale.constantBaseLocales[baseType]; + Locale locale = new Locale(base, null); + CONSTANT_LOCALES.put(base, locale); + return locale; + } /** * The key for the private use extension ('x'). @@ -709,7 +742,7 @@ public final class Locale implements Cloneable, Serializable { * @exception NullPointerException thrown if any argument is null. */ public Locale(String language, String country, String variant) { - if (language== null || country == null || variant == null) { + if (language == null || country == null || variant == null) { throw new NullPointerException(); } baseLocale = BaseLocale.getInstance(convertOldISOCodes(language), "", country, variant); @@ -766,15 +799,6 @@ public final class Locale implements Cloneable, Serializable { this(language, "", ""); } - /** - * This method must be called only for creating the Locale.* - * constants due to making shortcuts. - */ - private static Locale createConstant(String lang, String country) { - BaseLocale base = BaseLocale.createInstance(lang, country); - return getInstance(base, null); - } - /** * Returns a Locale constructed from the given * language, country and @@ -803,20 +827,27 @@ public final class Locale implements Cloneable, Serializable { extensions = getCompatibilityExtensions(language, script, country, variant); } - BaseLocale baseloc = BaseLocale.getInstance(language, script, country, variant); + BaseLocale baseloc = BaseLocale.getInstance(convertOldISOCodes(language), script, country, variant); return getInstance(baseloc, extensions); } static Locale getInstance(BaseLocale baseloc, LocaleExtensions extensions) { if (extensions == null) { - return LOCALECACHE.get(baseloc); + Locale locale = CONSTANT_LOCALES.get(baseloc); + if (locale != null) { + return locale; + } + return Cache.LOCALECACHE.get(baseloc); } else { LocaleKey key = new LocaleKey(baseloc, extensions); - return LOCALECACHE.get(key); + return Cache.LOCALECACHE.get(key); } } private static class Cache extends LocaleObjectCache { + + private static final Cache LOCALECACHE = new Cache(); + private Cache() { } @@ -977,8 +1008,11 @@ public final class Locale implements Cloneable, Serializable { } private static Optional getDefaultExtensions(String extensionsProp) { - LocaleExtensions exts = null; + if (LocaleUtils.isEmpty(extensionsProp)) { + return Optional.empty(); + } + LocaleExtensions exts = null; try { exts = new InternalLocaleBuilder() .setExtensions(extensionsProp) @@ -2308,6 +2342,7 @@ public final class Locale implements Cloneable, Serializable { String country = (String)fields.get("country", ""); String variant = (String)fields.get("variant", ""); String extStr = (String)fields.get("extensions", ""); + baseLocale = BaseLocale.getInstance(convertOldISOCodes(language), script, country, variant); if (!extStr.isEmpty()) { try { diff --git a/src/java.base/share/classes/sun/util/locale/BaseLocale.java b/src/java.base/share/classes/sun/util/locale/BaseLocale.java index 3f4c5f1db6c..27ad70001a1 100644 --- a/src/java.base/share/classes/sun/util/locale/BaseLocale.java +++ b/src/java.base/share/classes/sun/util/locale/BaseLocale.java @@ -32,14 +32,64 @@ package sun.util.locale; +import jdk.internal.misc.VM; +import jdk.internal.vm.annotation.Stable; + import java.lang.ref.SoftReference; import java.util.StringJoiner; public final class BaseLocale { - public static final String SEP = "_"; + public static @Stable BaseLocale[] constantBaseLocales; + public static final byte ENGLISH = 0, + FRENCH = 1, + GERMAN = 2, + ITALIAN = 3, + JAPANESE = 4, + KOREAN = 5, + CHINESE = 6, + SIMPLIFIED_CHINESE = 7, + TRADITIONAL_CHINESE = 8, + FRANCE = 9, + GERMANY = 10, + ITALY = 11, + JAPAN = 12, + KOREA = 13, + UK = 14, + US = 15, + CANADA = 16, + CANADA_FRENCH = 17, + ROOT = 18, + NUM_CONSTANTS = 19; + static { + VM.initializeFromArchive(BaseLocale.class); + BaseLocale[] baseLocales = constantBaseLocales; + if (baseLocales == null) { + baseLocales = new BaseLocale[NUM_CONSTANTS]; + baseLocales[ENGLISH] = createInstance("en", ""); + baseLocales[FRENCH] = createInstance("fr", ""); + baseLocales[GERMAN] = createInstance("de", ""); + baseLocales[ITALIAN] = createInstance("it", ""); + baseLocales[JAPANESE] = createInstance("ja", ""); + baseLocales[KOREAN] = createInstance("ko", ""); + baseLocales[CHINESE] = createInstance("zh", ""); + baseLocales[SIMPLIFIED_CHINESE] = createInstance("zh", "CN"); + baseLocales[TRADITIONAL_CHINESE] = createInstance("zh", "TW"); + baseLocales[FRANCE] = createInstance("fr", "FR"); + baseLocales[GERMANY] = createInstance("de", "DE"); + baseLocales[ITALY] = createInstance("it", "IT"); + baseLocales[JAPAN] = createInstance("ja", "JP"); + baseLocales[KOREA] = createInstance("ko", "KR"); + baseLocales[UK] = createInstance("en", "GB"); + baseLocales[US] = createInstance("en", "US"); + baseLocales[CANADA] = createInstance("en", "CA"); + baseLocales[CANADA_FRENCH] = createInstance("fr", "CA"); + baseLocales[ROOT] = createInstance("", ""); + constantBaseLocales = baseLocales; + } + } - private static final Cache CACHE = new Cache(); + public static final String SEP = "_"; private final String language; private final String script; @@ -67,28 +117,53 @@ public final class BaseLocale { // Called for creating the Locale.* constants. No argument // validation is performed. - public static BaseLocale createInstance(String language, String region) { - BaseLocale base = new BaseLocale(language, "", region, "", false); - CACHE.put(new Key(base), base); - return base; + private static BaseLocale createInstance(String language, String region) { + return new BaseLocale(language, "", region, "", false); } public static BaseLocale getInstance(String language, String script, String region, String variant) { + + if (script == null) { + script = ""; + } + if (region == null) { + region = ""; + } + if (language == null) { + language = null; + } + if (variant == null) { + variant = ""; + } + + // Non-allocating for most uses + language = LocaleUtils.toLowerString(language); + region = LocaleUtils.toUpperString(region); + + // Check for constant base locales first + if (script.isEmpty() && variant.isEmpty()) { + for (BaseLocale baseLocale : constantBaseLocales) { + if (baseLocale.getLanguage().equals(language) + && baseLocale.getRegion().equals(region)) { + return baseLocale; + } + } + } + // JDK uses deprecated ISO639.1 language codes for he, yi and id - if (language != null) { - if (LocaleUtils.caseIgnoreMatch(language, "he")) { + if (!language.isEmpty()) { + if (language.equals("he")) { language = "iw"; - } else if (LocaleUtils.caseIgnoreMatch(language, "yi")) { + } else if (language.equals("yi")) { language = "ji"; - } else if (LocaleUtils.caseIgnoreMatch(language, "id")) { + } else if (language.equals("id")) { language = "in"; } } Key key = new Key(language, script, region, variant, false); - BaseLocale baseLocale = CACHE.get(key); - return baseLocale; + return Cache.CACHE.get(key); } public String getLanguage() { @@ -171,46 +246,8 @@ public final class BaseLocale { private final boolean normalized; private final int hash; - /** - * Creates a Key. language and region must be normalized - * (intern'ed in the proper case). - */ - private Key(BaseLocale locale) { - this.holder = locale; - this.holderRef = null; - this.normalized = true; - String language = locale.getLanguage(); - String region = locale.getRegion(); - assert LocaleUtils.toLowerString(language).intern() == language - && LocaleUtils.toUpperString(region).intern() == region - && locale.getVariant() == "" - && locale.getScript() == ""; - - int h = language.hashCode(); - if (region != "") { - int len = region.length(); - for (int i = 0; i < len; i++) { - h = 31 * h + LocaleUtils.toLower(region.charAt(i)); - } - } - hash = h; - } - private Key(String language, String script, String region, String variant, boolean normalize) { - if (language == null) { - language = ""; - } - if (script == null) { - script = ""; - } - if (region == null) { - region = ""; - } - if (variant == null) { - variant = ""; - } - BaseLocale locale = new BaseLocale(language, script, region, variant, normalize); this.normalized = normalize; if (normalized) { @@ -291,6 +328,8 @@ public final class BaseLocale { private static class Cache extends LocaleObjectCache { + private static final Cache CACHE = new Cache(); + public Cache() { } diff --git a/src/java.base/share/classes/sun/util/locale/LocaleUtils.java b/src/java.base/share/classes/sun/util/locale/LocaleUtils.java index 264c50086cc..5af9110c1c5 100644 --- a/src/java.base/share/classes/sun/util/locale/LocaleUtils.java +++ b/src/java.base/share/classes/sun/util/locale/LocaleUtils.java @@ -206,19 +206,19 @@ public final class LocaleUtils { return true; } - static boolean isEmpty(String str) { + public static boolean isEmpty(String str) { return str == null || str.isEmpty(); } - static boolean isEmpty(Set set) { + public static boolean isEmpty(Set set) { return set == null || set.isEmpty(); } - static boolean isEmpty(Map map) { + public static boolean isEmpty(Map map) { return map == null || map.isEmpty(); } - static boolean isEmpty(List list) { + public static boolean isEmpty(List list) { return list == null || list.isEmpty(); } } diff --git a/src/java.base/share/classes/sun/util/locale/provider/JRELocaleProviderAdapter.java b/src/java.base/share/classes/sun/util/locale/provider/JRELocaleProviderAdapter.java index 89005429700..477697e32fc 100644 --- a/src/java.base/share/classes/sun/util/locale/provider/JRELocaleProviderAdapter.java +++ b/src/java.base/share/classes/sun/util/locale/provider/JRELocaleProviderAdapter.java @@ -491,8 +491,7 @@ public class JRELocaleProviderAdapter extends LocaleProviderAdapter implements R */ private static class AvailableJRELocales { private static final Locale[] localeList = createAvailableLocales(); - private AvailableJRELocales() { - } + private AvailableJRELocales() {} } private static Locale[] createAvailableLocales() { @@ -535,7 +534,7 @@ public class JRELocaleProviderAdapter extends LocaleProviderAdapter implements R public boolean isSupportedProviderLocale(Locale locale, Set langtags) { if (Locale.ROOT.equals(locale)) { return true; -} + } locale = locale.stripExtensions(); if (langtags.contains(locale.toLanguageTag())) { diff --git a/src/java.base/share/classes/sun/util/locale/provider/LocaleResources.java b/src/java.base/share/classes/sun/util/locale/provider/LocaleResources.java index 2a252b8f654..552d20191f4 100644 --- a/src/java.base/share/classes/sun/util/locale/provider/LocaleResources.java +++ b/src/java.base/share/classes/sun/util/locale/provider/LocaleResources.java @@ -44,6 +44,7 @@ import java.lang.ref.ReferenceQueue; import java.lang.ref.SoftReference; import java.text.MessageFormat; import java.text.NumberFormat; +import java.util.Arrays; import java.util.Calendar; import java.util.HashSet; import java.util.LinkedHashSet; @@ -325,7 +326,7 @@ public class LocaleResources { Set keyset = getZoneIDs(); // Use a LinkedHashSet to preseve the order Set value = new LinkedHashSet<>(); - Set tzIds = new HashSet<>(Set.of(TimeZone.getAvailableIDs())); + Set tzIds = new HashSet<>(Arrays.asList(TimeZone.getAvailableIDs())); for (String key : keyset) { if (!key.startsWith(TZNB_EXCITY_PREFIX)) { value.add(rb.getStringArray(key)); From 518e3a878862fd7be2d9eea42f122fdaa01c7dd8 Mon Sep 17 00:00:00 2001 From: Lance Andersen Date: Wed, 3 Apr 2019 11:30:23 -0400 Subject: [PATCH 03/73] 8216539: tools/jar/modularJar/Basic.java times out Reviewed-by: mchung, alanb, bchristi, bpb --- test/jdk/tools/jar/modularJar/Basic.java | 42 ++++++++++++++++++------ 1 file changed, 32 insertions(+), 10 deletions(-) diff --git a/test/jdk/tools/jar/modularJar/Basic.java b/test/jdk/tools/jar/modularJar/Basic.java index 0bc7ea901bb..2808c974136 100644 --- a/test/jdk/tools/jar/modularJar/Basic.java +++ b/test/jdk/tools/jar/modularJar/Basic.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2019, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -24,7 +24,9 @@ import java.io.*; import java.lang.module.ModuleDescriptor; import java.lang.reflect.Method; -import java.nio.file.*; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; import java.util.*; import java.util.function.Consumer; import java.util.jar.JarEntry; @@ -32,6 +34,7 @@ import java.util.jar.JarFile; import java.util.jar.JarInputStream; import java.util.jar.Manifest; import java.util.regex.Pattern; +import java.util.spi.ToolProvider; import java.util.stream.Collectors; import java.util.stream.Stream; @@ -59,6 +62,16 @@ import static java.lang.System.out; */ public class Basic { + + private static final ToolProvider JAR_TOOL = ToolProvider.findFirst("jar") + .orElseThrow(() + -> new RuntimeException("jar tool not found") + ); + private static final ToolProvider JAVAC_TOOL = ToolProvider.findFirst("javac") + .orElseThrow(() + -> new RuntimeException("javac tool not found") + ); + static final Path TEST_SRC = Paths.get(System.getProperty("test.src", ".")); static final Path TEST_CLASSES = Paths.get(System.getProperty("test.classes", ".")); static final Path MODULE_CLASSES = TEST_CLASSES.resolve("build"); @@ -977,13 +990,14 @@ public class Basic { } Stream.of(args).forEach(commands::add); ProcessBuilder p = new ProcessBuilder(commands); - if (stdinSource != null) + if (stdinSource != null) { p.redirectInput(stdinSource); + } return run(p); } static Result jar(String... args) { - return jarWithStdin(null, args); + return run(JAR_TOOL, args); } static Path compileModule(String mn) throws IOException { @@ -1071,10 +1085,8 @@ public class Basic { static void javac(Path dest, Path modulePath, Path... sourceFiles) throws IOException { - String javac = getJDKTool("javac"); List commands = new ArrayList<>(); - commands.add(javac); if (!TOOL_VM_OPTIONS.isEmpty()) { commands.addAll(Arrays.asList(TOOL_VM_OPTIONS.split("\\s+", -1))); } @@ -1092,7 +1104,13 @@ public class Basic { } Stream.of(sourceFiles).map(Object::toString).forEach(x -> commands.add(x)); - quickFail(run(new ProcessBuilder(commands))); + StringWriter sw = new StringWriter(); + try (PrintWriter pw = new PrintWriter(sw)) { + int rc = JAVAC_TOOL.run(pw, pw, commands.toArray(new String[0])); + if(rc != 0) { + throw new RuntimeException(sw.toString()); + } + } } static Result java(Path modulePath, String entryPoint, String... args) { @@ -1138,9 +1156,13 @@ public class Basic { return false; } - static void quickFail(Result r) { - if (r.ec != 0) - throw new RuntimeException(r.output); + static Result run(ToolProvider tp, String[] commands) { + int rc = 0; + StringWriter sw = new StringWriter(); + try (PrintWriter pw = new PrintWriter(sw)) { + rc = tp.run(pw, pw, commands); + } + return new Result(rc, sw.toString()); } static Result run(ProcessBuilder pb) { From 004b3ee748a266c6a4ccb773897a365263e2a5db Mon Sep 17 00:00:00 2001 From: Roman Kennke Date: Wed, 27 Mar 2019 22:25:03 +0100 Subject: [PATCH 04/73] 8220664: Simplify ShenandoahUpdateHeapRefsClosure Reviewed-by: shade --- .../gc/shenandoah/shenandoahOopClosures.hpp | 20 ++++++------------- .../shenandoahOopClosures.inline.hpp | 2 +- 2 files changed, 7 insertions(+), 15 deletions(-) diff --git a/src/hotspot/share/gc/shenandoah/shenandoahOopClosures.hpp b/src/hotspot/share/gc/shenandoah/shenandoahOopClosures.hpp index bd649b2f2f0..95304cc33d9 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahOopClosures.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahOopClosures.hpp @@ -184,25 +184,17 @@ public: virtual bool do_metadata() { return true; } }; -class ShenandoahUpdateHeapRefsSuperClosure : public BasicOopIterateClosure { +class ShenandoahUpdateHeapRefsClosure : public BasicOopIterateClosure { private: ShenandoahHeap* _heap; + + template + void do_oop_work(T* p); + public: - ShenandoahUpdateHeapRefsSuperClosure() : + ShenandoahUpdateHeapRefsClosure() : _heap(ShenandoahHeap::heap()) {} - template - void work(T *p); -}; - -class ShenandoahUpdateHeapRefsClosure : public ShenandoahUpdateHeapRefsSuperClosure { -private: - template - inline void do_oop_work(T* p) { work(p); } - -public: - ShenandoahUpdateHeapRefsClosure() : ShenandoahUpdateHeapRefsSuperClosure() {} - virtual void do_oop(narrowOop* p) { do_oop_work(p); } virtual void do_oop(oop* p) { do_oop_work(p); } }; diff --git a/src/hotspot/share/gc/shenandoah/shenandoahOopClosures.inline.hpp b/src/hotspot/share/gc/shenandoah/shenandoahOopClosures.inline.hpp index e827c86a229..23d5bc17a3b 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahOopClosures.inline.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahOopClosures.inline.hpp @@ -34,7 +34,7 @@ inline void ShenandoahMarkRefsSuperClosure::work(T *p) { } template -inline void ShenandoahUpdateHeapRefsSuperClosure::work(T* p) { +inline void ShenandoahUpdateHeapRefsClosure::do_oop_work(T* p) { _heap->maybe_update_with_forwarded(p); } From 18146afe7fec9ba255443077ee8af7b310f74e5d Mon Sep 17 00:00:00 2001 From: Erik Joelsson Date: Wed, 3 Apr 2019 12:52:37 -0700 Subject: [PATCH 05/73] 8221764: Reduce make Init.gmk logging overhead Reviewed-by: tbell --- make/Init.gmk | 8 +++++--- make/InitSupport.gmk | 7 +++++-- 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/make/Init.gmk b/make/Init.gmk index b8b78fbd5e0..474fa5b49b1 100644 --- a/make/Init.gmk +++ b/make/Init.gmk @@ -238,11 +238,13 @@ else # HAS_SPEC=true ifeq ($(LOG_NOFILE), true) # Disable build log if LOG=[level,]nofile was given override BUILD_LOG_PIPE := + override BUILD_LOG_PIPE_SIMPLE := endif ifeq ($(filter dist-clean, $(SEQUENTIAL_TARGETS)), dist-clean) # We can't have a log file if we're about to remove it. override BUILD_LOG_PIPE := + override BUILD_LOG_PIPE_SIMPLE := endif ifeq ($(OUTPUT_SYNC_SUPPORTED), true) @@ -303,7 +305,7 @@ else # HAS_SPEC=true main: $(INIT_TARGETS) ifneq ($(SEQUENTIAL_TARGETS)$(PARALLEL_TARGETS), ) $(call RotateLogFiles) - $(PRINTF) "Building $(TARGET_DESCRIPTION)\n" $(BUILD_LOG_PIPE) + $(PRINTF) "Building $(TARGET_DESCRIPTION)\n" $(BUILD_LOG_PIPE_SIMPLE) ifneq ($(SEQUENTIAL_TARGETS), ) # Don't touch build output dir since we might be cleaning. That # means no log pipe. @@ -325,7 +327,7 @@ else # HAS_SPEC=true $(PARALLEL_TARGETS) $(COMPARE_BUILD_MAKE) $(BUILD_LOG_PIPE) || \ ( exitcode=$$? && \ $(PRINTF) "\nERROR: Build failed for $(TARGET_DESCRIPTION) (exit code $$exitcode) \n" \ - $(BUILD_LOG_PIPE) && \ + $(BUILD_LOG_PIPE_SIMPLE) && \ cd $(TOPDIR) && $(MAKE) $(MAKE_ARGS) -j 1 -f make/Init.gmk \ HAS_SPEC=true on-failure ; \ exit $$exitcode ) ) @@ -336,7 +338,7 @@ else # HAS_SPEC=true if test -f $(MAKESUPPORT_OUTPUTDIR)/exit-with-error ; then \ exit 1 ; \ fi - $(PRINTF) "Finished building $(TARGET_DESCRIPTION)\n" $(BUILD_LOG_PIPE) + $(PRINTF) "Finished building $(TARGET_DESCRIPTION)\n" $(BUILD_LOG_PIPE_SIMPLE) $(call ReportProfileTimes) endif diff --git a/make/InitSupport.gmk b/make/InitSupport.gmk index 005d12dae63..57d22812ad5 100644 --- a/make/InitSupport.gmk +++ b/make/InitSupport.gmk @@ -296,6 +296,9 @@ else # $(HAS_SPEC)=true BUILD_PROFILE_LOG := $(OUTPUTDIR)/build-profile.log BUILD_LOG_PIPE := > >($(TEE) -a $(BUILD_LOG)) 2> >($(TEE) -a $(BUILD_LOG) >&2) && wait + # Use this for simple echo/printf commands that are never expected to print + # to stderr. + BUILD_LOG_PIPE_SIMPLE := | $(TEE) -a $(BUILD_LOG) ifneq ($(CUSTOM_ROOT), ) topdir=$(CUSTOM_ROOT) @@ -514,7 +517,7 @@ else # $(HAS_SPEC)=true "`$(LS) $(BUILDTIMESDIR)/build_time_diff_* | $(GREP) -v _TOTAL | \ $(XARGS) $(CAT) | $(SORT) -k 2`" \ "`$(CAT) $(BUILDTIMESDIR)/build_time_diff_TOTAL`" \ - $(BUILD_LOG_PIPE) + $(BUILD_LOG_PIPE_SIMPLE) endef define ReportProfileTimes @@ -524,7 +527,7 @@ else # $(HAS_SPEC)=true $(CAT) $(BUILD_PROFILE_LOG) && \ $(ECHO) End $(notdir $(BUILD_PROFILE_LOG)); \ } \ - $(BUILD_LOG_PIPE) + $(BUILD_LOG_PIPE_SIMPLE) ) endef From 2f20909d10ae33d93d62f5dcd4915efdbd83d968 Mon Sep 17 00:00:00 2001 From: David Holmes Date: Wed, 3 Apr 2019 22:03:39 +0000 Subject: [PATCH 06/73] 8218483: Crash in "assert(_daemon_threads_count->get_value() > daemon_count) failed: thread count mismatch 5 : 5" Reviewed-by: dcubed, stuefe --- src/hotspot/share/prims/jni.cpp | 2 +- src/hotspot/share/runtime/thread.cpp | 19 ++++++++++--------- src/hotspot/share/runtime/thread.hpp | 4 ++-- test/hotspot/gtest/threadHelper.inline.hpp | 6 +++--- 4 files changed, 16 insertions(+), 15 deletions(-) diff --git a/src/hotspot/share/prims/jni.cpp b/src/hotspot/share/prims/jni.cpp index 397f137948a..2375793e262 100644 --- a/src/hotspot/share/prims/jni.cpp +++ b/src/hotspot/share/prims/jni.cpp @@ -4166,7 +4166,7 @@ static jint attach_current_thread(JavaVM *vm, void **penv, void *_args, bool dae if (attach_failed) { // Added missing cleanup - thread->cleanup_failed_attach_current_thread(); + thread->cleanup_failed_attach_current_thread(daemon); return JNI_ERR; } diff --git a/src/hotspot/share/runtime/thread.cpp b/src/hotspot/share/runtime/thread.cpp index 244054e70fc..385ea67276d 100644 --- a/src/hotspot/share/runtime/thread.cpp +++ b/src/hotspot/share/runtime/thread.cpp @@ -2021,6 +2021,10 @@ void JavaThread::exit(bool destroy_vm, ExitType exit_type) { _timer_exit_phase1.stop(); _timer_exit_phase2.start(); } + + // Capture daemon status before the thread is marked as terminated. + bool daemon = is_daemon(threadObj()); + // Notify waiters on thread object. This has to be done after exit() is called // on the thread (if the thread is the last thread in a daemon ThreadGroup the // group should have the destroyed bit set before waiters are notified). @@ -2089,7 +2093,7 @@ void JavaThread::exit(bool destroy_vm, ExitType exit_type) { _timer_exit_phase4.start(); } // Remove from list of active threads list, and notify VM thread if we are the last non-daemon thread - Threads::remove(this); + Threads::remove(this, daemon); if (log_is_enabled(Debug, os, thread, timer)) { _timer_exit_phase4.stop(); @@ -2107,7 +2111,7 @@ void JavaThread::exit(bool destroy_vm, ExitType exit_type) { } } -void JavaThread::cleanup_failed_attach_current_thread() { +void JavaThread::cleanup_failed_attach_current_thread(bool is_daemon) { if (active_handles() != NULL) { JNIHandleBlock* block = active_handles(); set_active_handles(NULL); @@ -2129,7 +2133,7 @@ void JavaThread::cleanup_failed_attach_current_thread() { BarrierSet::barrier_set()->on_thread_detach(this); - Threads::remove(this); + Threads::remove(this, is_daemon); this->smr_delete(); } @@ -4455,7 +4459,7 @@ void Threads::add(JavaThread* p, bool force_daemon) { Events::log(p, "Thread added: " INTPTR_FORMAT, p2i(p)); } -void Threads::remove(JavaThread* p) { +void Threads::remove(JavaThread* p, bool is_daemon) { // Reclaim the ObjectMonitors from the omInUseList and omFreeList of the moribund thread. ObjectSynchronizer::omFlush(p); @@ -4484,11 +4488,8 @@ void Threads::remove(JavaThread* p) { } _number_of_threads--; - oop threadObj = p->threadObj(); - bool daemon = true; - if (!is_daemon(threadObj)) { + if (!is_daemon) { _number_of_non_daemon_threads--; - daemon = false; // Only one thread left, do a notify on the Threads_lock so a thread waiting // on destroy_vm will wake up. @@ -4496,7 +4497,7 @@ void Threads::remove(JavaThread* p) { Threads_lock->notify_all(); } } - ThreadService::remove_thread(p, daemon); + ThreadService::remove_thread(p, is_daemon); // Make sure that safepoint code disregard this thread. This is needed since // the thread might mess around with locks after this point. This can cause it diff --git a/src/hotspot/share/runtime/thread.hpp b/src/hotspot/share/runtime/thread.hpp index ab0ba1d863a..b977c7df186 100644 --- a/src/hotspot/share/runtime/thread.hpp +++ b/src/hotspot/share/runtime/thread.hpp @@ -1242,7 +1242,7 @@ class JavaThread: public Thread { }; void exit(bool destroy_vm, ExitType exit_type = normal_exit); - void cleanup_failed_attach_current_thread(); + void cleanup_failed_attach_current_thread(bool is_daemon); // Testers virtual bool is_Java_thread() const { return true; } @@ -2235,7 +2235,7 @@ class Threads: AllStatic { // force_daemon is a concession to JNI, where we may need to add a // thread to the thread list before allocating its thread object static void add(JavaThread* p, bool force_daemon = false); - static void remove(JavaThread* p); + static void remove(JavaThread* p, bool is_daemon); static void non_java_threads_do(ThreadClosure* tc); static void java_threads_do(ThreadClosure* tc); static void java_threads_and_vm_thread_do(ThreadClosure* tc); diff --git a/test/hotspot/gtest/threadHelper.inline.hpp b/test/hotspot/gtest/threadHelper.inline.hpp index b84116705a9..f9992d40a39 100644 --- a/test/hotspot/gtest/threadHelper.inline.hpp +++ b/test/hotspot/gtest/threadHelper.inline.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2019, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -66,7 +66,7 @@ public: // Override as JavaThread::post_run() calls JavaThread::exit which // expects a valid thread object oop. virtual void post_run() { - Threads::remove(this); + Threads::remove(this, false); this->smr_delete(); } @@ -118,7 +118,7 @@ public: // Override as JavaThread::post_run() calls JavaThread::exit which // expects a valid thread object oop. And we need to call signal. void post_run() { - Threads::remove(this); + Threads::remove(this, false); _post->signal(); this->smr_delete(); } From 661b5f15343e6d4d1918f44a3f89cacfd3c31e7e Mon Sep 17 00:00:00 2001 From: Xue-Lei Andrew Fan Date: Wed, 3 Apr 2019 16:23:22 -0700 Subject: [PATCH 07/73] 8217610: TLSv1.3 fail with ClassException when EC keys are stored in PKCS11 Reviewed-by: valeriep --- .../sun/security/ssl/CertificateVerify.java | 4 ++-- .../sun/security/ssl/DHServerKeyExchange.java | 2 +- .../security/ssl/ECDHClientKeyExchange.java | 7 ++----- .../sun/security/ssl/ECDHKeyExchange.java | 7 +++---- .../security/ssl/ECDHServerKeyExchange.java | 2 +- .../sun/security/ssl/SignatureScheme.java | 9 +++++--- .../sun/security/ssl/X509Authentication.java | 21 +++++++++++++++++++ 7 files changed, 36 insertions(+), 16 deletions(-) diff --git a/src/java.base/share/classes/sun/security/ssl/CertificateVerify.java b/src/java.base/share/classes/sun/security/ssl/CertificateVerify.java index c1179787938..b38e8b5e993 100644 --- a/src/java.base/share/classes/sun/security/ssl/CertificateVerify.java +++ b/src/java.base/share/classes/sun/security/ssl/CertificateVerify.java @@ -565,7 +565,7 @@ final class CertificateVerify { ClientHandshakeContext chc = (ClientHandshakeContext)context; this.signatureScheme = SignatureScheme.getPreferableAlgorithm( chc.peerRequestedSignatureSchemes, - x509Possession.popPrivateKey, + x509Possession, chc.negotiatedProtocol); if (signatureScheme == null) { // Unlikely, the credentials generator should have @@ -866,7 +866,7 @@ final class CertificateVerify { this.signatureScheme = SignatureScheme.getPreferableAlgorithm( context.peerRequestedSignatureSchemes, - x509Possession.popPrivateKey, + x509Possession, context.negotiatedProtocol); if (signatureScheme == null) { // Unlikely, the credentials generator should have diff --git a/src/java.base/share/classes/sun/security/ssl/DHServerKeyExchange.java b/src/java.base/share/classes/sun/security/ssl/DHServerKeyExchange.java index 19a4a45e174..26a768569c4 100644 --- a/src/java.base/share/classes/sun/security/ssl/DHServerKeyExchange.java +++ b/src/java.base/share/classes/sun/security/ssl/DHServerKeyExchange.java @@ -127,7 +127,7 @@ final class DHServerKeyExchange { if (useExplicitSigAlgorithm) { signatureScheme = SignatureScheme.getPreferableAlgorithm( shc.peerRequestedSignatureSchemes, - x509Possession.popPrivateKey, + x509Possession, shc.negotiatedProtocol); if (signatureScheme == null) { // Unlikely, the credentials generator should have diff --git a/src/java.base/share/classes/sun/security/ssl/ECDHClientKeyExchange.java b/src/java.base/share/classes/sun/security/ssl/ECDHClientKeyExchange.java index a55fbd64506..87b428cdcc6 100644 --- a/src/java.base/share/classes/sun/security/ssl/ECDHClientKeyExchange.java +++ b/src/java.base/share/classes/sun/security/ssl/ECDHClientKeyExchange.java @@ -31,9 +31,7 @@ import java.security.AlgorithmConstraints; import java.security.CryptoPrimitive; import java.security.GeneralSecurityException; import java.security.KeyFactory; -import java.security.PrivateKey; import java.security.PublicKey; -import java.security.interfaces.ECPrivateKey; import java.security.interfaces.ECPublicKey; import java.security.spec.ECParameterSpec; import java.security.spec.ECPoint; @@ -285,14 +283,13 @@ final class ECDHClientKeyExchange { "No expected EC server cert for ECDH client key exchange"); } - PrivateKey privateKey = x509Possession.popPrivateKey; - if (!privateKey.getAlgorithm().equals("EC")) { + ECParameterSpec params = x509Possession.getECParameterSpec(); + if (params == null) { // unlikely, have been checked during cipher suite negotiation. throw shc.conContext.fatal(Alert.ILLEGAL_PARAMETER, "Not EC server cert for ECDH client key exchange"); } - ECParameterSpec params = ((ECPrivateKey)privateKey).getParams(); NamedGroup namedGroup = NamedGroup.valueOf(params); if (namedGroup == null) { // unlikely, have been checked during cipher suite negotiation. diff --git a/src/java.base/share/classes/sun/security/ssl/ECDHKeyExchange.java b/src/java.base/share/classes/sun/security/ssl/ECDHKeyExchange.java index eee88b538cd..d62a8c22d5e 100644 --- a/src/java.base/share/classes/sun/security/ssl/ECDHKeyExchange.java +++ b/src/java.base/share/classes/sun/security/ssl/ECDHKeyExchange.java @@ -35,7 +35,6 @@ import java.security.KeyPairGenerator; import java.security.PrivateKey; import java.security.PublicKey; import java.security.SecureRandom; -import java.security.interfaces.ECPrivateKey; import java.security.interfaces.ECPublicKey; import java.security.spec.AlgorithmParameterSpec; import java.security.spec.ECGenParameterSpec; @@ -265,12 +264,12 @@ final class ECDHKeyExchange { continue; } - PrivateKey privateKey = ((X509Possession)poss).popPrivateKey; - if (!privateKey.getAlgorithm().equals("EC")) { + ECParameterSpec params = + ((X509Possession)poss).getECParameterSpec(); + if (params == null) { continue; } - ECParameterSpec params = ((ECPrivateKey)privateKey).getParams(); NamedGroup ng = NamedGroup.valueOf(params); if (ng == null) { // unlikely, have been checked during cipher suite negotiation. diff --git a/src/java.base/share/classes/sun/security/ssl/ECDHServerKeyExchange.java b/src/java.base/share/classes/sun/security/ssl/ECDHServerKeyExchange.java index b2a278f180b..895786668cd 100644 --- a/src/java.base/share/classes/sun/security/ssl/ECDHServerKeyExchange.java +++ b/src/java.base/share/classes/sun/security/ssl/ECDHServerKeyExchange.java @@ -142,7 +142,7 @@ final class ECDHServerKeyExchange { if (useExplicitSigAlgorithm) { signatureScheme = SignatureScheme.getPreferableAlgorithm( shc.peerRequestedSignatureSchemes, - x509Possession.popPrivateKey, + x509Possession, shc.negotiatedProtocol); if (signatureScheme == null) { // Unlikely, the credentials generator should have diff --git a/src/java.base/share/classes/sun/security/ssl/SignatureScheme.java b/src/java.base/share/classes/sun/security/ssl/SignatureScheme.java index 40c52678178..611956d3a5f 100644 --- a/src/java.base/share/classes/sun/security/ssl/SignatureScheme.java +++ b/src/java.base/share/classes/sun/security/ssl/SignatureScheme.java @@ -41,6 +41,7 @@ import java.util.List; import java.util.Set; import sun.security.ssl.SupportedGroupsExtension.NamedGroup; import sun.security.ssl.SupportedGroupsExtension.NamedGroupType; +import sun.security.ssl.X509Authentication.X509Possession; import sun.security.util.KeyUtil; enum SignatureScheme { @@ -415,9 +416,10 @@ enum SignatureScheme { static SignatureScheme getPreferableAlgorithm( List schemes, - PrivateKey signingKey, + X509Possession x509Possession, ProtocolVersion version) { + PrivateKey signingKey = x509Possession.popPrivateKey; String keyAlgorithm = signingKey.getAlgorithm(); int keySize; // Only need to check RSA algorithm at present. @@ -434,8 +436,9 @@ enum SignatureScheme { if (ss.namedGroup != null && ss.namedGroup.type == NamedGroupType.NAMED_GROUP_ECDHE) { ECParameterSpec params = - ((ECPrivateKey)signingKey).getParams(); - if (ss.namedGroup == NamedGroup.valueOf(params)) { + x509Possession.getECParameterSpec(); + if (params != null && + ss.namedGroup == NamedGroup.valueOf(params)) { return ss; } } else { diff --git a/src/java.base/share/classes/sun/security/ssl/X509Authentication.java b/src/java.base/share/classes/sun/security/ssl/X509Authentication.java index e3bf2aa08b8..1488f7d0b28 100644 --- a/src/java.base/share/classes/sun/security/ssl/X509Authentication.java +++ b/src/java.base/share/classes/sun/security/ssl/X509Authentication.java @@ -28,6 +28,7 @@ package sun.security.ssl; import java.security.PrivateKey; import java.security.PublicKey; import java.security.cert.X509Certificate; +import java.security.interfaces.ECKey; import java.security.interfaces.ECPublicKey; import java.security.spec.ECParameterSpec; import java.util.AbstractMap.SimpleImmutableEntry; @@ -127,6 +128,26 @@ enum X509Authentication implements SSLAuthentication { this.popCerts = popCerts; this.popPrivateKey = popPrivateKey; } + + ECParameterSpec getECParameterSpec() { + if (popPrivateKey == null || + !"EC".equals(popPrivateKey.getAlgorithm())) { + return null; + } + + if (popPrivateKey instanceof ECKey) { + return ((ECKey)popPrivateKey).getParams(); + } else if (popCerts != null && popCerts.length != 0) { + // The private key not extractable, get the parameters from + // the X.509 certificate. + PublicKey publicKey = popCerts[0].getPublicKey(); + if (publicKey instanceof ECKey) { + return ((ECKey)publicKey).getParams(); + } + } + + return null; + } } static final class X509Credentials implements SSLCredentials { From 8c67e267a03342b3aabba497b2cf0f473ecd7ac3 Mon Sep 17 00:00:00 2001 From: Jesper Wilhelmsson Date: Thu, 4 Apr 2019 01:46:14 +0200 Subject: [PATCH 08/73] Added tag jdk-13+15 for changeset f855ec13aa25 --- .hgtags | 1 + 1 file changed, 1 insertion(+) diff --git a/.hgtags b/.hgtags index 94e3649928c..a138389c9d1 100644 --- a/.hgtags +++ b/.hgtags @@ -552,3 +552,4 @@ b67884871b5fff79c5ef3eb8ac74dd48d71ea9b1 jdk-12+33 b67884871b5fff79c5ef3eb8ac74dd48d71ea9b1 jdk-12-ga 83cace4142c8563b6a921787db02388e1bc48d01 jdk-13+13 46cf212cdccaf4fb064d913b12004007d3322b67 jdk-13+14 +f855ec13aa2501ae184c8b3e0626a8cec9966116 jdk-13+15 From 8e5a71de4425426f058cc41a0d44930f73f54506 Mon Sep 17 00:00:00 2001 From: Coleen Phillimore Date: Wed, 3 Apr 2019 20:39:19 -0400 Subject: [PATCH 09/73] 8221872: Remove uses of ClassLoaderWeakHandle typedef in protection domain table Make consistent with StringTable and ResolvedMethodTable Reviewed-by: dholmes --- .../share/classfile/protectionDomainCache.cpp | 6 +++--- .../share/classfile/protectionDomainCache.hpp | 16 ++++++++-------- src/hotspot/share/utilities/hashtable.cpp | 11 +++++------ 3 files changed, 16 insertions(+), 17 deletions(-) diff --git a/src/hotspot/share/classfile/protectionDomainCache.cpp b/src/hotspot/share/classfile/protectionDomainCache.cpp index f2a2b59206a..0b2faaa3163 100644 --- a/src/hotspot/share/classfile/protectionDomainCache.cpp +++ b/src/hotspot/share/classfile/protectionDomainCache.cpp @@ -45,7 +45,7 @@ int ProtectionDomainCacheTable::index_for(Handle protection_domain) { } ProtectionDomainCacheTable::ProtectionDomainCacheTable(int table_size) - : Hashtable(table_size, sizeof(ProtectionDomainCacheEntry)) + : Hashtable, mtClass>(table_size, sizeof(ProtectionDomainCacheEntry)) { _dead_entries = false; _total_oops_removed = 0; } @@ -180,8 +180,8 @@ ProtectionDomainCacheEntry* ProtectionDomainCacheTable::add_entry(int index, uns protection_domain->print_value_on(&ls); ls.cr(); } - ClassLoaderWeakHandle w = ClassLoaderWeakHandle::create(protection_domain); + WeakHandle w = WeakHandle::create(protection_domain); ProtectionDomainCacheEntry* p = new_entry(hash, w); - Hashtable::add_entry(index, p); + Hashtable, mtClass>::add_entry(index, p); return p; } diff --git a/src/hotspot/share/classfile/protectionDomainCache.hpp b/src/hotspot/share/classfile/protectionDomainCache.hpp index e3a1cdf5497..c3d27f01097 100644 --- a/src/hotspot/share/classfile/protectionDomainCache.hpp +++ b/src/hotspot/share/classfile/protectionDomainCache.hpp @@ -35,18 +35,18 @@ // to dictionary.hpp pd_set for more information about how protection domain entries // are used. // This table is walked during GC, rather than the class loader data graph dictionaries. -class ProtectionDomainCacheEntry : public HashtableEntry { +class ProtectionDomainCacheEntry : public HashtableEntry, mtClass> { friend class VMStructs; public: oop object(); oop object_no_keepalive(); ProtectionDomainCacheEntry* next() { - return (ProtectionDomainCacheEntry*)HashtableEntry::next(); + return (ProtectionDomainCacheEntry*)HashtableEntry, mtClass>::next(); } ProtectionDomainCacheEntry** next_addr() { - return (ProtectionDomainCacheEntry**)HashtableEntry::next_addr(); + return (ProtectionDomainCacheEntry**)HashtableEntry, mtClass>::next_addr(); } void verify(); @@ -61,21 +61,21 @@ class ProtectionDomainCacheEntry : public HashtableEntry { +class ProtectionDomainCacheTable : public Hashtable, mtClass> { friend class VMStructs; private: ProtectionDomainCacheEntry* bucket(int i) const { - return (ProtectionDomainCacheEntry*) Hashtable::bucket(i); + return (ProtectionDomainCacheEntry*) Hashtable, mtClass>::bucket(i); } // The following method is not MT-safe and must be done under lock. ProtectionDomainCacheEntry** bucket_addr(int i) { - return (ProtectionDomainCacheEntry**) Hashtable::bucket_addr(i); + return (ProtectionDomainCacheEntry**) Hashtable, mtClass>::bucket_addr(i); } - ProtectionDomainCacheEntry* new_entry(unsigned int hash, ClassLoaderWeakHandle protection_domain) { + ProtectionDomainCacheEntry* new_entry(unsigned int hash, WeakHandle protection_domain) { ProtectionDomainCacheEntry* entry = (ProtectionDomainCacheEntry*) - Hashtable::new_entry(hash, protection_domain); + Hashtable, mtClass>::new_entry(hash, protection_domain); return entry; } diff --git a/src/hotspot/share/utilities/hashtable.cpp b/src/hotspot/share/utilities/hashtable.cpp index c59180a1a87..827859c7184 100644 --- a/src/hotspot/share/utilities/hashtable.cpp +++ b/src/hotspot/share/utilities/hashtable.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2019, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -129,7 +129,7 @@ static int literal_size(oop obj) { } } -static int literal_size(ClassLoaderWeakHandle v) { +static int literal_size(WeakHandle v) { return literal_size(v.peek()); } @@ -244,7 +244,7 @@ template void print_literal(T l) { l->print(); } -static void print_literal(ClassLoaderWeakHandle l) { +static void print_literal(WeakHandle l) { l.print(); } @@ -308,15 +308,14 @@ template class Hashtable; template class Hashtable; template class Hashtable; template class Hashtable; -template class Hashtable; +template class Hashtable, mtClass>; template class Hashtable; template class Hashtable; -template class Hashtable; template class Hashtable; template class HashtableEntry; template class HashtableEntry; template class HashtableEntry; -template class HashtableEntry; +template class HashtableEntry, mtClass>; template class HashtableBucket; template class BasicHashtableEntry; template class BasicHashtableEntry; From a801be79eb92a52cd71926644861c67aab1ee658 Mon Sep 17 00:00:00 2001 From: Ralf Schmelter Date: Tue, 26 Mar 2019 01:46:06 -0700 Subject: [PATCH 10/73] 8221325: Add information about swap space to print_memory_info() on MacOS Reviewed-by: stuefe, dholmes --- src/hotspot/os/bsd/os_bsd.cpp | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/hotspot/os/bsd/os_bsd.cpp b/src/hotspot/os/bsd/os_bsd.cpp index 30ed4d859ca..69bc3e764f1 100644 --- a/src/hotspot/os/bsd/os_bsd.cpp +++ b/src/hotspot/os/bsd/os_bsd.cpp @@ -1598,6 +1598,8 @@ void os::get_summary_cpu_info(char* buf, size_t buflen) { } void os::print_memory_info(outputStream* st) { + xsw_usage swap_usage; + size_t size = sizeof(swap_usage); st->print("Memory:"); st->print(" %dk page", os::vm_page_size()>>10); @@ -1606,6 +1608,16 @@ void os::print_memory_info(outputStream* st) { os::physical_memory() >> 10); st->print("(" UINT64_FORMAT "k free)", os::available_memory() >> 10); + + if((sysctlbyname("vm.swapusage", &swap_usage, &size, NULL, 0) == 0) || (errno == ENOMEM)) { + if (size >= offset_of(xsw_usage, xsu_used)) { + st->print(", swap " UINT64_FORMAT "k", + ((julong) swap_usage.xsu_total) >> 10); + st->print("(" UINT64_FORMAT "k free)", + ((julong) swap_usage.xsu_avail) >> 10); + } + } + st->cr(); } From cf973e3db48aa81068647cc70f611c259ddbee20 Mon Sep 17 00:00:00 2001 From: Weijun Wang Date: Thu, 4 Apr 2019 20:22:16 +0800 Subject: [PATCH 11/73] 8219861: Add new keytool -showinfo -tls command for displaying TLS configuration information Reviewed-by: mullan --- .../sun/security/tools/keytool/Main.java | 25 +++++++-- .../sun/security/tools/keytool/Resources.java | 5 ++ .../sun/security/tools/keytool/ShowInfo.java | 53 +++++++++++++++++++ 3 files changed, 80 insertions(+), 3 deletions(-) create mode 100644 src/java.base/share/classes/sun/security/tools/keytool/ShowInfo.java diff --git a/src/java.base/share/classes/sun/security/tools/keytool/Main.java b/src/java.base/share/classes/sun/security/tools/keytool/Main.java index d574bbbbb0f..aee0d40768e 100644 --- a/src/java.base/share/classes/sun/security/tools/keytool/Main.java +++ b/src/java.base/share/classes/sun/security/tools/keytool/Main.java @@ -175,6 +175,8 @@ public final class Main { private Set passwords = new HashSet<>(); private String startDate = null; + private boolean tlsInfo = false; + private List ids = new ArrayList<>(); // used in GENCRL private List v3ext = new ArrayList<>(); @@ -260,6 +262,8 @@ public final class Main { STOREPASSWD("Changes.the.store.password.of.a.keystore", NEW, KEYSTORE, CACERTS, STOREPASS, STORETYPE, PROVIDERNAME, ADDPROVIDER, PROVIDERCLASS, PROVIDERPATH, V), + SHOWINFO("showinfo.command.help", + TLS, V), // Undocumented start here, KEYCLONE is used a marker in -help; @@ -365,6 +369,7 @@ public final class Main { STARTDATE("startdate", "", "certificate.validity.start.date.time"), STOREPASS("storepass", "", "keystore.password"), STORETYPE("storetype", "", "keystore.type"), + TLS("tls", null, "tls.option.help"), TRUSTCACERTS("trustcacerts", null, "trust.certificates.from.cacerts"), V("v", null, "verbose.output"), VALIDITY("validity", "", "validity.number.of.days"); @@ -678,6 +683,8 @@ public final class Main { protectedPath = true; } else if (collator.compare(flags, "-srcprotected") == 0) { srcprotectedPath = true; + } else if (collator.compare(flags, "-tls") == 0) { + tlsInfo = true; } else { System.err.println(rb.getString("Illegal.option.") + flags); tinyHelp(); @@ -705,7 +712,7 @@ public final class Main { } boolean isKeyStoreRelated(Command cmd) { - return cmd != PRINTCERT && cmd != PRINTCERTREQ; + return cmd != PRINTCERT && cmd != PRINTCERTREQ && cmd != SHOWINFO; } /** @@ -874,8 +881,7 @@ public final class Main { // Check if keystore exists. // If no keystore has been specified at the command line, try to use // the default, which is located in $HOME/.keystore. - // If the command is "genkey", "identitydb", "import", or "printcert", - // it is OK not to have a keystore. + // No need to check if isKeyStoreRelated(command) is false. // DO NOT open the existing keystore if this is an in-place import. // The keystore should be created as brand new. @@ -889,6 +895,9 @@ public final class Main { } ksStream = new FileInputStream(ksfile); } catch (FileNotFoundException e) { + // These commands do not need the keystore to be existing. + // Either it will create a new one or the keystore is + // optional (i.e. PRINTCRL). if (command != GENKEYPAIR && command != GENSECKEY && command != IDENTITYDB && @@ -1311,6 +1320,8 @@ public final class Main { } } else if (command == PRINTCRL) { doPrintCRL(filename, out); + } else if (command == SHOWINFO) { + doShowInfo(); } // If we need to save the keystore, do so. @@ -2707,6 +2718,14 @@ public final class Main { } } + private void doShowInfo() throws Exception { + if (tlsInfo) { + ShowInfo.tls(verbose); + } else { + System.out.println(rb.getString("showinfo.no.option")); + } + } + private Collection generateCertificates(InputStream in) throws CertificateException, IOException { byte[] data = in.readAllBytes(); diff --git a/src/java.base/share/classes/sun/security/tools/keytool/Resources.java b/src/java.base/share/classes/sun/security/tools/keytool/Resources.java index 4ac8d4042e9..1edbeacfb96 100644 --- a/src/java.base/share/classes/sun/security/tools/keytool/Resources.java +++ b/src/java.base/share/classes/sun/security/tools/keytool/Resources.java @@ -96,6 +96,8 @@ public class Resources extends java.util.ListResourceBundle { "Generates a self-signed certificate"}, //-selfcert {"Changes.the.store.password.of.a.keystore", "Changes the store password of a keystore"}, //-storepasswd + {"showinfo.command.help", "Displays security-related information"}, + // keytool: help: options {"alias.name.of.the.entry.to.process", "alias name of the entry to process"}, //-alias @@ -141,6 +143,7 @@ public class Resources extends java.util.ListResourceBundle { "do not prompt"}, //-noprompt {"password.through.protected.mechanism", "password through protected mechanism"}, //-protected + {"tls.option.help", "Displays TLS configuration information"}, // The following 2 values should span 2 lines, the first for the // option itself, the second for its -providerArg value. @@ -472,6 +475,8 @@ public class Resources extends java.util.ListResourceBundle { {"backup.keystore.warning", "The original keystore \"%1$s\" is backed up as \"%3$s\"..."}, {"importing.keystore.status", "Importing keystore %1$s to %2$s..."}, {"keyalg.option.1.missing.warning", "No -keyalg option. The default key algorithm (%s) is a legacy algorithm and is no longer recommended. In a subsequent release of the JDK, the default will be removed and the -keyalg option must be specified."}, + + {"showinfo.no.option", "Missing option for -showinfo. Try \"keytool -showinfo -tls\"."}, }; diff --git a/src/java.base/share/classes/sun/security/tools/keytool/ShowInfo.java b/src/java.base/share/classes/sun/security/tools/keytool/ShowInfo.java new file mode 100644 index 00000000000..34c8c20921a --- /dev/null +++ b/src/java.base/share/classes/sun/security/tools/keytool/ShowInfo.java @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package sun.security.tools.keytool; + +import javax.net.ssl.SSLContext; +import javax.net.ssl.SSLSocket; + +class ShowInfo { + + // verbose is not used yet. + static void tls(boolean verbose) throws Exception { + + SSLSocket ssls = (SSLSocket) + SSLContext.getDefault().getSocketFactory().createSocket(); + + System.out.println("Enabled Protocols"); + System.out.println("-----------------"); + for (String s : ssls.getEnabledProtocols()) { + System.out.println(s); + } + + System.out.println(); + + System.out.println("Enabled Cipher Suites"); + System.out.println("---------------------"); + for (String s : ssls.getEnabledCipherSuites()) { + System.out.println(s); + } + } +} From 60e51498f2c26c8a532d26185015a03877f6c9a4 Mon Sep 17 00:00:00 2001 From: Erik Joelsson Date: Thu, 4 Apr 2019 07:43:44 -0700 Subject: [PATCH 12/73] 8217728: Speed up incremental rerun of "make hotspot" Reviewed-by: tbell --- make/Main.gmk | 5 +- make/common/NativeCompilation.gmk | 101 ++++++++++++++++++++---------- 2 files changed, 72 insertions(+), 34 deletions(-) diff --git a/make/Main.gmk b/make/Main.gmk index 0e5ff72b2a6..0b3319c484e 100644 --- a/make/Main.gmk +++ b/make/Main.gmk @@ -650,7 +650,6 @@ else # Declare dependencies between hotspot-* targets $(foreach v, $(JVM_VARIANTS), \ - $(eval hotspot-$v: hotspot-$v-gensrc hotspot-$v-libs) \ $(eval hotspot-$v-gensrc: java.base-copy) \ $(eval hotspot-$v-libs: hotspot-$v-gensrc java.base-copy) \ ) @@ -943,6 +942,10 @@ JVM_TOOLS_TARGETS ?= buildtools-hotspot buildtools: buildtools-langtools interim-langtools interim-rmic \ buildtools-jdk $(JVM_TOOLS_TARGETS) +# Declare dependencies from hotspot- targets +$(foreach v, $(JVM_VARIANTS), \ + $(eval hotspot-$v: hotspot-$v-gensrc hotspot-$v-libs) \ +) hotspot: $(HOTSPOT_VARIANT_TARGETS) # Create targets hotspot-libs and hotspot-gensrc. diff --git a/make/common/NativeCompilation.gmk b/make/common/NativeCompilation.gmk index 8c93d310cc4..479eaa33ec4 100644 --- a/make/common/NativeCompilation.gmk +++ b/make/common/NativeCompilation.gmk @@ -231,8 +231,8 @@ define SetupCompileNativeFileBody # Only continue if this object file hasn't been processed already. This lets # the first found source file override any other with the same name. - ifeq ($$(findstring $$($1_OBJ), $$($$($1_BASE)_OBJS_SO_FAR)), ) - $$($1_BASE)_OBJS_SO_FAR += $$($1_OBJ) + ifeq ($$($1_OBJ_PROCESSED), ) + $1_OBJ_PROCESSED := true # This is the definite source file to use for $1_FILENAME. $1_SRC_FILE := $$($1_FILE) @@ -308,14 +308,18 @@ define SetupCompileNativeFileBody ifeq ($$(filter %.s %.S, $$($1_FILENAME)), ) # And this is the dependency file for this obj file. - $1_DEP := $$(patsubst %$(OBJ_SUFFIX),%.d,$$($1_OBJ)) + $1_DEPS_FILE := $$(patsubst %$(OBJ_SUFFIX),%.d,$$($1_OBJ)) # The dependency target file lists all dependencies as empty targets to # avoid make error "No rule to make target" for removed files - $1_DEP_TARGETS := $$(patsubst %$(OBJ_SUFFIX),%.d.targets,$$($1_OBJ)) + $1_DEPS_TARGETS_FILE := $$(patsubst %$(OBJ_SUFFIX),%.d.targets,$$($1_OBJ)) - # Include previously generated dependency information. (if it exists) - -include $$($1_DEP) - -include $$($1_DEP_TARGETS) + # Only try to load individual dependency information files if the global + # file hasn't been loaded (could happen if make was interrupted). + ifneq ($$($$($1_BASE)_DEPS_FILE_LOADED), true) + # Include previously generated dependency information. (if it exists) + -include $$($1_DEPS_FILE) + -include $$($1_DEPS_TARGETS_FILE) + endif endif ifneq ($$(strip $$($1_CFLAGS) $$($1_CXXFLAGS) $$($1_OPTIMIZATION)), ) @@ -340,16 +344,16 @@ define SetupCompileNativeFileBody # object file in the generated deps files. Fixing it with sed. If # compiling assembly, don't try this. $$(call ExecuteWithLog, $$@, \ - $$($1_COMPILER) $$($1_DEP_FLAG) $$($1_DEP).tmp $$($1_COMPILE_OPTIONS)) - $(SED) 's|^$$(@F):|$$@:|' $$($1_DEP).tmp > $$($1_DEP) + $$($1_COMPILER) $$($1_DEP_FLAG) $$($1_DEPS_FILE).tmp $$($1_COMPILE_OPTIONS)) + $(SED) 's|^$$(@F):|$$@:|' $$($1_DEPS_FILE).tmp > $$($1_DEPS_FILE) else $$(call ExecuteWithLog, $$@, \ - $$($1_COMPILER) $$($1_DEP_FLAG) $$($1_DEP) $$($1_COMPILE_OPTIONS)) + $$($1_COMPILER) $$($1_DEP_FLAG) $$($1_DEPS_FILE) $$($1_COMPILE_OPTIONS)) endif # Create a dependency target file from the dependency file. # Solution suggested by http://make.mad-scientist.net/papers/advanced-auto-dependency-generation/ - ifneq ($$($1_DEP), ) - $(SED) $(DEPENDENCY_TARGET_SED_PATTERN) $$($1_DEP) > $$($1_DEP_TARGETS) + ifneq ($$($1_DEPS_FILE), ) + $(SED) $(DEPENDENCY_TARGET_SED_PATTERN) $$($1_DEPS_FILE) > $$($1_DEPS_TARGETS_FILE) endif else # The Visual Studio compiler lacks a feature for generating make @@ -363,10 +367,10 @@ define SetupCompileNativeFileBody $$($1_COMPILER) -showIncludes $$($1_COMPILE_OPTIONS)) \ | $(TR) -d '\r' | $(GREP) -v -e "^Note: including file:" \ -e "^$$($1_FILENAME)$$$$" || test "$$$$?" = "1" ; \ - $(ECHO) $$@: \\ > $$($1_DEP) ; \ + $(ECHO) $$@: \\ > $$($1_DEPS_FILE) ; \ $(SED) $(WINDOWS_SHOWINCLUDE_SED_PATTERN) $$($1_OBJ).log \ - | $(SORT) -u >> $$($1_DEP) ; \ - $(SED) $(DEPENDENCY_TARGET_SED_PATTERN) $$($1_DEP) > $$($1_DEP_TARGETS) + | $(SORT) -u >> $$($1_DEPS_FILE) ; \ + $(SED) $(DEPENDENCY_TARGET_SED_PATTERN) $$($1_DEPS_FILE) > $$($1_DEPS_TARGETS_FILE) endif endif endef @@ -486,6 +490,9 @@ define SetupNativeCompilationBody $1_NOSUFFIX := $$($1_PREFIX)$$($1_NAME) $1_SAFE_NAME := $$(strip $$(subst /,_, $1)) +# Need to make sure TARGET is first on list + $1 := $$($1_TARGET) + # Setup the toolchain to be used $$(call SetIfEmpty, $1_TOOLCHAIN, TOOLCHAIN_DEFAULT) $$(call SetIfEmpty, $1_CC, $$($$($1_TOOLCHAIN)_CC)) @@ -719,20 +726,21 @@ define SetupNativeCompilationBody $1_PCH_FILE := $$($1_OBJECT_DIR)/precompiled/$$(notdir $$($1_PRECOMPILED_HEADER)).pch $1_USE_PCH_FLAGS := -include-pch $$($1_PCH_FILE) endif - $1_PCH_DEP := $$($1_PCH_FILE).d - $1_PCH_DEP_TARGETS := $$($1_PCH_FILE).d.targets + $1_PCH_DEPS_FILE := $$($1_PCH_FILE).d + $1_PCH_DEPS_TARGETS_FILE := $$($1_PCH_FILE).d.targets - -include $$($1_PCH_DEP) - -include $$($1_PCH_DEP_TARGETS) + -include $$($1_PCH_DEPS_FILE) + -include $$($1_PCH_DEPS_TARGETS_FILE) $1_PCH_COMMAND := $$($1_CC) $$($1_CFLAGS) $$($1_EXTRA_CFLAGS) $$($1_SYSROOT_CFLAGS) \ - $$($1_OPT_CFLAGS) -x c++-header -c $(C_FLAG_DEPS) $$($1_PCH_DEP) + $$($1_OPT_CFLAGS) -x c++-header -c $(C_FLAG_DEPS) $$($1_PCH_DEPS_FILE) $$($1_PCH_FILE): $$($1_PRECOMPILED_HEADER) $$($1_COMPILE_VARDEPS_FILE) $$(call LogInfo, Generating precompiled header) $$(call MakeDir, $$(@D)) $$(call ExecuteWithLog, $$@, $$($1_PCH_COMMAND) $$< -o $$@) - $(SED) $(DEPENDENCY_TARGET_SED_PATTERN) $$($1_PCH_DEP) > $$($1_PCH_DEP_TARGETS) + $(SED) $(DEPENDENCY_TARGET_SED_PATTERN) $$($1_PCH_DEPS_FILE) \ + > $$($1_PCH_DEPS_TARGETS_FILE) $$($1_ALL_OBJS): $$($1_PCH_FILE) @@ -748,6 +756,34 @@ define SetupNativeCompilationBody endif endif + # Create a rule to collect all the individual make dependency files into a + # single makefile. + $1_DEPS_FILE := $$($1_OBJECT_DIR)/$1.d + + $$($1_DEPS_FILE): $$($1_ALL_OBJS) + $(RM) $$@ + # CD into dir to reduce risk of hitting command length limits, which + # could otherwise happen if TOPDIR is a very long path. + $(CD) $$($1_OBJECT_DIR) && $(CAT) *.d > $$@.tmp + $(CD) $$($1_OBJECT_DIR) && $(CAT) *.d.targets | $(SORT) -u >> $$@.tmp + # After generating the file, which happens after all objects have been + # compiled, copy it to .old extension. On the next make invocation, this + # .old file will be included by make. + $(CP) $$@.tmp $$@.old + $(MV) $$@.tmp $$@ + + $1 += $$($1_DEPS_FILE) + + # The include must be on the .old file, which represents the state from the + # previous invocation of make. The file being included must not have a rule + # defined for it as otherwise make will think it has to run the rule before + # being able to include the file, which would be wrong since we specifically + # need the file as it was generated by a previous make invocation. + ifneq ($$(wildcard $$($1_DEPS_FILE).old), ) + $1_DEPS_FILE_LOADED := true + -include $$($1_DEPS_FILE).old + endif + # Now call SetupCompileNativeFile for each source file we are going to compile. $$(foreach file, $$($1_SRCS), \ $$(eval $$(call SetupCompileNativeFile, $1_$$(notdir $$(file)),\ @@ -774,10 +810,10 @@ define SetupNativeCompilationBody ifeq ($(call isTargetOs, windows), true) ifneq ($$($1_VERSIONINFO_RESOURCE), ) $1_RES := $$($1_OBJECT_DIR)/$$($1_BASENAME).res - $1_RES_DEP := $$($1_RES).d - $1_RES_DEP_TARGETS := $$($1_RES).d.targets - -include $$($1_RES_DEP) - -include $$($1_RES_DEP_TARGETS) + $1_RES_DEPS_FILE := $$($1_RES).d + $1_RES_DEPS_TARGETS_FILE := $$($1_RES).d.targets + -include $$($1_RES_DEPS_FILE) + -include $$($1_RES_DEPS_TARGETS_FILE) $1_RES_VARDEPS := $$($1_RC) $$($1_RC_FLAGS) $1_RES_VARDEPS_FILE := $$(call DependOnVariable, $1_RES_VARDEPS, \ @@ -794,16 +830,18 @@ define SetupNativeCompilationBody # For some unknown reason, in this case CL actually outputs the show # includes to stderr so need to redirect it to hide the output from the # main log. - $$(call ExecuteWithLog, $$($1_RES_DEP).obj, \ + $$(call ExecuteWithLog, $$($1_RES_DEPS_FILE).obj, \ $$($1_CC) $$(filter-out -l%, $$($1_RC_FLAGS)) \ $$($1_SYSROOT_CFLAGS) -showIncludes -nologo -TC \ - $(CC_OUT_OPTION)$$($1_RES_DEP).obj -P -Fi$$($1_RES_DEP).pp \ + $(CC_OUT_OPTION)$$($1_RES_DEPS_FILE).obj -P -Fi$$($1_RES_DEPS_FILE).pp \ $$($1_VERSIONINFO_RESOURCE)) 2>&1 \ | $(TR) -d '\r' | $(GREP) -v -e "^Note: including file:" \ -e "^$$(notdir $$($1_VERSIONINFO_RESOURCE))$$$$" || test "$$$$?" = "1" ; \ - $(ECHO) $$($1_RES): \\ > $$($1_RES_DEP) ; \ - $(SED) $(WINDOWS_SHOWINCLUDE_SED_PATTERN) $$($1_RES_DEP).obj.log >> $$($1_RES_DEP) ; \ - $(SED) $(DEPENDENCY_TARGET_SED_PATTERN) $$($1_RES_DEP) > $$($1_RES_DEP_TARGETS) + $(ECHO) $$($1_RES): \\ > $$($1_RES_DEPS_FILE) ; \ + $(SED) $(WINDOWS_SHOWINCLUDE_SED_PATTERN) $$($1_RES_DEPS_FILE).obj.log \ + >> $$($1_RES_DEPS_FILE) ; \ + $(SED) $(DEPENDENCY_TARGET_SED_PATTERN) $$($1_RES_DEPS_FILE) \ + > $$($1_RES_DEPS_TARGETS_FILE) endif endif @@ -830,9 +868,6 @@ define SetupNativeCompilationBody $1_EXTRA_LDFLAGS += $(call SET_SHARED_LIBRARY_MAPFILE,$$($1_REAL_MAPFILE)) endif - # Need to make sure TARGET is first on list - $1 := $$($1_TARGET) - ifneq ($$($1_COPY_DEBUG_SYMBOLS), false) $1_COPY_DEBUG_SYMBOLS := $(COPY_DEBUG_SYMBOLS) endif From 03ab1404f0ed0a4e21f97bc2e7b3a3a2fc430217 Mon Sep 17 00:00:00 2001 From: Roman Kennke Date: Tue, 2 Apr 2019 23:00:22 +0200 Subject: [PATCH 13/73] 8221766: Load-reference barriers for Shenandoah Reviewed-by: kvn, erikj, aph, shade --- make/hotspot/lib/JvmFeatures.gmk | 2 - .../shenandoahBarrierSetAssembler_aarch64.cpp | 177 +- .../shenandoahBarrierSetAssembler_aarch64.hpp | 23 +- .../shenandoahBarrierSetC1_aarch64.cpp | 1 + .../gc/shenandoah/shenandoah_aarch64.ad | 12 - .../shenandoahBarrierSetAssembler_x86.cpp | 198 +- .../shenandoahBarrierSetAssembler_x86.hpp | 34 +- .../shenandoah/shenandoahBarrierSetC1_x86.cpp | 1 + .../x86/gc/shenandoah/shenandoah_x86_64.ad | 42 +- src/hotspot/share/adlc/formssel.cpp | 4 +- .../shenandoah/c1/shenandoahBarrierSetC1.cpp | 119 +- .../shenandoah/c1/shenandoahBarrierSetC1.hpp | 15 +- .../shenandoah/c2/shenandoahBarrierSetC2.cpp | 491 +-- .../shenandoah/c2/shenandoahBarrierSetC2.hpp | 41 +- .../gc/shenandoah/c2/shenandoahSupport.cpp | 2679 ++++++----------- .../gc/shenandoah/c2/shenandoahSupport.hpp | 219 +- .../shenandoahAdaptiveHeuristics.cpp | 5 +- .../shenandoahAggressiveHeuristics.cpp | 5 +- .../shenandoahCompactHeuristics.cpp | 5 +- .../shenandoahPassiveHeuristics.cpp | 5 +- .../heuristics/shenandoahStaticHeuristics.cpp | 5 +- .../shenandoahTraversalHeuristics.cpp | 5 +- .../gc/shenandoah/shenandoahArguments.cpp | 15 - .../gc/shenandoah/shenandoahBarrierSet.cpp | 49 +- .../gc/shenandoah/shenandoahBarrierSet.hpp | 144 +- .../shenandoahBarrierSet.inline.hpp | 144 +- .../gc/shenandoah/shenandoahCodeRoots.cpp | 43 +- .../shenandoah/shenandoahEvacOOMHandler.hpp | 14 +- .../share/gc/shenandoah/shenandoahHeap.cpp | 9 +- .../share/gc/shenandoah/shenandoahHeap.hpp | 6 +- .../gc/shenandoah/shenandoahMarkCompact.cpp | 2 +- .../gc/shenandoah/shenandoahOopClosures.hpp | 2 +- .../gc/shenandoah/shenandoahRootProcessor.cpp | 39 +- .../gc/shenandoah/shenandoahRootProcessor.hpp | 13 +- .../share/gc/shenandoah/shenandoahRuntime.cpp | 4 +- .../share/gc/shenandoah/shenandoahRuntime.hpp | 2 +- .../gc/shenandoah/shenandoah_globals.hpp | 26 +- src/hotspot/share/opto/classes.hpp | 4 +- src/hotspot/share/opto/compile.cpp | 2 +- src/hotspot/share/opto/lcm.cpp | 1 - src/hotspot/share/opto/library_call.cpp | 4 +- src/hotspot/share/opto/loopPredicate.cpp | 3 - src/hotspot/share/opto/loopnode.cpp | 2 +- src/hotspot/share/opto/loopnode.hpp | 5 +- src/hotspot/share/opto/loopopts.cpp | 7 +- src/hotspot/share/opto/node.hpp | 3 - .../options/TestSelectiveBarrierFlags.java | 8 +- .../options/TestWrongBarrierDisable.java | 9 +- 48 files changed, 1388 insertions(+), 3260 deletions(-) diff --git a/make/hotspot/lib/JvmFeatures.gmk b/make/hotspot/lib/JvmFeatures.gmk index 7c855492e53..4cf0f29fd89 100644 --- a/make/hotspot/lib/JvmFeatures.gmk +++ b/make/hotspot/lib/JvmFeatures.gmk @@ -172,8 +172,6 @@ endif ifneq ($(call check-jvm-feature, shenandoahgc), true) JVM_CFLAGS_FEATURES += -DINCLUDE_SHENANDOAHGC=0 JVM_EXCLUDE_PATTERNS += gc/shenandoah -else - JVM_CFLAGS_FEATURES += -DSUPPORT_BARRIER_ON_PRIMITIVES -DSUPPORT_NOT_TO_SPACE_INVARIANT endif ifneq ($(call check-jvm-feature, jfr), true) diff --git a/src/hotspot/cpu/aarch64/gc/shenandoah/shenandoahBarrierSetAssembler_aarch64.cpp b/src/hotspot/cpu/aarch64/gc/shenandoah/shenandoahBarrierSetAssembler_aarch64.cpp index c063ce7afa2..139738e171e 100644 --- a/src/hotspot/cpu/aarch64/gc/shenandoah/shenandoahBarrierSetAssembler_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/gc/shenandoah/shenandoahBarrierSetAssembler_aarch64.cpp @@ -40,7 +40,7 @@ #define __ masm-> -address ShenandoahBarrierSetAssembler::_shenandoah_wb = NULL; +address ShenandoahBarrierSetAssembler::_shenandoah_lrb = NULL; void ShenandoahBarrierSetAssembler::arraycopy_prologue(MacroAssembler* masm, DecoratorSet decorators, bool is_oop, Register addr, Register count, RegSet saved_regs) { @@ -198,60 +198,31 @@ void ShenandoahBarrierSetAssembler::satb_write_barrier_pre(MacroAssembler* masm, __ bind(done); } -void ShenandoahBarrierSetAssembler::read_barrier(MacroAssembler* masm, Register dst) { - if (ShenandoahReadBarrier) { - read_barrier_impl(masm, dst); - } -} - -void ShenandoahBarrierSetAssembler::read_barrier_impl(MacroAssembler* masm, Register dst) { - assert(UseShenandoahGC && (ShenandoahReadBarrier || ShenandoahStoreValReadBarrier || ShenandoahCASBarrier), "should be enabled"); +void ShenandoahBarrierSetAssembler::resolve_forward_pointer(MacroAssembler* masm, Register dst) { + assert(ShenandoahLoadRefBarrier || ShenandoahCASBarrier, "Should be enabled"); Label is_null; __ cbz(dst, is_null); - read_barrier_not_null_impl(masm, dst); + resolve_forward_pointer_not_null(masm, dst); __ bind(is_null); } -void ShenandoahBarrierSetAssembler::read_barrier_not_null(MacroAssembler* masm, Register dst) { - if (ShenandoahReadBarrier) { - read_barrier_not_null_impl(masm, dst); - } -} - - -void ShenandoahBarrierSetAssembler::read_barrier_not_null_impl(MacroAssembler* masm, Register dst) { - assert(UseShenandoahGC && (ShenandoahReadBarrier || ShenandoahStoreValReadBarrier || ShenandoahCASBarrier), "should be enabled"); +// IMPORTANT: This must preserve all registers, even rscratch1 and rscratch2. +void ShenandoahBarrierSetAssembler::resolve_forward_pointer_not_null(MacroAssembler* masm, Register dst) { + assert(ShenandoahLoadRefBarrier || ShenandoahCASBarrier, "Should be enabled"); __ ldr(dst, Address(dst, ShenandoahBrooksPointer::byte_offset())); } -void ShenandoahBarrierSetAssembler::write_barrier(MacroAssembler* masm, Register dst) { - if (ShenandoahWriteBarrier) { - write_barrier_impl(masm, dst); - } -} - -void ShenandoahBarrierSetAssembler::write_barrier_impl(MacroAssembler* masm, Register dst) { - assert(UseShenandoahGC && (ShenandoahWriteBarrier || ShenandoahStoreValEnqueueBarrier), "Should be enabled"); - assert(dst != rscratch1, "need rscratch1"); +void ShenandoahBarrierSetAssembler::load_reference_barrier_not_null(MacroAssembler* masm, Register dst, Register tmp) { + assert(ShenandoahLoadRefBarrier, "Should be enabled"); assert(dst != rscratch2, "need rscratch2"); Label done; - + __ enter(); Address gc_state(rthread, in_bytes(ShenandoahThreadLocalData::gc_state_offset())); - __ ldrb(rscratch1, gc_state); + __ ldrb(rscratch2, gc_state); // Check for heap stability - __ mov(rscratch2, ShenandoahHeap::HAS_FORWARDED | ShenandoahHeap::EVACUATION | ShenandoahHeap::TRAVERSAL); - __ tst(rscratch1, rscratch2); - __ br(Assembler::EQ, done); - - // Heap is unstable, need to perform the read-barrier even if WB is inactive - __ ldr(dst, Address(dst, ShenandoahBrooksPointer::byte_offset())); - - // Check for evacuation-in-progress and jump to WB slow-path if needed - __ mov(rscratch2, ShenandoahHeap::EVACUATION | ShenandoahHeap::TRAVERSAL); - __ tst(rscratch1, rscratch2); - __ br(Assembler::EQ, done); + __ tbz(rscratch2, ShenandoahHeap::HAS_FORWARDED_BITPOS, done); RegSet to_save = RegSet::of(r0); if (dst != r0) { @@ -259,7 +230,7 @@ void ShenandoahBarrierSetAssembler::write_barrier_impl(MacroAssembler* masm, Reg __ mov(r0, dst); } - __ far_call(RuntimeAddress(CAST_FROM_FN_PTR(address, ShenandoahBarrierSetAssembler::shenandoah_wb()))); + __ far_call(RuntimeAddress(CAST_FROM_FN_PTR(address, ShenandoahBarrierSetAssembler::shenandoah_lrb()))); if (dst != r0) { __ mov(dst, r0); @@ -267,14 +238,11 @@ void ShenandoahBarrierSetAssembler::write_barrier_impl(MacroAssembler* masm, Reg } __ bind(done); + __ leave(); } void ShenandoahBarrierSetAssembler::storeval_barrier(MacroAssembler* masm, Register dst, Register tmp) { if (ShenandoahStoreValEnqueueBarrier) { - Label is_null; - __ cbz(dst, is_null); - write_barrier_impl(masm, dst); - __ bind(is_null); // Save possibly live regs. RegSet live_regs = RegSet::range(r0, r4) - dst; __ push(live_regs, sp); @@ -286,44 +254,45 @@ void ShenandoahBarrierSetAssembler::storeval_barrier(MacroAssembler* masm, Regis __ ldrd(v0, __ post(sp, 2 * wordSize)); __ pop(live_regs, sp); } - if (ShenandoahStoreValReadBarrier) { - read_barrier_impl(masm, dst); +} + +void ShenandoahBarrierSetAssembler::load_reference_barrier(MacroAssembler* masm, Register dst, Register tmp) { + if (ShenandoahLoadRefBarrier) { + Label is_null; + __ cbz(dst, is_null); + load_reference_barrier_not_null(masm, dst, tmp); + __ bind(is_null); } } void ShenandoahBarrierSetAssembler::load_at(MacroAssembler* masm, DecoratorSet decorators, BasicType type, Register dst, Address src, Register tmp1, Register tmp_thread) { bool on_oop = type == T_OBJECT || type == T_ARRAY; - bool in_heap = (decorators & IN_HEAP) != 0; bool on_weak = (decorators & ON_WEAK_OOP_REF) != 0; bool on_phantom = (decorators & ON_PHANTOM_OOP_REF) != 0; bool on_reference = on_weak || on_phantom; - if (in_heap) { - read_barrier_not_null(masm, src.base()); - } - BarrierSetAssembler::load_at(masm, decorators, type, dst, src, tmp1, tmp_thread); - if (ShenandoahKeepAliveBarrier && on_oop && on_reference) { - __ enter(); - satb_write_barrier_pre(masm /* masm */, - noreg /* obj */, - dst /* pre_val */, - rthread /* thread */, - tmp1 /* tmp */, - true /* tosca_live */, - true /* expand_call */); - __ leave(); + if (on_oop) { + load_reference_barrier(masm, dst, tmp1); + + if (ShenandoahKeepAliveBarrier && on_reference) { + __ enter(); + satb_write_barrier_pre(masm /* masm */, + noreg /* obj */, + dst /* pre_val */, + rthread /* thread */, + tmp1 /* tmp */, + true /* tosca_live */, + true /* expand_call */); + __ leave(); + } } } void ShenandoahBarrierSetAssembler::store_at(MacroAssembler* masm, DecoratorSet decorators, BasicType type, Address dst, Register val, Register tmp1, Register tmp2) { bool on_oop = type == T_OBJECT || type == T_ARRAY; - bool in_heap = (decorators & IN_HEAP) != 0; - if (in_heap) { - write_barrier(masm, dst.base()); - } if (!on_oop) { BarrierSetAssembler::store_at(masm, decorators, type, dst, val, tmp1, tmp2); return; @@ -361,21 +330,6 @@ void ShenandoahBarrierSetAssembler::store_at(MacroAssembler* masm, DecoratorSet } -void ShenandoahBarrierSetAssembler::obj_equals(MacroAssembler* masm, Register op1, Register op2) { - __ cmp(op1, op2); - if (ShenandoahAcmpBarrier) { - Label done; - __ br(Assembler::EQ, done); - // The object may have been evacuated, but we won't see it without a - // membar here. - __ membar(Assembler::LoadStore| Assembler::LoadLoad); - read_barrier(masm, op1); - read_barrier(masm, op2); - __ cmp(op1, op2); - __ bind(done); - } -} - void ShenandoahBarrierSetAssembler::tlab_allocate(MacroAssembler* masm, Register obj, Register var_size_in_bytes, int con_size_in_bytes, @@ -410,27 +364,6 @@ void ShenandoahBarrierSetAssembler::tlab_allocate(MacroAssembler* masm, Register } } -void ShenandoahBarrierSetAssembler::resolve(MacroAssembler* masm, DecoratorSet decorators, Register obj) { - bool oop_not_null = (decorators & IS_NOT_NULL) != 0; - bool is_write = (decorators & ACCESS_WRITE) != 0; - if (is_write) { - if (oop_not_null) { - write_barrier(masm, obj); - } else { - Label done; - __ cbz(obj, done); - write_barrier(masm, obj); - __ bind(done); - } - } else { - if (oop_not_null) { - read_barrier_not_null(masm, obj); - } else { - read_barrier(masm, obj); - } - } -} - void ShenandoahBarrierSetAssembler::cmpxchg_oop(MacroAssembler* masm, Register addr, Register expected, Register new_val, bool acquire, bool release, bool weak, bool is_cae, Register result) { @@ -469,8 +402,8 @@ void ShenandoahBarrierSetAssembler::cmpxchg_oop(MacroAssembler* masm, Register a __ decode_heap_oop(tmp1, tmp1); __ decode_heap_oop(tmp2, tmp2); } - read_barrier_impl(masm, tmp1); - read_barrier_impl(masm, tmp2); + resolve_forward_pointer(masm, tmp1); + resolve_forward_pointer(masm, tmp2); __ cmp(tmp1, tmp2); // Retry with expected now being the value we just loaded from addr. __ br(Assembler::EQ, retry); @@ -515,7 +448,7 @@ void ShenandoahBarrierSetAssembler::gen_pre_barrier_stub(LIR_Assembler* ce, Shen __ b(*stub->continuation()); } -void ShenandoahBarrierSetAssembler::gen_write_barrier_stub(LIR_Assembler* ce, ShenandoahWriteBarrierStub* stub) { +void ShenandoahBarrierSetAssembler::gen_load_reference_barrier_stub(LIR_Assembler* ce, ShenandoahLoadReferenceBarrierStub* stub) { Register obj = stub->obj()->as_register(); Register res = stub->result()->as_register(); @@ -532,7 +465,7 @@ void ShenandoahBarrierSetAssembler::gen_write_barrier_stub(LIR_Assembler* ce, Sh __ cbz(res, done); } - write_barrier(ce->masm(), res); + load_reference_barrier_not_null(ce->masm(), res, rscratch1); __ bind(done); __ b(*stub->continuation()); @@ -592,14 +525,14 @@ void ShenandoahBarrierSetAssembler::generate_c1_pre_barrier_runtime_stub(StubAss #endif // COMPILER1 -address ShenandoahBarrierSetAssembler::shenandoah_wb() { - assert(_shenandoah_wb != NULL, "need write barrier stub"); - return _shenandoah_wb; +address ShenandoahBarrierSetAssembler::shenandoah_lrb() { + assert(_shenandoah_lrb != NULL, "need load reference barrier stub"); + return _shenandoah_lrb; } #define __ cgen->assembler()-> -// Shenandoah write barrier. +// Shenandoah load reference barrier. // // Input: // r0: OOP to evacuate. Not null. @@ -608,13 +541,13 @@ address ShenandoahBarrierSetAssembler::shenandoah_wb() { // r0: Pointer to evacuated OOP. // // Trash rscratch1, rscratch2. Preserve everything else. -address ShenandoahBarrierSetAssembler::generate_shenandoah_wb(StubCodeGenerator* cgen) { +address ShenandoahBarrierSetAssembler::generate_shenandoah_lrb(StubCodeGenerator* cgen) { __ align(6); - StubCodeMark mark(cgen, "StubRoutines", "shenandoah_wb"); + StubCodeMark mark(cgen, "StubRoutines", "shenandoah_lrb"); address start = __ pc(); - Label work; + Label work, done; __ mov(rscratch2, ShenandoahHeap::in_cset_fast_test_addr()); __ lsr(rscratch1, r0, ShenandoahHeapRegion::region_size_bytes_shift_jint()); __ ldrb(rscratch2, Address(rscratch2, rscratch1)); @@ -622,19 +555,23 @@ address ShenandoahBarrierSetAssembler::generate_shenandoah_wb(StubCodeGenerator* __ ret(lr); __ bind(work); - Register obj = r0; + __ mov(rscratch2, r0); + resolve_forward_pointer_not_null(cgen->assembler(), r0); + __ cmp(rscratch2, r0); + __ br(Assembler::NE, done); __ enter(); // required for proper stackwalking of RuntimeStub frame __ push_call_clobbered_registers(); - __ mov(lr, CAST_FROM_FN_PTR(address, ShenandoahRuntime::write_barrier_JRT)); + __ mov(lr, CAST_FROM_FN_PTR(address, ShenandoahRuntime::load_reference_barrier_JRT)); __ blrt(lr, 1, 0, MacroAssembler::ret_type_integral); - __ mov(rscratch1, obj); + __ mov(rscratch1, r0); __ pop_call_clobbered_registers(); - __ mov(obj, rscratch1); + __ mov(r0, rscratch1); __ leave(); // required for proper stackwalking of RuntimeStub frame + __ bind(done); __ ret(lr); return start; @@ -643,12 +580,12 @@ address ShenandoahBarrierSetAssembler::generate_shenandoah_wb(StubCodeGenerator* #undef __ void ShenandoahBarrierSetAssembler::barrier_stubs_init() { - if (ShenandoahWriteBarrier || ShenandoahStoreValEnqueueBarrier) { + 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_wb = generate_shenandoah_wb(&cgen); + _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 69e0782cf44..86b8e3503cd 100644 --- a/src/hotspot/cpu/aarch64/gc/shenandoah/shenandoahBarrierSetAssembler_aarch64.hpp +++ b/src/hotspot/cpu/aarch64/gc/shenandoah/shenandoahBarrierSetAssembler_aarch64.hpp @@ -29,7 +29,7 @@ #ifdef COMPILER1 class LIR_Assembler; class ShenandoahPreBarrierStub; -class ShenandoahWriteBarrierStub; +class ShenandoahLoadReferenceBarrierStub; class StubAssembler; class StubCodeGenerator; #endif @@ -37,7 +37,7 @@ class StubCodeGenerator; class ShenandoahBarrierSetAssembler: public BarrierSetAssembler { private: - static address _shenandoah_wb; + static address _shenandoah_lrb; void satb_write_barrier_pre(MacroAssembler* masm, Register obj, @@ -54,24 +54,21 @@ private: bool tosca_live, bool expand_call); - void read_barrier(MacroAssembler* masm, Register dst); - void read_barrier_impl(MacroAssembler* masm, Register dst); - void read_barrier_not_null(MacroAssembler* masm, Register dst); - void read_barrier_not_null_impl(MacroAssembler* masm, Register dst); - void write_barrier(MacroAssembler* masm, Register dst); - void write_barrier_impl(MacroAssembler* masm, Register dst); - void asm_acmp_barrier(MacroAssembler* masm, Register op1, Register op2); + void resolve_forward_pointer(MacroAssembler* masm, Register dst); + void resolve_forward_pointer_not_null(MacroAssembler* masm, Register dst); + void load_reference_barrier(MacroAssembler* masm, Register dst, Register tmp); + void load_reference_barrier_not_null(MacroAssembler* masm, Register dst, Register tmp); - address generate_shenandoah_wb(StubCodeGenerator* cgen); + address generate_shenandoah_lrb(StubCodeGenerator* cgen); public: - static address shenandoah_wb(); + 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); - void gen_write_barrier_stub(LIR_Assembler* ce, ShenandoahWriteBarrierStub* stub); + void gen_load_reference_barrier_stub(LIR_Assembler* ce, ShenandoahLoadReferenceBarrierStub* stub); void generate_c1_pre_barrier_runtime_stub(StubAssembler* sasm); #endif @@ -83,8 +80,6 @@ public: Register dst, Address src, Register tmp1, Register tmp_thread); virtual void store_at(MacroAssembler* masm, DecoratorSet decorators, BasicType type, Address dst, Register val, Register tmp1, Register tmp2); - virtual void obj_equals(MacroAssembler* masm, Register src1, Register src2); - virtual void resolve(MacroAssembler* masm, DecoratorSet decorators, Register obj); virtual void tlab_allocate(MacroAssembler* masm, Register obj, Register var_size_in_bytes, int con_size_in_bytes, diff --git a/src/hotspot/cpu/aarch64/gc/shenandoah/shenandoahBarrierSetC1_aarch64.cpp b/src/hotspot/cpu/aarch64/gc/shenandoah/shenandoahBarrierSetC1_aarch64.cpp index c78392a1220..e057c1691d3 100644 --- a/src/hotspot/cpu/aarch64/gc/shenandoah/shenandoahBarrierSetC1_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/gc/shenandoah/shenandoahBarrierSetC1_aarch64.cpp @@ -99,6 +99,7 @@ LIR_Opr ShenandoahBarrierSetC1::atomic_xchg_at_resolved(LIRAccess& access, LIRIt __ xchg(access.resolved_addr(), value_opr, result, tmp); if (access.is_oop()) { + result = load_reference_barrier(access.gen(), result, access.access_emit_info(), true); if (ShenandoahSATBBarrier) { pre_barrier(access.gen(), access.access_emit_info(), access.decorators(), LIR_OprFact::illegalOpr, result /* pre_val */); diff --git a/src/hotspot/cpu/aarch64/gc/shenandoah/shenandoah_aarch64.ad b/src/hotspot/cpu/aarch64/gc/shenandoah/shenandoah_aarch64.ad index c65fac0b724..99c97d48054 100644 --- a/src/hotspot/cpu/aarch64/gc/shenandoah/shenandoah_aarch64.ad +++ b/src/hotspot/cpu/aarch64/gc/shenandoah/shenandoah_aarch64.ad @@ -45,18 +45,6 @@ encode %{ %} %} -instruct shenandoahRB(iRegPNoSp dst, iRegP src, rFlagsReg cr) %{ - match(Set dst (ShenandoahReadBarrier src)); - format %{ "shenandoah_rb $dst,$src" %} - ins_encode %{ - Register s = $src$$Register; - Register d = $dst$$Register; - __ ldr(d, Address(s, ShenandoahBrooksPointer::byte_offset())); - %} - ins_pipe(pipe_class_memory); -%} - - instruct compareAndSwapP_shenandoah(iRegINoSp res, indirect mem, iRegP oldval, iRegP newval, iRegPNoSp tmp, rFlagsReg cr) %{ match(Set res (ShenandoahCompareAndSwapP mem (Binary oldval newval))); diff --git a/src/hotspot/cpu/x86/gc/shenandoah/shenandoahBarrierSetAssembler_x86.cpp b/src/hotspot/cpu/x86/gc/shenandoah/shenandoahBarrierSetAssembler_x86.cpp index 8cced4100b1..f3c74751053 100644 --- a/src/hotspot/cpu/x86/gc/shenandoah/shenandoahBarrierSetAssembler_x86.cpp +++ b/src/hotspot/cpu/x86/gc/shenandoah/shenandoahBarrierSetAssembler_x86.cpp @@ -41,7 +41,7 @@ #define __ masm-> -address ShenandoahBarrierSetAssembler::_shenandoah_wb = NULL; +address ShenandoahBarrierSetAssembler::_shenandoah_lrb = NULL; void ShenandoahBarrierSetAssembler::arraycopy_prologue(MacroAssembler* masm, DecoratorSet decorators, BasicType type, Register src, Register dst, Register count) { @@ -293,41 +293,23 @@ void ShenandoahBarrierSetAssembler::satb_write_barrier_pre(MacroAssembler* masm, __ bind(done); } -void ShenandoahBarrierSetAssembler::read_barrier(MacroAssembler* masm, Register dst) { - if (ShenandoahReadBarrier) { - read_barrier_impl(masm, dst); - } -} - -void ShenandoahBarrierSetAssembler::read_barrier_impl(MacroAssembler* masm, Register dst) { - assert(UseShenandoahGC && (ShenandoahReadBarrier || ShenandoahStoreValReadBarrier || ShenandoahCASBarrier), "should be enabled"); +void ShenandoahBarrierSetAssembler::resolve_forward_pointer(MacroAssembler* masm, Register dst) { + assert(ShenandoahCASBarrier, "should be enabled"); Label is_null; __ testptr(dst, dst); __ jcc(Assembler::zero, is_null); - read_barrier_not_null_impl(masm, dst); + resolve_forward_pointer_not_null(masm, dst); __ bind(is_null); } -void ShenandoahBarrierSetAssembler::read_barrier_not_null(MacroAssembler* masm, Register dst) { - if (ShenandoahReadBarrier) { - read_barrier_not_null_impl(masm, dst); - } -} - -void ShenandoahBarrierSetAssembler::read_barrier_not_null_impl(MacroAssembler* masm, Register dst) { - assert(UseShenandoahGC && (ShenandoahReadBarrier || ShenandoahStoreValReadBarrier || ShenandoahCASBarrier), "should be enabled"); +void ShenandoahBarrierSetAssembler::resolve_forward_pointer_not_null(MacroAssembler* masm, Register dst) { + assert(ShenandoahCASBarrier || ShenandoahLoadRefBarrier, "should be enabled"); __ movptr(dst, Address(dst, ShenandoahBrooksPointer::byte_offset())); } -void ShenandoahBarrierSetAssembler::write_barrier(MacroAssembler* masm, Register dst) { - if (ShenandoahWriteBarrier) { - write_barrier_impl(masm, dst); - } -} - -void ShenandoahBarrierSetAssembler::write_barrier_impl(MacroAssembler* masm, Register dst) { - assert(UseShenandoahGC && (ShenandoahWriteBarrier || ShenandoahStoreValEnqueueBarrier), "Should be enabled"); +void ShenandoahBarrierSetAssembler::load_reference_barrier_not_null(MacroAssembler* masm, Register dst) { + assert(ShenandoahLoadRefBarrier, "Should be enabled"); #ifdef _LP64 Label done; @@ -335,8 +317,8 @@ void ShenandoahBarrierSetAssembler::write_barrier_impl(MacroAssembler* masm, Reg __ testb(gc_state, ShenandoahHeap::HAS_FORWARDED | ShenandoahHeap::EVACUATION | ShenandoahHeap::TRAVERSAL); __ jccb(Assembler::zero, done); - // Heap is unstable, need to perform the read-barrier even if WB is inactive - read_barrier_not_null(masm, dst); + // Heap is unstable, need to perform the resolve even if LRB is inactive + resolve_forward_pointer_not_null(masm, dst); __ testb(gc_state, ShenandoahHeap::EVACUATION | ShenandoahHeap::TRAVERSAL); __ jccb(Assembler::zero, done); @@ -345,7 +327,7 @@ void ShenandoahBarrierSetAssembler::write_barrier_impl(MacroAssembler* masm, Reg __ xchgptr(dst, rax); // Move obj into rax and save rax into obj. } - __ call(RuntimeAddress(CAST_FROM_FN_PTR(address, ShenandoahBarrierSetAssembler::shenandoah_wb()))); + __ call(RuntimeAddress(CAST_FROM_FN_PTR(address, ShenandoahBarrierSetAssembler::shenandoah_lrb()))); if (dst != rax) { __ xchgptr(rax, dst); // Swap back obj with rax. @@ -358,24 +340,18 @@ void ShenandoahBarrierSetAssembler::write_barrier_impl(MacroAssembler* masm, Reg } void ShenandoahBarrierSetAssembler::storeval_barrier(MacroAssembler* masm, Register dst, Register tmp) { - if (ShenandoahStoreValReadBarrier || ShenandoahStoreValEnqueueBarrier) { + if (ShenandoahStoreValEnqueueBarrier) { storeval_barrier_impl(masm, dst, tmp); } } void ShenandoahBarrierSetAssembler::storeval_barrier_impl(MacroAssembler* masm, Register dst, Register tmp) { - assert(UseShenandoahGC && (ShenandoahStoreValReadBarrier || ShenandoahStoreValEnqueueBarrier), "should be enabled"); + assert(ShenandoahStoreValEnqueueBarrier, "should be enabled"); if (dst == noreg) return; #ifdef _LP64 if (ShenandoahStoreValEnqueueBarrier) { - Label is_null; - __ testptr(dst, dst); - __ jcc(Assembler::zero, is_null); - write_barrier_impl(masm, dst); - __ bind(is_null); - // The set of registers to be saved+restored is the same as in the write-barrier above. // Those are the commonly used registers in the interpreter. __ pusha(); @@ -389,50 +365,54 @@ void ShenandoahBarrierSetAssembler::storeval_barrier_impl(MacroAssembler* masm, //__ pop_callee_saved_registers(); __ popa(); } - if (ShenandoahStoreValReadBarrier) { - read_barrier_impl(masm, dst); - } #else Unimplemented(); #endif } +void ShenandoahBarrierSetAssembler::load_reference_barrier(MacroAssembler* masm, Register dst) { + if (ShenandoahLoadRefBarrier) { + Label done; + __ testptr(dst, dst); + __ jcc(Assembler::zero, done); + load_reference_barrier_not_null(masm, dst); + __ bind(done); + } +} + void ShenandoahBarrierSetAssembler::load_at(MacroAssembler* masm, DecoratorSet decorators, BasicType type, Register dst, Address src, Register tmp1, Register tmp_thread) { bool on_oop = type == T_OBJECT || type == T_ARRAY; - bool in_heap = (decorators & IN_HEAP) != 0; bool on_weak = (decorators & ON_WEAK_OOP_REF) != 0; bool on_phantom = (decorators & ON_PHANTOM_OOP_REF) != 0; bool on_reference = on_weak || on_phantom; - if (in_heap) { - read_barrier_not_null(masm, src.base()); - } - BarrierSetAssembler::load_at(masm, decorators, type, dst, src, tmp1, tmp_thread); - if (ShenandoahKeepAliveBarrier && on_oop && on_reference) { - const Register thread = NOT_LP64(tmp_thread) LP64_ONLY(r15_thread); - NOT_LP64(__ get_thread(thread)); + BarrierSetAssembler::load_at(masm, decorators, type, dst, src, tmp1, tmp_thread); + if (on_oop) { + load_reference_barrier(masm, dst); - // Generate the SATB pre-barrier code to log the value of - // the referent field in an SATB buffer. - shenandoah_write_barrier_pre(masm /* masm */, - noreg /* obj */, - dst /* pre_val */, - thread /* thread */, - tmp1 /* tmp */, - true /* tosca_live */, - true /* expand_call */); + if (ShenandoahKeepAliveBarrier && on_reference) { + const Register thread = NOT_LP64(tmp_thread) LP64_ONLY(r15_thread); + NOT_LP64(__ get_thread(thread)); + // Generate the SATB pre-barrier code to log the value of + // the referent field in an SATB buffer. + shenandoah_write_barrier_pre(masm /* masm */, + noreg /* obj */, + dst /* pre_val */, + thread /* thread */, + tmp1 /* tmp */, + true /* tosca_live */, + true /* expand_call */); + } } } void ShenandoahBarrierSetAssembler::store_at(MacroAssembler* masm, DecoratorSet decorators, BasicType type, Address dst, Register val, Register tmp1, Register tmp2) { + bool on_oop = type == T_OBJECT || type == T_ARRAY; bool in_heap = (decorators & IN_HEAP) != 0; bool as_normal = (decorators & AS_NORMAL) != 0; - if (in_heap) { - write_barrier(masm, dst.base()); - } - if (type == T_OBJECT || type == T_ARRAY) { + if (on_oop && in_heap) { bool needs_pre_barrier = as_normal; Register tmp3 = LP64_ONLY(r8) NOT_LP64(rsi); @@ -475,44 +455,6 @@ void ShenandoahBarrierSetAssembler::store_at(MacroAssembler* masm, DecoratorSet } } -#ifndef _LP64 -void ShenandoahBarrierSetAssembler::obj_equals(MacroAssembler* masm, - Address obj1, jobject obj2) { - Unimplemented(); -} - -void ShenandoahBarrierSetAssembler::obj_equals(MacroAssembler* masm, - Register obj1, jobject obj2) { - Unimplemented(); -} -#endif - - -void ShenandoahBarrierSetAssembler::obj_equals(MacroAssembler* masm, Register op1, Register op2) { - __ cmpptr(op1, op2); - if (ShenandoahAcmpBarrier) { - Label done; - __ jccb(Assembler::equal, done); - read_barrier(masm, op1); - read_barrier(masm, op2); - __ cmpptr(op1, op2); - __ bind(done); - } -} - -void ShenandoahBarrierSetAssembler::obj_equals(MacroAssembler* masm, Register src1, Address src2) { - __ cmpptr(src1, src2); - if (ShenandoahAcmpBarrier) { - Label done; - __ jccb(Assembler::equal, done); - __ movptr(rscratch2, src2); - read_barrier(masm, src1); - read_barrier(masm, rscratch2); - __ cmpptr(src1, rscratch2); - __ bind(done); - } -} - void ShenandoahBarrierSetAssembler::tlab_allocate(MacroAssembler* masm, Register thread, Register obj, Register var_size_in_bytes, @@ -562,28 +504,6 @@ void ShenandoahBarrierSetAssembler::tlab_allocate(MacroAssembler* masm, __ verify_tlab(); } -void ShenandoahBarrierSetAssembler::resolve(MacroAssembler* masm, DecoratorSet decorators, Register obj) { - bool oop_not_null = (decorators & IS_NOT_NULL) != 0; - bool is_write = (decorators & ACCESS_WRITE) != 0; - if (is_write) { - if (oop_not_null) { - write_barrier(masm, obj); - } else { - Label done; - __ testptr(obj, obj); - __ jcc(Assembler::zero, done); - write_barrier(masm, obj); - __ bind(done); - } - } else { - if (oop_not_null) { - read_barrier_not_null(masm, obj); - } else { - read_barrier(masm, obj); - } - } -} - // Special Shenandoah CAS implementation that handles false negatives // due to concurrent evacuation. #ifndef _LP64 @@ -622,14 +542,14 @@ void ShenandoahBarrierSetAssembler::cmpxchg_oop(MacroAssembler* masm, // Step 2. CAS had failed. This may be a false negative. // // The trouble comes when we compare the to-space pointer with the from-space - // pointer to the same object. To resolve this, it will suffice to read both - // oldval and the value from memory through the read barriers -- this will give - // both to-space pointers. If they mismatch, then it was a legitimate failure. + // pointer to the same object. To resolve this, it will suffice to resolve both + // oldval and the value from memory -- this will give both to-space pointers. + // If they mismatch, then it was a legitimate failure. // if (UseCompressedOops) { __ decode_heap_oop(tmp1); } - read_barrier_impl(masm, tmp1); + resolve_forward_pointer(masm, tmp1); if (UseCompressedOops) { __ movl(tmp2, oldval); @@ -637,7 +557,7 @@ void ShenandoahBarrierSetAssembler::cmpxchg_oop(MacroAssembler* masm, } else { __ movptr(tmp2, oldval); } - read_barrier_impl(masm, tmp2); + resolve_forward_pointer(masm, tmp2); __ cmpptr(tmp1, tmp2); __ jcc(Assembler::notEqual, done, true); @@ -646,8 +566,8 @@ void ShenandoahBarrierSetAssembler::cmpxchg_oop(MacroAssembler* masm, // // Corner case: it may happen that somebody stored the from-space pointer // to memory while we were preparing for retry. Therefore, we can fail again - // on retry, and so need to do this in loop, always re-reading the failure - // witness through the read barrier. + // on retry, and so need to do this in loop, always resolving the failure + // witness. __ bind(retry); if (os::is_MP()) __ lock(); if (UseCompressedOops) { @@ -663,7 +583,7 @@ void ShenandoahBarrierSetAssembler::cmpxchg_oop(MacroAssembler* masm, } else { __ movptr(tmp2, oldval); } - read_barrier_impl(masm, tmp2); + resolve_forward_pointer(masm, tmp2); __ cmpptr(tmp1, tmp2); __ jcc(Assembler::equal, retry, true); @@ -811,7 +731,7 @@ void ShenandoahBarrierSetAssembler::gen_pre_barrier_stub(LIR_Assembler* ce, Shen } -void ShenandoahBarrierSetAssembler::gen_write_barrier_stub(LIR_Assembler* ce, ShenandoahWriteBarrierStub* stub) { +void ShenandoahBarrierSetAssembler::gen_load_reference_barrier_stub(LIR_Assembler* ce, ShenandoahLoadReferenceBarrierStub* stub) { __ bind(*stub->entry()); Label done; @@ -828,7 +748,7 @@ void ShenandoahBarrierSetAssembler::gen_write_barrier_stub(LIR_Assembler* ce, Sh __ jcc(Assembler::zero, done); } - write_barrier(ce->masm(), res); + load_reference_barrier_not_null(ce->masm(), res); __ bind(done); __ jmp(*stub->continuation()); @@ -898,16 +818,16 @@ void ShenandoahBarrierSetAssembler::generate_c1_pre_barrier_runtime_stub(StubAss #endif // COMPILER1 -address ShenandoahBarrierSetAssembler::shenandoah_wb() { - assert(_shenandoah_wb != NULL, "need write barrier stub"); - return _shenandoah_wb; +address ShenandoahBarrierSetAssembler::shenandoah_lrb() { + assert(_shenandoah_lrb != NULL, "need load reference barrier stub"); + return _shenandoah_lrb; } #define __ cgen->assembler()-> -address ShenandoahBarrierSetAssembler::generate_shenandoah_wb(StubCodeGenerator* cgen) { +address ShenandoahBarrierSetAssembler::generate_shenandoah_lrb(StubCodeGenerator* cgen) { __ align(CodeEntryAlignment); - StubCodeMark mark(cgen, "StubRoutines", "shenandoah_wb"); + StubCodeMark mark(cgen, "StubRoutines", "shenandoah_lrb"); address start = __ pc(); #ifdef _LP64 @@ -955,7 +875,7 @@ address ShenandoahBarrierSetAssembler::generate_shenandoah_wb(StubCodeGenerator* __ push(r15); save_vector_registers(cgen->assembler()); __ movptr(rdi, rax); - __ call_VM_leaf(CAST_FROM_FN_PTR(address, ShenandoahRuntime::write_barrier_JRT), rdi); + __ call_VM_leaf(CAST_FROM_FN_PTR(address, ShenandoahRuntime::load_reference_barrier_JRT), rdi); restore_vector_registers(cgen->assembler()); __ pop(r15); __ pop(r14); @@ -982,12 +902,12 @@ address ShenandoahBarrierSetAssembler::generate_shenandoah_wb(StubCodeGenerator* #undef __ void ShenandoahBarrierSetAssembler::barrier_stubs_init() { - if (ShenandoahWriteBarrier || ShenandoahStoreValEnqueueBarrier) { + 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_wb = generate_shenandoah_wb(&cgen); + _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 afbd204d7be..c748ce62da1 100644 --- a/src/hotspot/cpu/x86/gc/shenandoah/shenandoahBarrierSetAssembler_x86.hpp +++ b/src/hotspot/cpu/x86/gc/shenandoah/shenandoahBarrierSetAssembler_x86.hpp @@ -29,7 +29,7 @@ #ifdef COMPILER1 class LIR_Assembler; class ShenandoahPreBarrierStub; -class ShenandoahWriteBarrierStub; +class ShenandoahLoadReferenceBarrierStub; class StubAssembler; class StubCodeGenerator; #endif @@ -37,7 +37,7 @@ class StubCodeGenerator; class ShenandoahBarrierSetAssembler: public BarrierSetAssembler { private: - static address _shenandoah_wb; + static address _shenandoah_lrb; void satb_write_barrier_pre(MacroAssembler* masm, Register obj, @@ -55,32 +55,30 @@ private: bool tosca_live, bool expand_call); - void read_barrier(MacroAssembler* masm, Register dst); - void read_barrier_impl(MacroAssembler* masm, Register dst); + void resolve_forward_pointer(MacroAssembler* masm, Register dst); + void resolve_forward_pointer_not_null(MacroAssembler* masm, Register dst); - void read_barrier_not_null(MacroAssembler* masm, Register dst); - void read_barrier_not_null_impl(MacroAssembler* masm, Register dst); - - void write_barrier(MacroAssembler* masm, Register dst); - void write_barrier_impl(MacroAssembler* masm, Register dst); + void load_reference_barrier_not_null(MacroAssembler* masm, Register dst); void storeval_barrier_impl(MacroAssembler* masm, Register dst, Register tmp); - address generate_shenandoah_wb(StubCodeGenerator* cgen); + address generate_shenandoah_lrb(StubCodeGenerator* cgen); void save_vector_registers(MacroAssembler* masm); void restore_vector_registers(MacroAssembler* masm); public: - static address shenandoah_wb(); + 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); - void gen_write_barrier_stub(LIR_Assembler* ce, ShenandoahWriteBarrierStub* stub); + void gen_load_reference_barrier_stub(LIR_Assembler* ce, ShenandoahLoadReferenceBarrierStub* stub); void generate_c1_pre_barrier_runtime_stub(StubAssembler* sasm); #endif + void load_reference_barrier(MacroAssembler* masm, Register dst); + void cmpxchg_oop(MacroAssembler* masm, Register res, Address addr, Register oldval, Register newval, bool exchange, Register tmp1, Register tmp2); @@ -93,16 +91,6 @@ public: virtual void store_at(MacroAssembler* masm, DecoratorSet decorators, BasicType type, Address dst, Register val, Register tmp1, Register tmp2); -#ifndef _LP64 - virtual void obj_equals(MacroAssembler* masm, - Address obj1, jobject obj2); - virtual void obj_equals(MacroAssembler* masm, - Register obj1, jobject obj2); -#endif - - virtual void obj_equals(MacroAssembler* masm, Register src1, Register src2); - virtual void obj_equals(MacroAssembler* masm, Register src1, Address src2); - virtual void tlab_allocate(MacroAssembler* masm, Register thread, Register obj, Register var_size_in_bytes, @@ -110,8 +98,6 @@ public: Register t1, Register t2, Label& slow_case); - virtual void resolve(MacroAssembler* masm, DecoratorSet decorators, Register obj); - virtual void barrier_stubs_init(); }; diff --git a/src/hotspot/cpu/x86/gc/shenandoah/shenandoahBarrierSetC1_x86.cpp b/src/hotspot/cpu/x86/gc/shenandoah/shenandoahBarrierSetC1_x86.cpp index c2a73d2b9a7..38ebe0af106 100644 --- a/src/hotspot/cpu/x86/gc/shenandoah/shenandoahBarrierSetC1_x86.cpp +++ b/src/hotspot/cpu/x86/gc/shenandoah/shenandoahBarrierSetC1_x86.cpp @@ -107,6 +107,7 @@ LIR_Opr ShenandoahBarrierSetC1::atomic_xchg_at_resolved(LIRAccess& access, LIRIt __ xchg(access.resolved_addr(), result, result, LIR_OprFact::illegalOpr); if (access.is_oop()) { + result = load_reference_barrier(access.gen(), result, access.access_emit_info(), true); if (ShenandoahSATBBarrier) { pre_barrier(access.gen(), access.access_emit_info(), access.decorators(), LIR_OprFact::illegalOpr, result /* pre_val */); diff --git a/src/hotspot/cpu/x86/gc/shenandoah/shenandoah_x86_64.ad b/src/hotspot/cpu/x86/gc/shenandoah/shenandoah_x86_64.ad index 40387d0c0d1..90481bcef88 100644 --- a/src/hotspot/cpu/x86/gc/shenandoah/shenandoah_x86_64.ad +++ b/src/hotspot/cpu/x86/gc/shenandoah/shenandoah_x86_64.ad @@ -23,47 +23,7 @@ source_hpp %{ #include "gc/shenandoah/shenandoahBarrierSetAssembler.hpp" -%} - -instruct shenandoahRB(rRegP dst, rRegP src, rFlagsReg cr) %{ - match(Set dst (ShenandoahReadBarrier src)); - effect(DEF dst, USE src); - ins_cost(125); // XXX - format %{ "shenandoah_rb $dst, $src" %} - ins_encode %{ - Register d = $dst$$Register; - Register s = $src$$Register; - __ movptr(d, Address(s, ShenandoahBrooksPointer::byte_offset())); - %} - ins_pipe(ialu_reg_mem); -%} - -instruct shenandoahRBNarrow(rRegP dst, rRegN src) %{ - predicate(UseCompressedOops && (Universe::narrow_oop_shift() == 0)); - match(Set dst (ShenandoahReadBarrier (DecodeN src))); - effect(DEF dst, USE src); - ins_cost(125); // XXX - format %{ "shenandoah_rb $dst, $src" %} - ins_encode %{ - Register d = $dst$$Register; - Register s = $src$$Register; - __ movptr(d, Address(r12, s, Address::times_1, ShenandoahBrooksPointer::byte_offset())); - %} - ins_pipe(ialu_reg_mem); -%} - -instruct shenandoahRBNarrowShift(rRegP dst, rRegN src) %{ - predicate(UseCompressedOops && (Universe::narrow_oop_shift() == Address::times_8)); - match(Set dst (ShenandoahReadBarrier (DecodeN src))); - effect(DEF dst, USE src); - ins_cost(125); // XXX - format %{ "shenandoah_rb $dst, $src" %} - ins_encode %{ - Register d = $dst$$Register; - Register s = $src$$Register; - __ movptr(d, Address(r12, s, Address::times_8, ShenandoahBrooksPointer::byte_offset())); - %} - ins_pipe(ialu_reg_mem); +#include "gc/shenandoah/c2/shenandoahSupport.hpp" %} instruct compareAndSwapP_shenandoah(rRegI res, diff --git a/src/hotspot/share/adlc/formssel.cpp b/src/hotspot/share/adlc/formssel.cpp index 3ddf421e7c3..d4a32b561d8 100644 --- a/src/hotspot/share/adlc/formssel.cpp +++ b/src/hotspot/share/adlc/formssel.cpp @@ -777,8 +777,7 @@ bool InstructForm::captures_bottom_type(FormDict &globals) const { !strcmp(_matrule->_rChild->_opType,"CompareAndExchangeP") || !strcmp(_matrule->_rChild->_opType,"CompareAndExchangeN") || !strcmp(_matrule->_rChild->_opType,"ShenandoahCompareAndExchangeP") || - !strcmp(_matrule->_rChild->_opType,"ShenandoahCompareAndExchangeN") || - !strcmp(_matrule->_rChild->_opType,"ShenandoahReadBarrier"))) return true; + !strcmp(_matrule->_rChild->_opType,"ShenandoahCompareAndExchangeN"))) return true; else if ( is_ideal_load() == Form::idealP ) return true; else if ( is_ideal_store() != Form::none ) return true; @@ -3506,7 +3505,6 @@ int MatchNode::needs_ideal_memory_edge(FormDict &globals) const { "ClearArray", "GetAndSetB", "GetAndSetS", "GetAndAddI", "GetAndSetI", "GetAndSetP", "GetAndAddB", "GetAndAddS", "GetAndAddL", "GetAndSetL", "GetAndSetN", - "ShenandoahReadBarrier", "LoadBarrierSlowReg", "LoadBarrierWeakSlowReg" }; int cnt = sizeof(needs_ideal_memory_list)/sizeof(char*); diff --git a/src/hotspot/share/gc/shenandoah/c1/shenandoahBarrierSetC1.cpp b/src/hotspot/share/gc/shenandoah/c1/shenandoahBarrierSetC1.cpp index 647a2407d67..ed4ee0534c3 100644 --- a/src/hotspot/share/gc/shenandoah/c1/shenandoahBarrierSetC1.cpp +++ b/src/hotspot/share/gc/shenandoah/c1/shenandoahBarrierSetC1.cpp @@ -46,9 +46,9 @@ void ShenandoahPreBarrierStub::emit_code(LIR_Assembler* ce) { bs->gen_pre_barrier_stub(ce, this); } -void ShenandoahWriteBarrierStub::emit_code(LIR_Assembler* ce) { +void ShenandoahLoadReferenceBarrierStub::emit_code(LIR_Assembler* ce) { ShenandoahBarrierSetAssembler* bs = (ShenandoahBarrierSetAssembler*)BarrierSet::barrier_set()->barrier_set_assembler(); - bs->gen_write_barrier_stub(ce, this); + bs->gen_load_reference_barrier_stub(ce, this); } void ShenandoahBarrierSetC1::pre_barrier(LIRGenerator* gen, CodeEmitInfo* info, DecoratorSet decorators, LIR_Opr addr_opr, LIR_Opr pre_val) { @@ -105,40 +105,16 @@ void ShenandoahBarrierSetC1::pre_barrier(LIRGenerator* gen, CodeEmitInfo* info, __ branch_destination(slow->continuation()); } -LIR_Opr ShenandoahBarrierSetC1::read_barrier(LIRGenerator* gen, LIR_Opr obj, CodeEmitInfo* info, bool need_null_check) { - if (UseShenandoahGC && ShenandoahReadBarrier) { - return read_barrier_impl(gen, obj, info, need_null_check); +LIR_Opr ShenandoahBarrierSetC1::load_reference_barrier(LIRGenerator* gen, LIR_Opr obj, CodeEmitInfo* info, bool need_null_check) { + if (ShenandoahLoadRefBarrier) { + return load_reference_barrier_impl(gen, obj, info, need_null_check); } else { return obj; } } -LIR_Opr ShenandoahBarrierSetC1::read_barrier_impl(LIRGenerator* gen, LIR_Opr obj, CodeEmitInfo* info, bool need_null_check) { - assert(UseShenandoahGC && (ShenandoahReadBarrier || ShenandoahStoreValReadBarrier), "Should be enabled"); - LabelObj* done = new LabelObj(); - LIR_Opr result = gen->new_register(T_OBJECT); - __ move(obj, result); - if (need_null_check) { - __ cmp(lir_cond_equal, result, LIR_OprFact::oopConst(NULL)); - __ branch(lir_cond_equal, T_LONG, done->label()); - } - LIR_Address* brooks_ptr_address = gen->generate_address(result, ShenandoahBrooksPointer::byte_offset(), T_ADDRESS); - __ load(brooks_ptr_address, result, info ? new CodeEmitInfo(info) : NULL, lir_patch_none); - - __ branch_destination(done->label()); - return result; -} - -LIR_Opr ShenandoahBarrierSetC1::write_barrier(LIRGenerator* gen, LIR_Opr obj, CodeEmitInfo* info, bool need_null_check) { - if (UseShenandoahGC && ShenandoahWriteBarrier) { - return write_barrier_impl(gen, obj, info, need_null_check); - } else { - return obj; - } -} - -LIR_Opr ShenandoahBarrierSetC1::write_barrier_impl(LIRGenerator* gen, LIR_Opr obj, CodeEmitInfo* info, bool need_null_check) { - assert(UseShenandoahGC && (ShenandoahWriteBarrier || ShenandoahStoreValEnqueueBarrier), "Should be enabled"); +LIR_Opr ShenandoahBarrierSetC1::load_reference_barrier_impl(LIRGenerator* gen, LIR_Opr obj, CodeEmitInfo* info, bool need_null_check) { + assert(ShenandoahLoadRefBarrier, "Should be enabled"); obj = ensure_in_register(gen, obj); assert(obj->is_register(), "must be a register at this point"); @@ -168,7 +144,7 @@ LIR_Opr ShenandoahBarrierSetC1::write_barrier_impl(LIRGenerator* gen, LIR_Opr ob } __ cmp(lir_cond_notEqual, flag_val, LIR_OprFact::intConst(0)); - CodeStub* slow = new ShenandoahWriteBarrierStub(obj, result, info ? new CodeEmitInfo(info) : NULL, need_null_check); + CodeStub* slow = new ShenandoahLoadReferenceBarrierStub(obj, result, info ? new CodeEmitInfo(info) : NULL, need_null_check); __ branch(lir_cond_notEqual, T_INT, slow); __ branch_destination(slow->continuation()); @@ -189,58 +165,13 @@ LIR_Opr ShenandoahBarrierSetC1::ensure_in_register(LIRGenerator* gen, LIR_Opr ob } LIR_Opr ShenandoahBarrierSetC1::storeval_barrier(LIRGenerator* gen, LIR_Opr obj, CodeEmitInfo* info, DecoratorSet decorators) { - bool need_null_check = (decorators & IS_NOT_NULL) == 0; if (ShenandoahStoreValEnqueueBarrier) { - obj = write_barrier_impl(gen, obj, info, need_null_check); + obj = ensure_in_register(gen, obj); pre_barrier(gen, info, decorators, LIR_OprFact::illegalOpr, obj); } - if (ShenandoahStoreValReadBarrier) { - obj = read_barrier_impl(gen, obj, info, true /*need_null_check*/); - } return obj; } -LIR_Opr ShenandoahBarrierSetC1::resolve_address(LIRAccess& access, bool resolve_in_register) { - DecoratorSet decorators = access.decorators(); - bool is_array = (decorators & IS_ARRAY) != 0; - bool needs_patching = (decorators & C1_NEEDS_PATCHING) != 0; - - bool is_write = (decorators & ACCESS_WRITE) != 0; - bool needs_null_check = (decorators & IS_NOT_NULL) == 0; - - LIR_Opr base = access.base().item().result(); - LIR_Opr offset = access.offset().opr(); - LIRGenerator* gen = access.gen(); - - if (is_write) { - base = write_barrier(gen, base, access.access_emit_info(), needs_null_check); - } else { - base = read_barrier(gen, base, access.access_emit_info(), needs_null_check); - } - - LIR_Opr addr_opr; - if (is_array) { - addr_opr = LIR_OprFact::address(gen->emit_array_address(base, offset, access.type())); - } else if (needs_patching) { - // we need to patch the offset in the instruction so don't allow - // generate_address to try to be smart about emitting the -1. - // Otherwise the patching code won't know how to find the - // instruction to patch. - addr_opr = LIR_OprFact::address(new LIR_Address(base, PATCHED_ADDR, access.type())); - } else { - addr_opr = LIR_OprFact::address(gen->generate_address(base, offset, 0, 0, access.type())); - } - - if (resolve_in_register) { - LIR_Opr resolved_addr = gen->new_pointer_register(); - __ leal(addr_opr, resolved_addr); - resolved_addr = LIR_OprFact::address(new LIR_Address(resolved_addr, access.type())); - return resolved_addr; - } else { - return addr_opr; - } -} - void ShenandoahBarrierSetC1::store_at_resolved(LIRAccess& access, LIR_Opr value) { if (access.is_oop()) { if (ShenandoahSATBBarrier) { @@ -252,15 +183,28 @@ void ShenandoahBarrierSetC1::store_at_resolved(LIRAccess& access, LIR_Opr value) } void ShenandoahBarrierSetC1::load_at_resolved(LIRAccess& access, LIR_Opr result) { - BarrierSetC1::load_at_resolved(access, result); + if (!access.is_oop()) { + BarrierSetC1::load_at_resolved(access, result); + return; + } + + LIRGenerator *gen = access.gen(); + + if (ShenandoahLoadRefBarrier) { + LIR_Opr tmp = gen->new_register(T_OBJECT); + BarrierSetC1::load_at_resolved(access, tmp); + tmp = load_reference_barrier(access.gen(), tmp, access.access_emit_info(), true); + __ move(tmp, result); + } else { + BarrierSetC1::load_at_resolved(access, result); + } if (ShenandoahKeepAliveBarrier) { DecoratorSet decorators = access.decorators(); bool is_weak = (decorators & ON_WEAK_OOP_REF) != 0; bool is_phantom = (decorators & ON_PHANTOM_OOP_REF) != 0; bool is_anonymous = (decorators & ON_UNKNOWN_OOP_REF) != 0; - LIRGenerator *gen = access.gen(); - if (access.is_oop() && (is_weak || is_phantom || is_anonymous)) { + if (is_weak || is_phantom || is_anonymous) { // Register the value in the referent field with the pre-barrier LabelObj *Lcont_anonymous; if (is_anonymous) { @@ -276,19 +220,6 @@ void ShenandoahBarrierSetC1::load_at_resolved(LIRAccess& access, LIR_Opr result) } } -LIR_Opr ShenandoahBarrierSetC1::atomic_add_at_resolved(LIRAccess& access, LIRItem& value) { - return BarrierSetC1::atomic_add_at_resolved(access, value); -} - -LIR_Opr ShenandoahBarrierSetC1::resolve(LIRGenerator* gen, DecoratorSet decorators, LIR_Opr obj) { - bool is_write = decorators & ACCESS_WRITE; - if (is_write) { - return write_barrier(gen, obj, NULL, (decorators & IS_NOT_NULL) == 0); - } else { - return read_barrier(gen, obj, NULL, (decorators & IS_NOT_NULL) == 0); - } -} - class C1ShenandoahPreBarrierCodeGenClosure : public StubAssemblerCodeGenClosure { virtual OopMapSet* generate_code(StubAssembler* sasm) { ShenandoahBarrierSetAssembler* bs = (ShenandoahBarrierSetAssembler*)BarrierSet::barrier_set()->barrier_set_assembler(); diff --git a/src/hotspot/share/gc/shenandoah/c1/shenandoahBarrierSetC1.hpp b/src/hotspot/share/gc/shenandoah/c1/shenandoahBarrierSetC1.hpp index 73e673466ae..dde6910a80d 100644 --- a/src/hotspot/share/gc/shenandoah/c1/shenandoahBarrierSetC1.hpp +++ b/src/hotspot/share/gc/shenandoah/c1/shenandoahBarrierSetC1.hpp @@ -85,7 +85,7 @@ public: #endif // PRODUCT }; -class ShenandoahWriteBarrierStub: public CodeStub { +class ShenandoahLoadReferenceBarrierStub: public CodeStub { friend class ShenandoahBarrierSetC1; private: LIR_Opr _obj; @@ -94,7 +94,7 @@ private: bool _needs_null_check; public: - ShenandoahWriteBarrierStub(LIR_Opr obj, LIR_Opr result, CodeEmitInfo* info, bool needs_null_check) : + ShenandoahLoadReferenceBarrierStub(LIR_Opr obj, LIR_Opr result, CodeEmitInfo* info, bool needs_null_check) : _obj(obj), _result(result), _info(info), _needs_null_check(needs_null_check) { assert(_obj->is_register(), "should be register"); @@ -113,7 +113,7 @@ public: visitor->do_temp(_result); } #ifndef PRODUCT - virtual void print_name(outputStream* out) const { out->print("ShenandoahWritePreBarrierStub"); } + virtual void print_name(outputStream* out) const { out->print("ShenandoahLoadReferenceBarrierStub"); } #endif // PRODUCT }; @@ -181,12 +181,10 @@ private: void pre_barrier(LIRGenerator* gen, CodeEmitInfo* info, DecoratorSet decorators, LIR_Opr addr_opr, LIR_Opr pre_val); - LIR_Opr read_barrier(LIRGenerator* gen, LIR_Opr obj, CodeEmitInfo* info, bool need_null_check); - LIR_Opr write_barrier(LIRGenerator* gen, LIR_Opr obj, CodeEmitInfo* info, bool need_null_check); + LIR_Opr load_reference_barrier(LIRGenerator* gen, LIR_Opr obj, CodeEmitInfo* info, bool need_null_check); LIR_Opr storeval_barrier(LIRGenerator* gen, LIR_Opr obj, CodeEmitInfo* info, DecoratorSet decorators); - LIR_Opr read_barrier_impl(LIRGenerator* gen, LIR_Opr obj, CodeEmitInfo* info, bool need_null_check); - LIR_Opr write_barrier_impl(LIRGenerator* gen, LIR_Opr obj, CodeEmitInfo* info, bool need_null_check); + LIR_Opr load_reference_barrier_impl(LIRGenerator* gen, LIR_Opr obj, CodeEmitInfo* info, bool need_null_check); LIR_Opr ensure_in_register(LIRGenerator* gen, LIR_Opr obj); @@ -194,7 +192,6 @@ public: CodeBlob* pre_barrier_c1_runtime_code_blob() { return _pre_barrier_c1_runtime_code_blob; } protected: - virtual LIR_Opr resolve_address(LIRAccess& access, bool resolve_in_register); virtual void store_at_resolved(LIRAccess& access, LIR_Opr value); virtual void load_at_resolved(LIRAccess& access, LIR_Opr result); @@ -202,10 +199,8 @@ protected: virtual LIR_Opr atomic_cmpxchg_at_resolved(LIRAccess& access, LIRItem& cmp_value, LIRItem& new_value); virtual LIR_Opr atomic_xchg_at_resolved(LIRAccess& access, LIRItem& value); - virtual LIR_Opr atomic_add_at_resolved(LIRAccess& access, LIRItem& value); public: - virtual LIR_Opr resolve(LIRGenerator* gen, DecoratorSet decorators, LIR_Opr obj); virtual void generate_c1_runtime_stubs(BufferBlob* buffer_blob); }; diff --git a/src/hotspot/share/gc/shenandoah/c2/shenandoahBarrierSetC2.cpp b/src/hotspot/share/gc/shenandoah/c2/shenandoahBarrierSetC2.cpp index 5d27bec4aaf..63756c5dbec 100644 --- a/src/hotspot/share/gc/shenandoah/c2/shenandoahBarrierSetC2.cpp +++ b/src/hotspot/share/gc/shenandoah/c2/shenandoahBarrierSetC2.cpp @@ -43,121 +43,56 @@ ShenandoahBarrierSetC2* ShenandoahBarrierSetC2::bsc2() { } ShenandoahBarrierSetC2State::ShenandoahBarrierSetC2State(Arena* comp_arena) - : _shenandoah_barriers(new (comp_arena) GrowableArray(comp_arena, 8, 0, NULL)) { + : _enqueue_barriers(new (comp_arena) GrowableArray(comp_arena, 8, 0, NULL)), + _load_reference_barriers(new (comp_arena) GrowableArray(comp_arena, 8, 0, NULL)) { } -int ShenandoahBarrierSetC2State::shenandoah_barriers_count() const { - return _shenandoah_barriers->length(); +int ShenandoahBarrierSetC2State::enqueue_barriers_count() const { + return _enqueue_barriers->length(); } -ShenandoahWriteBarrierNode* ShenandoahBarrierSetC2State::shenandoah_barrier(int idx) const { - return _shenandoah_barriers->at(idx); +ShenandoahEnqueueBarrierNode* ShenandoahBarrierSetC2State::enqueue_barrier(int idx) const { + return _enqueue_barriers->at(idx); } -void ShenandoahBarrierSetC2State::add_shenandoah_barrier(ShenandoahWriteBarrierNode * n) { - assert(!_shenandoah_barriers->contains(n), "duplicate entry in barrier list"); - _shenandoah_barriers->append(n); +void ShenandoahBarrierSetC2State::add_enqueue_barrier(ShenandoahEnqueueBarrierNode * n) { + assert(!_enqueue_barriers->contains(n), "duplicate entry in barrier list"); + _enqueue_barriers->append(n); } -void ShenandoahBarrierSetC2State::remove_shenandoah_barrier(ShenandoahWriteBarrierNode * n) { - if (_shenandoah_barriers->contains(n)) { - _shenandoah_barriers->remove(n); +void ShenandoahBarrierSetC2State::remove_enqueue_barrier(ShenandoahEnqueueBarrierNode * n) { + if (_enqueue_barriers->contains(n)) { + _enqueue_barriers->remove(n); } } -#define __ kit-> +int ShenandoahBarrierSetC2State::load_reference_barriers_count() const { + return _load_reference_barriers->length(); +} -Node* ShenandoahBarrierSetC2::shenandoah_read_barrier(GraphKit* kit, Node* obj) const { - if (ShenandoahReadBarrier) { - obj = shenandoah_read_barrier_impl(kit, obj, false, true, true); +ShenandoahLoadReferenceBarrierNode* ShenandoahBarrierSetC2State::load_reference_barrier(int idx) const { + return _load_reference_barriers->at(idx); +} + +void ShenandoahBarrierSetC2State::add_load_reference_barrier(ShenandoahLoadReferenceBarrierNode * n) { + assert(!_load_reference_barriers->contains(n), "duplicate entry in barrier list"); + _load_reference_barriers->append(n); +} + +void ShenandoahBarrierSetC2State::remove_load_reference_barrier(ShenandoahLoadReferenceBarrierNode * n) { + if (_load_reference_barriers->contains(n)) { + _load_reference_barriers->remove(n); } - return obj; } Node* ShenandoahBarrierSetC2::shenandoah_storeval_barrier(GraphKit* kit, Node* obj) const { if (ShenandoahStoreValEnqueueBarrier) { - obj = shenandoah_write_barrier(kit, obj); obj = shenandoah_enqueue_barrier(kit, obj); } - if (ShenandoahStoreValReadBarrier) { - obj = shenandoah_read_barrier_impl(kit, obj, true, false, false); - } return obj; } -Node* ShenandoahBarrierSetC2::shenandoah_read_barrier_impl(GraphKit* kit, Node* obj, bool use_ctrl, bool use_mem, bool allow_fromspace) const { - const Type* obj_type = obj->bottom_type(); - if (obj_type->higher_equal(TypePtr::NULL_PTR)) { - return obj; - } - const TypePtr* adr_type = ShenandoahBarrierNode::brooks_pointer_type(obj_type); - Node* mem = use_mem ? __ memory(adr_type) : __ immutable_memory(); - - if (! ShenandoahBarrierNode::needs_barrier(&__ gvn(), NULL, obj, mem, allow_fromspace)) { - // We know it is null, no barrier needed. - return obj; - } - - if (obj_type->meet(TypePtr::NULL_PTR) == obj_type->remove_speculative()) { - - // We don't know if it's null or not. Need null-check. - enum { _not_null_path = 1, _null_path, PATH_LIMIT }; - RegionNode* region = new RegionNode(PATH_LIMIT); - Node* phi = new PhiNode(region, obj_type); - Node* null_ctrl = __ top(); - Node* not_null_obj = __ null_check_oop(obj, &null_ctrl); - - region->init_req(_null_path, null_ctrl); - phi ->init_req(_null_path, __ zerocon(T_OBJECT)); - - Node* ctrl = use_ctrl ? __ control() : NULL; - ShenandoahReadBarrierNode* rb = new ShenandoahReadBarrierNode(ctrl, mem, not_null_obj, allow_fromspace); - Node* n = __ gvn().transform(rb); - - region->init_req(_not_null_path, __ control()); - phi ->init_req(_not_null_path, n); - - __ set_control(__ gvn().transform(region)); - __ record_for_igvn(region); - return __ gvn().transform(phi); - - } else { - // We know it is not null. Simple barrier is sufficient. - Node* ctrl = use_ctrl ? __ control() : NULL; - ShenandoahReadBarrierNode* rb = new ShenandoahReadBarrierNode(ctrl, mem, obj, allow_fromspace); - Node* n = __ gvn().transform(rb); - __ record_for_igvn(n); - return n; - } -} - -Node* ShenandoahBarrierSetC2::shenandoah_write_barrier_helper(GraphKit* kit, Node* obj, const TypePtr* adr_type) const { - ShenandoahWriteBarrierNode* wb = new ShenandoahWriteBarrierNode(kit->C, kit->control(), kit->memory(adr_type), obj); - Node* n = __ gvn().transform(wb); - if (n == wb) { // New barrier needs memory projection. - Node* proj = __ gvn().transform(new ShenandoahWBMemProjNode(n)); - __ set_memory(proj, adr_type); - } - return n; -} - -Node* ShenandoahBarrierSetC2::shenandoah_write_barrier(GraphKit* kit, Node* obj) const { - if (ShenandoahWriteBarrier) { - obj = shenandoah_write_barrier_impl(kit, obj); - } - return obj; -} - -Node* ShenandoahBarrierSetC2::shenandoah_write_barrier_impl(GraphKit* kit, Node* obj) const { - if (! ShenandoahBarrierNode::needs_barrier(&__ gvn(), NULL, obj, NULL, true)) { - return obj; - } - const Type* obj_type = obj->bottom_type(); - const TypePtr* adr_type = ShenandoahBarrierNode::brooks_pointer_type(obj_type); - Node* n = shenandoah_write_barrier_helper(kit, obj, adr_type); - __ record_for_igvn(n); - return n; -} +#define __ kit-> bool ShenandoahBarrierSetC2::satb_can_remove_pre_barrier(GraphKit* kit, PhaseTransform* phase, Node* adr, BasicType bt, uint adr_idx) const { @@ -304,7 +239,7 @@ void ShenandoahBarrierSetC2::satb_write_barrier_pre(GraphKit* kit, Node* gc_state = __ AddP(no_base, tls, __ ConX(in_bytes(ShenandoahThreadLocalData::gc_state_offset()))); Node* ld = __ load(__ ctrl(), gc_state, TypeInt::BYTE, T_BYTE, Compile::AliasIdxRaw); marking = __ AndI(ld, __ ConI(ShenandoahHeap::MARKING)); - assert(ShenandoahWriteBarrierNode::is_gc_state_load(ld), "Should match the shape"); + assert(ShenandoahBarrierC2Support::is_gc_state_load(ld), "Should match the shape"); // if (!marking) __ if_then(marking, BoolTest::ne, zero, unlikely); { @@ -361,7 +296,7 @@ bool ShenandoahBarrierSetC2::is_shenandoah_wb_pre_call(Node* call) { bool ShenandoahBarrierSetC2::is_shenandoah_wb_call(Node* call) { return call->is_CallLeaf() && - call->as_CallLeaf()->entry_point() == CAST_FROM_FN_PTR(address, ShenandoahRuntime::write_barrier_JRT); + call->as_CallLeaf()->entry_point() == CAST_FROM_FN_PTR(address, ShenandoahRuntime::load_reference_barrier_JRT); } bool ShenandoahBarrierSetC2::is_shenandoah_marking_if(PhaseTransform *phase, Node* n) { @@ -549,88 +484,6 @@ const TypeFunc* ShenandoahBarrierSetC2::shenandoah_write_barrier_Type() { return TypeFunc::make(domain, range); } -void ShenandoahBarrierSetC2::resolve_address(C2Access& access) const { - const TypePtr* adr_type = access.addr().type(); - - if ((access.decorators() & IN_NATIVE) == 0 && (adr_type->isa_instptr() || adr_type->isa_aryptr())) { - int off = adr_type->is_ptr()->offset(); - int base_off = adr_type->isa_instptr() ? instanceOopDesc::base_offset_in_bytes() : - arrayOopDesc::base_offset_in_bytes(adr_type->is_aryptr()->elem()->array_element_basic_type()); - assert(off != Type::OffsetTop, "unexpected offset"); - if (off == Type::OffsetBot || off >= base_off) { - DecoratorSet decorators = access.decorators(); - bool is_write = (decorators & C2_WRITE_ACCESS) != 0; - GraphKit* kit = NULL; - if (access.is_parse_access()) { - C2ParseAccess& parse_access = static_cast(access); - kit = parse_access.kit(); - } - Node* adr = access.addr().node(); - assert(adr->is_AddP(), "unexpected address shape"); - Node* base = adr->in(AddPNode::Base); - - if (is_write) { - if (kit != NULL) { - base = shenandoah_write_barrier(kit, base); - } else { - assert(access.is_opt_access(), "either parse or opt access"); - assert((access.decorators() & C2_ARRAY_COPY) != 0, "can be skipped for clone"); - } - } else { - if (adr_type->isa_instptr()) { - Compile* C = access.gvn().C; - ciField* field = C->alias_type(adr_type)->field(); - - // Insert read barrier for Shenandoah. - if (field != NULL && - ((ShenandoahOptimizeStaticFinals && field->is_static() && field->is_final()) || - (ShenandoahOptimizeInstanceFinals && !field->is_static() && field->is_final()) || - (ShenandoahOptimizeStableFinals && field->is_stable()))) { - // Skip the barrier for special fields - } else { - if (kit != NULL) { - base = shenandoah_read_barrier(kit, base); - } else { - assert(access.is_opt_access(), "either parse or opt access"); - assert((access.decorators() & C2_ARRAY_COPY) != 0, "can be skipped for arraycopy"); - } - } - } else { - if (kit != NULL) { - base = shenandoah_read_barrier(kit, base); - } else { - assert(access.is_opt_access(), "either parse or opt access"); - assert((access.decorators() & C2_ARRAY_COPY) != 0, "can be skipped for arraycopy"); - } - } - } - if (base != adr->in(AddPNode::Base)) { - assert(kit != NULL, "no barrier should have been added"); - - Node* address = adr->in(AddPNode::Address); - - if (address->is_AddP()) { - assert(address->in(AddPNode::Base) == adr->in(AddPNode::Base), "unexpected address shape"); - assert(!address->in(AddPNode::Address)->is_AddP(), "unexpected address shape"); - assert(address->in(AddPNode::Address) == adr->in(AddPNode::Base), "unexpected address shape"); - address = address->clone(); - address->set_req(AddPNode::Base, base); - address->set_req(AddPNode::Address, base); - address = kit->gvn().transform(address); - } else { - assert(address == adr->in(AddPNode::Base), "unexpected address shape"); - address = base; - } - adr = adr->clone(); - adr->set_req(AddPNode::Base, base); - adr->set_req(AddPNode::Address, address); - adr = kit->gvn().transform(adr); - access.addr().set_node(adr); - } - } - } -} - Node* ShenandoahBarrierSetC2::store_at_resolved(C2Access& access, C2AccessValue& val) const { DecoratorSet decorators = access.decorators(); @@ -662,44 +515,8 @@ Node* ShenandoahBarrierSetC2::store_at_resolved(C2Access& access, C2AccessValue& PhaseGVN& gvn = opt_access.gvn(); MergeMemNode* mm = opt_access.mem(); - if (ShenandoahStoreValReadBarrier) { - RegionNode* region = new RegionNode(3); - const Type* v_t = gvn.type(val.node()); - Node* phi = new PhiNode(region, v_t->isa_oopptr() ? v_t->is_oopptr()->cast_to_nonconst() : v_t); - Node* cmp = gvn.transform(new CmpPNode(val.node(), gvn.zerocon(T_OBJECT))); - Node* bol = gvn.transform(new BoolNode(cmp, BoolTest::ne)); - IfNode* iff = new IfNode(opt_access.ctl(), bol, PROB_LIKELY_MAG(3), COUNT_UNKNOWN); - - gvn.transform(iff); - if (gvn.is_IterGVN()) { - gvn.is_IterGVN()->_worklist.push(iff); - } else { - gvn.record_for_igvn(iff); - } - - Node* null_true = gvn.transform(new IfFalseNode(iff)); - Node* null_false = gvn.transform(new IfTrueNode(iff)); - region->init_req(1, null_true); - region->init_req(2, null_false); - phi->init_req(1, gvn.zerocon(T_OBJECT)); - Node* cast = new CastPPNode(val.node(), gvn.type(val.node())->join_speculative(TypePtr::NOTNULL)); - cast->set_req(0, null_false); - cast = gvn.transform(cast); - Node* rb = gvn.transform(new ShenandoahReadBarrierNode(null_false, gvn.C->immutable_memory(), cast, false)); - phi->init_req(2, rb); - opt_access.set_ctl(gvn.transform(region)); - val.set_node(gvn.transform(phi)); - } if (ShenandoahStoreValEnqueueBarrier) { - const TypePtr* adr_type = ShenandoahBarrierNode::brooks_pointer_type(gvn.type(val.node())); - int alias = gvn.C->get_alias_index(adr_type); - Node* wb = new ShenandoahWriteBarrierNode(gvn.C, opt_access.ctl(), mm->memory_at(alias), val.node()); - Node* wb_transformed = gvn.transform(wb); - Node* enqueue = gvn.transform(new ShenandoahEnqueueBarrierNode(wb_transformed)); - if (wb_transformed == wb) { - Node* proj = gvn.transform(new ShenandoahWBMemProjNode(wb)); - mm->set_memory_at(alias, proj); - } + Node* enqueue = gvn.transform(new ShenandoahEnqueueBarrierNode(val.node())); val.set_node(enqueue); } } @@ -724,6 +541,17 @@ Node* ShenandoahBarrierSetC2::load_at_resolved(C2Access& access, const Type* val Node* offset = adr->is_AddP() ? adr->in(AddPNode::Offset) : top; Node* load = BarrierSetC2::load_at_resolved(access, val_type); + if (access.is_oop()) { + if (ShenandoahLoadRefBarrier) { + load = new ShenandoahLoadReferenceBarrierNode(NULL, load); + if (access.is_parse_access()) { + load = static_cast(access).kit()->gvn().transform(load); + } else { + load = static_cast(access).gvn().transform(load); + } + } + } + // If we are reading the value of the referent field of a Reference // object (either by using Unsafe directly or through reflection) // then, if SATB is enabled, we need to record the referent in an @@ -797,9 +625,10 @@ Node* ShenandoahBarrierSetC2::atomic_cmpxchg_val_at_resolved(C2AtomicParseAccess #ifdef _LP64 if (adr->bottom_type()->is_ptr_to_narrowoop()) { - return kit->gvn().transform(new DecodeNNode(load_store, load_store->get_ptr_type())); + load_store = kit->gvn().transform(new DecodeNNode(load_store, load_store->get_ptr_type())); } #endif + load_store = kit->gvn().transform(new ShenandoahLoadReferenceBarrierNode(NULL, load_store)); return load_store; } return BarrierSetC2::atomic_cmpxchg_val_at_resolved(access, expected_val, new_val, value_type); @@ -867,6 +696,7 @@ Node* ShenandoahBarrierSetC2::atomic_xchg_at_resolved(C2AtomicParseAccess& acces } Node* result = BarrierSetC2::atomic_xchg_at_resolved(access, val, value_type); if (access.is_oop()) { + result = kit->gvn().transform(new ShenandoahLoadReferenceBarrierNode(NULL, result)); shenandoah_write_barrier_pre(kit, false /* do_load */, NULL, NULL, max_juint, NULL, NULL, result /* pre_val */, T_OBJECT); @@ -876,19 +706,9 @@ Node* ShenandoahBarrierSetC2::atomic_xchg_at_resolved(C2AtomicParseAccess& acces void ShenandoahBarrierSetC2::clone(GraphKit* kit, Node* src, Node* dst, Node* size, bool is_array) const { assert(!src->is_AddP(), "unexpected input"); - src = shenandoah_read_barrier(kit, src); BarrierSetC2::clone(kit, src, dst, size, is_array); } -Node* ShenandoahBarrierSetC2::resolve(GraphKit* kit, Node* n, DecoratorSet decorators) const { - bool is_write = decorators & ACCESS_WRITE; - if (is_write) { - return shenandoah_write_barrier(kit, n); - } else { - return shenandoah_read_barrier(kit, n); - } -} - Node* ShenandoahBarrierSetC2::obj_allocate(PhaseMacroExpand* macro, Node* ctrl, Node* mem, Node* toobig_false, Node* size_in_bytes, Node*& i_o, Node*& needgc_ctrl, Node*& fast_oop_ctrl, Node*& fast_oop_rawmem, @@ -915,6 +735,7 @@ Node* ShenandoahBarrierSetC2::obj_allocate(PhaseMacroExpand* macro, Node* ctrl, // Support for GC barriers emitted during parsing bool ShenandoahBarrierSetC2::is_gc_barrier_node(Node* node) const { + if (node->Opcode() == Op_ShenandoahLoadReferenceBarrier) return true; if (node->Opcode() != Op_CallLeaf && node->Opcode() != Op_CallLeafNoFP) { return false; } @@ -929,26 +750,30 @@ bool ShenandoahBarrierSetC2::is_gc_barrier_node(Node* node) const { } Node* ShenandoahBarrierSetC2::step_over_gc_barrier(Node* c) const { - return ShenandoahBarrierNode::skip_through_barrier(c); + if (c->Opcode() == Op_ShenandoahLoadReferenceBarrier) { + return c->in(ShenandoahLoadReferenceBarrierNode::ValueIn); + } + if (c->Opcode() == Op_ShenandoahEnqueueBarrier) { + c = c->in(1); + } + return c; } bool ShenandoahBarrierSetC2::expand_barriers(Compile* C, PhaseIterGVN& igvn) const { - return !ShenandoahWriteBarrierNode::expand(C, igvn); + return !ShenandoahBarrierC2Support::expand(C, igvn); } bool ShenandoahBarrierSetC2::optimize_loops(PhaseIdealLoop* phase, LoopOptsMode mode, VectorSet& visited, Node_Stack& nstack, Node_List& worklist) const { if (mode == LoopOptsShenandoahExpand) { assert(UseShenandoahGC, "only for shenandoah"); - ShenandoahWriteBarrierNode::pin_and_expand(phase); + ShenandoahBarrierC2Support::pin_and_expand(phase); return true; } else if (mode == LoopOptsShenandoahPostExpand) { assert(UseShenandoahGC, "only for shenandoah"); visited.Clear(); - ShenandoahWriteBarrierNode::optimize_after_expansion(visited, nstack, worklist, phase); + ShenandoahBarrierC2Support::optimize_after_expansion(visited, nstack, worklist, phase); return true; } - GrowableArray memory_graph_fixers; - ShenandoahWriteBarrierNode::optimize_before_expansion(phase, memory_graph_fixers, false); return false; } @@ -957,7 +782,6 @@ bool ShenandoahBarrierSetC2::array_copy_requires_gc_barriers(bool tightly_couple if (!is_oop) { return false; } - if (tightly_coupled_alloc) { if (phase == Optimization) { return false; @@ -985,7 +809,7 @@ bool ShenandoahBarrierSetC2::clone_needs_postbarrier(ArrayCopyNode *ac, PhaseIte } } else { return true; - } + } } else if (src_type->isa_aryptr()) { BasicType src_elem = src_type->klass()->as_array_klass()->element_type()->basic_type(); if (src_elem == T_OBJECT || src_elem == T_ARRAY) { @@ -1038,14 +862,20 @@ void ShenandoahBarrierSetC2::clone_barrier_at_expansion(ArrayCopyNode* ac, Node* // Support for macro expanded GC barriers void ShenandoahBarrierSetC2::register_potential_barrier_node(Node* node) const { - if (node->Opcode() == Op_ShenandoahWriteBarrier) { - state()->add_shenandoah_barrier((ShenandoahWriteBarrierNode*) node); + if (node->Opcode() == Op_ShenandoahEnqueueBarrier) { + state()->add_enqueue_barrier((ShenandoahEnqueueBarrierNode*) node); + } + if (node->Opcode() == Op_ShenandoahLoadReferenceBarrier) { + state()->add_load_reference_barrier((ShenandoahLoadReferenceBarrierNode*) node); } } void ShenandoahBarrierSetC2::unregister_potential_barrier_node(Node* node) const { - if (node->Opcode() == Op_ShenandoahWriteBarrier) { - state()->remove_shenandoah_barrier((ShenandoahWriteBarrierNode*) node); + if (node->Opcode() == Op_ShenandoahEnqueueBarrier) { + state()->remove_enqueue_barrier((ShenandoahEnqueueBarrierNode*) node); + } + if (node->Opcode() == Op_ShenandoahLoadReferenceBarrier) { + state()->remove_load_reference_barrier((ShenandoahLoadReferenceBarrierNode*) node); } } @@ -1091,19 +921,18 @@ void ShenandoahBarrierSetC2::eliminate_useless_gc_barriers(Unique_Node_List &use } } } - for (int i = state()->shenandoah_barriers_count()-1; i >= 0; i--) { - ShenandoahWriteBarrierNode* n = state()->shenandoah_barrier(i); + for (int i = state()->enqueue_barriers_count() - 1; i >= 0; i--) { + ShenandoahEnqueueBarrierNode* n = state()->enqueue_barrier(i); if (!useful.member(n)) { - state()->remove_shenandoah_barrier(n); + state()->remove_enqueue_barrier(n); + } + } + for (int i = state()->load_reference_barriers_count() - 1; i >= 0; i--) { + ShenandoahLoadReferenceBarrierNode* n = state()->load_reference_barrier(i); + if (!useful.member(n)) { + state()->remove_load_reference_barrier(n); } } - -} - -bool ShenandoahBarrierSetC2::has_special_unique_user(const Node* node) const { - assert(node->outcnt() == 1, "match only for unique out"); - Node* n = node->unique_out(); - return node->Opcode() == Op_ShenandoahWriteBarrier && n->Opcode() == Op_ShenandoahWBMemProj; } void ShenandoahBarrierSetC2::add_users_to_worklist(Unique_Node_List* worklist) const {} @@ -1123,7 +952,7 @@ bool ShenandoahBarrierSetC2::expand_macro_nodes(PhaseMacroExpand* macro) const { #ifdef ASSERT void ShenandoahBarrierSetC2::verify_gc_barriers(Compile* compile, CompilePhase phase) const { if (ShenandoahVerifyOptoBarriers && phase == BarrierSetC2::BeforeExpand) { - ShenandoahBarrierNode::verify(Compile::current()->root()); + ShenandoahBarrierC2Support::verify(Compile::current()->root()); } else if (phase == BarrierSetC2::BeforeCodeGen) { // Verify G1 pre-barriers const int marking_offset = in_bytes(ShenandoahThreadLocalData::satb_mark_queue_active_offset()); @@ -1229,7 +1058,7 @@ Node* ShenandoahBarrierSetC2::ideal_node(PhaseGVN* phase, Node* n, bool can_resh } } else if (can_reshape && n->Opcode() == Op_If && - ShenandoahWriteBarrierNode::is_heap_stable_test(n) && + ShenandoahBarrierC2Support::is_heap_stable_test(n) && n->in(0) != NULL) { Node* dom = n->in(0); Node* prev_dom = n; @@ -1237,7 +1066,7 @@ Node* ShenandoahBarrierSetC2::ideal_node(PhaseGVN* phase, Node* n, bool can_resh int dist = 16; // Search up the dominator tree for another heap stable test while (dom->Opcode() != op || // Not same opcode? - !ShenandoahWriteBarrierNode::is_heap_stable_test(dom) || // Not same input 1? + !ShenandoahBarrierC2Support::is_heap_stable_test(dom) || // Not same input 1? prev_dom->in(0) != dom) { // One path of test does not dominate? if (dist < 0) return NULL; @@ -1258,46 +1087,6 @@ Node* ShenandoahBarrierSetC2::ideal_node(PhaseGVN* phase, Node* n, bool can_resh return NULL; } -Node* ShenandoahBarrierSetC2::identity_node(PhaseGVN* phase, Node* n) const { - if (n->is_Load()) { - Node *mem = n->in(MemNode::Memory); - Node *value = n->as_Load()->can_see_stored_value(mem, phase); - if (value) { - PhaseIterGVN *igvn = phase->is_IterGVN(); - if (igvn != NULL && - value->is_Phi() && - value->req() > 2 && - value->in(1) != NULL && - value->in(1)->is_ShenandoahBarrier()) { - if (igvn->_worklist.member(value) || - igvn->_worklist.member(value->in(0)) || - (value->in(0)->in(1) != NULL && - value->in(0)->in(1)->is_IfProj() && - (igvn->_worklist.member(value->in(0)->in(1)) || - (value->in(0)->in(1)->in(0) != NULL && - igvn->_worklist.member(value->in(0)->in(1)->in(0)))))) { - igvn->_worklist.push(n); - return n; - } - } - // (This works even when value is a Con, but LoadNode::Value - // usually runs first, producing the singleton type of the Con.) - Node *value_no_barrier = step_over_gc_barrier(value->Opcode() == Op_EncodeP ? value->in(1) : value); - if (value->Opcode() == Op_EncodeP) { - if (value_no_barrier != value->in(1)) { - Node *encode = value->clone(); - encode->set_req(1, value_no_barrier); - encode = phase->transform(encode); - return encode; - } - } else { - return value_no_barrier; - } - } - } - return n; -} - bool ShenandoahBarrierSetC2::has_only_shenandoah_wb_pre_uses(Node* n) { for (DUIterator_Fast imax, i = n->fast_outs(imax); i < imax; i++) { Node* u = n->fast_out(i); @@ -1308,20 +1097,6 @@ bool ShenandoahBarrierSetC2::has_only_shenandoah_wb_pre_uses(Node* n) { return n->outcnt() > 0; } -bool ShenandoahBarrierSetC2::flatten_gc_alias_type(const TypePtr*& adr_type) const { - int offset = adr_type->offset(); - if (offset == ShenandoahBrooksPointer::byte_offset()) { - if (adr_type->isa_aryptr()) { - adr_type = TypeAryPtr::make(adr_type->ptr(), adr_type->isa_aryptr()->ary(), adr_type->isa_aryptr()->klass(), false, offset); - } else if (adr_type->isa_instptr()) { - adr_type = TypeInstPtr::make(adr_type->ptr(), ciEnv::current()->Object_klass(), false, NULL, offset); - } - return true; - } else { - return false; - } -} - bool ShenandoahBarrierSetC2::final_graph_reshaping(Compile* compile, Node* n, uint opcode) const { switch (opcode) { case Op_CallLeaf: @@ -1356,9 +1131,7 @@ bool ShenandoahBarrierSetC2::final_graph_reshaping(Compile* compile, Node* n, ui } #endif return true; - case Op_ShenandoahReadBarrier: - return true; - case Op_ShenandoahWriteBarrier: + case Op_ShenandoahLoadReferenceBarrier: assert(false, "should have been expanded already"); return true; default: @@ -1366,17 +1139,6 @@ bool ShenandoahBarrierSetC2::final_graph_reshaping(Compile* compile, Node* n, ui } } -#ifdef ASSERT -bool ShenandoahBarrierSetC2::verify_gc_alias_type(const TypePtr* adr_type, int offset) const { - if (offset == ShenandoahBrooksPointer::byte_offset() && - (adr_type->base() == Type::AryPtr || adr_type->base() == Type::OopPtr)) { - return true; - } else { - return false; - } -} -#endif - bool ShenandoahBarrierSetC2::escape_add_to_con_graph(ConnectionGraph* conn_graph, PhaseGVN* gvn, Unique_Node_List* delayed_worklist, Node* n, uint opcode) const { switch (opcode) { case Op_ShenandoahCompareAndExchangeP: @@ -1412,15 +1174,12 @@ bool ShenandoahBarrierSetC2::escape_add_to_con_graph(ConnectionGraph* conn_graph } return false; } - case Op_ShenandoahReadBarrier: - case Op_ShenandoahWriteBarrier: - // Barriers 'pass through' its arguments. I.e. what goes in, comes out. - // It doesn't escape. - conn_graph->add_local_var_and_edge(n, PointsToNode::NoEscape, n->in(ShenandoahBarrierNode::ValueIn), delayed_worklist); - break; case Op_ShenandoahEnqueueBarrier: conn_graph->add_local_var_and_edge(n, PointsToNode::NoEscape, n->in(1), delayed_worklist); break; + case Op_ShenandoahLoadReferenceBarrier: + conn_graph->add_local_var_and_edge(n, PointsToNode::NoEscape, n->in(ShenandoahLoadReferenceBarrierNode::ValueIn), delayed_worklist); + return true; default: // Nothing break; @@ -1441,15 +1200,12 @@ bool ShenandoahBarrierSetC2::escape_add_final_edges(ConnectionGraph* conn_graph, case Op_ShenandoahWeakCompareAndSwapP: case Op_ShenandoahWeakCompareAndSwapN: return conn_graph->add_final_edges_unsafe_access(n, opcode); - case Op_ShenandoahReadBarrier: - case Op_ShenandoahWriteBarrier: - // Barriers 'pass through' its arguments. I.e. what goes in, comes out. - // It doesn't escape. - conn_graph->add_local_var_and_edge(n, PointsToNode::NoEscape, n->in(ShenandoahBarrierNode::ValueIn), NULL); - return true; case Op_ShenandoahEnqueueBarrier: conn_graph->add_local_var_and_edge(n, PointsToNode::NoEscape, n->in(1), NULL); return true; + case Op_ShenandoahLoadReferenceBarrier: + conn_graph->add_local_var_and_edge(n, PointsToNode::NoEscape, n->in(ShenandoahLoadReferenceBarrierNode::ValueIn), NULL); + return true; default: // Nothing break; @@ -1464,21 +1220,7 @@ bool ShenandoahBarrierSetC2::escape_has_out_with_unsafe_object(Node* n) const { } bool ShenandoahBarrierSetC2::escape_is_barrier_node(Node* n) const { - return n->is_ShenandoahBarrier(); -} - -bool ShenandoahBarrierSetC2::matcher_find_shared_visit(Matcher* matcher, Matcher::MStack& mstack, Node* n, uint opcode, bool& mem_op, int& mem_addr_idx) const { - switch (opcode) { - case Op_ShenandoahReadBarrier: - if (n->in(ShenandoahBarrierNode::ValueIn)->is_DecodeNarrowPtr()) { - matcher->set_shared(n->in(ShenandoahBarrierNode::ValueIn)->in(1)); - } - matcher->set_shared(n); - return true; - default: - break; - } - return false; + return n->Opcode() == Op_ShenandoahLoadReferenceBarrier; } bool ShenandoahBarrierSetC2::matcher_find_shared_post_visit(Matcher* matcher, Node* n, uint opcode) const { @@ -1510,62 +1252,3 @@ bool ShenandoahBarrierSetC2::matcher_is_store_load_barrier(Node* x, uint xop) co xop == Op_ShenandoahCompareAndSwapN || xop == Op_ShenandoahCompareAndSwapP; } - -void ShenandoahBarrierSetC2::igvn_add_users_to_worklist(PhaseIterGVN* igvn, Node* use) const { - if (use->is_ShenandoahBarrier()) { - for (DUIterator_Fast i2max, i2 = use->fast_outs(i2max); i2 < i2max; i2++) { - Node* u = use->fast_out(i2); - Node* cmp = use->find_out_with(Op_CmpP); - if (u->Opcode() == Op_CmpP) { - igvn->_worklist.push(cmp); - } - } - } -} - -void ShenandoahBarrierSetC2::ccp_analyze(PhaseCCP* ccp, Unique_Node_List& worklist, Node* use) const { - if (use->is_ShenandoahBarrier()) { - for (DUIterator_Fast i2max, i2 = use->fast_outs(i2max); i2 < i2max; i2++) { - Node* p = use->fast_out(i2); - if (p->Opcode() == Op_AddP) { - for (DUIterator_Fast i3max, i3 = p->fast_outs(i3max); i3 < i3max; i3++) { - Node* q = p->fast_out(i3); - if (q->is_Load()) { - if(q->bottom_type() != ccp->type(q)) { - worklist.push(q); - } - } - } - } - } - } -} - -Node* ShenandoahBarrierSetC2::split_if_pre(PhaseIdealLoop* phase, Node* n) const { - if (n->Opcode() == Op_ShenandoahReadBarrier) { - ((ShenandoahReadBarrierNode*)n)->try_move(phase); - } else if (n->Opcode() == Op_ShenandoahWriteBarrier) { - return ((ShenandoahWriteBarrierNode*)n)->try_split_thru_phi(phase); - } - - return NULL; -} - -bool ShenandoahBarrierSetC2::build_loop_late_post(PhaseIdealLoop* phase, Node* n) const { - return ShenandoahBarrierNode::build_loop_late_post(phase, n); -} - -bool ShenandoahBarrierSetC2::sink_node(PhaseIdealLoop* phase, Node* n, Node* x, Node* x_ctrl, Node* n_ctrl) const { - if (n->is_ShenandoahBarrier()) { - return x->as_ShenandoahBarrier()->sink_node(phase, x_ctrl, n_ctrl); - } - if (n->is_MergeMem()) { - // PhaseIdealLoop::split_if_with_blocks_post() would: - // _igvn._worklist.yank(x); - // which sometimes causes chains of MergeMem which some of - // shenandoah specific code doesn't support - phase->register_new_node(x, x_ctrl); - return true; - } - return false; -} diff --git a/src/hotspot/share/gc/shenandoah/c2/shenandoahBarrierSetC2.hpp b/src/hotspot/share/gc/shenandoah/c2/shenandoahBarrierSetC2.hpp index b2ed04dc43c..aee5687c1aa 100644 --- a/src/hotspot/share/gc/shenandoah/c2/shenandoahBarrierSetC2.hpp +++ b/src/hotspot/share/gc/shenandoah/c2/shenandoahBarrierSetC2.hpp @@ -30,14 +30,21 @@ class ShenandoahBarrierSetC2State : public ResourceObj { private: - GrowableArray* _shenandoah_barriers; + GrowableArray* _enqueue_barriers; + GrowableArray* _load_reference_barriers; public: ShenandoahBarrierSetC2State(Arena* comp_arena); - int shenandoah_barriers_count() const; - ShenandoahWriteBarrierNode* shenandoah_barrier(int idx) const; - void add_shenandoah_barrier(ShenandoahWriteBarrierNode * n); - void remove_shenandoah_barrier(ShenandoahWriteBarrierNode * n); + + int enqueue_barriers_count() const; + ShenandoahEnqueueBarrierNode* enqueue_barrier(int idx) const; + void add_enqueue_barrier(ShenandoahEnqueueBarrierNode* n); + void remove_enqueue_barrier(ShenandoahEnqueueBarrierNode * n); + + int load_reference_barriers_count() const; + ShenandoahLoadReferenceBarrierNode* load_reference_barrier(int idx) const; + void add_load_reference_barrier(ShenandoahLoadReferenceBarrierNode* n); + void remove_load_reference_barrier(ShenandoahLoadReferenceBarrierNode * n); }; class ShenandoahBarrierSetC2 : public BarrierSetC2 { @@ -66,12 +73,7 @@ private: BasicType bt) const; Node* shenandoah_enqueue_barrier(GraphKit* kit, Node* val) const; - Node* shenandoah_read_barrier(GraphKit* kit, Node* obj) const; Node* shenandoah_storeval_barrier(GraphKit* kit, Node* obj) const; - Node* shenandoah_write_barrier(GraphKit* kit, Node* obj) const; - Node* shenandoah_read_barrier_impl(GraphKit* kit, Node* obj, bool use_ctrl, bool use_mem, bool allow_fromspace) const; - Node* shenandoah_write_barrier_impl(GraphKit* kit, Node* obj) const; - Node* shenandoah_write_barrier_helper(GraphKit* kit, Node* obj, const TypePtr* adr_type) const; void insert_pre_barrier(GraphKit* kit, Node* base_oop, Node* offset, Node* pre_val, bool need_mem_bar) const; @@ -79,7 +81,6 @@ private: static bool clone_needs_postbarrier(ArrayCopyNode *ac, PhaseIterGVN& igvn); protected: - virtual void resolve_address(C2Access& access) const; virtual Node* load_at_resolved(C2Access& access, const Type* val_type) const; virtual Node* store_at_resolved(C2Access& access, C2AccessValue& val) const; virtual Node* atomic_cmpxchg_val_at_resolved(C2AtomicParseAccess& access, Node* expected_val, @@ -102,12 +103,11 @@ public: static const TypeFunc* write_ref_field_pre_entry_Type(); static const TypeFunc* shenandoah_clone_barrier_Type(); static const TypeFunc* shenandoah_write_barrier_Type(); + virtual bool has_load_barriers() const { return true; } // This is the entry-point for the backend to perform accesses through the Access API. virtual void clone(GraphKit* kit, Node* src, Node* dst, Node* size, bool is_array) const; - virtual Node* resolve(GraphKit* kit, Node* n, DecoratorSet decorators) const; - virtual Node* obj_allocate(PhaseMacroExpand* macro, Node* ctrl, Node* mem, Node* toobig_false, Node* size_in_bytes, Node*& i_o, Node*& needgc_ctrl, Node*& fast_oop_ctrl, Node*& fast_oop_rawmem, @@ -144,13 +144,7 @@ public: virtual void verify_gc_barriers(Compile* compile, CompilePhase phase) const; #endif - virtual bool flatten_gc_alias_type(const TypePtr*& adr_type) const; -#ifdef ASSERT - virtual bool verify_gc_alias_type(const TypePtr* adr_type, int offset) const; -#endif - virtual Node* ideal_node(PhaseGVN* phase, Node* n, bool can_reshape) const; - virtual Node* identity_node(PhaseGVN* phase, Node* n) const; virtual bool final_graph_reshaping(Compile* compile, Node* n, uint opcode) const; virtual bool escape_add_to_con_graph(ConnectionGraph* conn_graph, PhaseGVN* gvn, Unique_Node_List* delayed_worklist, Node* n, uint opcode) const; @@ -158,17 +152,8 @@ public: virtual bool escape_has_out_with_unsafe_object(Node* n) const; virtual bool escape_is_barrier_node(Node* n) const; - virtual bool matcher_find_shared_visit(Matcher* matcher, Matcher::MStack& mstack, Node* n, uint opcode, bool& mem_op, int& mem_addr_idx) const; virtual bool matcher_find_shared_post_visit(Matcher* matcher, Node* n, uint opcode) const; virtual bool matcher_is_store_load_barrier(Node* x, uint xop) const; - - virtual void igvn_add_users_to_worklist(PhaseIterGVN* igvn, Node* use) const; - virtual void ccp_analyze(PhaseCCP* ccp, Unique_Node_List& worklist, Node* use) const; - - virtual bool has_special_unique_user(const Node* node) const; - virtual Node* split_if_pre(PhaseIdealLoop* phase, Node* n) const; - virtual bool build_loop_late_post(PhaseIdealLoop* phase, Node* n) const; - virtual bool sink_node(PhaseIdealLoop* phase, Node* n, Node* x, Node* x_ctrl, Node* n_ctrl) const; }; #endif // SHARE_GC_SHENANDOAH_C2_SHENANDOAHBARRIERSETC2_HPP diff --git a/src/hotspot/share/gc/shenandoah/c2/shenandoahSupport.cpp b/src/hotspot/share/gc/shenandoah/c2/shenandoahSupport.cpp index 709209859bf..a92b1726f5e 100644 --- a/src/hotspot/share/gc/shenandoah/c2/shenandoahSupport.cpp +++ b/src/hotspot/share/gc/shenandoah/c2/shenandoahSupport.cpp @@ -41,383 +41,28 @@ #include "opto/runtime.hpp" #include "opto/subnode.hpp" -Node* ShenandoahBarrierNode::skip_through_barrier(Node* n) { - if (n == NULL) { - return NULL; - } - if (n->Opcode() == Op_ShenandoahEnqueueBarrier) { - n = n->in(1); - } - - if (n->is_ShenandoahBarrier()) { - return n->in(ValueIn); - } else if (n->is_Phi() && - n->req() == 3 && - n->in(1) != NULL && - n->in(1)->is_ShenandoahBarrier() && - n->in(2) != NULL && - n->in(2)->bottom_type() == TypePtr::NULL_PTR && - n->in(0) != NULL && - n->in(0)->in(1) != NULL && - n->in(0)->in(1)->is_IfProj() && - n->in(0)->in(2) != NULL && - n->in(0)->in(2)->is_IfProj() && - n->in(0)->in(1)->in(0) != NULL && - n->in(0)->in(1)->in(0) == n->in(0)->in(2)->in(0) && - n->in(1)->in(ValueIn)->Opcode() == Op_CastPP) { - Node* iff = n->in(0)->in(1)->in(0); - Node* res = n->in(1)->in(ValueIn)->in(1); - if (iff->is_If() && - iff->in(1) != NULL && - iff->in(1)->is_Bool() && - iff->in(1)->as_Bool()->_test._test == BoolTest::ne && - iff->in(1)->in(1) != NULL && - iff->in(1)->in(1)->Opcode() == Op_CmpP && - iff->in(1)->in(1)->in(1) != NULL && - iff->in(1)->in(1)->in(1) == res && - iff->in(1)->in(1)->in(2) != NULL && - iff->in(1)->in(1)->in(2)->bottom_type() == TypePtr::NULL_PTR) { - return res; - } - } - return n; -} - -bool ShenandoahBarrierNode::needs_barrier(PhaseGVN* phase, ShenandoahBarrierNode* orig, Node* n, Node* rb_mem, bool allow_fromspace) { - Unique_Node_List visited; - return needs_barrier_impl(phase, orig, n, rb_mem, allow_fromspace, visited); -} - -bool ShenandoahBarrierNode::needs_barrier_impl(PhaseGVN* phase, ShenandoahBarrierNode* orig, Node* n, Node* rb_mem, bool allow_fromspace, Unique_Node_List &visited) { - if (visited.member(n)) { - return false; // Been there. - } - visited.push(n); - - if (n->is_Allocate()) { - return false; - } - - if (n->is_Call()) { - return true; - } - - const Type* type = phase->type(n); - if (type == Type::TOP) { - return false; - } - if (type->make_ptr()->higher_equal(TypePtr::NULL_PTR)) { - return false; - } - if (type->make_oopptr() && type->make_oopptr()->const_oop() != NULL) { - return false; - } - - if (ShenandoahOptimizeStableFinals) { - const TypeAryPtr* ary = type->isa_aryptr(); - if (ary && ary->is_stable() && allow_fromspace) { - return false; - } - } - - if (n->is_CheckCastPP() || n->is_ConstraintCast() || n->Opcode() == Op_ShenandoahEnqueueBarrier) { - return needs_barrier_impl(phase, orig, n->in(1), rb_mem, allow_fromspace, visited); - } - if (n->is_Parm()) { - return true; - } - if (n->is_Proj()) { - return needs_barrier_impl(phase, orig, n->in(0), rb_mem, allow_fromspace, visited); - } - - if (n->Opcode() == Op_ShenandoahWBMemProj) { - return needs_barrier_impl(phase, orig, n->in(ShenandoahWBMemProjNode::WriteBarrier), rb_mem, allow_fromspace, visited); - } - if (n->is_Phi()) { - bool need_barrier = false; - for (uint i = 1; i < n->req() && ! need_barrier; i++) { - Node* input = n->in(i); - if (input == NULL) { - need_barrier = true; // Phi not complete yet? - } else if (needs_barrier_impl(phase, orig, input, rb_mem, allow_fromspace, visited)) { - need_barrier = true; - } - } - return need_barrier; - } - if (n->is_CMove()) { - return needs_barrier_impl(phase, orig, n->in(CMoveNode::IfFalse), rb_mem, allow_fromspace, visited) || - needs_barrier_impl(phase, orig, n->in(CMoveNode::IfTrue ), rb_mem, allow_fromspace, visited); - } - if (n->Opcode() == Op_CreateEx) { - return true; - } - if (n->Opcode() == Op_ShenandoahWriteBarrier) { - return false; - } - if (n->Opcode() == Op_ShenandoahReadBarrier) { - if (rb_mem == n->in(Memory)) { - return false; - } else { - return true; - } - } - - if (n->Opcode() == Op_LoadP || - n->Opcode() == Op_LoadN || - n->Opcode() == Op_GetAndSetP || - n->Opcode() == Op_CompareAndExchangeP || - n->Opcode() == Op_ShenandoahCompareAndExchangeP || - n->Opcode() == Op_GetAndSetN || - n->Opcode() == Op_CompareAndExchangeN || - n->Opcode() == Op_ShenandoahCompareAndExchangeN) { - return true; - } - if (n->Opcode() == Op_DecodeN || - n->Opcode() == Op_EncodeP) { - return needs_barrier_impl(phase, orig, n->in(1), rb_mem, allow_fromspace, visited); - } - -#ifdef ASSERT - tty->print("need barrier on?: "); n->dump(); - ShouldNotReachHere(); -#endif - return true; -} - -bool ShenandoahReadBarrierNode::dominates_memory_rb_impl(PhaseGVN* phase, - Node* b1, - Node* b2, - Node* current, - bool linear) { - ResourceMark rm; - VectorSet visited(Thread::current()->resource_area()); - Node_Stack phis(0); - - for(int i = 0; i < 10; i++) { - if (current == NULL) { - return false; - } else if (visited.test_set(current->_idx) || current->is_top() || current == b1) { - current = NULL; - while (phis.is_nonempty() && current == NULL) { - uint idx = phis.index(); - Node* phi = phis.node(); - if (idx >= phi->req()) { - phis.pop(); - } else { - current = phi->in(idx); - phis.set_index(idx+1); - } - } - if (current == NULL) { - return true; - } - } else if (current == phase->C->immutable_memory()) { - return false; - } else if (current->isa_Phi()) { - if (!linear) { +bool ShenandoahBarrierC2Support::expand(Compile* C, PhaseIterGVN& igvn) { + ShenandoahBarrierSetC2State* state = ShenandoahBarrierSetC2::bsc2()->state(); + if ((state->enqueue_barriers_count() + + state->load_reference_barriers_count()) > 0) { + bool attempt_more_loopopts = ShenandoahLoopOptsAfterExpansion; + C->clear_major_progress(); + PhaseIdealLoop ideal_loop(igvn, LoopOptsShenandoahExpand); + if (C->failing()) return false; + PhaseIdealLoop::verify(igvn); + DEBUG_ONLY(verify_raw_mem(C->root());) + if (attempt_more_loopopts) { + C->set_major_progress(); + if (!C->optimize_loops(igvn, LoopOptsShenandoahPostExpand)) { return false; } - phis.push(current, 2); - current = current->in(1); - } else if (current->Opcode() == Op_ShenandoahWriteBarrier) { - const Type* in_type = current->bottom_type(); - const Type* this_type = b2->bottom_type(); - if (is_independent(in_type, this_type)) { - current = current->in(Memory); - } else { - return false; - } - } else if (current->Opcode() == Op_ShenandoahWBMemProj) { - current = current->in(ShenandoahWBMemProjNode::WriteBarrier); - } else if (current->is_Proj()) { - current = current->in(0); - } else if (current->is_Call()) { - return false; // TODO: Maybe improve by looking at the call's memory effects? - } else if (current->is_MemBar()) { - return false; // TODO: Do we need to stop at *any* membar? - } else if (current->is_MergeMem()) { - const TypePtr* adr_type = brooks_pointer_type(phase->type(b2)); - uint alias_idx = phase->C->get_alias_index(adr_type); - current = current->as_MergeMem()->memory_at(alias_idx); - } else { -#ifdef ASSERT - current->dump(); -#endif - ShouldNotReachHere(); - return false; - } - } - return false; -} - -bool ShenandoahReadBarrierNode::is_independent(Node* mem) { - if (mem->is_Phi() || mem->is_Proj() || mem->is_MergeMem()) { - return true; - } else if (mem->Opcode() == Op_ShenandoahWBMemProj) { - return true; - } else if (mem->Opcode() == Op_ShenandoahWriteBarrier) { - const Type* mem_type = mem->bottom_type(); - const Type* this_type = bottom_type(); - if (is_independent(mem_type, this_type)) { - return true; - } else { - return false; - } - } else if (mem->is_Call() || mem->is_MemBar()) { - return false; - } -#ifdef ASSERT - mem->dump(); -#endif - ShouldNotReachHere(); - return true; -} - -bool ShenandoahReadBarrierNode::dominates_memory_rb(PhaseGVN* phase, Node* b1, Node* b2, bool linear) { - return dominates_memory_rb_impl(phase, b1->in(Memory), b2, b2->in(Memory), linear); -} - -bool ShenandoahReadBarrierNode::is_independent(const Type* in_type, const Type* this_type) { - assert(in_type->isa_oopptr(), "expect oop ptr"); - assert(this_type->isa_oopptr(), "expect oop ptr"); - - ciKlass* in_kls = in_type->is_oopptr()->klass(); - ciKlass* this_kls = this_type->is_oopptr()->klass(); - if (in_kls != NULL && this_kls != NULL && - in_kls->is_loaded() && this_kls->is_loaded() && - (!in_kls->is_subclass_of(this_kls)) && - (!this_kls->is_subclass_of(in_kls))) { - return true; - } - return false; -} - -Node* ShenandoahReadBarrierNode::Ideal(PhaseGVN *phase, bool can_reshape) { - if (! can_reshape) { - return NULL; - } - - if (in(Memory) == phase->C->immutable_memory()) return NULL; - - // If memory input is a MergeMem, take the appropriate slice out of it. - Node* mem_in = in(Memory); - if (mem_in->isa_MergeMem()) { - const TypePtr* adr_type = brooks_pointer_type(bottom_type()); - uint alias_idx = phase->C->get_alias_index(adr_type); - mem_in = mem_in->as_MergeMem()->memory_at(alias_idx); - set_req(Memory, mem_in); - return this; - } - - Node* input = in(Memory); - if (input->Opcode() == Op_ShenandoahWBMemProj) { - ResourceMark rm; - VectorSet seen(Thread::current()->resource_area()); - Node* n = in(Memory); - while (n->Opcode() == Op_ShenandoahWBMemProj && - n->in(ShenandoahWBMemProjNode::WriteBarrier) != NULL && - n->in(ShenandoahWBMemProjNode::WriteBarrier)->Opcode() == Op_ShenandoahWriteBarrier && - n->in(ShenandoahWBMemProjNode::WriteBarrier)->in(Memory) != NULL) { - if (seen.test_set(n->_idx)) { - return NULL; // loop - } - n = n->in(ShenandoahWBMemProjNode::WriteBarrier)->in(Memory); - } - - Node* wb = input->in(ShenandoahWBMemProjNode::WriteBarrier); - const Type* in_type = phase->type(wb); - // is_top() test not sufficient here: we can come here after CCP - // in a dead branch of the graph that has not yet been removed. - if (in_type == Type::TOP) return NULL; // Dead path. - assert(wb->Opcode() == Op_ShenandoahWriteBarrier, "expect write barrier"); - if (is_independent(in_type, _type)) { - phase->igvn_rehash_node_delayed(wb); - set_req(Memory, wb->in(Memory)); - if (can_reshape && input->outcnt() == 0) { - phase->is_IterGVN()->_worklist.push(input); - } - return this; - } - } - return NULL; -} - -ShenandoahWriteBarrierNode::ShenandoahWriteBarrierNode(Compile* C, Node* ctrl, Node* mem, Node* obj) - : ShenandoahBarrierNode(ctrl, mem, obj, false) { - assert(UseShenandoahGC && ShenandoahWriteBarrier, "should be enabled"); - ShenandoahBarrierSetC2::bsc2()->state()->add_shenandoah_barrier(this); -} - -Node* ShenandoahWriteBarrierNode::Identity(PhaseGVN* phase) { - assert(in(0) != NULL, "should have control"); - PhaseIterGVN* igvn = phase->is_IterGVN(); - Node* mem_in = in(Memory); - Node* mem_proj = NULL; - - if (igvn != NULL) { - mem_proj = find_out_with(Op_ShenandoahWBMemProj); - if (mem_in == mem_proj) { - return this; - } - } - - Node* replacement = Identity_impl(phase); - if (igvn != NULL) { - if (replacement != NULL && replacement != this && mem_proj != NULL) { - igvn->replace_node(mem_proj, mem_in); - } - } - return replacement; -} - -Node* ShenandoahWriteBarrierNode::Ideal(PhaseGVN *phase, bool can_reshape) { - assert(in(0) != NULL, "should have control"); - if (!can_reshape) { - return NULL; - } - - Node* mem_in = in(Memory); - - if (mem_in->isa_MergeMem()) { - const TypePtr* adr_type = brooks_pointer_type(bottom_type()); - uint alias_idx = phase->C->get_alias_index(adr_type); - mem_in = mem_in->as_MergeMem()->memory_at(alias_idx); - set_req(Memory, mem_in); - return this; - } - - Node* val = in(ValueIn); - if (val->is_ShenandoahBarrier()) { - set_req(ValueIn, val->in(ValueIn)); - return this; - } - - return NULL; -} - -bool ShenandoahWriteBarrierNode::expand(Compile* C, PhaseIterGVN& igvn) { - if (UseShenandoahGC) { - if (ShenandoahBarrierSetC2::bsc2()->state()->shenandoah_barriers_count() > 0 || (!ShenandoahWriteBarrier && ShenandoahStoreValEnqueueBarrier)) { - bool attempt_more_loopopts = ShenandoahLoopOptsAfterExpansion; C->clear_major_progress(); - PhaseIdealLoop ideal_loop(igvn, LoopOptsShenandoahExpand); - if (C->failing()) return false; - PhaseIdealLoop::verify(igvn); - DEBUG_ONLY(ShenandoahBarrierNode::verify_raw_mem(C->root());) - if (attempt_more_loopopts) { - C->set_major_progress(); - if (!C->optimize_loops(igvn, LoopOptsShenandoahPostExpand)) { - return false; - } - C->clear_major_progress(); - } } } return true; } -bool ShenandoahWriteBarrierNode::is_heap_state_test(Node* iff, int mask) { +bool ShenandoahBarrierC2Support::is_heap_state_test(Node* iff, int mask) { if (!UseShenandoahGC) { return false; } @@ -450,11 +95,11 @@ bool ShenandoahWriteBarrierNode::is_heap_state_test(Node* iff, int mask) { return is_gc_state_load(in1); } -bool ShenandoahWriteBarrierNode::is_heap_stable_test(Node* iff) { +bool ShenandoahBarrierC2Support::is_heap_stable_test(Node* iff) { return is_heap_state_test(iff, ShenandoahHeap::HAS_FORWARDED); } -bool ShenandoahWriteBarrierNode::is_gc_state_load(Node *n) { +bool ShenandoahBarrierC2Support::is_gc_state_load(Node *n) { if (!UseShenandoahGC) { return false; } @@ -476,7 +121,7 @@ bool ShenandoahWriteBarrierNode::is_gc_state_load(Node *n) { return true; } -bool ShenandoahWriteBarrierNode::has_safepoint_between(Node* start, Node* stop, PhaseIdealLoop *phase) { +bool ShenandoahBarrierC2Support::has_safepoint_between(Node* start, Node* stop, PhaseIdealLoop *phase) { assert(phase->is_dominator(stop, start), "bad inputs"); ResourceMark rm; Unique_Node_List wq; @@ -500,7 +145,7 @@ bool ShenandoahWriteBarrierNode::has_safepoint_between(Node* start, Node* stop, return false; } -bool ShenandoahWriteBarrierNode::try_common_gc_state_load(Node *n, PhaseIdealLoop *phase) { +bool ShenandoahBarrierC2Support::try_common_gc_state_load(Node *n, PhaseIdealLoop *phase) { assert(is_gc_state_load(n), "inconsistent"); Node* addp = n->in(MemNode::Address); Node* dominator = NULL; @@ -525,193 +170,8 @@ bool ShenandoahWriteBarrierNode::try_common_gc_state_load(Node *n, PhaseIdealLoo return true; } -bool ShenandoahBarrierNode::dominates_memory_impl(PhaseGVN* phase, - Node* b1, - Node* b2, - Node* current, - bool linear) { - ResourceMark rm; - VectorSet visited(Thread::current()->resource_area()); - Node_Stack phis(0); - - for(int i = 0; i < 10; i++) { - if (current == NULL) { - return false; - } else if (visited.test_set(current->_idx) || current->is_top() || current == b1) { - current = NULL; - while (phis.is_nonempty() && current == NULL) { - uint idx = phis.index(); - Node* phi = phis.node(); - if (idx >= phi->req()) { - phis.pop(); - } else { - current = phi->in(idx); - phis.set_index(idx+1); - } - } - if (current == NULL) { - return true; - } - } else if (current == b2) { - return false; - } else if (current == phase->C->immutable_memory()) { - return false; - } else if (current->isa_Phi()) { - if (!linear) { - return false; - } - phis.push(current, 2); - current = current->in(1); - } else if (current->Opcode() == Op_ShenandoahWriteBarrier) { - current = current->in(Memory); - } else if (current->Opcode() == Op_ShenandoahWBMemProj) { - current = current->in(ShenandoahWBMemProjNode::WriteBarrier); - } else if (current->is_Proj()) { - current = current->in(0); - } else if (current->is_Call()) { - current = current->in(TypeFunc::Memory); - } else if (current->is_MemBar()) { - current = current->in(TypeFunc::Memory); - } else if (current->is_MergeMem()) { - const TypePtr* adr_type = brooks_pointer_type(phase->type(b2)); - uint alias_idx = phase->C->get_alias_index(adr_type); - current = current->as_MergeMem()->memory_at(alias_idx); - } else { #ifdef ASSERT - current->dump(); -#endif - ShouldNotReachHere(); - return false; - } - } - return false; -} - -/** - * Determines if b1 dominates b2 through memory inputs. It returns true if: - * - b1 can be reached by following each branch in b2's memory input (through phis, etc) - * - or we get back to b2 (i.e. through a loop) without seeing b1 - * In all other cases, (in particular, if we reach immutable_memory without having seen b1) - * we return false. - */ -bool ShenandoahBarrierNode::dominates_memory(PhaseGVN* phase, Node* b1, Node* b2, bool linear) { - return dominates_memory_impl(phase, b1, b2, b2->in(Memory), linear); -} - -Node* ShenandoahBarrierNode::Identity_impl(PhaseGVN* phase) { - Node* n = in(ValueIn); - - Node* rb_mem = Opcode() == Op_ShenandoahReadBarrier ? in(Memory) : NULL; - if (! needs_barrier(phase, this, n, rb_mem, _allow_fromspace)) { - return n; - } - - // Try to find a write barrier sibling with identical inputs that we can fold into. - for (DUIterator i = n->outs(); n->has_out(i); i++) { - Node* sibling = n->out(i); - if (sibling == this) { - continue; - } - if (sibling->Opcode() != Op_ShenandoahWriteBarrier) { - continue; - } - - assert(sibling->in(ValueIn) == in(ValueIn), "sanity"); - assert(sibling->Opcode() == Op_ShenandoahWriteBarrier, "sanity"); - - if (dominates_memory(phase, sibling, this, phase->is_IterGVN() == NULL)) { - return sibling; - } - } - return this; -} - -#ifndef PRODUCT -void ShenandoahBarrierNode::dump_spec(outputStream *st) const { - const TypePtr* adr = adr_type(); - if (adr == NULL) { - return; - } - st->print(" @"); - adr->dump_on(st); - st->print(" ("); - Compile::current()->alias_type(adr)->adr_type()->dump_on(st); - st->print(") "); -} -#endif - -Node* ShenandoahReadBarrierNode::Identity(PhaseGVN* phase) { - Node* id = Identity_impl(phase); - - if (id == this && phase->is_IterGVN()) { - Node* n = in(ValueIn); - // No success in super call. Try to combine identical read barriers. - for (DUIterator i = n->outs(); n->has_out(i); i++) { - Node* sibling = n->out(i); - if (sibling == this || sibling->Opcode() != Op_ShenandoahReadBarrier) { - continue; - } - assert(sibling->in(ValueIn) == in(ValueIn), "sanity"); - if (phase->is_IterGVN()->hash_find(sibling) && - sibling->bottom_type() == bottom_type() && - sibling->in(Control) == in(Control) && - dominates_memory_rb(phase, sibling, this, phase->is_IterGVN() == NULL)) { - return sibling; - } - } - } - return id; -} - -const Type* ShenandoahBarrierNode::Value(PhaseGVN* phase) const { - // Either input is TOP ==> the result is TOP - const Type *t1 = phase->type(in(Memory)); - if (t1 == Type::TOP) return Type::TOP; - const Type *t2 = phase->type(in(ValueIn)); - if( t2 == Type::TOP ) return Type::TOP; - - if (t2 == TypePtr::NULL_PTR) { - return _type; - } - - const Type* type = t2->is_oopptr()->cast_to_nonconst(); - return type; -} - -uint ShenandoahBarrierNode::hash() const { - return TypeNode::hash() + _allow_fromspace; -} - -bool ShenandoahBarrierNode::cmp(const Node& n) const { - return _allow_fromspace == ((ShenandoahBarrierNode&) n)._allow_fromspace - && TypeNode::cmp(n); -} - -uint ShenandoahBarrierNode::size_of() const { - return sizeof(*this); -} - -Node* ShenandoahWBMemProjNode::Identity(PhaseGVN* phase) { - Node* wb = in(WriteBarrier); - if (wb->is_top()) return phase->C->top(); // Dead path. - - assert(wb->Opcode() == Op_ShenandoahWriteBarrier, "expect write barrier"); - PhaseIterGVN* igvn = phase->is_IterGVN(); - // We can't do the below unless the graph is fully constructed. - if (igvn == NULL) { - return this; - } - - // If the mem projection has no barrier users, it's not needed anymore. - if (wb->outcnt() == 1) { - return wb->in(ShenandoahBarrierNode::Memory); - } - - return this; -} - -#ifdef ASSERT -bool ShenandoahBarrierNode::verify_helper(Node* in, Node_Stack& phis, VectorSet& visited, verify_type t, bool trace, Unique_Node_List& barriers_used) { +bool ShenandoahBarrierC2Support::verify_helper(Node* in, Node_Stack& phis, VectorSet& visited, verify_type t, bool trace, Unique_Node_List& barriers_used) { assert(phis.size() == 0, ""); while (true) { @@ -732,12 +192,24 @@ bool ShenandoahBarrierNode::verify_helper(Node* in, Node_Stack& phis, VectorSet& in = in->in(AddPNode::Address); continue; } else if (in->is_Con()) { - if (trace) {tty->print("Found constant"); in->dump();} - } else if (in->is_ShenandoahBarrier()) { + if (trace) { + tty->print("Found constant"); + in->dump(); + } + } else if (in->Opcode() == Op_Parm) { + if (trace) { + tty->print("Found argument"); + } + } else if (in->Opcode() == Op_CreateEx) { + if (trace) { + tty->print("Found create-exception"); + } + } else if (in->Opcode() == Op_LoadP && in->adr_type() == TypeRawPtr::BOTTOM) { + if (trace) { + tty->print("Found raw LoadP (OSR argument?)"); + } + } else if (in->Opcode() == Op_ShenandoahLoadReferenceBarrier) { if (t == ShenandoahOopStore) { - if (in->Opcode() != Op_ShenandoahWriteBarrier) { - return false; - } uint i = 0; for (; i < phis.size(); i++) { Node* n = phis.node_at(i); @@ -748,8 +220,6 @@ bool ShenandoahBarrierNode::verify_helper(Node* in, Node_Stack& phis, VectorSet& if (i == phis.size()) { return false; } - } else if (t == ShenandoahStore && in->Opcode() != Op_ShenandoahWriteBarrier) { - return false; } barriers_used.push(in); if (trace) {tty->print("Found barrier"); in->dump();} @@ -763,7 +233,14 @@ bool ShenandoahBarrierNode::verify_helper(Node* in, Node_Stack& phis, VectorSet& in = in->in(1); continue; } else if (in->is_Proj() && in->in(0)->is_Allocate()) { - if (trace) {tty->print("Found alloc"); in->in(0)->dump();} + if (trace) { + tty->print("Found alloc"); + in->in(0)->dump(); + } + } else if (in->is_Proj() && (in->in(0)->Opcode() == Op_CallStaticJava || in->in(0)->Opcode() == Op_CallDynamicJava)) { + if (trace) { + tty->print("Found Java call"); + } } else if (in->is_Phi()) { if (!visited.test_set(in->_idx)) { if (trace) {tty->print("Pushed phi:"); in->dump();} @@ -809,7 +286,7 @@ bool ShenandoahBarrierNode::verify_helper(Node* in, Node_Stack& phis, VectorSet& return true; } -void ShenandoahBarrierNode::report_verify_failure(const char *msg, Node *n1, Node *n2) { +void ShenandoahBarrierC2Support::report_verify_failure(const char* msg, Node* n1, Node* n2) { if (n1 != NULL) { n1->dump(+10); } @@ -819,7 +296,7 @@ void ShenandoahBarrierNode::report_verify_failure(const char *msg, Node *n1, Nod fatal("%s", msg); } -void ShenandoahBarrierNode::verify(RootNode* root) { +void ShenandoahBarrierC2Support::verify(RootNode* root) { ResourceMark rm; Unique_Node_List wq; GrowableArray barriers; @@ -871,7 +348,7 @@ void ShenandoahBarrierNode::verify(RootNode* root) { } } - if (verify && !ShenandoahBarrierNode::verify_helper(n->in(MemNode::Address), phis, visited, ShenandoahLoad, trace, barriers_used)) { + if (verify && !verify_helper(n->in(MemNode::Address), phis, visited, ShenandoahLoad, trace, barriers_used)) { report_verify_failure("Shenandoah verification: Load should have barriers", n); } } @@ -899,11 +376,11 @@ void ShenandoahBarrierNode::verify(RootNode* root) { } } - if (verify && !ShenandoahBarrierNode::verify_helper(n->in(MemNode::ValueIn), phis, visited, ShenandoahStoreValEnqueueBarrier ? ShenandoahOopStore : ShenandoahValue, trace, barriers_used)) { + if (verify && !verify_helper(n->in(MemNode::ValueIn), phis, visited, ShenandoahStoreValEnqueueBarrier ? ShenandoahOopStore : ShenandoahValue, trace, barriers_used)) { report_verify_failure("Shenandoah verification: Store should have barriers", n); } } - if (!ShenandoahBarrierNode::verify_helper(n->in(MemNode::Address), phis, visited, ShenandoahStore, trace, barriers_used)) { + if (!verify_helper(n->in(MemNode::Address), phis, visited, ShenandoahStore, trace, barriers_used)) { report_verify_failure("Shenandoah verification: Store (address) should have barriers", n); } } else if (n->Opcode() == Op_CmpP) { @@ -926,26 +403,26 @@ void ShenandoahBarrierNode::verify(RootNode* root) { } else { assert(in2->bottom_type()->isa_oopptr(), ""); - if (!ShenandoahBarrierNode::verify_helper(in1, phis, visited, ShenandoahStore, trace, barriers_used) || - !ShenandoahBarrierNode::verify_helper(in2, phis, visited, ShenandoahStore, trace, barriers_used)) { + if (!verify_helper(in1, phis, visited, ShenandoahStore, trace, barriers_used) || + !verify_helper(in2, phis, visited, ShenandoahStore, trace, barriers_used)) { report_verify_failure("Shenandoah verification: Cmp should have barriers", n); } } if (verify_no_useless_barrier && mark_inputs && - (!ShenandoahBarrierNode::verify_helper(in1, phis, visited, ShenandoahValue, trace, barriers_used) || - !ShenandoahBarrierNode::verify_helper(in2, phis, visited, ShenandoahValue, trace, barriers_used))) { + (!verify_helper(in1, phis, visited, ShenandoahValue, trace, barriers_used) || + !verify_helper(in2, phis, visited, ShenandoahValue, trace, barriers_used))) { phis.clear(); visited.Reset(); } } } else if (n->is_LoadStore()) { if (n->in(MemNode::ValueIn)->bottom_type()->make_ptr() && - !ShenandoahBarrierNode::verify_helper(n->in(MemNode::ValueIn), phis, visited, ShenandoahStoreValEnqueueBarrier ? ShenandoahOopStore : ShenandoahValue, trace, barriers_used)) { + !verify_helper(n->in(MemNode::ValueIn), phis, visited, ShenandoahStoreValEnqueueBarrier ? ShenandoahOopStore : ShenandoahValue, trace, barriers_used)) { report_verify_failure("Shenandoah verification: LoadStore (value) should have barriers", n); } - if (n->in(MemNode::Address)->bottom_type()->make_oopptr() && !ShenandoahBarrierNode::verify_helper(n->in(MemNode::Address), phis, visited, ShenandoahStore, trace, barriers_used)) { + if (n->in(MemNode::Address)->bottom_type()->make_oopptr() && !verify_helper(n->in(MemNode::Address), phis, visited, ShenandoahStore, trace, barriers_used)) { report_verify_failure("Shenandoah verification: LoadStore (address) should have barriers", n); } } else if (n->Opcode() == Op_CallLeafNoFP || n->Opcode() == Op_CallLeaf) { @@ -1041,13 +518,13 @@ void ShenandoahBarrierNode::verify(RootNode* root) { } } } - if (!ShenandoahBarrierNode::verify_helper(n->in(TypeFunc::Parms), phis, visited, ShenandoahLoad, trace, barriers_used) || - !ShenandoahBarrierNode::verify_helper(dest, phis, visited, ShenandoahStore, trace, barriers_used)) { + if (!verify_helper(n->in(TypeFunc::Parms), phis, visited, ShenandoahLoad, trace, barriers_used) || + !verify_helper(dest, phis, visited, ShenandoahStore, trace, barriers_used)) { report_verify_failure("Shenandoah verification: ArrayCopy should have barriers", n); } } else if (strlen(call->_name) > 5 && !strcmp(call->_name + strlen(call->_name) - 5, "_fill")) { - if (!ShenandoahBarrierNode::verify_helper(n->in(TypeFunc::Parms), phis, visited, ShenandoahStore, trace, barriers_used)) { + if (!verify_helper(n->in(TypeFunc::Parms), phis, visited, ShenandoahStore, trace, barriers_used)) { report_verify_failure("Shenandoah verification: _fill should have barriers", n); } } else if (!strcmp(call->_name, "shenandoah_wb_pre")) { @@ -1067,7 +544,7 @@ void ShenandoahBarrierNode::verify(RootNode* root) { if (pos == -1) { break; } - if (!ShenandoahBarrierNode::verify_helper(call->in(pos), phis, visited, calls[i].args[j].t, trace, barriers_used)) { + if (!verify_helper(call->in(pos), phis, visited, calls[i].args[j].t, trace, barriers_used)) { report_verify_failure("Shenandoah verification: intrinsic calls should have barriers", n); } } @@ -1090,15 +567,8 @@ void ShenandoahBarrierNode::verify(RootNode* root) { } } } - } else if (n->is_ShenandoahBarrier()) { - assert(!barriers.contains(n), ""); - assert(n->Opcode() != Op_ShenandoahWriteBarrier || n->find_out_with(Op_ShenandoahWBMemProj) != NULL, "bad shenandoah write barrier"); - assert(n->Opcode() != Op_ShenandoahWriteBarrier || n->outcnt() > 1, "bad shenandoah write barrier"); - barriers.push(n); - } else if (n->Opcode() == Op_ShenandoahEnqueueBarrier) { + } else if (n->Opcode() == Op_ShenandoahEnqueueBarrier || n->Opcode() == Op_ShenandoahLoadReferenceBarrier) { // skip - } else if (n->Opcode() == Op_ShenandoahWBMemProj) { - assert(n->in(0) == NULL && n->in(ShenandoahWBMemProjNode::WriteBarrier)->Opcode() == Op_ShenandoahWriteBarrier, "strange ShenandoahWBMemProj"); } else if (n->is_AddP() || n->is_Phi() || n->is_ConstraintCast() @@ -1165,7 +635,7 @@ void ShenandoahBarrierNode::verify(RootNode* root) { if (pos == -1) { break; } - if (!ShenandoahBarrierNode::verify_helper(n->in(pos), phis, visited, others[i].inputs[j].t, trace, barriers_used)) { + if (!verify_helper(n->in(pos), phis, visited, others[i].inputs[j].t, trace, barriers_used)) { report_verify_failure("Shenandoah verification: intrinsic calls should have barriers", n); } } @@ -1193,7 +663,7 @@ void ShenandoahBarrierNode::verify(RootNode* root) { SafePointNode* sfpt = n->as_SafePoint(); if (verify_no_useless_barrier && sfpt->jvms() != NULL) { for (uint i = sfpt->jvms()->scloff(); i < sfpt->jvms()->endoff(); i++) { - if (!ShenandoahBarrierNode::verify_helper(sfpt->in(i), phis, visited, ShenandoahLoad, trace, barriers_used)) { + if (!verify_helper(sfpt->in(i), phis, visited, ShenandoahLoad, trace, barriers_used)) { phis.clear(); visited.Reset(); } @@ -1227,9 +697,8 @@ void ShenandoahBarrierNode::verify(RootNode* root) { n->Opcode() == Op_SCMemProj || n->Opcode() == Op_EncodeP || n->Opcode() == Op_DecodeN || - n->Opcode() == Op_ShenandoahWriteBarrier || - n->Opcode() == Op_ShenandoahWBMemProj || - n->Opcode() == Op_ShenandoahEnqueueBarrier)) { + n->Opcode() == Op_ShenandoahEnqueueBarrier || + n->Opcode() == Op_ShenandoahLoadReferenceBarrier)) { if (m->bottom_type()->make_oopptr() && m->bottom_type()->make_oopptr()->meet(TypePtr::NULL_PTR) == m->bottom_type()) { report_verify_failure("Shenandoah verification: null input", n, m); } @@ -1251,7 +720,7 @@ void ShenandoahBarrierNode::verify(RootNode* root) { } #endif -bool ShenandoahBarrierNode::is_dominator_same_ctrl(Node*c, Node* d, Node* n, PhaseIdealLoop* phase) { +bool ShenandoahBarrierC2Support::is_dominator_same_ctrl(Node* c, Node* d, Node* n, PhaseIdealLoop* phase) { // That both nodes have the same control is not sufficient to prove // domination, verify that there's no path from d to n ResourceMark rm; @@ -1275,7 +744,7 @@ bool ShenandoahBarrierNode::is_dominator_same_ctrl(Node*c, Node* d, Node* n, Pha return true; } -bool ShenandoahBarrierNode::is_dominator(Node *d_c, Node *n_c, Node* d, Node* n, PhaseIdealLoop* phase) { +bool ShenandoahBarrierC2Support::is_dominator(Node* d_c, Node* n_c, Node* d, Node* n, PhaseIdealLoop* phase) { if (d_c != n_c) { return phase->is_dominator(d_c, n_c); } @@ -1290,15 +759,11 @@ Node* next_mem(Node* mem, int alias) { res = mem->in(TypeFunc::Memory); } else if (mem->is_Phi()) { res = mem->in(1); - } else if (mem->is_ShenandoahBarrier()) { - res = mem->in(ShenandoahBarrierNode::Memory); } else if (mem->is_MergeMem()) { res = mem->as_MergeMem()->memory_at(alias); } else if (mem->is_Store() || mem->is_LoadStore() || mem->is_ClearArray()) { assert(alias = Compile::AliasIdxRaw, "following raw memory can't lead to a barrier"); res = mem->in(MemNode::Memory); - } else if (mem->Opcode() == Op_ShenandoahWBMemProj) { - res = mem->in(ShenandoahWBMemProjNode::WriteBarrier); } else { #ifdef ASSERT mem->dump(); @@ -1308,7 +773,7 @@ Node* next_mem(Node* mem, int alias) { return res; } -Node* ShenandoahBarrierNode::no_branches(Node* c, Node* dom, bool allow_one_proj, PhaseIdealLoop* phase) { +Node* ShenandoahBarrierC2Support::no_branches(Node* c, Node* dom, bool allow_one_proj, PhaseIdealLoop* phase) { Node* iffproj = NULL; while (c != dom) { Node* next = phase->idom(c); @@ -1373,270 +838,7 @@ Node* ShenandoahBarrierNode::no_branches(Node* c, Node* dom, bool allow_one_proj return iffproj; } -bool ShenandoahBarrierNode::build_loop_late_post(PhaseIdealLoop* phase, Node* n) { - if (n->Opcode() == Op_ShenandoahReadBarrier || - n->Opcode() == Op_ShenandoahWriteBarrier || - n->Opcode() == Op_ShenandoahWBMemProj) { - - phase->build_loop_late_post_work(n, false); - - if (n->Opcode() == Op_ShenandoahWriteBarrier) { - // The write barrier and its memory proj must have the same - // control otherwise some loop opts could put nodes (Phis) between - // them - Node* proj = n->find_out_with(Op_ShenandoahWBMemProj); - if (proj != NULL) { - phase->set_ctrl_and_loop(proj, phase->get_ctrl(n)); - } - } - return true; - } - return false; -} - -bool ShenandoahBarrierNode::sink_node(PhaseIdealLoop* phase, Node* ctrl, Node* n_ctrl) { - ctrl = phase->find_non_split_ctrl(ctrl); - assert(phase->dom_depth(n_ctrl) <= phase->dom_depth(ctrl), "n is later than its clone"); - set_req(0, ctrl); - phase->register_new_node(this, ctrl); - return true; -} - -#ifdef ASSERT -void ShenandoahWriteBarrierNode::memory_dominates_all_paths_helper(Node* c, Node* rep_ctrl, Unique_Node_List& controls, PhaseIdealLoop* phase) { - const bool trace = false; - if (trace) { tty->print("X control is"); c->dump(); } - - uint start = controls.size(); - controls.push(c); - for (uint i = start; i < controls.size(); i++) { - Node *n = controls.at(i); - - if (trace) { tty->print("X from"); n->dump(); } - - if (n == rep_ctrl) { - continue; - } - - if (n->is_Proj()) { - Node* n_dom = n->in(0); - IdealLoopTree* n_dom_loop = phase->get_loop(n_dom); - if (n->is_IfProj() && n_dom->outcnt() == 2) { - n_dom_loop = phase->get_loop(n_dom->as_If()->proj_out(n->as_Proj()->_con == 0 ? 1 : 0)); - } - if (n_dom_loop != phase->ltree_root()) { - Node* tail = n_dom_loop->tail(); - if (tail->is_Region()) { - for (uint j = 1; j < tail->req(); j++) { - if (phase->is_dominator(n_dom, tail->in(j)) && !phase->is_dominator(n, tail->in(j))) { - assert(phase->is_dominator(rep_ctrl, tail->in(j)), "why are we here?"); - // entering loop from below, mark backedge - if (trace) { tty->print("X pushing backedge"); tail->in(j)->dump(); } - controls.push(tail->in(j)); - //assert(n->in(0) == n_dom, "strange flow control"); - } - } - } else if (phase->get_loop(n) != n_dom_loop && phase->is_dominator(n_dom, tail)) { - // entering loop from below, mark backedge - if (trace) { tty->print("X pushing backedge"); tail->dump(); } - controls.push(tail); - //assert(n->in(0) == n_dom, "strange flow control"); - } - } - } - - if (n->is_Loop()) { - Node* c = n->in(LoopNode::EntryControl); - if (trace) { tty->print("X pushing"); c->dump(); } - controls.push(c); - } else if (n->is_Region()) { - for (uint i = 1; i < n->req(); i++) { - Node* c = n->in(i); - if (trace) { tty->print("X pushing"); c->dump(); } - controls.push(c); - } - } else { - Node* c = n->in(0); - if (trace) { tty->print("X pushing"); c->dump(); } - controls.push(c); - } - } -} - -bool ShenandoahWriteBarrierNode::memory_dominates_all_paths(Node* mem, Node* rep_ctrl, int alias, PhaseIdealLoop* phase) { - const bool trace = false; - if (trace) { - tty->print("XXX mem is"); mem->dump(); - tty->print("XXX rep ctrl is"); rep_ctrl->dump(); - tty->print_cr("XXX alias is %d", alias); - } - ResourceMark rm; - Unique_Node_List wq; - Unique_Node_List controls; - wq.push(mem); - for (uint next = 0; next < wq.size(); next++) { - Node *nn = wq.at(next); - if (trace) { tty->print("XX from mem"); nn->dump(); } - assert(nn->bottom_type() == Type::MEMORY, "memory only"); - - if (nn->is_Phi()) { - Node* r = nn->in(0); - for (DUIterator_Fast jmax, j = r->fast_outs(jmax); j < jmax; j++) { - Node* u = r->fast_out(j); - if (u->is_Phi() && u->bottom_type() == Type::MEMORY && u != nn && - (u->adr_type() == TypePtr::BOTTOM || phase->C->get_alias_index(u->adr_type()) == alias)) { - if (trace) { tty->print("XX Next mem (other phi)"); u->dump(); } - wq.push(u); - } - } - } - - for (DUIterator_Fast imax, i = nn->fast_outs(imax); i < imax; i++) { - Node* use = nn->fast_out(i); - - if (trace) { tty->print("XX use %p", use->adr_type()); use->dump(); } - if (use->is_CFG() && use->in(TypeFunc::Memory) == nn) { - Node* c = use->in(0); - if (phase->is_dominator(rep_ctrl, c)) { - memory_dominates_all_paths_helper(c, rep_ctrl, controls, phase); - } else if (use->is_CallStaticJava() && use->as_CallStaticJava()->uncommon_trap_request() != 0 && c->is_Region()) { - Node* region = c; - if (trace) { tty->print("XX unc region"); region->dump(); } - for (uint j = 1; j < region->req(); j++) { - if (phase->is_dominator(rep_ctrl, region->in(j))) { - if (trace) { tty->print("XX unc follows"); region->in(j)->dump(); } - memory_dominates_all_paths_helper(region->in(j), rep_ctrl, controls, phase); - } - } - } - //continue; - } else if (use->is_Phi()) { - assert(use->bottom_type() == Type::MEMORY, "bad phi"); - if ((use->adr_type() == TypePtr::BOTTOM) || - phase->C->get_alias_index(use->adr_type()) == alias) { - for (uint j = 1; j < use->req(); j++) { - if (use->in(j) == nn) { - Node* c = use->in(0)->in(j); - if (phase->is_dominator(rep_ctrl, c)) { - memory_dominates_all_paths_helper(c, rep_ctrl, controls, phase); - } - } - } - } - // continue; - } - - if (use->is_MergeMem()) { - if (use->as_MergeMem()->memory_at(alias) == nn) { - if (trace) { tty->print("XX Next mem"); use->dump(); } - // follow the memory edges - wq.push(use); - } - } else if (use->is_Phi()) { - assert(use->bottom_type() == Type::MEMORY, "bad phi"); - if ((use->adr_type() == TypePtr::BOTTOM) || - phase->C->get_alias_index(use->adr_type()) == alias) { - if (trace) { tty->print("XX Next mem"); use->dump(); } - // follow the memory edges - wq.push(use); - } - } else if (use->bottom_type() == Type::MEMORY && - (use->adr_type() == TypePtr::BOTTOM || phase->C->get_alias_index(use->adr_type()) == alias)) { - if (trace) { tty->print("XX Next mem"); use->dump(); } - // follow the memory edges - wq.push(use); - } else if ((use->is_SafePoint() || use->is_MemBar()) && - (use->adr_type() == TypePtr::BOTTOM || phase->C->get_alias_index(use->adr_type()) == alias)) { - for (DUIterator_Fast jmax, j = use->fast_outs(jmax); j < jmax; j++) { - Node* u = use->fast_out(j); - if (u->bottom_type() == Type::MEMORY) { - if (trace) { tty->print("XX Next mem"); u->dump(); } - // follow the memory edges - wq.push(u); - } - } - } else if (use->Opcode() == Op_ShenandoahWriteBarrier && phase->C->get_alias_index(use->adr_type()) == alias) { - Node* m = use->find_out_with(Op_ShenandoahWBMemProj); - if (m != NULL) { - if (trace) { tty->print("XX Next mem"); m->dump(); } - // follow the memory edges - wq.push(m); - } - } - } - } - - if (controls.size() == 0) { - return false; - } - - for (uint i = 0; i < controls.size(); i++) { - Node *n = controls.at(i); - - if (trace) { tty->print("X checking"); n->dump(); } - - if (n->unique_ctrl_out() != NULL) { - continue; - } - - if (n->Opcode() == Op_NeverBranch) { - Node* taken = n->as_Multi()->proj_out(0); - if (!controls.member(taken)) { - if (trace) { tty->print("X not seen"); taken->dump(); } - return false; - } - continue; - } - - for (DUIterator_Fast jmax, j = n->fast_outs(jmax); j < jmax; j++) { - Node* u = n->fast_out(j); - - if (u->is_CFG()) { - if (!controls.member(u)) { - if (u->is_Proj() && u->as_Proj()->is_uncommon_trap_proj(Deoptimization::Reason_none)) { - if (trace) { tty->print("X not seen but unc"); u->dump(); } - } else { - Node* c = u; - do { - c = c->unique_ctrl_out(); - } while (c != NULL && c->is_Region()); - if (c != NULL && c->Opcode() == Op_Halt) { - if (trace) { tty->print("X not seen but halt"); c->dump(); } - } else { - if (trace) { tty->print("X not seen"); u->dump(); } - return false; - } - } - } else { - if (trace) { tty->print("X seen"); u->dump(); } - } - } - } - } - return true; -} -#endif - -Node* ShenandoahBarrierNode::dom_mem(Node* mem, Node*& mem_ctrl, Node* n, Node* rep_ctrl, int alias, PhaseIdealLoop* phase) { - ResourceMark rm; - VectorSet wq(Thread::current()->resource_area()); - wq.set(mem->_idx); - mem_ctrl = phase->get_ctrl(mem); - while (!is_dominator(mem_ctrl, rep_ctrl, mem, n, phase)) { - mem = next_mem(mem, alias); - if (wq.test_set(mem->_idx)) { - return NULL; // hit an unexpected loop - } - mem_ctrl = phase->ctrl_or_self(mem); - } - if (mem->is_MergeMem()) { - mem = mem->as_MergeMem()->memory_at(alias); - mem_ctrl = phase->ctrl_or_self(mem); - } - return mem; -} - -Node* ShenandoahBarrierNode::dom_mem(Node* mem, Node* ctrl, int alias, Node*& mem_ctrl, PhaseIdealLoop* phase) { +Node* ShenandoahBarrierC2Support::dom_mem(Node* mem, Node* ctrl, int alias, Node*& mem_ctrl, PhaseIdealLoop* phase) { ResourceMark rm; VectorSet wq(Thread::current()->resource_area()); wq.set(mem->_idx); @@ -1655,650 +857,7 @@ Node* ShenandoahBarrierNode::dom_mem(Node* mem, Node* ctrl, int alias, Node*& me return mem; } -static void disconnect_barrier_mem(Node* wb, PhaseIterGVN& igvn) { - Node* mem_in = wb->in(ShenandoahBarrierNode::Memory); - Node* proj = wb->find_out_with(Op_ShenandoahWBMemProj); - - for (DUIterator_Last imin, i = proj->last_outs(imin); i >= imin; ) { - Node* u = proj->last_out(i); - igvn.rehash_node_delayed(u); - int nb = u->replace_edge(proj, mem_in); - assert(nb > 0, "no replacement?"); - i -= nb; - } -} - -Node* ShenandoahWriteBarrierNode::move_above_predicates(LoopNode* cl, Node* val_ctrl, PhaseIdealLoop* phase) { - Node* entry = cl->skip_strip_mined(-1)->in(LoopNode::EntryControl); - Node* above_pred = phase->skip_all_loop_predicates(entry); - Node* ctrl = entry; - while (ctrl != above_pred) { - Node* next = ctrl->in(0); - if (!phase->is_dominator(val_ctrl, next)) { - break; - } - ctrl = next; - } - return ctrl; -} - -static MemoryGraphFixer* find_fixer(GrowableArray& memory_graph_fixers, int alias) { - for (int i = 0; i < memory_graph_fixers.length(); i++) { - if (memory_graph_fixers.at(i)->alias() == alias) { - return memory_graph_fixers.at(i); - } - } - return NULL; -} - -static MemoryGraphFixer* create_fixer(GrowableArray& memory_graph_fixers, int alias, PhaseIdealLoop* phase, bool include_lsm) { - assert(find_fixer(memory_graph_fixers, alias) == NULL, "none should exist yet"); - MemoryGraphFixer* fixer = new MemoryGraphFixer(alias, include_lsm, phase); - memory_graph_fixers.push(fixer); - return fixer; -} - -void ShenandoahWriteBarrierNode::try_move_before_loop_helper(LoopNode* cl, Node* val_ctrl, GrowableArray& memory_graph_fixers, PhaseIdealLoop* phase, bool include_lsm, Unique_Node_List& uses) { - assert(cl->is_Loop(), "bad control"); - Node* ctrl = move_above_predicates(cl, val_ctrl, phase); - Node* mem_ctrl = NULL; - int alias = phase->C->get_alias_index(adr_type()); - - MemoryGraphFixer* fixer = find_fixer(memory_graph_fixers, alias); - if (fixer == NULL) { - fixer = create_fixer(memory_graph_fixers, alias, phase, include_lsm); - } - - Node* proj = find_out_with(Op_ShenandoahWBMemProj); - - fixer->remove(proj); - Node* mem = fixer->find_mem(ctrl, NULL); - - assert(!ShenandoahVerifyOptoBarriers || memory_dominates_all_paths(mem, ctrl, alias, phase), "can't fix the memory graph"); - - phase->set_ctrl_and_loop(this, ctrl); - phase->igvn().replace_input_of(this, Control, ctrl); - - disconnect_barrier_mem(this, phase->igvn()); - - phase->igvn().replace_input_of(this, Memory, mem); - phase->set_ctrl_and_loop(proj, ctrl); - - fixer->fix_mem(ctrl, ctrl, mem, mem, proj, uses); - assert(proj->outcnt() > 0, "disconnected write barrier"); -} - -LoopNode* ShenandoahWriteBarrierNode::try_move_before_pre_loop(Node* c, Node* val_ctrl, PhaseIdealLoop* phase) { - // A write barrier between a pre and main loop can get in the way of - // vectorization. Move it above the pre loop if possible - CountedLoopNode* cl = NULL; - if (c->is_IfFalse() && - c->in(0)->is_CountedLoopEnd()) { - cl = c->in(0)->as_CountedLoopEnd()->loopnode(); - } else if (c->is_IfProj() && - c->in(0)->is_If() && - c->in(0)->in(0)->is_IfFalse() && - c->in(0)->in(0)->in(0)->is_CountedLoopEnd()) { - cl = c->in(0)->in(0)->in(0)->as_CountedLoopEnd()->loopnode(); - } - if (cl != NULL && - cl->is_pre_loop() && - val_ctrl != cl && - phase->is_dominator(val_ctrl, cl)) { - return cl; - } - return NULL; -} - -void ShenandoahWriteBarrierNode::try_move_before_loop(GrowableArray& memory_graph_fixers, PhaseIdealLoop* phase, bool include_lsm, Unique_Node_List& uses) { - Node *n_ctrl = phase->get_ctrl(this); - IdealLoopTree *n_loop = phase->get_loop(n_ctrl); - Node* val = in(ValueIn); - Node* val_ctrl = phase->get_ctrl(val); - if (n_loop != phase->ltree_root() && !n_loop->_irreducible) { - IdealLoopTree *val_loop = phase->get_loop(val_ctrl); - Node* mem = in(Memory); - IdealLoopTree *mem_loop = phase->get_loop(phase->get_ctrl(mem)); - if (!n_loop->is_member(val_loop) && - n_loop->is_member(mem_loop)) { - Node* n_loop_head = n_loop->_head; - - if (n_loop_head->is_Loop()) { - LoopNode* loop = n_loop_head->as_Loop(); - if (n_loop_head->is_CountedLoop() && n_loop_head->as_CountedLoop()->is_main_loop()) { - LoopNode* res = try_move_before_pre_loop(n_loop_head->in(LoopNode::EntryControl), val_ctrl, phase); - if (res != NULL) { - loop = res; - } - } - - try_move_before_loop_helper(loop, val_ctrl, memory_graph_fixers, phase, include_lsm, uses); - } - } - } - LoopNode* ctrl = try_move_before_pre_loop(in(0), val_ctrl, phase); - if (ctrl != NULL) { - try_move_before_loop_helper(ctrl, val_ctrl, memory_graph_fixers, phase, include_lsm, uses); - } -} - -Node* ShenandoahWriteBarrierNode::would_subsume(ShenandoahBarrierNode* other, PhaseIdealLoop* phase) { - Node* val = in(ValueIn); - Node* val_ctrl = phase->get_ctrl(val); - Node* other_mem = other->in(Memory); - Node* other_ctrl = phase->get_ctrl(other); - Node* this_ctrl = phase->get_ctrl(this); - IdealLoopTree* this_loop = phase->get_loop(this_ctrl); - IdealLoopTree* other_loop = phase->get_loop(other_ctrl); - - Node* ctrl = phase->dom_lca(other_ctrl, this_ctrl); - - if (ctrl->is_Proj() && - ctrl->in(0)->is_Call() && - ctrl->unique_ctrl_out() != NULL && - ctrl->unique_ctrl_out()->Opcode() == Op_Catch && - !phase->is_dominator(val_ctrl, ctrl->in(0)->in(0))) { - return NULL; - } - - IdealLoopTree* loop = phase->get_loop(ctrl); - - // We don't want to move a write barrier in a loop - // If the LCA is in a inner loop, try a control out of loop if possible - while (!loop->is_member(this_loop) && (other->Opcode() != Op_ShenandoahWriteBarrier || !loop->is_member(other_loop))) { - ctrl = phase->idom(ctrl); - if (ctrl->is_MultiBranch()) { - ctrl = ctrl->in(0); - } - if (ctrl != val_ctrl && phase->is_dominator(ctrl, val_ctrl)) { - return NULL; - } - loop = phase->get_loop(ctrl); - } - - if (ShenandoahDontIncreaseWBFreq) { - Node* this_iffproj = no_branches(this_ctrl, ctrl, true, phase); - if (other->Opcode() == Op_ShenandoahWriteBarrier) { - Node* other_iffproj = no_branches(other_ctrl, ctrl, true, phase); - if (other_iffproj == NULL || this_iffproj == NULL) { - return ctrl; - } else if (other_iffproj != NodeSentinel && this_iffproj != NodeSentinel && - other_iffproj->in(0) == this_iffproj->in(0)) { - return ctrl; - } - } else if (this_iffproj == NULL) { - return ctrl; - } - return NULL; - } - - return ctrl; -} - -void ShenandoahWriteBarrierNode::optimize_before_expansion(PhaseIdealLoop* phase, GrowableArray memory_graph_fixers, bool include_lsm) { - bool progress = false; - Unique_Node_List uses; - do { - progress = false; - for (int i = 0; i < ShenandoahBarrierSetC2::bsc2()->state()->shenandoah_barriers_count(); i++) { - ShenandoahWriteBarrierNode* wb = ShenandoahBarrierSetC2::bsc2()->state()->shenandoah_barrier(i); - - wb->try_move_before_loop(memory_graph_fixers, phase, include_lsm, uses); - - Node* val = wb->in(ValueIn); - - for (DUIterator_Fast jmax, j = val->fast_outs(jmax); j < jmax; j++) { - Node* u = val->fast_out(j); - if (u != wb && u->is_ShenandoahBarrier()) { - Node* rep_ctrl = wb->would_subsume(u->as_ShenandoahBarrier(), phase); - - if (rep_ctrl != NULL) { - Node* other = u; - Node* val_ctrl = phase->get_ctrl(val); - if (rep_ctrl->is_Proj() && - rep_ctrl->in(0)->is_Call() && - rep_ctrl->unique_ctrl_out() != NULL && - rep_ctrl->unique_ctrl_out()->Opcode() == Op_Catch) { - rep_ctrl = rep_ctrl->in(0)->in(0); - - assert(phase->is_dominator(val_ctrl, rep_ctrl), "bad control"); - } else { - LoopNode* c = ShenandoahWriteBarrierNode::try_move_before_pre_loop(rep_ctrl, val_ctrl, phase); - if (c != NULL) { - rep_ctrl = ShenandoahWriteBarrierNode::move_above_predicates(c, val_ctrl, phase); - } else { - while (rep_ctrl->is_IfProj()) { - CallStaticJavaNode* unc = rep_ctrl->as_Proj()->is_uncommon_trap_if_pattern(Deoptimization::Reason_none); - if (unc != NULL) { - int req = unc->uncommon_trap_request(); - Deoptimization::DeoptReason trap_reason = Deoptimization::trap_request_reason(req); - if ((trap_reason == Deoptimization::Reason_loop_limit_check || - trap_reason == Deoptimization::Reason_predicate || - trap_reason == Deoptimization::Reason_profile_predicate) && - phase->is_dominator(val_ctrl, rep_ctrl->in(0)->in(0))) { - rep_ctrl = rep_ctrl->in(0)->in(0); - continue; - } - } - break; - } - } - } - - Node* wb_ctrl = phase->get_ctrl(wb); - Node* other_ctrl = phase->get_ctrl(other); - int alias = phase->C->get_alias_index(wb->adr_type()); - MemoryGraphFixer* fixer = find_fixer(memory_graph_fixers, alias);; - if (!is_dominator(wb_ctrl, other_ctrl, wb, other, phase)) { - if (fixer == NULL) { - fixer = create_fixer(memory_graph_fixers, alias, phase, include_lsm); - } - Node* mem = fixer->find_mem(rep_ctrl, phase->get_ctrl(other) == rep_ctrl ? other : NULL); - - if (mem->has_out_with(Op_Lock) || mem->has_out_with(Op_Unlock)) { - continue; - } - - Node* wb_proj = wb->find_out_with(Op_ShenandoahWBMemProj); - fixer->remove(wb_proj); - Node* mem_for_ctrl = fixer->find_mem(rep_ctrl, NULL); - - if (wb->in(Memory) != mem) { - disconnect_barrier_mem(wb, phase->igvn()); - phase->igvn().replace_input_of(wb, Memory, mem); - } - if (rep_ctrl != wb_ctrl) { - phase->set_ctrl_and_loop(wb, rep_ctrl); - phase->igvn().replace_input_of(wb, Control, rep_ctrl); - phase->set_ctrl_and_loop(wb_proj, rep_ctrl); - progress = true; - } - - fixer->fix_mem(rep_ctrl, rep_ctrl, mem, mem_for_ctrl, wb_proj, uses); - - assert(!ShenandoahVerifyOptoBarriers || ShenandoahWriteBarrierNode::memory_dominates_all_paths(mem, rep_ctrl, alias, phase), "can't fix the memory graph"); - } - - if (other->Opcode() == Op_ShenandoahWriteBarrier) { - Node* other_proj = other->find_out_with(Op_ShenandoahWBMemProj); - if (fixer != NULL) { - fixer->remove(other_proj); - } - phase->igvn().replace_node(other_proj, other->in(Memory)); - } - phase->igvn().replace_node(other, wb); - --j; --jmax; - } - } - } - } - } while(progress); -} - -// Some code duplication with PhaseIdealLoop::split_if_with_blocks_pre() -Node* ShenandoahWriteBarrierNode::try_split_thru_phi(PhaseIdealLoop* phase) { - Node *ctrl = phase->get_ctrl(this); - if (ctrl == NULL) { - return this; - } - Node *blk = phase->has_local_phi_input(this); - if (blk == NULL) { - return this; - } - - if (in(0) != blk) { - return this; - } - - int policy = blk->req() >> 2; - - if (blk->is_CountedLoop()) { - IdealLoopTree *lp = phase->get_loop(blk); - if (lp && lp->_rce_candidate) { - return this; - } - } - - if (phase->C->live_nodes() > 35000) { - return this; - } - - uint unique = phase->C->unique(); - Node *phi = phase->split_thru_phi(this, blk, policy); - if (phi == NULL) { - return this; - } - - Node* mem_phi = new PhiNode(blk, Type::MEMORY, phase->C->alias_type(adr_type())->adr_type()); - for (uint i = 1; i < blk->req(); i++) { - Node* n = phi->in(i); - if (n->Opcode() == Op_ShenandoahWriteBarrier && - n->_idx >= unique) { - Node* proj = new ShenandoahWBMemProjNode(n); - phase->register_new_node(proj, phase->get_ctrl(n)); - mem_phi->init_req(i, proj); - } else { - Node* mem = in(ShenandoahBarrierNode::Memory); - if (mem->is_Phi() && mem->in(0) == blk) { - mem = mem->in(i); - } - mem_phi->init_req(i, mem); - } - } - phase->register_new_node(mem_phi, blk); - - - Node* proj = find_out_with(Op_ShenandoahWBMemProj); - phase->igvn().replace_node(proj, mem_phi); - phase->igvn().replace_node(this, phi); - - return phi; -} - -void ShenandoahReadBarrierNode::try_move(PhaseIdealLoop* phase) { - Node *n_ctrl = phase->get_ctrl(this); - if (n_ctrl == NULL) { - return; - } - Node* mem = in(MemNode::Memory); - int alias = phase->C->get_alias_index(adr_type()); - const bool trace = false; - -#ifdef ASSERT - if (trace) { tty->print("Trying to move mem of"); dump(); } -#endif - - Node* new_mem = mem; - - ResourceMark rm; - VectorSet seen(Thread::current()->resource_area()); - Node_List phis; - - for (;;) { -#ifdef ASSERT - if (trace) { tty->print("Looking for dominator from"); mem->dump(); } -#endif - if (mem->is_Proj() && mem->in(0)->is_Start()) { - if (new_mem != in(MemNode::Memory)) { -#ifdef ASSERT - if (trace) { tty->print("XXX Setting mem to"); new_mem->dump(); tty->print(" for "); dump(); } -#endif - phase->igvn().replace_input_of(this, MemNode::Memory, new_mem); - } - return; - } - - Node* candidate = mem; - do { - if (!is_independent(mem)) { - if (trace) { tty->print_cr("Not independent"); } - if (new_mem != in(MemNode::Memory)) { -#ifdef ASSERT - if (trace) { tty->print("XXX Setting mem to"); new_mem->dump(); tty->print(" for "); dump(); } -#endif - phase->igvn().replace_input_of(this, MemNode::Memory, new_mem); - } - return; - } - if (seen.test_set(mem->_idx)) { - if (trace) { tty->print_cr("Already seen"); } - ShouldNotReachHere(); - // Strange graph - if (new_mem != in(MemNode::Memory)) { -#ifdef ASSERT - if (trace) { tty->print("XXX Setting mem to"); new_mem->dump(); tty->print(" for "); dump(); } -#endif - phase->igvn().replace_input_of(this, MemNode::Memory, new_mem); - } - return; - } - if (mem->is_Phi()) { - phis.push(mem); - } - mem = next_mem(mem, alias); - if (mem->bottom_type() == Type::MEMORY) { - candidate = mem; - } - assert(is_dominator(phase->ctrl_or_self(mem), n_ctrl, mem, this, phase) == phase->is_dominator(phase->ctrl_or_self(mem), n_ctrl), "strange dominator"); -#ifdef ASSERT - if (trace) { tty->print("Next mem is"); mem->dump(); } -#endif - } while (mem->bottom_type() != Type::MEMORY || !phase->is_dominator(phase->ctrl_or_self(mem), n_ctrl)); - - assert(mem->bottom_type() == Type::MEMORY, "bad mem"); - - bool not_dom = false; - for (uint i = 0; i < phis.size() && !not_dom; i++) { - Node* nn = phis.at(i); - -#ifdef ASSERT - if (trace) { tty->print("Looking from phi"); nn->dump(); } -#endif - assert(nn->is_Phi(), "phis only"); - for (uint j = 2; j < nn->req() && !not_dom; j++) { - Node* m = nn->in(j); -#ifdef ASSERT - if (trace) { tty->print("Input %d is", j); m->dump(); } -#endif - while (m != mem && !seen.test_set(m->_idx)) { - if (is_dominator(phase->ctrl_or_self(m), phase->ctrl_or_self(mem), m, mem, phase)) { - not_dom = true; - // Scheduling anomaly -#ifdef ASSERT - if (trace) { tty->print("Giving up"); m->dump(); } -#endif - break; - } - if (!is_independent(m)) { - if (trace) { tty->print_cr("Not independent"); } - if (new_mem != in(MemNode::Memory)) { -#ifdef ASSERT - if (trace) { tty->print("XXX Setting mem to"); new_mem->dump(); tty->print(" for "); dump(); } -#endif - phase->igvn().replace_input_of(this, MemNode::Memory, new_mem); - } - return; - } - if (m->is_Phi()) { - phis.push(m); - } - m = next_mem(m, alias); -#ifdef ASSERT - if (trace) { tty->print("Next mem is"); m->dump(); } -#endif - } - } - } - if (!not_dom) { - new_mem = mem; - phis.clear(); - } else { - seen.Clear(); - } - } -} - -CallStaticJavaNode* ShenandoahWriteBarrierNode::pin_and_expand_null_check(PhaseIterGVN& igvn) { - Node* val = in(ValueIn); - - const Type* val_t = igvn.type(val); - - if (val_t->meet(TypePtr::NULL_PTR) != val_t && - val->Opcode() == Op_CastPP && - val->in(0) != NULL && - val->in(0)->Opcode() == Op_IfTrue && - val->in(0)->as_Proj()->is_uncommon_trap_if_pattern(Deoptimization::Reason_none) && - val->in(0)->in(0)->is_If() && - val->in(0)->in(0)->in(1)->Opcode() == Op_Bool && - val->in(0)->in(0)->in(1)->as_Bool()->_test._test == BoolTest::ne && - val->in(0)->in(0)->in(1)->in(1)->Opcode() == Op_CmpP && - val->in(0)->in(0)->in(1)->in(1)->in(1) == val->in(1) && - val->in(0)->in(0)->in(1)->in(1)->in(2)->bottom_type() == TypePtr::NULL_PTR) { - assert(val->in(0)->in(0)->in(1)->in(1)->in(1) == val->in(1), ""); - CallStaticJavaNode* unc = val->in(0)->as_Proj()->is_uncommon_trap_if_pattern(Deoptimization::Reason_none); - return unc; - } - return NULL; -} - -void ShenandoahWriteBarrierNode::pin_and_expand_move_barrier(PhaseIdealLoop* phase, GrowableArray& memory_graph_fixers, Unique_Node_List& uses) { - Node* unc = pin_and_expand_null_check(phase->igvn()); - Node* val = in(ValueIn); - - if (unc != NULL) { - Node* ctrl = phase->get_ctrl(this); - Node* unc_ctrl = val->in(0); - - // Don't move write barrier in a loop - IdealLoopTree* loop = phase->get_loop(ctrl); - IdealLoopTree* unc_loop = phase->get_loop(unc_ctrl); - - if (!unc_loop->is_member(loop)) { - return; - } - - Node* branch = no_branches(ctrl, unc_ctrl, false, phase); - assert(branch == NULL || branch == NodeSentinel, "was not looking for a branch"); - if (branch == NodeSentinel) { - return; - } - - RegionNode* r = new RegionNode(3); - IfNode* iff = unc_ctrl->in(0)->as_If(); - - Node* ctrl_use = unc_ctrl->unique_ctrl_out(); - Node* unc_ctrl_clone = unc_ctrl->clone(); - phase->register_control(unc_ctrl_clone, loop, iff); - Node* c = unc_ctrl_clone; - Node* new_cast = clone_null_check(c, val, unc_ctrl_clone, phase); - r->init_req(1, new_cast->in(0)->in(0)->as_If()->proj_out(0)); - - phase->igvn().replace_input_of(unc_ctrl, 0, c->in(0)); - phase->set_idom(unc_ctrl, c->in(0), phase->dom_depth(unc_ctrl)); - phase->lazy_replace(c, unc_ctrl); - c = NULL;; - phase->igvn().replace_input_of(val, 0, unc_ctrl_clone); - phase->set_ctrl(val, unc_ctrl_clone); - - IfNode* new_iff = new_cast->in(0)->in(0)->as_If(); - fix_null_check(unc, unc_ctrl_clone, r, uses, phase); - Node* iff_proj = iff->proj_out(0); - r->init_req(2, iff_proj); - phase->register_control(r, phase->ltree_root(), iff); - - Node* new_bol = new_iff->in(1)->clone(); - Node* new_cmp = new_bol->in(1)->clone(); - assert(new_cmp->Opcode() == Op_CmpP, "broken"); - assert(new_cmp->in(1) == val->in(1), "broken"); - new_bol->set_req(1, new_cmp); - new_cmp->set_req(1, this); - phase->register_new_node(new_bol, new_iff->in(0)); - phase->register_new_node(new_cmp, new_iff->in(0)); - phase->igvn().replace_input_of(new_iff, 1, new_bol); - phase->igvn().replace_input_of(new_cast, 1, this); - - for (DUIterator_Fast imax, i = this->fast_outs(imax); i < imax; i++) { - Node* u = this->fast_out(i); - if (u == new_cast || u->Opcode() == Op_ShenandoahWBMemProj || u == new_cmp) { - continue; - } - phase->igvn().rehash_node_delayed(u); - int nb = u->replace_edge(this, new_cast); - assert(nb > 0, "no update?"); - --i; imax -= nb; - } - - for (DUIterator_Fast imax, i = val->fast_outs(imax); i < imax; i++) { - Node* u = val->fast_out(i); - if (u == this) { - continue; - } - phase->igvn().rehash_node_delayed(u); - int nb = u->replace_edge(val, new_cast); - assert(nb > 0, "no update?"); - --i; imax -= nb; - } - - Node* new_ctrl = unc_ctrl_clone; - - int alias = phase->C->get_alias_index(adr_type()); - MemoryGraphFixer* fixer = find_fixer(memory_graph_fixers, alias); - if (fixer == NULL) { - fixer = create_fixer(memory_graph_fixers, alias, phase, true); - } - - Node* proj = find_out_with(Op_ShenandoahWBMemProj); - fixer->remove(proj); - Node* mem = fixer->find_mem(new_ctrl, NULL); - - if (in(Memory) != mem) { - disconnect_barrier_mem(this, phase->igvn()); - phase->igvn().replace_input_of(this, Memory, mem); - } - - phase->set_ctrl_and_loop(this, new_ctrl); - phase->igvn().replace_input_of(this, Control, new_ctrl); - phase->set_ctrl_and_loop(proj, new_ctrl); - - fixer->fix_mem(new_ctrl, new_ctrl, mem, mem, proj, uses); - } -} - -void ShenandoahWriteBarrierNode::pin_and_expand_helper(PhaseIdealLoop* phase) { - Node* val = in(ValueIn); - CallStaticJavaNode* unc = pin_and_expand_null_check(phase->igvn()); - Node* rep = this; - Node* ctrl = phase->get_ctrl(this); - if (unc != NULL && val->in(0) == ctrl) { - Node* unc_ctrl = val->in(0); - IfNode* other_iff = unc_ctrl->unique_ctrl_out()->as_If(); - ProjNode* other_unc_ctrl = other_iff->proj_out(1); - Node* cast = NULL; - for (DUIterator_Fast imax, i = other_unc_ctrl->fast_outs(imax); i < imax && cast == NULL; i++) { - Node* u = other_unc_ctrl->fast_out(i); - if (u->Opcode() == Op_CastPP && u->in(1) == this) { - cast = u; - } - } - assert(other_unc_ctrl->is_uncommon_trap_if_pattern(Deoptimization::Reason_none) == unc, "broken"); - rep = cast; - } - - // Replace all uses of barrier's input that are dominated by ctrl - // with the value returned by the barrier: no need to keep both - // live. - for (DUIterator_Fast imax, i = val->fast_outs(imax); i < imax; i++) { - Node* u = val->fast_out(i); - if (u != this) { - if (u->is_Phi()) { - int nb = 0; - for (uint j = 1; j < u->req(); j++) { - if (u->in(j) == val) { - Node* c = u->in(0)->in(j); - if (phase->is_dominator(ctrl, c)) { - phase->igvn().replace_input_of(u, j, rep); - nb++; - } - } - } - if (nb > 0) { - imax -= nb; - --i; - } - } else { - Node* c = phase->ctrl_or_self(u); - if (is_dominator(ctrl, c, this, u, phase)) { - phase->igvn().rehash_node_delayed(u); - int nb = u->replace_edge(val, rep); - assert(nb > 0, "no update?"); - --i, imax -= nb; - } - } - } - } -} - -Node* ShenandoahWriteBarrierNode::find_bottom_mem(Node* ctrl, PhaseIdealLoop* phase) { +Node* ShenandoahBarrierC2Support::find_bottom_mem(Node* ctrl, PhaseIdealLoop* phase) { Node* mem = NULL; Node* c = ctrl; do { @@ -2355,7 +914,7 @@ Node* ShenandoahWriteBarrierNode::find_bottom_mem(Node* ctrl, PhaseIdealLoop* ph return mem; } -void ShenandoahWriteBarrierNode::follow_barrier_uses(Node* n, Node* ctrl, Unique_Node_List& uses, PhaseIdealLoop* phase) { +void ShenandoahBarrierC2Support::follow_barrier_uses(Node* n, Node* ctrl, Unique_Node_List& uses, PhaseIdealLoop* phase) { for (DUIterator_Fast imax, i = n->fast_outs(imax); i < imax; i++) { Node* u = n->fast_out(i); if (!u->is_CFG() && phase->get_ctrl(u) == ctrl && (!u->is_Phi() || !u->in(0)->is_Loop() || u->in(LoopNode::LoopBackControl) != n)) { @@ -2375,7 +934,7 @@ static void hide_strip_mined_loop(OuterStripMinedLoopNode* outer, CountedLoopNod inner->clear_strip_mined(); } -void ShenandoahWriteBarrierNode::test_heap_stable(Node*& ctrl, Node* raw_mem, Node*& heap_stable_ctrl, +void ShenandoahBarrierC2Support::test_heap_stable(Node*& ctrl, Node* raw_mem, Node*& heap_stable_ctrl, PhaseIdealLoop* phase) { IdealLoopTree* loop = phase->get_loop(ctrl); Node* thread = new ThreadLocalNode(); @@ -2407,7 +966,7 @@ void ShenandoahWriteBarrierNode::test_heap_stable(Node*& ctrl, Node* raw_mem, No assert(is_heap_stable_test(heap_stable_iff), "Should match the shape"); } -void ShenandoahWriteBarrierNode::test_null(Node*& ctrl, Node* val, Node*& null_ctrl, PhaseIdealLoop* phase) { +void ShenandoahBarrierC2Support::test_null(Node*& ctrl, Node* val, Node*& null_ctrl, PhaseIdealLoop* phase) { const Type* val_t = phase->igvn().type(val); if (val_t->meet(TypePtr::NULL_PTR) == val_t) { IdealLoopTree* loop = phase->get_loop(ctrl); @@ -2424,7 +983,7 @@ void ShenandoahWriteBarrierNode::test_null(Node*& ctrl, Node* val, Node*& null_c } } -Node* ShenandoahWriteBarrierNode::clone_null_check(Node*& c, Node* val, Node* unc_ctrl, PhaseIdealLoop* phase) { +Node* ShenandoahBarrierC2Support::clone_null_check(Node*& c, Node* val, Node* unc_ctrl, PhaseIdealLoop* phase) { IdealLoopTree *loop = phase->get_loop(c); Node* iff = unc_ctrl->in(0); assert(iff->is_If(), "broken"); @@ -2445,7 +1004,7 @@ Node* ShenandoahWriteBarrierNode::clone_null_check(Node*& c, Node* val, Node* un return val; } -void ShenandoahWriteBarrierNode::fix_null_check(Node* unc, Node* unc_ctrl, Node* new_unc_ctrl, +void ShenandoahBarrierC2Support::fix_null_check(Node* unc, Node* unc_ctrl, Node* new_unc_ctrl, Unique_Node_List& uses, PhaseIdealLoop* phase) { IfNode* iff = unc_ctrl->in(0)->as_If(); Node* proj = iff->proj_out(0); @@ -2494,7 +1053,7 @@ void ShenandoahWriteBarrierNode::fix_null_check(Node* unc, Node* unc_ctrl, Node* assert(nb == 1, "only use expected"); } -void ShenandoahWriteBarrierNode::in_cset_fast_test(Node*& ctrl, Node*& not_cset_ctrl, Node* val, Node* raw_mem, PhaseIdealLoop* phase) { +void ShenandoahBarrierC2Support::in_cset_fast_test(Node*& ctrl, Node*& not_cset_ctrl, Node* val, Node* raw_mem, PhaseIdealLoop* phase) { IdealLoopTree *loop = phase->get_loop(ctrl); Node* raw_rbtrue = new CastP2XNode(ctrl, val); phase->register_new_node(raw_rbtrue, ctrl); @@ -2523,23 +1082,18 @@ void ShenandoahWriteBarrierNode::in_cset_fast_test(Node*& ctrl, Node*& not_cset_ phase->register_control(ctrl, loop, in_cset_fast_test_iff); } -void ShenandoahWriteBarrierNode::call_wb_stub(Node*& ctrl, Node*& val, Node*& result_mem, - Node* raw_mem, Node* wb_mem, - int alias, - PhaseIdealLoop* phase) { +void ShenandoahBarrierC2Support::call_lrb_stub(Node*& ctrl, Node*& val, Node*& result_mem, Node* raw_mem, PhaseIdealLoop* phase) { IdealLoopTree*loop = phase->get_loop(ctrl); const TypePtr* obj_type = phase->igvn().type(val)->is_oopptr()->cast_to_nonconst(); // The slow path stub consumes and produces raw memory in addition // to the existing memory edges Node* base = find_bottom_mem(ctrl, phase); - MergeMemNode* mm = MergeMemNode::make(base); - mm->set_memory_at(alias, wb_mem); mm->set_memory_at(Compile::AliasIdxRaw, raw_mem); phase->register_new_node(mm, ctrl); - Node* call = new CallLeafNode(ShenandoahBarrierSetC2::shenandoah_write_barrier_Type(), CAST_FROM_FN_PTR(address, ShenandoahRuntime::write_barrier_JRT), "shenandoah_write_barrier", TypeRawPtr::BOTTOM); + Node* call = new CallLeafNode(ShenandoahBarrierSetC2::shenandoah_write_barrier_Type(), CAST_FROM_FN_PTR(address, ShenandoahRuntime::load_reference_barrier_JRT), "shenandoah_write_barrier", TypeRawPtr::BOTTOM); call->init_req(TypeFunc::Control, ctrl); call->init_req(TypeFunc::I_O, phase->C->top()); call->init_req(TypeFunc::Memory, mm); @@ -2557,7 +1111,7 @@ void ShenandoahWriteBarrierNode::call_wb_stub(Node*& ctrl, Node*& val, Node*& re phase->register_new_node(val, ctrl); } -void ShenandoahWriteBarrierNode::fix_ctrl(Node* barrier, Node* region, const MemoryGraphFixer& fixer, Unique_Node_List& uses, Unique_Node_List& uses_to_ignore, uint last, PhaseIdealLoop* phase) { +void ShenandoahBarrierC2Support::fix_ctrl(Node* barrier, Node* region, const MemoryGraphFixer& fixer, Unique_Node_List& uses, Unique_Node_List& uses_to_ignore, uint last, PhaseIdealLoop* phase) { Node* ctrl = phase->get_ctrl(barrier); Node* init_raw_mem = fixer.find_mem(ctrl, barrier); @@ -2610,26 +1164,32 @@ void ShenandoahWriteBarrierNode::fix_ctrl(Node* barrier, Node* region, const Mem } } -void ShenandoahWriteBarrierNode::pin_and_expand(PhaseIdealLoop* phase) { - Node_List enqueue_barriers; - if (ShenandoahStoreValEnqueueBarrier) { - Unique_Node_List wq; - wq.push(phase->C->root()); - for (uint i = 0; i < wq.size(); i++) { - Node* n = wq.at(i); - if (n->Opcode() == Op_ShenandoahEnqueueBarrier) { - enqueue_barriers.push(n); - } - for (uint i = 0; i < n->req(); i++) { - Node* in = n->in(i); - if (in != NULL) { - wq.push(in); - } - } +static Node* create_phis_on_call_return(Node* ctrl, Node* c, Node* n, Node* n_clone, const CallProjections& projs, PhaseIdealLoop* phase) { + Node* region = NULL; + while (c != ctrl) { + if (c->is_Region()) { + region = c; + } + c = phase->idom(c); + } + assert(region != NULL, ""); + Node* phi = new PhiNode(region, n->bottom_type()); + for (uint j = 1; j < region->req(); j++) { + Node* in = region->in(j); + if (phase->is_dominator(projs.fallthrough_catchproj, in)) { + phi->init_req(j, n); + } else if (phase->is_dominator(projs.catchall_catchproj, in)) { + phi->init_req(j, n_clone); + } else { + phi->init_req(j, create_phis_on_call_return(ctrl, in, n, n_clone, projs, phase)); } } + phase->register_new_node(phi, region); + return phi; +} - const bool trace = false; +void ShenandoahBarrierC2Support::pin_and_expand(PhaseIdealLoop* phase) { + ShenandoahBarrierSetC2State* state = ShenandoahBarrierSetC2::bsc2()->state(); // Collect raw memory state at CFG points in the entire graph and // record it in memory_nodes. Optimize the raw memory graph in the @@ -2637,34 +1197,9 @@ void ShenandoahWriteBarrierNode::pin_and_expand(PhaseIdealLoop* phase) { // simpler. GrowableArray memory_graph_fixers; - // Let's try to common write barriers again - optimize_before_expansion(phase, memory_graph_fixers, true); - Unique_Node_List uses; - for (int i = 0; i < ShenandoahBarrierSetC2::bsc2()->state()->shenandoah_barriers_count(); i++) { - ShenandoahWriteBarrierNode* wb = ShenandoahBarrierSetC2::bsc2()->state()->shenandoah_barrier(i); - Node* ctrl = phase->get_ctrl(wb); - - Node* val = wb->in(ValueIn); - if (ctrl->is_Proj() && ctrl->in(0)->is_CallJava()) { - assert(is_dominator(phase->get_ctrl(val), ctrl->in(0)->in(0), val, ctrl->in(0), phase), "can't move"); - phase->set_ctrl(wb, ctrl->in(0)->in(0)); - } else if (ctrl->is_CallRuntime()) { - assert(is_dominator(phase->get_ctrl(val), ctrl->in(0), val, ctrl, phase), "can't move"); - phase->set_ctrl(wb, ctrl->in(0)); - } - - assert(wb->Opcode() == Op_ShenandoahWriteBarrier, "only for write barriers"); - // Look for a null check that dominates this barrier and move the - // barrier right after the null check to enable implicit null - // checks - wb->pin_and_expand_move_barrier(phase, memory_graph_fixers, uses); - - wb->pin_and_expand_helper(phase); - } - - for (uint i = 0; i < enqueue_barriers.size(); i++) { - Node* barrier = enqueue_barriers.at(i); + for (int i = 0; i < state->enqueue_barriers_count(); i++) { + Node* barrier = state->enqueue_barrier(i); Node* ctrl = phase->get_ctrl(barrier); IdealLoopTree* loop = phase->get_loop(ctrl); if (loop->_head->is_OuterStripMinedLoop()) { @@ -2676,24 +1211,386 @@ void ShenandoahWriteBarrierNode::pin_and_expand(PhaseIdealLoop* phase) { } } - for (int i = ShenandoahBarrierSetC2::bsc2()->state()->shenandoah_barriers_count(); i > 0; i--) { - int cnt = ShenandoahBarrierSetC2::bsc2()->state()->shenandoah_barriers_count(); - ShenandoahWriteBarrierNode* wb = ShenandoahBarrierSetC2::bsc2()->state()->shenandoah_barrier(i-1); - Node* ctrl = phase->get_ctrl(wb); - IdealLoopTree* loop = phase->get_loop(ctrl); - if (loop->_head->is_OuterStripMinedLoop()) { - // Expanding a barrier here will break loop strip mining - // verification. Transform the loop so the loop nest doesn't - // appear as strip mined. - OuterStripMinedLoopNode* outer = loop->_head->as_OuterStripMinedLoop(); - hide_strip_mined_loop(outer, outer->unique_ctrl_out()->as_CountedLoop(), phase); + Node_Stack stack(0); + Node_List clones; + for (int i = state->load_reference_barriers_count() - 1; i >= 0; i--) { + ShenandoahLoadReferenceBarrierNode* lrb = state->load_reference_barrier(i); + if (lrb->get_barrier_strength() == ShenandoahLoadReferenceBarrierNode::NONE) { + continue; + } + + Node* ctrl = phase->get_ctrl(lrb); + Node* val = lrb->in(ShenandoahLoadReferenceBarrierNode::ValueIn); + + CallStaticJavaNode* unc = NULL; + Node* unc_ctrl = NULL; + Node* uncasted_val = val; + + for (DUIterator_Fast imax, i = lrb->fast_outs(imax); i < imax; i++) { + Node* u = lrb->fast_out(i); + if (u->Opcode() == Op_CastPP && + u->in(0) != NULL && + phase->is_dominator(u->in(0), ctrl)) { + const Type* u_t = phase->igvn().type(u); + + if (u_t->meet(TypePtr::NULL_PTR) != u_t && + u->in(0)->Opcode() == Op_IfTrue && + u->in(0)->as_Proj()->is_uncommon_trap_if_pattern(Deoptimization::Reason_none) && + u->in(0)->in(0)->is_If() && + u->in(0)->in(0)->in(1)->Opcode() == Op_Bool && + u->in(0)->in(0)->in(1)->as_Bool()->_test._test == BoolTest::ne && + u->in(0)->in(0)->in(1)->in(1)->Opcode() == Op_CmpP && + u->in(0)->in(0)->in(1)->in(1)->in(1) == val && + u->in(0)->in(0)->in(1)->in(1)->in(2)->bottom_type() == TypePtr::NULL_PTR) { + IdealLoopTree* loop = phase->get_loop(ctrl); + IdealLoopTree* unc_loop = phase->get_loop(u->in(0)); + + if (!unc_loop->is_member(loop)) { + continue; + } + + Node* branch = no_branches(ctrl, u->in(0), false, phase); + assert(branch == NULL || branch == NodeSentinel, "was not looking for a branch"); + if (branch == NodeSentinel) { + continue; + } + + phase->igvn().replace_input_of(u, 1, val); + phase->igvn().replace_input_of(lrb, ShenandoahLoadReferenceBarrierNode::ValueIn, u); + phase->set_ctrl(u, u->in(0)); + phase->set_ctrl(lrb, u->in(0)); + unc = u->in(0)->as_Proj()->is_uncommon_trap_if_pattern(Deoptimization::Reason_none); + unc_ctrl = u->in(0); + val = u; + + for (DUIterator_Fast jmax, j = val->fast_outs(jmax); j < jmax; j++) { + Node* u = val->fast_out(j); + if (u == lrb) continue; + phase->igvn().rehash_node_delayed(u); + int nb = u->replace_edge(val, lrb); + --j; jmax -= nb; + } + + RegionNode* r = new RegionNode(3); + IfNode* iff = unc_ctrl->in(0)->as_If(); + + Node* ctrl_use = unc_ctrl->unique_ctrl_out(); + Node* unc_ctrl_clone = unc_ctrl->clone(); + phase->register_control(unc_ctrl_clone, loop, iff); + Node* c = unc_ctrl_clone; + Node* new_cast = clone_null_check(c, val, unc_ctrl_clone, phase); + r->init_req(1, new_cast->in(0)->in(0)->as_If()->proj_out(0)); + + phase->igvn().replace_input_of(unc_ctrl, 0, c->in(0)); + phase->set_idom(unc_ctrl, c->in(0), phase->dom_depth(unc_ctrl)); + phase->lazy_replace(c, unc_ctrl); + c = NULL;; + phase->igvn().replace_input_of(val, 0, unc_ctrl_clone); + phase->set_ctrl(val, unc_ctrl_clone); + + IfNode* new_iff = new_cast->in(0)->in(0)->as_If(); + fix_null_check(unc, unc_ctrl_clone, r, uses, phase); + Node* iff_proj = iff->proj_out(0); + r->init_req(2, iff_proj); + phase->register_control(r, phase->ltree_root(), iff); + + Node* new_bol = new_iff->in(1)->clone(); + Node* new_cmp = new_bol->in(1)->clone(); + assert(new_cmp->Opcode() == Op_CmpP, "broken"); + assert(new_cmp->in(1) == val->in(1), "broken"); + new_bol->set_req(1, new_cmp); + new_cmp->set_req(1, lrb); + phase->register_new_node(new_bol, new_iff->in(0)); + phase->register_new_node(new_cmp, new_iff->in(0)); + phase->igvn().replace_input_of(new_iff, 1, new_bol); + phase->igvn().replace_input_of(new_cast, 1, lrb); + + for (DUIterator_Fast imax, i = lrb->fast_outs(imax); i < imax; i++) { + Node* u = lrb->fast_out(i); + if (u == new_cast || u == new_cmp) { + continue; + } + phase->igvn().rehash_node_delayed(u); + int nb = u->replace_edge(lrb, new_cast); + assert(nb > 0, "no update?"); + --i; imax -= nb; + } + + for (DUIterator_Fast imax, i = val->fast_outs(imax); i < imax; i++) { + Node* u = val->fast_out(i); + if (u == lrb) { + continue; + } + phase->igvn().rehash_node_delayed(u); + int nb = u->replace_edge(val, new_cast); + assert(nb > 0, "no update?"); + --i; imax -= nb; + } + + ctrl = unc_ctrl_clone; + phase->set_ctrl_and_loop(lrb, ctrl); + break; + } + } + } + if (ctrl->is_Proj() && ctrl->in(0)->is_CallJava()) { + CallNode* call = ctrl->in(0)->as_CallJava(); + CallProjections projs; + call->extract_projections(&projs, false, false); + + Node* lrb_clone = lrb->clone(); + phase->register_new_node(lrb_clone, projs.catchall_catchproj); + phase->set_ctrl(lrb, projs.fallthrough_catchproj); + + stack.push(lrb, 0); + clones.push(lrb_clone); + + do { + assert(stack.size() == clones.size(), ""); + Node* n = stack.node(); +#ifdef ASSERT + if (n->is_Load()) { + Node* mem = n->in(MemNode::Memory); + for (DUIterator_Fast jmax, j = mem->fast_outs(jmax); j < jmax; j++) { + Node* u = mem->fast_out(j); + assert(!u->is_Store() || !u->is_LoadStore() || phase->get_ctrl(u) != ctrl, "anti dependent store?"); + } + } +#endif + uint idx = stack.index(); + Node* n_clone = clones.at(clones.size()-1); + if (idx < n->outcnt()) { + Node* u = n->raw_out(idx); + Node* c = phase->ctrl_or_self(u); + if (c == ctrl) { + stack.set_index(idx+1); + assert(!u->is_CFG(), ""); + stack.push(u, 0); + Node* u_clone = u->clone(); + int nb = u_clone->replace_edge(n, n_clone); + assert(nb > 0, "should have replaced some uses"); + phase->register_new_node(u_clone, projs.catchall_catchproj); + clones.push(u_clone); + phase->set_ctrl(u, projs.fallthrough_catchproj); + } else { + bool replaced = false; + if (u->is_Phi()) { + for (uint k = 1; k < u->req(); k++) { + if (u->in(k) == n) { + if (phase->is_dominator(projs.catchall_catchproj, u->in(0)->in(k))) { + phase->igvn().replace_input_of(u, k, n_clone); + replaced = true; + } else if (!phase->is_dominator(projs.fallthrough_catchproj, u->in(0)->in(k))) { + phase->igvn().replace_input_of(u, k, create_phis_on_call_return(ctrl, u->in(0)->in(k), n, n_clone, projs, phase)); + replaced = true; + } + } + } + } else { + if (phase->is_dominator(projs.catchall_catchproj, c)) { + phase->igvn().rehash_node_delayed(u); + int nb = u->replace_edge(n, n_clone); + assert(nb > 0, "should have replaced some uses"); + replaced = true; + } else if (!phase->is_dominator(projs.fallthrough_catchproj, c)) { + phase->igvn().rehash_node_delayed(u); + int nb = u->replace_edge(n, create_phis_on_call_return(ctrl, c, n, n_clone, projs, phase)); + assert(nb > 0, "should have replaced some uses"); + replaced = true; + } + } + if (!replaced) { + stack.set_index(idx+1); + } + } + } else { + // assert(n_clone->outcnt() > 0, ""); + // assert(n->outcnt() > 0, ""); + stack.pop(); + clones.pop(); + } + } while (stack.size() > 0); + assert(stack.size() == 0 && clones.size() == 0, ""); + ctrl = projs.fallthrough_catchproj; } } + // Expand load-reference-barriers MemoryGraphFixer fixer(Compile::AliasIdxRaw, true, phase); Unique_Node_List uses_to_ignore; - for (uint i = 0; i < enqueue_barriers.size(); i++) { - Node* barrier = enqueue_barriers.at(i); + for (int i = state->load_reference_barriers_count() - 1; i >= 0; i--) { + ShenandoahLoadReferenceBarrierNode* lrb = state->load_reference_barrier(i); + if (lrb->get_barrier_strength() == ShenandoahLoadReferenceBarrierNode::NONE) { + phase->igvn().replace_node(lrb, lrb->in(ShenandoahLoadReferenceBarrierNode::ValueIn)); + continue; + } + uint last = phase->C->unique(); + Node* ctrl = phase->get_ctrl(lrb); + Node* val = lrb->in(ShenandoahLoadReferenceBarrierNode::ValueIn); + + + Node* orig_ctrl = ctrl; + + Node* raw_mem = fixer.find_mem(ctrl, lrb); + Node* init_raw_mem = raw_mem; + Node* raw_mem_for_ctrl = fixer.find_mem(ctrl, NULL); + // int alias = phase->C->get_alias_index(lrb->adr_type()); + + IdealLoopTree *loop = phase->get_loop(ctrl); + CallStaticJavaNode* unc = lrb->pin_and_expand_null_check(phase->igvn()); + Node* unc_ctrl = NULL; + if (unc != NULL) { + if (val->in(ShenandoahLoadReferenceBarrierNode::Control) != ctrl) { + unc = NULL; + } else { + unc_ctrl = val->in(ShenandoahLoadReferenceBarrierNode::Control); + } + } + + Node* uncasted_val = val; + if (unc != NULL) { + uncasted_val = val->in(1); + } + + Node* heap_stable_ctrl = NULL; + Node* null_ctrl = NULL; + + assert(val->bottom_type()->make_oopptr(), "need oop"); + assert(val->bottom_type()->make_oopptr()->const_oop() == NULL, "expect non-constant"); + + enum { _heap_stable = 1, _not_cset, _not_equal, _evac_path, _null_path, PATH_LIMIT }; + Node* region = new RegionNode(PATH_LIMIT); + Node* val_phi = new PhiNode(region, uncasted_val->bottom_type()->is_oopptr()); + Node* raw_mem_phi = PhiNode::make(region, raw_mem, Type::MEMORY, TypeRawPtr::BOTTOM); + + // Stable path. + test_heap_stable(ctrl, raw_mem, heap_stable_ctrl, phase); + IfNode* heap_stable_iff = heap_stable_ctrl->in(0)->as_If(); + + // Heap stable case + region->init_req(_heap_stable, heap_stable_ctrl); + val_phi->init_req(_heap_stable, uncasted_val); + raw_mem_phi->init_req(_heap_stable, raw_mem); + + Node* reg2_ctrl = NULL; + // Null case + test_null(ctrl, val, null_ctrl, phase); + if (null_ctrl != NULL) { + reg2_ctrl = null_ctrl->in(0); + region->init_req(_null_path, null_ctrl); + val_phi->init_req(_null_path, uncasted_val); + raw_mem_phi->init_req(_null_path, raw_mem); + } else { + region->del_req(_null_path); + val_phi->del_req(_null_path); + raw_mem_phi->del_req(_null_path); + } + + // Test for in-cset. + // Wires !in_cset(obj) to slot 2 of region and phis + Node* not_cset_ctrl = NULL; + in_cset_fast_test(ctrl, not_cset_ctrl, uncasted_val, raw_mem, phase); + if (not_cset_ctrl != NULL) { + if (reg2_ctrl == NULL) reg2_ctrl = not_cset_ctrl->in(0); + region->init_req(_not_cset, not_cset_ctrl); + val_phi->init_req(_not_cset, uncasted_val); + raw_mem_phi->init_req(_not_cset, raw_mem); + } + + // Resolve object when orig-value is in cset. + // Make the unconditional resolve for fwdptr. + Node* new_val = uncasted_val; + if (unc_ctrl != NULL) { + // Clone the null check in this branch to allow implicit null check + new_val = clone_null_check(ctrl, val, unc_ctrl, phase); + fix_null_check(unc, unc_ctrl, ctrl->in(0)->as_If()->proj_out(0), uses, phase); + + IfNode* iff = unc_ctrl->in(0)->as_If(); + phase->igvn().replace_input_of(iff, 1, phase->igvn().intcon(1)); + } + Node* addr = new AddPNode(new_val, uncasted_val, phase->igvn().MakeConX(ShenandoahBrooksPointer::byte_offset())); + phase->register_new_node(addr, ctrl); + assert(val->bottom_type()->isa_oopptr(), "what else?"); + const TypePtr* obj_type = val->bottom_type()->is_oopptr(); + const TypePtr* adr_type = TypeRawPtr::BOTTOM; + Node* fwd = new LoadPNode(ctrl, raw_mem, addr, adr_type, obj_type, MemNode::unordered); + phase->register_new_node(fwd, ctrl); + + // Only branch to LRB stub if object is not forwarded; otherwise reply with fwd ptr + Node* cmp = new CmpPNode(fwd, new_val); + phase->register_new_node(cmp, ctrl); + Node* bol = new BoolNode(cmp, BoolTest::eq); + phase->register_new_node(bol, ctrl); + + IfNode* iff = new IfNode(ctrl, bol, PROB_UNLIKELY(0.999), COUNT_UNKNOWN); + if (reg2_ctrl == NULL) reg2_ctrl = iff; + phase->register_control(iff, loop, ctrl); + Node* if_not_eq = new IfFalseNode(iff); + phase->register_control(if_not_eq, loop, iff); + Node* if_eq = new IfTrueNode(iff); + phase->register_control(if_eq, loop, iff); + + // Wire up not-equal-path in slots 3. + region->init_req(_not_equal, if_not_eq); + val_phi->init_req(_not_equal, fwd); + raw_mem_phi->init_req(_not_equal, raw_mem); + + // Call wb-stub and wire up that path in slots 4 + Node* result_mem = NULL; + ctrl = if_eq; + call_lrb_stub(ctrl, fwd, result_mem, raw_mem, phase); + region->init_req(_evac_path, ctrl); + val_phi->init_req(_evac_path, fwd); + raw_mem_phi->init_req(_evac_path, result_mem); + + phase->register_control(region, loop, heap_stable_iff); + Node* out_val = val_phi; + phase->register_new_node(val_phi, region); + phase->register_new_node(raw_mem_phi, region); + + fix_ctrl(lrb, region, fixer, uses, uses_to_ignore, last, phase); + + ctrl = orig_ctrl; + + if (unc != NULL) { + for (DUIterator_Fast imax, i = val->fast_outs(imax); i < imax; i++) { + Node* u = val->fast_out(i); + Node* c = phase->ctrl_or_self(u); + if (u != lrb && (c != ctrl || is_dominator_same_ctrl(c, lrb, u, phase))) { + phase->igvn().rehash_node_delayed(u); + int nb = u->replace_edge(val, out_val); + --i, imax -= nb; + } + } + if (val->outcnt() == 0) { + phase->igvn()._worklist.push(val); + } + } + phase->igvn().replace_node(lrb, out_val); + + follow_barrier_uses(out_val, ctrl, uses, phase); + + for(uint next = 0; next < uses.size(); next++ ) { + Node *n = uses.at(next); + assert(phase->get_ctrl(n) == ctrl, "bad control"); + assert(n != init_raw_mem, "should leave input raw mem above the barrier"); + phase->set_ctrl(n, region); + follow_barrier_uses(n, ctrl, uses, phase); + } + + // The slow path call produces memory: hook the raw memory phi + // from the expanded load reference barrier with the rest of the graph + // which may require adding memory phis at every post dominated + // region and at enclosing loop heads. Use the memory state + // collected in memory_nodes to fix the memory graph. Update that + // memory state as we go. + fixer.fix_mem(ctrl, region, init_raw_mem, raw_mem_for_ctrl, raw_mem_phi, uses); + } + // Done expanding load-reference-barriers. + assert(ShenandoahBarrierSetC2::bsc2()->state()->load_reference_barriers_count() == 0, "all load reference barrier nodes should have been replaced"); + + for (int i = state->enqueue_barriers_count() - 1; i >= 0; i--) { + Node* barrier = state->enqueue_barrier(i); Node* pre_val = barrier->in(1); if (phase->igvn().type(pre_val)->higher_equal(TypePtr::NULL_PTR)) { @@ -2840,212 +1737,11 @@ void ShenandoahWriteBarrierNode::pin_and_expand(PhaseIdealLoop* phase) { phase->igvn().replace_node(barrier, pre_val); } + assert(state->enqueue_barriers_count() == 0, "all enqueue barrier nodes should have been replaced"); - for (int i = ShenandoahBarrierSetC2::bsc2()->state()->shenandoah_barriers_count(); i > 0; i--) { - int cnt = ShenandoahBarrierSetC2::bsc2()->state()->shenandoah_barriers_count(); - ShenandoahWriteBarrierNode* wb = ShenandoahBarrierSetC2::bsc2()->state()->shenandoah_barrier(i-1); - - uint last = phase->C->unique(); - Node* ctrl = phase->get_ctrl(wb); - Node* orig_ctrl = ctrl; - - Node* raw_mem = fixer.find_mem(ctrl, wb); - Node* init_raw_mem = raw_mem; - Node* raw_mem_for_ctrl = fixer.find_mem(ctrl, NULL); - int alias = phase->C->get_alias_index(wb->adr_type()); - Node* wb_mem = wb->in(Memory); - Node* init_wb_mem = wb_mem; - - Node* val = wb->in(ValueIn); - Node* wbproj = wb->find_out_with(Op_ShenandoahWBMemProj); - IdealLoopTree *loop = phase->get_loop(ctrl); - - assert(val->Opcode() != Op_ShenandoahWriteBarrier, "No chain of write barriers"); - - CallStaticJavaNode* unc = wb->pin_and_expand_null_check(phase->igvn()); - Node* unc_ctrl = NULL; - if (unc != NULL) { - if (val->in(0) != ctrl) { - unc = NULL; - } else { - unc_ctrl = val->in(0); - } - } - - Node* uncasted_val = val; - if (unc != NULL) { - uncasted_val = val->in(1); - } - - Node* heap_stable_ctrl = NULL; - Node* null_ctrl = NULL; - - assert(val->bottom_type()->make_oopptr(), "need oop"); - assert(val->bottom_type()->make_oopptr()->const_oop() == NULL, "expect non-constant"); - - enum { _heap_stable = 1, _heap_unstable, PATH_LIMIT }; - Node* region = new RegionNode(PATH_LIMIT); - Node* val_phi = new PhiNode(region, uncasted_val->bottom_type()->is_oopptr()); - Node* mem_phi = PhiNode::make(region, wb_mem, Type::MEMORY, phase->C->alias_type(wb->adr_type())->adr_type()); - Node* raw_mem_phi = PhiNode::make(region, raw_mem, Type::MEMORY, TypeRawPtr::BOTTOM); - - enum { _not_cset = 1, _not_equal, _evac_path, _null_path, PATH_LIMIT2 }; - Node* region2 = new RegionNode(PATH_LIMIT2); - Node* val_phi2 = new PhiNode(region2, uncasted_val->bottom_type()->is_oopptr()); - Node* mem_phi2 = PhiNode::make(region2, wb_mem, Type::MEMORY, phase->C->alias_type(wb->adr_type())->adr_type()); - Node* raw_mem_phi2 = PhiNode::make(region2, raw_mem, Type::MEMORY, TypeRawPtr::BOTTOM); - - // Stable path. - test_heap_stable(ctrl, raw_mem, heap_stable_ctrl, phase); - IfNode* heap_stable_iff = heap_stable_ctrl->in(0)->as_If(); - - // Heap stable case - region->init_req(_heap_stable, heap_stable_ctrl); - val_phi->init_req(_heap_stable, uncasted_val); - mem_phi->init_req(_heap_stable, wb_mem); - raw_mem_phi->init_req(_heap_stable, raw_mem); - - Node* reg2_ctrl = NULL; - // Null case - test_null(ctrl, val, null_ctrl, phase); - if (null_ctrl != NULL) { - reg2_ctrl = null_ctrl->in(0); - region2->init_req(_null_path, null_ctrl); - val_phi2->init_req(_null_path, uncasted_val); - mem_phi2->init_req(_null_path, wb_mem); - raw_mem_phi2->init_req(_null_path, raw_mem); - } else { - region2->del_req(_null_path); - val_phi2->del_req(_null_path); - mem_phi2->del_req(_null_path); - raw_mem_phi2->del_req(_null_path); - } - - // Test for in-cset. - // Wires !in_cset(obj) to slot 2 of region and phis - Node* not_cset_ctrl = NULL; - in_cset_fast_test(ctrl, not_cset_ctrl, uncasted_val, raw_mem, phase); - if (not_cset_ctrl != NULL) { - if (reg2_ctrl == NULL) reg2_ctrl = not_cset_ctrl->in(0); - region2->init_req(_not_cset, not_cset_ctrl); - val_phi2->init_req(_not_cset, uncasted_val); - mem_phi2->init_req(_not_cset, wb_mem); - raw_mem_phi2->init_req(_not_cset, raw_mem); - } - - // Resolve object when orig-value is in cset. - // Make the unconditional resolve for fwdptr, not the read barrier. - Node* new_val = uncasted_val; - if (unc_ctrl != NULL) { - // Clone the null check in this branch to allow implicit null check - new_val = clone_null_check(ctrl, val, unc_ctrl, phase); - fix_null_check(unc, unc_ctrl, ctrl->in(0)->as_If()->proj_out(0), uses, phase); - - IfNode* iff = unc_ctrl->in(0)->as_If(); - phase->igvn().replace_input_of(iff, 1, phase->igvn().intcon(1)); - } - Node* addr = new AddPNode(new_val, uncasted_val, phase->igvn().MakeConX(ShenandoahBrooksPointer::byte_offset())); - phase->register_new_node(addr, ctrl); - assert(val->bottom_type()->isa_oopptr(), "what else?"); - const TypePtr* obj_type = val->bottom_type()->is_oopptr(); - const TypePtr* adr_type = ShenandoahBarrierNode::brooks_pointer_type(obj_type); - Node* fwd = new LoadPNode(ctrl, wb_mem, addr, adr_type, obj_type, MemNode::unordered); - phase->register_new_node(fwd, ctrl); - - // Only branch to WB stub if object is not forwarded; otherwise reply with fwd ptr - Node* cmp = new CmpPNode(fwd, new_val); - phase->register_new_node(cmp, ctrl); - Node* bol = new BoolNode(cmp, BoolTest::eq); - phase->register_new_node(bol, ctrl); - - IfNode* iff = new IfNode(ctrl, bol, PROB_UNLIKELY(0.999), COUNT_UNKNOWN); - if (reg2_ctrl == NULL) reg2_ctrl = iff; - phase->register_control(iff, loop, ctrl); - Node* if_not_eq = new IfFalseNode(iff); - phase->register_control(if_not_eq, loop, iff); - Node* if_eq = new IfTrueNode(iff); - phase->register_control(if_eq, loop, iff); - - // Wire up not-equal-path in slots 3. - region2->init_req(_not_equal, if_not_eq); - val_phi2->init_req(_not_equal, fwd); - mem_phi2->init_req(_not_equal, wb_mem); - raw_mem_phi2->init_req(_not_equal, raw_mem); - - // Call wb-stub and wire up that path in slots 4 - Node* result_mem = NULL; - ctrl = if_eq; - call_wb_stub(ctrl, new_val, result_mem, - raw_mem, wb_mem, - alias, phase); - region2->init_req(_evac_path, ctrl); - val_phi2->init_req(_evac_path, new_val); - mem_phi2->init_req(_evac_path, result_mem); - raw_mem_phi2->init_req(_evac_path, result_mem); - - phase->register_control(region2, loop, reg2_ctrl); - phase->register_new_node(val_phi2, region2); - phase->register_new_node(mem_phi2, region2); - phase->register_new_node(raw_mem_phi2, region2); - - region->init_req(_heap_unstable, region2); - val_phi->init_req(_heap_unstable, val_phi2); - mem_phi->init_req(_heap_unstable, mem_phi2); - raw_mem_phi->init_req(_heap_unstable, raw_mem_phi2); - - phase->register_control(region, loop, heap_stable_iff); - Node* out_val = val_phi; - phase->register_new_node(val_phi, region); - phase->register_new_node(mem_phi, region); - phase->register_new_node(raw_mem_phi, region); - - fix_ctrl(wb, region, fixer, uses, uses_to_ignore, last, phase); - - ctrl = orig_ctrl; - - phase->igvn().replace_input_of(wbproj, ShenandoahWBMemProjNode::WriteBarrier, phase->C->top()); - phase->igvn().replace_node(wbproj, mem_phi); - if (unc != NULL) { - for (DUIterator_Fast imax, i = val->fast_outs(imax); i < imax; i++) { - Node* u = val->fast_out(i); - Node* c = phase->ctrl_or_self(u); - if (u != wb && (c != ctrl || is_dominator_same_ctrl(c, wb, u, phase))) { - phase->igvn().rehash_node_delayed(u); - int nb = u->replace_edge(val, out_val); - --i, imax -= nb; - } - } - if (val->outcnt() == 0) { - phase->igvn()._worklist.push(val); - } - } - phase->igvn().replace_node(wb, out_val); - - follow_barrier_uses(mem_phi, ctrl, uses, phase); - follow_barrier_uses(out_val, ctrl, uses, phase); - - for(uint next = 0; next < uses.size(); next++ ) { - Node *n = uses.at(next); - assert(phase->get_ctrl(n) == ctrl, "bad control"); - assert(n != init_raw_mem, "should leave input raw mem above the barrier"); - phase->set_ctrl(n, region); - follow_barrier_uses(n, ctrl, uses, phase); - } - - // The slow path call produces memory: hook the raw memory phi - // from the expanded write barrier with the rest of the graph - // which may require adding memory phis at every post dominated - // region and at enclosing loop heads. Use the memory state - // collected in memory_nodes to fix the memory graph. Update that - // memory state as we go. - fixer.fix_mem(ctrl, region, init_raw_mem, raw_mem_for_ctrl, raw_mem_phi, uses); - assert(ShenandoahBarrierSetC2::bsc2()->state()->shenandoah_barriers_count() == cnt - 1, "not replaced"); - } - - assert(ShenandoahBarrierSetC2::bsc2()->state()->shenandoah_barriers_count() == 0, "all write barrier nodes should have been replaced"); } -void ShenandoahWriteBarrierNode::move_heap_stable_test_out_of_loop(IfNode* iff, PhaseIdealLoop* phase) { +void ShenandoahBarrierC2Support::move_heap_stable_test_out_of_loop(IfNode* iff, PhaseIdealLoop* phase) { IdealLoopTree *loop = phase->get_loop(iff); Node* loop_head = loop->_head; Node* entry_c = loop_head->in(LoopNode::EntryControl); @@ -3078,7 +1774,7 @@ void ShenandoahWriteBarrierNode::move_heap_stable_test_out_of_loop(IfNode* iff, } } -bool ShenandoahWriteBarrierNode::identical_backtoback_ifs(Node *n, PhaseIdealLoop* phase) { +bool ShenandoahBarrierC2Support::identical_backtoback_ifs(Node* n, PhaseIdealLoop* phase) { if (!n->is_If() || n->is_CountedLoopEnd()) { return false; } @@ -3113,7 +1809,7 @@ bool ShenandoahWriteBarrierNode::identical_backtoback_ifs(Node *n, PhaseIdealLoo return true; } -void ShenandoahWriteBarrierNode::merge_back_to_back_tests(Node* n, PhaseIdealLoop* phase) { +void ShenandoahBarrierC2Support::merge_back_to_back_tests(Node* n, PhaseIdealLoop* phase) { assert(is_heap_stable_test(n), "no other tests"); if (identical_backtoback_ifs(n, phase)) { Node* n_ctrl = n->in(0); @@ -3149,7 +1845,7 @@ void ShenandoahWriteBarrierNode::merge_back_to_back_tests(Node* n, PhaseIdealLoo } } -IfNode* ShenandoahWriteBarrierNode::find_unswitching_candidate(const IdealLoopTree *loop, PhaseIdealLoop* phase) { +IfNode* ShenandoahBarrierC2Support::find_unswitching_candidate(const IdealLoopTree* loop, PhaseIdealLoop* phase) { // Find first invariant test that doesn't exit the loop LoopNode *head = loop->_head->as_Loop(); IfNode* unswitch_iff = NULL; @@ -3194,10 +1890,9 @@ IfNode* ShenandoahWriteBarrierNode::find_unswitching_candidate(const IdealLoopTr } -void ShenandoahWriteBarrierNode::optimize_after_expansion(VectorSet &visited, Node_Stack &stack, Node_List &old_new, PhaseIdealLoop* phase) { +void ShenandoahBarrierC2Support::optimize_after_expansion(VectorSet &visited, Node_Stack &stack, Node_List &old_new, PhaseIdealLoop* phase) { Node_List heap_stable_tests; Node_List gc_state_loads; - stack.push(phase->C->start(), 0); do { Node* n = stack.node(); @@ -3274,7 +1969,7 @@ void ShenandoahWriteBarrierNode::optimize_after_expansion(VectorSet &visited, No } #ifdef ASSERT -void ShenandoahBarrierNode::verify_raw_mem(RootNode* root) { +void ShenandoahBarrierC2Support::verify_raw_mem(RootNode* root) { const bool trace = false; ResourceMark rm; Unique_Node_List nodes; @@ -3372,6 +2067,10 @@ void ShenandoahBarrierNode::verify_raw_mem(RootNode* root) { } #endif +ShenandoahEnqueueBarrierNode::ShenandoahEnqueueBarrierNode(Node* val) : Node(NULL, val) { + ShenandoahBarrierSetC2::bsc2()->state()->add_enqueue_barrier(this); +} + const Type* ShenandoahEnqueueBarrierNode::bottom_type() const { if (in(1) == NULL || in(1)->is_top()) { return Type::TOP; @@ -3531,6 +2230,26 @@ void MemoryGraphFixer::collect_memory_nodes() { Node* call = in->in(0)->in(0); assert(call->is_Call(), ""); mem = call->in(TypeFunc::Memory); + } else if (in->Opcode() == Op_NeverBranch) { + ResourceMark rm; + Unique_Node_List wq; + wq.push(in); + wq.push(in->as_Multi()->proj_out(0)); + for (uint j = 1; j < wq.size(); j++) { + Node* c = wq.at(j); + assert(!c->is_Root(), "shouldn't leave loop"); + if (c->is_SafePoint()) { + assert(mem == NULL, "only one safepoint"); + mem = c->in(TypeFunc::Memory); + } + for (DUIterator_Fast kmax, k = c->fast_outs(kmax); k < kmax; k++) { + Node* u = c->fast_out(k); + if (u->is_CFG()) { + wq.push(u); + } + } + } + assert(mem != NULL, "should have found safepoint"); } } } else { @@ -3569,12 +2288,6 @@ void MemoryGraphFixer::collect_memory_nodes() { assert(_alias == Compile::AliasIdxRaw, ""); stack.push(mem, mem->req()); mem = mem->in(MemNode::Memory); - } else if (mem->Opcode() == Op_ShenandoahWriteBarrier) { - assert(_alias != Compile::AliasIdxRaw, ""); - mem = mem->in(ShenandoahBarrierNode::Memory); - } else if (mem->Opcode() == Op_ShenandoahWBMemProj) { - stack.push(mem, mem->req()); - mem = mem->in(ShenandoahWBMemProjNode::WriteBarrier); } else { #ifdef ASSERT mem->dump(); @@ -3628,7 +2341,7 @@ void MemoryGraphFixer::collect_memory_nodes() { while (progress) { progress = false; iteration++; - assert(iteration <= 2+max_depth || _phase->C->has_irreducible_loop(), ""); + assert(iteration <= 2+max_depth || _phase->C->has_irreducible_loop() || has_never_branch(_phase->C->root()), ""); if (trace) { tty->print_cr("XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"); } IdealLoopTree* last_updated_ilt = NULL; for (int i = rpo_list.size() - 1; i >= 0; i--) { @@ -3796,7 +2509,7 @@ Node* MemoryGraphFixer::find_mem(Node* ctrl, Node* n) const { mem = _memory_nodes[c->_idx]; } if (n != NULL && mem_is_valid(mem, c)) { - while (!ShenandoahWriteBarrierNode::is_dominator_same_ctrl(c, mem, n, _phase) && _phase->ctrl_or_self(mem) == ctrl) { + while (!ShenandoahBarrierC2Support::is_dominator_same_ctrl(c, mem, n, _phase) && _phase->ctrl_or_self(mem) == ctrl) { mem = next_mem(mem, _alias); } if (mem->is_MergeMem()) { @@ -3842,12 +2555,6 @@ void MemoryGraphFixer::fix_mem(Node* ctrl, Node* new_ctrl, Node* mem, Node* mem_ } else if (old->Opcode() == Op_SCMemProj) { assert(_alias == Compile::AliasIdxRaw, ""); old = old->in(0); - } else if (old->Opcode() == Op_ShenandoahWBMemProj) { - assert(_alias != Compile::AliasIdxRaw, ""); - old = old->in(ShenandoahWBMemProjNode::WriteBarrier); - } else if (old->Opcode() == Op_ShenandoahWriteBarrier) { - assert(_alias != Compile::AliasIdxRaw, ""); - old = old->in(ShenandoahBarrierNode::Memory); } else { ShouldNotReachHere(); } @@ -3857,7 +2564,7 @@ void MemoryGraphFixer::fix_mem(Node* ctrl, Node* new_ctrl, Node* mem, Node* mem_ _memory_nodes.map(ctrl->_idx, mem); _memory_nodes.map(new_ctrl->_idx, mem_for_ctrl); } - uint input = prev->Opcode() == Op_ShenandoahWriteBarrier ? (uint)ShenandoahBarrierNode::Memory : (uint)MemNode::Memory; + uint input = (uint)MemNode::Memory; _phase->igvn().replace_input_of(prev, input, new_mem); } else { uses.clear(); @@ -3925,19 +2632,14 @@ void MemoryGraphFixer::fix_mem(Node* ctrl, Node* new_ctrl, Node* mem, Node* mem_ } else { DEBUG_ONLY(if (trace) { tty->print("ZZZ NOT setting mem"); m->dump(); }); for (;;) { - assert(m->is_Mem() || m->is_LoadStore() || m->is_Proj() || m->Opcode() == Op_ShenandoahWriteBarrier || m->Opcode() == Op_ShenandoahWBMemProj, ""); + assert(m->is_Mem() || m->is_LoadStore() || m->is_Proj(), ""); Node* next = NULL; if (m->is_Proj()) { next = m->in(0); - } else if (m->Opcode() == Op_ShenandoahWBMemProj) { - next = m->in(ShenandoahWBMemProjNode::WriteBarrier); - } else if (m->is_Mem() || m->is_LoadStore()) { + } else { + assert(m->is_Mem() || m->is_LoadStore(), ""); assert(_alias == Compile::AliasIdxRaw, ""); next = m->in(MemNode::Memory); - } else { - assert(_alias != Compile::AliasIdxRaw, ""); - assert (m->Opcode() == Op_ShenandoahWriteBarrier, ""); - next = m->in(ShenandoahBarrierNode::Memory); } if (_phase->get_ctrl(next) != u) { break; @@ -3954,8 +2656,8 @@ void MemoryGraphFixer::fix_mem(Node* ctrl, Node* new_ctrl, Node* mem, Node* mem_ } DEBUG_ONLY(if (trace) { tty->print("ZZZ setting to phi"); m->dump(); }); - assert(m->is_Mem() || m->is_LoadStore() || m->Opcode() == Op_ShenandoahWriteBarrier, ""); - uint input = (m->is_Mem() || m->is_LoadStore()) ? (uint)MemNode::Memory : (uint)ShenandoahBarrierNode::Memory; + assert(m->is_Mem() || m->is_LoadStore(), ""); + uint input = (uint)MemNode::Memory; _phase->igvn().replace_input_of(m, input, phi); push = false; } @@ -4181,20 +2883,7 @@ void MemoryGraphFixer::fix_memory_uses(Node* mem, Node* replacement, Node* rep_p for (DUIterator i = mem->outs(); mem->has_out(i); i++) { Node* u = mem->out(i); if (u != replacement && u->_idx < last) { - if (u->is_ShenandoahBarrier() && _alias != Compile::AliasIdxRaw) { - if (_phase->C->get_alias_index(u->adr_type()) == _alias && ShenandoahWriteBarrierNode::is_dominator(rep_ctrl, _phase->ctrl_or_self(u), replacement, u, _phase)) { - _phase->igvn().replace_input_of(u, u->find_edge(mem), rep_proj); - assert(u->find_edge(mem) == -1, "only one edge"); - --i; - } - } else if (u->is_Mem()) { - if (_phase->C->get_alias_index(u->adr_type()) == _alias && ShenandoahWriteBarrierNode::is_dominator(rep_ctrl, _phase->ctrl_or_self(u), replacement, u, _phase)) { - assert(_alias == Compile::AliasIdxRaw , "only raw memory can lead to a memory operation"); - _phase->igvn().replace_input_of(u, u->find_edge(mem), rep_proj); - assert(u->find_edge(mem) == -1, "only one edge"); - --i; - } - } else if (u->is_MergeMem()) { + if (u->is_MergeMem()) { MergeMemNode* u_mm = u->as_MergeMem(); if (u_mm->memory_at(_alias) == mem) { MergeMemNode* newmm = NULL; @@ -4222,7 +2911,7 @@ void MemoryGraphFixer::fix_memory_uses(Node* mem, Node* replacement, Node* rep_p } } } else { - if (rep_ctrl != uu && ShenandoahWriteBarrierNode::is_dominator(rep_ctrl, _phase->ctrl_or_self(uu), replacement, uu, _phase)) { + if (rep_ctrl != uu && ShenandoahBarrierC2Support::is_dominator(rep_ctrl, _phase->ctrl_or_self(uu), replacement, uu, _phase)) { if (newmm == NULL) { newmm = clone_merge_mem(u, mem, rep_proj, rep_ctrl, i); } @@ -4263,10 +2952,11 @@ void MemoryGraphFixer::fix_memory_uses(Node* mem, Node* replacement, Node* rep_p u->Opcode() == Op_Rethrow || u->Opcode() == Op_Return || u->Opcode() == Op_SafePoint || + u->Opcode() == Op_StoreLConditional || (u->is_CallStaticJava() && u->as_CallStaticJava()->uncommon_trap_request() != 0) || (u->is_CallStaticJava() && u->as_CallStaticJava()->_entry_point == OptoRuntime::rethrow_stub()) || u->Opcode() == Op_CallLeaf, ""); - if (ShenandoahWriteBarrierNode::is_dominator(rep_ctrl, _phase->ctrl_or_self(u), replacement, u, _phase)) { + if (ShenandoahBarrierC2Support::is_dominator(rep_ctrl, _phase->ctrl_or_self(u), replacement, u, _phase)) { if (mm == NULL) { mm = allocate_merge_mem(mem, rep_proj, rep_ctrl); } @@ -4274,7 +2964,7 @@ void MemoryGraphFixer::fix_memory_uses(Node* mem, Node* replacement, Node* rep_p --i; } } else if (_phase->C->get_alias_index(u->adr_type()) == _alias) { - if (ShenandoahWriteBarrierNode::is_dominator(rep_ctrl, _phase->ctrl_or_self(u), replacement, u, _phase)) { + if (ShenandoahBarrierC2Support::is_dominator(rep_ctrl, _phase->ctrl_or_self(u), replacement, u, _phase)) { _phase->igvn().replace_input_of(u, u->find_edge(mem), rep_proj); --i; } @@ -4283,11 +2973,322 @@ void MemoryGraphFixer::fix_memory_uses(Node* mem, Node* replacement, Node* rep_p } } -void MemoryGraphFixer::remove(Node* n) { - assert(n->Opcode() == Op_ShenandoahWBMemProj, ""); - Node* c = _phase->get_ctrl(n); - Node* mem = find_mem(c, NULL); - if (mem == n) { - _memory_nodes.map(c->_idx, mem->in(ShenandoahWBMemProjNode::WriteBarrier)->in(ShenandoahBarrierNode::Memory)); - } +ShenandoahLoadReferenceBarrierNode::ShenandoahLoadReferenceBarrierNode(Node* ctrl, Node* obj) +: Node(ctrl, obj) { + ShenandoahBarrierSetC2::bsc2()->state()->add_load_reference_barrier(this); +} + +const Type* ShenandoahLoadReferenceBarrierNode::bottom_type() const { + if (in(ValueIn) == NULL || in(ValueIn)->is_top()) { + return Type::TOP; + } + const Type* t = in(ValueIn)->bottom_type(); + if (t == TypePtr::NULL_PTR) { + return t; + } + return t->is_oopptr(); +} + +const Type* ShenandoahLoadReferenceBarrierNode::Value(PhaseGVN* phase) const { + // Either input is TOP ==> the result is TOP + const Type *t2 = phase->type(in(ValueIn)); + if( t2 == Type::TOP ) return Type::TOP; + + if (t2 == TypePtr::NULL_PTR) { + return t2; + } + + const Type* type = t2->is_oopptr()/*->cast_to_nonconst()*/; + return type; +} + +Node* ShenandoahLoadReferenceBarrierNode::Identity(PhaseGVN* phase) { + Node* value = in(ValueIn); + if (!needs_barrier(phase, value)) { + return value; + } + return this; +} + +bool ShenandoahLoadReferenceBarrierNode::needs_barrier(PhaseGVN* phase, Node* n) { + Unique_Node_List visited; + return needs_barrier_impl(phase, n, visited); +} + +bool ShenandoahLoadReferenceBarrierNode::needs_barrier_impl(PhaseGVN* phase, Node* n, Unique_Node_List &visited) { + if (n == NULL) return false; + if (visited.member(n)) { + return false; // Been there. + } + visited.push(n); + + if (n->is_Allocate()) { + // tty->print_cr("optimize barrier on alloc"); + return false; + } + if (n->is_Call()) { + // tty->print_cr("optimize barrier on call"); + return false; + } + + const Type* type = phase->type(n); + if (type == Type::TOP) { + return false; + } + if (type->make_ptr()->higher_equal(TypePtr::NULL_PTR)) { + // tty->print_cr("optimize barrier on null"); + return false; + } + if (type->make_oopptr() && type->make_oopptr()->const_oop() != NULL) { + // tty->print_cr("optimize barrier on constant"); + return false; + } + + switch (n->Opcode()) { + case Op_AddP: + return true; // TODO: Can refine? + case Op_LoadP: + case Op_ShenandoahCompareAndExchangeN: + case Op_ShenandoahCompareAndExchangeP: + case Op_CompareAndExchangeN: + case Op_CompareAndExchangeP: + case Op_GetAndSetN: + case Op_GetAndSetP: + return true; + case Op_Phi: { + for (uint i = 1; i < n->req(); i++) { + if (needs_barrier_impl(phase, n->in(i), visited)) return true; + } + return false; + } + case Op_CheckCastPP: + case Op_CastPP: + return needs_barrier_impl(phase, n->in(1), visited); + case Op_Proj: + return needs_barrier_impl(phase, n->in(0), visited); + case Op_ShenandoahLoadReferenceBarrier: + // tty->print_cr("optimize barrier on barrier"); + return false; + case Op_Parm: + // tty->print_cr("optimize barrier on input arg"); + return false; + case Op_DecodeN: + case Op_EncodeP: + return needs_barrier_impl(phase, n->in(1), visited); + case Op_LoadN: + return true; + case Op_CMoveP: + return needs_barrier_impl(phase, n->in(2), visited) || + needs_barrier_impl(phase, n->in(3), visited); + case Op_ShenandoahEnqueueBarrier: + return needs_barrier_impl(phase, n->in(1), visited); + default: + break; + } +#ifdef ASSERT + tty->print("need barrier on?: "); + tty->print_cr("ins:"); + n->dump(2); + tty->print_cr("outs:"); + n->dump(-2); + ShouldNotReachHere(); +#endif + return true; +} + +ShenandoahLoadReferenceBarrierNode::Strength ShenandoahLoadReferenceBarrierNode::get_barrier_strength() { + Unique_Node_List visited; + Node_Stack stack(0); + stack.push(this, 0); + Strength strength = NONE; + while (strength != STRONG && stack.size() > 0) { + Node* n = stack.node(); + if (visited.member(n)) { + stack.pop(); + continue; + } + visited.push(n); + bool visit_users = false; + switch (n->Opcode()) { + case Op_StoreN: + case Op_StoreP: { + strength = STRONG; + break; + } + case Op_CmpP: { + if (!n->in(1)->bottom_type()->higher_equal(TypePtr::NULL_PTR) && + !n->in(2)->bottom_type()->higher_equal(TypePtr::NULL_PTR)) { + strength = STRONG; + } + break; + } + case Op_CallStaticJava: { + strength = STRONG; + break; + } + case Op_CallDynamicJava: + case Op_CallLeaf: + case Op_CallLeafNoFP: + case Op_CompareAndSwapL: + case Op_CompareAndSwapI: + case Op_CompareAndSwapB: + case Op_CompareAndSwapS: + case Op_ShenandoahCompareAndSwapN: + case Op_ShenandoahCompareAndSwapP: + case Op_ShenandoahWeakCompareAndSwapN: + case Op_ShenandoahWeakCompareAndSwapP: + case Op_ShenandoahCompareAndExchangeN: + case Op_ShenandoahCompareAndExchangeP: + case Op_CompareAndExchangeL: + case Op_CompareAndExchangeI: + case Op_CompareAndExchangeB: + case Op_CompareAndExchangeS: + case Op_WeakCompareAndSwapL: + case Op_WeakCompareAndSwapI: + case Op_WeakCompareAndSwapB: + case Op_WeakCompareAndSwapS: + case Op_GetAndSetL: + case Op_GetAndSetI: + case Op_GetAndSetB: + case Op_GetAndSetS: + case Op_GetAndSetP: + case Op_GetAndSetN: + case Op_GetAndAddL: + case Op_GetAndAddI: + case Op_GetAndAddB: + case Op_GetAndAddS: + case Op_ShenandoahEnqueueBarrier: + case Op_FastLock: + case Op_FastUnlock: + case Op_Rethrow: + case Op_Return: + case Op_StoreB: + case Op_StoreC: + case Op_StoreD: + case Op_StoreF: + case Op_StoreL: + case Op_StoreLConditional: + case Op_StoreI: + case Op_StoreVector: + case Op_StrInflatedCopy: + case Op_StrCompressedCopy: + case Op_EncodeP: + case Op_CastP2X: + case Op_SafePoint: + case Op_EncodeISOArray: + strength = STRONG; + break; + case Op_LoadB: + case Op_LoadUB: + case Op_LoadUS: + case Op_LoadD: + case Op_LoadF: + case Op_LoadL: + case Op_LoadI: + case Op_LoadS: + case Op_LoadN: + case Op_LoadP: + case Op_LoadVector: { + const TypePtr* adr_type = n->adr_type(); + int alias_idx = Compile::current()->get_alias_index(adr_type); + Compile::AliasType* alias_type = Compile::current()->alias_type(alias_idx); + ciField* field = alias_type->field(); + bool is_static = field != NULL && field->is_static(); + bool is_final = field != NULL && field->is_final(); + bool is_stable = field != NULL && field->is_stable(); + if (ShenandoahOptimizeStaticFinals && is_static && is_final) { + // Leave strength as is. + } else if (ShenandoahOptimizeInstanceFinals && !is_static && is_final) { + // Leave strength as is. + } else if (ShenandoahOptimizeStableFinals && (is_stable || (adr_type->isa_aryptr() && adr_type->isa_aryptr()->is_stable()))) { + // Leave strength as is. + } else { + strength = WEAK; + } + break; + } + case Op_AryEq: { + Node* n1 = n->in(2); + Node* n2 = n->in(3); + if (!ShenandoahOptimizeStableFinals || + !n1->bottom_type()->isa_aryptr() || !n1->bottom_type()->isa_aryptr()->is_stable() || + !n2->bottom_type()->isa_aryptr() || !n2->bottom_type()->isa_aryptr()->is_stable()) { + strength = WEAK; + } + break; + } + case Op_StrEquals: + case Op_StrComp: + case Op_StrIndexOf: + case Op_StrIndexOfChar: + if (!ShenandoahOptimizeStableFinals) { + strength = WEAK; + } + break; + case Op_Conv2B: + case Op_LoadRange: + case Op_LoadKlass: + case Op_LoadNKlass: + // NONE, i.e. leave current strength as is + break; + case Op_AddP: + case Op_CheckCastPP: + case Op_CastPP: + case Op_CMoveP: + case Op_Phi: + case Op_ShenandoahLoadReferenceBarrier: + visit_users = true; + break; + default: { +#ifdef ASSERT + tty->print_cr("Unknown node in get_barrier_strength:"); + n->dump(1); + ShouldNotReachHere(); +#else + strength = STRONG; +#endif + } + } +#ifdef ASSERT +/* + if (strength == STRONG) { + tty->print("strengthening node: "); + n->dump(); + } + */ +#endif + stack.pop(); + if (visit_users) { + for (DUIterator_Fast imax, i = n->fast_outs(imax); i < imax; i++) { + Node* user = n->fast_out(i); + if (user != NULL) { + stack.push(user, 0); + } + } + } + } + return strength; +} + +CallStaticJavaNode* ShenandoahLoadReferenceBarrierNode::pin_and_expand_null_check(PhaseIterGVN& igvn) { + Node* val = in(ValueIn); + + const Type* val_t = igvn.type(val); + + if (val_t->meet(TypePtr::NULL_PTR) != val_t && + val->Opcode() == Op_CastPP && + val->in(0) != NULL && + val->in(0)->Opcode() == Op_IfTrue && + val->in(0)->as_Proj()->is_uncommon_trap_if_pattern(Deoptimization::Reason_none) && + val->in(0)->in(0)->is_If() && + val->in(0)->in(0)->in(1)->Opcode() == Op_Bool && + val->in(0)->in(0)->in(1)->as_Bool()->_test._test == BoolTest::ne && + val->in(0)->in(0)->in(1)->in(1)->Opcode() == Op_CmpP && + val->in(0)->in(0)->in(1)->in(1)->in(1) == val->in(1) && + val->in(0)->in(0)->in(1)->in(1)->in(2)->bottom_type() == TypePtr::NULL_PTR) { + assert(val->in(0)->in(0)->in(1)->in(1)->in(1) == val->in(1), ""); + CallStaticJavaNode* unc = val->in(0)->as_Proj()->is_uncommon_trap_if_pattern(Deoptimization::Reason_none); + return unc; + } + return NULL; } diff --git a/src/hotspot/share/gc/shenandoah/c2/shenandoahSupport.hpp b/src/hotspot/share/gc/shenandoah/c2/shenandoahSupport.hpp index 02caf091f20..bfbe7e2b5d6 100644 --- a/src/hotspot/share/gc/shenandoah/c2/shenandoahSupport.hpp +++ b/src/hotspot/share/gc/shenandoah/c2/shenandoahSupport.hpp @@ -36,10 +36,8 @@ class PhaseGVN; class MemoryGraphFixer; -class ShenandoahBarrierNode : public TypeNode { +class ShenandoahBarrierC2Support : public AllStatic { private: - bool _allow_fromspace; - #ifdef ASSERT enum verify_type { ShenandoahLoad, @@ -50,204 +48,49 @@ private: }; static bool verify_helper(Node* in, Node_Stack& phis, VectorSet& visited, verify_type t, bool trace, Unique_Node_List& barriers_used); -#endif - -public: - enum { Control, - Memory, - ValueIn - }; - - ShenandoahBarrierNode(Node* ctrl, Node* mem, Node* obj, bool allow_fromspace) - : TypeNode(obj->bottom_type()->isa_oopptr() ? obj->bottom_type()->is_oopptr()->cast_to_nonconst() : obj->bottom_type(), 3), - _allow_fromspace(allow_fromspace) { - - init_req(Control, ctrl); - init_req(Memory, mem); - init_req(ValueIn, obj); - - init_class_id(Class_ShenandoahBarrier); - } - - static Node* skip_through_barrier(Node* n); - - static const TypeOopPtr* brooks_pointer_type(const Type* t) { - return t->is_oopptr()->cast_to_nonconst()->add_offset(ShenandoahBrooksPointer::byte_offset())->is_oopptr(); - } - - virtual const TypePtr* adr_type() const { - if (bottom_type() == Type::TOP) { - return NULL; - } - //const TypePtr* adr_type = in(MemNode::Address)->bottom_type()->is_ptr(); - const TypePtr* adr_type = brooks_pointer_type(bottom_type()); - assert(adr_type->offset() == ShenandoahBrooksPointer::byte_offset(), "sane offset"); - assert(Compile::current()->alias_type(adr_type)->is_rewritable(), "brooks ptr must be rewritable"); - return adr_type; - } - - virtual uint ideal_reg() const { return Op_RegP; } - virtual uint match_edge(uint idx) const { - return idx >= ValueIn; - } - - Node* Identity_impl(PhaseGVN* phase); - - virtual const Type* Value(PhaseGVN* phase) const; - virtual bool depends_only_on_test() const { - return true; - }; - - static bool needs_barrier(PhaseGVN* phase, ShenandoahBarrierNode* orig, Node* n, Node* rb_mem, bool allow_fromspace); - -#ifdef ASSERT static void report_verify_failure(const char* msg, Node* n1 = NULL, Node* n2 = NULL); - static void verify(RootNode* root); static void verify_raw_mem(RootNode* root); #endif -#ifndef PRODUCT - virtual void dump_spec(outputStream *st) const; -#endif - - // protected: - static Node* dom_mem(Node* mem, Node*& mem_ctrl, Node* n, Node* rep_ctrl, int alias, PhaseIdealLoop* phase); static Node* dom_mem(Node* mem, Node* ctrl, int alias, Node*& mem_ctrl, PhaseIdealLoop* phase); - static bool is_dominator(Node *d_c, Node *n_c, Node* d, Node* n, PhaseIdealLoop* phase); - static bool is_dominator_same_ctrl(Node* c, Node* d, Node* n, PhaseIdealLoop* phase); static Node* no_branches(Node* c, Node* dom, bool allow_one_proj, PhaseIdealLoop* phase); - static bool build_loop_late_post(PhaseIdealLoop* phase, Node* n); - bool sink_node(PhaseIdealLoop* phase, Node* ctrl, Node* n_ctrl); - -protected: - uint hash() const; - bool cmp(const Node& n) const; - uint size_of() const; - -private: - static bool needs_barrier_impl(PhaseGVN* phase, ShenandoahBarrierNode* orig, Node* n, Node* rb_mem, bool allow_fromspace, Unique_Node_List &visited); - - static bool dominates_memory(PhaseGVN* phase, Node* b1, Node* b2, bool linear); - static bool dominates_memory_impl(PhaseGVN* phase, Node* b1, Node* b2, Node* current, bool linear); -}; - -class ShenandoahReadBarrierNode : public ShenandoahBarrierNode { -public: - ShenandoahReadBarrierNode(Node* ctrl, Node* mem, Node* obj) - : ShenandoahBarrierNode(ctrl, mem, obj, true) { - assert(UseShenandoahGC && (ShenandoahReadBarrier || ShenandoahStoreValReadBarrier || - ShenandoahWriteBarrier || ShenandoahAcmpBarrier), - "should be enabled"); - } - ShenandoahReadBarrierNode(Node* ctrl, Node* mem, Node* obj, bool allow_fromspace) - : ShenandoahBarrierNode(ctrl, mem, obj, allow_fromspace) { - assert(UseShenandoahGC && (ShenandoahReadBarrier || ShenandoahStoreValReadBarrier || - ShenandoahWriteBarrier || ShenandoahAcmpBarrier), - "should be enabled"); - } - - virtual Node *Ideal(PhaseGVN *phase, bool can_reshape); - virtual Node* Identity(PhaseGVN* phase); - virtual int Opcode() const; - - bool is_independent(Node* mem); - - void try_move(PhaseIdealLoop* phase); - -private: - static bool is_independent(const Type* in_type, const Type* this_type); - static bool dominates_memory_rb(PhaseGVN* phase, Node* b1, Node* b2, bool linear); - static bool dominates_memory_rb_impl(PhaseGVN* phase, Node* b1, Node* b2, Node* current, bool linear); -}; - -class ShenandoahWriteBarrierNode : public ShenandoahBarrierNode { -public: - ShenandoahWriteBarrierNode(Compile* C, Node* ctrl, Node* mem, Node* obj); - - virtual int Opcode() const; - virtual Node *Ideal(PhaseGVN *phase, bool can_reshape); - virtual Node* Identity(PhaseGVN* phase); - virtual bool depends_only_on_test() const { return false; } - - static bool expand(Compile* C, PhaseIterGVN& igvn); - static bool is_gc_state_load(Node *n); static bool is_heap_state_test(Node* iff, int mask); - static bool is_heap_stable_test(Node* iff); static bool try_common_gc_state_load(Node *n, PhaseIdealLoop *phase); static bool has_safepoint_between(Node* start, Node* stop, PhaseIdealLoop *phase); - - static LoopNode* try_move_before_pre_loop(Node* c, Node* val_ctrl, PhaseIdealLoop* phase); - static Node* move_above_predicates(LoopNode* cl, Node* val_ctrl, PhaseIdealLoop* phase); -#ifdef ASSERT - static bool memory_dominates_all_paths(Node* mem, Node* rep_ctrl, int alias, PhaseIdealLoop* phase); - static void memory_dominates_all_paths_helper(Node* c, Node* rep_ctrl, Unique_Node_List& controls, PhaseIdealLoop* phase); -#endif - void try_move_before_loop(GrowableArray& memory_graph_fixers, PhaseIdealLoop* phase, bool include_lsm, Unique_Node_List& uses); - void try_move_before_loop_helper(LoopNode* cl, Node* val_ctrl, GrowableArray& memory_graph_fixers, PhaseIdealLoop* phase, bool include_lsm, Unique_Node_List& uses); - static void pin_and_expand(PhaseIdealLoop* phase); - CallStaticJavaNode* pin_and_expand_null_check(PhaseIterGVN& igvn); - void pin_and_expand_move_barrier(PhaseIdealLoop* phase, GrowableArray& memory_graph_fixers, Unique_Node_List& uses); - void pin_and_expand_helper(PhaseIdealLoop* phase); static Node* find_bottom_mem(Node* ctrl, PhaseIdealLoop* phase); static void follow_barrier_uses(Node* n, Node* ctrl, Unique_Node_List& uses, PhaseIdealLoop* phase); static void test_null(Node*& ctrl, Node* val, Node*& null_ctrl, PhaseIdealLoop* phase); - static void test_heap_stable(Node*& ctrl, Node* raw_mem, Node*& heap_stable_ctrl, PhaseIdealLoop* phase); - static void call_wb_stub(Node*& ctrl, Node*& val, Node*& result_mem, - Node* raw_mem, Node* wb_mem, int alias, - PhaseIdealLoop* phase); + static void call_lrb_stub(Node*& ctrl, Node*& val, Node*& result_mem, Node* raw_mem, PhaseIdealLoop* phase); static Node* clone_null_check(Node*& c, Node* val, Node* unc_ctrl, PhaseIdealLoop* phase); static void fix_null_check(Node* unc, Node* unc_ctrl, Node* new_unc_ctrl, Unique_Node_List& uses, PhaseIdealLoop* phase); static void in_cset_fast_test(Node*& ctrl, Node*& not_cset_ctrl, Node* val, Node* raw_mem, PhaseIdealLoop* phase); static void move_heap_stable_test_out_of_loop(IfNode* iff, PhaseIdealLoop* phase); - - static void optimize_after_expansion(VectorSet &visited, Node_Stack &nstack, Node_List &old_new, PhaseIdealLoop* phase); static void merge_back_to_back_tests(Node* n, PhaseIdealLoop* phase); static bool identical_backtoback_ifs(Node *n, PhaseIdealLoop* phase); static void fix_ctrl(Node* barrier, Node* region, const MemoryGraphFixer& fixer, Unique_Node_List& uses, Unique_Node_List& uses_to_ignore, uint last, PhaseIdealLoop* phase); - - static void optimize_before_expansion(PhaseIdealLoop* phase, GrowableArray memory_graph_fixers, bool include_lsm); - Node* would_subsume(ShenandoahBarrierNode* other, PhaseIdealLoop* phase); static IfNode* find_unswitching_candidate(const IdealLoopTree *loop, PhaseIdealLoop* phase); - Node* try_split_thru_phi(PhaseIdealLoop* phase); -}; - -class ShenandoahWBMemProjNode : public Node { public: - enum { Control, - WriteBarrier }; + static bool is_dominator(Node* d_c, Node* n_c, Node* d, Node* n, PhaseIdealLoop* phase); + static bool is_dominator_same_ctrl(Node* c, Node* d, Node* n, PhaseIdealLoop* phase); - ShenandoahWBMemProjNode(Node *src) : Node(NULL, src) { - assert(UseShenandoahGC && ShenandoahWriteBarrier, "should be enabled"); - assert(src->Opcode() == Op_ShenandoahWriteBarrier || src->is_Mach(), "epxect wb"); - } - virtual Node* Identity(PhaseGVN* phase); + static bool is_gc_state_load(Node* n); + static bool is_heap_stable_test(Node* iff); - virtual int Opcode() const; - virtual bool is_CFG() const { return false; } - virtual const Type *bottom_type() const {return Type::MEMORY;} - virtual const TypePtr *adr_type() const { - Node* wb = in(WriteBarrier); - if (wb == NULL || wb->is_top()) return NULL; // node is dead - assert(wb->Opcode() == Op_ShenandoahWriteBarrier || (wb->is_Mach() && wb->as_Mach()->ideal_Opcode() == Op_ShenandoahWriteBarrier) || wb->is_Phi(), "expect wb"); - return ShenandoahBarrierNode::brooks_pointer_type(wb->bottom_type()); - } + static bool expand(Compile* C, PhaseIterGVN& igvn); + static void pin_and_expand(PhaseIdealLoop* phase); + static void optimize_after_expansion(VectorSet& visited, Node_Stack& nstack, Node_List& old_new, PhaseIdealLoop* phase); - virtual uint ideal_reg() const { return 0;} // memory projections don't have a register - virtual const Type *Value(PhaseGVN* phase ) const { - return bottom_type(); - } -#ifndef PRODUCT - virtual void dump_spec(outputStream *st) const {}; +#ifdef ASSERT + static void verify(RootNode* root); #endif }; class ShenandoahEnqueueBarrierNode : public Node { public: - ShenandoahEnqueueBarrierNode(Node* val) : Node(NULL, val) { - } + ShenandoahEnqueueBarrierNode(Node* val); const Type *bottom_type() const; const Type* Value(PhaseGVN* phase) const; @@ -289,7 +132,6 @@ public: Node* find_mem(Node* ctrl, Node* n) const; void fix_mem(Node* ctrl, Node* region, Node* mem, Node* mem_for_ctrl, Node* mem_phi, Unique_Node_List& uses); int alias() const { return _alias; } - void remove(Node* n); }; class ShenandoahCompareAndSwapPNode : public CompareAndSwapPNode { @@ -382,4 +224,41 @@ public: virtual int Opcode() const; }; +class ShenandoahLoadReferenceBarrierNode : public Node { +public: + enum { + Control, + ValueIn + }; + + enum Strength { + NONE, WEAK, STRONG, NA + }; + + ShenandoahLoadReferenceBarrierNode(Node* ctrl, Node* val); + + virtual int Opcode() const; + virtual const Type* bottom_type() const; + virtual const Type* Value(PhaseGVN* phase) const; + virtual const class TypePtr *adr_type() const { return TypeOopPtr::BOTTOM; } + virtual uint match_edge(uint idx) const { + return idx >= ValueIn; + } + virtual uint ideal_reg() const { return Op_RegP; } + + virtual Node* Identity(PhaseGVN* phase); + + uint size_of() const { + return sizeof(*this); + } + + Strength get_barrier_strength(); + CallStaticJavaNode* pin_and_expand_null_check(PhaseIterGVN& igvn); + +private: + bool needs_barrier(PhaseGVN* phase, Node* n); + bool needs_barrier_impl(PhaseGVN* phase, Node* n, Unique_Node_List &visited); +}; + + #endif // SHARE_GC_SHENANDOAH_C2_SHENANDOAHSUPPORT_HPP diff --git a/src/hotspot/share/gc/shenandoah/heuristics/shenandoahAdaptiveHeuristics.cpp b/src/hotspot/share/gc/shenandoah/heuristics/shenandoahAdaptiveHeuristics.cpp index 3d8d3f39f7b..5ab8da48a4e 100644 --- a/src/hotspot/share/gc/shenandoah/heuristics/shenandoahAdaptiveHeuristics.cpp +++ b/src/hotspot/share/gc/shenandoah/heuristics/shenandoahAdaptiveHeuristics.cpp @@ -41,13 +41,10 @@ ShenandoahAdaptiveHeuristics::ShenandoahAdaptiveHeuristics() : SHENANDOAH_ERGO_ENABLE_FLAG(ShenandoahImplicitGCInvokesConcurrent); // Final configuration checks + SHENANDOAH_CHECK_FLAG_SET(ShenandoahLoadRefBarrier); SHENANDOAH_CHECK_FLAG_SET(ShenandoahSATBBarrier); - SHENANDOAH_CHECK_FLAG_SET(ShenandoahReadBarrier); - SHENANDOAH_CHECK_FLAG_SET(ShenandoahWriteBarrier); - SHENANDOAH_CHECK_FLAG_SET(ShenandoahStoreValReadBarrier); SHENANDOAH_CHECK_FLAG_SET(ShenandoahKeepAliveBarrier); SHENANDOAH_CHECK_FLAG_SET(ShenandoahCASBarrier); - SHENANDOAH_CHECK_FLAG_SET(ShenandoahAcmpBarrier); SHENANDOAH_CHECK_FLAG_SET(ShenandoahCloneBarrier); } diff --git a/src/hotspot/share/gc/shenandoah/heuristics/shenandoahAggressiveHeuristics.cpp b/src/hotspot/share/gc/shenandoah/heuristics/shenandoahAggressiveHeuristics.cpp index 21b1a725293..f9ffa109b44 100644 --- a/src/hotspot/share/gc/shenandoah/heuristics/shenandoahAggressiveHeuristics.cpp +++ b/src/hotspot/share/gc/shenandoah/heuristics/shenandoahAggressiveHeuristics.cpp @@ -47,13 +47,10 @@ ShenandoahAggressiveHeuristics::ShenandoahAggressiveHeuristics() : ShenandoahHeu } // Final configuration checks + SHENANDOAH_CHECK_FLAG_SET(ShenandoahLoadRefBarrier); SHENANDOAH_CHECK_FLAG_SET(ShenandoahSATBBarrier); - SHENANDOAH_CHECK_FLAG_SET(ShenandoahReadBarrier); - SHENANDOAH_CHECK_FLAG_SET(ShenandoahWriteBarrier); - SHENANDOAH_CHECK_FLAG_SET(ShenandoahStoreValReadBarrier); SHENANDOAH_CHECK_FLAG_SET(ShenandoahKeepAliveBarrier); SHENANDOAH_CHECK_FLAG_SET(ShenandoahCASBarrier); - SHENANDOAH_CHECK_FLAG_SET(ShenandoahAcmpBarrier); SHENANDOAH_CHECK_FLAG_SET(ShenandoahCloneBarrier); } diff --git a/src/hotspot/share/gc/shenandoah/heuristics/shenandoahCompactHeuristics.cpp b/src/hotspot/share/gc/shenandoah/heuristics/shenandoahCompactHeuristics.cpp index 7447c3200e6..43fce548a76 100644 --- a/src/hotspot/share/gc/shenandoah/heuristics/shenandoahCompactHeuristics.cpp +++ b/src/hotspot/share/gc/shenandoah/heuristics/shenandoahCompactHeuristics.cpp @@ -42,13 +42,10 @@ ShenandoahCompactHeuristics::ShenandoahCompactHeuristics() : ShenandoahHeuristic SHENANDOAH_ERGO_OVERRIDE_DEFAULT(ShenandoahGarbageThreshold, 10); // Final configuration checks + SHENANDOAH_CHECK_FLAG_SET(ShenandoahLoadRefBarrier); SHENANDOAH_CHECK_FLAG_SET(ShenandoahSATBBarrier); - SHENANDOAH_CHECK_FLAG_SET(ShenandoahReadBarrier); - SHENANDOAH_CHECK_FLAG_SET(ShenandoahWriteBarrier); - SHENANDOAH_CHECK_FLAG_SET(ShenandoahStoreValReadBarrier); SHENANDOAH_CHECK_FLAG_SET(ShenandoahKeepAliveBarrier); SHENANDOAH_CHECK_FLAG_SET(ShenandoahCASBarrier); - SHENANDOAH_CHECK_FLAG_SET(ShenandoahAcmpBarrier); SHENANDOAH_CHECK_FLAG_SET(ShenandoahCloneBarrier); } diff --git a/src/hotspot/share/gc/shenandoah/heuristics/shenandoahPassiveHeuristics.cpp b/src/hotspot/share/gc/shenandoah/heuristics/shenandoahPassiveHeuristics.cpp index 6bb325185a5..1c813454cea 100644 --- a/src/hotspot/share/gc/shenandoah/heuristics/shenandoahPassiveHeuristics.cpp +++ b/src/hotspot/share/gc/shenandoah/heuristics/shenandoahPassiveHeuristics.cpp @@ -43,14 +43,11 @@ ShenandoahPassiveHeuristics::ShenandoahPassiveHeuristics() : ShenandoahHeuristic } // Disable known barriers by default. + SHENANDOAH_ERGO_DISABLE_FLAG(ShenandoahLoadRefBarrier); SHENANDOAH_ERGO_DISABLE_FLAG(ShenandoahSATBBarrier); SHENANDOAH_ERGO_DISABLE_FLAG(ShenandoahKeepAliveBarrier); - SHENANDOAH_ERGO_DISABLE_FLAG(ShenandoahWriteBarrier); - SHENANDOAH_ERGO_DISABLE_FLAG(ShenandoahReadBarrier); SHENANDOAH_ERGO_DISABLE_FLAG(ShenandoahStoreValEnqueueBarrier); - SHENANDOAH_ERGO_DISABLE_FLAG(ShenandoahStoreValReadBarrier); SHENANDOAH_ERGO_DISABLE_FLAG(ShenandoahCASBarrier); - SHENANDOAH_ERGO_DISABLE_FLAG(ShenandoahAcmpBarrier); SHENANDOAH_ERGO_DISABLE_FLAG(ShenandoahCloneBarrier); // Final configuration checks diff --git a/src/hotspot/share/gc/shenandoah/heuristics/shenandoahStaticHeuristics.cpp b/src/hotspot/share/gc/shenandoah/heuristics/shenandoahStaticHeuristics.cpp index db6aa6fcd6a..16ad81395af 100644 --- a/src/hotspot/share/gc/shenandoah/heuristics/shenandoahStaticHeuristics.cpp +++ b/src/hotspot/share/gc/shenandoah/heuristics/shenandoahStaticHeuristics.cpp @@ -40,13 +40,10 @@ ShenandoahStaticHeuristics::ShenandoahStaticHeuristics() : ShenandoahHeuristics( SHENANDOAH_ERGO_ENABLE_FLAG(ShenandoahImplicitGCInvokesConcurrent); // Final configuration checks + SHENANDOAH_CHECK_FLAG_SET(ShenandoahLoadRefBarrier); SHENANDOAH_CHECK_FLAG_SET(ShenandoahSATBBarrier); - SHENANDOAH_CHECK_FLAG_SET(ShenandoahReadBarrier); - SHENANDOAH_CHECK_FLAG_SET(ShenandoahWriteBarrier); - SHENANDOAH_CHECK_FLAG_SET(ShenandoahStoreValReadBarrier); SHENANDOAH_CHECK_FLAG_SET(ShenandoahKeepAliveBarrier); SHENANDOAH_CHECK_FLAG_SET(ShenandoahCASBarrier); - SHENANDOAH_CHECK_FLAG_SET(ShenandoahAcmpBarrier); SHENANDOAH_CHECK_FLAG_SET(ShenandoahCloneBarrier); } diff --git a/src/hotspot/share/gc/shenandoah/heuristics/shenandoahTraversalHeuristics.cpp b/src/hotspot/share/gc/shenandoah/heuristics/shenandoahTraversalHeuristics.cpp index c57002c0fda..0dcc6a258e5 100644 --- a/src/hotspot/share/gc/shenandoah/heuristics/shenandoahTraversalHeuristics.cpp +++ b/src/hotspot/share/gc/shenandoah/heuristics/shenandoahTraversalHeuristics.cpp @@ -37,7 +37,6 @@ ShenandoahTraversalHeuristics::ShenandoahTraversalHeuristics() : ShenandoahHeuri _last_cset_select(0) { FLAG_SET_DEFAULT(ShenandoahSATBBarrier, false); - FLAG_SET_DEFAULT(ShenandoahStoreValReadBarrier, false); FLAG_SET_DEFAULT(ShenandoahStoreValEnqueueBarrier, true); FLAG_SET_DEFAULT(ShenandoahKeepAliveBarrier, false); FLAG_SET_DEFAULT(ShenandoahAllowMixedAllocs, false); @@ -53,11 +52,9 @@ ShenandoahTraversalHeuristics::ShenandoahTraversalHeuristics() : ShenandoahHeuri SHENANDOAH_ERGO_ENABLE_FLAG(ShenandoahImplicitGCInvokesConcurrent); // Final configuration checks - SHENANDOAH_CHECK_FLAG_SET(ShenandoahReadBarrier); - SHENANDOAH_CHECK_FLAG_SET(ShenandoahWriteBarrier); + SHENANDOAH_CHECK_FLAG_SET(ShenandoahLoadRefBarrier); SHENANDOAH_CHECK_FLAG_SET(ShenandoahStoreValEnqueueBarrier); SHENANDOAH_CHECK_FLAG_SET(ShenandoahCASBarrier); - SHENANDOAH_CHECK_FLAG_SET(ShenandoahAcmpBarrier); SHENANDOAH_CHECK_FLAG_SET(ShenandoahCloneBarrier); } diff --git a/src/hotspot/share/gc/shenandoah/shenandoahArguments.cpp b/src/hotspot/share/gc/shenandoah/shenandoahArguments.cpp index caefc0605e5..45a1c2ca178 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahArguments.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahArguments.cpp @@ -46,12 +46,8 @@ void ShenandoahArguments::initialize() { FLAG_SET_DEFAULT(ShenandoahSATBBarrier, false); FLAG_SET_DEFAULT(ShenandoahKeepAliveBarrier, false); - FLAG_SET_DEFAULT(ShenandoahWriteBarrier, false); - FLAG_SET_DEFAULT(ShenandoahReadBarrier, false); FLAG_SET_DEFAULT(ShenandoahStoreValEnqueueBarrier, false); - FLAG_SET_DEFAULT(ShenandoahStoreValReadBarrier, false); FLAG_SET_DEFAULT(ShenandoahCASBarrier, false); - FLAG_SET_DEFAULT(ShenandoahAcmpBarrier, false); FLAG_SET_DEFAULT(ShenandoahCloneBarrier, false); #endif @@ -111,12 +107,8 @@ void ShenandoahArguments::initialize() { if (ShenandoahVerifyOptoBarriers && (!FLAG_IS_DEFAULT(ShenandoahSATBBarrier) || !FLAG_IS_DEFAULT(ShenandoahKeepAliveBarrier) || - !FLAG_IS_DEFAULT(ShenandoahWriteBarrier) || - !FLAG_IS_DEFAULT(ShenandoahReadBarrier) || !FLAG_IS_DEFAULT(ShenandoahStoreValEnqueueBarrier) || - !FLAG_IS_DEFAULT(ShenandoahStoreValReadBarrier) || !FLAG_IS_DEFAULT(ShenandoahCASBarrier) || - !FLAG_IS_DEFAULT(ShenandoahAcmpBarrier) || !FLAG_IS_DEFAULT(ShenandoahCloneBarrier) )) { warning("Unusual barrier configuration, disabling C2 barrier verification"); @@ -164,13 +156,6 @@ void ShenandoahArguments::initialize() { FLAG_SET_DEFAULT(UseAOT, false); } - // JNI fast get field stuff is not currently supported by Shenandoah. - // It would introduce another heap memory access for reading the forwarding - // pointer, which would have to be guarded by the signal handler machinery. - // See: - // http://mail.openjdk.java.net/pipermail/hotspot-dev/2018-June/032763.html - FLAG_SET_DEFAULT(UseFastJNIAccessors, false); - // TLAB sizing policy makes resizing decisions before each GC cycle. It averages // historical data, assigning more recent data the weight according to TLABAllocationWeight. // Current default is good for generational collectors that run frequent young GCs. diff --git a/src/hotspot/share/gc/shenandoah/shenandoahBarrierSet.cpp b/src/hotspot/share/gc/shenandoah/shenandoahBarrierSet.cpp index 412df539aeb..02a64b29e4e 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahBarrierSet.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahBarrierSet.cpp @@ -218,31 +218,25 @@ void ShenandoahBarrierSet::write_region(MemRegion mr) { } } -oop ShenandoahBarrierSet::read_barrier(oop src) { - // Check for forwarded objects, because on Full GC path we might deal with - // non-trivial fwdptrs that contain Full GC specific metadata. We could check - // for is_full_gc_in_progress(), but this also covers the case of stable heap, - // which provides a bit of performance improvement. - if (ShenandoahReadBarrier && _heap->has_forwarded_objects()) { - return ShenandoahBarrierSet::resolve_forwarded(src); +oop ShenandoahBarrierSet::load_reference_barrier_not_null(oop obj) { + if (ShenandoahLoadRefBarrier && _heap->has_forwarded_objects()) { + return load_reference_barrier_impl(obj); } else { - return src; + return obj; } } -bool ShenandoahBarrierSet::obj_equals(oop obj1, oop obj2) { - bool eq = oopDesc::equals_raw(obj1, obj2); - if (! eq && ShenandoahAcmpBarrier) { - OrderAccess::loadload(); - obj1 = resolve_forwarded(obj1); - obj2 = resolve_forwarded(obj2); - eq = oopDesc::equals_raw(obj1, obj2); +oop ShenandoahBarrierSet::load_reference_barrier(oop obj) { + if (obj != NULL) { + return load_reference_barrier_not_null(obj); + } else { + return obj; } - return eq; } -oop ShenandoahBarrierSet::write_barrier_mutator(oop obj) { - assert(UseShenandoahGC && ShenandoahWriteBarrier, "should be enabled"); + +oop ShenandoahBarrierSet::load_reference_barrier_mutator(oop obj) { + assert(ShenandoahLoadRefBarrier, "should be enabled"); assert(_heap->is_gc_in_progress_mask(ShenandoahHeap::EVACUATION | ShenandoahHeap::TRAVERSAL), "evac should be in progress"); shenandoah_assert_in_cset(NULL, obj); @@ -288,8 +282,8 @@ oop ShenandoahBarrierSet::write_barrier_mutator(oop obj) { return fwd; } -oop ShenandoahBarrierSet::write_barrier_impl(oop obj) { - assert(UseShenandoahGC && ShenandoahWriteBarrier, "should be enabled"); +oop ShenandoahBarrierSet::load_reference_barrier_impl(oop obj) { + assert(ShenandoahLoadRefBarrier, "should be enabled"); if (!CompressedOops::is_null(obj)) { bool evac_in_progress = _heap->is_gc_in_progress_mask(ShenandoahHeap::EVACUATION | ShenandoahHeap::TRAVERSAL); oop fwd = resolve_forwarded_not_null(obj); @@ -311,23 +305,10 @@ oop ShenandoahBarrierSet::write_barrier_impl(oop obj) { } } -oop ShenandoahBarrierSet::write_barrier(oop obj) { - if (ShenandoahWriteBarrier && _heap->has_forwarded_objects()) { - return write_barrier_impl(obj); - } else { - return obj; - } -} - -oop ShenandoahBarrierSet::storeval_barrier(oop obj) { +void ShenandoahBarrierSet::storeval_barrier(oop obj) { if (ShenandoahStoreValEnqueueBarrier && !CompressedOops::is_null(obj) && _heap->is_concurrent_traversal_in_progress()) { - obj = write_barrier(obj); enqueue(obj); } - if (ShenandoahStoreValReadBarrier) { - obj = resolve_forwarded(obj); - } - return obj; } void ShenandoahBarrierSet::keep_alive_barrier(oop obj) { diff --git a/src/hotspot/share/gc/shenandoah/shenandoahBarrierSet.hpp b/src/hotspot/share/gc/shenandoah/shenandoahBarrierSet.hpp index 65ae19bfd3b..1edaa26d0e1 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahBarrierSet.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahBarrierSet.hpp @@ -87,24 +87,15 @@ public: virtual void on_thread_attach(Thread* thread); virtual void on_thread_detach(Thread* thread); - virtual oop read_barrier(oop src); - static inline oop resolve_forwarded_not_null(oop p); static inline oop resolve_forwarded(oop p); - virtual oop write_barrier(oop obj); + void storeval_barrier(oop obj); + void keep_alive_barrier(oop obj); - oop write_barrier_mutator(oop obj); - - virtual oop storeval_barrier(oop obj); - - virtual void keep_alive_barrier(oop obj); - - bool obj_equals(oop obj1, oop obj2); - -#ifdef CHECK_UNHANDLED_OOPS - bool oop_equals_operator_allowed() { return !ShenandoahVerifyObjectEquals; } -#endif + oop load_reference_barrier(oop obj); + oop load_reference_barrier_mutator(oop obj); + oop load_reference_barrier_not_null(oop obj); void enqueue(oop obj); @@ -114,7 +105,7 @@ private: template void write_ref_array_loop(HeapWord* start, size_t count); - oop write_barrier_impl(oop obj); + oop load_reference_barrier_impl(oop obj); static void keep_alive_if_weak(DecoratorSet decorators, oop value) { assert((decorators & ON_UNKNOWN_OOP_REF) == 0, "Reference strength must be known"); @@ -149,114 +140,31 @@ public: class AccessBarrier: public BarrierSet::AccessBarrier { typedef BarrierSet::AccessBarrier Raw; + template + static oop oop_atomic_cmpxchg_in_heap_impl(oop new_value, T* addr, oop compare_value); + + template + static oop oop_atomic_xchg_in_heap_impl(oop new_value, T* addr); + public: - // Primitive heap accesses. These accessors get resolved when - // IN_HEAP is set (e.g. when using the HeapAccess API), it is - // not an oop_* overload, and the barrier strength is AS_NORMAL. - template - static T load_in_heap(T* addr) { - ShouldNotReachHere(); - return Raw::template load(addr); - } - - template - static T load_in_heap_at(oop base, ptrdiff_t offset) { - base = ShenandoahBarrierSet::resolve_forwarded(base); - return Raw::template load_at(base, offset); - } - - template - static void store_in_heap(T* addr, T value) { - ShouldNotReachHere(); - Raw::store(addr, value); - } - - template - static void store_in_heap_at(oop base, ptrdiff_t offset, T value) { - base = ShenandoahBarrierSet::barrier_set()->write_barrier(base); - Raw::store_at(base, offset, value); - } - - template - static T atomic_cmpxchg_in_heap(T new_value, T* addr, T compare_value) { - ShouldNotReachHere(); - return Raw::atomic_cmpxchg(new_value, addr, compare_value); - } - - template - static T atomic_cmpxchg_in_heap_at(T new_value, oop base, ptrdiff_t offset, T compare_value) { - base = ShenandoahBarrierSet::barrier_set()->write_barrier(base); - return Raw::atomic_cmpxchg_at(new_value, base, offset, compare_value); - } - - template - static T atomic_xchg_in_heap(T new_value, T* addr) { - ShouldNotReachHere(); - return Raw::atomic_xchg(new_value, addr); - } - - template - static T atomic_xchg_in_heap_at(T new_value, oop base, ptrdiff_t offset) { - base = ShenandoahBarrierSet::barrier_set()->write_barrier(base); - return Raw::atomic_xchg_at(new_value, base, offset); - } - - template - static void arraycopy_in_heap(arrayOop src_obj, size_t src_offset_in_bytes, T* src_raw, - arrayOop dst_obj, size_t dst_offset_in_bytes, T* dst_raw, - size_t length); - // Heap oop accesses. These accessors get resolved when // IN_HEAP is set (e.g. when using the HeapAccess API), it is // an oop_* overload, and the barrier strength is AS_NORMAL. template - static oop oop_load_in_heap(T* addr) { - // ShouldNotReachHere(); - oop value = Raw::template oop_load(addr); - keep_alive_if_weak(decorators, value); - return value; - } - - static oop oop_load_in_heap_at(oop base, ptrdiff_t offset) { - base = ShenandoahBarrierSet::resolve_forwarded(base); - oop value = Raw::template oop_load_at(base, offset); - keep_alive_if_weak(AccessBarrierSupport::resolve_possibly_unknown_oop_ref_strength(base, offset), value); - return value; - } + static oop oop_load_in_heap(T* addr); + static oop oop_load_in_heap_at(oop base, ptrdiff_t offset); template - static void oop_store_in_heap(T* addr, oop value) { - const bool keep_alive = (decorators & AS_NO_KEEPALIVE) == 0; - if (keep_alive) { - ShenandoahBarrierSet::barrier_set()->write_ref_field_pre_work(addr, value); - } - Raw::oop_store(addr, value); - } - - static void oop_store_in_heap_at(oop base, ptrdiff_t offset, oop value) { - base = ShenandoahBarrierSet::barrier_set()->write_barrier(base); - value = ShenandoahBarrierSet::barrier_set()->storeval_barrier(value); - - oop_store_in_heap(AccessInternal::oop_field_addr(base, offset), value); - } + static void oop_store_in_heap(T* addr, oop value); + static void oop_store_in_heap_at(oop base, ptrdiff_t offset, oop value); template static oop oop_atomic_cmpxchg_in_heap(oop new_value, T* addr, oop compare_value); - - static oop oop_atomic_cmpxchg_in_heap_at(oop new_value, oop base, ptrdiff_t offset, oop compare_value) { - base = ShenandoahBarrierSet::barrier_set()->write_barrier(base); - new_value = ShenandoahBarrierSet::barrier_set()->storeval_barrier(new_value); - return oop_atomic_cmpxchg_in_heap(new_value, AccessInternal::oop_field_addr(base, offset), compare_value); - } + static oop oop_atomic_cmpxchg_in_heap_at(oop new_value, oop base, ptrdiff_t offset, oop compare_value); template static oop oop_atomic_xchg_in_heap(oop new_value, T* addr); - - static oop oop_atomic_xchg_in_heap_at(oop new_value, oop base, ptrdiff_t offset) { - base = ShenandoahBarrierSet::barrier_set()->write_barrier(base); - new_value = ShenandoahBarrierSet::barrier_set()->storeval_barrier(new_value); - return oop_atomic_xchg_in_heap(new_value, AccessInternal::oop_field_addr(base, offset)); - } + static oop oop_atomic_xchg_in_heap_at(oop new_value, oop base, ptrdiff_t offset); template static bool oop_arraycopy_in_heap(arrayOop src_obj, size_t src_offset_in_bytes, T* src_raw, @@ -268,19 +176,13 @@ public: // Needed for loads on non-heap weak references template - static oop oop_load_not_in_heap(T* addr) { - oop value = Raw::oop_load_not_in_heap(addr); - keep_alive_if_weak(decorators, value); - return value; - } + static oop oop_load_not_in_heap(T* addr); - static oop resolve(oop obj) { - return ShenandoahBarrierSet::barrier_set()->write_barrier(obj); - } + template + static oop oop_atomic_cmpxchg_not_in_heap(oop new_value, T* addr, oop compare_value); - static bool equals(oop o1, oop o2) { - return ShenandoahBarrierSet::barrier_set()->obj_equals(o1, o2); - } + template + static oop oop_atomic_xchg_not_in_heap(oop new_value, T* addr); }; diff --git a/src/hotspot/share/gc/shenandoah/shenandoahBarrierSet.inline.hpp b/src/hotspot/share/gc/shenandoah/shenandoahBarrierSet.inline.hpp index c6c0624c1f5..f902ec59d9c 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahBarrierSet.inline.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahBarrierSet.inline.hpp @@ -52,7 +52,49 @@ inline oop ShenandoahBarrierSet::resolve_forwarded(oop p) { template template -inline oop ShenandoahBarrierSet::AccessBarrier::oop_atomic_cmpxchg_in_heap(oop new_value, T* addr, oop compare_value) { +inline oop ShenandoahBarrierSet::AccessBarrier::oop_load_in_heap(T* addr) { + oop value = Raw::oop_load_in_heap(addr); + value = ShenandoahBarrierSet::barrier_set()->load_reference_barrier(value); + keep_alive_if_weak(decorators, value); + return value; +} + +template +inline oop ShenandoahBarrierSet::AccessBarrier::oop_load_in_heap_at(oop base, ptrdiff_t offset) { + oop value = Raw::oop_load_in_heap_at(base, offset); + value = ShenandoahBarrierSet::barrier_set()->load_reference_barrier(value); + keep_alive_if_weak(AccessBarrierSupport::resolve_possibly_unknown_oop_ref_strength(base, offset), value); + return value; +} + +template +template +inline oop ShenandoahBarrierSet::AccessBarrier::oop_load_not_in_heap(T* addr) { + oop value = Raw::oop_load_not_in_heap(addr); + value = ShenandoahBarrierSet::barrier_set()->load_reference_barrier(value); + keep_alive_if_weak(decorators, value); + return value; +} + +template +template +inline void ShenandoahBarrierSet::AccessBarrier::oop_store_in_heap(T* addr, oop value) { + ShenandoahBarrierSet::barrier_set()->storeval_barrier(value); + const bool keep_alive = (decorators & AS_NO_KEEPALIVE) == 0; + if (keep_alive) { + ShenandoahBarrierSet::barrier_set()->write_ref_field_pre_work(addr, value); + } + Raw::oop_store_in_heap(addr, value); +} + +template +inline void ShenandoahBarrierSet::AccessBarrier::oop_store_in_heap_at(oop base, ptrdiff_t offset, oop value) { + oop_store_in_heap(AccessInternal::oop_field_addr(base, offset), value); +} + +template +template +inline oop ShenandoahBarrierSet::AccessBarrier::oop_atomic_cmpxchg_not_in_heap(oop new_value, T* addr, oop compare_value) { oop res; oop expected = compare_value; do { @@ -60,42 +102,79 @@ inline oop ShenandoahBarrierSet::AccessBarrier::oop_ato res = Raw::oop_atomic_cmpxchg(new_value, addr, compare_value); expected = res; } while ((! oopDesc::equals_raw(compare_value, expected)) && oopDesc::equals_raw(resolve_forwarded(compare_value), resolve_forwarded(expected))); - if (oopDesc::equals_raw(expected, compare_value)) { - const bool keep_alive = (decorators & AS_NO_KEEPALIVE) == 0; - if (keep_alive && ShenandoahSATBBarrier && !CompressedOops::is_null(compare_value) && - ShenandoahHeap::heap()->is_concurrent_mark_in_progress()) { - ShenandoahBarrierSet::barrier_set()->enqueue(compare_value); - } + if (res != NULL) { + return ShenandoahBarrierSet::barrier_set()->load_reference_barrier_not_null(res); + } else { + return res; } - return res; +} + +template +template +inline oop ShenandoahBarrierSet::AccessBarrier::oop_atomic_cmpxchg_in_heap_impl(oop new_value, T* addr, oop compare_value) { + ShenandoahBarrierSet::barrier_set()->storeval_barrier(new_value); + oop result = oop_atomic_cmpxchg_not_in_heap(new_value, addr, compare_value); + const bool keep_alive = (decorators & AS_NO_KEEPALIVE) == 0; + if (keep_alive && ShenandoahSATBBarrier && !CompressedOops::is_null(result) && + oopDesc::equals_raw(result, compare_value) && + ShenandoahHeap::heap()->is_concurrent_mark_in_progress()) { + ShenandoahBarrierSet::barrier_set()->enqueue(result); + } + return result; +} + +template +template +inline oop ShenandoahBarrierSet::AccessBarrier::oop_atomic_cmpxchg_in_heap(oop new_value, T* addr, oop compare_value) { + oop result = oop_atomic_cmpxchg_in_heap_impl(new_value, addr, compare_value); + keep_alive_if_weak(decorators, result); + return result; +} + +template +inline oop ShenandoahBarrierSet::AccessBarrier::oop_atomic_cmpxchg_in_heap_at(oop new_value, oop base, ptrdiff_t offset, oop compare_value) { + oop result = oop_atomic_cmpxchg_in_heap_impl(new_value, AccessInternal::oop_field_addr(base, offset), compare_value); + keep_alive_if_weak(AccessBarrierSupport::resolve_possibly_unknown_oop_ref_strength(base, offset), result); + return result; +} + +template +template +inline oop ShenandoahBarrierSet::AccessBarrier::oop_atomic_xchg_not_in_heap(oop new_value, T* addr) { + oop previous = Raw::oop_atomic_xchg(new_value, addr); + if (previous != NULL) { + return ShenandoahBarrierSet::barrier_set()->load_reference_barrier_not_null(previous); + } else { + return previous; + } +} + +template +template +inline oop ShenandoahBarrierSet::AccessBarrier::oop_atomic_xchg_in_heap_impl(oop new_value, T* addr) { + ShenandoahBarrierSet::barrier_set()->storeval_barrier(new_value); + oop result = oop_atomic_xchg_not_in_heap(new_value, addr); + const bool keep_alive = (decorators & AS_NO_KEEPALIVE) == 0; + if (keep_alive && ShenandoahSATBBarrier && !CompressedOops::is_null(result) && + ShenandoahHeap::heap()->is_concurrent_mark_in_progress()) { + ShenandoahBarrierSet::barrier_set()->enqueue(result); + } + return result; } template template inline oop ShenandoahBarrierSet::AccessBarrier::oop_atomic_xchg_in_heap(oop new_value, T* addr) { - oop previous = Raw::oop_atomic_xchg(new_value, addr); - if (ShenandoahSATBBarrier) { - const bool keep_alive = (decorators & AS_NO_KEEPALIVE) == 0; - if (keep_alive && !CompressedOops::is_null(previous) && - ShenandoahHeap::heap()->is_concurrent_mark_in_progress()) { - ShenandoahBarrierSet::barrier_set()->enqueue(previous); - } - } - return previous; + oop result = oop_atomic_xchg_in_heap_impl(new_value, addr); + keep_alive_if_weak(addr, result); + return result; } template -template -void ShenandoahBarrierSet::AccessBarrier::arraycopy_in_heap(arrayOop src_obj, size_t src_offset_in_bytes, T* src_raw, - arrayOop dst_obj, size_t dst_offset_in_bytes, T* dst_raw, - size_t length) { - if (!CompressedOops::is_null(src_obj)) { - src_obj = arrayOop(ShenandoahBarrierSet::barrier_set()->read_barrier(src_obj)); - } - if (!CompressedOops::is_null(dst_obj)) { - dst_obj = arrayOop(ShenandoahBarrierSet::barrier_set()->write_barrier(dst_obj)); - } - Raw::arraycopy(src_obj, src_offset_in_bytes, src_raw, dst_obj, dst_offset_in_bytes, dst_raw, length); +inline oop ShenandoahBarrierSet::AccessBarrier::oop_atomic_xchg_in_heap_at(oop new_value, oop base, ptrdiff_t offset) { + oop result = oop_atomic_xchg_in_heap_impl(new_value, AccessInternal::oop_field_addr(base, offset)); + keep_alive_if_weak(AccessBarrierSupport::resolve_possibly_unknown_oop_ref_strength(base, offset), result); + return result; } template @@ -248,8 +327,6 @@ bool ShenandoahBarrierSet::arraycopy_element(T* cur_src, T* cur_dst, Klass* boun // Clone barrier support template void ShenandoahBarrierSet::AccessBarrier::clone_in_heap(oop src, oop dst, size_t size) { - src = arrayOop(ShenandoahBarrierSet::barrier_set()->read_barrier(src)); - dst = arrayOop(ShenandoahBarrierSet::barrier_set()->write_barrier(dst)); Raw::clone(src, dst, size); ShenandoahBarrierSet::barrier_set()->write_region(MemRegion((HeapWord*) dst, size)); } @@ -260,13 +337,6 @@ bool ShenandoahBarrierSet::AccessBarrier::oop_arraycopy arrayOop dst_obj, size_t dst_offset_in_bytes, T* dst_raw, size_t length) { ShenandoahHeap* heap = ShenandoahHeap::heap(); - if (!CompressedOops::is_null(src_obj)) { - src_obj = arrayOop(ShenandoahBarrierSet::barrier_set()->read_barrier(src_obj)); - } - if (!CompressedOops::is_null(dst_obj)) { - dst_obj = arrayOop(ShenandoahBarrierSet::barrier_set()->write_barrier(dst_obj)); - } - bool satb = ShenandoahSATBBarrier && heap->is_concurrent_mark_in_progress(); bool checkcast = HasDecorator::value; bool disjoint = HasDecorator::value; diff --git a/src/hotspot/share/gc/shenandoah/shenandoahCodeRoots.cpp b/src/hotspot/share/gc/shenandoah/shenandoahCodeRoots.cpp index 73f980d6142..78d68129421 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahCodeRoots.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahCodeRoots.cpp @@ -119,39 +119,6 @@ public: } }; -class ShenandoahNMethodOopInitializer : public OopClosure { -private: - ShenandoahHeap* const _heap; - -public: - ShenandoahNMethodOopInitializer() : _heap(ShenandoahHeap::heap()) {}; - -private: - template - inline void do_oop_work(T* p) { - T o = RawAccess<>::oop_load(p); - if (! CompressedOops::is_null(o)) { - oop obj1 = CompressedOops::decode_not_null(o); - oop obj2 = ShenandoahBarrierSet::barrier_set()->write_barrier(obj1); - if (! oopDesc::equals_raw(obj1, obj2)) { - shenandoah_assert_not_in_cset(NULL, obj2); - RawAccess::oop_store(p, obj2); - if (_heap->is_concurrent_traversal_in_progress()) { - ShenandoahBarrierSet::barrier_set()->enqueue(obj2); - } - } - } - } - -public: - void do_oop(oop* o) { - do_oop_work(o); - } - void do_oop(narrowOop* o) { - do_oop_work(o); - } -}; - ShenandoahCodeRoots::PaddedLock ShenandoahCodeRoots::_recorded_nms_lock; GrowableArray* ShenandoahCodeRoots::_recorded_nms; @@ -163,21 +130,13 @@ void ShenandoahCodeRoots::initialize() { void ShenandoahCodeRoots::add_nmethod(nmethod* nm) { switch (ShenandoahCodeRootsStyle) { case 0: - case 1: { - ShenandoahNMethodOopInitializer init; - nm->oops_do(&init); - nm->fix_oop_relocations(); + case 1: break; - } case 2: { ShenandoahNMethodOopDetector detector; nm->oops_do(&detector); if (detector.has_oops()) { - ShenandoahNMethodOopInitializer init; - nm->oops_do(&init); - nm->fix_oop_relocations(); - ShenandoahNMethod* nmr = new ShenandoahNMethod(nm, detector.oops()); nmr->assert_alive_and_correct(); diff --git a/src/hotspot/share/gc/shenandoah/shenandoahEvacOOMHandler.hpp b/src/hotspot/share/gc/shenandoah/shenandoahEvacOOMHandler.hpp index 83071cf40d8..13831ce6f64 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahEvacOOMHandler.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahEvacOOMHandler.hpp @@ -31,8 +31,8 @@ * Provides safe handling of out-of-memory situations during evacuation. * * When a Java thread encounters out-of-memory while evacuating an object in a - * write-barrier (i.e. it cannot copy the object to to-space), it does not necessarily - * follow we can return immediately from the WB (and store to from-space). + * load-reference-barrier (i.e. it cannot copy the object to to-space), it does not + * necessarily follow we can return immediately from the LRB (and store to from-space). * * In very basic case, on such failure we may wait until the the evacuation is over, * and then resolve the forwarded copy, and to the store there. This is possible @@ -64,17 +64,17 @@ * - failure: * - if offending value is a valid counter, then try again * - if offending value is OOM-during-evac special value: loop until - * counter drops to 0, then exit with read-barrier + * counter drops to 0, then exit with resolving the ptr * * Upon exit, exiting thread will decrease the counter using atomic dec. * * Upon OOM-during-evac, any thread will attempt to CAS OOM-during-evac * special value into the counter. Depending on result: - * - success: busy-loop until counter drops to zero, then exit with RB + * - success: busy-loop until counter drops to zero, then exit with resolve * - failure: * - offender is valid counter update: try again * - offender is OOM-during-evac: busy loop until counter drops to - * zero, then exit with RB + * zero, then exit with resolve */ class ShenandoahEvacOOMHandler { private: @@ -94,7 +94,7 @@ public: * * When this returns true, it is safe to continue with normal evacuation. * When this method returns false, evacuation must not be entered, and caller - * may safely continue with a read-barrier (if Java thread). + * may safely continue with a simple resolve (if Java thread). */ void enter_evacuation(); @@ -106,7 +106,7 @@ public: /** * Signal out-of-memory during evacuation. It will prevent any other threads * from entering the evacuation path, then wait until all threads have left the - * evacuation path, and then return. It is then safe to continue with a read-barrier. + * evacuation path, and then return. It is then safe to continue with a simple resolve. */ void handle_out_of_memory_during_evacuation(); diff --git a/src/hotspot/share/gc/shenandoah/shenandoahHeap.cpp b/src/hotspot/share/gc/shenandoah/shenandoahHeap.cpp index 588f186c3f6..e9178a17947 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahHeap.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahHeap.cpp @@ -389,10 +389,6 @@ void ShenandoahHeap::initialize_heuristics() { err_msg("Heuristics \"%s\" is experimental, and must be enabled via -XX:+UnlockExperimentalVMOptions.", _heuristics->name())); } - - if (ShenandoahStoreValEnqueueBarrier && ShenandoahStoreValReadBarrier) { - vm_exit_during_initialization("Cannot use both ShenandoahStoreValEnqueueBarrier and ShenandoahStoreValReadBarrier"); - } log_info(gc, init)("Shenandoah heuristics: %s", _heuristics->name()); } else { @@ -791,7 +787,7 @@ HeapWord* ShenandoahHeap::allocate_memory(ShenandoahAllocRequest& req) { assert(req.is_gc_alloc(), "Can only accept GC allocs here"); result = allocate_memory_under_lock(req, in_new_region); // Do not call handle_alloc_failure() here, because we cannot block. - // The allocation failure would be handled by the WB slowpath with handle_alloc_failure_evac(). + // The allocation failure would be handled by the LRB slowpath with handle_alloc_failure_evac(). } if (in_new_region) { @@ -1105,7 +1101,6 @@ public: ShenandoahParallelWorkerSession worker_session(worker_id); ShenandoahEvacOOMScope oom_evac_scope; ShenandoahEvacuateUpdateRootsClosure cl; - MarkingCodeBlobClosure blobsCl(&cl, CodeBlobToOopClosure::FixRelocations); _rp->process_evacuate_roots(&cl, &blobsCl, worker_id); } @@ -2062,14 +2057,12 @@ void ShenandoahHeap::unregister_nmethod(nmethod* nm) { } oop ShenandoahHeap::pin_object(JavaThread* thr, oop o) { - o = ShenandoahBarrierSet::barrier_set()->write_barrier(o); ShenandoahHeapLocker locker(lock()); heap_region_containing(o)->make_pinned(); return o; } void ShenandoahHeap::unpin_object(JavaThread* thr, oop o) { - o = ShenandoahBarrierSet::barrier_set()->read_barrier(o); ShenandoahHeapLocker locker(lock()); heap_region_containing(o)->make_unpinned(); } diff --git a/src/hotspot/share/gc/shenandoah/shenandoahHeap.hpp b/src/hotspot/share/gc/shenandoah/shenandoahHeap.hpp index 2258448f95d..cc8d3fdbbf1 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahHeap.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahHeap.hpp @@ -270,16 +270,16 @@ public: // public: enum GCStateBitPos { - // Heap has forwarded objects: need RB, ACMP, CAS barriers. + // Heap has forwarded objects: needs LRB barriers. HAS_FORWARDED_BITPOS = 0, // Heap is under marking: needs SATB barriers. MARKING_BITPOS = 1, - // Heap is under evacuation: needs WB barriers. (Set together with UNSTABLE) + // Heap is under evacuation: needs LRB barriers. (Set together with HAS_FORWARDED) EVACUATION_BITPOS = 2, - // Heap is under updating: needs SVRB/SVWB barriers. + // Heap is under updating: needs no additional barriers. UPDATEREFS_BITPOS = 3, // Heap is under traversal collection diff --git a/src/hotspot/share/gc/shenandoah/shenandoahMarkCompact.cpp b/src/hotspot/share/gc/shenandoah/shenandoahMarkCompact.cpp index b67af972f1e..f71bfcb676b 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahMarkCompact.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahMarkCompact.cpp @@ -129,7 +129,7 @@ void ShenandoahMarkCompact::do_it(GCCause::Cause gc_cause) { // Once marking is done, which may have fixed up forwarded objects, we can drop it. // Coming out of Full GC, we would not have any forwarded objects. - // This also prevents read barrier from kicking in while adjusting pointers in phase3. + // This also prevents resolves with fwdptr from kicking in while adjusting pointers in phase3. heap->set_has_forwarded_objects(false); heap->set_full_gc_move_in_progress(true); diff --git a/src/hotspot/share/gc/shenandoah/shenandoahOopClosures.hpp b/src/hotspot/share/gc/shenandoah/shenandoahOopClosures.hpp index 95304cc33d9..190eae3ac13 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahOopClosures.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahOopClosures.hpp @@ -34,7 +34,7 @@ enum UpdateRefsMode { NONE, // No reference updating - RESOLVE, // Only a read-barrier (no reference updating) + RESOLVE, // Only a resolve (no reference updating) SIMPLE, // Reference updating using simple store CONCURRENT // Reference updating using CAS }; diff --git a/src/hotspot/share/gc/shenandoah/shenandoahRootProcessor.cpp b/src/hotspot/share/gc/shenandoah/shenandoahRootProcessor.cpp index 62e38518681..8b333ee6532 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahRootProcessor.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahRootProcessor.cpp @@ -242,13 +242,21 @@ ShenandoahRootEvacuator::ShenandoahRootEvacuator(ShenandoahHeap* heap, uint n_wo _evacuation_tasks(new SubTasksDone(SHENANDOAH_EVAC_NumElements)), _srs(n_workers), _phase(phase), - _coderoots_cset_iterator(ShenandoahCodeRoots::cset_iterator()) + _coderoots_cset_iterator(ShenandoahCodeRoots::cset_iterator()), + _par_state_string(StringTable::weak_storage()) + { heap->phase_timings()->record_workers_start(_phase); + if (ShenandoahStringDedup::is_enabled()) { + StringDedup::gc_prologue(false); + } } ShenandoahRootEvacuator::~ShenandoahRootEvacuator() { delete _evacuation_tasks; + if (ShenandoahStringDedup::is_enabled()) { + StringDedup::gc_epilogue(); + } ShenandoahHeap::heap()->phase_timings()->record_workers_end(_phase); } @@ -270,11 +278,38 @@ void ShenandoahRootEvacuator::process_evacuate_roots(OopClosure* oops, _coderoots_cset_iterator.possibly_parallel_blobs_do(blobs); } - if (_evacuation_tasks->try_claim_task(SHENANDOAH_EVAC_jvmti_oops_do)) { + if (ShenandoahStringDedup::is_enabled()) { ShenandoahForwardedIsAliveClosure is_alive; + ShenandoahStringDedup::parallel_oops_do(&is_alive, oops, worker_id); + } + + if (_evacuation_tasks->try_claim_task(SHENANDOAH_EVAC_Universe_oops_do)) { + ShenandoahWorkerTimingsTracker timer(worker_times, ShenandoahPhaseTimings::UniverseRoots, worker_id); + Universe::oops_do(oops); + } + + if (_evacuation_tasks->try_claim_task(SHENANDOAH_EVAC_Management_oops_do)) { + ShenandoahWorkerTimingsTracker timer(worker_times, ShenandoahPhaseTimings::ManagementRoots, worker_id); + Management::oops_do(oops); + } + + if (_evacuation_tasks->try_claim_task(SHENANDOAH_EVAC_jvmti_oops_do)) { ShenandoahWorkerTimingsTracker timer(worker_times, ShenandoahPhaseTimings::JVMTIRoots, worker_id); + JvmtiExport::oops_do(oops); + ShenandoahForwardedIsAliveClosure is_alive; JvmtiExport::weak_oops_do(&is_alive, oops); } + + if (_evacuation_tasks->try_claim_task(SHENANDOAH_EVAC_SystemDictionary_oops_do)) { + ShenandoahWorkerTimingsTracker timer(worker_times, ShenandoahPhaseTimings::SystemDictionaryRoots, worker_id); + SystemDictionary::oops_do(oops); + } + + if (_evacuation_tasks->try_claim_task(SHENANDOAH_EVAC_ObjectSynchronizer_oops_do)) { + ShenandoahWorkerTimingsTracker timer(worker_times, ShenandoahPhaseTimings::ObjectSynchronizerRoots, worker_id); + ObjectSynchronizer::oops_do(oops); + } + } uint ShenandoahRootEvacuator::n_workers() const { diff --git a/src/hotspot/share/gc/shenandoah/shenandoahRootProcessor.hpp b/src/hotspot/share/gc/shenandoah/shenandoahRootProcessor.hpp index 323475b2768..2821e950575 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahRootProcessor.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahRootProcessor.hpp @@ -58,7 +58,7 @@ class ShenandoahRootProcessor : public StackObj { StrongRootsScope _srs; OopStorage::ParState _par_state_string; ShenandoahPhaseTimings::Phase _phase; - ParallelCLDRootIterator _cld_iterator; + ParallelCLDRootIterator _cld_iterator; ShenandoahAllCodeRootsIterator _coderoots_all_iterator; CodeBlobClosure* _threads_nmethods_cl; WeakProcessorPhaseTimes _weak_processor_timings; @@ -120,11 +120,16 @@ class ShenandoahRootEvacuator : public StackObj { StrongRootsScope _srs; ShenandoahPhaseTimings::Phase _phase; ShenandoahCsetCodeRootsIterator _coderoots_cset_iterator; + OopStorage::ParState _par_state_string; enum Shenandoah_evacuate_roots_tasks { - SHENANDOAH_EVAC_jvmti_oops_do, - // Leave this one last. - SHENANDOAH_EVAC_NumElements + SHENANDOAH_EVAC_Universe_oops_do, + SHENANDOAH_EVAC_ObjectSynchronizer_oops_do, + SHENANDOAH_EVAC_Management_oops_do, + SHENANDOAH_EVAC_SystemDictionary_oops_do, + SHENANDOAH_EVAC_jvmti_oops_do, + // Leave this one last. + SHENANDOAH_EVAC_NumElements }; public: ShenandoahRootEvacuator(ShenandoahHeap* heap, uint n_workers, diff --git a/src/hotspot/share/gc/shenandoah/shenandoahRuntime.cpp b/src/hotspot/share/gc/shenandoah/shenandoahRuntime.cpp index c011897b251..8fb70834c4d 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahRuntime.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahRuntime.cpp @@ -55,8 +55,8 @@ JRT_LEAF(void, ShenandoahRuntime::write_ref_field_pre_entry(oopDesc* orig, JavaT ShenandoahThreadLocalData::satb_mark_queue(thread).enqueue_known_active(orig); JRT_END -JRT_LEAF(oopDesc*, ShenandoahRuntime::write_barrier_JRT(oopDesc* src)) - oop result = ShenandoahBarrierSet::barrier_set()->write_barrier_mutator(src); +JRT_LEAF(oopDesc*, ShenandoahRuntime::load_reference_barrier_JRT(oopDesc* src)) + oop result = ShenandoahBarrierSet::barrier_set()->load_reference_barrier_mutator(src); return (oopDesc*) result; JRT_END diff --git a/src/hotspot/share/gc/shenandoah/shenandoahRuntime.hpp b/src/hotspot/share/gc/shenandoah/shenandoahRuntime.hpp index 87943ce2047..f142e16f039 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahRuntime.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahRuntime.hpp @@ -37,7 +37,7 @@ public: static void write_ref_array_post_entry(HeapWord* dst, size_t length); static void write_ref_field_pre_entry(oopDesc* orig, JavaThread* thread); - static oopDesc* write_barrier_JRT(oopDesc* src); + static oopDesc* load_reference_barrier_JRT(oopDesc* src); static void shenandoah_clone_barrier(oopDesc* obj); }; diff --git a/src/hotspot/share/gc/shenandoah/shenandoah_globals.hpp b/src/hotspot/share/gc/shenandoah/shenandoah_globals.hpp index 533b728dafd..a6c1742efdd 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoah_globals.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoah_globals.hpp @@ -244,7 +244,7 @@ "Time is in microseconds.") \ \ experimental(uintx, ShenandoahEvacAssist, 10, \ - "How many objects to evacuate on WB assist path. " \ + "How many objects to evacuate on LRB assist path. " \ "Use zero to disable.") \ \ experimental(bool, ShenandoahPacing, true, \ @@ -352,27 +352,18 @@ diagnostic(bool, ShenandoahKeepAliveBarrier, true, \ "Turn on/off keep alive barriers in Shenandoah") \ \ - diagnostic(bool, ShenandoahWriteBarrier, true, \ - "Turn on/off write barriers in Shenandoah") \ - \ - diagnostic(bool, ShenandoahReadBarrier, true, \ - "Turn on/off read barriers in Shenandoah") \ - \ diagnostic(bool, ShenandoahStoreValEnqueueBarrier, false, \ "Turn on/off enqueuing of oops for storeval barriers") \ \ - diagnostic(bool, ShenandoahStoreValReadBarrier, true, \ - "Turn on/off store val read barriers in Shenandoah") \ - \ diagnostic(bool, ShenandoahCASBarrier, true, \ "Turn on/off CAS barriers in Shenandoah") \ \ - diagnostic(bool, ShenandoahAcmpBarrier, true, \ - "Turn on/off acmp barriers in Shenandoah") \ - \ diagnostic(bool, ShenandoahCloneBarrier, true, \ "Turn on/off clone barriers in Shenandoah") \ \ + diagnostic(bool, ShenandoahLoadRefBarrier, true, \ + "Turn on/off load-reference barriers in Shenandoah") \ + \ diagnostic(bool, ShenandoahStoreCheck, false, \ "Emit additional code that checks objects are written to only" \ " in to-space") \ @@ -401,20 +392,13 @@ "Turn it off for maximum compatibility with reflection or JNI " \ "code that manipulates final fields.") \ \ - diagnostic(bool, ShenandoahDecreaseRegisterPressure, false, \ - "Try to reuse after-barrier values to reduce register pressure") \ - \ experimental(bool, ShenandoahCommonGCStateLoads, false, \ "Enable commonming for GC state loads in generated code.") \ \ develop(bool, ShenandoahVerifyOptoBarriers, false, \ "Verify no missing barriers in C2") \ \ - experimental(bool, ShenandoahDontIncreaseWBFreq, true, \ - "Common 2 WriteBarriers or WriteBarrier and a ReadBarrier only " \ - "if the resulting WriteBarrier isn't executed more frequently") \ - \ experimental(bool, ShenandoahLoopOptsAfterExpansion, true, \ - "Attempt more loop opts after write barrier expansion") \ + "Attempt more loop opts after barrier expansion") \ #endif // SHARE_GC_SHENANDOAH_SHENANDOAH_GLOBALS_HPP diff --git a/src/hotspot/share/opto/classes.hpp b/src/hotspot/share/opto/classes.hpp index d090889046e..bb6565e7017 100644 --- a/src/hotspot/share/opto/classes.hpp +++ b/src/hotspot/share/opto/classes.hpp @@ -281,9 +281,7 @@ shmacro(ShenandoahCompareAndSwapP) shmacro(ShenandoahWeakCompareAndSwapN) shmacro(ShenandoahWeakCompareAndSwapP) shmacro(ShenandoahEnqueueBarrier) -shmacro(ShenandoahReadBarrier) -shmacro(ShenandoahWriteBarrier) -shmacro(ShenandoahWBMemProj) +shmacro(ShenandoahLoadReferenceBarrier) macro(SCMemProj) macro(SqrtD) macro(SqrtF) diff --git a/src/hotspot/share/opto/compile.cpp b/src/hotspot/share/opto/compile.cpp index 04d041df3d9..98b81a08913 100644 --- a/src/hotspot/share/opto/compile.cpp +++ b/src/hotspot/share/opto/compile.cpp @@ -3070,7 +3070,7 @@ void Compile::final_graph_reshaping_main_switch(Node* n, Final_Reshape_Counts& f Node *m = wq.at(next); for (DUIterator_Fast imax, i = m->fast_outs(imax); i < imax; i++) { Node* use = m->fast_out(i); - if (use->is_Mem() || use->is_EncodeNarrowPtr() || use->is_ShenandoahBarrier()) { + if (use->is_Mem() || use->is_EncodeNarrowPtr()) { use->ensure_control_or_add_prec(n->in(0)); } else { switch(use->Opcode()) { diff --git a/src/hotspot/share/opto/lcm.cpp b/src/hotspot/share/opto/lcm.cpp index 9e43a24aac5..50c0c2dd341 100644 --- a/src/hotspot/share/opto/lcm.cpp +++ b/src/hotspot/share/opto/lcm.cpp @@ -178,7 +178,6 @@ void PhaseCFG::implicit_null_check(Block* block, Node *proj, Node *val, int allo case Op_LoadRange: case Op_LoadD_unaligned: case Op_LoadL_unaligned: - case Op_ShenandoahReadBarrier: assert(mach->in(2) == val, "should be address"); break; case Op_StoreB: diff --git a/src/hotspot/share/opto/library_call.cpp b/src/hotspot/share/opto/library_call.cpp index bd3daf55db6..f8c5cededc1 100644 --- a/src/hotspot/share/opto/library_call.cpp +++ b/src/hotspot/share/opto/library_call.cpp @@ -4485,7 +4485,7 @@ JVMState* LibraryCallKit::arraycopy_restore_alloc_state(AllocateArrayNode* alloc for (MergeMemStream mms(merged_memory(), mem->as_MergeMem()); mms.next_non_empty2(); ) { Node* n = mms.memory(); if (n != mms.memory2() && !(n->is_Proj() && n->in(0) == alloc->initialization())) { - assert(n->is_Store() || n->Opcode() == Op_ShenandoahWBMemProj, "what else?"); + assert(n->is_Store(), "what else?"); no_interfering_store = false; break; } @@ -4494,7 +4494,7 @@ JVMState* LibraryCallKit::arraycopy_restore_alloc_state(AllocateArrayNode* alloc for (MergeMemStream mms(merged_memory()); mms.next_non_empty(); ) { Node* n = mms.memory(); if (n != mem && !(n->is_Proj() && n->in(0) == alloc->initialization())) { - assert(n->is_Store() || n->Opcode() == Op_ShenandoahWBMemProj, "what else?"); + assert(n->is_Store(), "what else?"); no_interfering_store = false; break; } diff --git a/src/hotspot/share/opto/loopPredicate.cpp b/src/hotspot/share/opto/loopPredicate.cpp index 9534ec44a2a..5d2e69f9bd6 100644 --- a/src/hotspot/share/opto/loopPredicate.cpp +++ b/src/hotspot/share/opto/loopPredicate.cpp @@ -536,9 +536,6 @@ class Invariance : public StackObj { if (_lpt->is_invariant(n)) { // known invariant _invariant.set(n->_idx); } else if (!n->is_CFG()) { - if (n->Opcode() == Op_ShenandoahWriteBarrier) { - return; - } Node *n_ctrl = _phase->ctrl_or_self(n); Node *u_ctrl = _phase->ctrl_or_self(use); // self if use is a CFG if (_phase->is_dominator(n_ctrl, u_ctrl)) { diff --git a/src/hotspot/share/opto/loopnode.cpp b/src/hotspot/share/opto/loopnode.cpp index 672dcda6923..4b1df0a872b 100644 --- a/src/hotspot/share/opto/loopnode.cpp +++ b/src/hotspot/share/opto/loopnode.cpp @@ -3971,7 +3971,7 @@ Node *PhaseIdealLoop::get_late_ctrl( Node *n, Node *early ) { } while(worklist.size() != 0 && LCA != early) { Node* s = worklist.pop(); - if (s->is_Load() || s->is_ShenandoahBarrier() || s->Opcode() == Op_SafePoint || + if (s->is_Load() || s->Opcode() == Op_SafePoint || (s->is_CallStaticJava() && s->as_CallStaticJava()->uncommon_trap_request() != 0)) { continue; } else if (s->is_MergeMem()) { diff --git a/src/hotspot/share/opto/loopnode.hpp b/src/hotspot/share/opto/loopnode.hpp index 09f13ab58d7..6a7b253f7ad 100644 --- a/src/hotspot/share/opto/loopnode.hpp +++ b/src/hotspot/share/opto/loopnode.hpp @@ -38,8 +38,6 @@ class IdealLoopTree; class LoopNode; class Node; class OuterStripMinedLoopEndNode; -class ShenandoahBarrierNode; -class ShenandoahWriteBarrierNode; class PathFrequency; class PhaseIdealLoop; class CountedLoopReserveKit; @@ -638,8 +636,7 @@ class PhaseIdealLoop : public PhaseTransform { friend class IdealLoopTree; friend class SuperWord; friend class CountedLoopReserveKit; - friend class ShenandoahBarrierNode; - friend class ShenandoahWriteBarrierNode; + friend class ShenandoahBarrierC2Support; // Pre-computed def-use info PhaseIterGVN &_igvn; diff --git a/src/hotspot/share/opto/loopopts.cpp b/src/hotspot/share/opto/loopopts.cpp index 5b955cb8775..bb70c2cca41 100644 --- a/src/hotspot/share/opto/loopopts.cpp +++ b/src/hotspot/share/opto/loopopts.cpp @@ -1082,11 +1082,6 @@ static bool merge_point_safe(Node* region) { Node* m = n->fast_out(j); if (m->is_FastLock()) return false; -#if INCLUDE_SHENANDOAHGC - if (m->is_ShenandoahBarrier() && m->has_out_with(Op_FastLock)) { - return false; - } -#endif #ifdef _LP64 if (m->Opcode() == Op_ConvI2L) return false; @@ -3210,7 +3205,7 @@ bool PhaseIdealLoop::partial_peel( IdealLoopTree *loop, Node_List &old_new ) { // if not pinned and not a load (which maybe anti-dependent on a store) // and not a CMove (Matcher expects only bool->cmove). - if (n->in(0) == NULL && !n->is_Load() && !n->is_CMove() && n->Opcode() != Op_ShenandoahWBMemProj) { + if (n->in(0) == NULL && !n->is_Load() && !n->is_CMove()) { cloned_for_outside_use += clone_for_use_outside_loop( loop, n, worklist ); sink_list.push(n); peel >>= n->_idx; // delete n from peel set. diff --git a/src/hotspot/share/opto/node.hpp b/src/hotspot/share/opto/node.hpp index 2f02b98bda7..29b649bafd2 100644 --- a/src/hotspot/share/opto/node.hpp +++ b/src/hotspot/share/opto/node.hpp @@ -142,7 +142,6 @@ class RegionNode; class RootNode; class SafePointNode; class SafePointScalarObjectNode; -class ShenandoahBarrierNode; class StartNode; class State; class StoreNode; @@ -676,7 +675,6 @@ public: DEFINE_CLASS_ID(EncodeNarrowPtr, Type, 6) DEFINE_CLASS_ID(EncodeP, EncodeNarrowPtr, 0) DEFINE_CLASS_ID(EncodePKlass, EncodeNarrowPtr, 1) - DEFINE_CLASS_ID(ShenandoahBarrier, Type, 7) DEFINE_CLASS_ID(Proj, Node, 3) DEFINE_CLASS_ID(CatchProj, Proj, 0) @@ -875,7 +873,6 @@ public: DEFINE_CLASS_QUERY(Root) DEFINE_CLASS_QUERY(SafePoint) DEFINE_CLASS_QUERY(SafePointScalarObject) - DEFINE_CLASS_QUERY(ShenandoahBarrier) DEFINE_CLASS_QUERY(Start) DEFINE_CLASS_QUERY(Store) DEFINE_CLASS_QUERY(Sub) diff --git a/test/hotspot/jtreg/gc/shenandoah/options/TestSelectiveBarrierFlags.java b/test/hotspot/jtreg/gc/shenandoah/options/TestSelectiveBarrierFlags.java index 6c2d7c4da4e..7be36345bf7 100644 --- a/test/hotspot/jtreg/gc/shenandoah/options/TestSelectiveBarrierFlags.java +++ b/test/hotspot/jtreg/gc/shenandoah/options/TestSelectiveBarrierFlags.java @@ -43,13 +43,9 @@ public class TestSelectiveBarrierFlags { public static void main(String[] args) throws Exception { String[][] opts = { new String[] { "ShenandoahKeepAliveBarrier" }, - new String[] { "ShenandoahWriteBarrier" }, - new String[] { "ShenandoahReadBarrier" }, - // StoreValRead+SATB are actually compatible, but we need to protect against - // StorveValEnqueue+SATB. TODO: Make it better. - new String[] { "ShenandoahSATBBarrier", "ShenandoahStoreValReadBarrier", "ShenandoahStoreValEnqueueBarrier" }, + new String[] { "ShenandoahLoadRefBarrier" }, + new String[] { "ShenandoahSATBBarrier", "ShenandoahStoreValEnqueueBarrier" }, new String[] { "ShenandoahCASBarrier" }, - new String[] { "ShenandoahAcmpBarrier" }, new String[] { "ShenandoahCloneBarrier" }, }; diff --git a/test/hotspot/jtreg/gc/shenandoah/options/TestWrongBarrierDisable.java b/test/hotspot/jtreg/gc/shenandoah/options/TestWrongBarrierDisable.java index e8b282fec37..ec5901b90d8 100644 --- a/test/hotspot/jtreg/gc/shenandoah/options/TestWrongBarrierDisable.java +++ b/test/hotspot/jtreg/gc/shenandoah/options/TestWrongBarrierDisable.java @@ -38,21 +38,16 @@ public class TestWrongBarrierDisable { public static void main(String[] args) throws Exception { String[] concurrent = { - "ShenandoahReadBarrier", - "ShenandoahWriteBarrier", + "ShenandoahLoadRefBarrier", "ShenandoahCASBarrier", - "ShenandoahAcmpBarrier", "ShenandoahCloneBarrier", "ShenandoahSATBBarrier", "ShenandoahKeepAliveBarrier", - "ShenandoahStoreValReadBarrier", }; String[] traversal = { - "ShenandoahReadBarrier", - "ShenandoahWriteBarrier", + "ShenandoahLoadRefBarrier", "ShenandoahCASBarrier", - "ShenandoahAcmpBarrier", "ShenandoahCloneBarrier", }; From 05b294ea97abd112433ff785c54a3f8348ccbb9a Mon Sep 17 00:00:00 2001 From: Mikhailo Seledtsov Date: Thu, 4 Apr 2019 12:29:43 -0700 Subject: [PATCH 14/73] 8221710: [TESTBUG] more configurable parameters for docker testing Introduced docker test config properties Reviewed-by: lmesnik, iignatyev, egahlin --- .../containers/docker/DockerBasicTest.java | 5 +-- .../containers/docker/DockerTestUtils.java | 37 +++++++++++++------ 2 files changed, 27 insertions(+), 15 deletions(-) diff --git a/test/hotspot/jtreg/runtime/containers/docker/DockerBasicTest.java b/test/hotspot/jtreg/runtime/containers/docker/DockerBasicTest.java index 6087ef69bbe..792418f074d 100644 --- a/test/hotspot/jtreg/runtime/containers/docker/DockerBasicTest.java +++ b/test/hotspot/jtreg/runtime/containers/docker/DockerBasicTest.java @@ -42,8 +42,6 @@ import jdk.test.lib.Utils; public class DockerBasicTest { private static final String imageNameAndTag = Common.imageName("basic"); - // Diganostics: set to false to examine image after the test - private static final boolean removeImageAfterTest = true; public static void main(String[] args) throws Exception { if (!DockerTestUtils.canTestDocker()) { @@ -56,8 +54,9 @@ public class DockerBasicTest { testJavaVersion(); testHelloDocker(); } finally { - if (removeImageAfterTest) + if (!DockerTestUtils.RETAIN_IMAGE_AFTER_TEST) { DockerTestUtils.removeDockerImage(imageNameAndTag); + } } } diff --git a/test/lib/jdk/test/lib/containers/docker/DockerTestUtils.java b/test/lib/jdk/test/lib/containers/docker/DockerTestUtils.java index 0e71aa9e646..2bcf9468867 100644 --- a/test/lib/jdk/test/lib/containers/docker/DockerTestUtils.java +++ b/test/lib/jdk/test/lib/containers/docker/DockerTestUtils.java @@ -38,6 +38,7 @@ import java.util.List; import jdk.test.lib.Utils; import jdk.test.lib.process.OutputAnalyzer; import jdk.test.lib.process.ProcessTools; +import jtreg.SkippedException; public class DockerTestUtils { @@ -45,8 +46,23 @@ public class DockerTestUtils { private static boolean isDockerEngineAvailable = false; private static boolean wasDockerEngineChecked = false; - // Diagnostics: set to true to enable more diagnostic info - private static final boolean DEBUG = false; + // Use this property to specify docker location on your system. + // E.g.: "/usr/local/bin/docker". + private static final String DOCKER_COMMAND = + System.getProperty("jdk.test.docker.command", "docker"); + + // Set this property to true to retain image after test. By default + // images are removed after test execution completes. + // Retaining the image can be useful for diagnostics and image inspection. + // E.g.: start image interactively: docker run -it . + public static final boolean RETAIN_IMAGE_AFTER_TEST = + Boolean.getBoolean("jdk.test.docker.retain.image"); + + // Path to a JDK under test. + // This may be useful when developing tests on non-Linux platforms. + public static final String JDK_UNDER_TEST = + System.getProperty("jdk.test.docker.jdk", Utils.TEST_JDK); + /** * Optimized check of whether the docker engine is available in a given @@ -76,9 +92,7 @@ public class DockerTestUtils { if (isDockerEngineAvailable()) { return true; } else { - System.out.println("Docker engine is not available on this system"); - System.out.println("This test is SKIPPED"); - return false; + throw new SkippedException("Docker engine is not available on this system"); } } @@ -94,7 +108,7 @@ public class DockerTestUtils { */ private static boolean isDockerEngineAvailableCheck() throws Exception { try { - execute("docker", "ps") + execute(DOCKER_COMMAND, "ps") .shouldHaveExitValue(0) .shouldContain("CONTAINER") .shouldContain("IMAGE"); @@ -126,7 +140,7 @@ public class DockerTestUtils { throw new RuntimeException("The docker build directory already exists: " + buildDir); } - Path jdkSrcDir = Paths.get(Utils.TEST_JDK); + Path jdkSrcDir = Paths.get(JDK_UNDER_TEST); Path jdkDstDir = buildDir.resolve("jdk"); Files.createDirectories(jdkDstDir); @@ -157,7 +171,7 @@ public class DockerTestUtils { DockerfileConfig.getBaseImageVersion()); // Build the docker - execute("docker", "build", "--no-cache", "--tag", imageName, buildDir.toString()) + execute(DOCKER_COMMAND, "build", "--no-cache", "--tag", imageName, buildDir.toString()) .shouldHaveExitValue(0) .shouldContain("Successfully built"); } @@ -174,7 +188,7 @@ public class DockerTestUtils { public static OutputAnalyzer dockerRunJava(DockerRunOptions opts) throws Exception { ArrayList cmd = new ArrayList<>(); - cmd.add("docker"); + cmd.add(DOCKER_COMMAND); cmd.add("run"); if (opts.tty) cmd.add("--tty=true"); @@ -201,11 +215,10 @@ public class DockerTestUtils { * Remove docker image * * @param DockerRunOptions optins for running docker - * @return output of the command * @throws Exception */ - public static OutputAnalyzer removeDockerImage(String imageNameAndTag) throws Exception { - return execute("docker", "rmi", "--force", imageNameAndTag); + public static void removeDockerImage(String imageNameAndTag) throws Exception { + execute(DOCKER_COMMAND, "rmi", "--force", imageNameAndTag); } From 6292ecd39b8cfa8e27120bf01ad188602f9a87cc Mon Sep 17 00:00:00 2001 From: Roman Kennke Date: Thu, 4 Apr 2019 21:29:46 +0200 Subject: [PATCH 15/73] 8221848: Shenandoah: ArrayCopy post-barrier improvements Reviewed-by: zgu --- .../shenandoahBarrierSetAssembler_aarch64.cpp | 12 ++++++++++++ .../shenandoahBarrierSetAssembler_x86.cpp | 19 +++++++++++++++++++ .../gc/shenandoah/shenandoahBarrierSet.cpp | 10 +++------- .../gc/shenandoah/shenandoahBarrierSet.hpp | 2 -- .../shenandoahBarrierSet.inline.hpp | 8 +------- .../share/gc/shenandoah/shenandoahHeap.cpp | 10 +++++++--- 6 files changed, 42 insertions(+), 19 deletions(-) diff --git a/src/hotspot/cpu/aarch64/gc/shenandoah/shenandoahBarrierSetAssembler_aarch64.cpp b/src/hotspot/cpu/aarch64/gc/shenandoah/shenandoahBarrierSetAssembler_aarch64.cpp index 139738e171e..a104748dbf6 100644 --- a/src/hotspot/cpu/aarch64/gc/shenandoah/shenandoahBarrierSetAssembler_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/gc/shenandoah/shenandoahBarrierSetAssembler_aarch64.cpp @@ -87,6 +87,16 @@ void ShenandoahBarrierSetAssembler::arraycopy_prologue(MacroAssembler* masm, Dec void ShenandoahBarrierSetAssembler::arraycopy_epilogue(MacroAssembler* masm, DecoratorSet decorators, bool is_oop, Register start, Register count, Register scratch, RegSet saved_regs) { if (is_oop) { + Label done; + + // Avoid calling runtime if count == 0 + __ cbz(count, done); + + // Is updating references? + Address gc_state(rthread, in_bytes(ShenandoahThreadLocalData::gc_state_offset())); + __ ldrb(rscratch1, gc_state); + __ tbz(rscratch1, ShenandoahHeap::UPDATEREFS_BITPOS, done); + __ push(saved_regs, sp); assert_different_registers(start, count, scratch); assert_different_registers(c_rarg0, count); @@ -94,6 +104,8 @@ void ShenandoahBarrierSetAssembler::arraycopy_epilogue(MacroAssembler* masm, Dec __ mov(c_rarg1, count); __ call_VM_leaf(CAST_FROM_FN_PTR(address, ShenandoahRuntime::write_ref_array_post_entry), 2); __ pop(saved_regs, sp); + + __ bind(done); } } diff --git a/src/hotspot/cpu/x86/gc/shenandoah/shenandoahBarrierSetAssembler_x86.cpp b/src/hotspot/cpu/x86/gc/shenandoah/shenandoahBarrierSetAssembler_x86.cpp index f3c74751053..d9fd352ec90 100644 --- a/src/hotspot/cpu/x86/gc/shenandoah/shenandoahBarrierSetAssembler_x86.cpp +++ b/src/hotspot/cpu/x86/gc/shenandoah/shenandoahBarrierSetAssembler_x86.cpp @@ -138,6 +138,22 @@ void ShenandoahBarrierSetAssembler::arraycopy_epilogue(MacroAssembler* masm, Dec } #endif + Register thread = NOT_LP64(rax) LP64_ONLY(r15_thread); +#ifndef _LP64 + __ push(thread); + __ get_thread(thread); +#endif + + // Short-circuit if count == 0. + Label done; + __ testptr(count, count); + __ jcc(Assembler::zero, done); + + // Skip runtime call if no forwarded objects. + Address gc_state(thread, in_bytes(ShenandoahThreadLocalData::gc_state_offset())); + __ testb(gc_state, ShenandoahHeap::UPDATEREFS); + __ jcc(Assembler::zero, done); + __ pusha(); // push registers (overkill) #ifdef _LP64 if (c_rarg0 == count) { // On win64 c_rarg0 == rcx @@ -155,6 +171,9 @@ void ShenandoahBarrierSetAssembler::arraycopy_epilogue(MacroAssembler* masm, Dec dst, count); #endif __ popa(); + + __ bind(done); + NOT_LP64(__ pop(thread);) } } diff --git a/src/hotspot/share/gc/shenandoah/shenandoahBarrierSet.cpp b/src/hotspot/share/gc/shenandoah/shenandoahBarrierSet.cpp index 02a64b29e4e..7ff8dbf6b22 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahBarrierSet.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahBarrierSet.cpp @@ -107,11 +107,8 @@ void ShenandoahBarrierSet::write_ref_array_loop(HeapWord* start, size_t count) { } void ShenandoahBarrierSet::write_ref_array(HeapWord* start, size_t count) { - assert(UseShenandoahGC, "should be enabled"); - if (count == 0) return; - if (!ShenandoahCloneBarrier) return; - - if (!need_update_refs_barrier()) return; + assert(_heap->is_update_refs_in_progress(), "should not be here otherwise"); + assert(count > 0, "Should have been filtered before"); if (_heap->is_concurrent_traversal_in_progress()) { ShenandoahEvacOOMScope oom_evac_scope; @@ -197,9 +194,8 @@ void ShenandoahBarrierSet::write_ref_field_work(void* v, oop o, bool release) { } void ShenandoahBarrierSet::write_region(MemRegion mr) { - assert(UseShenandoahGC, "should be enabled"); if (!ShenandoahCloneBarrier) return; - if (! need_update_refs_barrier()) return; + if (!_heap->is_update_refs_in_progress()) return; // This is called for cloning an object (see jvm.cpp) after the clone // has been made. We are not interested in any 'previous value' because diff --git a/src/hotspot/share/gc/shenandoah/shenandoahBarrierSet.hpp b/src/hotspot/share/gc/shenandoah/shenandoahBarrierSet.hpp index 1edaa26d0e1..d1a08b8c5cc 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahBarrierSet.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahBarrierSet.hpp @@ -100,8 +100,6 @@ public: void enqueue(oop obj); private: - inline bool need_update_refs_barrier(); - template void write_ref_array_loop(HeapWord* start, size_t count); diff --git a/src/hotspot/share/gc/shenandoah/shenandoahBarrierSet.inline.hpp b/src/hotspot/share/gc/shenandoah/shenandoahBarrierSet.inline.hpp index f902ec59d9c..66b361b66b9 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahBarrierSet.inline.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahBarrierSet.inline.hpp @@ -32,12 +32,6 @@ #include "gc/shenandoah/shenandoahMarkingContext.inline.hpp" #include "gc/shenandoah/shenandoahThreadLocalData.hpp" -bool ShenandoahBarrierSet::need_update_refs_barrier() { - return _heap->is_update_refs_in_progress() || - _heap->is_concurrent_traversal_in_progress() || - (_heap->is_concurrent_mark_in_progress() && _heap->has_forwarded_objects()); -} - inline oop ShenandoahBarrierSet::resolve_forwarded_not_null(oop p) { return ShenandoahBrooksPointer::forwardee(p); } @@ -344,7 +338,7 @@ bool ShenandoahBarrierSet::AccessBarrier::oop_arraycopy if (heap->has_forwarded_objects()) { if (heap->is_concurrent_traversal_in_progress()) { storeval_mode = WRITE_BARRIER; - } else if (heap->is_concurrent_mark_in_progress() || heap->is_update_refs_in_progress()) { + } else if (heap->is_update_refs_in_progress()) { storeval_mode = READ_BARRIER; } else { assert(heap->is_idle() || heap->is_evacuation_in_progress(), "must not have anything in progress"); diff --git a/src/hotspot/share/gc/shenandoah/shenandoahHeap.cpp b/src/hotspot/share/gc/shenandoah/shenandoahHeap.cpp index e9178a17947..3fae82abc49 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahHeap.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahHeap.cpp @@ -1795,13 +1795,13 @@ void ShenandoahHeap::op_degenerated_futile() { void ShenandoahHeap::stop_concurrent_marking() { assert(is_concurrent_mark_in_progress(), "How else could we get here?"); + set_concurrent_mark_in_progress(false); if (!cancelled_gc()) { // If we needed to update refs, and concurrent marking has been cancelled, // we need to finish updating references. set_has_forwarded_objects(false); mark_complete_marking_context(); } - set_concurrent_mark_in_progress(false); } void ShenandoahHeap::force_satb_flush_all_threads() { @@ -1831,12 +1831,16 @@ void ShenandoahHeap::set_gc_state_mask(uint mask, bool value) { } void ShenandoahHeap::set_concurrent_mark_in_progress(bool in_progress) { - set_gc_state_mask(MARKING, in_progress); + if (has_forwarded_objects()) { + set_gc_state_mask(MARKING | UPDATEREFS, in_progress); + } else { + set_gc_state_mask(MARKING, in_progress); + } ShenandoahBarrierSet::satb_mark_queue_set().set_active_all_threads(in_progress, !in_progress); } void ShenandoahHeap::set_concurrent_traversal_in_progress(bool in_progress) { - set_gc_state_mask(TRAVERSAL | HAS_FORWARDED, in_progress); + set_gc_state_mask(TRAVERSAL | HAS_FORWARDED | UPDATEREFS, in_progress); ShenandoahBarrierSet::satb_mark_queue_set().set_active_all_threads(in_progress, !in_progress); } From fbba7c49b612e489447eadd564a7c97269faaa5a Mon Sep 17 00:00:00 2001 From: Erik Joelsson Date: Thu, 4 Apr 2019 13:56:04 -0700 Subject: [PATCH 16/73] 8221996: Bootcycle build broken Reviewed-by: tbell --- make/Main.gmk | 1 + 1 file changed, 1 insertion(+) diff --git a/make/Main.gmk b/make/Main.gmk index 0b3319c484e..4da01b131d5 100644 --- a/make/Main.gmk +++ b/make/Main.gmk @@ -335,6 +335,7 @@ BOOTCYCLE_TARGET := product-images bootcycle-images: ifneq ($(COMPILE_TYPE), cross) $(call LogWarn, Boot cycle build step 2: Building a new JDK image using previously built image) + $(call MakeDir, $(OUTPUTDIR)/bootcycle-build) +$(MAKE) $(MAKE_ARGS) -f $(TOPDIR)/make/Init.gmk PARALLEL_TARGETS=$(BOOTCYCLE_TARGET) \ JOBS= SPEC=$(dir $(SPEC))bootcycle-spec.gmk main else From 3233a6f944d23800b60f0d8d0bd48d5ff30fddb1 Mon Sep 17 00:00:00 2001 From: Claes Redestad Date: Thu, 4 Apr 2019 23:19:26 +0200 Subject: [PATCH 17/73] 8221980: Simplify Optional implementation Reviewed-by: smarks, clanger --- .../share/classes/java/util/Optional.java | 25 +++++++------------ 1 file changed, 9 insertions(+), 16 deletions(-) diff --git a/src/java.base/share/classes/java/util/Optional.java b/src/java.base/share/classes/java/util/Optional.java index 0b62a6fa917..9533e35e60e 100644 --- a/src/java.base/share/classes/java/util/Optional.java +++ b/src/java.base/share/classes/java/util/Optional.java @@ -61,23 +61,13 @@ public final class Optional { /** * Common instance for {@code empty()}. */ - private static final Optional EMPTY = new Optional<>(); + private static final Optional EMPTY = new Optional<>(null); /** * If non-null, the value; if null, indicates no value is present */ private final T value; - /** - * Constructs an empty instance. - * - * @implNote Generally only one empty instance, {@link Optional#EMPTY}, - * should exist per VM. - */ - private Optional() { - this.value = null; - } - /** * Returns an empty {@code Optional} instance. No value is present for this * {@code Optional}. @@ -100,11 +90,12 @@ public final class Optional { /** * Constructs an instance with the described value. * - * @param value the non-{@code null} value to describe - * @throws NullPointerException if value is {@code null} + * @param value the value to describe; it's the caller's responsibility to + * ensure the value is non-{@code null} unless creating the singleton + * instance returned by {@code empty()}. */ private Optional(T value) { - this.value = Objects.requireNonNull(value); + this.value = value; } /** @@ -117,7 +108,7 @@ public final class Optional { * @throws NullPointerException if value is {@code null} */ public static Optional of(T value) { - return new Optional<>(value); + return new Optional<>(Objects.requireNonNull(value)); } /** @@ -129,8 +120,10 @@ public final class Optional { * @return an {@code Optional} with a present value if the specified value * is non-{@code null}, otherwise an empty {@code Optional} */ + @SuppressWarnings("unchecked") public static Optional ofNullable(T value) { - return value == null ? empty() : of(value); + return value == null ? (Optional) EMPTY + : new Optional<>(value); } /** From 15d989faa4fbf66eb8ca25169f8efda9d918f6b7 Mon Sep 17 00:00:00 2001 From: Claes Redestad Date: Thu, 4 Apr 2019 23:21:24 +0200 Subject: [PATCH 18/73] 8221981: Simplify Map/List/Set.of() implementation Reviewed-by: smarks --- .../classes/java/util/ImmutableCollections.java | 17 +---------------- src/java.base/share/classes/java/util/List.java | 7 +++++-- src/java.base/share/classes/java/util/Map.java | 7 +++++-- src/java.base/share/classes/java/util/Set.java | 7 +++++-- 4 files changed, 16 insertions(+), 22 deletions(-) diff --git a/src/java.base/share/classes/java/util/ImmutableCollections.java b/src/java.base/share/classes/java/util/ImmutableCollections.java index 2a3aaf0e190..71f544f1954 100644 --- a/src/java.base/share/classes/java/util/ImmutableCollections.java +++ b/src/java.base/share/classes/java/util/ImmutableCollections.java @@ -95,11 +95,6 @@ class ImmutableCollections { } } - @SuppressWarnings("unchecked") - static List emptyList() { - return (List) ListN.EMPTY_LIST; - } - static abstract class AbstractImmutableList extends AbstractImmutableCollection implements List, RandomAccess { @@ -556,11 +551,6 @@ class ImmutableCollections { public abstract int hashCode(); } - @SuppressWarnings("unchecked") - static Set emptySet() { - return (Set) SetN.EMPTY_SET; - } - static final class Set12 extends AbstractImmutableSet implements Serializable { @@ -844,11 +834,6 @@ class ImmutableCollections { // ---------- Map Implementations ---------- - @SuppressWarnings("unchecked") - static Map emptyMap() { - return (Map) MapN.EMPTY_MAP; - } - abstract static class AbstractImmutableMap extends AbstractMap implements Serializable { @Override public void clear() { throw uoe(); } @Override public V compute(K key, BiFunction rf) { throw uoe(); } @@ -1248,7 +1233,7 @@ final class CollSer implements Serializable { return Set.of(array); case IMM_MAP: if (array.length == 0) { - return ImmutableCollections.emptyMap(); + return ImmutableCollections.MapN.EMPTY_MAP; } else if (array.length == 2) { return new ImmutableCollections.Map1<>(array[0], array[1]); } else { diff --git a/src/java.base/share/classes/java/util/List.java b/src/java.base/share/classes/java/util/List.java index 686875a42b7..8cc4d8a9a43 100644 --- a/src/java.base/share/classes/java/util/List.java +++ b/src/java.base/share/classes/java/util/List.java @@ -787,8 +787,9 @@ public interface List extends Collection { * * @since 9 */ + @SuppressWarnings("unchecked") static List of() { - return ImmutableCollections.emptyList(); + return (List) ImmutableCollections.ListN.EMPTY_LIST; } /** @@ -1031,7 +1032,9 @@ public interface List extends Collection { static List of(E... elements) { switch (elements.length) { // implicit null check of elements case 0: - return ImmutableCollections.emptyList(); + @SuppressWarnings("unchecked") + var list = (List) ImmutableCollections.ListN.EMPTY_LIST; + return list; case 1: return new ImmutableCollections.List12<>(elements[0]); case 2: diff --git a/src/java.base/share/classes/java/util/Map.java b/src/java.base/share/classes/java/util/Map.java index 1148e638922..9b60b26de09 100644 --- a/src/java.base/share/classes/java/util/Map.java +++ b/src/java.base/share/classes/java/util/Map.java @@ -1286,8 +1286,9 @@ public interface Map { * * @since 9 */ + @SuppressWarnings("unchecked") static Map of() { - return ImmutableCollections.emptyMap(); + return (Map) ImmutableCollections.MapN.EMPTY_MAP; } /** @@ -1604,7 +1605,9 @@ public interface Map { @SuppressWarnings("varargs") static Map ofEntries(Entry... entries) { if (entries.length == 0) { // implicit null check of entries array - return ImmutableCollections.emptyMap(); + @SuppressWarnings("unchecked") + var map = (Map) ImmutableCollections.MapN.EMPTY_MAP; + return map; } else if (entries.length == 1) { // implicit null check of the array slot return new ImmutableCollections.Map1<>(entries[0].getKey(), diff --git a/src/java.base/share/classes/java/util/Set.java b/src/java.base/share/classes/java/util/Set.java index 504904f2263..8897de89de8 100644 --- a/src/java.base/share/classes/java/util/Set.java +++ b/src/java.base/share/classes/java/util/Set.java @@ -448,8 +448,9 @@ public interface Set extends Collection { * * @since 9 */ + @SuppressWarnings("unchecked") static Set of() { - return ImmutableCollections.emptySet(); + return (Set) ImmutableCollections.SetN.EMPTY_SET; } /** @@ -692,7 +693,9 @@ public interface Set extends Collection { static Set of(E... elements) { switch (elements.length) { // implicit null check of elements case 0: - return ImmutableCollections.emptySet(); + @SuppressWarnings("unchecked") + var set = (Set) ImmutableCollections.SetN.EMPTY_SET; + return set; case 1: return new ImmutableCollections.Set12<>(elements[0]); case 2: From f7fa05ca72d15b121af2b4fa04b3f1d86f297e10 Mon Sep 17 00:00:00 2001 From: Claes Redestad Date: Thu, 4 Apr 2019 23:21:52 +0200 Subject: [PATCH 19/73] 8221921: Implement size() / isEmpty() in immutable collections Reviewed-by: smarks --- .../java/util/ImmutableCollections.java | 32 ++++++++++++++++++- 1 file changed, 31 insertions(+), 1 deletion(-) diff --git a/src/java.base/share/classes/java/util/ImmutableCollections.java b/src/java.base/share/classes/java/util/ImmutableCollections.java index 71f544f1954..c16998050d1 100644 --- a/src/java.base/share/classes/java/util/ImmutableCollections.java +++ b/src/java.base/share/classes/java/util/ImmutableCollections.java @@ -403,6 +403,11 @@ class ImmutableCollections { return e1 != null ? 2 : 1; } + @Override + public boolean isEmpty() { + return false; + } + @Override public E get(int index) { if (index == 0) { @@ -480,7 +485,7 @@ class ImmutableCollections { @Override public boolean isEmpty() { - return size() == 0; + return elements.length == 0; } @Override @@ -578,6 +583,11 @@ class ImmutableCollections { return (e1 == null) ? 1 : 2; } + @Override + public boolean isEmpty() { + return false; + } + @Override public boolean contains(Object o) { return o.equals(e0) || o.equals(e1); // implicit nullcheck of o @@ -705,6 +715,11 @@ class ImmutableCollections { return size; } + @Override + public boolean isEmpty() { + return size == 0; + } + @Override public boolean contains(Object o) { Objects.requireNonNull(o); @@ -876,6 +891,16 @@ class ImmutableCollections { return o.equals(v0); // implicit nullcheck of o } + @Override + public int size() { + return 1; + } + + @Override + public boolean isEmpty() { + return false; + } + private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException { throw new InvalidObjectException("not serial proxy"); } @@ -993,6 +1018,11 @@ class ImmutableCollections { return size; } + @Override + public boolean isEmpty() { + return size == 0; + } + class MapNIterator implements Iterator> { private int remaining; From d812742d687cf6e8748d65552831f60be156c860 Mon Sep 17 00:00:00 2001 From: Xue-Lei Andrew Fan Date: Thu, 4 Apr 2019 14:19:29 -0700 Subject: [PATCH 20/73] 8163326: Update the default enabled cipher suites preference Reviewed-by: mullan --- .../classes/sun/security/ssl/CipherSuite.java | 302 +++++++++++------- .../ciphersuites/CheckCipherSuites.java | 234 +++++++++----- 2 files changed, 340 insertions(+), 196 deletions(-) diff --git a/src/java.base/share/classes/sun/security/ssl/CipherSuite.java b/src/java.base/share/classes/sun/security/ssl/CipherSuite.java index f62bd421952..eb76b75c31b 100644 --- a/src/java.base/share/classes/sun/security/ssl/CipherSuite.java +++ b/src/java.base/share/classes/sun/security/ssl/CipherSuite.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 2019, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -56,20 +56,22 @@ enum CipherSuite { // the following criteria: // 1. Prefer Suite B compliant cipher suites, see RFC6460 (To be // changed later, see below). - // 2. Prefer the stronger bulk cipher, in the order of AES_256(GCM), + // 2. Prefer forward secrecy cipher suites. + // 3. Prefer the stronger bulk cipher, in the order of AES_256(GCM), // AES_128(GCM), AES_256, AES_128, 3DES-EDE. - // 3. Prefer the stronger MAC algorithm, in the order of SHA384, + // 4. Prefer the stronger MAC algorithm, in the order of SHA384, // SHA256, SHA, MD5. - // 4. Prefer the better performance of key exchange and digital + // 5. Prefer the better performance of key exchange and digital // signature algorithm, in the order of ECDHE-ECDSA, ECDHE-RSA, - // RSA, ECDH-ECDSA, ECDH-RSA, DHE-RSA, DHE-DSS. + // DHE-RSA, DHE-DSS, ECDH-ECDSA, ECDH-RSA, RSA. - TLS_AES_128_GCM_SHA256( - 0x1301, true, "TLS_AES_128_GCM_SHA256", - ProtocolVersion.PROTOCOLS_OF_13, B_AES_128_GCM_IV, H_SHA256), + // TLS 1.3 cipher suites. TLS_AES_256_GCM_SHA384( 0x1302, true, "TLS_AES_256_GCM_SHA384", ProtocolVersion.PROTOCOLS_OF_13, B_AES_256_GCM_IV, H_SHA384), + TLS_AES_128_GCM_SHA256( + 0x1301, true, "TLS_AES_128_GCM_SHA256", + ProtocolVersion.PROTOCOLS_OF_13, B_AES_128_GCM_IV, H_SHA256), TLS_CHACHA20_POLY1305_SHA256( 0x1303, true, "TLS_CHACHA20_POLY1305_SHA256", ProtocolVersion.PROTOCOLS_OF_13, B_CC20_P1305, H_SHA256), @@ -97,7 +99,11 @@ enum CipherSuite { ProtocolVersion.PROTOCOLS_OF_12, K_ECDHE_ECDSA, B_CC20_P1305, M_NULL, H_SHA256), - // AES_256(GCM) + // + // Forward screcy cipher suites. + // + + // AES_256(GCM) - ECDHE TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384( 0xC030, true, "TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384", "", ProtocolVersion.PROTOCOLS_OF_12, @@ -106,18 +112,14 @@ enum CipherSuite { 0xCCA8, true, "TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256", "", ProtocolVersion.PROTOCOLS_OF_12, K_ECDHE_RSA, B_CC20_P1305, M_NULL, H_SHA256), - TLS_RSA_WITH_AES_256_GCM_SHA384( - 0x009D, true, "TLS_RSA_WITH_AES_256_GCM_SHA384", "", + + // AES_128(GCM) - ECDHE + TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256( + 0xC02F, true, "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256", "", ProtocolVersion.PROTOCOLS_OF_12, - K_RSA, B_AES_256_GCM, M_NULL, H_SHA384), - TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384( - 0xC02E, true, "TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384", "", - ProtocolVersion.PROTOCOLS_OF_12, - K_ECDH_ECDSA, B_AES_256_GCM, M_NULL, H_SHA384), - TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384( - 0xC032, true, "TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384", "", - ProtocolVersion.PROTOCOLS_OF_12, - K_ECDH_RSA, B_AES_256_GCM, M_NULL, H_SHA384), + K_ECDHE_RSA, B_AES_128_GCM, M_NULL, H_SHA256), + + // AES_256(GCM) - DHE TLS_DHE_RSA_WITH_AES_256_GCM_SHA384( 0x009F, true, "TLS_DHE_RSA_WITH_AES_256_GCM_SHA384", "", ProtocolVersion.PROTOCOLS_OF_12, @@ -131,23 +133,7 @@ enum CipherSuite { ProtocolVersion.PROTOCOLS_OF_12, K_DHE_DSS, B_AES_256_GCM, M_NULL, H_SHA384), - // AES_128(GCM) - TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256( - 0xC02F, true, "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256", "", - ProtocolVersion.PROTOCOLS_OF_12, - K_ECDHE_RSA, B_AES_128_GCM, M_NULL, H_SHA256), - TLS_RSA_WITH_AES_128_GCM_SHA256( - 0x009C, true, "TLS_RSA_WITH_AES_128_GCM_SHA256", "", - ProtocolVersion.PROTOCOLS_OF_12, - K_RSA, B_AES_128_GCM, M_NULL, H_SHA256), - TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256( - 0xC02D, true, "TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256", "", - ProtocolVersion.PROTOCOLS_OF_12, - K_ECDH_ECDSA, B_AES_128_GCM, M_NULL, H_SHA256), - TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256( - 0xC031, true, "TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256", "", - ProtocolVersion.PROTOCOLS_OF_12, - K_ECDH_RSA, B_AES_128_GCM, M_NULL, H_SHA256), + // AES_128(GCM) - DHE TLS_DHE_RSA_WITH_AES_128_GCM_SHA256( 0x009E, true, "TLS_DHE_RSA_WITH_AES_128_GCM_SHA256", "", ProtocolVersion.PROTOCOLS_OF_12, @@ -157,7 +143,7 @@ enum CipherSuite { ProtocolVersion.PROTOCOLS_OF_12, K_DHE_DSS, B_AES_128_GCM, M_NULL, H_SHA256), - // AES_256(CBC) + // AES_256(CBC) - ECDHE TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384( 0xC024, true, "TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384", "", ProtocolVersion.PROTOCOLS_OF_12, @@ -166,18 +152,18 @@ enum CipherSuite { 0xC028, true, "TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384", "", ProtocolVersion.PROTOCOLS_OF_12, K_ECDHE_RSA, B_AES_256, M_SHA384, H_SHA384), - TLS_RSA_WITH_AES_256_CBC_SHA256( - 0x003D, true, "TLS_RSA_WITH_AES_256_CBC_SHA256", "", + + // AES_128(CBC) - ECDHE + TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256( + 0xC023, true, "TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256", "", ProtocolVersion.PROTOCOLS_OF_12, - K_RSA, B_AES_256, M_SHA256, H_SHA256), - TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384( - 0xC026, true, "TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384", "", + K_ECDHE_ECDSA, B_AES_128, M_SHA256, H_SHA256), + TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256( + 0xC027, true, "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256", "", ProtocolVersion.PROTOCOLS_OF_12, - K_ECDH_ECDSA, B_AES_256, M_SHA384, H_SHA384), - TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384( - 0xC02A, true, "TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384", "", - ProtocolVersion.PROTOCOLS_OF_12, - K_ECDH_RSA, B_AES_256, M_SHA384, H_SHA384), + K_ECDHE_RSA, B_AES_128, M_SHA256, H_SHA256), + + // AES_256(CBC) - DHE TLS_DHE_RSA_WITH_AES_256_CBC_SHA256( 0x006B, true, "TLS_DHE_RSA_WITH_AES_256_CBC_SHA256", "", ProtocolVersion.PROTOCOLS_OF_12, @@ -187,56 +173,7 @@ enum CipherSuite { ProtocolVersion.PROTOCOLS_OF_12, K_DHE_DSS, B_AES_256, M_SHA256, H_SHA256), - TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA( - 0xC00A, true, "TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA", "", - ProtocolVersion.PROTOCOLS_TO_12, - K_ECDHE_ECDSA, B_AES_256, M_SHA, H_SHA256), - TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA( - 0xC014, true, "TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA", "", - ProtocolVersion.PROTOCOLS_TO_12, - K_ECDHE_RSA, B_AES_256, M_SHA, H_SHA256), - TLS_RSA_WITH_AES_256_CBC_SHA( - 0x0035, true, "TLS_RSA_WITH_AES_256_CBC_SHA", "", - ProtocolVersion.PROTOCOLS_TO_12, - K_RSA, B_AES_256, M_SHA, H_SHA256), - TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA( - 0xC005, true, "TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA", "", - ProtocolVersion.PROTOCOLS_TO_12, - K_ECDH_ECDSA, B_AES_256, M_SHA, H_SHA256), - TLS_ECDH_RSA_WITH_AES_256_CBC_SHA( - 0xC00F, true, "TLS_ECDH_RSA_WITH_AES_256_CBC_SHA", "", - ProtocolVersion.PROTOCOLS_TO_12, - K_ECDH_RSA, B_AES_256, M_SHA, H_SHA256), - TLS_DHE_RSA_WITH_AES_256_CBC_SHA( - 0x0039, true, "TLS_DHE_RSA_WITH_AES_256_CBC_SHA", "", - ProtocolVersion.PROTOCOLS_TO_12, - K_DHE_RSA, B_AES_256, M_SHA, H_SHA256), - TLS_DHE_DSS_WITH_AES_256_CBC_SHA( - 0x0038, true, "TLS_DHE_DSS_WITH_AES_256_CBC_SHA", "", - ProtocolVersion.PROTOCOLS_TO_12, - K_DHE_DSS, B_AES_256, M_SHA, H_SHA256), - - // AES_128(CBC) - TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256( - 0xC023, true, "TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256", "", - ProtocolVersion.PROTOCOLS_OF_12, - K_ECDHE_ECDSA, B_AES_128, M_SHA256, H_SHA256), - TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256( - 0xC027, true, "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256", "", - ProtocolVersion.PROTOCOLS_OF_12, - K_ECDHE_RSA, B_AES_128, M_SHA256, H_SHA256), - TLS_RSA_WITH_AES_128_CBC_SHA256( - 0x003C, true, "TLS_RSA_WITH_AES_128_CBC_SHA256", "", - ProtocolVersion.PROTOCOLS_OF_12, - K_RSA, B_AES_128, M_SHA256, H_SHA256), - TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256( - 0xC025, true, "TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256", "", - ProtocolVersion.PROTOCOLS_OF_12, - K_ECDH_ECDSA, B_AES_128, M_SHA256, H_SHA256), - TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256( - 0xC029, true, "TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256", "", - ProtocolVersion.PROTOCOLS_OF_12, - K_ECDH_RSA, B_AES_128, M_SHA256, H_SHA256), + // AES_128(CBC) - DHE TLS_DHE_RSA_WITH_AES_128_CBC_SHA256( 0x0067, true, "TLS_DHE_RSA_WITH_AES_128_CBC_SHA256", "", ProtocolVersion.PROTOCOLS_OF_12, @@ -246,6 +183,65 @@ enum CipherSuite { ProtocolVersion.PROTOCOLS_OF_12, K_DHE_DSS, B_AES_128, M_SHA256, H_SHA256), + // + // not forward screcy cipher suites. + // + + // AES_256(GCM) + TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384( + 0xC02E, true, "TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384", "", + ProtocolVersion.PROTOCOLS_OF_12, + K_ECDH_ECDSA, B_AES_256_GCM, M_NULL, H_SHA384), + TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384( + 0xC032, true, "TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384", "", + ProtocolVersion.PROTOCOLS_OF_12, + K_ECDH_RSA, B_AES_256_GCM, M_NULL, H_SHA384), + + // AES_128(GCM) + TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256( + 0xC02D, true, "TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256", "", + ProtocolVersion.PROTOCOLS_OF_12, + K_ECDH_ECDSA, B_AES_128_GCM, M_NULL, H_SHA256), + TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256( + 0xC031, true, "TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256", "", + ProtocolVersion.PROTOCOLS_OF_12, + K_ECDH_RSA, B_AES_128_GCM, M_NULL, H_SHA256), + + // AES_256(CBC) + TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384( + 0xC026, true, "TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384", "", + ProtocolVersion.PROTOCOLS_OF_12, + K_ECDH_ECDSA, B_AES_256, M_SHA384, H_SHA384), + TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384( + 0xC02A, true, "TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384", "", + ProtocolVersion.PROTOCOLS_OF_12, + K_ECDH_RSA, B_AES_256, M_SHA384, H_SHA384), + + // AES_128(CBC) + TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256( + 0xC025, true, "TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256", "", + ProtocolVersion.PROTOCOLS_OF_12, + K_ECDH_ECDSA, B_AES_128, M_SHA256, H_SHA256), + TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256( + 0xC029, true, "TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256", "", + ProtocolVersion.PROTOCOLS_OF_12, + K_ECDH_RSA, B_AES_128, M_SHA256, H_SHA256), + + // + // Legacy, used for compatibility + // + + // AES_256(CBC) - ECDHE - Using SHA + TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA( + 0xC00A, true, "TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA", "", + ProtocolVersion.PROTOCOLS_TO_12, + K_ECDHE_ECDSA, B_AES_256, M_SHA, H_SHA256), + TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA( + 0xC014, true, "TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA", "", + ProtocolVersion.PROTOCOLS_TO_12, + K_ECDHE_RSA, B_AES_256, M_SHA, H_SHA256), + + // AES_128(CBC) - ECDHE - using SHA TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA( 0xC009, true, "TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA", "", ProtocolVersion.PROTOCOLS_TO_12, @@ -254,18 +250,18 @@ enum CipherSuite { 0xC013, true, "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA", "", ProtocolVersion.PROTOCOLS_TO_12, K_ECDHE_RSA, B_AES_128, M_SHA, H_SHA256), - TLS_RSA_WITH_AES_128_CBC_SHA( - 0x002F, true, "TLS_RSA_WITH_AES_128_CBC_SHA", "", + + // AES_256(CBC) - DHE - Using SHA + TLS_DHE_RSA_WITH_AES_256_CBC_SHA( + 0x0039, true, "TLS_DHE_RSA_WITH_AES_256_CBC_SHA", "", ProtocolVersion.PROTOCOLS_TO_12, - K_RSA, B_AES_128, M_SHA, H_SHA256), - TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA( - 0xC004, true, "TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA", "", + K_DHE_RSA, B_AES_256, M_SHA, H_SHA256), + TLS_DHE_DSS_WITH_AES_256_CBC_SHA( + 0x0038, true, "TLS_DHE_DSS_WITH_AES_256_CBC_SHA", "", ProtocolVersion.PROTOCOLS_TO_12, - K_ECDH_ECDSA, B_AES_128, M_SHA, H_SHA256), - TLS_ECDH_RSA_WITH_AES_128_CBC_SHA( - 0xC00E, true, "TLS_ECDH_RSA_WITH_AES_128_CBC_SHA", "", - ProtocolVersion.PROTOCOLS_TO_12, - K_ECDH_RSA, B_AES_128, M_SHA, H_SHA256), + K_DHE_DSS, B_AES_256, M_SHA, H_SHA256), + + // AES_128(CBC) - DHE - using SHA TLS_DHE_RSA_WITH_AES_128_CBC_SHA( 0x0033, true, "TLS_DHE_RSA_WITH_AES_128_CBC_SHA", "", ProtocolVersion.PROTOCOLS_TO_12, @@ -275,7 +271,67 @@ enum CipherSuite { ProtocolVersion.PROTOCOLS_TO_12, K_DHE_DSS, B_AES_128, M_SHA, H_SHA256), - // 3DES_EDE + // AES_256(CBC) - using SHA, not forward screcy + TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA( + 0xC005, true, "TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA", "", + ProtocolVersion.PROTOCOLS_TO_12, + K_ECDH_ECDSA, B_AES_256, M_SHA, H_SHA256), + TLS_ECDH_RSA_WITH_AES_256_CBC_SHA( + 0xC00F, true, "TLS_ECDH_RSA_WITH_AES_256_CBC_SHA", "", + ProtocolVersion.PROTOCOLS_TO_12, + K_ECDH_RSA, B_AES_256, M_SHA, H_SHA256), + + // AES_128(CBC) - using SHA, not forward screcy + TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA( + 0xC004, true, "TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA", "", + ProtocolVersion.PROTOCOLS_TO_12, + K_ECDH_ECDSA, B_AES_128, M_SHA, H_SHA256), + TLS_ECDH_RSA_WITH_AES_128_CBC_SHA( + 0xC00E, true, "TLS_ECDH_RSA_WITH_AES_128_CBC_SHA", "", + ProtocolVersion.PROTOCOLS_TO_12, + K_ECDH_RSA, B_AES_128, M_SHA, H_SHA256), + + // + // deprecated, used for compatibility + // + + // RSA, AES_256(GCM) + TLS_RSA_WITH_AES_256_GCM_SHA384( + 0x009D, true, "TLS_RSA_WITH_AES_256_GCM_SHA384", "", + ProtocolVersion.PROTOCOLS_OF_12, + K_RSA, B_AES_256_GCM, M_NULL, H_SHA384), + + // RSA, AES_128(GCM) + TLS_RSA_WITH_AES_128_GCM_SHA256( + 0x009C, true, "TLS_RSA_WITH_AES_128_GCM_SHA256", "", + ProtocolVersion.PROTOCOLS_OF_12, + K_RSA, B_AES_128_GCM, M_NULL, H_SHA256), + + // RSA, AES_256(CBC) + TLS_RSA_WITH_AES_256_CBC_SHA256( + 0x003D, true, "TLS_RSA_WITH_AES_256_CBC_SHA256", "", + ProtocolVersion.PROTOCOLS_OF_12, + K_RSA, B_AES_256, M_SHA256, H_SHA256), + + // RSA, AES_128(CBC) + TLS_RSA_WITH_AES_128_CBC_SHA256( + 0x003C, true, "TLS_RSA_WITH_AES_128_CBC_SHA256", "", + ProtocolVersion.PROTOCOLS_OF_12, + K_RSA, B_AES_128, M_SHA256, H_SHA256), + + // RSA, AES_256(CBC) - using SHA, not forward screcy + TLS_RSA_WITH_AES_256_CBC_SHA( + 0x0035, true, "TLS_RSA_WITH_AES_256_CBC_SHA", "", + ProtocolVersion.PROTOCOLS_TO_12, + K_RSA, B_AES_256, M_SHA, H_SHA256), + + // RSA, AES_128(CBC) - using SHA, not forward screcy + TLS_RSA_WITH_AES_128_CBC_SHA( + 0x002F, true, "TLS_RSA_WITH_AES_128_CBC_SHA", "", + ProtocolVersion.PROTOCOLS_TO_12, + K_RSA, B_AES_128, M_SHA, H_SHA256), + + // 3DES_EDE, forward secrecy. TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA( 0xC008, true, "TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA", "", ProtocolVersion.PROTOCOLS_TO_12, @@ -284,19 +340,6 @@ enum CipherSuite { 0xC012, true, "TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA", "", ProtocolVersion.PROTOCOLS_TO_12, K_ECDHE_RSA, B_3DES, M_SHA, H_SHA256), - SSL_RSA_WITH_3DES_EDE_CBC_SHA( - 0x000A, true, "SSL_RSA_WITH_3DES_EDE_CBC_SHA", - "TLS_RSA_WITH_3DES_EDE_CBC_SHA", - ProtocolVersion.PROTOCOLS_TO_12, - K_RSA, B_3DES, M_SHA, H_SHA256), - TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA( - 0xC003, true, "TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA", "", - ProtocolVersion.PROTOCOLS_TO_12, - K_ECDH_ECDSA, B_3DES, M_SHA, H_SHA256), - TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA( - 0xC00D, true, "TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA", "", - ProtocolVersion.PROTOCOLS_TO_12, - K_ECDH_RSA, B_3DES, M_SHA, H_SHA256), SSL_DHE_RSA_WITH_3DES_EDE_CBC_SHA( 0x0016, true, "SSL_DHE_RSA_WITH_3DES_EDE_CBC_SHA", "TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA", @@ -308,6 +351,21 @@ enum CipherSuite { ProtocolVersion.PROTOCOLS_TO_12, K_DHE_DSS, B_3DES, M_SHA, H_SHA256), + // 3DES_EDE, not forward secrecy. + TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA( + 0xC003, true, "TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA", "", + ProtocolVersion.PROTOCOLS_TO_12, + K_ECDH_ECDSA, B_3DES, M_SHA, H_SHA256), + TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA( + 0xC00D, true, "TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA", "", + ProtocolVersion.PROTOCOLS_TO_12, + K_ECDH_RSA, B_3DES, M_SHA, H_SHA256), + SSL_RSA_WITH_3DES_EDE_CBC_SHA( + 0x000A, true, "SSL_RSA_WITH_3DES_EDE_CBC_SHA", + "TLS_RSA_WITH_3DES_EDE_CBC_SHA", + ProtocolVersion.PROTOCOLS_TO_12, + K_RSA, B_3DES, M_SHA, H_SHA256), + // Renegotiation protection request Signalling Cipher Suite Value (SCSV). TLS_EMPTY_RENEGOTIATION_INFO_SCSV( // RFC 5746, TLS 1.2 and prior 0x00FF, true, "TLS_EMPTY_RENEGOTIATION_INFO_SCSV", "", diff --git a/test/jdk/javax/net/ssl/sanity/ciphersuites/CheckCipherSuites.java b/test/jdk/javax/net/ssl/sanity/ciphersuites/CheckCipherSuites.java index f2e53a4b8ca..0fc9c02f2d0 100644 --- a/test/jdk/javax/net/ssl/sanity/ciphersuites/CheckCipherSuites.java +++ b/test/jdk/javax/net/ssl/sanity/ciphersuites/CheckCipherSuites.java @@ -23,9 +23,9 @@ /* * @test - * @bug 4750141 4895631 8217579 + * @bug 4750141 4895631 8217579 8163326 * @summary Check enabled and supported ciphersuites are correct - * @run main CheckCipherSuites default + * @run main/othervm CheckCipherSuites default * @run main/othervm CheckCipherSuites limited */ @@ -38,54 +38,97 @@ public class CheckCipherSuites { // List of enabled cipher suites when the "crypto.policy" security // property is set to "unlimited" (the default value). private final static String[] ENABLED_DEFAULT = { - "TLS_AES_128_GCM_SHA256", + // TLS 1.3 cipher suites "TLS_AES_256_GCM_SHA384", + "TLS_AES_128_GCM_SHA256", "TLS_CHACHA20_POLY1305_SHA256", + + // Suite B compliant cipher suites "TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384", "TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256", + + // Not suite B, but we want it to position the suite early "TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256", + + // AES_256(GCM) - ECDHE - forward screcy "TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384", "TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256", - "TLS_RSA_WITH_AES_256_GCM_SHA384", - "TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384", - "TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384", + + // AES_128(GCM) - ECDHE - forward screcy + "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256", + + // AES_256(GCM) - DHE - forward screcy "TLS_DHE_RSA_WITH_AES_256_GCM_SHA384", "TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256", "TLS_DHE_DSS_WITH_AES_256_GCM_SHA384", - "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256", - "TLS_RSA_WITH_AES_128_GCM_SHA256", - "TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256", - "TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256", + + // AES_128(GCM) - DHE - forward screcy "TLS_DHE_RSA_WITH_AES_128_GCM_SHA256", "TLS_DHE_DSS_WITH_AES_128_GCM_SHA256", + + // AES_256(CBC) - ECDHE - forward screcy "TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384", "TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384", - "TLS_RSA_WITH_AES_256_CBC_SHA256", - "TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384", - "TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384", - "TLS_DHE_RSA_WITH_AES_256_CBC_SHA256", - "TLS_DHE_DSS_WITH_AES_256_CBC_SHA256", - "TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA", - "TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA", - "TLS_RSA_WITH_AES_256_CBC_SHA", - "TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA", - "TLS_ECDH_RSA_WITH_AES_256_CBC_SHA", - "TLS_DHE_RSA_WITH_AES_256_CBC_SHA", - "TLS_DHE_DSS_WITH_AES_256_CBC_SHA", + + // AES_256(CBC) - ECDHE - forward screcy "TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256", "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256", - "TLS_RSA_WITH_AES_128_CBC_SHA256", - "TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256", - "TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256", + + // AES_256(CBC) - DHE - forward screcy + "TLS_DHE_RSA_WITH_AES_256_CBC_SHA256", + "TLS_DHE_DSS_WITH_AES_256_CBC_SHA256", + + // AES_128(CBC) - DHE - forward screcy "TLS_DHE_RSA_WITH_AES_128_CBC_SHA256", "TLS_DHE_DSS_WITH_AES_128_CBC_SHA256", + + // AES_256(GCM) - not forward screcy + "TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384", + "TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384", + + // AES_128(GCM) - not forward screcy + "TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256", + "TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256", + + // AES_256(CBC) - not forward screcy + "TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384", + "TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384", + + // AES_128(CBC) - not forward screcy + "TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256", + "TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256", + + // AES_256(CBC) - ECDHE - using SHA + "TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA", + "TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA", + + // AES_128(CBC) - ECDHE - using SHA "TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA", "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA", - "TLS_RSA_WITH_AES_128_CBC_SHA", - "TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA", - "TLS_ECDH_RSA_WITH_AES_128_CBC_SHA", + + // AES_256(CBC) - DHE - using SHA + "TLS_DHE_RSA_WITH_AES_256_CBC_SHA", + "TLS_DHE_DSS_WITH_AES_256_CBC_SHA", + + // AES_128(CBC) - DHE - using SHA "TLS_DHE_RSA_WITH_AES_128_CBC_SHA", "TLS_DHE_DSS_WITH_AES_128_CBC_SHA", + + // AES_256(CBC) - using SHA, not forward screcy + "TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA", + "TLS_ECDH_RSA_WITH_AES_256_CBC_SHA", + + // AES_128(CBC) - using SHA, not forward screcy + "TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA", + "TLS_ECDH_RSA_WITH_AES_128_CBC_SHA", + + // deprecated + "TLS_RSA_WITH_AES_256_GCM_SHA384", + "TLS_RSA_WITH_AES_128_GCM_SHA256", + "TLS_RSA_WITH_AES_256_CBC_SHA256", + "TLS_RSA_WITH_AES_128_CBC_SHA256", + "TLS_RSA_WITH_AES_256_CBC_SHA", + "TLS_RSA_WITH_AES_128_CBC_SHA", "TLS_EMPTY_RENEGOTIATION_INFO_SCSV" }; @@ -95,79 +138,122 @@ public class CheckCipherSuites { "TLS_AES_128_GCM_SHA256", "TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256", "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256", - "TLS_RSA_WITH_AES_128_GCM_SHA256", - "TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256", - "TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256", "TLS_DHE_RSA_WITH_AES_128_GCM_SHA256", "TLS_DHE_DSS_WITH_AES_128_GCM_SHA256", "TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256", "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256", - "TLS_RSA_WITH_AES_128_CBC_SHA256", - "TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256", - "TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256", "TLS_DHE_RSA_WITH_AES_128_CBC_SHA256", "TLS_DHE_DSS_WITH_AES_128_CBC_SHA256", + "TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256", + "TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256", + "TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256", + "TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256", "TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA", "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA", - "TLS_RSA_WITH_AES_128_CBC_SHA", - "TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA", - "TLS_ECDH_RSA_WITH_AES_128_CBC_SHA", "TLS_DHE_RSA_WITH_AES_128_CBC_SHA", "TLS_DHE_DSS_WITH_AES_128_CBC_SHA", + "TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA", + "TLS_ECDH_RSA_WITH_AES_128_CBC_SHA", + "TLS_RSA_WITH_AES_128_GCM_SHA256", + "TLS_RSA_WITH_AES_128_CBC_SHA256", + "TLS_RSA_WITH_AES_128_CBC_SHA", "TLS_EMPTY_RENEGOTIATION_INFO_SCSV" }; // List of supported cipher suites when the "crypto.policy" security // property is set to "unlimited" (the default value). private final static String[] SUPPORTED_DEFAULT = { - "TLS_AES_128_GCM_SHA256", + // TLS 1.3 cipher suites "TLS_AES_256_GCM_SHA384", + "TLS_AES_128_GCM_SHA256", "TLS_CHACHA20_POLY1305_SHA256", + + // Suite B compliant cipher suites "TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384", "TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256", + + // Not suite B, but we want it to position the suite early "TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256", + + // AES_256(GCM) - ECDHE - forward screcy "TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384", "TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256", - "TLS_RSA_WITH_AES_256_GCM_SHA384", - "TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384", - "TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384", + + // AES_128(GCM) - ECDHE - forward screcy + "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256", + + // AES_256(GCM) - DHE - forward screcy "TLS_DHE_RSA_WITH_AES_256_GCM_SHA384", "TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256", "TLS_DHE_DSS_WITH_AES_256_GCM_SHA384", - "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256", - "TLS_RSA_WITH_AES_128_GCM_SHA256", - "TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256", - "TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256", + + // AES_128(GCM) - DHE - forward screcy "TLS_DHE_RSA_WITH_AES_128_GCM_SHA256", "TLS_DHE_DSS_WITH_AES_128_GCM_SHA256", + + // AES_256(CBC) - ECDHE - forward screcy "TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384", "TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384", - "TLS_RSA_WITH_AES_256_CBC_SHA256", - "TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384", - "TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384", - "TLS_DHE_RSA_WITH_AES_256_CBC_SHA256", - "TLS_DHE_DSS_WITH_AES_256_CBC_SHA256", - "TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA", - "TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA", - "TLS_RSA_WITH_AES_256_CBC_SHA", - "TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA", - "TLS_ECDH_RSA_WITH_AES_256_CBC_SHA", - "TLS_DHE_RSA_WITH_AES_256_CBC_SHA", - "TLS_DHE_DSS_WITH_AES_256_CBC_SHA", + + // AES_256(CBC) - ECDHE - forward screcy "TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256", "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256", - "TLS_RSA_WITH_AES_128_CBC_SHA256", - "TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256", - "TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256", + + // AES_256(CBC) - DHE - forward screcy + "TLS_DHE_RSA_WITH_AES_256_CBC_SHA256", + "TLS_DHE_DSS_WITH_AES_256_CBC_SHA256", + + // AES_128(CBC) - DHE - forward screcy "TLS_DHE_RSA_WITH_AES_128_CBC_SHA256", "TLS_DHE_DSS_WITH_AES_128_CBC_SHA256", + + // AES_256(GCM) - not forward screcy + "TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384", + "TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384", + + // AES_128(GCM) - not forward screcy + "TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256", + "TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256", + + // AES_256(CBC) - not forward screcy + "TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384", + "TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384", + + // AES_128(CBC) - not forward screcy + "TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256", + "TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256", + + // AES_256(CBC) - ECDHE - using SHA + "TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA", + "TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA", + + // AES_128(CBC) - ECDHE - using SHA "TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA", "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA", - "TLS_RSA_WITH_AES_128_CBC_SHA", - "TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA", - "TLS_ECDH_RSA_WITH_AES_128_CBC_SHA", + + // AES_256(CBC) - DHE - using SHA + "TLS_DHE_RSA_WITH_AES_256_CBC_SHA", + "TLS_DHE_DSS_WITH_AES_256_CBC_SHA", + + // AES_128(CBC) - DHE - using SHA "TLS_DHE_RSA_WITH_AES_128_CBC_SHA", "TLS_DHE_DSS_WITH_AES_128_CBC_SHA", + + // AES_256(CBC) - using SHA, not forward screcy + "TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA", + "TLS_ECDH_RSA_WITH_AES_256_CBC_SHA", + + // AES_128(CBC) - using SHA, not forward screcy + "TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA", + "TLS_ECDH_RSA_WITH_AES_128_CBC_SHA", + + // deprecated + "TLS_RSA_WITH_AES_256_GCM_SHA384", + "TLS_RSA_WITH_AES_128_GCM_SHA256", + "TLS_RSA_WITH_AES_256_CBC_SHA256", + "TLS_RSA_WITH_AES_128_CBC_SHA256", + "TLS_RSA_WITH_AES_256_CBC_SHA", + "TLS_RSA_WITH_AES_128_CBC_SHA", "TLS_EMPTY_RENEGOTIATION_INFO_SCSV" }; @@ -177,25 +263,25 @@ public class CheckCipherSuites { "TLS_AES_128_GCM_SHA256", "TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256", "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256", - "TLS_RSA_WITH_AES_128_GCM_SHA256", - "TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256", - "TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256", "TLS_DHE_RSA_WITH_AES_128_GCM_SHA256", "TLS_DHE_DSS_WITH_AES_128_GCM_SHA256", "TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256", "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256", - "TLS_RSA_WITH_AES_128_CBC_SHA256", - "TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256", - "TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256", "TLS_DHE_RSA_WITH_AES_128_CBC_SHA256", "TLS_DHE_DSS_WITH_AES_128_CBC_SHA256", + "TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256", + "TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256", + "TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256", + "TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256", "TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA", "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA", - "TLS_RSA_WITH_AES_128_CBC_SHA", - "TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA", - "TLS_ECDH_RSA_WITH_AES_128_CBC_SHA", "TLS_DHE_RSA_WITH_AES_128_CBC_SHA", "TLS_DHE_DSS_WITH_AES_128_CBC_SHA", + "TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA", + "TLS_ECDH_RSA_WITH_AES_128_CBC_SHA", + "TLS_RSA_WITH_AES_128_GCM_SHA256", + "TLS_RSA_WITH_AES_128_CBC_SHA256", + "TLS_RSA_WITH_AES_128_CBC_SHA", "TLS_EMPTY_RENEGOTIATION_INFO_SCSV" }; @@ -228,7 +314,8 @@ public class CheckCipherSuites { throw new Exception("Illegal argument"); } - SSLSocketFactory factory = (SSLSocketFactory)SSLSocketFactory.getDefault(); + SSLSocketFactory factory = + (SSLSocketFactory)SSLSocketFactory.getDefault(); SSLSocket socket = (SSLSocket)factory.createSocket(); String[] enabled = socket.getEnabledCipherSuites(); @@ -257,5 +344,4 @@ public class CheckCipherSuites { long end = System.currentTimeMillis(); System.out.println("Done (" + (end - start) + " ms)."); } - } From 6780d21dd63746df358e59b15dbf805032230d7e Mon Sep 17 00:00:00 2001 From: Coleen Phillimore Date: Thu, 4 Apr 2019 17:23:05 -0400 Subject: [PATCH 21/73] 8221992: Fix old method replacement in ResolvedMethodTable Use method get_new_method() which is used in other call sites. Reviewed-by: sspitsyn --- src/hotspot/share/prims/resolvedMethodTable.cpp | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/src/hotspot/share/prims/resolvedMethodTable.cpp b/src/hotspot/share/prims/resolvedMethodTable.cpp index da3737980ec..38fbcbf2548 100644 --- a/src/hotspot/share/prims/resolvedMethodTable.cpp +++ b/src/hotspot/share/prims/resolvedMethodTable.cpp @@ -126,17 +126,14 @@ oop ResolvedMethodTable::add_method(const methodHandle& m, Handle resolved_metho Method* method = m(); // Check if method has been redefined while taking out ResolvedMethodTable_lock, if so - // use new method. The old method won't be deallocated because it's passed in as a Handle. + // use new method in the ResolvedMethodName. The old method won't be deallocated + // yet because it's passed in as a Handle. if (method->is_old()) { - // Replace method with redefined version - InstanceKlass* holder = method->method_holder(); - method = holder->method_with_idnum(method->method_idnum()); - if (method == NULL) { - // Replace deleted method with NSME. - method = Universe::throw_no_such_method_error(); - } + method = (method->is_deleted()) ? Universe::throw_no_such_method_error() : + method->get_new_method(); java_lang_invoke_ResolvedMethodName::set_vmtarget(resolved_method_name(), method); } + // Set flag in class to indicate this InstanceKlass has entries in the table // to avoid walking table during redefinition if none of the redefined classes // have any membernames in the table. From 39f3368ffdd653f58a6a320ddf14407b431ae7d6 Mon Sep 17 00:00:00 2001 From: Goetz Lindenmaier Date: Thu, 4 Apr 2019 09:39:44 +0200 Subject: [PATCH 22/73] 8221470: Print methods in exception messages in java-like Syntax Reviewed-by: dholmes, mdoerr, coleenp --- src/hotspot/share/classfile/verifier.cpp | 4 +- .../share/interpreter/linkResolver.cpp | 191 +++++++++--------- .../share/interpreter/linkResolver.hpp | 1 - src/hotspot/share/oops/constantPool.cpp | 19 +- src/hotspot/share/oops/klassVtable.cpp | 17 +- src/hotspot/share/oops/method.cpp | 21 ++ src/hotspot/share/oops/method.hpp | 16 +- src/hotspot/share/oops/symbol.cpp | 60 ++++++ src/hotspot/share/oops/symbol.hpp | 9 + src/hotspot/share/prims/jni.cpp | 10 +- src/hotspot/share/prims/nativeLookup.cpp | 7 +- src/hotspot/share/prims/stackwalk.cpp | 4 +- src/hotspot/share/runtime/reflection.cpp | 20 +- .../itableLdrConstraint/Test.java | 12 +- .../vtableLdrConstraint/Test.java | 4 +- .../membership/TestNestmateMembership.java | 12 +- .../TestConstructorHierarchy.java | 6 +- .../AbstractMethodErrorTest.java | 22 +- .../IllegalAccessErrorTest.java | 4 +- .../exceptionMsgs/methodPrinting/TeMe3_C.jasm | 37 ++++ .../methodPrinting/TestPrintingMethods.java | 151 ++++++++++++++ .../ExpQualToM1PrivateMethodIAE.java | 4 +- 22 files changed, 470 insertions(+), 161 deletions(-) create mode 100644 test/hotspot/jtreg/runtime/exceptionMsgs/methodPrinting/TeMe3_C.jasm create mode 100644 test/hotspot/jtreg/runtime/exceptionMsgs/methodPrinting/TestPrintingMethods.java diff --git a/src/hotspot/share/classfile/verifier.cpp b/src/hotspot/share/classfile/verifier.cpp index ad9644b48b8..b480039db20 100644 --- a/src/hotspot/share/classfile/verifier.cpp +++ b/src/hotspot/share/classfile/verifier.cpp @@ -2060,7 +2060,9 @@ void ClassVerifier::class_format_error(const char* msg, ...) { ss.vprint(msg, va); va_end(va); if (!_method.is_null()) { - ss.print(" in method %s", _method->name_and_sig_as_C_string()); + ss.print(" in method '"); + _method->print_external_name(&ss); + ss.print("'"); } _message = ss.as_string(); } diff --git a/src/hotspot/share/interpreter/linkResolver.cpp b/src/hotspot/share/interpreter/linkResolver.cpp index 69f90b4a3d7..6fdd056287f 100644 --- a/src/hotspot/share/interpreter/linkResolver.cpp +++ b/src/hotspot/share/interpreter/linkResolver.cpp @@ -264,10 +264,6 @@ LinkInfo::LinkInfo(const constantPoolHandle& pool, int index, TRAPS) { _check_access = true; } -char* LinkInfo::method_string() const { - return Method::name_and_sig_as_C_string(_resolved_klass, _name, _signature); -} - #ifndef PRODUCT void LinkInfo::print() { ResourceMark rm; @@ -593,14 +589,12 @@ void LinkResolver::check_method_accessability(Klass* ref_klass, Exceptions::fthrow( THREAD_AND_LOCATION, vmSymbols::java_lang_IllegalAccessError(), - "class %s tried to access %s%s%smethod %s.%s%s (%s%s%s)", + "class %s tried to access %s%s%smethod '%s' (%s%s%s)", ref_klass->external_name(), sel_method->is_abstract() ? "abstract " : "", sel_method->is_protected() ? "protected " : "", sel_method->is_private() ? "private " : "", - sel_klass->external_name(), - sel_method->name()->as_C_string(), - sel_method->signature()->as_C_string(), + sel_method->external_name(), (same_module) ? ref_klass->joint_in_module_of_loader(sel_klass) : ref_klass->class_in_module_of_loader(), (same_module) ? "" : "; ", (same_module) ? "" : sel_klass->class_in_module_of_loader() @@ -670,12 +664,11 @@ void LinkResolver::check_method_loader_constraints(const LinkInfo& link_info, assert(target_loader_data != NULL, "resolved method's class has no class loader data"); stringStream ss; - ss.print("loader constraint violation: when resolving %s" - " \"%s\" the class loader %s of the current class, %s," + ss.print("loader constraint violation: when resolving %s '", method_type); + Method::print_external_name(&ss, link_info.resolved_klass(), link_info.name(), link_info.signature()); + ss.print("' the class loader %s of the current class, %s," " and the class loader %s for the method's defining class, %s, have" " different Class objects for the type %s used in the signature (%s; %s)", - method_type, - link_info.method_string(), current_loader_data->loader_name_and_id(), current_class->name()->as_C_string(), target_loader_data->loader_name_and_id(), @@ -739,9 +732,11 @@ methodHandle LinkResolver::resolve_method(const LinkInfo& link_info, // 2. check constant pool tag for called method - must be JVM_CONSTANT_Methodref if (!link_info.tag().is_invalid() && !link_info.tag().is_method()) { ResourceMark rm(THREAD); - char buf[200]; - jio_snprintf(buf, sizeof(buf), "Method %s must be Methodref constant", link_info.method_string()); - THROW_MSG_NULL(vmSymbols::java_lang_IncompatibleClassChangeError(), buf); + stringStream ss; + ss.print("Method '"); + Method::print_external_name(&ss, link_info.resolved_klass(), link_info.name(), link_info.signature()); + ss.print("' must be Methodref constant"); + THROW_MSG_NULL(vmSymbols::java_lang_IncompatibleClassChangeError(), ss.as_string()); } // 3. lookup method in resolved klass and its super klasses @@ -764,11 +759,12 @@ methodHandle LinkResolver::resolve_method(const LinkInfo& link_info, // 5. method lookup failed if (resolved_method.is_null()) { ResourceMark rm(THREAD); + stringStream ss; + ss.print("'"); + Method::print_external_name(&ss, resolved_klass, link_info.name(), link_info.signature()); + ss.print("'"); THROW_MSG_CAUSE_(vmSymbols::java_lang_NoSuchMethodError(), - Method::name_and_sig_as_C_string(resolved_klass, - link_info.name(), - link_info.signature()), - nested_exception, NULL); + ss.as_string(), nested_exception, NULL); } // 6. access checks, access checking may be turned off when calling from within the VM. @@ -840,9 +836,11 @@ methodHandle LinkResolver::resolve_interface_method(const LinkInfo& link_info, B // check constant pool tag for called method - must be JVM_CONSTANT_InterfaceMethodref if (!link_info.tag().is_invalid() && !link_info.tag().is_interface_method()) { ResourceMark rm(THREAD); - char buf[200]; - jio_snprintf(buf, sizeof(buf), "Method %s must be InterfaceMethodref constant", link_info.method_string()); - THROW_MSG_NULL(vmSymbols::java_lang_IncompatibleClassChangeError(), buf); + stringStream ss; + ss.print("Method '"); + Method::print_external_name(&ss, link_info.resolved_klass(), link_info.name(), link_info.signature()); + ss.print("' must be InterfaceMethodref constant"); + THROW_MSG_NULL(vmSymbols::java_lang_IncompatibleClassChangeError(), ss.as_string()); } // lookup method in this interface or its super, java.lang.Object @@ -857,10 +855,11 @@ methodHandle LinkResolver::resolve_interface_method(const LinkInfo& link_info, B if (resolved_method.is_null()) { // no method found ResourceMark rm(THREAD); - THROW_MSG_NULL(vmSymbols::java_lang_NoSuchMethodError(), - Method::name_and_sig_as_C_string(resolved_klass, - link_info.name(), - link_info.signature())); + stringStream ss; + ss.print("'"); + Method::print_external_name(&ss, resolved_klass, link_info.name(), link_info.signature()); + ss.print("'"); + THROW_MSG_NULL(vmSymbols::java_lang_NoSuchMethodError(), ss.as_string()); } if (link_info.check_access()) { @@ -881,11 +880,12 @@ methodHandle LinkResolver::resolve_interface_method(const LinkInfo& link_info, B if (code != Bytecodes::_invokestatic && resolved_method->is_static()) { ResourceMark rm(THREAD); - char buf[200]; - jio_snprintf(buf, sizeof(buf), "Expected instance not static method %s", - Method::name_and_sig_as_C_string(resolved_klass, - resolved_method->name(), resolved_method->signature())); - THROW_MSG_NULL(vmSymbols::java_lang_IncompatibleClassChangeError(), buf); + stringStream ss; + ss.print("Expected instance not static method '"); + Method::print_external_name(&ss, resolved_klass, + resolved_method->name(), resolved_method->signature()); + ss.print("'"); + THROW_MSG_NULL(vmSymbols::java_lang_IncompatibleClassChangeError(), ss.as_string()); } if (log_develop_is_enabled(Trace, itables)) { @@ -1086,11 +1086,11 @@ methodHandle LinkResolver::linktime_resolve_static_method(const LinkInfo& link_i // check if static if (!resolved_method->is_static()) { ResourceMark rm(THREAD); - char buf[200]; - jio_snprintf(buf, sizeof(buf), "Expected static method %s", Method::name_and_sig_as_C_string(resolved_klass, - resolved_method->name(), - resolved_method->signature())); - THROW_MSG_NULL(vmSymbols::java_lang_IncompatibleClassChangeError(), buf); + stringStream ss; + ss.print("Expected static method '"); + resolved_method()->print_external_name(&ss); + ss.print("'"); + THROW_MSG_NULL(vmSymbols::java_lang_IncompatibleClassChangeError(), ss.as_string()); } return resolved_method; } @@ -1127,14 +1127,16 @@ methodHandle LinkResolver::linktime_resolve_special_method(const LinkInfo& link_ if (resolved_method->name() == vmSymbols::object_initializer_name() && resolved_method->method_holder() != resolved_klass) { ResourceMark rm(THREAD); + stringStream ss; + ss.print("%s: method '", resolved_klass->external_name()); + resolved_method->signature()->print_as_signature_external_return_type(&ss); + ss.print(" %s(", resolved_method->name()->as_C_string()); + resolved_method->signature()->print_as_signature_external_parameters(&ss); + ss.print(")' not found"); Exceptions::fthrow( THREAD_AND_LOCATION, vmSymbols::java_lang_NoSuchMethodError(), - "%s: method %s%s not found", - resolved_klass->external_name(), - resolved_method->name()->as_C_string(), - resolved_method->signature()->as_C_string() - ); + "%s", ss.as_string()); return NULL; } @@ -1153,27 +1155,23 @@ methodHandle LinkResolver::linktime_resolve_special_method(const LinkInfo& link_ if (!is_reflect && !klass_to_check->is_same_or_direct_interface(resolved_klass)) { ResourceMark rm(THREAD); - char buf[200]; - jio_snprintf(buf, sizeof(buf), - "Interface method reference: %s, is in an indirect superinterface of %s", - Method::name_and_sig_as_C_string(resolved_klass, - resolved_method->name(), - resolved_method->signature()), - current_klass->external_name()); - THROW_MSG_NULL(vmSymbols::java_lang_IncompatibleClassChangeError(), buf); + stringStream ss; + ss.print("Interface method reference: '"); + resolved_method->print_external_name(&ss); + ss.print("', is in an indirect superinterface of %s", + current_klass->external_name()); + THROW_MSG_NULL(vmSymbols::java_lang_IncompatibleClassChangeError(), ss.as_string()); } } // check if not static if (resolved_method->is_static()) { ResourceMark rm(THREAD); - char buf[200]; - jio_snprintf(buf, sizeof(buf), - "Expecting non-static method %s", - Method::name_and_sig_as_C_string(resolved_klass, - resolved_method->name(), - resolved_method->signature())); - THROW_MSG_NULL(vmSymbols::java_lang_IncompatibleClassChangeError(), buf); + stringStream ss; + ss.print("Expecting non-static method '"); + resolved_method->print_external_name(&ss); + ss.print("'"); + THROW_MSG_NULL(vmSymbols::java_lang_IncompatibleClassChangeError(), ss.as_string()); } if (log_develop_is_enabled(Trace, itables)) { @@ -1219,10 +1217,11 @@ void LinkResolver::runtime_resolve_special_method(CallInfo& result, // check if found if (sel_method.is_null()) { ResourceMark rm(THREAD); - THROW_MSG(vmSymbols::java_lang_AbstractMethodError(), - Method::name_and_sig_as_C_string(resolved_klass, - resolved_method->name(), - resolved_method->signature())); + stringStream ss; + ss.print("'"); + resolved_method->print_external_name(&ss); + ss.print("'"); + THROW_MSG(vmSymbols::java_lang_AbstractMethodError(), ss.as_string()); // check loader constraints if found a different method } else if (sel_method() != resolved_method()) { check_method_loader_constraints(link_info, sel_method, "method", CHECK); @@ -1244,8 +1243,8 @@ void LinkResolver::runtime_resolve_special_method(CallInfo& result, char buf[500]; jio_snprintf(buf, sizeof(buf), "Receiver class %s must be the current class or a subtype of interface %s", - receiver_klass->name()->as_C_string(), - sender->name()->as_C_string()); + receiver_klass->external_name(), + sender->external_name()); THROW_MSG(vmSymbols::java_lang_IllegalAccessError(), buf); } } @@ -1254,20 +1253,21 @@ void LinkResolver::runtime_resolve_special_method(CallInfo& result, // check if not static if (sel_method->is_static()) { ResourceMark rm(THREAD); - char buf[200]; - jio_snprintf(buf, sizeof(buf), "Expecting non-static method %s", Method::name_and_sig_as_C_string(resolved_klass, - resolved_method->name(), - resolved_method->signature())); - THROW_MSG(vmSymbols::java_lang_IncompatibleClassChangeError(), buf); + stringStream ss; + ss.print("Expecting non-static method '"); + resolved_method->print_external_name(&ss); + ss.print("'"); + THROW_MSG(vmSymbols::java_lang_IncompatibleClassChangeError(), ss.as_string()); } // check if abstract if (sel_method->is_abstract()) { ResourceMark rm(THREAD); - THROW_MSG(vmSymbols::java_lang_AbstractMethodError(), - Method::name_and_sig_as_C_string(resolved_klass, - sel_method->name(), - sel_method->signature())); + stringStream ss; + ss.print("'"); + Method::print_external_name(&ss, resolved_klass, sel_method->name(), sel_method->signature()); + ss.print("'"); + THROW_MSG(vmSymbols::java_lang_AbstractMethodError(), ss.as_string()); } if (log_develop_is_enabled(Trace, itables)) { @@ -1305,23 +1305,22 @@ methodHandle LinkResolver::linktime_resolve_virtual_method(const LinkInfo& link_ // This is impossible, if resolve_klass is an interface, we've thrown icce in resolve_method if (resolved_klass->is_interface() && resolved_method->is_private()) { ResourceMark rm(THREAD); - char buf[200]; - jio_snprintf(buf, sizeof(buf), "private interface method requires invokespecial, not invokevirtual: method %s, caller-class:%s", - Method::name_and_sig_as_C_string(resolved_klass, - resolved_method->name(), - resolved_method->signature()), - (current_klass == NULL ? "" : current_klass->internal_name())); - THROW_MSG_NULL(vmSymbols::java_lang_IncompatibleClassChangeError(), buf); + stringStream ss; + ss.print("private interface method requires invokespecial, not invokevirtual: method '"); + resolved_method->print_external_name(&ss); + ss.print("', caller-class: %s", + (current_klass == NULL ? "" : current_klass->internal_name())); + THROW_MSG_NULL(vmSymbols::java_lang_IncompatibleClassChangeError(), ss.as_string()); } // check if not static if (resolved_method->is_static()) { ResourceMark rm(THREAD); - char buf[200]; - jio_snprintf(buf, sizeof(buf), "Expecting non-static method %s", Method::name_and_sig_as_C_string(resolved_klass, - resolved_method->name(), - resolved_method->signature())); - THROW_MSG_NULL(vmSymbols::java_lang_IncompatibleClassChangeError(), buf); + stringStream ss; + ss.print("Expecting non-static method '"); + resolved_method->print_external_name(&ss); + ss.print("'"); + THROW_MSG_NULL(vmSymbols::java_lang_IncompatibleClassChangeError(), ss.as_string()); } if (log_develop_is_enabled(Trace, vtables)) { @@ -1470,10 +1469,11 @@ void LinkResolver::runtime_resolve_interface_method(CallInfo& result, // Throw Illegal Access Error if selected_method is not public. if (!selected_method->is_public()) { ResourceMark rm(THREAD); - THROW_MSG(vmSymbols::java_lang_IllegalAccessError(), - Method::name_and_sig_as_C_string(recv_klass, - selected_method->name(), - selected_method->signature())); + stringStream ss; + ss.print("'"); + Method::print_external_name(&ss, recv_klass, selected_method->name(), selected_method->signature()); + ss.print("'"); + THROW_MSG(vmSymbols::java_lang_IllegalAccessError(), ss.as_string()); } // check if abstract if (check_null_and_abstract && selected_method->is_abstract()) { @@ -1806,19 +1806,22 @@ void LinkResolver::throw_abstract_method_error(const methodHandle& resolved_meth } assert(resolved_method.not_null(), "Sanity"); - ss.print(" resolved method %s%s%s%s of %s %s.", + ss.print(" resolved method '%s%s", resolved_method->is_abstract() ? "abstract " : "", - resolved_method->is_private() ? "private " : "", - resolved_method->name()->as_C_string(), - resolved_method->signature()->as_C_string(), + resolved_method->is_private() ? "private " : ""); + resolved_method->signature()->print_as_signature_external_return_type(&ss); + ss.print(" %s(", resolved_method->name()->as_C_string()); + resolved_method->signature()->print_as_signature_external_parameters(&ss); + ss.print(")' of %s %s.", resolved_klass->external_kind(), resolved_klass->external_name()); if (selected_method.not_null() && !(resolved_method == selected_method)) { - ss.print(" Selected method is %s%s%s.", + ss.print(" Selected method is '%s%s", selected_method->is_abstract() ? "abstract " : "", - selected_method->is_private() ? "private " : "", - selected_method->name_and_sig_as_C_string()); + selected_method->is_private() ? "private " : ""); + selected_method->print_external_name(&ss); + ss.print("'."); } THROW_MSG(vmSymbols::java_lang_AbstractMethodError(), ss.as_string()); diff --git a/src/hotspot/share/interpreter/linkResolver.hpp b/src/hotspot/share/interpreter/linkResolver.hpp index e357320e3f9..52ab55a7900 100644 --- a/src/hotspot/share/interpreter/linkResolver.hpp +++ b/src/hotspot/share/interpreter/linkResolver.hpp @@ -182,7 +182,6 @@ class LinkInfo : public StackObj { methodHandle current_method() const { return _current_method; } constantTag tag() const { return _tag; } bool check_access() const { return _check_access; } - char* method_string() const; void print() PRODUCT_RETURN; }; diff --git a/src/hotspot/share/oops/constantPool.cpp b/src/hotspot/share/oops/constantPool.cpp index 4815ed37d18..292576beef3 100644 --- a/src/hotspot/share/oops/constantPool.cpp +++ b/src/hotspot/share/oops/constantPool.cpp @@ -1000,14 +1000,17 @@ oop ConstantPool::resolve_constant_at_impl(const constantPoolHandle& this_cp, if ((callee->is_interface() && m_tag.is_method()) || ((!callee->is_interface() && m_tag.is_interface_method()))) { ResourceMark rm(THREAD); - char buf[400]; - jio_snprintf(buf, sizeof(buf), - "Inconsistent constant pool data in classfile for class %s. " - "Method %s%s at index %d is %s and should be %s", - callee->name()->as_C_string(), name->as_C_string(), signature->as_C_string(), index, - callee->is_interface() ? "CONSTANT_MethodRef" : "CONSTANT_InterfaceMethodRef", - callee->is_interface() ? "CONSTANT_InterfaceMethodRef" : "CONSTANT_MethodRef"); - THROW_MSG_NULL(vmSymbols::java_lang_IncompatibleClassChangeError(), buf); + stringStream ss; + ss.print("Inconsistent constant pool data in classfile for class %s. " + "Method '", callee->name()->as_C_string()); + signature->print_as_signature_external_return_type(&ss); + ss.print(" %s(", name->as_C_string()); + signature->print_as_signature_external_parameters(&ss); + ss.print(")' at index %d is %s and should be %s", + index, + callee->is_interface() ? "CONSTANT_MethodRef" : "CONSTANT_InterfaceMethodRef", + callee->is_interface() ? "CONSTANT_InterfaceMethodRef" : "CONSTANT_MethodRef"); + THROW_MSG_NULL(vmSymbols::java_lang_IncompatibleClassChangeError(), ss.as_string()); } Klass* klass = this_cp->pool_holder(); diff --git a/src/hotspot/share/oops/klassVtable.cpp b/src/hotspot/share/oops/klassVtable.cpp index d67afb1de86..ba2736e5592 100644 --- a/src/hotspot/share/oops/klassVtable.cpp +++ b/src/hotspot/share/oops/klassVtable.cpp @@ -500,11 +500,11 @@ bool klassVtable::update_inherited_vtable(InstanceKlass* klass, const methodHand if (failed_type_symbol != NULL) { stringStream ss; ss.print("loader constraint violation for class %s: when selecting " - "overriding method %s the class loader %s of the " + "overriding method '", klass->external_name()); + target_method()->print_external_name(&ss), + ss.print("' the class loader %s of the " "selected method's type %s, and the class loader %s for its super " "type %s have different Class objects for the type %s used in the signature (%s; %s)", - klass->external_name(), - target_method()->name_and_sig_as_C_string(), target_klass->class_loader_data()->loader_name_and_id(), target_klass->external_name(), super_klass->class_loader_data()->loader_name_and_id(), @@ -1227,15 +1227,16 @@ void klassItable::initialize_itable_for_interface(int method_table_offset, Insta if (failed_type_symbol != NULL) { stringStream ss; ss.print("loader constraint violation in interface itable" - " initialization for class %s: when selecting method %s the" - " class loader %s for super interface %s, and the class" - " loader %s of the selected method's type, %s have" + " initialization for class %s: when selecting method '", + _klass->external_name()); + m->print_external_name(&ss), + ss.print("' the class loader %s for super interface %s, and the class" + " loader %s of the selected method's %s, %s have" " different Class objects for the type %s used in the signature (%s; %s)", - _klass->external_name(), - m->name_and_sig_as_C_string(), interf->class_loader_data()->loader_name_and_id(), interf->external_name(), target()->method_holder()->class_loader_data()->loader_name_and_id(), + target()->method_holder()->external_kind(), target()->method_holder()->external_name(), failed_type_symbol->as_klass_external_name(), interf->class_in_module_of_loader(false, true), diff --git a/src/hotspot/share/oops/method.cpp b/src/hotspot/share/oops/method.cpp index 0d1215f87a2..f4f4fca0719 100644 --- a/src/hotspot/share/oops/method.cpp +++ b/src/hotspot/share/oops/method.cpp @@ -178,6 +178,27 @@ char* Method::name_and_sig_as_C_string(Klass* klass, Symbol* method_name, Symbol return buf; } +const char* Method::external_name() const { + return external_name(constants()->pool_holder(), name(), signature()); +} + +void Method::print_external_name(outputStream *os) const { + print_external_name(os, constants()->pool_holder(), name(), signature()); +} + +const char* Method::external_name(Klass* klass, Symbol* method_name, Symbol* signature) { + stringStream ss; + print_external_name(&ss, klass, method_name, signature); + return ss.as_string(); +} + +void Method::print_external_name(outputStream *os, Klass* klass, Symbol* method_name, Symbol* signature) { + signature->print_as_signature_external_return_type(os); + os->print(" %s.%s(", klass->external_name(), method_name->as_C_string()); + signature->print_as_signature_external_parameters(os); + os->print(")"); +} + int Method::fast_exception_handler_bci_for(const methodHandle& mh, Klass* ex_klass, int throw_bci, TRAPS) { // exception table holds quadruple entries of the form (beg_bci, end_bci, handler_bci, klass_index) // access exception table diff --git a/src/hotspot/share/oops/method.hpp b/src/hotspot/share/oops/method.hpp index 49a892762d2..238a437a6fd 100644 --- a/src/hotspot/share/oops/method.hpp +++ b/src/hotspot/share/oops/method.hpp @@ -180,8 +180,8 @@ class Method : public Metadata { } // Helper routine: get klass name + "." + method name + signature as - // C string, for the purpose of providing more useful NoSuchMethodErrors - // and fatal error handling. The string is allocated in resource + // C string, for the purpose of providing more useful + // fatal error handling. The string is allocated in resource // area if a buffer is not provided by the caller. char* name_and_sig_as_C_string() const; char* name_and_sig_as_C_string(char* buf, int size) const; @@ -190,6 +190,18 @@ class Method : public Metadata { static char* name_and_sig_as_C_string(Klass* klass, Symbol* method_name, Symbol* signature); static char* name_and_sig_as_C_string(Klass* klass, Symbol* method_name, Symbol* signature, char* buf, int size); + // Get return type + klass name + "." + method name + ( parameters types ) + // as a C string or print it to an outputStream. + // This is to be used to assemble strings passed to Java, so that + // the text more resembles Java code. Used in exception messages. + // Memory is allocated in the resource area; the caller needs + // a ResourceMark. + const char* external_name() const; + void print_external_name(outputStream *os) const; + + static const char* external_name( Klass* klass, Symbol* method_name, Symbol* signature); + static void print_external_name(outputStream *os, Klass* klass, Symbol* method_name, Symbol* signature); + Bytecodes::Code java_code_at(int bci) const { return Bytecodes::java_code_at(this, bcp_from(bci)); } diff --git a/src/hotspot/share/oops/symbol.cpp b/src/hotspot/share/oops/symbol.cpp index 76f6d7b2e01..d37a354026f 100644 --- a/src/hotspot/share/oops/symbol.cpp +++ b/src/hotspot/share/oops/symbol.cpp @@ -200,6 +200,66 @@ const char* Symbol::as_klass_external_name() const { return str; } +static void print_class(outputStream *os, char *class_str, int len) { + for (int i = 0; i < len; ++i) { + if (class_str[i] == '/') { + os->put('.'); + } else { + os->put(class_str[i]); + } + } +} + +static void print_array(outputStream *os, char *array_str, int len) { + int dimensions = 0; + for (int i = 0; i < len; ++i) { + if (array_str[i] == '[') { + dimensions++; + } else if (array_str[i] == 'L') { + // Expected format: L;. Skip 'L' and ';' delimiting the type name. + print_class(os, array_str+i+1, len-i-2); + break; + } else { + os->print("%s", type2name(char2type(array_str[i]))); + } + } + for (int i = 0; i < dimensions; ++i) { + os->print("[]"); + } +} + +void Symbol::print_as_signature_external_return_type(outputStream *os) { + for (SignatureStream ss(this); !ss.is_done(); ss.next()) { + if (ss.at_return_type()) { + if (ss.is_array()) { + print_array(os, (char*)ss.raw_bytes(), (int)ss.raw_length()); + } else if (ss.is_object()) { + // Expected format: L;. Skip 'L' and ';' delimiting the class name. + print_class(os, (char*)ss.raw_bytes()+1, (int)ss.raw_length()-2); + } else { + os->print("%s", type2name(ss.type())); + } + } + } +} + +void Symbol::print_as_signature_external_parameters(outputStream *os) { + bool first = true; + for (SignatureStream ss(this); !ss.is_done(); ss.next()) { + if (ss.at_return_type()) break; + if (!first) { os->print(", "); } + if (ss.is_array()) { + print_array(os, (char*)ss.raw_bytes(), (int)ss.raw_length()); + } else if (ss.is_object()) { + // Skip 'L' and ';'. + print_class(os, (char*)ss.raw_bytes()+1, (int)ss.raw_length()-2); + } else { + os->print("%s", type2name(ss.type())); + } + first = false; + } +} + // Increment refcount while checking for zero. If the Symbol's refcount becomes zero // a thread could be concurrently removing the Symbol. This is used during SymbolTable // lookup to avoid reviving a dead Symbol. diff --git a/src/hotspot/share/oops/symbol.hpp b/src/hotspot/share/oops/symbol.hpp index ddaf57b2c10..333da081c31 100644 --- a/src/hotspot/share/oops/symbol.hpp +++ b/src/hotspot/share/oops/symbol.hpp @@ -229,6 +229,15 @@ class Symbol : public MetaspaceObj { const char* as_klass_external_name() const; const char* as_klass_external_name(char* buf, int size) const; + // Treating the symbol as a signature, print the return + // type to the outputStream. Prints external names as 'double' or + // 'java.lang.Object[][]'. + void print_as_signature_external_return_type(outputStream *os); + // Treating the symbol as a signature, print the parameter types + // seperated by ', ' to the outputStream. Prints external names as + // 'double' or 'java.lang.Object[][]'. + void print_as_signature_external_parameters(outputStream *os); + void metaspace_pointers_do(MetaspaceClosure* it); MetaspaceObj::Type type() const { return SymbolType; } diff --git a/src/hotspot/share/prims/jni.cpp b/src/hotspot/share/prims/jni.cpp index 2375793e262..bd1460bea8d 100644 --- a/src/hotspot/share/prims/jni.cpp +++ b/src/hotspot/share/prims/jni.cpp @@ -2955,8 +2955,9 @@ static bool register_native(Klass* k, Symbol* name, Symbol* signature, address e if (method == NULL) { ResourceMark rm; stringStream st; - st.print("Method %s name or signature does not match", - Method::name_and_sig_as_C_string(k, name, signature)); + st.print("Method '"); + Method::print_external_name(&st, k, name, signature); + st.print("' name or signature does not match"); THROW_MSG_(vmSymbols::java_lang_NoSuchMethodError(), st.as_string(), false); } if (!method->is_native()) { @@ -2965,8 +2966,9 @@ static bool register_native(Klass* k, Symbol* name, Symbol* signature, address e if (method == NULL) { ResourceMark rm; stringStream st; - st.print("Method %s is not declared as native", - Method::name_and_sig_as_C_string(k, name, signature)); + st.print("Method '"); + Method::print_external_name(&st, k, name, signature); + st.print("' is not declared as native"); THROW_MSG_(vmSymbols::java_lang_NoSuchMethodError(), st.as_string(), false); } } diff --git a/src/hotspot/share/prims/nativeLookup.cpp b/src/hotspot/share/prims/nativeLookup.cpp index 690e23738ea..649a5dc4f03 100644 --- a/src/hotspot/share/prims/nativeLookup.cpp +++ b/src/hotspot/share/prims/nativeLookup.cpp @@ -380,8 +380,11 @@ address NativeLookup::lookup_base(const methodHandle& method, bool& in_base_libr if (entry != NULL) return entry; // Native function not found, throw UnsatisfiedLinkError - THROW_MSG_0(vmSymbols::java_lang_UnsatisfiedLinkError(), - method->name_and_sig_as_C_string()); + stringStream ss; + ss.print("'"); + method->print_external_name(&ss); + ss.print("'"); + THROW_MSG_0(vmSymbols::java_lang_UnsatisfiedLinkError(), ss.as_string()); } diff --git a/src/hotspot/share/prims/stackwalk.cpp b/src/hotspot/share/prims/stackwalk.cpp index 14882f77bbe..d38ef1f196f 100644 --- a/src/hotspot/share/prims/stackwalk.cpp +++ b/src/hotspot/share/prims/stackwalk.cpp @@ -151,8 +151,8 @@ int StackWalk::fill_in_frames(jlong mode, BaseFrameStream& stream, index == start_index && method->caller_sensitive()) { ResourceMark rm(THREAD); THROW_MSG_0(vmSymbols::java_lang_UnsupportedOperationException(), - err_msg("StackWalker::getCallerClass called from @CallerSensitive %s method", - method->name_and_sig_as_C_string())); + err_msg("StackWalker::getCallerClass called from @CallerSensitive '%s' method", + method->external_name())); } // fill in StackFrameInfo and initialize MemberName stream.fill_frame(index, frames_array, method, CHECK_0); diff --git a/src/hotspot/share/runtime/reflection.cpp b/src/hotspot/share/runtime/reflection.cpp index cbfc3a1466b..244a4d1300f 100644 --- a/src/hotspot/share/runtime/reflection.cpp +++ b/src/hotspot/share/runtime/reflection.cpp @@ -1085,11 +1085,12 @@ static oop invoke(InstanceKlass* klass, if (method->is_abstract()) { // new default: 6531596 ResourceMark rm(THREAD); + stringStream ss; + ss.print("'"); + Method::print_external_name(&ss, target_klass, method->name(), method->signature()); + ss.print("'"); Handle h_origexception = Exceptions::new_exception(THREAD, - vmSymbols::java_lang_AbstractMethodError(), - Method::name_and_sig_as_C_string(target_klass, - method->name(), - method->signature())); + vmSymbols::java_lang_AbstractMethodError(), ss.as_string()); JavaCallArguments args(h_origexception); THROW_ARG_0(vmSymbols::java_lang_reflect_InvocationTargetException(), vmSymbols::throwable_void_signature(), @@ -1104,10 +1105,13 @@ static oop invoke(InstanceKlass* klass, // an internal vtable bug. If you ever get this please let Karen know. if (method.is_null()) { ResourceMark rm(THREAD); - THROW_MSG_0(vmSymbols::java_lang_NoSuchMethodError(), - Method::name_and_sig_as_C_string(klass, - reflected_method->name(), - reflected_method->signature())); + stringStream ss; + ss.print("'"); + Method::print_external_name(&ss, klass, + reflected_method->name(), + reflected_method->signature()); + ss.print("'"); + THROW_MSG_0(vmSymbols::java_lang_NoSuchMethodError(), ss.as_string()); } assert(ptypes->is_objArray(), "just checking"); diff --git a/test/hotspot/jtreg/runtime/LoaderConstraints/itableLdrConstraint/Test.java b/test/hotspot/jtreg/runtime/LoaderConstraints/itableLdrConstraint/Test.java index 807fec0349b..825d3047223 100644 --- a/test/hotspot/jtreg/runtime/LoaderConstraints/itableLdrConstraint/Test.java +++ b/test/hotspot/jtreg/runtime/LoaderConstraints/itableLdrConstraint/Test.java @@ -38,19 +38,19 @@ public class Test { // Break expected error messages into 3 parts since the loader name includes its identity // hash which is unique and can't be compared against. static String expectedErrorMessage1_part1 = "loader constraint violation in interface itable initialization for " + - "class test.C: when selecting method test.I.m()Ltest/Foo; the class loader " + + "class test.C: when selecting method 'test.Foo test.I.m()' the class loader " + "PreemptingClassLoader @"; static String expectedErrorMessage1_part2 = " for super interface test.I, and the class loader 'app' of the " + - "selected method's type, test.J have different Class objects for the " + + "selected method's interface, test.J have different Class objects for the " + "type test.Foo used in the signature (test.I is in unnamed module of loader " + "PreemptingClassLoader @"; static String expectedErrorMessage1_part3 = ", parent loader 'app'; test.J is in unnamed module of loader 'app')"; static String expectedErrorMessage2_part1 = "loader constraint violation in interface itable initialization for " + - "class test.C: when selecting method test.I.m()Ltest/Foo; the class loader " + + "class test.C: when selecting method 'test.Foo test.I.m()' the class loader " + "'ItableLdrCnstrnt_Test_Loader' @"; static String expectedErrorMessage2_part2 = " for super interface test.I, and the class loader 'app' of the " + - "selected method's type, test.J have different Class objects for the " + + "selected method's interface, test.J have different Class objects for the " + "type test.Foo used in the signature (test.I is in unnamed module of loader " + "'ItableLdrCnstrnt_Test_Loader' @"; static String expectedErrorMessage2_part3 = ", parent loader 'app'; test.J is in unnamed module of loader 'app')"; @@ -79,7 +79,9 @@ public class Test { if (!errorMsg.contains(expectedErrorMessage_part1) || !errorMsg.contains(expectedErrorMessage_part2) || !errorMsg.contains(expectedErrorMessage_part3)) { - System.out.println("Expected: " + expectedErrorMessage_part1 + "" + expectedErrorMessage_part2 + "\n" + + System.out.println("Expected: " + expectedErrorMessage_part1 + "" + + expectedErrorMessage_part2 + "" + + expectedErrorMessage_part3 + "\n" + "but got: " + errorMsg); throw new RuntimeException("Wrong LinkageError exception thrown: " + errorMsg); } diff --git a/test/hotspot/jtreg/runtime/LoaderConstraints/vtableLdrConstraint/Test.java b/test/hotspot/jtreg/runtime/LoaderConstraints/vtableLdrConstraint/Test.java index 83acb4a935f..9c88739268b 100644 --- a/test/hotspot/jtreg/runtime/LoaderConstraints/vtableLdrConstraint/Test.java +++ b/test/hotspot/jtreg/runtime/LoaderConstraints/vtableLdrConstraint/Test.java @@ -38,7 +38,7 @@ public class Test { // Break expected error messages into 3 parts since the loader name includes its identity // hash which is unique and can't be compared against. static String expectedErrorMessage1_part1 = "loader constraint violation for class test.Task: when " + - "selecting overriding method test.Task.m()Ltest/Foo; the " + + "selecting overriding method 'test.Foo test.Task.m()' the " + "class loader PreemptingClassLoader @"; static String expectedErrorMessage1_part2 = " of the selected method's type test.Task, and the class " + "loader 'app' for its super type test.J have different Class objects " + @@ -47,7 +47,7 @@ public class Test { static String expectedErrorMessage1_part3 = ", parent loader 'app'; test.J is in unnamed module of loader 'app')"; static String expectedErrorMessage2_part1 = "loader constraint violation for class test.Task: when " + - "selecting overriding method test.Task.m()Ltest/Foo; the " + + "selecting overriding method 'test.Foo test.Task.m()' the " + "class loader 'VtableLdrCnstrnt_Test_Loader' @"; static String expectedErrorMessage2_part2 = " of the selected method's type test.Task, and the class " + "loader 'app' for its super type test.J have different Class objects " + diff --git a/test/hotspot/jtreg/runtime/Nestmates/membership/TestNestmateMembership.java b/test/hotspot/jtreg/runtime/Nestmates/membership/TestNestmateMembership.java index 97e023901f1..b1730b6724e 100644 --- a/test/hotspot/jtreg/runtime/Nestmates/membership/TestNestmateMembership.java +++ b/test/hotspot/jtreg/runtime/Nestmates/membership/TestNestmateMembership.java @@ -671,7 +671,7 @@ public class TestNestmateMembership { static void test_NoHostInvoke() throws Throwable { System.out.println("Testing for missing nest-host attribute"); String msg = "class TestNestmateMembership$Caller tried to access " + - "private method TestNestmateMembership$TargetNoHost.m()V"; + "private method 'void TestNestmateMembership$TargetNoHost.m()'"; try { Caller.invokeTargetNoHost(); throw new Error("Missing IllegalAccessError: " + msg); @@ -698,7 +698,7 @@ public class TestNestmateMembership { } msg = "class TestNestmateMembership$CallerNoHost tried to access " + - "private method TestNestmateMembership$Target.m()V"; + "private method 'void TestNestmateMembership$Target.m()'"; try { CallerNoHost.invokeTarget(); throw new Error("Missing IllegalAccessError: " + msg); @@ -707,7 +707,7 @@ public class TestNestmateMembership { check_expected(expected, msg); } msg = "class TestNestmateMembership$CallerNoHost tried to access private " + - "method TestNestmateMembership$TargetNoHost.m()V"; + "method 'void TestNestmateMembership$TargetNoHost.m()'"; try { CallerNoHost.invokeTargetNoHost(); throw new Error("Missing IllegalAccessError: " + msg); @@ -950,7 +950,7 @@ public class TestNestmateMembership { static void test_NoHostConstruct() throws Throwable { System.out.println("Testing for missing nest-host attribute"); String msg = "class TestNestmateMembership$Caller tried to access private " + - "method TestNestmateMembership$TargetNoHost.()V"; + "method 'void TestNestmateMembership$TargetNoHost.()'"; try { Caller.newTargetNoHost(); throw new Error("Missing IncompatibleClassChangeError: " + msg); @@ -977,7 +977,7 @@ public class TestNestmateMembership { } msg = "class TestNestmateMembership$CallerNoHost tried to access private " + - "method TestNestmateMembership$Target.()V"; + "method 'void TestNestmateMembership$Target.()'"; try { CallerNoHost.newTarget(); throw new Error("Missing IncompatibleClassChangeError: " + msg); @@ -986,7 +986,7 @@ public class TestNestmateMembership { check_expected(expected, msg); } msg = "class TestNestmateMembership$CallerNoHost tried to access private " + - "method TestNestmateMembership$TargetNoHost.()V"; + "method 'void TestNestmateMembership$TargetNoHost.()'"; try { CallerNoHost.newTargetNoHost(); throw new Error("Missing IncompatibleClassChangeError: " + msg); diff --git a/test/hotspot/jtreg/runtime/Nestmates/privateConstructors/TestConstructorHierarchy.java b/test/hotspot/jtreg/runtime/Nestmates/privateConstructors/TestConstructorHierarchy.java index a19ac564e62..88ec0cc97fe 100644 --- a/test/hotspot/jtreg/runtime/Nestmates/privateConstructors/TestConstructorHierarchy.java +++ b/test/hotspot/jtreg/runtime/Nestmates/privateConstructors/TestConstructorHierarchy.java @@ -51,7 +51,7 @@ public class TestConstructorHierarchy { throw new Error("Unexpected construction of ExternalSuper"); } catch (IllegalAccessError iae) { - if (iae.getMessage().contains("class TestConstructorHierarchy tried to access private method ExternalSuper.()V")) { + if (iae.getMessage().contains("class TestConstructorHierarchy tried to access private method 'void ExternalSuper.()'")) { System.out.println("Got expected exception constructing ExternalSuper: " + iae); } else throw new Error("Unexpected IllegalAccessError: " + iae); @@ -61,7 +61,7 @@ public class TestConstructorHierarchy { throw new Error("Unexpected construction of NestedA and supers"); } catch (IllegalAccessError iae) { - if (iae.getMessage().contains("class TestConstructorHierarchy$NestedA tried to access private method ExternalSuper.()V")) { + if (iae.getMessage().contains("class TestConstructorHierarchy$NestedA tried to access private method 'void ExternalSuper.()'")) { System.out.println("Got expected exception constructing NestedA: " + iae); } else throw new Error("Unexpected IllegalAccessError: " + iae); @@ -71,7 +71,7 @@ public class TestConstructorHierarchy { throw new Error("Unexpected construction of ExternalSub"); } catch (IllegalAccessError iae) { - if (iae.getMessage().contains("class ExternalSub tried to access private method TestConstructorHierarchy$NestedA.()V")) { + if (iae.getMessage().contains("class ExternalSub tried to access private method 'void TestConstructorHierarchy$NestedA.()'")) { System.out.println("Got expected exception constructing ExternalSub: " + iae); } else throw new Error("Unexpected IllegalAccessError: " + iae); diff --git a/test/hotspot/jtreg/runtime/exceptionMsgs/AbstractMethodError/AbstractMethodErrorTest.java b/test/hotspot/jtreg/runtime/exceptionMsgs/AbstractMethodError/AbstractMethodErrorTest.java index 1dcf760a4d2..1da52dd2187 100644 --- a/test/hotspot/jtreg/runtime/exceptionMsgs/AbstractMethodError/AbstractMethodErrorTest.java +++ b/test/hotspot/jtreg/runtime/exceptionMsgs/AbstractMethodError/AbstractMethodErrorTest.java @@ -99,11 +99,11 @@ public class AbstractMethodErrorTest { } private static String expectedErrorMessageAME1_1 = - "Missing implementation of resolved method abstract " + - "anAbstractMethod()Ljava/lang/String; of abstract class AME1_B."; + "Missing implementation of resolved method 'abstract " + + "java.lang.String anAbstractMethod()' of abstract class AME1_B."; private static String expectedErrorMessageAME1_2 = "Receiver class AME1_E does not define or inherit an implementation of the " + - "resolved method abstract aFunctionOfMyInterface()Ljava/lang/String; of " + + "resolved method 'abstract java.lang.String aFunctionOfMyInterface()' of " + "interface AME1_C."; public static void test_ame1() { @@ -158,11 +158,11 @@ public class AbstractMethodErrorTest { } private static String expectedErrorMessageAME2_Interpreted = - "Missing implementation of resolved method abstract " + - "aFunctionOfMyInterface()V of interface AME2_A."; + "Missing implementation of resolved method 'abstract " + + "void aFunctionOfMyInterface()' of interface AME2_A."; private static String expectedErrorMessageAME2_Compiled = "Receiver class AME2_C does not define or inherit an implementation of the resolved method " + - "abstract aFunctionOfMyInterface()V of interface AME2_A."; + "'abstract void aFunctionOfMyInterface()' of interface AME2_A."; public AbstractMethodErrorTest() throws InstantiationException, IllegalAccessException { try { @@ -228,7 +228,7 @@ public class AbstractMethodErrorTest { private static String expectedErrorMessageAME3_1 = "Receiver class AME3_C does not define or inherit an implementation of the resolved method " + - "ma()V of class AME3_A. Selected method is abstract AME3_B.ma()V."; + "'void ma()' of class AME3_A. Selected method is 'abstract void AME3_B.ma()'."; // Testing abstract class that extends a class that has an implementation. // Loop so that method gets eventually compiled/osred. @@ -259,7 +259,7 @@ public class AbstractMethodErrorTest { private static String expectedErrorMessageAME3_2 = "Receiver class AME3_C does not define or inherit an implementation of " + - "the resolved method abstract ma()V of abstract class AME3_B."; + "the resolved method 'abstract void ma()' of abstract class AME3_B."; // Testing abstract class that extends a class that has an implementation. // Loop so that method gets eventually compiled/osred. @@ -289,7 +289,7 @@ public class AbstractMethodErrorTest { } private static String expectedErrorMessageAME4 = - "Missing implementation of resolved method abstract ma()V of " + + "Missing implementation of resolved method 'abstract void ma()' of " + "abstract class AME4_B."; // Testing abstract class that extends a class that has an implementation. @@ -336,7 +336,7 @@ public class AbstractMethodErrorTest { } private static String expectedErrorMessageAME5_VtableStub = - "Receiver class AME5_B does not define or inherit an implementation of the resolved method abstract mc()V " + + "Receiver class AME5_B does not define or inherit an implementation of the resolved method 'abstract void mc()' " + "of abstract class AME5_A."; // AbstractMethodErrors detected in vtable stubs. @@ -409,7 +409,7 @@ public class AbstractMethodErrorTest { private static String expectedErrorMessageAME6_ItableStub = "Receiver class AME6_B does not define or inherit an implementation of the resolved" + - " method abstract mc()V of interface AME6_A."; + " method 'abstract void mc()' of interface AME6_A."; // ------------------------------------------------------------------------- // AbstractMethodErrors detected in itable stubs. diff --git a/test/hotspot/jtreg/runtime/exceptionMsgs/IllegalAccessError/IllegalAccessErrorTest.java b/test/hotspot/jtreg/runtime/exceptionMsgs/IllegalAccessError/IllegalAccessErrorTest.java index ff5a25bacc0..0c3bc2d6bc1 100644 --- a/test/hotspot/jtreg/runtime/exceptionMsgs/IllegalAccessError/IllegalAccessErrorTest.java +++ b/test/hotspot/jtreg/runtime/exceptionMsgs/IllegalAccessError/IllegalAccessErrorTest.java @@ -141,7 +141,7 @@ abstract public class IllegalAccessErrorTest { private static void iae4_m() { } private static String expectedErrorMessage4 = - "class test.Runner4 tried to access private method test.IllegalAccessErrorTest.iae4_m()V " + + "class test.Runner4 tried to access private method 'void test.IllegalAccessErrorTest.iae4_m()' " + "(test.Runner4 and test.IllegalAccessErrorTest are in unnamed module of loader 'app')"; // Test according to java/lang/invoke/DefineClassTest.java @@ -264,7 +264,7 @@ abstract public class IllegalAccessErrorTest { } private static String expectedErrorMessage7_1 = - "class test.IAE78_B tried to access method test.IAE78_A.()V " + + "class test.IAE78_B tried to access method 'void test.IAE78_A.()' " + "(test.IAE78_B is in unnamed module of loader 'test7_method_CL' @"; private static String expectedErrorMessage7_2 = "; test.IAE78_A is in unnamed module of loader 'app')"; diff --git a/test/hotspot/jtreg/runtime/exceptionMsgs/methodPrinting/TeMe3_C.jasm b/test/hotspot/jtreg/runtime/exceptionMsgs/methodPrinting/TeMe3_C.jasm new file mode 100644 index 00000000000..2085d43e905 --- /dev/null +++ b/test/hotspot/jtreg/runtime/exceptionMsgs/methodPrinting/TeMe3_C.jasm @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019 SAP SE. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package test; + +/* Method ma() is missing in this implementation to cause error. */ + +class TeMe3_C extends TeMe3_B { + public Method "":"()V" + stack 1 locals 1 + { + aload_0; + invokespecial Method TeMe3_B."":()V; + return; + } +} diff --git a/test/hotspot/jtreg/runtime/exceptionMsgs/methodPrinting/TestPrintingMethods.java b/test/hotspot/jtreg/runtime/exceptionMsgs/methodPrinting/TestPrintingMethods.java new file mode 100644 index 00000000000..5c413b07a69 --- /dev/null +++ b/test/hotspot/jtreg/runtime/exceptionMsgs/methodPrinting/TestPrintingMethods.java @@ -0,0 +1,151 @@ +/* + * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019 SAP SE. 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 + * @summary Check that methods are printed properly. + * @compile -encoding UTF-8 TestPrintingMethods.java + * @compile TeMe3_C.jasm + * @run main/othervm -Xbootclasspath/a:. test.TestPrintingMethods + */ + +package test; + +public class TestPrintingMethods { + + private static String expectedErrorMessage_VV = "void test.TeMe3_B.ma()"; + private static String expectedErrorMessage_integral = "double[][] test.TeMe3_B.ma(int, boolean, byte[][], float)"; + private static String expectedErrorMessage_classes = "test.TeMe3_B[][] test.TeMe3_B.ma(java.lang.Object[][][])"; + private static String expectedErrorMessage_unicode = "java.lang.Object test.TeMe3_B.m\u20ac\u00a3a(java.lang.Object)"; + + static void checkMsg(Error e, String expected) throws Exception { + String errorMsg = e.getMessage(); + if (errorMsg == null) { + throw new RuntimeException("Caught AbstractMethodError with empty message."); + } else if (errorMsg.contains(expected)) { + System.out.println("Passed with message: " + errorMsg); + } else { + System.out.println("Expected method to be printed as \"" + expected + "\"\n" + + "in exception message: " + errorMsg); + throw new RuntimeException("Method not printed as expected."); + } + } + + // Call various missing methods to check that the exception + // message contains the proper string for the method name and + // signature. We expect Java-like printing of parameters etc. + static void test() throws Exception { + TeMe3_A c = new TeMe3_C(); + + try { + c.ma(); + throw new RuntimeException("Expected AbstractMethodError was not thrown."); + } catch (AbstractMethodError e) { + checkMsg(e, expectedErrorMessage_VV); + } + + try { + c.ma(2, true, new byte[2][3], 23.4f); + throw new RuntimeException("Expected AbstractMethodError was not thrown."); + } catch (AbstractMethodError e) { + checkMsg(e, expectedErrorMessage_integral); + } + + try { + c.ma(new java.lang.Object[1][2][3]); + throw new RuntimeException("Expected AbstractMethodError was not thrown."); + } catch (AbstractMethodError e) { + checkMsg(e, expectedErrorMessage_classes); + } + + try { + c.m\u20ac\u00a3a(new java.lang.Object()); + throw new RuntimeException("Expected AbstractMethodError was not thrown."); + } catch (AbstractMethodError e) { + checkMsg(e, expectedErrorMessage_unicode); + } + } + + public static void main(String[] args) throws Exception { + test(); + } +} + +// Helper classes to test abstract method error. +// +// Errorneous versions of these classes are implemented in java +// assembler. + + +// ----------------------------------------------------------------------- +// Test AbstractMethod error shadowing existing implementation. +// +// Class hierachy: +// +// A // A class implementing m() and similar. +// | +// B // An abstract class defining m() abstract. +// | +// C // An errorneous class lacking an implementation of m(). +// +class TeMe3_A { + public void ma() { + System.out.print("A.ma()"); + } + public double[][] ma(int i, boolean z, byte[][] b, float f) { + return null; + } + public TeMe3_B[][] ma(java.lang.Object[][][] o) { + return null; + } + public java.lang.Object m\u20ac\u00a3a(java.lang.Object s) { + return null; + } +} + +abstract class TeMe3_B extends TeMe3_A { + public abstract void ma(); + public abstract double[][] ma(int i, boolean z, byte[][] b, float f); + public abstract TeMe3_B[][] ma(java.lang.Object[][][] o); + public abstract java.lang.Object m\u20ac\u00a3a(java.lang.Object s); +} + +// An errorneous version of this class is implemented in java +// assembler. +class TeMe3_C extends TeMe3_B { + // These methods are missing in the .jasm implementation. + public void ma() { + System.out.print("C.ma()"); + } + public double[][] ma(int i, boolean z, byte[][] b, float f) { + return new double[2][2]; + } + public TeMe3_B[][] ma(java.lang.Object[][][] o) { + return new TeMe3_C[3][3]; + } + public java.lang.Object m\u20ac\u00a3a(java.lang.Object s) { + return new java.lang.Object(); + } +} + diff --git a/test/hotspot/jtreg/runtime/modules/AccessCheck/ExpQualToM1PrivateMethodIAE.java b/test/hotspot/jtreg/runtime/modules/AccessCheck/ExpQualToM1PrivateMethodIAE.java index ac2ee32629c..0a6fcc6b871 100644 --- a/test/hotspot/jtreg/runtime/modules/AccessCheck/ExpQualToM1PrivateMethodIAE.java +++ b/test/hotspot/jtreg/runtime/modules/AccessCheck/ExpQualToM1PrivateMethodIAE.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2019, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -103,7 +103,7 @@ public class ExpQualToM1PrivateMethodIAE { // java.lang.IllegalAccessError: // tried to access private method p2.c2.method2()V from class p1.c1 (p2.c2 is in module m2x of loader // myloaders.MySameClassLoader @; p1.c1 is in module m1x of loader myloaders.MySameClassLoader @) - if (!message.contains("class p1.c1 tried to access private method p2.c2.method2()V " + + if (!message.contains("class p1.c1 tried to access private method 'void p2.c2.method2()' " + "(p1.c1 is in module m1x of loader myloaders.MySameClassLoader @") || !message.contains("; p2.c2 is in module m2x of loader myloaders.MySameClassLoader @")) { throw new RuntimeException("Test Failed, an IAE was thrown with the wrong message: " + e.toString()); From d6c2cc2413e38d44dd88da942c122e5487f80749 Mon Sep 17 00:00:00 2001 From: Goetz Lindenmaier Date: Fri, 5 Apr 2019 07:59:13 +0200 Subject: [PATCH 23/73] 8219918: ProblemList hotspot tests failing in SAP testing Reviewed-by: dholmes --- test/hotspot/jtreg/ProblemList.txt | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/test/hotspot/jtreg/ProblemList.txt b/test/hotspot/jtreg/ProblemList.txt index fcad14ecae5..1875d59fdb2 100644 --- a/test/hotspot/jtreg/ProblemList.txt +++ b/test/hotspot/jtreg/ProblemList.txt @@ -83,6 +83,7 @@ gc/metaspace/CompressedClassSpaceSizeInJmapHeap.java 8193639 solaris-all runtime/NMT/CheckForProperDetailStackTrace.java 8218458 generic-all runtime/SharedArchiveFile/SASymbolTableTest.java 8193639 solaris-all runtime/containers/docker/TestCPUSets.java 8220672 generic-all +runtime/jni/terminatedThread/TestTerminatedThread.java 8219652 aix-ppc64 ############################################################################# @@ -172,6 +173,9 @@ vmTestbase/nsk/jvmti/ResourceExhausted/resexhausted003/TestDescription.java 6606 vmTestbase/nsk/jvmti/ResourceExhausted/resexhausted004/TestDescription.java 6606767 generic-all vmTestbase/nsk/jvmti/scenarios/extension/EX03/ex03t001/TestDescription.java 8173658 generic-all vmTestbase/nsk/jvmti/AttachOnDemand/attach045/TestDescription.java 8202971 generic-all +vmTestbase/nsk/jvmti/scenarios/jni_interception/JI05/ji05t001/TestDescription.java 8219652 aix-ppc64 +vmTestbase/nsk/jvmti/scenarios/jni_interception/JI06/ji06t001/TestDescription.java 8219652 aix-ppc64 +vmTestbase/nsk/jvmti/SetJNIFunctionTable/setjniftab001/TestDescription.java 8219652 aix-ppc64 vmTestbase/gc/lock/jni/jnilock002/TestDescription.java 8208243,8192647 generic-all From 77ae10cd259a352e3cdc262826ca63228c76917f Mon Sep 17 00:00:00 2001 From: Matthias Baesken Date: Tue, 2 Apr 2019 13:54:00 +0200 Subject: [PATCH 24/73] 8218547: Simplify JLI_Open on Windows in native code (libjli) Reviewed-by: alanb, clanger --- src/java.base/windows/native/libjli/java_md.c | 102 ++++++++++-------- test/jdk/tools/launcher/Arrrghs.java | 42 +++++--- 2 files changed, 81 insertions(+), 63 deletions(-) diff --git a/src/java.base/windows/native/libjli/java_md.c b/src/java.base/windows/native/libjli/java_md.c index 69d09a678b7..76d0e1bbe95 100644 --- a/src/java.base/windows/native/libjli/java_md.c +++ b/src/java.base/windows/native/libjli/java_md.c @@ -41,8 +41,6 @@ #define JVM_DLL "jvm.dll" #define JAVA_DLL "java.dll" -#define ELP_PREFIX L"\\\\?\\" - /* * Prototypes. */ @@ -497,57 +495,67 @@ JLI_Snprintf(char* buffer, size_t size, const char* format, ...) { return rc; } -/* On Windows, if _open fails, retry again with CreateFileW and - * "\\?\" prefix ( extended-length paths) - this allows to open paths with larger file names; - * otherwise we run into the MAX_PATH limitation */ -int JLI_Open(const char* name, int flags) { - int fd = _open(name, flags); - if (fd == -1 && errno == ENOENT) { - wchar_t* wname = NULL; - wchar_t* wfullname = NULL; - wchar_t* wfullname_w_prefix = NULL; - size_t wnamelen, wfullnamelen, elplen; - HANDLE h; - - wnamelen = strlen(name) + 1; - wname = (wchar_t*) malloc(wnamelen*sizeof(wchar_t)); - if (wname == NULL) { - goto end; - } - if (mbstowcs(wname, name, wnamelen - 1) == -1) { - goto end; - } - wname[wnamelen - 1] = L'\0'; - wfullname = _wfullpath(wfullname, wname, 0); - if (wfullname == NULL) { - goto end; - } - - wfullnamelen = wcslen(wfullname); - if (wfullnamelen > 247) { - elplen = wcslen(ELP_PREFIX); - wfullname_w_prefix = (wchar_t*) malloc((elplen+wfullnamelen+1)*sizeof(wchar_t)); - wcscpy(wfullname_w_prefix, ELP_PREFIX); - wcscpy(wfullname_w_prefix+elplen, wfullname); - - h = CreateFileW(wfullname_w_prefix, GENERIC_READ, FILE_SHARE_READ, NULL, - OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); - if (h == INVALID_HANDLE_VALUE) { - goto end; +/* taken from hotspot and slightly adjusted for jli lib; + * creates a UNC/ELP path from input 'path' + * the return buffer is allocated in C heap and needs to be freed using + * JLI_MemFree by the caller. + */ +static wchar_t* create_unc_path(const char* path, errno_t* err) { + wchar_t* wpath = NULL; + size_t converted_chars = 0; + size_t path_len = strlen(path) + 1; /* includes the terminating NULL */ + if (path[0] == '\\' && path[1] == '\\') { + if (path[2] == '?' && path[3] == '\\') { + /* if it already has a \\?\ don't do the prefix */ + wpath = (wchar_t*) JLI_MemAlloc(path_len * sizeof(wchar_t)); + if (wpath != NULL) { + *err = mbstowcs_s(&converted_chars, wpath, path_len, path, path_len); + } else { + *err = ENOMEM; + } + } else { + /* only UNC pathname includes double slashes here */ + wpath = (wchar_t*) JLI_MemAlloc((path_len + 7) * sizeof(wchar_t)); + if (wpath != NULL) { + wcscpy(wpath, L"\\\\?\\UNC\0"); + *err = mbstowcs_s(&converted_chars, &wpath[7], path_len, path, path_len); + } else { + *err = ENOMEM; } - /* associates fd with handle */ - fd = _open_osfhandle((intptr_t)h, _O_RDONLY); } -end: - free(wname); - free(wfullname); - free(wfullname_w_prefix); + } else { + wpath = (wchar_t*) JLI_MemAlloc((path_len + 4) * sizeof(wchar_t)); + if (wpath != NULL) { + wcscpy(wpath, L"\\\\?\\\0"); + *err = mbstowcs_s(&converted_chars, &wpath[4], path_len, path, path_len); + } else { + *err = ENOMEM; + } + } + return wpath; +} + +int JLI_Open(const char* name, int flags) { + int fd; + if (strlen(name) < MAX_PATH) { + fd = _open(name, flags); + } else { + errno_t err = ERROR_SUCCESS; + wchar_t* wpath = create_unc_path(name, &err); + if (err != ERROR_SUCCESS) { + if (wpath != NULL) JLI_MemFree(wpath); + errno = err; + return -1; + } + fd = _wopen(wpath, flags); + if (fd == -1) { + errno = GetLastError(); + } + JLI_MemFree(wpath); } return fd; } - - JNIEXPORT void JNICALL JLI_ReportErrorMessage(const char* fmt, ...) { va_list vl; diff --git a/test/jdk/tools/launcher/Arrrghs.java b/test/jdk/tools/launcher/Arrrghs.java index d351c142765..11a6ab0a520 100644 --- a/test/jdk/tools/launcher/Arrrghs.java +++ b/test/jdk/tools/launcher/Arrrghs.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2007, 2019, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -24,7 +24,7 @@ /** * @test * @bug 5030233 6214916 6356475 6571029 6684582 6742159 4459600 6758881 6753938 - * 6894719 6968053 7151434 7146424 8007333 8077822 8143640 8132379 + * 6894719 6968053 7151434 7146424 8007333 8077822 8143640 8132379 8218547 * @summary Argument parsing validation. * @modules jdk.compiler * jdk.zipfs @@ -36,6 +36,9 @@ import java.io.File; import java.io.FileNotFoundException; import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Paths; +import java.nio.file.Path; import java.util.ArrayList; import java.util.Arrays; import java.util.HashMap; @@ -55,20 +58,6 @@ public class Arrrghs extends TestHelper { * */ - /* - * SIGH, On Windows all strings are quoted, we need to unwrap it - */ - private static String removeExtraQuotes(String in) { - if (isWindows) { - // Trim the string and remove the enclosed quotes if any. - in = in.trim(); - if (in.startsWith("\"") && in.endsWith("\"")) { - return in.substring(1, in.length()-1); - } - } - return in; - } - // the pattern we hope to see in the output static final Pattern ArgPattern = Pattern.compile("\\s*argv\\[[0-9]*\\].*=.*"); @@ -489,6 +478,27 @@ public class Arrrghs extends TestHelper { System.out.println(tr); } + /* + * Tests -jar command on a jar file with "long" (> 260 chars) full path on Windows + */ + @Test + void testLongPathJarFile() throws IOException { + if (!isWindows) { + return; + } + // put the jar file to a location with long path + String longPathPart = "longpathtest_longpathtest/"; + String longPathStr = longPathPart.repeat(15); + Path longPath = Paths.get(longPathStr); + Path jarPath = Files.createDirectories(longPath).resolve("elp.jar"); + File elp = jarPath.toFile(); + createJar(elp, new File("Foo"), "public static void main(String[] args){ System.out.println(\"Hello from ELP\"); }"); + System.out.println("execute " + elp.getAbsolutePath()); + TestResult tr = doExec(javaCmd, "-jar", elp.getAbsolutePath()); + tr.checkPositive(); + tr.contains("Hello from ELP"); + } + /* * Tests various dispositions of the main method, these tests are limited * to English locales as they check for error messages that are localized. From 208ecde943660451f0f38bf5792c8e68404b6239 Mon Sep 17 00:00:00 2001 From: Aleksey Shipilev Date: Fri, 5 Apr 2019 09:06:19 +0200 Subject: [PATCH 25/73] 8221918: runtime/SharedArchiveFile/serviceability/ReplaceCriticalClasses.java fails: Shared archive not found Reviewed-by: jiangli, dholmes --- .../serviceability/ReplaceCriticalClasses.java | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/test/hotspot/jtreg/runtime/SharedArchiveFile/serviceability/ReplaceCriticalClasses.java b/test/hotspot/jtreg/runtime/SharedArchiveFile/serviceability/ReplaceCriticalClasses.java index 7a4c1825ed7..e70021c4ef8 100644 --- a/test/hotspot/jtreg/runtime/SharedArchiveFile/serviceability/ReplaceCriticalClasses.java +++ b/test/hotspot/jtreg/runtime/SharedArchiveFile/serviceability/ReplaceCriticalClasses.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2019, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -47,6 +47,15 @@ public class ReplaceCriticalClasses { public void process(String args[]) throws Throwable { if (args.length == 0) { + // Dump the shared archive in case it was not generated during the JDK build. + // Put the archive at separate file to avoid clashes with concurrent tests. + CDSOptions opts = new CDSOptions() + .setXShareMode("dump") + .setArchiveName(ReplaceCriticalClasses.class.getName() + ".jsa") + .setUseVersion(false) + .addSuffix("-showversion"); + CDSTestUtils.run(opts).assertNormalExit(""); + launchChildProcesses(getTests()); } else if (args.length == 3 && args[0].equals("child")) { Class klass = Class.forName(args[2].replace("/", ".")); @@ -152,7 +161,7 @@ public class ReplaceCriticalClasses { CDSOptions opts = (new CDSOptions()) .setXShareMode("auto") - .setUseSystemArchive(true) + .setArchiveName(ReplaceCriticalClasses.class.getName() + ".jsa") .setUseVersion(false) .addSuffix("-showversion", "-Xlog:cds", From f65be307bfde9a17bb2d4d0aaf4c59b520cfe985 Mon Sep 17 00:00:00 2001 From: Martin Doerr Date: Fri, 5 Apr 2019 09:18:18 +0200 Subject: [PATCH 26/73] 8221833: Readability check in Symbol::is_valid not performed for some addresses Reviewed-by: zgu, coleenp --- src/hotspot/share/runtime/os.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/hotspot/share/runtime/os.cpp b/src/hotspot/share/runtime/os.cpp index 8e2ddff79b0..e45e312acde 100644 --- a/src/hotspot/share/runtime/os.cpp +++ b/src/hotspot/share/runtime/os.cpp @@ -1024,8 +1024,9 @@ bool os::is_readable_pointer(const void* p) { } bool os::is_readable_range(const void* from, const void* to) { - for (address p = align_down((address)from, min_page_size()); p < to; p += min_page_size()) { - if (!is_readable_pointer(p)) { + if ((uintptr_t)from >= (uintptr_t)to) return false; + for (uintptr_t p = align_down((uintptr_t)from, min_page_size()); p < (uintptr_t)to; p += min_page_size()) { + if (!is_readable_pointer((const void*)p)) { return false; } } From 1baf5289c5634ca495be412fddde97667f046949 Mon Sep 17 00:00:00 2001 From: Thomas Stuefe Date: Wed, 27 Mar 2019 14:13:34 +0100 Subject: [PATCH 27/73] 8221539: [metaspace] Improve MetaspaceObj::is_metaspace_obj() and friends Reviewed-by: adinn, coleenp, mdoerr --- src/hotspot/cpu/aarch64/frame_aarch64.cpp | 2 +- src/hotspot/cpu/arm/frame_arm.cpp | 2 +- src/hotspot/cpu/sparc/frame_sparc.cpp | 2 +- src/hotspot/cpu/x86/frame_x86.cpp | 2 +- .../os_cpu/linux_ppc/thread_linux_ppc.cpp | 2 +- .../os_cpu/linux_s390/thread_linux_s390.cpp | 3 +- src/hotspot/share/memory/allocation.cpp | 10 +- src/hotspot/share/memory/allocation.hpp | 13 +- .../memory/metaspace/virtualSpaceList.cpp | 78 +++++++++--- .../memory/metaspace/virtualSpaceList.hpp | 17 +++ .../memory/metaspace/virtualSpaceNode.hpp | 2 + src/hotspot/share/oops/instanceKlass.cpp | 2 +- .../gtest/memory/test_is_metaspace_obj.cpp | 115 ++++++++++++++++++ 13 files changed, 222 insertions(+), 28 deletions(-) create mode 100644 test/hotspot/gtest/memory/test_is_metaspace_obj.cpp diff --git a/src/hotspot/cpu/aarch64/frame_aarch64.cpp b/src/hotspot/cpu/aarch64/frame_aarch64.cpp index d3a6feedd86..419dde8111b 100644 --- a/src/hotspot/cpu/aarch64/frame_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/frame_aarch64.cpp @@ -559,7 +559,7 @@ bool frame::is_interpreted_frame_valid(JavaThread* thread) const { // validate constantPoolCache* ConstantPoolCache* cp = *interpreter_frame_cache_addr(); - if (cp == NULL || !cp->is_metaspace_object()) return false; + if (MetaspaceObj::is_valid(cp) == false) return false; // validate locals diff --git a/src/hotspot/cpu/arm/frame_arm.cpp b/src/hotspot/cpu/arm/frame_arm.cpp index a664a7aa337..0e054f377d9 100644 --- a/src/hotspot/cpu/arm/frame_arm.cpp +++ b/src/hotspot/cpu/arm/frame_arm.cpp @@ -494,7 +494,7 @@ bool frame::is_interpreted_frame_valid(JavaThread* thread) const { // validate ConstantPoolCache* ConstantPoolCache* cp = *interpreter_frame_cache_addr(); - if (cp == NULL || !cp->is_metaspace_object()) return false; + if (MetaspaceObj::is_valid(cp) == false) return false; // validate locals diff --git a/src/hotspot/cpu/sparc/frame_sparc.cpp b/src/hotspot/cpu/sparc/frame_sparc.cpp index 2fbca263743..6f5ab67126a 100644 --- a/src/hotspot/cpu/sparc/frame_sparc.cpp +++ b/src/hotspot/cpu/sparc/frame_sparc.cpp @@ -665,7 +665,7 @@ bool frame::is_interpreted_frame_valid(JavaThread* thread) const { // validate ConstantPoolCache* ConstantPoolCache* cp = *interpreter_frame_cache_addr(); - if (cp == NULL || !cp->is_metaspace_object()) return false; + if (MetaspaceObj::is_valid(cp) == false) return false; // validate locals diff --git a/src/hotspot/cpu/x86/frame_x86.cpp b/src/hotspot/cpu/x86/frame_x86.cpp index acedaf827b7..34a1a73b4c7 100644 --- a/src/hotspot/cpu/x86/frame_x86.cpp +++ b/src/hotspot/cpu/x86/frame_x86.cpp @@ -546,7 +546,7 @@ bool frame::is_interpreted_frame_valid(JavaThread* thread) const { // validate ConstantPoolCache* ConstantPoolCache* cp = *interpreter_frame_cache_addr(); - if (cp == NULL || !cp->is_metaspace_object()) return false; + if (MetaspaceObj::is_valid(cp) == false) return false; // validate locals diff --git a/src/hotspot/os_cpu/linux_ppc/thread_linux_ppc.cpp b/src/hotspot/os_cpu/linux_ppc/thread_linux_ppc.cpp index 9213c8772da..0a0633a71ce 100644 --- a/src/hotspot/os_cpu/linux_ppc/thread_linux_ppc.cpp +++ b/src/hotspot/os_cpu/linux_ppc/thread_linux_ppc.cpp @@ -66,7 +66,7 @@ bool JavaThread::pd_get_top_frame_for_profiling(frame* fr_addr, void* ucontext, if (ret_frame.is_interpreted_frame()) { frame::ijava_state* istate = ret_frame.get_ijava_state(); - if (!((Method*)(istate->method))->is_metaspace_object()) { + if (MetaspaceObj::is_valid((Method*)(istate->method)) == false) { return false; } uint64_t reg_bcp = uc->uc_mcontext.regs->gpr[14/*R14_bcp*/]; diff --git a/src/hotspot/os_cpu/linux_s390/thread_linux_s390.cpp b/src/hotspot/os_cpu/linux_s390/thread_linux_s390.cpp index c3379f5049e..9695b9a898f 100644 --- a/src/hotspot/os_cpu/linux_s390/thread_linux_s390.cpp +++ b/src/hotspot/os_cpu/linux_s390/thread_linux_s390.cpp @@ -63,7 +63,8 @@ bool JavaThread::pd_get_top_frame_for_profiling(frame* fr_addr, void* ucontext, if (ret_frame.is_interpreted_frame()) { frame::z_ijava_state* istate = ret_frame.ijava_state_unchecked(); - if ((stack_base() >= (address)istate && (address)istate > stack_end()) || !((Method*)(istate->method))->is_metaspace_object()) { + if ((stack_base() >= (address)istate && (address)istate > stack_end()) || + MetaspaceObj::is_valid((Method*)(istate->method)) == false) { return false; } uint64_t reg_bcp = uc->uc_mcontext.gregs[13/*Z_BCP*/]; diff --git a/src/hotspot/share/memory/allocation.cpp b/src/hotspot/share/memory/allocation.cpp index 5f4b5f94944..f04ee776d83 100644 --- a/src/hotspot/share/memory/allocation.cpp +++ b/src/hotspot/share/memory/allocation.cpp @@ -84,8 +84,14 @@ void* MetaspaceObj::operator new(size_t size, ClassLoaderData* loader_data, return Metaspace::allocate(loader_data, word_size, type, THREAD); } -bool MetaspaceObj::is_metaspace_object() const { - return Metaspace::contains((void*)this); +bool MetaspaceObj::is_valid(const MetaspaceObj* p) { + // Weed out obvious bogus values first without traversing metaspace + if ((size_t)p < os::min_page_size()) { + return false; + } else if (!is_aligned((address)p, sizeof(MetaWord))) { + return false; + } + return Metaspace::contains((void*)p); } void MetaspaceObj::print_address_on(outputStream* st) const { diff --git a/src/hotspot/share/memory/allocation.hpp b/src/hotspot/share/memory/allocation.hpp index 17273c08c7e..08908a3d0fd 100644 --- a/src/hotspot/share/memory/allocation.hpp +++ b/src/hotspot/share/memory/allocation.hpp @@ -258,12 +258,19 @@ class MetaspaceObj { static void* _shared_metaspace_top; // (exclusive) high address public: - bool is_metaspace_object() const; - bool is_shared() const { + + // Returns true if the pointer points to a valid MetaspaceObj. A valid + // MetaspaceObj is MetaWord-aligned and contained within either + // non-shared or shared metaspace. + static bool is_valid(const MetaspaceObj* p); + + static bool is_shared(const MetaspaceObj* p) { // If no shared metaspace regions are mapped, _shared_metaspace_{base,top} will // both be NULL and all values of p will be rejected quickly. - return (((void*)this) < _shared_metaspace_top && ((void*)this) >= _shared_metaspace_base); + return (((void*)p) < _shared_metaspace_top && ((void*)p) >= _shared_metaspace_base); } + bool is_shared() const { return MetaspaceObj::is_shared(this); } + void print_address_on(outputStream* st) const; // nonvirtual address printing static void set_shared_metaspace_range(void* base, void* top) { diff --git a/src/hotspot/share/memory/metaspace/virtualSpaceList.cpp b/src/hotspot/share/memory/metaspace/virtualSpaceList.cpp index 721eab60a26..7381ea51123 100644 --- a/src/hotspot/share/memory/metaspace/virtualSpaceList.cpp +++ b/src/hotspot/share/memory/metaspace/virtualSpaceList.cpp @@ -92,9 +92,9 @@ void VirtualSpaceList::purge(ChunkManager* chunk_manager) { assert_lock_strong(MetaspaceExpand_lock); // Don't use a VirtualSpaceListIterator because this // list is being changed and a straightforward use of an iterator is not safe. - VirtualSpaceNode* purged_vsl = NULL; VirtualSpaceNode* prev_vsl = virtual_space_list(); VirtualSpaceNode* next_vsl = prev_vsl; + int num_purged_nodes = 0; while (next_vsl != NULL) { VirtualSpaceNode* vsl = next_vsl; DEBUG_ONLY(vsl->verify(false);) @@ -118,20 +118,17 @@ void VirtualSpaceList::purge(ChunkManager* chunk_manager) { dec_reserved_words(vsl->reserved_words()); dec_committed_words(vsl->committed_words()); dec_virtual_space_count(); - purged_vsl = vsl; delete vsl; + num_purged_nodes ++; } else { prev_vsl = vsl; } } + + // Verify list #ifdef ASSERT - if (purged_vsl != NULL) { - // List should be stable enough to use an iterator here. - VirtualSpaceListIterator iter(virtual_space_list()); - while (iter.repeat()) { - VirtualSpaceNode* vsl = iter.get_next(); - assert(vsl != purged_vsl, "Purge of vsl failed"); - } + if (num_purged_nodes > 0) { + verify(false); } #endif } @@ -143,11 +140,13 @@ void VirtualSpaceList::purge(ChunkManager* chunk_manager) { VirtualSpaceNode* VirtualSpaceList::find_enclosing_space(const void* ptr) { // List should be stable enough to use an iterator here because removing virtual // space nodes is only allowed at a safepoint. - VirtualSpaceListIterator iter(virtual_space_list()); - while (iter.repeat()) { - VirtualSpaceNode* vsn = iter.get_next(); - if (vsn->contains(ptr)) { - return vsn; + if (is_within_envelope((address)ptr)) { + VirtualSpaceListIterator iter(virtual_space_list()); + while (iter.repeat()) { + VirtualSpaceNode* vsn = iter.get_next(); + if (vsn->contains(ptr)) { + return vsn; + } } } return NULL; @@ -170,7 +169,9 @@ VirtualSpaceList::VirtualSpaceList(size_t word_size) : _is_class(false), _reserved_words(0), _committed_words(0), - _virtual_space_count(0) { + _virtual_space_count(0), + _envelope_lo((address)max_uintx), + _envelope_hi(NULL) { MutexLockerEx cl(MetaspaceExpand_lock, Mutex::_no_safepoint_check_flag); create_new_virtual_space(word_size); @@ -182,12 +183,17 @@ VirtualSpaceList::VirtualSpaceList(ReservedSpace rs) : _is_class(true), _reserved_words(0), _committed_words(0), - _virtual_space_count(0) { + _virtual_space_count(0), + _envelope_lo((address)max_uintx), + _envelope_hi(NULL) { MutexLockerEx cl(MetaspaceExpand_lock, Mutex::_no_safepoint_check_flag); VirtualSpaceNode* class_entry = new VirtualSpaceNode(is_class(), rs); bool succeeded = class_entry->initialize(); if (succeeded) { + expand_envelope_to_include_node(class_entry); + // ensure lock-free iteration sees fully initialized node + OrderAccess::storestore(); link_vs(class_entry); } } @@ -224,12 +230,16 @@ bool VirtualSpaceList::create_new_virtual_space(size_t vs_word_size) { } else { assert(new_entry->reserved_words() == vs_word_size, "Reserved memory size differs from requested memory size"); + expand_envelope_to_include_node(new_entry); // ensure lock-free iteration sees fully initialized node OrderAccess::storestore(); link_vs(new_entry); DEBUG_ONLY(Atomic::inc(&g_internal_statistics.num_vsnodes_created)); return true; } + + DEBUG_ONLY(verify(false);) + } void VirtualSpaceList::link_vs(VirtualSpaceNode* new_entry) { @@ -399,5 +409,41 @@ void VirtualSpaceList::print_map(outputStream* st) const { } } +// Given a node, expand range such that it includes the node. +void VirtualSpaceList::expand_envelope_to_include_node(const VirtualSpaceNode* node) { + _envelope_lo = MIN2(_envelope_lo, (address)node->low_boundary()); + _envelope_hi = MAX2(_envelope_hi, (address)node->high_boundary()); +} + + +#ifdef ASSERT +void VirtualSpaceList::verify(bool slow) { + VirtualSpaceNode* list = virtual_space_list(); + VirtualSpaceListIterator iter(list); + size_t reserved = 0; + size_t committed = 0; + size_t node_count = 0; + while (iter.repeat()) { + VirtualSpaceNode* node = iter.get_next(); + if (slow) { + node->verify(true); + } + // Check that the node resides fully within our envelope. + assert((address)node->low_boundary() >= _envelope_lo && (address)node->high_boundary() <= _envelope_hi, + "Node " SIZE_FORMAT " [" PTR_FORMAT ", " PTR_FORMAT ") outside envelope [" PTR_FORMAT ", " PTR_FORMAT ").", + node_count, p2i(node->low_boundary()), p2i(node->high_boundary()), p2i(_envelope_lo), p2i(_envelope_hi)); + reserved += node->reserved_words(); + committed += node->committed_words(); + node_count ++; + } + assert(reserved == reserved_words() && committed == committed_words() && node_count == _virtual_space_count, + "Mismatch: reserved real: " SIZE_FORMAT " expected: " SIZE_FORMAT + ", committed real: " SIZE_FORMAT " expected: " SIZE_FORMAT + ", node count real: " SIZE_FORMAT " expected: " SIZE_FORMAT ".", + reserved, reserved_words(), committed, committed_words(), + node_count, _virtual_space_count); +} +#endif // ASSERT + } // namespace metaspace diff --git a/src/hotspot/share/memory/metaspace/virtualSpaceList.hpp b/src/hotspot/share/memory/metaspace/virtualSpaceList.hpp index 5c55eed4b2c..937d2dcdb31 100644 --- a/src/hotspot/share/memory/metaspace/virtualSpaceList.hpp +++ b/src/hotspot/share/memory/metaspace/virtualSpaceList.hpp @@ -58,6 +58,19 @@ class VirtualSpaceList : public CHeapObj { // Number of virtual spaces size_t _virtual_space_count; + // Optimization: we keep an address range to quickly exclude pointers + // which are clearly not pointing into metaspace. This is an optimization for + // VirtualSpaceList::contains(). + address _envelope_lo; + address _envelope_hi; + + bool is_within_envelope(address p) const { + return p >= _envelope_lo && p < _envelope_hi; + } + + // Given a node, expand range such that it includes the node. + void expand_envelope_to_include_node(const VirtualSpaceNode* node); + ~VirtualSpaceList(); VirtualSpaceNode* virtual_space_list() const { return _virtual_space_list; } @@ -80,6 +93,8 @@ class VirtualSpaceList : public CHeapObj { // virtual space and add the chunks to the free list. void retire_current_virtual_space(); + DEBUG_ONLY(bool contains_node(const VirtualSpaceNode* node) const;) + public: VirtualSpaceList(size_t word_size); VirtualSpaceList(ReservedSpace rs); @@ -126,6 +141,8 @@ class VirtualSpaceList : public CHeapObj { void print_on(outputStream* st, size_t scale) const; void print_map(outputStream* st) const; + DEBUG_ONLY(void verify(bool slow);) + class VirtualSpaceListIterator : public StackObj { VirtualSpaceNode* _virtual_spaces; public: diff --git a/src/hotspot/share/memory/metaspace/virtualSpaceNode.hpp b/src/hotspot/share/memory/metaspace/virtualSpaceNode.hpp index fcf5dcda395..c8fbdaa431d 100644 --- a/src/hotspot/share/memory/metaspace/virtualSpaceNode.hpp +++ b/src/hotspot/share/memory/metaspace/virtualSpaceNode.hpp @@ -60,6 +60,8 @@ class VirtualSpaceNode : public CHeapObj { // Convenience functions to access the _virtual_space char* low() const { return virtual_space()->low(); } char* high() const { return virtual_space()->high(); } + char* low_boundary() const { return virtual_space()->low_boundary(); } + char* high_boundary() const { return virtual_space()->high_boundary(); } // The first Metachunk will be allocated at the bottom of the // VirtualSpace diff --git a/src/hotspot/share/oops/instanceKlass.cpp b/src/hotspot/share/oops/instanceKlass.cpp index 5d802f4bf77..741cdf76fb9 100644 --- a/src/hotspot/share/oops/instanceKlass.cpp +++ b/src/hotspot/share/oops/instanceKlass.cpp @@ -3104,7 +3104,7 @@ static void print_vtable(intptr_t* start, int len, outputStream* st) { for (int i = 0; i < len; i++) { intptr_t e = start[i]; st->print("%d : " INTPTR_FORMAT, i, e); - if (e != 0 && ((Metadata*)e)->is_metaspace_object()) { + if (MetaspaceObj::is_valid((Metadata*)e)) { st->print(" "); ((Metadata*)e)->print_value_on(st); } diff --git a/test/hotspot/gtest/memory/test_is_metaspace_obj.cpp b/test/hotspot/gtest/memory/test_is_metaspace_obj.cpp new file mode 100644 index 00000000000..cfe84141525 --- /dev/null +++ b/test/hotspot/gtest/memory/test_is_metaspace_obj.cpp @@ -0,0 +1,115 @@ +/* + * Copyright (c) 2016, 2018 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 "memory/allocation.inline.hpp" +#include "memory/metaspace.hpp" +#include "memory/metaspace/virtualSpaceList.hpp" +#include "runtime/mutex.hpp" +#include "runtime/mutexLocker.hpp" +#include "runtime/os.hpp" +#include "unittest.hpp" + +using namespace metaspace; + + +// Test the cheerful multitude of metaspace-contains-functions. +class MetaspaceIsMetaspaceObjTest : public ::testing::Test { + Mutex* _lock; + ClassLoaderMetaspace* _ms; + +public: + + MetaspaceIsMetaspaceObjTest() : _lock(NULL), _ms(NULL) {} + + virtual void SetUp() { + } + + virtual void TearDown() { + delete _ms; + delete _lock; + } + + void do_test(Metaspace::MetadataType mdType) { + _lock = new Mutex(Monitor::native, "gtest-IsMetaspaceObjTest-lock", false, Monitor::_safepoint_check_never); + { + MutexLockerEx ml(_lock, Mutex::_no_safepoint_check_flag); + _ms = new ClassLoaderMetaspace(_lock, Metaspace::StandardMetaspaceType); + } + + const MetaspaceObj* p = (MetaspaceObj*) _ms->allocate(42, mdType); + + // Test MetaspaceObj::is_metaspace_object + ASSERT_TRUE(MetaspaceObj::is_valid(p)); + + // A misaligned object shall not be recognized + const MetaspaceObj* p_misaligned = (MetaspaceObj*)((address)p) + 1; + ASSERT_FALSE(MetaspaceObj::is_valid(p_misaligned)); + + // Test VirtualSpaceList::contains and find_enclosing_space + VirtualSpaceList* list = Metaspace::space_list(); + if (mdType == Metaspace::ClassType && Metaspace::using_class_space()) { + list = Metaspace::class_space_list(); + } + ASSERT_TRUE(list->contains(p)); + VirtualSpaceNode* const n = list->find_enclosing_space(p); + ASSERT_TRUE(n != NULL); + ASSERT_TRUE(n->contains(p)); + + // A misaligned pointer shall be recognized by list::contains + ASSERT_TRUE(list->contains((address)p) + 1); + + // Now for some bogus values + ASSERT_FALSE(MetaspaceObj::is_valid((MetaspaceObj*)NULL)); + + // Should exercise various paths in MetaspaceObj::is_valid() + ASSERT_FALSE(MetaspaceObj::is_valid((MetaspaceObj*)1024)); + ASSERT_FALSE(MetaspaceObj::is_valid((MetaspaceObj*)8192)); + + MetaspaceObj* p_stack = (MetaspaceObj*) &_lock; + ASSERT_FALSE(MetaspaceObj::is_valid(p_stack)); + + MetaspaceObj* p_heap = (MetaspaceObj*) os::malloc(41, mtInternal); + ASSERT_FALSE(MetaspaceObj::is_valid(p_heap)); + os::free(p_heap); + + // Test Metaspace::contains_xxx + ASSERT_TRUE(Metaspace::contains(p)); + ASSERT_TRUE(Metaspace::contains_non_shared(p)); + + delete _ms; + _ms = NULL; + delete _lock; + _lock = NULL; + } + +}; + +TEST_VM_F(MetaspaceIsMetaspaceObjTest, non_class_space) { + do_test(Metaspace::NonClassType); +} + +TEST_VM_F(MetaspaceIsMetaspaceObjTest, class_space) { + do_test(Metaspace::ClassType); +} + From 7a093bcf507fcd2fc5d1ee21b0807d5419fdeb6a Mon Sep 17 00:00:00 2001 From: Gary Adams Date: Fri, 5 Apr 2019 07:10:07 -0400 Subject: [PATCH 28/73] 8203364: Some serviceability/sa/ tests intermittently fail with java.io.IOException: LingeredApp terminated with non-zero exit code 3 Reviewed-by: cjplummer, jcbeyler --- test/lib/jdk/test/lib/apps/LingeredApp.java | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/test/lib/jdk/test/lib/apps/LingeredApp.java b/test/lib/jdk/test/lib/apps/LingeredApp.java index 3be74e56908..e96993032db 100644 --- a/test/lib/jdk/test/lib/apps/LingeredApp.java +++ b/test/lib/jdk/test/lib/apps/LingeredApp.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2019, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -492,18 +492,22 @@ public class LingeredApp { } String theLockFileName = args[0]; + Path path = Paths.get(theLockFileName); try { - Path path = Paths.get(theLockFileName); - while (Files.exists(path)) { // Touch the lock to indicate our readiness setLastModified(theLockFileName, epoch()); Thread.sleep(spinDelay); } - } catch (NoSuchFileException ex) { + } catch (IOException ex) { // Lock deleted while we are setting last modified time. - // Ignore error and lets the app exits + // Ignore the error and let the app exit. + if (Files.exists(path)) { + // If the lock file was not removed, return an error. + System.err.println("LingeredApp IOException: lock file still exists"); + System.exit(4); + } } catch (Exception ex) { System.err.println("LingeredApp ERROR: " + ex); // Leave exit_code = 1 to Java launcher From 71164a973b42acb0c7798945e5a5e58c8e759420 Mon Sep 17 00:00:00 2001 From: Andrew Dinn Date: Fri, 5 Apr 2019 10:01:09 +0100 Subject: [PATCH 29/73] 8221477: Inject os/cpu-specific constants into Unsafe from JVM Initialize Unsafe os/cpu-specific constants using injection instead of native callouts Reviewed-by: stuefe, coleenp, dholmes, plevart --- src/hotspot/share/classfile/javaClasses.cpp | 44 +++++++- src/hotspot/share/classfile/javaClasses.hpp | 10 ++ .../share/classfile/systemDictionary.hpp | 1 + src/hotspot/share/classfile/vmSymbols.hpp | 7 ++ src/hotspot/share/prims/unsafe.cpp | 25 ----- src/hotspot/share/runtime/thread.cpp | 10 ++ .../classes/jdk/internal/misc/Unsafe.java | 40 +++---- .../jdk/internal/misc/UnsafeConstants.java | 103 ++++++++++++++++++ .../AccessibleObject/CanAccessTest.java | 2 +- 9 files changed, 190 insertions(+), 52 deletions(-) create mode 100644 src/java.base/share/classes/jdk/internal/misc/UnsafeConstants.java diff --git a/src/hotspot/share/classfile/javaClasses.cpp b/src/hotspot/share/classfile/javaClasses.cpp index d76751f1bef..193fed590ba 100644 --- a/src/hotspot/share/classfile/javaClasses.cpp +++ b/src/hotspot/share/classfile/javaClasses.cpp @@ -218,7 +218,7 @@ public: void java_lang_String::set_compact_strings(bool value) { CompactStringsFixup fix(value); - InstanceKlass::cast(SystemDictionary::String_klass())->do_local_static_fields(&fix); + SystemDictionary::String_klass()->do_local_static_fields(&fix); } Handle java_lang_String::basic_create(int length, bool is_latin1, TRAPS) { @@ -3991,6 +3991,48 @@ int java_lang_System::in_offset_in_bytes() { return static_in_offset; } int java_lang_System::out_offset_in_bytes() { return static_out_offset; } int java_lang_System::err_offset_in_bytes() { return static_err_offset; } +// Support for jdk_internal_misc_UnsafeConstants +// +class UnsafeConstantsFixup : public FieldClosure { +private: + int _address_size; + int _page_size; + bool _big_endian; + bool _use_unaligned_access; +public: + UnsafeConstantsFixup() { + // round up values for all static final fields + _address_size = sizeof(void*); + _page_size = os::vm_page_size(); + _big_endian = LITTLE_ENDIAN_ONLY(false) BIG_ENDIAN_ONLY(true); + _use_unaligned_access = UseUnalignedAccesses; + } + + void do_field(fieldDescriptor* fd) { + oop mirror = fd->field_holder()->java_mirror(); + assert(mirror != NULL, "UnsafeConstants must have mirror already"); + assert(fd->field_holder() == SystemDictionary::UnsafeConstants_klass(), "Should be UnsafeConstants"); + assert(fd->is_final(), "fields of UnsafeConstants must be final"); + assert(fd->is_static(), "fields of UnsafeConstants must be static"); + if (fd->name() == vmSymbols::address_size_name()) { + mirror->int_field_put(fd->offset(), _address_size); + } else if (fd->name() == vmSymbols::page_size_name()) { + mirror->int_field_put(fd->offset(), _page_size); + } else if (fd->name() == vmSymbols::big_endian_name()) { + mirror->bool_field_put(fd->offset(), _big_endian); + } else if (fd->name() == vmSymbols::use_unaligned_access_name()) { + mirror->bool_field_put(fd->offset(), _use_unaligned_access); + } else { + assert(false, "unexpected UnsafeConstants field"); + } + } +}; + +void jdk_internal_misc_UnsafeConstants::set_unsafe_constants() { + UnsafeConstantsFixup fixup; + SystemDictionary::UnsafeConstants_klass()->do_local_static_fields(&fixup); +} + int java_lang_Class::_klass_offset; int java_lang_Class::_array_klass_offset; int java_lang_Class::_oop_size_offset; diff --git a/src/hotspot/share/classfile/javaClasses.hpp b/src/hotspot/share/classfile/javaClasses.hpp index df164ce4f9c..b7682befc29 100644 --- a/src/hotspot/share/classfile/javaClasses.hpp +++ b/src/hotspot/share/classfile/javaClasses.hpp @@ -81,6 +81,7 @@ f(java_lang_StackFrameInfo) \ f(java_lang_LiveStackFrameInfo) \ f(java_util_concurrent_locks_AbstractOwnableSynchronizer) \ + f(jdk_internal_misc_UnsafeConstants) \ //end #define BASIC_JAVA_CLASSES_DO(f) \ @@ -1483,6 +1484,15 @@ class java_util_concurrent_locks_AbstractOwnableSynchronizer : AllStatic { static void serialize_offsets(SerializeClosure* f) NOT_CDS_RETURN; }; + // Interface to jdk.internal.misc.UnsafeConsants + +class jdk_internal_misc_UnsafeConstants : AllStatic { + public: + static void set_unsafe_constants(); + static void compute_offsets() { } + static void serialize_offsets(SerializeClosure* f) { } +}; + // Use to declare fields that need to be injected into Java classes // for the JVM to use. The name_index and signature_index are // declared in vmSymbols. The may_be_java flag is used to declare diff --git a/src/hotspot/share/classfile/systemDictionary.hpp b/src/hotspot/share/classfile/systemDictionary.hpp index e62752fe1ed..a0879378310 100644 --- a/src/hotspot/share/classfile/systemDictionary.hpp +++ b/src/hotspot/share/classfile/systemDictionary.hpp @@ -177,6 +177,7 @@ class OopStorage; do_klass(AssertionStatusDirectives_klass, java_lang_AssertionStatusDirectives ) \ do_klass(StringBuffer_klass, java_lang_StringBuffer ) \ do_klass(StringBuilder_klass, java_lang_StringBuilder ) \ + do_klass(UnsafeConstants_klass, jdk_internal_misc_UnsafeConstants ) \ do_klass(internal_Unsafe_klass, jdk_internal_misc_Unsafe ) \ do_klass(module_Modules_klass, jdk_internal_module_Modules ) \ \ diff --git a/src/hotspot/share/classfile/vmSymbols.hpp b/src/hotspot/share/classfile/vmSymbols.hpp index c6d4c7fdb02..142ddf749a9 100644 --- a/src/hotspot/share/classfile/vmSymbols.hpp +++ b/src/hotspot/share/classfile/vmSymbols.hpp @@ -446,6 +446,10 @@ template(module_entry_name, "module_entry") \ template(resolved_references_name, "") \ template(init_lock_name, "") \ + template(address_size_name, "ADDRESS_SIZE0") \ + template(page_size_name, "PAGE_SIZE") \ + template(big_endian_name, "BIG_ENDIAN") \ + template(use_unaligned_access_name, "UNALIGNED_ACCESS") \ \ /* name symbols needed by intrinsics */ \ VM_INTRINSICS_DO(VM_INTRINSIC_IGNORE, VM_SYMBOL_IGNORE, template, VM_SYMBOL_IGNORE, VM_ALIAS_IGNORE) \ @@ -1070,6 +1074,9 @@ do_intrinsic(_updateByteBufferAdler32, java_util_zip_Adler32, updateByteBuffer_A_name, updateByteBuffer_signature, F_SN) \ do_name( updateByteBuffer_A_name, "updateByteBuffer") \ \ + /* support for UnsafeConstants */ \ + do_class(jdk_internal_misc_UnsafeConstants, "jdk/internal/misc/UnsafeConstants") \ + \ /* support for Unsafe */ \ do_class(jdk_internal_misc_Unsafe, "jdk/internal/misc/Unsafe") \ \ diff --git a/src/hotspot/share/prims/unsafe.cpp b/src/hotspot/share/prims/unsafe.cpp index 4f5404f5ca3..322f2ec95b8 100644 --- a/src/hotspot/share/prims/unsafe.cpp +++ b/src/hotspot/share/prims/unsafe.cpp @@ -292,18 +292,6 @@ UNSAFE_ENTRY(jobject, Unsafe_GetUncompressedObject(JNIEnv *env, jobject unsafe, return JNIHandles::make_local(env, v); } UNSAFE_END -UNSAFE_LEAF(jboolean, Unsafe_isBigEndian0(JNIEnv *env, jobject unsafe)) { -#ifdef VM_LITTLE_ENDIAN - return false; -#else - return true; -#endif -} UNSAFE_END - -UNSAFE_LEAF(jint, Unsafe_unalignedAccess0(JNIEnv *env, jobject unsafe)) { - return UseUnalignedAccesses; -} UNSAFE_END - #define DEFINE_GETSETOOP(java_type, Type) \ \ UNSAFE_ENTRY(java_type, Unsafe_Get##Type(JNIEnv *env, jobject unsafe, jobject obj, jlong offset)) { \ @@ -446,14 +434,6 @@ UNSAFE_LEAF(void, Unsafe_CopySwapMemory0(JNIEnv *env, jobject unsafe, jobject sr ////// Random queries -UNSAFE_LEAF(jint, Unsafe_AddressSize0(JNIEnv *env, jobject unsafe)) { - return sizeof(void*); -} UNSAFE_END - -UNSAFE_LEAF(jint, Unsafe_PageSize()) { - return os::vm_page_size(); -} UNSAFE_END - static jlong find_field_offset(jclass clazz, jstring name, TRAPS) { assert(clazz != NULL, "clazz must not be NULL"); assert(name != NULL, "name must not be NULL"); @@ -1073,8 +1053,6 @@ static JNINativeMethod jdk_internal_misc_Unsafe_methods[] = { {CC "ensureClassInitialized0", CC "(" CLS ")V", FN_PTR(Unsafe_EnsureClassInitialized0)}, {CC "arrayBaseOffset0", CC "(" CLS ")I", FN_PTR(Unsafe_ArrayBaseOffset0)}, {CC "arrayIndexScale0", CC "(" CLS ")I", FN_PTR(Unsafe_ArrayIndexScale0)}, - {CC "addressSize0", CC "()I", FN_PTR(Unsafe_AddressSize0)}, - {CC "pageSize", CC "()I", FN_PTR(Unsafe_PageSize)}, {CC "defineClass0", CC "(" DC_Args ")" CLS, FN_PTR(Unsafe_DefineClass0)}, {CC "allocateInstance", CC "(" CLS ")" OBJ, FN_PTR(Unsafe_AllocateInstance)}, @@ -1102,9 +1080,6 @@ static JNINativeMethod jdk_internal_misc_Unsafe_methods[] = { {CC "loadFence", CC "()V", FN_PTR(Unsafe_LoadFence)}, {CC "storeFence", CC "()V", FN_PTR(Unsafe_StoreFence)}, {CC "fullFence", CC "()V", FN_PTR(Unsafe_FullFence)}, - - {CC "isBigEndian0", CC "()Z", FN_PTR(Unsafe_isBigEndian0)}, - {CC "unalignedAccess0", CC "()Z", FN_PTR(Unsafe_unalignedAccess0)} }; #undef CC diff --git a/src/hotspot/share/runtime/thread.cpp b/src/hotspot/share/runtime/thread.cpp index 385ea67276d..c8932ea2c9e 100644 --- a/src/hotspot/share/runtime/thread.cpp +++ b/src/hotspot/share/runtime/thread.cpp @@ -3628,6 +3628,7 @@ void Threads::initialize_java_lang_classes(JavaThread* main_thread, TRAPS) { initialize_class(vmSymbols::java_lang_Thread(), CHECK); oop thread_object = create_initial_thread(thread_group, main_thread, CHECK); main_thread->set_threadObj(thread_object); + // Set thread status to running since main thread has // been started and running. java_lang_Thread::set_thread_status(thread_object, @@ -3636,6 +3637,15 @@ void Threads::initialize_java_lang_classes(JavaThread* main_thread, TRAPS) { // The VM creates objects of this class. initialize_class(vmSymbols::java_lang_Module(), CHECK); +#ifdef ASSERT + InstanceKlass *k = SystemDictionary::UnsafeConstants_klass(); + assert(k->is_not_initialized(), "UnsafeConstants should not already be initialized"); +#endif + + // initialize the hardware-specific constants needed by Unsafe + initialize_class(vmSymbols::jdk_internal_misc_UnsafeConstants(), CHECK); + jdk_internal_misc_UnsafeConstants::set_unsafe_constants(); + // The VM preresolves methods to these classes. Make sure that they get initialized initialize_class(vmSymbols::java_lang_reflect_Method(), CHECK); initialize_class(vmSymbols::java_lang_ref_Finalizer(), CHECK); diff --git a/src/java.base/share/classes/jdk/internal/misc/Unsafe.java b/src/java.base/share/classes/jdk/internal/misc/Unsafe.java index 8b444aee948..c88fdaeaf38 100644 --- a/src/java.base/share/classes/jdk/internal/misc/Unsafe.java +++ b/src/java.base/share/classes/jdk/internal/misc/Unsafe.java @@ -33,6 +33,7 @@ import sun.nio.ch.DirectBuffer; import java.lang.reflect.Field; import java.security.ProtectionDomain; +import static jdk.internal.misc.UnsafeConstants.*; /** * A collection of methods for performing low-level, unsafe operations. @@ -1166,14 +1167,13 @@ public final class Unsafe { } /** The value of {@code addressSize()} */ - public static final int ADDRESS_SIZE = theUnsafe.addressSize0(); + public static final int ADDRESS_SIZE = ADDRESS_SIZE0; /** * Reports the size in bytes of a native memory page (whatever that is). * This value will always be a power of two. */ - public native int pageSize(); - + public int pageSize() { return PAGE_SIZE; } /// random trusted operations from JNI: @@ -1417,7 +1417,7 @@ public final class Unsafe { byte x) { long wordOffset = offset & ~3; int shift = (int) (offset & 3) << 3; - if (BE) { + if (BIG_ENDIAN) { shift = 24 - shift; } int mask = 0xFF << shift; @@ -1491,7 +1491,7 @@ public final class Unsafe { } long wordOffset = offset & ~3; int shift = (int) (offset & 3) << 3; - if (BE) { + if (BIG_ENDIAN) { shift = 16 - shift; } int mask = 0xFFFF << shift; @@ -3354,14 +3354,14 @@ public final class Unsafe { * @return Returns true if the native byte ordering of this * platform is big-endian, false if it is little-endian. */ - public final boolean isBigEndian() { return BE; } + public final boolean isBigEndian() { return BIG_ENDIAN; } /** * @return Returns true if this platform is capable of performing * accesses at addresses which are not aligned for the type of the * primitive type being accessed, false otherwise. */ - public final boolean unalignedAccess() { return unalignedAccess; } + public final boolean unalignedAccess() { return UNALIGNED_ACCESS; } /** * Fetches a value at some byte offset into a given Java object. @@ -3603,14 +3603,7 @@ public final class Unsafe { putCharUnaligned(o, offset, convEndian(bigEndian, x)); } - // JVM interface methods - // BE is true iff the native endianness of this platform is big. - private static final boolean BE = theUnsafe.isBigEndian0(); - - // unalignedAccess is true iff this platform can perform unaligned accesses. - private static final boolean unalignedAccess = theUnsafe.unalignedAccess0(); - - private static int pickPos(int top, int pos) { return BE ? top - pos : pos; } + private static int pickPos(int top, int pos) { return BIG_ENDIAN ? top - pos : pos; } // These methods construct integers from bytes. The byte ordering // is the native endianness of this platform. @@ -3649,9 +3642,9 @@ public final class Unsafe { | (toUnsignedInt(i1) << pickPos(8, 8))); } - private static byte pick(byte le, byte be) { return BE ? be : le; } - private static short pick(short le, short be) { return BE ? be : le; } - private static int pick(int le, int be) { return BE ? be : le; } + private static byte pick(byte le, byte be) { return BIG_ENDIAN ? be : le; } + private static short pick(short le, short be) { return BIG_ENDIAN ? be : le; } + private static int pick(int le, int be) { return BIG_ENDIAN ? be : le; } // These methods write integers to memory from smaller parts // provided by their caller. The ordering in which these parts @@ -3699,10 +3692,10 @@ public final class Unsafe { private static long toUnsignedLong(int n) { return n & 0xffffffffl; } // Maybe byte-reverse an integer - private static char convEndian(boolean big, char n) { return big == BE ? n : Character.reverseBytes(n); } - private static short convEndian(boolean big, short n) { return big == BE ? n : Short.reverseBytes(n) ; } - private static int convEndian(boolean big, int n) { return big == BE ? n : Integer.reverseBytes(n) ; } - private static long convEndian(boolean big, long n) { return big == BE ? n : Long.reverseBytes(n) ; } + private static char convEndian(boolean big, char n) { return big == BIG_ENDIAN ? n : Character.reverseBytes(n); } + private static short convEndian(boolean big, short n) { return big == BIG_ENDIAN ? n : Short.reverseBytes(n) ; } + private static int convEndian(boolean big, int n) { return big == BIG_ENDIAN ? n : Integer.reverseBytes(n) ; } + private static long convEndian(boolean big, long n) { return big == BIG_ENDIAN ? n : Long.reverseBytes(n) ; } @@ -3721,11 +3714,8 @@ public final class Unsafe { private native void ensureClassInitialized0(Class c); private native int arrayBaseOffset0(Class arrayClass); private native int arrayIndexScale0(Class arrayClass); - private native int addressSize0(); private native Class defineAnonymousClass0(Class hostClass, byte[] data, Object[] cpPatches); private native int getLoadAverage0(double[] loadavg, int nelems); - private native boolean unalignedAccess0(); - private native boolean isBigEndian0(); /** diff --git a/src/java.base/share/classes/jdk/internal/misc/UnsafeConstants.java b/src/java.base/share/classes/jdk/internal/misc/UnsafeConstants.java new file mode 100644 index 00000000000..f2475f70e43 --- /dev/null +++ b/src/java.base/share/classes/jdk/internal/misc/UnsafeConstants.java @@ -0,0 +1,103 @@ +/* + * Copyright (c) 2019, Red Hat Inc. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.internal.misc; + +/** + * A class used to expose details of the underlying hardware that + * configure the operation of class Unsafe. This class is + * package-private as the only intended client is class Unsafe. + * All fields in this class must be static final constants. + * + * @since 13 + * + * @implNote + * + * The JVM injects hardware-specific values into all the static fields + * of this class during JVM initialization. The static initialization + * block is executed when the class is initialized then JVM injection + * updates the fields with the correct constants. The static block + * is required to prevent the fields from being considered constant + * variables, so the field values will be not be compiled directly into + * any class that uses them. + */ + +final class UnsafeConstants { + + /** + * This constructor is private because the class is not meant to + * be instantiated. + */ + private UnsafeConstants() {} + + /** + * The size in bytes of a native pointer, as stored via {@link + * #putAddress}. This value will be either 4 or 8. Note that the + * sizes of other primitive types (as stored in native memory + * blocks) is determined fully by their information content. + * + * @implNote + * The actual value for this field is injected by the JVM. + */ + + static final int ADDRESS_SIZE0; + + /** + * The size in bytes of a native memory page (whatever that is). + * This value will always be a power of two. + * + * @implNote + * The actual value for this field is injected by the JVM. + */ + + static final int PAGE_SIZE; + + /** + * Flag whose value is true if and only if the native endianness + * of this platform is big. + * + * @implNote + * The actual value for this field is injected by the JVM. + */ + + static final boolean BIG_ENDIAN; + + /** + * Flag whose value is true if and only if the platform can + * perform unaligned accesses + * + * @implNote + * The actual value for this field is injected by the JVM. + */ + + static final boolean UNALIGNED_ACCESS; + + static { + ADDRESS_SIZE0 = 0; + PAGE_SIZE = 0; + BIG_ENDIAN = false; + UNALIGNED_ACCESS = false; + } +} diff --git a/test/jdk/java/lang/reflect/AccessibleObject/CanAccessTest.java b/test/jdk/java/lang/reflect/AccessibleObject/CanAccessTest.java index ba641215b05..6bf93f1312e 100644 --- a/test/jdk/java/lang/reflect/AccessibleObject/CanAccessTest.java +++ b/test/jdk/java/lang/reflect/AccessibleObject/CanAccessTest.java @@ -94,7 +94,7 @@ public class CanAccessTest { * for instance members */ public void testInstanceMethod() throws Exception { - Method m = Unsafe.class.getDeclaredMethod("addressSize0"); + Method m = Unsafe.class.getDeclaredMethod("allocateMemory0", long.class); assertFalse(m.canAccess(INSTANCE)); try { From 79218415bcff5807b33c60a7e066bf9dbb5feb9b Mon Sep 17 00:00:00 2001 From: Andrew Haley Date: Fri, 5 Apr 2019 09:53:07 -0400 Subject: [PATCH 30/73] 8219993: AArch64: Compiled CI stubs are unsafely modified Reviewed-by: adinn --- .../cpu/aarch64/c1_LIRAssembler_aarch64.cpp | 8 +++--- .../cpu/aarch64/c1_LIRAssembler_aarch64.hpp | 4 ++- .../cpu/aarch64/compiledIC_aarch64.cpp | 28 +++++++++++-------- .../cpu/aarch64/macroAssembler_aarch64.cpp | 12 ++++++++ .../cpu/aarch64/macroAssembler_aarch64.hpp | 1 + .../cpu/aarch64/nativeInst_aarch64.cpp | 6 +++- 6 files changed, 41 insertions(+), 18 deletions(-) diff --git a/src/hotspot/cpu/aarch64/c1_LIRAssembler_aarch64.cpp b/src/hotspot/cpu/aarch64/c1_LIRAssembler_aarch64.cpp index 17480052d43..7febbe72eee 100644 --- a/src/hotspot/cpu/aarch64/c1_LIRAssembler_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/c1_LIRAssembler_aarch64.cpp @@ -34,6 +34,7 @@ #include "c1/c1_ValueStack.hpp" #include "ci/ciArrayKlass.hpp" #include "ci/ciInstance.hpp" +#include "code/compiledIC.hpp" #include "gc/shared/barrierSet.hpp" #include "gc/shared/cardTableBarrierSet.hpp" #include "gc/shared/collectedHeap.hpp" @@ -2063,11 +2064,10 @@ void LIR_Assembler::emit_static_call_stub() { int start = __ offset(); __ relocate(static_stub_Relocation::spec(call_pc)); - __ mov_metadata(rmethod, (Metadata*)NULL); - __ movptr(rscratch1, 0); - __ br(rscratch1); + __ emit_static_call_stub(); - assert(__ offset() - start <= call_stub_size(), "stub too big"); + assert(__ offset() - start + CompiledStaticCall::to_trampoline_stub_size() + <= call_stub_size(), "stub too big"); __ end_a_stub(); } diff --git a/src/hotspot/cpu/aarch64/c1_LIRAssembler_aarch64.hpp b/src/hotspot/cpu/aarch64/c1_LIRAssembler_aarch64.hpp index 3f577251b76..8e663ba270f 100644 --- a/src/hotspot/cpu/aarch64/c1_LIRAssembler_aarch64.hpp +++ b/src/hotspot/cpu/aarch64/c1_LIRAssembler_aarch64.hpp @@ -69,7 +69,9 @@ friend class ArrayCopyStub; void deoptimize_trap(CodeEmitInfo *info); enum { - _call_stub_size = 12 * NativeInstruction::instruction_size, + // call stub: CompiledStaticCall::to_interp_stub_size() + + // CompiledStaticCall::to_trampoline_stub_size() + _call_stub_size = 13 * NativeInstruction::instruction_size, _call_aot_stub_size = 0, _exception_handler_size = DEBUG_ONLY(1*K) NOT_DEBUG(175), _deopt_handler_size = 7 * NativeInstruction::instruction_size diff --git a/src/hotspot/cpu/aarch64/compiledIC_aarch64.cpp b/src/hotspot/cpu/aarch64/compiledIC_aarch64.cpp index ca3cc39a0be..5b1e2dad4eb 100644 --- a/src/hotspot/cpu/aarch64/compiledIC_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/compiledIC_aarch64.cpp @@ -61,14 +61,14 @@ address CompiledStaticCall::emit_to_interp_stub(CodeBuffer &cbuf, address mark) // Don't create a Metadata reloc if we're generating immutable PIC. if (cbuf.immutable_PIC()) { __ movptr(rmethod, 0); - } else { - __ mov_metadata(rmethod, (Metadata*)NULL); - } -#else - __ mov_metadata(rmethod, (Metadata*)NULL); + __ movptr(rscratch1, 0); + __ br(rscratch1); + + } else #endif - __ movptr(rscratch1, 0); - __ br(rscratch1); + { + __ emit_static_call_stub(); + } assert((__ offset() - offset) <= (int)to_interp_stub_size(), "stub too big"); __ end_a_stub(); @@ -77,7 +77,8 @@ address CompiledStaticCall::emit_to_interp_stub(CodeBuffer &cbuf, address mark) #undef __ int CompiledStaticCall::to_interp_stub_size() { - return 7 * NativeInstruction::instruction_size; + // isb; movk; movz; movz; movk; movz; movz; br + return 8 * NativeInstruction::instruction_size; } int CompiledStaticCall::to_trampoline_stub_size() { @@ -159,7 +160,8 @@ void CompiledDirectStaticCall::set_to_interpreted(const methodHandle& callee, ad } // Creation also verifies the object. - NativeMovConstReg* method_holder = nativeMovConstReg_at(stub); + NativeMovConstReg* method_holder + = nativeMovConstReg_at(stub + NativeInstruction::instruction_size); #ifndef PRODUCT NativeGeneralJump* jump = nativeGeneralJump_at(method_holder->next_instruction_address()); @@ -184,7 +186,8 @@ void CompiledDirectStaticCall::set_stub_to_clean(static_stub_Relocation* static_ assert(stub != NULL, "stub not found"); assert(CompiledICLocker::is_safe(stub), "mt unsafe call"); // Creation also verifies the object. - NativeMovConstReg* method_holder = nativeMovConstReg_at(stub); + NativeMovConstReg* method_holder + = nativeMovConstReg_at(stub + NativeInstruction::instruction_size); method_holder->set_data(0); } @@ -201,8 +204,9 @@ void CompiledDirectStaticCall::verify() { address stub = find_stub(false /* is_aot */); assert(stub != NULL, "no stub found for static call"); // Creation also verifies the object. - NativeMovConstReg* method_holder = nativeMovConstReg_at(stub); - NativeJump* jump = nativeJump_at(method_holder->next_instruction_address()); + NativeMovConstReg* method_holder + = nativeMovConstReg_at(stub + NativeInstruction::instruction_size); + NativeJump* jump = nativeJump_at(method_holder->next_instruction_address()); // Verify state. assert(is_clean() || is_call_to_compiled() || is_call_to_interpreted(), "sanity check"); diff --git a/src/hotspot/cpu/aarch64/macroAssembler_aarch64.cpp b/src/hotspot/cpu/aarch64/macroAssembler_aarch64.cpp index f5130b23a89..e617b2d7c4e 100644 --- a/src/hotspot/cpu/aarch64/macroAssembler_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/macroAssembler_aarch64.cpp @@ -812,6 +812,18 @@ address MacroAssembler::emit_trampoline_stub(int insts_call_instruction_offset, return stub_start_addr; } +void MacroAssembler::emit_static_call_stub() { + // CompiledDirectStaticCall::set_to_interpreted knows the + // exact layout of this stub. + + isb(); + mov_metadata(rmethod, (Metadata*)NULL); + + // Jump to the entry point of the i2c stub. + movptr(rscratch1, 0); + br(rscratch1); +} + void MacroAssembler::c2bool(Register x) { // implements x == 0 ? 0 : 1 // note: must only look at least-significant byte of x diff --git a/src/hotspot/cpu/aarch64/macroAssembler_aarch64.hpp b/src/hotspot/cpu/aarch64/macroAssembler_aarch64.hpp index 7b9f62f554b..9cae321a2da 100644 --- a/src/hotspot/cpu/aarch64/macroAssembler_aarch64.hpp +++ b/src/hotspot/cpu/aarch64/macroAssembler_aarch64.hpp @@ -607,6 +607,7 @@ public: static int patch_narrow_klass(address insn_addr, narrowKlass n); address emit_trampoline_stub(int insts_call_instruction_offset, address target); + void emit_static_call_stub(); // The following 4 methods return the offset of the appropriate move instruction diff --git a/src/hotspot/cpu/aarch64/nativeInst_aarch64.cpp b/src/hotspot/cpu/aarch64/nativeInst_aarch64.cpp index 668795050ea..4cf08059a67 100644 --- a/src/hotspot/cpu/aarch64/nativeInst_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/nativeInst_aarch64.cpp @@ -232,7 +232,11 @@ void NativeCall::insert(address code_pos, address entry) { Unimplemented(); } //------------------------------------------------------------------- void NativeMovConstReg::verify() { - // make sure code pattern is actually mov reg64, imm64 instructions + if (! (nativeInstruction_at(instruction_address())->is_movz() || + is_adrp_at(instruction_address()) || + is_ldr_literal_at(instruction_address())) ) { + fatal("should be MOVZ or ADRP or LDR (literal)"); + } } From 049c57493303706a7fc58707f1c6b3f27ba7ec15 Mon Sep 17 00:00:00 2001 From: Brian Burkhalter Date: Fri, 5 Apr 2019 08:37:33 -0700 Subject: [PATCH 31/73] 8221597: A typo in the Java API doc for File.getUsableSpace() Reviewed-by: lancea, darcy --- src/java.base/share/classes/java/io/File.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/java.base/share/classes/java/io/File.java b/src/java.base/share/classes/java/io/File.java index c5d67f42cf2..c242cd9ec7f 100644 --- a/src/java.base/share/classes/java/io/File.java +++ b/src/java.base/share/classes/java/io/File.java @@ -1869,7 +1869,7 @@ public class File * *

The returned number of available bytes is a hint, but not a * guarantee, that it is possible to use most or any of these bytes. The - * number of unallocated bytes is most likely to be accurate immediately + * number of available bytes is most likely to be accurate immediately * after this call. It is likely to be made inaccurate by any external * I/O operations including those made on the system outside of this * virtual machine. This method makes no guarantee that write operations From 6d617481d4f852ecf017b99317c6e2221bd84336 Mon Sep 17 00:00:00 2001 From: Jonathan Gibbons Date: Fri, 5 Apr 2019 11:17:09 -0700 Subject: [PATCH 32/73] 8221997: fix headings in jdk.javadoc Reviewed-by: hannesw --- .../share/classes/jdk/javadoc/doclet/package-info.java | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/doclet/package-info.java b/src/jdk.javadoc/share/classes/jdk/javadoc/doclet/package-info.java index e4c7413684f..2e895024b93 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/doclet/package-info.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/doclet/package-info.java @@ -62,7 +62,7 @@ *

* * - *

Terminology

+ *

Terminology

* *
*
Selected
@@ -88,7 +88,7 @@ *
*

* - *

Options

+ *

Options

* Javadoc selection control can be specified with these options * as follows: *
    @@ -132,7 +132,7 @@ *
*

* - *

Interactions with older options.

+ *

Interactions with older options.

* * The new {@code --show-*} options provide a more detailed replacement * for the older options {@code -public}, {@code -protected}, {@code -package}, {@code -private}. @@ -181,7 +181,7 @@ *

* * - *

Example

+ *

Example

* * The following is an example doclet that displays information of a class * and its members, supporting an option. @@ -300,7 +300,7 @@ * source-location/Example.java * * - *

Migration Guide

+ *

Migration Guide

* *

Many of the types in the old {@code com.sun.javadoc} API do not have equivalents in this * package. Instead, types in the {@code javax.lang.model} and {@code com.sun.source} APIs From 8263b618ba54d3029bd65ccf7c4bbc67c0668591 Mon Sep 17 00:00:00 2001 From: Xue-Lei Andrew Fan Date: Fri, 5 Apr 2019 11:28:23 -0700 Subject: [PATCH 33/73] 8221882: Use fiber-friendly java.util.concurrent.locks in JSSE Reviewed-by: alanb, dfuchs --- .../classes/javax/net/ssl/SSLContext.java | 38 +- .../javax/net/ssl/SSLServerSocketFactory.java | 94 +-- .../javax/net/ssl/SSLSocketFactory.java | 99 +-- .../https/HttpsURLConnectionImpl.java | 14 +- .../sun/security/ssl/BaseSSLSocketImpl.java | 4 +- .../sun/security/ssl/DTLSInputRecord.java | 4 +- .../sun/security/ssl/DTLSOutputRecord.java | 19 +- .../sun/security/ssl/EphemeralKeyManager.java | 39 +- .../sun/security/ssl/HelloCookieManager.java | 42 +- .../classes/sun/security/ssl/InputRecord.java | 24 +- .../sun/security/ssl/OutputRecord.java | 168 +++-- .../sun/security/ssl/SSLContextImpl.java | 13 +- .../sun/security/ssl/SSLEngineImpl.java | 635 +++++++++++------- .../security/ssl/SSLEngineOutputRecord.java | 19 +- .../sun/security/ssl/SSLServerSocketImpl.java | 210 ++++-- .../sun/security/ssl/SSLSessionImpl.java | 223 +++--- .../sun/security/ssl/SSLSocketImpl.java | 422 ++++++++---- .../security/ssl/SSLSocketOutputRecord.java | 473 +++++++------ .../security/ssl/SunX509KeyManagerImpl.java | 22 +- .../sun/security/ssl/TransportContext.java | 12 +- .../sun/security/ssl/TrustStoreManager.java | 105 +-- .../security/ssl/X509TrustManagerImpl.java | 13 +- 22 files changed, 1672 insertions(+), 1020 deletions(-) diff --git a/src/java.base/share/classes/javax/net/ssl/SSLContext.java b/src/java.base/share/classes/javax/net/ssl/SSLContext.java index 5a1801e22c1..d7c7f6b4380 100644 --- a/src/java.base/share/classes/javax/net/ssl/SSLContext.java +++ b/src/java.base/share/classes/javax/net/ssl/SSLContext.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2019, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -26,8 +26,9 @@ package javax.net.ssl; import java.security.*; +import java.lang.invoke.MethodHandles; +import java.lang.invoke.VarHandle; import java.util.Objects; - import sun.security.jca.GetInstance; /** @@ -58,6 +59,20 @@ public class SSLContext { private final String protocol; + private static volatile SSLContext defaultContext; + + private static final VarHandle VH_DEFAULT_CONTEXT; + + static { + try { + VH_DEFAULT_CONTEXT = MethodHandles.lookup() + .findStaticVarHandle( + SSLContext.class, "defaultContext", SSLContext.class); + } catch (Exception e) { + throw new ExceptionInInitializerError(e); + } + } + /** * Creates an SSLContext object. * @@ -72,8 +87,6 @@ public class SSLContext { this.protocol = protocol; } - private static SSLContext defaultContext; - /** * Returns the default SSL context. * @@ -91,12 +104,16 @@ public class SSLContext { * {@link SSLContext#getInstance SSLContext.getInstance()} call fails * @since 1.6 */ - public static synchronized SSLContext getDefault() - throws NoSuchAlgorithmException { - if (defaultContext == null) { - defaultContext = SSLContext.getInstance("Default"); + public static SSLContext getDefault() throws NoSuchAlgorithmException { + SSLContext temporaryContext = defaultContext; + if (temporaryContext == null) { + temporaryContext = SSLContext.getInstance("Default"); + if (!VH_DEFAULT_CONTEXT.compareAndSet(null, temporaryContext)) { + temporaryContext = defaultContext; + } } - return defaultContext; + + return temporaryContext; } /** @@ -111,7 +128,7 @@ public class SSLContext { * {@code SSLPermission("setDefaultSSLContext")} * @since 1.6 */ - public static synchronized void setDefault(SSLContext context) { + public static void setDefault(SSLContext context) { if (context == null) { throw new NullPointerException(); } @@ -119,6 +136,7 @@ public class SSLContext { if (sm != null) { sm.checkPermission(new SSLPermission("setDefaultSSLContext")); } + defaultContext = context; } diff --git a/src/java.base/share/classes/javax/net/ssl/SSLServerSocketFactory.java b/src/java.base/share/classes/javax/net/ssl/SSLServerSocketFactory.java index ef384e60979..e66bd11239d 100644 --- a/src/java.base/share/classes/javax/net/ssl/SSLServerSocketFactory.java +++ b/src/java.base/share/classes/javax/net/ssl/SSLServerSocketFactory.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2019, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -42,17 +42,7 @@ import java.security.*; * @see SSLServerSocket * @author David Brownell */ -public abstract class SSLServerSocketFactory extends ServerSocketFactory -{ - private static SSLServerSocketFactory theFactory; - - private static boolean propertyChecked; - - private static void log(String msg) { - if (SSLSocketFactory.DEBUG) { - System.out.println(msg); - } - } +public abstract class SSLServerSocketFactory extends ServerSocketFactory { /** * Constructor is used only by subclasses. @@ -75,39 +65,9 @@ public abstract class SSLServerSocketFactory extends ServerSocketFactory * @return the default ServerSocketFactory * @see SSLContext#getDefault */ - public static synchronized ServerSocketFactory getDefault() { - if (theFactory != null) { - return theFactory; - } - - if (propertyChecked == false) { - propertyChecked = true; - String clsName = SSLSocketFactory.getSecurityProperty - ("ssl.ServerSocketFactory.provider"); - if (clsName != null) { - log("setting up default SSLServerSocketFactory"); - try { - Class cls = null; - try { - cls = Class.forName(clsName); - } catch (ClassNotFoundException e) { - ClassLoader cl = ClassLoader.getSystemClassLoader(); - if (cl != null) { - cls = cl.loadClass(clsName); - } - } - log("class " + clsName + " is loaded"); - @SuppressWarnings("deprecation") - SSLServerSocketFactory fac = (SSLServerSocketFactory)cls.newInstance(); - log("instantiated an instance of class " + clsName); - theFactory = fac; - return fac; - } catch (Exception e) { - log("SSLServerSocketFactory instantiation failed: " + e); - theFactory = new DefaultSSLServerSocketFactory(e); - return theFactory; - } - } + public static ServerSocketFactory getDefault() { + if (DefaultFactoryHolder.defaultFactory != null) { + return DefaultFactoryHolder.defaultFactory; } try { @@ -156,8 +116,50 @@ public abstract class SSLServerSocketFactory extends ServerSocketFactory * @see #getDefaultCipherSuites() */ public abstract String [] getSupportedCipherSuites(); -} + // lazy initialization holder class idiom for static default factory + // + // See Effective Java Second Edition: Item 71. + private static final class DefaultFactoryHolder { + private static final SSLServerSocketFactory defaultFactory; + + static { + SSLServerSocketFactory mediator = null; + String clsName = SSLSocketFactory.getSecurityProperty( + "ssl.ServerSocketFactory.provider"); + if (clsName != null) { + log("setting up default SSLServerSocketFactory"); + try { + Class cls = null; + try { + cls = Class.forName(clsName); + } catch (ClassNotFoundException e) { + ClassLoader cl = ClassLoader.getSystemClassLoader(); + if (cl != null) { + cls = cl.loadClass(clsName); + } + } + log("class " + clsName + " is loaded"); + + mediator = (SSLServerSocketFactory)cls + .getDeclaredConstructor().newInstance(); + log("instantiated an instance of class " + clsName); + } catch (Exception e) { + log("SSLServerSocketFactory instantiation failed: " + e); + mediator = new DefaultSSLServerSocketFactory(e); + } + } + + defaultFactory = mediator; + } + + private static void log(String msg) { + if (SSLSocketFactory.DEBUG) { + System.out.println(msg); + } + } + } +} // // The default factory does NOTHING. diff --git a/src/java.base/share/classes/javax/net/ssl/SSLSocketFactory.java b/src/java.base/share/classes/javax/net/ssl/SSLSocketFactory.java index 1115c48d8f3..4fae98e7bed 100644 --- a/src/java.base/share/classes/javax/net/ssl/SSLSocketFactory.java +++ b/src/java.base/share/classes/javax/net/ssl/SSLSocketFactory.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2019, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -42,31 +42,20 @@ import sun.security.action.GetPropertyAction; * @see SSLSocket * @author David Brownell */ -public abstract class SSLSocketFactory extends SocketFactory -{ - private static SSLSocketFactory theFactory; - - private static boolean propertyChecked; - +public abstract class SSLSocketFactory extends SocketFactory { static final boolean DEBUG; static { - String s = GetPropertyAction.privilegedGetProperty("javax.net.debug", "") - .toLowerCase(Locale.ENGLISH); - + String s = GetPropertyAction.privilegedGetProperty( + "javax.net.debug", "").toLowerCase(Locale.ENGLISH); DEBUG = s.contains("all") || s.contains("ssl"); } - private static void log(String msg) { - if (DEBUG) { - System.out.println(msg); - } - } - /** * Constructor is used only by subclasses. */ public SSLSocketFactory() { + // blank } /** @@ -85,38 +74,9 @@ public abstract class SSLSocketFactory extends SocketFactory * @return the default SocketFactory * @see SSLContext#getDefault */ - public static synchronized SocketFactory getDefault() { - if (theFactory != null) { - return theFactory; - } - - if (propertyChecked == false) { - propertyChecked = true; - String clsName = getSecurityProperty("ssl.SocketFactory.provider"); - if (clsName != null) { - log("setting up default SSLSocketFactory"); - try { - Class cls = null; - try { - cls = Class.forName(clsName); - } catch (ClassNotFoundException e) { - ClassLoader cl = ClassLoader.getSystemClassLoader(); - if (cl != null) { - cls = cl.loadClass(clsName); - } - } - log("class " + clsName + " is loaded"); - @SuppressWarnings("deprecation") - SSLSocketFactory fac = (SSLSocketFactory)cls.newInstance(); - log("instantiated an instance of class " + clsName); - theFactory = fac; - return fac; - } catch (Exception e) { - log("SSLSocketFactory instantiation failed: " + e.toString()); - theFactory = new DefaultSSLSocketFactory(e); - return theFactory; - } - } + public static SocketFactory getDefault() { + if (DefaultFactoryHolder.defaultFactory != null) { + return DefaultFactoryHolder.defaultFactory; } try { @@ -246,6 +206,49 @@ public abstract class SSLSocketFactory extends SocketFactory boolean autoClose) throws IOException { throw new UnsupportedOperationException(); } + + // lazy initialization holder class idiom for static default factory + // + // See Effective Java Second Edition: Item 71. + private static final class DefaultFactoryHolder { + private static final SSLSocketFactory defaultFactory; + + static { + SSLSocketFactory mediator = null; + String clsName = getSecurityProperty("ssl.SocketFactory.provider"); + if (clsName != null) { + log("setting up default SSLSocketFactory"); + try { + Class cls = null; + try { + cls = Class.forName(clsName); + } catch (ClassNotFoundException e) { + ClassLoader cl = ClassLoader.getSystemClassLoader(); + if (cl != null) { + cls = cl.loadClass(clsName); + } + } + log("class " + clsName + " is loaded"); + + mediator = (SSLSocketFactory)cls + .getDeclaredConstructor().newInstance(); + + log("instantiated an instance of class " + clsName); + } catch (Exception e) { + log("SSLSocketFactory instantiation failed: " + e); + mediator = new DefaultSSLSocketFactory(e); + } + } + + defaultFactory = mediator; + } + + private static void log(String msg) { + if (DEBUG) { + System.out.println(msg); + } + } + } } diff --git a/src/java.base/share/classes/sun/net/www/protocol/https/HttpsURLConnectionImpl.java b/src/java.base/share/classes/sun/net/www/protocol/https/HttpsURLConnectionImpl.java index 05b215c18ca..71c455d204d 100644 --- a/src/java.base/share/classes/sun/net/www/protocol/https/HttpsURLConnectionImpl.java +++ b/src/java.base/share/classes/sun/net/www/protocol/https/HttpsURLConnectionImpl.java @@ -57,8 +57,7 @@ import sun.net.www.http.HttpClient; public class HttpsURLConnectionImpl extends javax.net.ssl.HttpsURLConnection { - // NOTE: made protected for plugin so that subclass can set it. - protected DelegateHttpsURLConnection delegate; + private final DelegateHttpsURLConnection delegate; HttpsURLConnectionImpl(URL u, Handler handler) throws IOException { this(u, null, handler); @@ -78,13 +77,6 @@ public class HttpsURLConnectionImpl delegate = new DelegateHttpsURLConnection(url, p, handler, this); } - // NOTE: introduced for plugin - // subclass needs to overwrite this to set delegate to - // the appropriate delegatee - protected HttpsURLConnectionImpl(URL u) throws IOException { - super(u); - } - /** * Create a new HttpClient object, bypassing the cache of * HTTP client objects/connections. @@ -219,11 +211,11 @@ public class HttpsURLConnectionImpl * - get input, [read input,] get output, [write output] */ - public synchronized OutputStream getOutputStream() throws IOException { + public OutputStream getOutputStream() throws IOException { return delegate.getOutputStream(); } - public synchronized InputStream getInputStream() throws IOException { + public InputStream getInputStream() throws IOException { return delegate.getInputStream(); } diff --git a/src/java.base/share/classes/sun/security/ssl/BaseSSLSocketImpl.java b/src/java.base/share/classes/sun/security/ssl/BaseSSLSocketImpl.java index 20f0f2e9359..d701e403c53 100644 --- a/src/java.base/share/classes/sun/security/ssl/BaseSSLSocketImpl.java +++ b/src/java.base/share/classes/sun/security/ssl/BaseSSLSocketImpl.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 2019, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -632,7 +632,7 @@ abstract class BaseSSLSocketImpl extends SSLSocket { } @Override - public synchronized void setSoTimeout(int timeout) throws SocketException { + public void setSoTimeout(int timeout) throws SocketException { if (self == this) { super.setSoTimeout(timeout); } else { diff --git a/src/java.base/share/classes/sun/security/ssl/DTLSInputRecord.java b/src/java.base/share/classes/sun/security/ssl/DTLSInputRecord.java index ad126d89045..93f74f30df4 100644 --- a/src/java.base/share/classes/sun/security/ssl/DTLSInputRecord.java +++ b/src/java.base/share/classes/sun/security/ssl/DTLSInputRecord.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2019, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -58,7 +58,7 @@ final class DTLSInputRecord extends InputRecord implements DTLSRecord { } @Override - public synchronized void close() throws IOException { + public void close() throws IOException { if (!isClosed) { super.close(); } diff --git a/src/java.base/share/classes/sun/security/ssl/DTLSOutputRecord.java b/src/java.base/share/classes/sun/security/ssl/DTLSOutputRecord.java index a6604a25017..3031cc3aa89 100644 --- a/src/java.base/share/classes/sun/security/ssl/DTLSOutputRecord.java +++ b/src/java.base/share/classes/sun/security/ssl/DTLSOutputRecord.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1996, 2019, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -58,13 +58,18 @@ final class DTLSOutputRecord extends OutputRecord implements DTLSRecord { } @Override - public synchronized void close() throws IOException { - if (!isClosed) { - if (fragmenter != null && fragmenter.hasAlert()) { - isCloseWaiting = true; - } else { - super.close(); + public void close() throws IOException { + recordLock.lock(); + try { + if (!isClosed) { + if (fragmenter != null && fragmenter.hasAlert()) { + isCloseWaiting = true; + } else { + super.close(); + } } + } finally { + recordLock.unlock(); } } diff --git a/src/java.base/share/classes/sun/security/ssl/EphemeralKeyManager.java b/src/java.base/share/classes/sun/security/ssl/EphemeralKeyManager.java index fe9a9090fb9..b1160049969 100644 --- a/src/java.base/share/classes/sun/security/ssl/EphemeralKeyManager.java +++ b/src/java.base/share/classes/sun/security/ssl/EphemeralKeyManager.java @@ -26,6 +26,7 @@ package sun.security.ssl; import java.security.*; +import java.util.concurrent.locks.ReentrantLock; /** * The "KeyManager" for ephemeral RSA keys. Ephemeral DH and ECDH keys @@ -48,6 +49,8 @@ final class EphemeralKeyManager { new EphemeralKeyPair(null), }; + private final ReentrantLock cachedKeysLock = new ReentrantLock(); + EphemeralKeyManager() { // empty } @@ -65,20 +68,32 @@ final class EphemeralKeyManager { index = INDEX_RSA1024; } - synchronized (keys) { - KeyPair kp = keys[index].getKeyPair(); - if (kp == null) { - try { - KeyPairGenerator kgen = KeyPairGenerator.getInstance("RSA"); - kgen.initialize(length, random); - keys[index] = new EphemeralKeyPair(kgen.genKeyPair()); - kp = keys[index].getKeyPair(); - } catch (Exception e) { - // ignore - } - } + KeyPair kp = keys[index].getKeyPair(); + if (kp != null) { return kp; } + + cachedKeysLock.lock(); + try { + // double check + kp = keys[index].getKeyPair(); + if (kp != null) { + return kp; + } + + try { + KeyPairGenerator kgen = KeyPairGenerator.getInstance("RSA"); + kgen.initialize(length, random); + keys[index] = new EphemeralKeyPair(kgen.genKeyPair()); + kp = keys[index].getKeyPair(); + } catch (Exception e) { + // ignore + } + } finally { + cachedKeysLock.unlock(); + } + + return kp; } /** diff --git a/src/java.base/share/classes/sun/security/ssl/HelloCookieManager.java b/src/java.base/share/classes/sun/security/ssl/HelloCookieManager.java index 31c61036acf..b878c703989 100644 --- a/src/java.base/share/classes/sun/security/ssl/HelloCookieManager.java +++ b/src/java.base/share/classes/sun/security/ssl/HelloCookieManager.java @@ -30,6 +30,7 @@ import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; import java.security.SecureRandom; import java.util.Arrays; +import java.util.concurrent.locks.ReentrantLock; import static sun.security.ssl.ClientHello.ClientHelloMessage; /** @@ -45,6 +46,8 @@ abstract class HelloCookieManager { private volatile D13HelloCookieManager d13HelloCookieManager; private volatile T13HelloCookieManager t13HelloCookieManager; + private final ReentrantLock managerLock = new ReentrantLock(); + Builder(SecureRandom secureRandom) { this.secureRandom = secureRandom; } @@ -56,11 +59,14 @@ abstract class HelloCookieManager { return d13HelloCookieManager; } - synchronized (this) { + managerLock.lock(); + try { if (d13HelloCookieManager == null) { d13HelloCookieManager = new D13HelloCookieManager(secureRandom); } + } finally { + managerLock.unlock(); } return d13HelloCookieManager; @@ -69,11 +75,14 @@ abstract class HelloCookieManager { return d10HelloCookieManager; } - synchronized (this) { + managerLock.lock(); + try { if (d10HelloCookieManager == null) { d10HelloCookieManager = new D10HelloCookieManager(secureRandom); } + } finally { + managerLock.unlock(); } return d10HelloCookieManager; @@ -84,11 +93,14 @@ abstract class HelloCookieManager { return t13HelloCookieManager; } - synchronized (this) { + managerLock.lock(); + try { if (t13HelloCookieManager == null) { t13HelloCookieManager = new T13HelloCookieManager(secureRandom); } + } finally { + managerLock.unlock(); } return t13HelloCookieManager; @@ -114,6 +126,8 @@ abstract class HelloCookieManager { private byte[] cookieSecret; private byte[] legacySecret; + private final ReentrantLock d10ManagerLock = new ReentrantLock(); + D10HelloCookieManager(SecureRandom secureRandom) { this.secureRandom = secureRandom; @@ -131,7 +145,8 @@ abstract class HelloCookieManager { int version; byte[] secret; - synchronized (this) { + d10ManagerLock.lock(); + try { version = cookieVersion; secret = cookieSecret; @@ -142,6 +157,8 @@ abstract class HelloCookieManager { } cookieVersion++; + } finally { + d10ManagerLock.unlock(); } MessageDigest md; @@ -168,12 +185,15 @@ abstract class HelloCookieManager { } byte[] secret; - synchronized (this) { + d10ManagerLock.lock(); + try { if (((cookieVersion >> 24) & 0xFF) == cookie[0]) { secret = cookieSecret; } else { secret = legacySecret; // including out of window cookies } + } finally { + d10ManagerLock.unlock(); } MessageDigest md; @@ -218,6 +238,8 @@ abstract class HelloCookieManager { private final byte[] cookieSecret; private final byte[] legacySecret; + private final ReentrantLock t13ManagerLock = new ReentrantLock(); + T13HelloCookieManager(SecureRandom secureRandom) { this.secureRandom = secureRandom; this.cookieVersion = secureRandom.nextInt(); @@ -234,7 +256,8 @@ abstract class HelloCookieManager { int version; byte[] secret; - synchronized (this) { + t13ManagerLock.lock(); + try { version = cookieVersion; secret = cookieSecret; @@ -245,6 +268,8 @@ abstract class HelloCookieManager { } cookieVersion++; // allow wrapped version number + } finally { + t13ManagerLock.unlock(); } MessageDigest md; @@ -313,12 +338,15 @@ abstract class HelloCookieManager { Arrays.copyOfRange(cookie, 3 + hashLen, cookie.length); byte[] secret; - synchronized (this) { + t13ManagerLock.lock(); + try { if ((byte)((cookieVersion >> 24) & 0xFF) == cookie[2]) { secret = cookieSecret; } else { secret = legacySecret; // including out of window cookies } + } finally { + t13ManagerLock.unlock(); } MessageDigest md; diff --git a/src/java.base/share/classes/sun/security/ssl/InputRecord.java b/src/java.base/share/classes/sun/security/ssl/InputRecord.java index f033ad298eb..8277c799f7f 100644 --- a/src/java.base/share/classes/sun/security/ssl/InputRecord.java +++ b/src/java.base/share/classes/sun/security/ssl/InputRecord.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1996, 2019, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -31,6 +31,7 @@ import java.io.InputStream; import java.io.OutputStream; import java.nio.BufferUnderflowException; import java.nio.ByteBuffer; +import java.util.concurrent.locks.ReentrantLock; import javax.crypto.BadPaddingException; import sun.security.ssl.SSLCipher.SSLReadCipher; @@ -43,10 +44,10 @@ import sun.security.ssl.SSLCipher.SSLReadCipher; abstract class InputRecord implements Record, Closeable { SSLReadCipher readCipher; // Needed for KeyUpdate, used after Handshake.Finished - TransportContext tc; + TransportContext tc; final HandshakeHash handshakeHash; - boolean isClosed; + volatile boolean isClosed; // The ClientHello version to accept. If set to ProtocolVersion.SSL20Hello // and the first message we read is a ClientHello in V2 format, we convert @@ -56,6 +57,8 @@ abstract class InputRecord implements Record, Closeable { // fragment size int fragmentSize; + final ReentrantLock recordLock = new ReentrantLock(); + InputRecord(HandshakeHash handshakeHash, SSLReadCipher readCipher) { this.readCipher = readCipher; this.helloVersion = ProtocolVersion.TLS10; @@ -92,14 +95,19 @@ abstract class InputRecord implements Record, Closeable { * and flag the record as holding no data. */ @Override - public synchronized void close() throws IOException { - if (!isClosed) { - isClosed = true; - readCipher.dispose(); + public void close() throws IOException { + recordLock.lock(); + try { + if (!isClosed) { + isClosed = true; + readCipher.dispose(); + } + } finally { + recordLock.unlock(); } } - synchronized boolean isClosed() { + boolean isClosed() { return isClosed; } diff --git a/src/java.base/share/classes/sun/security/ssl/OutputRecord.java b/src/java.base/share/classes/sun/security/ssl/OutputRecord.java index a340cfe80ee..a46645e6c4e 100644 --- a/src/java.base/share/classes/sun/security/ssl/OutputRecord.java +++ b/src/java.base/share/classes/sun/security/ssl/OutputRecord.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1996, 2019, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -30,6 +30,7 @@ import java.io.Closeable; import java.io.IOException; import java.io.OutputStream; import java.nio.ByteBuffer; +import java.util.concurrent.locks.ReentrantLock; import sun.security.ssl.SSLCipher.SSLWriteCipher; /** @@ -68,6 +69,8 @@ abstract class OutputRecord // closed or not? volatile boolean isClosed; + final ReentrantLock recordLock = new ReentrantLock(); + /* * Mappings from V3 cipher suite encodings to their pure V2 equivalents. * This is taken from the SSL V3 specification, Appendix E. @@ -89,15 +92,25 @@ abstract class OutputRecord // Please set packetSize and protocolVersion in the implementation. } - synchronized void setVersion(ProtocolVersion protocolVersion) { - this.protocolVersion = protocolVersion; + void setVersion(ProtocolVersion protocolVersion) { + recordLock.lock(); + try { + this.protocolVersion = protocolVersion; + } finally { + recordLock.unlock(); + } } /* * Updates helloVersion of this record. */ - synchronized void setHelloVersion(ProtocolVersion helloVersion) { - this.helloVersion = helloVersion; + void setHelloVersion(ProtocolVersion helloVersion) { + recordLock.lock(); + try { + this.helloVersion = helloVersion; + } finally { + recordLock.unlock(); + } } /* @@ -108,9 +121,14 @@ abstract class OutputRecord return false; } - synchronized boolean seqNumIsHuge() { - return (writeCipher.authenticator != null) && + boolean seqNumIsHuge() { + recordLock.lock(); + try { + return (writeCipher.authenticator != null) && writeCipher.authenticator.seqNumIsHuge(); + } finally { + recordLock.unlock(); + } } // SSLEngine and SSLSocket @@ -148,68 +166,93 @@ abstract class OutputRecord } // Change write ciphers, may use change_cipher_spec record. - synchronized void changeWriteCiphers(SSLWriteCipher writeCipher, + void changeWriteCiphers(SSLWriteCipher writeCipher, boolean useChangeCipherSpec) throws IOException { - if (isClosed()) { - if (SSLLogger.isOn && SSLLogger.isOn("ssl")) { - SSLLogger.warning("outbound has closed, ignore outbound " + - "change_cipher_spec message"); + recordLock.lock(); + try { + if (isClosed()) { + if (SSLLogger.isOn && SSLLogger.isOn("ssl")) { + SSLLogger.warning("outbound has closed, ignore outbound " + + "change_cipher_spec message"); + } + return; } - return; + + if (useChangeCipherSpec) { + encodeChangeCipherSpec(); + } + + /* + * Dispose of any intermediate state in the underlying cipher. + * For PKCS11 ciphers, this will release any attached sessions, + * and thus make finalization faster. + * + * Since MAC's doFinal() is called for every SSL/TLS packet, it's + * not necessary to do the same with MAC's. + */ + writeCipher.dispose(); + + this.writeCipher = writeCipher; + this.isFirstAppOutputRecord = true; + } finally { + recordLock.unlock(); } - - if (useChangeCipherSpec) { - encodeChangeCipherSpec(); - } - - /* - * Dispose of any intermediate state in the underlying cipher. - * For PKCS11 ciphers, this will release any attached sessions, - * and thus make finalization faster. - * - * Since MAC's doFinal() is called for every SSL/TLS packet, it's - * not necessary to do the same with MAC's. - */ - writeCipher.dispose(); - - this.writeCipher = writeCipher; - this.isFirstAppOutputRecord = true; } // Change write ciphers using key_update handshake message. - synchronized void changeWriteCiphers(SSLWriteCipher writeCipher, + void changeWriteCiphers(SSLWriteCipher writeCipher, byte keyUpdateRequest) throws IOException { - if (isClosed()) { - if (SSLLogger.isOn && SSLLogger.isOn("ssl")) { - SSLLogger.warning("outbound has closed, ignore outbound " + - "key_update handshake message"); + recordLock.lock(); + try { + if (isClosed()) { + if (SSLLogger.isOn && SSLLogger.isOn("ssl")) { + SSLLogger.warning("outbound has closed, ignore outbound " + + "key_update handshake message"); + } + return; } - return; + + // encode the handshake message, KeyUpdate + byte[] hm = HANDSHAKE_MESSAGE_KEY_UPDATE.clone(); + hm[hm.length - 1] = keyUpdateRequest; + encodeHandshake(hm, 0, hm.length); + flush(); + + // Dispose of any intermediate state in the underlying cipher. + writeCipher.dispose(); + + this.writeCipher = writeCipher; + this.isFirstAppOutputRecord = true; + } finally { + recordLock.unlock(); } - - // encode the handshake message, KeyUpdate - byte[] hm = HANDSHAKE_MESSAGE_KEY_UPDATE.clone(); - hm[hm.length - 1] = keyUpdateRequest; - encodeHandshake(hm, 0, hm.length); - flush(); - - // Dispose of any intermediate state in the underlying cipher. - writeCipher.dispose(); - - this.writeCipher = writeCipher; - this.isFirstAppOutputRecord = true; } - synchronized void changePacketSize(int packetSize) { - this.packetSize = packetSize; + void changePacketSize(int packetSize) { + recordLock.lock(); + try { + this.packetSize = packetSize; + } finally { + recordLock.unlock(); + } } - synchronized void changeFragmentSize(int fragmentSize) { - this.fragmentSize = fragmentSize; + void changeFragmentSize(int fragmentSize) { + recordLock.lock(); + try { + this.fragmentSize = fragmentSize; + } finally { + recordLock.unlock(); + } } - synchronized int getMaxPacketSize() { - return packetSize; + int getMaxPacketSize() { + recordLock.lock(); + try { + return packetSize; + } finally { + recordLock.unlock(); + } } // apply to DTLS SSLEngine @@ -228,13 +271,18 @@ abstract class OutputRecord } @Override - public synchronized void close() throws IOException { - if (isClosed) { - return; - } + public void close() throws IOException { + recordLock.lock(); + try { + if (isClosed) { + return; + } - isClosed = true; - writeCipher.dispose(); + isClosed = true; + writeCipher.dispose(); + } finally { + recordLock.unlock(); + } } boolean isClosed() { diff --git a/src/java.base/share/classes/sun/security/ssl/SSLContextImpl.java b/src/java.base/share/classes/sun/security/ssl/SSLContextImpl.java index 0572079d8d2..fb95cd4ac78 100644 --- a/src/java.base/share/classes/sun/security/ssl/SSLContextImpl.java +++ b/src/java.base/share/classes/sun/security/ssl/SSLContextImpl.java @@ -30,6 +30,7 @@ import java.net.Socket; import java.security.*; import java.security.cert.*; import java.util.*; +import java.util.concurrent.locks.ReentrantLock; import javax.net.ssl.*; import sun.security.action.GetPropertyAction; import sun.security.provider.certpath.AlgorithmChecker; @@ -69,6 +70,8 @@ public abstract class SSLContextImpl extends SSLContextSpi { private volatile StatusResponseManager statusResponseManager; + private final ReentrantLock contextLock = new ReentrantLock(); + SSLContextImpl() { ephemeralKeyManager = new EphemeralKeyManager(); clientCache = new SSLSessionContextImpl(); @@ -230,11 +233,14 @@ public abstract class SSLContextImpl extends SSLContextSpi { // Used for DTLS in server mode only. HelloCookieManager getHelloCookieManager(ProtocolVersion protocolVersion) { if (helloCookieManagerBuilder == null) { - synchronized (this) { + contextLock.lock(); + try { if (helloCookieManagerBuilder == null) { helloCookieManagerBuilder = new HelloCookieManager.Builder(secureRandom); } + } finally { + contextLock.unlock(); } } @@ -243,7 +249,8 @@ public abstract class SSLContextImpl extends SSLContextSpi { StatusResponseManager getStatusResponseManager() { if (serverEnableStapling && statusResponseManager == null) { - synchronized (this) { + contextLock.lock(); + try { if (statusResponseManager == null) { if (SSLLogger.isOn && SSLLogger.isOn("ssl,sslctx")) { SSLLogger.finest( @@ -251,6 +258,8 @@ public abstract class SSLContextImpl extends SSLContextSpi { } statusResponseManager = new StatusResponseManager(); } + } finally { + contextLock.unlock(); } } diff --git a/src/java.base/share/classes/sun/security/ssl/SSLEngineImpl.java b/src/java.base/share/classes/sun/security/ssl/SSLEngineImpl.java index cf09a6bcc52..21b9e467180 100644 --- a/src/java.base/share/classes/sun/security/ssl/SSLEngineImpl.java +++ b/src/java.base/share/classes/sun/security/ssl/SSLEngineImpl.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2019, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -33,6 +33,7 @@ import java.security.PrivilegedActionException; import java.security.PrivilegedExceptionAction; import java.util.List; import java.util.Map; +import java.util.concurrent.locks.ReentrantLock; import java.util.function.BiFunction; import javax.net.ssl.SSLEngine; import javax.net.ssl.SSLEngineResult; @@ -54,6 +55,7 @@ import javax.net.ssl.SSLSession; final class SSLEngineImpl extends SSLEngine implements SSLTransport { private final SSLContextImpl sslContext; final TransportContext conContext; + private final ReentrantLock engineLock = new ReentrantLock(); /** * Constructor for an SSLEngine from SSLContext, without @@ -93,57 +95,68 @@ final class SSLEngineImpl extends SSLEngine implements SSLTransport { } @Override - public synchronized void beginHandshake() throws SSLException { - if (conContext.isUnsureMode) { - throw new IllegalStateException( - "Client/Server mode has not yet been set."); - } - + public void beginHandshake() throws SSLException { + engineLock.lock(); try { - conContext.kickstart(); - } catch (IOException ioe) { - throw conContext.fatal(Alert.HANDSHAKE_FAILURE, - "Couldn't kickstart handshaking", ioe); - } catch (Exception ex) { // including RuntimeException - throw conContext.fatal(Alert.INTERNAL_ERROR, - "Fail to begin handshake", ex); + if (conContext.isUnsureMode) { + throw new IllegalStateException( + "Client/Server mode has not yet been set."); + } + + try { + conContext.kickstart(); + } catch (IOException ioe) { + throw conContext.fatal(Alert.HANDSHAKE_FAILURE, + "Couldn't kickstart handshaking", ioe); + } catch (Exception ex) { // including RuntimeException + throw conContext.fatal(Alert.INTERNAL_ERROR, + "Fail to begin handshake", ex); + } + } finally { + engineLock.unlock(); } } @Override - public synchronized SSLEngineResult wrap(ByteBuffer[] appData, + public SSLEngineResult wrap(ByteBuffer[] appData, int offset, int length, ByteBuffer netData) throws SSLException { return wrap(appData, offset, length, new ByteBuffer[]{ netData }, 0, 1); } // @Override - public synchronized SSLEngineResult wrap( + public SSLEngineResult wrap( ByteBuffer[] srcs, int srcsOffset, int srcsLength, ByteBuffer[] dsts, int dstsOffset, int dstsLength) throws SSLException { - if (conContext.isUnsureMode) { - throw new IllegalStateException( - "Client/Server mode has not yet been set."); - } - - // See if the handshaker needs to report back some SSLException. - checkTaskThrown(); - - // check parameters - checkParams(srcs, srcsOffset, srcsLength, dsts, dstsOffset, dstsLength); - + engineLock.lock(); try { - return writeRecord( - srcs, srcsOffset, srcsLength, dsts, dstsOffset, dstsLength); - } catch (SSLProtocolException spe) { - // may be an unexpected handshake message - throw conContext.fatal(Alert.UNEXPECTED_MESSAGE, spe); - } catch (IOException ioe) { - throw conContext.fatal(Alert.INTERNAL_ERROR, - "problem wrapping app data", ioe); - } catch (Exception ex) { // including RuntimeException - throw conContext.fatal(Alert.INTERNAL_ERROR, - "Fail to wrap application data", ex); + if (conContext.isUnsureMode) { + throw new IllegalStateException( + "Client/Server mode has not yet been set."); + } + + // See if the handshaker needs to report back some SSLException. + checkTaskThrown(); + + // check parameters + checkParams(srcs, srcsOffset, srcsLength, + dsts, dstsOffset, dstsLength); + + try { + return writeRecord( + srcs, srcsOffset, srcsLength, dsts, dstsOffset, dstsLength); + } catch (SSLProtocolException spe) { + // may be an unexpected handshake message + throw conContext.fatal(Alert.UNEXPECTED_MESSAGE, spe); + } catch (IOException ioe) { + throw conContext.fatal(Alert.INTERNAL_ERROR, + "problem wrapping app data", ioe); + } catch (Exception ex) { // including RuntimeException + throw conContext.fatal(Alert.INTERNAL_ERROR, + "Fail to wrap application data", ex); + } + } finally { + engineLock.unlock(); } } @@ -428,47 +441,53 @@ final class SSLEngineImpl extends SSLEngine implements SSLTransport { } @Override - public synchronized SSLEngineResult unwrap(ByteBuffer src, + public SSLEngineResult unwrap(ByteBuffer src, ByteBuffer[] dsts, int offset, int length) throws SSLException { return unwrap( new ByteBuffer[]{src}, 0, 1, dsts, offset, length); } // @Override - public synchronized SSLEngineResult unwrap( + public SSLEngineResult unwrap( ByteBuffer[] srcs, int srcsOffset, int srcsLength, ByteBuffer[] dsts, int dstsOffset, int dstsLength) throws SSLException { - if (conContext.isUnsureMode) { - throw new IllegalStateException( - "Client/Server mode has not yet been set."); - } - - // See if the handshaker needs to report back some SSLException. - checkTaskThrown(); - - // check parameters - checkParams(srcs, srcsOffset, srcsLength, dsts, dstsOffset, dstsLength); - + engineLock.lock(); try { - return readRecord( - srcs, srcsOffset, srcsLength, dsts, dstsOffset, dstsLength); - } catch (SSLProtocolException spe) { - // may be an unexpected handshake message - throw conContext.fatal(Alert.UNEXPECTED_MESSAGE, - spe.getMessage(), spe); - } catch (IOException ioe) { - /* - * Don't reset position so it looks like we didn't - * consume anything. We did consume something, and it - * got us into this situation, so report that much back. - * Our days of consuming are now over anyway. - */ - throw conContext.fatal(Alert.INTERNAL_ERROR, - "problem unwrapping net record", ioe); - } catch (Exception ex) { // including RuntimeException - throw conContext.fatal(Alert.INTERNAL_ERROR, - "Fail to unwrap network record", ex); + if (conContext.isUnsureMode) { + throw new IllegalStateException( + "Client/Server mode has not yet been set."); + } + + // See if the handshaker needs to report back some SSLException. + checkTaskThrown(); + + // check parameters + checkParams(srcs, srcsOffset, srcsLength, + dsts, dstsOffset, dstsLength); + + try { + return readRecord( + srcs, srcsOffset, srcsLength, dsts, dstsOffset, dstsLength); + } catch (SSLProtocolException spe) { + // may be an unexpected handshake message + throw conContext.fatal(Alert.UNEXPECTED_MESSAGE, + spe.getMessage(), spe); + } catch (IOException ioe) { + /* + * Don't reset position so it looks like we didn't + * consume anything. We did consume something, and it + * got us into this situation, so report that much back. + * Our days of consuming are now over anyway. + */ + throw conContext.fatal(Alert.INTERNAL_ERROR, + "problem unwrapping net record", ioe); + } catch (Exception ex) { // including RuntimeException + throw conContext.fatal(Alert.INTERNAL_ERROR, + "Fail to unwrap network record", ex); + } + } finally { + engineLock.unlock(); } } @@ -703,61 +722,87 @@ final class SSLEngineImpl extends SSLEngine implements SSLTransport { } @Override - public synchronized Runnable getDelegatedTask() { - if (conContext.handshakeContext != null && // PRE or POST handshake - !conContext.handshakeContext.taskDelegated && - !conContext.handshakeContext.delegatedActions.isEmpty()) { - conContext.handshakeContext.taskDelegated = true; - return new DelegatedTask(this); + public Runnable getDelegatedTask() { + engineLock.lock(); + try { + if (conContext.handshakeContext != null && // PRE or POST handshake + !conContext.handshakeContext.taskDelegated && + !conContext.handshakeContext.delegatedActions.isEmpty()) { + conContext.handshakeContext.taskDelegated = true; + return new DelegatedTask(this); + } + } finally { + engineLock.unlock(); } return null; } @Override - public synchronized void closeInbound() throws SSLException { - if (isInboundDone()) { - return; + public void closeInbound() throws SSLException { + engineLock.lock(); + try { + if (isInboundDone()) { + return; + } + + if (SSLLogger.isOn && SSLLogger.isOn("ssl")) { + SSLLogger.finest("Closing inbound of SSLEngine"); + } + + // Is it ready to close inbound? + // + // No exception if the initial handshake is not started. + if (!conContext.isInputCloseNotified && + (conContext.isNegotiated || + conContext.handshakeContext != null)) { + + throw conContext.fatal(Alert.INTERNAL_ERROR, + "closing inbound before receiving peer's close_notify"); + } + + conContext.closeInbound(); + } finally { + engineLock.unlock(); } - - if (SSLLogger.isOn && SSLLogger.isOn("ssl")) { - SSLLogger.finest("Closing inbound of SSLEngine"); - } - - // Is it ready to close inbound? - // - // No need to throw exception if the initial handshake is not started. - if (!conContext.isInputCloseNotified && - (conContext.isNegotiated || conContext.handshakeContext != null)) { - - throw conContext.fatal(Alert.INTERNAL_ERROR, - "closing inbound before receiving peer's close_notify"); - } - - conContext.closeInbound(); } @Override - public synchronized boolean isInboundDone() { - return conContext.isInboundClosed(); + public boolean isInboundDone() { + engineLock.lock(); + try { + return conContext.isInboundClosed(); + } finally { + engineLock.unlock(); + } } @Override - public synchronized void closeOutbound() { - if (conContext.isOutboundClosed()) { - return; - } + public void closeOutbound() { + engineLock.lock(); + try { + if (conContext.isOutboundClosed()) { + return; + } - if (SSLLogger.isOn && SSLLogger.isOn("ssl")) { - SSLLogger.finest("Closing outbound of SSLEngine"); - } + if (SSLLogger.isOn && SSLLogger.isOn("ssl")) { + SSLLogger.finest("Closing outbound of SSLEngine"); + } - conContext.closeOutbound(); + conContext.closeOutbound(); + } finally { + engineLock.unlock(); + } } @Override - public synchronized boolean isOutboundDone() { - return conContext.isOutboundDone(); + public boolean isOutboundDone() { + engineLock.lock(); + try { + return conContext.isOutboundDone(); + } finally { + engineLock.unlock(); + } } @Override @@ -766,14 +811,24 @@ final class SSLEngineImpl extends SSLEngine implements SSLTransport { } @Override - public synchronized String[] getEnabledCipherSuites() { - return CipherSuite.namesOf(conContext.sslConfig.enabledCipherSuites); + public String[] getEnabledCipherSuites() { + engineLock.lock(); + try { + return CipherSuite.namesOf(conContext.sslConfig.enabledCipherSuites); + } finally { + engineLock.unlock(); + } } @Override - public synchronized void setEnabledCipherSuites(String[] suites) { - conContext.sslConfig.enabledCipherSuites = - CipherSuite.validValuesOf(suites); + public void setEnabledCipherSuites(String[] suites) { + engineLock.lock(); + try { + conContext.sslConfig.enabledCipherSuites = + CipherSuite.validValuesOf(suites); + } finally { + engineLock.unlock(); + } } @Override @@ -783,119 +838,214 @@ final class SSLEngineImpl extends SSLEngine implements SSLTransport { } @Override - public synchronized String[] getEnabledProtocols() { - return ProtocolVersion.toStringArray( - conContext.sslConfig.enabledProtocols); - } - - @Override - public synchronized void setEnabledProtocols(String[] protocols) { - if (protocols == null) { - throw new IllegalArgumentException("Protocols cannot be null"); - } - - conContext.sslConfig.enabledProtocols = - ProtocolVersion.namesOf(protocols); - } - - @Override - public synchronized SSLSession getSession() { - return conContext.conSession; - } - - @Override - public synchronized SSLSession getHandshakeSession() { - return conContext.handshakeContext == null ? - null : conContext.handshakeContext.handshakeSession; - } - - @Override - public synchronized SSLEngineResult.HandshakeStatus getHandshakeStatus() { - return conContext.getHandshakeStatus(); - } - - @Override - public synchronized void setUseClientMode(boolean mode) { - conContext.setUseClientMode(mode); - } - - @Override - public synchronized boolean getUseClientMode() { - return conContext.sslConfig.isClientMode; - } - - @Override - public synchronized void setNeedClientAuth(boolean need) { - conContext.sslConfig.clientAuthType = - (need ? ClientAuthType.CLIENT_AUTH_REQUIRED : - ClientAuthType.CLIENT_AUTH_NONE); - } - - @Override - public synchronized boolean getNeedClientAuth() { - return (conContext.sslConfig.clientAuthType == - ClientAuthType.CLIENT_AUTH_REQUIRED); - } - - @Override - public synchronized void setWantClientAuth(boolean want) { - conContext.sslConfig.clientAuthType = - (want ? ClientAuthType.CLIENT_AUTH_REQUESTED : - ClientAuthType.CLIENT_AUTH_NONE); - } - - @Override - public synchronized boolean getWantClientAuth() { - return (conContext.sslConfig.clientAuthType == - ClientAuthType.CLIENT_AUTH_REQUESTED); - } - - @Override - public synchronized void setEnableSessionCreation(boolean flag) { - conContext.sslConfig.enableSessionCreation = flag; - } - - @Override - public synchronized boolean getEnableSessionCreation() { - return conContext.sslConfig.enableSessionCreation; - } - - @Override - public synchronized SSLParameters getSSLParameters() { - return conContext.sslConfig.getSSLParameters(); - } - - @Override - public synchronized void setSSLParameters(SSLParameters params) { - conContext.sslConfig.setSSLParameters(params); - - if (conContext.sslConfig.maximumPacketSize != 0) { - conContext.outputRecord.changePacketSize( - conContext.sslConfig.maximumPacketSize); + public String[] getEnabledProtocols() { + engineLock.lock(); + try { + return ProtocolVersion.toStringArray( + conContext.sslConfig.enabledProtocols); + } finally { + engineLock.unlock(); } } @Override - public synchronized String getApplicationProtocol() { - return conContext.applicationProtocol; + public void setEnabledProtocols(String[] protocols) { + engineLock.lock(); + try { + if (protocols == null) { + throw new IllegalArgumentException("Protocols cannot be null"); + } + + conContext.sslConfig.enabledProtocols = + ProtocolVersion.namesOf(protocols); + } finally { + engineLock.unlock(); + } } @Override - public synchronized String getHandshakeApplicationProtocol() { - return conContext.handshakeContext == null ? - null : conContext.handshakeContext.applicationProtocol; + public SSLSession getSession() { + engineLock.lock(); + try { + return conContext.conSession; + } finally { + engineLock.unlock(); + } } @Override - public synchronized void setHandshakeApplicationProtocolSelector( + public SSLSession getHandshakeSession() { + engineLock.lock(); + try { + return conContext.handshakeContext == null ? + null : conContext.handshakeContext.handshakeSession; + } finally { + engineLock.unlock(); + } + } + + @Override + public SSLEngineResult.HandshakeStatus getHandshakeStatus() { + engineLock.lock(); + try { + return conContext.getHandshakeStatus(); + } finally { + engineLock.unlock(); + } + } + + @Override + public void setUseClientMode(boolean mode) { + engineLock.lock(); + try { + conContext.setUseClientMode(mode); + } finally { + engineLock.unlock(); + } + } + + @Override + public boolean getUseClientMode() { + engineLock.lock(); + try { + return conContext.sslConfig.isClientMode; + } finally { + engineLock.unlock(); + } + } + + @Override + public void setNeedClientAuth(boolean need) { + engineLock.lock(); + try { + conContext.sslConfig.clientAuthType = + (need ? ClientAuthType.CLIENT_AUTH_REQUIRED : + ClientAuthType.CLIENT_AUTH_NONE); + } finally { + engineLock.unlock(); + } + } + + @Override + public boolean getNeedClientAuth() { + engineLock.lock(); + try { + return (conContext.sslConfig.clientAuthType == + ClientAuthType.CLIENT_AUTH_REQUIRED); + } finally { + engineLock.unlock(); + } + } + + @Override + public void setWantClientAuth(boolean want) { + engineLock.lock(); + try { + conContext.sslConfig.clientAuthType = + (want ? ClientAuthType.CLIENT_AUTH_REQUESTED : + ClientAuthType.CLIENT_AUTH_NONE); + } finally { + engineLock.unlock(); + } + } + + @Override + public boolean getWantClientAuth() { + engineLock.lock(); + try { + return (conContext.sslConfig.clientAuthType == + ClientAuthType.CLIENT_AUTH_REQUESTED); + } finally { + engineLock.unlock(); + } + } + + @Override + public void setEnableSessionCreation(boolean flag) { + engineLock.lock(); + try { + conContext.sslConfig.enableSessionCreation = flag; + } finally { + engineLock.unlock(); + } + } + + @Override + public boolean getEnableSessionCreation() { + engineLock.lock(); + try { + return conContext.sslConfig.enableSessionCreation; + } finally { + engineLock.unlock(); + } + } + + @Override + public SSLParameters getSSLParameters() { + engineLock.lock(); + try { + return conContext.sslConfig.getSSLParameters(); + } finally { + engineLock.unlock(); + } + } + + @Override + public void setSSLParameters(SSLParameters params) { + engineLock.lock(); + try { + conContext.sslConfig.setSSLParameters(params); + + if (conContext.sslConfig.maximumPacketSize != 0) { + conContext.outputRecord.changePacketSize( + conContext.sslConfig.maximumPacketSize); + } + } finally { + engineLock.unlock(); + } + } + + @Override + public String getApplicationProtocol() { + engineLock.lock(); + try { + return conContext.applicationProtocol; + } finally { + engineLock.unlock(); + } + } + + @Override + public String getHandshakeApplicationProtocol() { + engineLock.lock(); + try { + return conContext.handshakeContext == null ? + null : conContext.handshakeContext.applicationProtocol; + } finally { + engineLock.unlock(); + } + } + + @Override + public void setHandshakeApplicationProtocolSelector( BiFunction, String> selector) { - conContext.sslConfig.engineAPSelector = selector; + engineLock.lock(); + try { + conContext.sslConfig.engineAPSelector = selector; + } finally { + engineLock.unlock(); + } } @Override - public synchronized BiFunction, String> + public BiFunction, String> getHandshakeApplicationProtocolSelector() { - return conContext.sslConfig.engineAPSelector; + engineLock.lock(); + try { + return conContext.sslConfig.engineAPSelector; + } finally { + engineLock.unlock(); + } } @Override @@ -909,38 +1059,42 @@ final class SSLEngineImpl extends SSLEngine implements SSLTransport { * null, report back the Exception that happened in the delegated * task(s). */ - private synchronized void checkTaskThrown() throws SSLException { + private void checkTaskThrown() throws SSLException { Exception exc = null; - - // First check the handshake context. - HandshakeContext hc = conContext.handshakeContext; - if ((hc != null) && (hc.delegatedThrown != null)) { - exc = hc.delegatedThrown; - hc.delegatedThrown = null; - } - - /* - * hc.delegatedThrown and conContext.delegatedThrown are most likely - * the same, but it's possible we could have had a non-fatal - * exception and thus the new HandshakeContext is still valid - * (alert warning). If so, then we may have a secondary exception - * waiting to be reported from the TransportContext, so we will - * need to clear that on a successive call. Otherwise, clear it now. - */ - if (conContext.delegatedThrown != null) { - if (exc != null) { - // hc object comparison - if (conContext.delegatedThrown == exc) { - // clear if/only if both are the same - conContext.delegatedThrown = null; - } // otherwise report the hc delegatedThrown - } else { - // Nothing waiting in HandshakeContext, but one is in the - // TransportContext. - exc = conContext.delegatedThrown; - conContext.delegatedThrown = null; + engineLock.lock(); + try { + // First check the handshake context. + HandshakeContext hc = conContext.handshakeContext; + if ((hc != null) && (hc.delegatedThrown != null)) { + exc = hc.delegatedThrown; + hc.delegatedThrown = null; } + + /* + * hc.delegatedThrown and conContext.delegatedThrown are most + * likely the same, but it's possible we could have had a non-fatal + * exception and thus the new HandshakeContext is still valid + * (alert warning). If so, then we may have a secondary exception + * waiting to be reported from the TransportContext, so we will + * need to clear that on a successive call. Otherwise, clear it now. + */ + if (conContext.delegatedThrown != null) { + if (exc != null) { + // hc object comparison + if (conContext.delegatedThrown == exc) { + // clear if/only if both are the same + conContext.delegatedThrown = null; + } // otherwise report the hc delegatedThrown + } else { + // Nothing waiting in HandshakeContext, but one is in the + // TransportContext. + exc = conContext.delegatedThrown; + conContext.delegatedThrown = null; + } + } + } finally { + engineLock.unlock(); } // Anything to report? @@ -998,7 +1152,8 @@ final class SSLEngineImpl extends SSLEngine implements SSLTransport { @Override public void run() { - synchronized (engine) { + engine.engineLock.lock(); + try { HandshakeContext hc = engine.conContext.handshakeContext; if (hc == null || hc.delegatedActions.isEmpty()) { return; @@ -1055,6 +1210,8 @@ final class SSLEngineImpl extends SSLEngine implements SSLTransport { if (hc != null) { hc.taskDelegated = false; } + } finally { + engine.engineLock.unlock(); } } diff --git a/src/java.base/share/classes/sun/security/ssl/SSLEngineOutputRecord.java b/src/java.base/share/classes/sun/security/ssl/SSLEngineOutputRecord.java index 45621f3233c..6bb0ed0a0d8 100644 --- a/src/java.base/share/classes/sun/security/ssl/SSLEngineOutputRecord.java +++ b/src/java.base/share/classes/sun/security/ssl/SSLEngineOutputRecord.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1996, 2019, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -51,13 +51,18 @@ final class SSLEngineOutputRecord extends OutputRecord implements SSLRecord { } @Override - public synchronized void close() throws IOException { - if (!isClosed) { - if (fragmenter != null && fragmenter.hasAlert()) { - isCloseWaiting = true; - } else { - super.close(); + public void close() throws IOException { + recordLock.lock(); + try { + if (!isClosed) { + if (fragmenter != null && fragmenter.hasAlert()) { + isCloseWaiting = true; + } else { + super.close(); + } } + } finally { + recordLock.unlock(); } } diff --git a/src/java.base/share/classes/sun/security/ssl/SSLServerSocketImpl.java b/src/java.base/share/classes/sun/security/ssl/SSLServerSocketImpl.java index ccaf169cf6d..addcad2a1a2 100644 --- a/src/java.base/share/classes/sun/security/ssl/SSLServerSocketImpl.java +++ b/src/java.base/share/classes/sun/security/ssl/SSLServerSocketImpl.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1996, 2019, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -28,6 +28,7 @@ package sun.security.ssl; import java.io.IOException; import java.net.InetAddress; import java.net.Socket; +import java.util.concurrent.locks.ReentrantLock; import javax.net.ssl.SSLParameters; import javax.net.ssl.SSLServerSocket; @@ -56,6 +57,7 @@ import javax.net.ssl.SSLServerSocket; final class SSLServerSocketImpl extends SSLServerSocket { private final SSLContextImpl sslContext; private final SSLConfiguration sslConfig; + private final ReentrantLock serverSocketLock = new ReentrantLock(); SSLServerSocketImpl(SSLContextImpl sslContext) throws IOException { @@ -84,14 +86,24 @@ final class SSLServerSocketImpl extends SSLServerSocket { } @Override - public synchronized String[] getEnabledCipherSuites() { - return CipherSuite.namesOf(sslConfig.enabledCipherSuites); + public String[] getEnabledCipherSuites() { + serverSocketLock.lock(); + try { + return CipherSuite.namesOf(sslConfig.enabledCipherSuites); + } finally { + serverSocketLock.unlock(); + } } @Override - public synchronized void setEnabledCipherSuites(String[] suites) { - sslConfig.enabledCipherSuites = - CipherSuite.validValuesOf(suites); + public void setEnabledCipherSuites(String[] suites) { + serverSocketLock.lock(); + try { + sslConfig.enabledCipherSuites = + CipherSuite.validValuesOf(suites); + } finally { + serverSocketLock.unlock(); + } } @Override @@ -106,93 +118,153 @@ final class SSLServerSocketImpl extends SSLServerSocket { } @Override - public synchronized String[] getEnabledProtocols() { - return ProtocolVersion.toStringArray(sslConfig.enabledProtocols); - } - - @Override - public synchronized void setEnabledProtocols(String[] protocols) { - if (protocols == null) { - throw new IllegalArgumentException("Protocols cannot be null"); + public String[] getEnabledProtocols() { + serverSocketLock.lock(); + try { + return ProtocolVersion.toStringArray(sslConfig.enabledProtocols); + } finally { + serverSocketLock.unlock(); } - - sslConfig.enabledProtocols = ProtocolVersion.namesOf(protocols); } @Override - public synchronized void setNeedClientAuth(boolean need) { - sslConfig.clientAuthType = - (need ? ClientAuthType.CLIENT_AUTH_REQUIRED : - ClientAuthType.CLIENT_AUTH_NONE); + public void setEnabledProtocols(String[] protocols) { + serverSocketLock.lock(); + try { + if (protocols == null) { + throw new IllegalArgumentException("Protocols cannot be null"); + } + + sslConfig.enabledProtocols = ProtocolVersion.namesOf(protocols); + } finally { + serverSocketLock.unlock(); + } } @Override - public synchronized boolean getNeedClientAuth() { - return (sslConfig.clientAuthType == + public void setNeedClientAuth(boolean need) { + serverSocketLock.lock(); + try { + sslConfig.clientAuthType = + (need ? ClientAuthType.CLIENT_AUTH_REQUIRED : + ClientAuthType.CLIENT_AUTH_NONE); + } finally { + serverSocketLock.unlock(); + } + } + + @Override + public boolean getNeedClientAuth() { + serverSocketLock.lock(); + try { + return (sslConfig.clientAuthType == ClientAuthType.CLIENT_AUTH_REQUIRED); - } - - @Override - public synchronized void setWantClientAuth(boolean want) { - sslConfig.clientAuthType = - (want ? ClientAuthType.CLIENT_AUTH_REQUESTED : - ClientAuthType.CLIENT_AUTH_NONE); - } - - @Override - public synchronized boolean getWantClientAuth() { - return (sslConfig.clientAuthType == - ClientAuthType.CLIENT_AUTH_REQUESTED); - } - - @Override - public synchronized void setUseClientMode(boolean useClientMode) { - /* - * If we need to change the client mode and the enabled - * protocols and cipher suites haven't specifically been - * set by the user, change them to the corresponding - * default ones. - */ - if (sslConfig.isClientMode != useClientMode) { - if (sslContext.isDefaultProtocolVesions( - sslConfig.enabledProtocols)) { - sslConfig.enabledProtocols = - sslContext.getDefaultProtocolVersions(!useClientMode); - } - - if (sslContext.isDefaultCipherSuiteList( - sslConfig.enabledCipherSuites)) { - sslConfig.enabledCipherSuites = - sslContext.getDefaultCipherSuites(!useClientMode); - } - - sslConfig.isClientMode = useClientMode; + } finally { + serverSocketLock.unlock(); } } @Override - public synchronized boolean getUseClientMode() { - return sslConfig.isClientMode; + public void setWantClientAuth(boolean want) { + serverSocketLock.lock(); + try { + sslConfig.clientAuthType = + (want ? ClientAuthType.CLIENT_AUTH_REQUESTED : + ClientAuthType.CLIENT_AUTH_NONE); + } finally { + serverSocketLock.unlock(); + } } @Override - public synchronized void setEnableSessionCreation(boolean flag) { - sslConfig.enableSessionCreation = flag; + public boolean getWantClientAuth() { + serverSocketLock.lock(); + try { + return (sslConfig.clientAuthType == + ClientAuthType.CLIENT_AUTH_REQUESTED); + } finally { + serverSocketLock.unlock(); + } } @Override - public synchronized boolean getEnableSessionCreation() { - return sslConfig.enableSessionCreation; + public void setUseClientMode(boolean useClientMode) { + serverSocketLock.lock(); + try { + /* + * If we need to change the client mode and the enabled + * protocols and cipher suites haven't specifically been + * set by the user, change them to the corresponding + * default ones. + */ + if (sslConfig.isClientMode != useClientMode) { + if (sslContext.isDefaultProtocolVesions( + sslConfig.enabledProtocols)) { + sslConfig.enabledProtocols = + sslContext.getDefaultProtocolVersions(!useClientMode); + } + + if (sslContext.isDefaultCipherSuiteList( + sslConfig.enabledCipherSuites)) { + sslConfig.enabledCipherSuites = + sslContext.getDefaultCipherSuites(!useClientMode); + } + + sslConfig.isClientMode = useClientMode; + } + } finally { + serverSocketLock.unlock(); + } } @Override - public synchronized SSLParameters getSSLParameters() { - return sslConfig.getSSLParameters(); + public boolean getUseClientMode() { + serverSocketLock.lock(); + try { + return sslConfig.isClientMode; + } finally { + serverSocketLock.unlock(); + } } @Override - public synchronized void setSSLParameters(SSLParameters params) { - sslConfig.setSSLParameters(params); + public void setEnableSessionCreation(boolean flag) { + serverSocketLock.lock(); + try { + sslConfig.enableSessionCreation = flag; + } finally { + serverSocketLock.unlock(); + } + } + + @Override + public boolean getEnableSessionCreation() { + serverSocketLock.lock(); + try { + return sslConfig.enableSessionCreation; + } finally { + serverSocketLock.unlock(); + } + } + + @Override + public SSLParameters getSSLParameters() { + serverSocketLock.lock(); + try { + return sslConfig.getSSLParameters(); + } finally { + serverSocketLock.unlock(); + } + } + + @Override + public void setSSLParameters(SSLParameters params) { + serverSocketLock.lock(); + try { + sslConfig.setSSLParameters(params); + } finally { + serverSocketLock.unlock(); + } } @Override diff --git a/src/java.base/share/classes/sun/security/ssl/SSLSessionImpl.java b/src/java.base/share/classes/sun/security/ssl/SSLSessionImpl.java index 07649c5c908..32ad336db1d 100644 --- a/src/java.base/share/classes/sun/security/ssl/SSLSessionImpl.java +++ b/src/java.base/share/classes/sun/security/ssl/SSLSessionImpl.java @@ -38,6 +38,7 @@ import java.util.Enumeration; import java.util.List; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentLinkedQueue; +import java.util.concurrent.locks.ReentrantLock; import javax.crypto.SecretKey; import javax.net.ssl.ExtendedSSLSession; import javax.net.ssl.SNIServerName; @@ -133,7 +134,9 @@ final class SSLSessionImpl extends ExtendedSSLSession { // The endpoint identification algorithm used to check certificates // in this session. - private final String identificationProtocol; + private final String identificationProtocol; + + private final ReentrantLock sessionLock = new ReentrantLock(); /* * Create a new non-rejoinable session, using the default (null) @@ -289,15 +292,22 @@ final class SSLSessionImpl extends ExtendedSSLSession { return resumptionMasterSecret; } - synchronized SecretKey getPreSharedKey() { - return preSharedKey; + SecretKey getPreSharedKey() { + sessionLock.lock(); + try { + return preSharedKey; + } finally { + sessionLock.unlock(); + } } - synchronized SecretKey consumePreSharedKey() { + SecretKey consumePreSharedKey() { + sessionLock.lock(); try { return preSharedKey; } finally { preSharedKey = null; + sessionLock.unlock(); } } @@ -313,11 +323,13 @@ final class SSLSessionImpl extends ExtendedSSLSession { * be used once. This method will return the identity and then clear it * so it cannot be used again. */ - synchronized byte[] consumePskIdentity() { + byte[] consumePskIdentity() { + sessionLock.lock(); try { return pskIdentity; } finally { pskIdentity = null; + sessionLock.unlock(); } } @@ -393,8 +405,13 @@ final class SSLSessionImpl extends ExtendedSSLSession { } @Override - public synchronized boolean isValid() { - return isRejoinable(); + public boolean isValid() { + sessionLock.lock(); + try { + return isRejoinable(); + } finally { + sessionLock.unlock(); + } } /** @@ -777,29 +794,35 @@ final class SSLSessionImpl extends ExtendedSSLSession { * no connections will be able to rejoin this session. */ @Override - public synchronized void invalidate() { - // - // Can't invalidate the NULL session -- this would be - // attempted when we get a handshaking error on a brand - // new connection, with no "real" session yet. - // - if (this == nullSession) { - return; - } + public void invalidate() { + sessionLock.lock(); + try { + // + // Can't invalidate the NULL session -- this would be + // attempted when we get a handshaking error on a brand + // new connection, with no "real" session yet. + // + if (this == nullSession) { + return; + } - if (context != null) { - context.remove(sessionId); - context = null; - } - if (invalidated) { - return; - } - invalidated = true; - if (SSLLogger.isOn && SSLLogger.isOn("session")) { - SSLLogger.finest("Invalidated session: " + this); - } - for (SSLSessionImpl child : childSessions) { - child.invalidate(); + if (context != null) { + context.remove(sessionId); + context = null; + } + + if (invalidated) { + return; + } + invalidated = true; + if (SSLLogger.isOn && SSLLogger.isOn("session")) { + SSLLogger.finest("Invalidated session: " + this); + } + for (SSLSessionImpl child : childSessions) { + child.invalidate(); + } + } finally { + sessionLock.unlock(); } } @@ -912,8 +935,13 @@ final class SSLSessionImpl extends ExtendedSSLSession { * Expand the buffer size of both SSL/TLS network packet and * application data. */ - protected synchronized void expandBufferSizes() { - acceptLargeFragments = true; + protected void expandBufferSizes() { + sessionLock.lock(); + try { + acceptLargeFragments = true; + } finally { + sessionLock.unlock(); + } } /** @@ -921,30 +949,35 @@ final class SSLSessionImpl extends ExtendedSSLSession { * when using this session. */ @Override - public synchronized int getPacketBufferSize() { - // Use the bigger packet size calculated from maximumPacketSize - // and negotiatedMaxFragLen. - int packetSize = 0; - if (negotiatedMaxFragLen > 0) { - packetSize = cipherSuite.calculatePacketSize( - negotiatedMaxFragLen, protocolVersion, - protocolVersion.isDTLS); - } + public int getPacketBufferSize() { + sessionLock.lock(); + try { + // Use the bigger packet size calculated from maximumPacketSize + // and negotiatedMaxFragLen. + int packetSize = 0; + if (negotiatedMaxFragLen > 0) { + packetSize = cipherSuite.calculatePacketSize( + negotiatedMaxFragLen, protocolVersion, + protocolVersion.isDTLS); + } - if (maximumPacketSize > 0) { - return (maximumPacketSize > packetSize) ? - maximumPacketSize : packetSize; - } + if (maximumPacketSize > 0) { + return (maximumPacketSize > packetSize) ? + maximumPacketSize : packetSize; + } - if (packetSize != 0) { - return packetSize; - } + if (packetSize != 0) { + return packetSize; + } - if (protocolVersion.isDTLS) { - return DTLSRecord.maxRecordSize; - } else { - return acceptLargeFragments ? - SSLRecord.maxLargeRecordSize : SSLRecord.maxRecordSize; + if (protocolVersion.isDTLS) { + return DTLSRecord.maxRecordSize; + } else { + return acceptLargeFragments ? + SSLRecord.maxLargeRecordSize : SSLRecord.maxRecordSize; + } + } finally { + sessionLock.unlock(); } } @@ -953,31 +986,36 @@ final class SSLSessionImpl extends ExtendedSSLSession { * expected when using this session. */ @Override - public synchronized int getApplicationBufferSize() { - // Use the bigger fragment size calculated from maximumPacketSize - // and negotiatedMaxFragLen. - int fragmentSize = 0; - if (maximumPacketSize > 0) { - fragmentSize = cipherSuite.calculateFragSize( - maximumPacketSize, protocolVersion, - protocolVersion.isDTLS); - } + public int getApplicationBufferSize() { + sessionLock.lock(); + try { + // Use the bigger fragment size calculated from maximumPacketSize + // and negotiatedMaxFragLen. + int fragmentSize = 0; + if (maximumPacketSize > 0) { + fragmentSize = cipherSuite.calculateFragSize( + maximumPacketSize, protocolVersion, + protocolVersion.isDTLS); + } - if (negotiatedMaxFragLen > 0) { - return (negotiatedMaxFragLen > fragmentSize) ? - negotiatedMaxFragLen : fragmentSize; - } + if (negotiatedMaxFragLen > 0) { + return (negotiatedMaxFragLen > fragmentSize) ? + negotiatedMaxFragLen : fragmentSize; + } - if (fragmentSize != 0) { - return fragmentSize; - } + if (fragmentSize != 0) { + return fragmentSize; + } - if (protocolVersion.isDTLS) { - return Record.maxDataSize; - } else { - int maxPacketSize = acceptLargeFragments ? - SSLRecord.maxLargeRecordSize : SSLRecord.maxRecordSize; - return (maxPacketSize - SSLRecord.headerSize); + if (protocolVersion.isDTLS) { + return Record.maxDataSize; + } else { + int maxPacketSize = acceptLargeFragments ? + SSLRecord.maxLargeRecordSize : SSLRecord.maxRecordSize; + return (maxPacketSize - SSLRecord.headerSize); + } + } finally { + sessionLock.unlock(); } } @@ -989,10 +1027,14 @@ final class SSLSessionImpl extends ExtendedSSLSession { * the negotiated maximum fragment length, or {@code -1} if * no such length has been negotiated. */ - synchronized void setNegotiatedMaxFragSize( + void setNegotiatedMaxFragSize( int negotiatedMaxFragLen) { - - this.negotiatedMaxFragLen = negotiatedMaxFragLen; + sessionLock.lock(); + try { + this.negotiatedMaxFragLen = negotiatedMaxFragLen; + } finally { + sessionLock.unlock(); + } } /** @@ -1002,16 +1044,31 @@ final class SSLSessionImpl extends ExtendedSSLSession { * @return the negotiated maximum fragment length, or {@code -1} if * no such length has been negotiated. */ - synchronized int getNegotiatedMaxFragSize() { - return negotiatedMaxFragLen; + int getNegotiatedMaxFragSize() { + sessionLock.lock(); + try { + return negotiatedMaxFragLen; + } finally { + sessionLock.unlock(); + } } - synchronized void setMaximumPacketSize(int maximumPacketSize) { - this.maximumPacketSize = maximumPacketSize; + void setMaximumPacketSize(int maximumPacketSize) { + sessionLock.lock(); + try { + this.maximumPacketSize = maximumPacketSize; + } finally { + sessionLock.unlock(); + } } - synchronized int getMaximumPacketSize() { - return maximumPacketSize; + int getMaximumPacketSize() { + sessionLock.lock(); + try { + return maximumPacketSize; + } finally { + sessionLock.unlock(); + } } /** diff --git a/src/java.base/share/classes/sun/security/ssl/SSLSocketImpl.java b/src/java.base/share/classes/sun/security/ssl/SSLSocketImpl.java index 8757a1b0a3a..3d322e05d1f 100644 --- a/src/java.base/share/classes/sun/security/ssl/SSLSocketImpl.java +++ b/src/java.base/share/classes/sun/security/ssl/SSLSocketImpl.java @@ -38,6 +38,7 @@ import java.net.SocketException; import java.net.UnknownHostException; import java.nio.ByteBuffer; import java.util.List; +import java.util.concurrent.locks.ReentrantLock; import java.util.function.BiFunction; import javax.net.ssl.HandshakeCompletedListener; import javax.net.ssl.SSLException; @@ -84,6 +85,9 @@ public final class SSLSocketImpl private boolean isConnected = false; private volatile boolean tlsIsClosed = false; + private final ReentrantLock socketLock = new ReentrantLock(); + private final ReentrantLock handshakeLock = new ReentrantLock(); + /* * Is the local name service trustworthy? * @@ -292,14 +296,25 @@ public final class SSLSocketImpl } @Override - public synchronized String[] getEnabledCipherSuites() { - return CipherSuite.namesOf(conContext.sslConfig.enabledCipherSuites); + public String[] getEnabledCipherSuites() { + socketLock.lock(); + try { + return CipherSuite.namesOf( + conContext.sslConfig.enabledCipherSuites); + } finally { + socketLock.unlock(); + } } @Override - public synchronized void setEnabledCipherSuites(String[] suites) { - conContext.sslConfig.enabledCipherSuites = - CipherSuite.validValuesOf(suites); + public void setEnabledCipherSuites(String[] suites) { + socketLock.lock(); + try { + conContext.sslConfig.enabledCipherSuites = + CipherSuite.validValuesOf(suites); + } finally { + socketLock.unlock(); + } } @Override @@ -309,19 +324,29 @@ public final class SSLSocketImpl } @Override - public synchronized String[] getEnabledProtocols() { - return ProtocolVersion.toStringArray( - conContext.sslConfig.enabledProtocols); + public String[] getEnabledProtocols() { + socketLock.lock(); + try { + return ProtocolVersion.toStringArray( + conContext.sslConfig.enabledProtocols); + } finally { + socketLock.unlock(); + } } @Override - public synchronized void setEnabledProtocols(String[] protocols) { + public void setEnabledProtocols(String[] protocols) { if (protocols == null) { throw new IllegalArgumentException("Protocols cannot be null"); } - conContext.sslConfig.enabledProtocols = - ProtocolVersion.namesOf(protocols); + socketLock.lock(); + try { + conContext.sslConfig.enabledProtocols = + ProtocolVersion.namesOf(protocols); + } finally { + socketLock.unlock(); + } } @Override @@ -341,29 +366,44 @@ public final class SSLSocketImpl } @Override - public synchronized SSLSession getHandshakeSession() { - return conContext.handshakeContext == null ? - null : conContext.handshakeContext.handshakeSession; + public SSLSession getHandshakeSession() { + socketLock.lock(); + try { + return conContext.handshakeContext == null ? + null : conContext.handshakeContext.handshakeSession; + } finally { + socketLock.unlock(); + } } @Override - public synchronized void addHandshakeCompletedListener( + public void addHandshakeCompletedListener( HandshakeCompletedListener listener) { if (listener == null) { throw new IllegalArgumentException("listener is null"); } - conContext.sslConfig.addHandshakeCompletedListener(listener); + socketLock.lock(); + try { + conContext.sslConfig.addHandshakeCompletedListener(listener); + } finally { + socketLock.unlock(); + } } @Override - public synchronized void removeHandshakeCompletedListener( + public void removeHandshakeCompletedListener( HandshakeCompletedListener listener) { if (listener == null) { throw new IllegalArgumentException("listener is null"); } - conContext.sslConfig.removeHandshakeCompletedListener(listener); + socketLock.lock(); + try { + conContext.sslConfig.removeHandshakeCompletedListener(listener); + } finally { + socketLock.unlock(); + } } @Override @@ -377,7 +417,8 @@ public final class SSLSocketImpl throw new SocketException("Socket has been closed or broken"); } - synchronized (conContext) { // handshake lock + handshakeLock.lock(); + try { // double check the context status if (conContext.isBroken || conContext.isInboundClosed() || conContext.isOutboundClosed()) { @@ -400,53 +441,95 @@ public final class SSLSocketImpl } catch (Exception oe) { // including RuntimeException handleException(oe); } + } finally { + handshakeLock.unlock(); } } @Override - public synchronized void setUseClientMode(boolean mode) { - conContext.setUseClientMode(mode); + public void setUseClientMode(boolean mode) { + socketLock.lock(); + try { + conContext.setUseClientMode(mode); + } finally { + socketLock.unlock(); + } } @Override - public synchronized boolean getUseClientMode() { - return conContext.sslConfig.isClientMode; + public boolean getUseClientMode() { + socketLock.lock(); + try { + return conContext.sslConfig.isClientMode; + } finally { + socketLock.unlock(); + } } @Override - public synchronized void setNeedClientAuth(boolean need) { - conContext.sslConfig.clientAuthType = - (need ? ClientAuthType.CLIENT_AUTH_REQUIRED : - ClientAuthType.CLIENT_AUTH_NONE); + public void setNeedClientAuth(boolean need) { + socketLock.lock(); + try { + conContext.sslConfig.clientAuthType = + (need ? ClientAuthType.CLIENT_AUTH_REQUIRED : + ClientAuthType.CLIENT_AUTH_NONE); + } finally { + socketLock.unlock(); + } } @Override - public synchronized boolean getNeedClientAuth() { - return (conContext.sslConfig.clientAuthType == + public boolean getNeedClientAuth() { + socketLock.lock(); + try { + return (conContext.sslConfig.clientAuthType == ClientAuthType.CLIENT_AUTH_REQUIRED); + } finally { + socketLock.unlock(); + } } @Override - public synchronized void setWantClientAuth(boolean want) { - conContext.sslConfig.clientAuthType = - (want ? ClientAuthType.CLIENT_AUTH_REQUESTED : - ClientAuthType.CLIENT_AUTH_NONE); + public void setWantClientAuth(boolean want) { + socketLock.lock(); + try { + conContext.sslConfig.clientAuthType = + (want ? ClientAuthType.CLIENT_AUTH_REQUESTED : + ClientAuthType.CLIENT_AUTH_NONE); + } finally { + socketLock.unlock(); + } } @Override - public synchronized boolean getWantClientAuth() { - return (conContext.sslConfig.clientAuthType == + public boolean getWantClientAuth() { + socketLock.lock(); + try { + return (conContext.sslConfig.clientAuthType == ClientAuthType.CLIENT_AUTH_REQUESTED); + } finally { + socketLock.unlock(); + } } @Override - public synchronized void setEnableSessionCreation(boolean flag) { - conContext.sslConfig.enableSessionCreation = flag; + public void setEnableSessionCreation(boolean flag) { + socketLock.lock(); + try { + conContext.sslConfig.enableSessionCreation = flag; + } finally { + socketLock.unlock(); + } } @Override - public synchronized boolean getEnableSessionCreation() { - return conContext.sslConfig.enableSessionCreation; + public boolean getEnableSessionCreation() { + socketLock.lock(); + try { + return conContext.sslConfig.enableSessionCreation; + } finally { + socketLock.unlock(); + } } @Override @@ -535,8 +618,9 @@ public final class SSLSocketImpl // Need a lock here so that the user_canceled alert and the // close_notify alert can be delivered together. + conContext.outputRecord.recordLock.lock(); try { - synchronized (conContext.outputRecord) { + try { // send a user_canceled alert if needed. if (useUserCanceled) { conContext.warning(Alert.USER_CANCELED); @@ -544,15 +628,17 @@ public final class SSLSocketImpl // send a close_notify alert conContext.warning(Alert.CLOSE_NOTIFY); + } finally { + if (!conContext.isOutboundClosed()) { + conContext.outputRecord.close(); + } + + if ((autoClose || !isLayered()) && !super.isOutputShutdown()) { + super.shutdownOutput(); + } } } finally { - if (!conContext.isOutboundClosed()) { - conContext.outputRecord.close(); - } - - if ((autoClose || !isLayered()) && !super.isOutputShutdown()) { - super.shutdownOutput(); - } + conContext.outputRecord.recordLock.unlock(); } if (!isInputShutdown()) { @@ -681,20 +767,25 @@ public final class SSLSocketImpl } @Override - public synchronized InputStream getInputStream() throws IOException { - if (isClosed()) { - throw new SocketException("Socket is closed"); - } + public InputStream getInputStream() throws IOException { + socketLock.lock(); + try { + if (isClosed()) { + throw new SocketException("Socket is closed"); + } - if (!isConnected) { - throw new SocketException("Socket is not connected"); - } + if (!isConnected) { + throw new SocketException("Socket is not connected"); + } - if (conContext.isInboundClosed() || isInputShutdown()) { - throw new SocketException("Socket input is already shutdown"); - } + if (conContext.isInboundClosed() || isInputShutdown()) { + throw new SocketException("Socket input is already shutdown"); + } - return appInput; + return appInput; + } finally { + socketLock.unlock(); + } } private void ensureNegotiated() throws IOException { @@ -703,7 +794,8 @@ public final class SSLSocketImpl return; } - synchronized (conContext) { // handshake lock + handshakeLock.lock(); + try { // double check the context status if (conContext.isNegotiated || conContext.isBroken || conContext.isInboundClosed() || @@ -712,6 +804,8 @@ public final class SSLSocketImpl } startHandshake(); + } finally { + handshakeLock.unlock(); } } @@ -729,6 +823,9 @@ public final class SSLSocketImpl // Is application data available in the stream? private volatile boolean appDataIsAvailable; + // reading lock + private final ReentrantLock readLock = new ReentrantLock(); + AppInputStream() { this.appDataIsAvailable = false; this.buffer = ByteBuffer.allocate(4096); @@ -807,7 +904,8 @@ public final class SSLSocketImpl // // Note that the receiving and processing of post-handshake message // are also synchronized with the read lock. - synchronized (this) { + readLock.lock(); + try { int remains = available(); if (remains > 0) { int howmany = Math.min(remains, len); @@ -839,6 +937,8 @@ public final class SSLSocketImpl // dummy for compiler return -1; } + } finally { + readLock.unlock(); } } @@ -850,19 +950,24 @@ public final class SSLSocketImpl * things simpler. */ @Override - public synchronized long skip(long n) throws IOException { + public long skip(long n) throws IOException { // dummy array used to implement skip() byte[] skipArray = new byte[256]; - long skipped = 0; - while (n > 0) { - int len = (int)Math.min(n, skipArray.length); - int r = read(skipArray, 0, len); - if (r <= 0) { - break; + + readLock.lock(); + try { + while (n > 0) { + int len = (int)Math.min(n, skipArray.length); + int r = read(skipArray, 0, len); + if (r <= 0) { + break; + } + n -= r; + skipped += r; } - n -= r; - skipped += r; + } finally { + readLock.unlock(); } return skipped; @@ -910,8 +1015,18 @@ public final class SSLSocketImpl * Try the best to use up the input records so as to close the * socket gracefully, without impact the performance too much. */ - private synchronized void deplete() { - if (!conContext.isInboundClosed()) { + private void deplete() { + if (conContext.isInboundClosed()) { + return; + } + + readLock.lock(); + try { + // double check + if (conContext.isInboundClosed()) { + return; + } + if (!(conContext.inputRecord instanceof SSLSocketInputRecord)) { return; } @@ -927,25 +1042,32 @@ public final class SSLSocketImpl "input stream close depletion failed", ioe); } } + } finally { + readLock.unlock(); } } } @Override - public synchronized OutputStream getOutputStream() throws IOException { - if (isClosed()) { - throw new SocketException("Socket is closed"); - } + public OutputStream getOutputStream() throws IOException { + socketLock.lock(); + try { + if (isClosed()) { + throw new SocketException("Socket is closed"); + } - if (!isConnected) { - throw new SocketException("Socket is not connected"); - } + if (!isConnected) { + throw new SocketException("Socket is not connected"); + } - if (conContext.isOutboundDone() || isOutputShutdown()) { - throw new SocketException("Socket output is already shutdown"); - } + if (conContext.isOutboundDone() || isOutputShutdown()) { + throw new SocketException("Socket output is already shutdown"); + } - return appOutput; + return appOutput; + } finally { + socketLock.unlock(); + } } @@ -1035,44 +1157,74 @@ public final class SSLSocketImpl } @Override - public synchronized SSLParameters getSSLParameters() { - return conContext.sslConfig.getSSLParameters(); - } - - @Override - public synchronized void setSSLParameters(SSLParameters params) { - conContext.sslConfig.setSSLParameters(params); - - if (conContext.sslConfig.maximumPacketSize != 0) { - conContext.outputRecord.changePacketSize( - conContext.sslConfig.maximumPacketSize); + public SSLParameters getSSLParameters() { + socketLock.lock(); + try { + return conContext.sslConfig.getSSLParameters(); + } finally { + socketLock.unlock(); } } @Override - public synchronized String getApplicationProtocol() { - return conContext.applicationProtocol; + public void setSSLParameters(SSLParameters params) { + socketLock.lock(); + try { + conContext.sslConfig.setSSLParameters(params); + + if (conContext.sslConfig.maximumPacketSize != 0) { + conContext.outputRecord.changePacketSize( + conContext.sslConfig.maximumPacketSize); + } + } finally { + socketLock.unlock(); + } } @Override - public synchronized String getHandshakeApplicationProtocol() { - if (conContext.handshakeContext != null) { - return conContext.handshakeContext.applicationProtocol; + public String getApplicationProtocol() { + socketLock.lock(); + try { + return conContext.applicationProtocol; + } finally { + socketLock.unlock(); + } + } + + @Override + public String getHandshakeApplicationProtocol() { + socketLock.lock(); + try { + if (conContext.handshakeContext != null) { + return conContext.handshakeContext.applicationProtocol; + } + } finally { + socketLock.unlock(); } return null; } @Override - public synchronized void setHandshakeApplicationProtocolSelector( + public void setHandshakeApplicationProtocolSelector( BiFunction, String> selector) { - conContext.sslConfig.socketAPSelector = selector; + socketLock.lock(); + try { + conContext.sslConfig.socketAPSelector = selector; + } finally { + socketLock.unlock(); + } } @Override - public synchronized BiFunction, String> + public BiFunction, String> getHandshakeApplicationProtocolSelector() { - return conContext.sslConfig.socketAPSelector; + socketLock.lock(); + try { + return conContext.sslConfig.socketAPSelector; + } finally { + socketLock.unlock(); + } } /** @@ -1142,8 +1294,11 @@ public final class SSLSocketImpl try { Plaintext plainText; - synchronized (this) { + socketLock.lock(); + try { plainText = decode(buffer); + } finally { + socketLock.unlock(); } if (plainText.contentType == ContentType.APPLICATION_DATA.id && buffer.position() > 0) { @@ -1222,27 +1377,33 @@ public final class SSLSocketImpl * * Called by connect, the layered constructor, and SSLServerSocket. */ - synchronized void doneConnect() throws IOException { - // In server mode, it is not necessary to set host and serverNames. - // Otherwise, would require a reverse DNS lookup to get the hostname. - if (peerHost == null || peerHost.isEmpty()) { - boolean useNameService = - trustNameService && conContext.sslConfig.isClientMode; - useImplicitHost(useNameService); - } else { - conContext.sslConfig.serverNames = - Utilities.addToSNIServerNameList( - conContext.sslConfig.serverNames, peerHost); + void doneConnect() throws IOException { + socketLock.lock(); + try { + // In server mode, it is not necessary to set host and serverNames. + // Otherwise, would require a reverse DNS lookup to get + // the hostname. + if (peerHost == null || peerHost.isEmpty()) { + boolean useNameService = + trustNameService && conContext.sslConfig.isClientMode; + useImplicitHost(useNameService); + } else { + conContext.sslConfig.serverNames = + Utilities.addToSNIServerNameList( + conContext.sslConfig.serverNames, peerHost); + } + + InputStream sockInput = super.getInputStream(); + conContext.inputRecord.setReceiverStream(sockInput); + + OutputStream sockOutput = super.getOutputStream(); + conContext.inputRecord.setDeliverStream(sockOutput); + conContext.outputRecord.setDeliverStream(sockOutput); + + this.isConnected = true; + } finally { + socketLock.unlock(); } - - InputStream sockInput = super.getInputStream(); - conContext.inputRecord.setReceiverStream(sockInput); - - OutputStream sockOutput = super.getOutputStream(); - conContext.inputRecord.setDeliverStream(sockOutput); - conContext.outputRecord.setDeliverStream(sockOutput); - - this.isConnected = true; } private void useImplicitHost(boolean useNameService) { @@ -1288,11 +1449,16 @@ public final class SSLSocketImpl // Please NOTE that this method MUST be called before calling to // SSLSocket.setSSLParameters(). Otherwise, the {@code host} parameter // may override SNIHostName in the customized server name indication. - public synchronized void setHost(String host) { - this.peerHost = host; - this.conContext.sslConfig.serverNames = - Utilities.addToSNIServerNameList( - conContext.sslConfig.serverNames, host); + public void setHost(String host) { + socketLock.lock(); + try { + this.peerHost = host; + this.conContext.sslConfig.serverNames = + Utilities.addToSNIServerNameList( + conContext.sslConfig.serverNames, host); + } finally { + socketLock.unlock(); + } } /** diff --git a/src/java.base/share/classes/sun/security/ssl/SSLSocketOutputRecord.java b/src/java.base/share/classes/sun/security/ssl/SSLSocketOutputRecord.java index 2eff804cfe1..07ef617d8cc 100644 --- a/src/java.base/share/classes/sun/security/ssl/SSLSocketOutputRecord.java +++ b/src/java.base/share/classes/sun/security/ssl/SSLSocketOutputRecord.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1996, 2019, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -51,123 +51,206 @@ final class SSLSocketOutputRecord extends OutputRecord implements SSLRecord { } @Override - synchronized void encodeAlert( - byte level, byte description) throws IOException { - if (isClosed()) { - if (SSLLogger.isOn && SSLLogger.isOn("ssl")) { - SSLLogger.warning("outbound has closed, ignore outbound " + - "alert message: " + Alert.nameOf(description)); + void encodeAlert(byte level, byte description) throws IOException { + recordLock.lock(); + try { + if (isClosed()) { + if (SSLLogger.isOn && SSLLogger.isOn("ssl")) { + SSLLogger.warning("outbound has closed, ignore outbound " + + "alert message: " + Alert.nameOf(description)); + } + return; } - return; + + // use the buf of ByteArrayOutputStream + int position = headerSize + writeCipher.getExplicitNonceSize(); + count = position; + + write(level); + write(description); + if (SSLLogger.isOn && SSLLogger.isOn("record")) { + SSLLogger.fine("WRITE: " + protocolVersion + + " " + ContentType.ALERT.name + + "(" + Alert.nameOf(description) + ")" + + ", length = " + (count - headerSize)); + } + + // Encrypt the fragment and wrap up a record. + encrypt(writeCipher, ContentType.ALERT.id, headerSize); + + // deliver this message + deliverStream.write(buf, 0, count); // may throw IOException + deliverStream.flush(); // may throw IOException + + if (SSLLogger.isOn && SSLLogger.isOn("packet")) { + SSLLogger.fine("Raw write", + (new ByteArrayInputStream(buf, 0, count))); + } + + // reset the internal buffer + count = 0; + } finally { + recordLock.unlock(); } - - // use the buf of ByteArrayOutputStream - int position = headerSize + writeCipher.getExplicitNonceSize(); - count = position; - - write(level); - write(description); - if (SSLLogger.isOn && SSLLogger.isOn("record")) { - SSLLogger.fine("WRITE: " + protocolVersion + - " " + ContentType.ALERT.name + - "(" + Alert.nameOf(description) + ")" + - ", length = " + (count - headerSize)); - } - - // Encrypt the fragment and wrap up a record. - encrypt(writeCipher, ContentType.ALERT.id, headerSize); - - // deliver this message - deliverStream.write(buf, 0, count); // may throw IOException - deliverStream.flush(); // may throw IOException - - if (SSLLogger.isOn && SSLLogger.isOn("packet")) { - SSLLogger.fine("Raw write", - (new ByteArrayInputStream(buf, 0, count))); - } - - // reset the internal buffer - count = 0; } @Override - synchronized void encodeHandshake(byte[] source, + void encodeHandshake(byte[] source, int offset, int length) throws IOException { - if (isClosed()) { - if (SSLLogger.isOn && SSLLogger.isOn("ssl")) { - SSLLogger.warning("outbound has closed, ignore outbound " + - "handshake message", - ByteBuffer.wrap(source, offset, length)); + recordLock.lock(); + try { + if (isClosed()) { + if (SSLLogger.isOn && SSLLogger.isOn("ssl")) { + SSLLogger.warning("outbound has closed, ignore outbound " + + "handshake message", + ByteBuffer.wrap(source, offset, length)); + } + return; } - return; - } - if (firstMessage) { - firstMessage = false; + if (firstMessage) { + firstMessage = false; - if ((helloVersion == ProtocolVersion.SSL20Hello) && - (source[offset] == SSLHandshake.CLIENT_HELLO.id) && + if ((helloVersion == ProtocolVersion.SSL20Hello) && + (source[offset] == SSLHandshake.CLIENT_HELLO.id) && // 5: recode header size - (source[offset + 4 + 2 + 32] == 0)) { + (source[offset + 4 + 2 + 32] == 0)) { // V3 session ID is empty // 4: handshake header size // 2: client_version in ClientHello // 32: random in ClientHello - ByteBuffer v2ClientHello = encodeV2ClientHello( - source, (offset + 4), (length - 4)); + ByteBuffer v2ClientHello = encodeV2ClientHello( + source, (offset + 4), (length - 4)); - byte[] record = v2ClientHello.array(); // array offset is zero - int limit = v2ClientHello.limit(); - handshakeHash.deliver(record, 2, (limit - 2)); + // array offset is zero + byte[] record = v2ClientHello.array(); + int limit = v2ClientHello.limit(); + handshakeHash.deliver(record, 2, (limit - 2)); + + if (SSLLogger.isOn && SSLLogger.isOn("record")) { + SSLLogger.fine( + "WRITE: SSLv2 ClientHello message" + + ", length = " + limit); + } + + // deliver this message + // + // Version 2 ClientHello message should be plaintext. + // + // No max fragment length negotiation. + deliverStream.write(record, 0, limit); + deliverStream.flush(); + + if (SSLLogger.isOn && SSLLogger.isOn("packet")) { + SSLLogger.fine("Raw write", + (new ByteArrayInputStream(record, 0, limit))); + } + + return; + } + } + + byte handshakeType = source[0]; + if (handshakeHash.isHashable(handshakeType)) { + handshakeHash.deliver(source, offset, length); + } + + int fragLimit = getFragLimit(); + int position = headerSize + writeCipher.getExplicitNonceSize(); + if (count == 0) { + count = position; + } + + if ((count - position) < (fragLimit - length)) { + write(source, offset, length); + return; + } + + for (int limit = (offset + length); offset < limit;) { + + int remains = (limit - offset) + (count - position); + int fragLen = Math.min(fragLimit, remains); + + // use the buf of ByteArrayOutputStream + write(source, offset, fragLen); + if (remains < fragLimit) { + return; + } if (SSLLogger.isOn && SSLLogger.isOn("record")) { SSLLogger.fine( - "WRITE: SSLv2 ClientHello message" + - ", length = " + limit); + "WRITE: " + protocolVersion + + " " + ContentType.HANDSHAKE.name + + ", length = " + (count - headerSize)); } + // Encrypt the fragment and wrap up a record. + encrypt(writeCipher, ContentType.HANDSHAKE.id, headerSize); + // deliver this message - // - // Version 2 ClientHello message should be plaintext. - // - // No max fragment length negotiation. - deliverStream.write(record, 0, limit); - deliverStream.flush(); + deliverStream.write(buf, 0, count); // may throw IOException + deliverStream.flush(); // may throw IOException if (SSLLogger.isOn && SSLLogger.isOn("packet")) { SSLLogger.fine("Raw write", - (new ByteArrayInputStream(record, 0, limit))); + (new ByteArrayInputStream(buf, 0, count))); } + // reset the offset + offset += fragLen; + + // reset the internal buffer + count = position; + } + } finally { + recordLock.unlock(); + } + } + + @Override + void encodeChangeCipherSpec() throws IOException { + recordLock.lock(); + try { + if (isClosed()) { + if (SSLLogger.isOn && SSLLogger.isOn("ssl")) { + SSLLogger.warning("outbound has closed, ignore outbound " + + "change_cipher_spec message"); + } return; } - } - - byte handshakeType = source[0]; - if (handshakeHash.isHashable(handshakeType)) { - handshakeHash.deliver(source, offset, length); - } - - int fragLimit = getFragLimit(); - int position = headerSize + writeCipher.getExplicitNonceSize(); - if (count == 0) { - count = position; - } - - if ((count - position) < (fragLimit - length)) { - write(source, offset, length); - return; - } - - for (int limit = (offset + length); offset < limit;) { - - int remains = (limit - offset) + (count - position); - int fragLen = Math.min(fragLimit, remains); // use the buf of ByteArrayOutputStream - write(source, offset, fragLen); - if (remains < fragLimit) { + int position = headerSize + writeCipher.getExplicitNonceSize(); + count = position; + + write((byte)1); // byte 1: change_cipher_spec( + + // Encrypt the fragment and wrap up a record. + encrypt(writeCipher, ContentType.CHANGE_CIPHER_SPEC.id, headerSize); + + // deliver this message + deliverStream.write(buf, 0, count); // may throw IOException + // deliverStream.flush(); // flush in Finished + + if (SSLLogger.isOn && SSLLogger.isOn("packet")) { + SSLLogger.fine("Raw write", + (new ByteArrayInputStream(buf, 0, count))); + } + + // reset the internal buffer + count = 0; + } finally { + recordLock.unlock(); + } + } + + @Override + public void flush() throws IOException { + recordLock.lock(); + try { + int position = headerSize + writeCipher.getExplicitNonceSize(); + if (count <= position) { return; } @@ -190,155 +273,103 @@ final class SSLSocketOutputRecord extends OutputRecord implements SSLRecord { (new ByteArrayInputStream(buf, 0, count))); } - // reset the offset - offset += fragLen; - // reset the internal buffer - count = position; + count = 0; // DON'T use position + } finally { + recordLock.unlock(); } } @Override - synchronized void encodeChangeCipherSpec() throws IOException { - if (isClosed()) { - if (SSLLogger.isOn && SSLLogger.isOn("ssl")) { - SSLLogger.warning("outbound has closed, ignore outbound " + - "change_cipher_spec message"); - } - return; - } - - // use the buf of ByteArrayOutputStream - int position = headerSize + writeCipher.getExplicitNonceSize(); - count = position; - - write((byte)1); // byte 1: change_cipher_spec( - - // Encrypt the fragment and wrap up a record. - encrypt(writeCipher, ContentType.CHANGE_CIPHER_SPEC.id, headerSize); - - // deliver this message - deliverStream.write(buf, 0, count); // may throw IOException - // deliverStream.flush(); // flush in Finished - - if (SSLLogger.isOn && SSLLogger.isOn("packet")) { - SSLLogger.fine("Raw write", - (new ByteArrayInputStream(buf, 0, count))); - } - - // reset the internal buffer - count = 0; - } - - @Override - public synchronized void flush() throws IOException { - int position = headerSize + writeCipher.getExplicitNonceSize(); - if (count <= position) { - return; - } - - if (SSLLogger.isOn && SSLLogger.isOn("record")) { - SSLLogger.fine( - "WRITE: " + protocolVersion + - " " + ContentType.HANDSHAKE.name + - ", length = " + (count - headerSize)); - } - - // Encrypt the fragment and wrap up a record. - encrypt(writeCipher, ContentType.HANDSHAKE.id, headerSize); - - // deliver this message - deliverStream.write(buf, 0, count); // may throw IOException - deliverStream.flush(); // may throw IOException - - if (SSLLogger.isOn && SSLLogger.isOn("packet")) { - SSLLogger.fine("Raw write", - (new ByteArrayInputStream(buf, 0, count))); - } - - // reset the internal buffer - count = 0; // DON'T use position - } - - @Override - synchronized void deliver( - byte[] source, int offset, int length) throws IOException { - if (isClosed()) { - throw new SocketException("Connection or outbound has been closed"); - } - - if (writeCipher.authenticator.seqNumOverflow()) { - if (SSLLogger.isOn && SSLLogger.isOn("ssl")) { - SSLLogger.fine( - "sequence number extremely close to overflow " + - "(2^64-1 packets). Closing connection."); + void deliver(byte[] source, int offset, int length) throws IOException { + recordLock.lock(); + try { + if (isClosed()) { + throw new SocketException( + "Connection or outbound has been closed"); } - throw new SSLHandshakeException("sequence number overflow"); - } + if (writeCipher.authenticator.seqNumOverflow()) { + if (SSLLogger.isOn && SSLLogger.isOn("ssl")) { + SSLLogger.fine( + "sequence number extremely close to overflow " + + "(2^64-1 packets). Closing connection."); + } - boolean isFirstRecordOfThePayload = true; - for (int limit = (offset + length); offset < limit;) { - int fragLen; - if (packetSize > 0) { - fragLen = Math.min(maxRecordSize, packetSize); - fragLen = - writeCipher.calculateFragmentSize(fragLen, headerSize); - - fragLen = Math.min(fragLen, Record.maxDataSize); - } else { - fragLen = Record.maxDataSize; + throw new SSLHandshakeException("sequence number overflow"); } - if (fragmentSize > 0) { - fragLen = Math.min(fragLen, fragmentSize); + boolean isFirstRecordOfThePayload = true; + for (int limit = (offset + length); offset < limit;) { + int fragLen; + if (packetSize > 0) { + fragLen = Math.min(maxRecordSize, packetSize); + fragLen = writeCipher.calculateFragmentSize( + fragLen, headerSize); + + fragLen = Math.min(fragLen, Record.maxDataSize); + } else { + fragLen = Record.maxDataSize; + } + + if (fragmentSize > 0) { + fragLen = Math.min(fragLen, fragmentSize); + } + + if (isFirstRecordOfThePayload && needToSplitPayload()) { + fragLen = 1; + isFirstRecordOfThePayload = false; + } else { + fragLen = Math.min(fragLen, (limit - offset)); + } + + // use the buf of ByteArrayOutputStream + int position = headerSize + writeCipher.getExplicitNonceSize(); + count = position; + write(source, offset, fragLen); + + if (SSLLogger.isOn && SSLLogger.isOn("record")) { + SSLLogger.fine( + "WRITE: " + protocolVersion + + " " + ContentType.APPLICATION_DATA.name + + ", length = " + (count - position)); + } + + // Encrypt the fragment and wrap up a record. + encrypt(writeCipher, + ContentType.APPLICATION_DATA.id, headerSize); + + // deliver this message + deliverStream.write(buf, 0, count); // may throw IOException + deliverStream.flush(); // may throw IOException + + if (SSLLogger.isOn && SSLLogger.isOn("packet")) { + SSLLogger.fine("Raw write", + (new ByteArrayInputStream(buf, 0, count))); + } + + // reset the internal buffer + count = 0; + + if (isFirstAppOutputRecord) { + isFirstAppOutputRecord = false; + } + + offset += fragLen; } - - if (isFirstRecordOfThePayload && needToSplitPayload()) { - fragLen = 1; - isFirstRecordOfThePayload = false; - } else { - fragLen = Math.min(fragLen, (limit - offset)); - } - - // use the buf of ByteArrayOutputStream - int position = headerSize + writeCipher.getExplicitNonceSize(); - count = position; - write(source, offset, fragLen); - - if (SSLLogger.isOn && SSLLogger.isOn("record")) { - SSLLogger.fine( - "WRITE: " + protocolVersion + - " " + ContentType.APPLICATION_DATA.name + - ", length = " + (count - position)); - } - - // Encrypt the fragment and wrap up a record. - encrypt(writeCipher, ContentType.APPLICATION_DATA.id, headerSize); - - // deliver this message - deliverStream.write(buf, 0, count); // may throw IOException - deliverStream.flush(); // may throw IOException - - if (SSLLogger.isOn && SSLLogger.isOn("packet")) { - SSLLogger.fine("Raw write", - (new ByteArrayInputStream(buf, 0, count))); - } - - // reset the internal buffer - count = 0; - - if (isFirstAppOutputRecord) { - isFirstAppOutputRecord = false; - } - - offset += fragLen; + } finally { + recordLock.unlock(); } } @Override - synchronized void setDeliverStream(OutputStream outputStream) { - this.deliverStream = outputStream; + void setDeliverStream(OutputStream outputStream) { + recordLock.lock(); + try { + this.deliverStream = outputStream; + } finally { + recordLock.unlock(); + } } /* diff --git a/src/java.base/share/classes/sun/security/ssl/SunX509KeyManagerImpl.java b/src/java.base/share/classes/sun/security/ssl/SunX509KeyManagerImpl.java index 17e2ffd4831..f9d19c4c45e 100644 --- a/src/java.base/share/classes/sun/security/ssl/SunX509KeyManagerImpl.java +++ b/src/java.base/share/classes/sun/security/ssl/SunX509KeyManagerImpl.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2019, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -102,25 +102,21 @@ final class SunX509KeyManagerImpl extends X509ExtendedKeyManager { * Basic container for credentials implemented as an inner class. */ private static class X509Credentials { - PrivateKey privateKey; - X509Certificate[] certificates; - private Set issuerX500Principals; + final PrivateKey privateKey; + final X509Certificate[] certificates; + private final Set issuerX500Principals; X509Credentials(PrivateKey privateKey, X509Certificate[] certificates) { // assert privateKey and certificates != null this.privateKey = privateKey; this.certificates = certificates; + this.issuerX500Principals = new HashSet<>(certificates.length); + for (X509Certificate certificate : certificates) { + issuerX500Principals.add(certificate.getIssuerX500Principal()); + } } - synchronized Set getIssuerX500Principals() { - // lazy initialization - if (issuerX500Principals == null) { - issuerX500Principals = new HashSet(); - for (int i = 0; i < certificates.length; i++) { - issuerX500Principals.add( - certificates[i].getIssuerX500Principal()); - } - } + Set getIssuerX500Principals() { return issuerX500Principals; } } diff --git a/src/java.base/share/classes/sun/security/ssl/TransportContext.java b/src/java.base/share/classes/sun/security/ssl/TransportContext.java index cdba43ffdf5..dd8d18a23f9 100644 --- a/src/java.base/share/classes/sun/security/ssl/TransportContext.java +++ b/src/java.base/share/classes/sun/security/ssl/TransportContext.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2019, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -496,13 +496,16 @@ class TransportContext implements ConnectionContext { } if (needCloseNotify) { - synchronized (outputRecord) { + outputRecord.recordLock.lock(); + try { try { // send a close_notify alert warning(Alert.CLOSE_NOTIFY); } finally { outputRecord.close(); } + } finally { + outputRecord.recordLock.unlock(); } } } @@ -541,7 +544,8 @@ class TransportContext implements ConnectionContext { // Need a lock here so that the user_canceled alert and the // close_notify alert can be delivered together. - synchronized (outputRecord) { + outputRecord.recordLock.lock(); + try { try { // send a user_canceled alert if needed. if (useUserCanceled) { @@ -553,6 +557,8 @@ class TransportContext implements ConnectionContext { } finally { outputRecord.close(); } + } finally { + outputRecord.recordLock.unlock(); } } diff --git a/src/java.base/share/classes/sun/security/ssl/TrustStoreManager.java b/src/java.base/share/classes/sun/security/ssl/TrustStoreManager.java index 71e79584b79..ba0639ec867 100644 --- a/src/java.base/share/classes/sun/security/ssl/TrustStoreManager.java +++ b/src/java.base/share/classes/sun/security/ssl/TrustStoreManager.java @@ -30,6 +30,7 @@ import java.lang.ref.WeakReference; import java.security.*; import java.security.cert.*; import java.util.*; +import java.util.concurrent.locks.ReentrantLock; import sun.security.action.*; import sun.security.validator.TrustStoreUtil; @@ -244,6 +245,8 @@ final class TrustStoreManager { // objects can be atomically cleared, and reloaded if needed. private WeakReference> csRef; + private final ReentrantLock tamLock = new ReentrantLock(); + private TrustAnchorManager() { this.descriptor = null; this.ksRef = new WeakReference<>(null); @@ -255,7 +258,7 @@ final class TrustStoreManager { * * @return null if the underlying KeyStore is not available. */ - synchronized KeyStore getKeyStore( + KeyStore getKeyStore( TrustStoreDescriptor descriptor) throws Exception { TrustStoreDescriptor temporaryDesc = this.descriptor; @@ -264,14 +267,25 @@ final class TrustStoreManager { return ks; } - // Reload a new key store. - if (SSLLogger.isOn && SSLLogger.isOn("trustmanager")) { - SSLLogger.fine("Reload the trust store"); - } + tamLock.lock(); + try { + // double check + ks = ksRef.get(); + if ((ks != null) && descriptor.equals(temporaryDesc)) { + return ks; + } - ks = loadKeyStore(descriptor); - this.descriptor = descriptor; - this.ksRef = new WeakReference<>(ks); + // Reload a new key store. + if (SSLLogger.isOn && SSLLogger.isOn("trustmanager")) { + SSLLogger.fine("Reload the trust store"); + } + + ks = loadKeyStore(descriptor); + this.descriptor = descriptor; + this.ksRef = new WeakReference<>(ks); + } finally { + tamLock.unlock(); + } return ks; } @@ -282,51 +296,62 @@ final class TrustStoreManager { * * @return empty collection if the underlying KeyStore is not available. */ - synchronized Set getTrustedCerts( + Set getTrustedCerts( TrustStoreDescriptor descriptor) throws Exception { KeyStore ks = null; TrustStoreDescriptor temporaryDesc = this.descriptor; Set certs = csRef.get(); - if (certs != null) { - if (descriptor.equals(temporaryDesc)) { - return certs; - } else { - // Use the new descriptor. - this.descriptor = descriptor; - } - } else { - // Try to use the cached store at first. - if (descriptor.equals(temporaryDesc)) { - ks = ksRef.get(); - } else { - // Use the new descriptor. - this.descriptor = descriptor; - } + if ((certs != null) && descriptor.equals(temporaryDesc)) { + return certs; } - // Reload the trust store if needed. - if (ks == null) { + tamLock.lock(); + try { + // double check + temporaryDesc = this.descriptor; + certs = csRef.get(); + if (certs != null) { + if (descriptor.equals(temporaryDesc)) { + return certs; + } else { + // Use the new descriptor. + this.descriptor = descriptor; + } + } else { + // Try to use the cached store at first. + if (descriptor.equals(temporaryDesc)) { + ks = ksRef.get(); + } else { + // Use the new descriptor. + this.descriptor = descriptor; + } + } + + // Reload the trust store if needed. + if (ks == null) { + if (SSLLogger.isOn && SSLLogger.isOn("trustmanager")) { + SSLLogger.fine("Reload the trust store"); + } + ks = loadKeyStore(descriptor); + this.ksRef = new WeakReference<>(ks); + } + + // Reload trust certs from the key store. if (SSLLogger.isOn && SSLLogger.isOn("trustmanager")) { - SSLLogger.fine("Reload the trust store"); + SSLLogger.fine("Reload trust certs"); } - ks = loadKeyStore(descriptor); - } - // Reload trust certs from the key store. - if (SSLLogger.isOn && SSLLogger.isOn("trustmanager")) { - SSLLogger.fine("Reload trust certs"); - } + certs = loadTrustedCerts(ks); + if (SSLLogger.isOn && SSLLogger.isOn("trustmanager")) { + SSLLogger.fine("Reloaded " + certs.size() + " trust certs"); + } - certs = loadTrustedCerts(ks); - if (SSLLogger.isOn && SSLLogger.isOn("trustmanager")) { - SSLLogger.fine("Reloaded " + certs.size() + " trust certs"); + this.csRef = new WeakReference<>(certs); + } finally { + tamLock.unlock(); } - // Note that as ks is a local variable, it is not - // necessary to add it to the ksRef weak reference. - this.csRef = new WeakReference<>(certs); - return certs; } diff --git a/src/java.base/share/classes/sun/security/ssl/X509TrustManagerImpl.java b/src/java.base/share/classes/sun/security/ssl/X509TrustManagerImpl.java index 9e5d9665160..00e99ba3bca 100644 --- a/src/java.base/share/classes/sun/security/ssl/X509TrustManagerImpl.java +++ b/src/java.base/share/classes/sun/security/ssl/X509TrustManagerImpl.java @@ -29,6 +29,7 @@ import java.net.Socket; import java.security.*; import java.security.cert.*; import java.util.*; +import java.util.concurrent.locks.ReentrantLock; import javax.net.ssl.*; import sun.security.util.AnchorCertificates; import sun.security.util.HostnameChecker; @@ -63,6 +64,8 @@ final class X509TrustManagerImpl extends X509ExtendedTrustManager // the different extension checks. They are initialized lazily on demand. private volatile Validator clientValidator, serverValidator; + private final ReentrantLock validatorLock = new ReentrantLock(); + X509TrustManagerImpl(String validatorType, Collection trustedCerts) { @@ -157,12 +160,15 @@ final class X509TrustManagerImpl extends X509ExtendedTrustManager if (isClient) { v = clientValidator; if (v == null) { - synchronized (this) { + validatorLock.lock(); + try { v = clientValidator; if (v == null) { v = getValidator(Validator.VAR_TLS_CLIENT); clientValidator = v; } + } finally { + validatorLock.unlock(); } } } else { @@ -170,12 +176,15 @@ final class X509TrustManagerImpl extends X509ExtendedTrustManager // (guaranteed under the new Tiger memory model) v = serverValidator; if (v == null) { - synchronized (this) { + validatorLock.lock(); + try { v = serverValidator; if (v == null) { v = getValidator(Validator.VAR_TLS_SERVER); serverValidator = v; } + } finally { + validatorLock.unlock(); } } } From 0abdc381b72f9dca86ac8f9c8943980eda7fd853 Mon Sep 17 00:00:00 2001 From: Jonathan Gibbons Date: Fri, 5 Apr 2019 15:57:33 -0700 Subject: [PATCH 34/73] 8221871: javadoc should not set role=region on

elements Reviewed-by: hannesw --- .../doclets/formats/html/markup/HtmlTree.java | 8 +- .../doclet/testHtmlTag/TestHtmlTag.java | 2 +- .../testHtmlVersion/TestHtmlVersion.java | 76 +++++++++---------- .../doclet/testModules/TestModules.java | 4 +- .../doclet/testUseOption/TestUseOption.java | 2 +- 5 files changed, 44 insertions(+), 48 deletions(-) diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/markup/HtmlTree.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/markup/HtmlTree.java index 47ddf05b630..27c89b03168 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/markup/HtmlTree.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/markup/HtmlTree.java @@ -722,9 +722,7 @@ public class HtmlTree extends Content { * @return an HtmlTree object for the SECTION tag */ public static HtmlTree SECTION() { - HtmlTree htmltree = new HtmlTree(HtmlTag.SECTION); - htmltree.setRole(Role.REGION); - return htmltree; + return new HtmlTree(HtmlTag.SECTION); } /** @@ -734,9 +732,7 @@ public class HtmlTree extends Content { * @return an HtmlTree object for the SECTION tag */ public static HtmlTree SECTION(Content body) { - HtmlTree htmltree = new HtmlTree(HtmlTag.SECTION, nullCheck(body)); - htmltree.setRole(Role.REGION); - return htmltree; + return new HtmlTree(HtmlTag.SECTION, nullCheck(body)); } /** diff --git a/test/langtools/jdk/javadoc/doclet/testHtmlTag/TestHtmlTag.java b/test/langtools/jdk/javadoc/doclet/testHtmlTag/TestHtmlTag.java index 90257477da3..a57f4847787 100644 --- a/test/langtools/jdk/javadoc/doclet/testHtmlTag/TestHtmlTag.java +++ b/test/langtools/jdk/javadoc/doclet/testHtmlTag/TestHtmlTag.java @@ -109,7 +109,7 @@ public class TestHtmlTag extends JavadocTester { checkOutput("pkg3/package-summary.html", true, "
\n" - + "
\n" + + "
\n" + "\n" + "\n" + "

This is the first line. Note the newlines before the <p> is relevant.

\n" diff --git a/test/langtools/jdk/javadoc/doclet/testHtmlVersion/TestHtmlVersion.java b/test/langtools/jdk/javadoc/doclet/testHtmlVersion/TestHtmlVersion.java index 6ebfabd813b..21b8cdb85b7 100644 --- a/test/langtools/jdk/javadoc/doclet/testHtmlVersion/TestHtmlVersion.java +++ b/test/langtools/jdk/javadoc/doclet/testHtmlVersion/TestHtmlVersion.java @@ -24,7 +24,7 @@ /* * @test * @bug 8072945 8081854 8141492 8148985 8150188 4649116 8173707 8151743 8169819 8183037 8182765 8196202 - * 8202624 8210047 8184205 + * 8202624 8210047 8184205 8221871 * @summary Test the version of HTML generated by the javadoc tool. * @author bpatel * @library ../../lib @@ -100,7 +100,7 @@ public class TestHtmlVersion extends JavadocTester { + "", "
\n" + "
", - "
\n" + "
\n" + "\n" + "\n" + "
Test package.
", @@ -129,13 +129,13 @@ public class TestHtmlVersion extends JavadocTester { + "", "
\n" + "
", - "
\n" + "
\n" + "

Class Hierarchy

", - "
\n" + "
\n" + "

Interface Hierarchy

", - "
\n" + "
\n" + "

Annotation Type Hierarchy

", - "
\n" + "
\n" + "

Enum Hierarchy

", "