--- a/.hgtags Fri May 17 13:21:44 2019 +0100
+++ b/.hgtags Thu May 23 11:07:37 2019 +0100
@@ -559,3 +559,4 @@
a43d6467317d8f1e160f67aadec37919c9d64443 jdk-13+19
6ccc7cd7931e34129f6b7e04988fc9a63958dde0 jdk-13+20
f2f11d7f7f4e7128f8aba6ffa576cfa76fbf7d1a jdk-13+21
+181986c5476468bc2dd4532af49599003ee8af37 jdk-13+22
--- a/doc/building.html Fri May 17 13:21:44 2019 +0100
+++ b/doc/building.html Thu May 23 11:07:37 2019 +0100
@@ -297,6 +297,10 @@
</tr>
</tbody>
</table>
+<p>All compilers are expected to be able to compile to the C99 language standard,
+as some C99 features are used in the source code. Microsoft Visual Studio
+doesn't fully support C99 so in practice shared code is limited to using C99
+features that it does support.</p>
<h3 id="gcc">gcc</h3>
<p>The minimum accepted version of gcc is 4.8. Older versions will generate a warning by <code>configure</code> and are unlikely to work.</p>
<p>The JDK is currently known to be able to compile with at least version 7.4 of gcc.</p>
--- a/doc/building.md Fri May 17 13:21:44 2019 +0100
+++ b/doc/building.md Thu May 23 11:07:37 2019 +0100
@@ -328,6 +328,11 @@
Solaris Oracle Solaris Studio 12.6 (with compiler version 5.15)
Windows Microsoft Visual Studio 2017 update 15.9.6
+All compilers are expected to be able to compile to the C99 language standard,
+as some C99 features are used in the source code. Microsoft Visual Studio
+doesn't fully support C99 so in practice shared code is limited to using C99
+features that it does support.
+
### gcc
The minimum accepted version of gcc is 4.8. Older versions will generate a warning
--- a/make/Docs.gmk Fri May 17 13:21:44 2019 +0100
+++ b/make/Docs.gmk Thu May 23 11:07:37 2019 +0100
@@ -85,13 +85,14 @@
-tag param \
-tag return \
-tag throws \
+ -taglet build.tools.taglet.JSpec\$$JLS \
+ -taglet build.tools.taglet.JSpec\$$JVMS \
-taglet build.tools.taglet.ModuleGraph \
+ -taglet build.tools.taglet.ToolGuide \
-tag since \
-tag serialData \
-tag factory \
-tag see \
- -tag 'jvms:a:See <cite>The Java™ Virtual Machine Specification</cite>:' \
- -tag 'jls:a:See <cite>The Java™ Language Specification</cite>:' \
-taglet build.tools.taglet.ExtLink \
-taglet build.tools.taglet.Incubating \
-tagletpath $(BUILDTOOLS_OUTPUTDIR)/jdk_tools_classes \
@@ -275,7 +276,8 @@
$1_INDIRECT_EXPORTS := $$(call FindTransitiveIndirectDepsForModules, $$($1_MODULES))
$1_ALL_MODULES := $$(sort $$($1_MODULES) $$($1_INDIRECT_EXPORTS))
- $1_JAVA_ARGS := -Dextlink.spec.version=$$(VERSION_SPECIFICATION)
+ $1_JAVA_ARGS := -Dextlink.spec.version=$$(VERSION_SPECIFICATION) \
+ -Djspec.version=$$(VERSION_SPECIFICATION)
ifeq ($$(ENABLE_FULL_DOCS), true)
# Tell the ModuleGraph taglet to generate html links to soon-to-be-created
--- a/make/autoconf/flags-cflags.m4 Fri May 17 13:21:44 2019 +0100
+++ b/make/autoconf/flags-cflags.m4 Thu May 23 11:07:37 2019 +0100
@@ -300,6 +300,20 @@
C_O_FLAG_DEBUG="-O0"
C_O_FLAG_DEBUG_JVM="-O0"
C_O_FLAG_NONE="-O0"
+ # -D_FORTIFY_SOURCE=2 hardening option needs optimization (at least -O1) enabled
+ # set for lower O-levels -U_FORTIFY_SOURCE to overwrite previous settings
+ if test "x$OPENJDK_TARGET_OS" = xlinux -a "x$DEBUG_LEVEL" = "xfastdebug"; then
+ ENABLE_FORTIFY_CFLAGS="-D_FORTIFY_SOURCE=2"
+ DISABLE_FORTIFY_CFLAGS="-U_FORTIFY_SOURCE"
+ C_O_FLAG_HIGHEST_JVM="${C_O_FLAG_HIGHEST_JVM} ${ENABLE_FORTIFY_CFLAGS}"
+ C_O_FLAG_HIGHEST="${C_O_FLAG_HIGHEST} ${ENABLE_FORTIFY_CFLAGS}"
+ C_O_FLAG_HI="${C_O_FLAG_HI} ${ENABLE_FORTIFY_CFLAGS}"
+ C_O_FLAG_NORM="${C_O_FLAG_NORM} ${ENABLE_FORTIFY_CFLAGS}"
+ C_O_FLAG_SIZE="${C_O_FLAG_SIZE} ${DISABLE_FORTIFY_CFLAGS}"
+ C_O_FLAG_DEBUG="${C_O_FLAG_DEBUG} ${DISABLE_FORTIFY_CFLAGS}"
+ C_O_FLAG_DEBUG_JVM="${C_O_FLAG_DEBUG_JVM} ${DISABLE_FORTIFY_CFLAGS}"
+ C_O_FLAG_NONE="${C_O_FLAG_NONE} ${DISABLE_FORTIFY_CFLAGS}"
+ fi
elif test "x$TOOLCHAIN_TYPE" = xclang; then
if test "x$OPENJDK_TARGET_OS" = xmacosx; then
# On MacOSX we optimize for size, something
@@ -550,7 +564,7 @@
TOOLCHAIN_CFLAGS="-errshort=tags"
TOOLCHAIN_CFLAGS_JDK="-mt $TOOLCHAIN_FLAGS"
- TOOLCHAIN_CFLAGS_JDK_CONLY="-xCC -Xa -W0,-noglobal $TOOLCHAIN_CFLAGS" # C only
+ TOOLCHAIN_CFLAGS_JDK_CONLY="-W0,-noglobal $TOOLCHAIN_CFLAGS" # C only
TOOLCHAIN_CFLAGS_JDK_CXXONLY="-features=no%except -norunpath -xnolib" # CXX only
TOOLCHAIN_CFLAGS_JVM="-template=no%extdef -features=no%split_init \
-library=stlport4 -mt -features=no%except $TOOLCHAIN_FLAGS"
@@ -571,6 +585,30 @@
TOOLCHAIN_CFLAGS_JDK="-nologo -MD -Zc:wchar_t-"
fi
+ # CFLAGS C language level for JDK sources (hotspot only uses C++)
+ # Ideally we would have a common level across all toolchains so that all sources
+ # are sure to conform to the same standard. Unfortunately neither our sources nor
+ # our toolchains are in a condition to support that. But what we loosely aim for is
+ # C99 level.
+ if test "x$TOOLCHAIN_TYPE" = xgcc || test "x$TOOLCHAIN_TYPE" = xclang || test "x$TOOLCHAIN_TYPE" = xxlc; then
+ # This raises the language level for older 4.8 gcc, while lowering it for later
+ # versions. clang and xlclang support the same flag.
+ LANGSTD_CFLAGS="-std=c99"
+ elif test "x$TOOLCHAIN_TYPE" = xsolstudio; then
+ # We can't turn on -std=c99 without breaking compilation of the splashscreen/png
+ # utilities. But we can enable c99 as below (previously achieved by using -Xa).
+ # It is the no_lib that makes the difference.
+ LANGSTD_CFLAGS="-xc99=all,no_lib"
+ elif test "x$TOOLCHAIN_TYPE" = xmicrosoft; then
+ # MSVC doesn't support C99/C11 explicitly, unless you compile as C++:
+ # LANGSTD_CFLAGS="/TP"
+ # but that requires numerous changes to the sources files. So we are limited
+ # to C89/C90 plus whatever extensions Visual Studio has decided to implement.
+ # This is the lowest bar for shared code.
+ LANGSTD_CFLAGS=""
+ fi
+ TOOLCHAIN_CFLAGS_JDK_CONLY="$LANGSTD_CFLAGS $TOOLCHAIN_CFLAGS_JDK_CONLY"
+
# CFLAGS WARNINGS STUFF
# Set JVM_CFLAGS warning handling
if test "x$TOOLCHAIN_TYPE" = xgcc; then
--- a/make/hotspot/lib/JvmFeatures.gmk Fri May 17 13:21:44 2019 +0100
+++ b/make/hotspot/lib/JvmFeatures.gmk Thu May 23 11:07:37 2019 +0100
@@ -111,6 +111,7 @@
JVM_EXCLUDE_FILES += \
classListParser.cpp \
classLoaderExt.cpp \
+ dynamicArchive.cpp \
filemap.cpp \
heapShared.cpp \
metaspaceShared.cpp \
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/make/jdk/src/classes/build/tools/taglet/JSpec.java Thu May 23 11:07:37 2019 +0100
@@ -0,0 +1,192 @@
+/*
+ * Copyright (c) 2017, 2019, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * 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 build.tools.taglet;
+
+import java.util.EnumSet;
+import java.util.List;
+import java.util.Set;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+import javax.lang.model.element.Element;
+
+import com.sun.source.doctree.DocTree;
+import com.sun.source.doctree.LiteralTree;
+import com.sun.source.doctree.UnknownBlockTagTree;
+import com.sun.source.util.SimpleDocTreeVisitor;
+import jdk.javadoc.doclet.Taglet;
+
+import static com.sun.source.doctree.DocTree.Kind.*;
+
+/**
+ * A base class for block tags to insert a link to an external copy of JLS or JVMS.
+ * The tags can be used as follows:
+ *
+ * <pre>
+ * @jls section-number description
+ * </pre>
+ *
+ * For example:
+ *
+ * <pre>
+ * @jls 3.4 Line Terminators
+ * </pre>
+ *
+ * will produce the following HTML for a docs build configured for Java SE 12.
+ *
+ * <pre>{@code
+ * <dt>See <i>Java Language Specification</i>:
+ * <dd><a href="https://docs.oracle.com/javase/specs/jls/se12/html/jls-3.html#jls-3.4">3.4 Line terminators</a>
+ * }</pre>
+ *
+ * The version of the spec must be set in the jspec.version system property.
+ */
+public class JSpec implements Taglet {
+ static final String SPEC_VERSION;
+
+ static {
+ SPEC_VERSION = System.getProperty("jspec.version");
+ if (SPEC_VERSION == null) {
+ throw new RuntimeException("jspec.version property not set");
+ }
+ }
+
+ public static class JLS extends JSpec {
+ public JLS() {
+ super("jls",
+ "Java Language Specification",
+ "https://docs.oracle.com/javase/specs/jls/se" + SPEC_VERSION + "/html",
+ "jls");
+ }
+ }
+
+ public static class JVMS extends JSpec {
+ public JVMS() {
+ super("jvms",
+ "Java Virtual Machine Specification",
+ "https://docs.oracle.com/javase/specs/jvms/se" + SPEC_VERSION + "/html",
+ "jvms");
+ }
+ }
+
+ private String tagName;
+ private String specTitle;
+ private String baseURL;
+ private String idPrefix;
+
+ protected JSpec(String tagName, String specTitle, String baseURL, String idPrefix) {
+ this.tagName = tagName;
+ this.specTitle = specTitle;
+ this.baseURL = baseURL;
+ this.idPrefix = idPrefix;
+ }
+
+
+ static final Pattern TAG_PATTERN = Pattern.compile("(?s)(.+ )?(?<chapter>[1-9][0-9]*)(?<section>[0-9.]*)( .*)?$");
+
+
+ /**
+ * Returns the set of locations in which the tag may be used.
+ */
+ @Override
+ public Set<Location> getAllowedLocations() {
+ return EnumSet.allOf(jdk.javadoc.doclet.Taglet.Location.class);
+ }
+
+ @Override
+ public boolean isInlineTag() {
+ return false;
+ }
+
+ @Override
+ public String getName() {
+ return tagName;
+ }
+
+ @Override
+ public String toString(List<? extends DocTree> tags, Element elem) {
+
+ if (tags.isEmpty())
+ return "";
+
+ StringBuilder sb = new StringBuilder();
+ sb.append("<dt>See <i>" + specTitle + "</i>:</dt>\n")
+ .append("<dd>\n");
+
+ for (DocTree tag : tags) {
+
+ if (tag.getKind() != UNKNOWN_BLOCK_TAG) {
+ continue;
+ }
+
+ UnknownBlockTagTree blockTag = (UnknownBlockTagTree)tag;
+ String tagText = blockTag.getContent().toString().trim();
+ Matcher m = TAG_PATTERN.matcher(tagText);
+ if (m.find()) {
+ String chapter = m.group("chapter");
+ String section = m.group("section");
+
+ String url = String.format("%1$s/%2$s-%3$s.html#jls-%3$s%4$s",
+ baseURL, idPrefix, chapter, section);
+
+
+ sb.append("<a href=\"")
+ .append(url)
+ .append("\">")
+ .append(expand(blockTag))
+ .append("</a><br>");
+ }
+
+ }
+
+ sb.append("</dd>");
+
+ return sb.toString();
+ }
+
+ private String expand(UnknownBlockTagTree tree) {
+ StringBuilder sb = new StringBuilder();
+ return (new SimpleDocTreeVisitor<StringBuilder, StringBuilder>() {
+ public StringBuilder defaultAction(DocTree tree, StringBuilder sb) {
+ return sb.append(tree.toString());
+ }
+
+ public StringBuilder visitLiteral(LiteralTree tree, StringBuilder sb) {
+ if (tree.getKind() == CODE) {
+ sb.append("<code>");
+ }
+ sb.append(escape(tree.getBody().toString()));
+ if (tree.getKind() == CODE) {
+ sb.append("</code>");
+ }
+ return sb;
+ }
+
+ private String escape(String s) {
+ return s.replace("&", "&").replace("<", "<").replace(">", ">");
+ }
+ }).visit(tree.getContent(), new StringBuilder()).toString();
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/make/jdk/src/classes/build/tools/taglet/ToolGuide.java Thu May 23 11:07:37 2019 +0100
@@ -0,0 +1,159 @@
+/*
+ * Copyright (c) 2017, 2019, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * 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 build.tools.taglet;
+
+import java.util.EnumSet;
+import java.util.List;
+import java.util.Set;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+import javax.lang.model.element.Element;
+import javax.lang.model.element.ModuleElement;
+import javax.lang.model.element.PackageElement;
+
+import com.sun.source.doctree.DocTree;
+import com.sun.source.doctree.UnknownBlockTagTree;
+import jdk.javadoc.doclet.Taglet;
+
+import static com.sun.source.doctree.DocTree.Kind.*;
+import static jdk.javadoc.doclet.Taglet.Location.*;
+
+/**
+ * A block tag to insert a link to tool guide in a nearby directory.
+ * The tag can be used as follows:
+ * <ul>
+ * <li>@toolGuide tool-name label
+ * </ul>
+ *
+ * If the label is omitted, it defaults to the tool name.
+ *
+ * For example
+ * <p>
+ * @toolGuide javac
+ * <p>
+ * will produce the following html, depending on the file containing
+ * the tag.
+ * <p>
+ * {@code
+ * <dt>Tool Guides:
+ * <dd><a href="../../specs/man/javac.html">javac</a>
+ * }
+ */
+public class ToolGuide implements Taglet {
+
+ static final String TAG_NAME = "toolGuide";
+
+ static final String BASE_URL = "../specs/man";
+
+ static final Pattern TAG_PATTERN = Pattern.compile("(?s)(?<name>[A-Za-z0-9]+)\\s*(?<label>.*)$");
+
+ /**
+ * Returns the set of locations in which the tag may be used.
+ */
+ @Override
+ public Set<Location> getAllowedLocations() {
+ return EnumSet.of(MODULE, PACKAGE);
+ }
+
+ @Override
+ public boolean isInlineTag() {
+ return false;
+ }
+
+ @Override
+ public String getName() {
+ return TAG_NAME;
+ }
+
+ @Override
+ public String toString(List<? extends DocTree> tags, Element elem) {
+
+ if (tags.isEmpty())
+ return "";
+
+ StringBuilder sb = new StringBuilder();
+ sb.append("<dt class=\"simpleTagLabel\">Tool Guides:</dt>\n")
+ .append("<dd>");
+
+ boolean needComma = false;
+ for (DocTree tag : tags) {
+
+ if (tag.getKind() != UNKNOWN_BLOCK_TAG) {
+ continue;
+ }
+
+ UnknownBlockTagTree blockTag = (UnknownBlockTagTree)tag;
+ String tagText = blockTag.getContent().toString().trim();
+ Matcher m = TAG_PATTERN.matcher(tagText);
+ if (m.matches()) {
+ String name = m.group("name");
+ String label = m.group("label");
+ if (label.isEmpty()) {
+ label = name;
+ }
+
+ String url = String.format("%s/%s/%s.html",
+ docRoot(elem), BASE_URL, name);
+
+ if (needComma) {
+ sb.append(",\n");
+ } else {
+ needComma = true;
+ }
+
+ sb.append("<a href=\"")
+ .append(url)
+ .append("\">")
+ .append(label)
+ .append("</a>");
+ }
+ }
+
+ sb.append("</dd>\n");
+
+ return sb.toString();
+ }
+
+ private String docRoot(Element elem) {
+ switch (elem.getKind()) {
+ case MODULE:
+ return "..";
+
+ case PACKAGE:
+ PackageElement pe = (PackageElement)elem;
+ String pkgPart = pe.getQualifiedName()
+ .toString()
+ .replace('.', '/')
+ .replaceAll("[^/]+", "..");
+ return pe.getEnclosingElement() != null
+ ? "../" + pkgPart
+ : pkgPart;
+
+ default:
+ throw new IllegalArgumentException(elem.getKind().toString());
+ }
+ }
+}
--- a/make/lib/Awt2dLibraries.gmk Fri May 17 13:21:44 2019 +0100
+++ b/make/lib/Awt2dLibraries.gmk Thu May 23 11:07:37 2019 +0100
@@ -378,7 +378,6 @@
OPTIMIZATION := HIGHEST, \
CFLAGS := $(CFLAGS_JDKLIB) \
$(LCMS_CFLAGS), \
- CFLAGS_solaris := -xc99=no_lib, \
CFLAGS_windows := -DCMS_IS_WINDOWS_, \
EXTRA_HEADER_DIRS := \
common/awt/debug \
--- a/make/test/JtregNativeJdk.gmk Fri May 17 13:21:44 2019 +0100
+++ b/make/test/JtregNativeJdk.gmk Thu May 23 11:07:37 2019 +0100
@@ -62,9 +62,11 @@
WIN_LIB_JLI := $(SUPPORT_OUTPUTDIR)/native/java.base/libjli/jli.lib
BUILD_JDK_JTREG_EXECUTABLES_LIBS_exeJliLaunchTest := $(WIN_LIB_JLI)
BUILD_JDK_JTREG_EXECUTABLES_LIBS_exeCallerAccessTest := jvm.lib
+ BUILD_JDK_JTREG_EXECUTABLES_LIBS_exerevokeall := advapi32.lib
else
BUILD_JDK_JTREG_LIBRARIES_LIBS_libstringPlatformChars := -ljava
BUILD_JDK_JTREG_LIBRARIES_LIBS_libDirectIO := -ljava
+ BUILD_JDK_JTREG_EXCLUDE += exerevokeall.c
ifeq ($(call isTargetOs, linux), true)
BUILD_JDK_JTREG_LIBRARIES_LIBS_libInheritedChannel := -ljava
else ifeq ($(call isTargetOs, solaris), true)
--- a/src/hotspot/cpu/aarch64/assembler_aarch64.hpp Fri May 17 13:21:44 2019 +0100
+++ b/src/hotspot/cpu/aarch64/assembler_aarch64.hpp Thu May 23 11:07:37 2019 +0100
@@ -629,6 +629,14 @@
enum { instruction_size = 4 };
+ //---< calculate length of instruction >---
+ // We just use the values set above.
+ // instruction must start at passed address
+ static unsigned int instr_len(unsigned char *instr) { return instruction_size; }
+
+ //---< longest instructions >---
+ static unsigned int instr_maxlen() { return instruction_size; }
+
Address adjust(Register base, int offset, bool preIncrement) {
if (preIncrement)
return Address(Pre(base, offset));
--- a/src/hotspot/cpu/aarch64/c2_globals_aarch64.hpp Fri May 17 13:21:44 2019 +0100
+++ b/src/hotspot/cpu/aarch64/c2_globals_aarch64.hpp Thu May 23 11:07:37 2019 +0100
@@ -76,7 +76,7 @@
define_pd_global(intx, NonProfiledCodeHeapSize, 21*M);
define_pd_global(intx, ProfiledCodeHeapSize, 22*M);
define_pd_global(intx, NonNMethodCodeHeapSize, 5*M );
-define_pd_global(uintx, CodeCacheMinBlockLength, 4);
+define_pd_global(uintx, CodeCacheMinBlockLength, 6);
define_pd_global(uintx, CodeCacheMinimumUseSpace, 400*K);
// Heap related flags
--- a/src/hotspot/cpu/aarch64/disassembler_aarch64.hpp Fri May 17 13:21:44 2019 +0100
+++ b/src/hotspot/cpu/aarch64/disassembler_aarch64.hpp Thu May 23 11:07:37 2019 +0100
@@ -34,4 +34,24 @@
return "";
}
+ // Returns address of n-th instruction preceding addr,
+ // NULL if no preceding instruction can be found.
+ // On ARM(aarch64), we assume a constant instruction length.
+ // It might be beneficial to check "is_readable" as we do on ppc and s390.
+ static address find_prev_instr(address addr, int n_instr) {
+ return addr - Assembler::instruction_size*n_instr;
+ }
+
+ // special-case instruction decoding.
+ // There may be cases where the binutils disassembler doesn't do
+ // the perfect job. In those cases, decode_instruction0 may kick in
+ // and do it right.
+ // If nothing had to be done, just return "here", otherwise return "here + instr_len(here)"
+ static address decode_instruction0(address here, outputStream* st, address virtual_begin = NULL) {
+ return here;
+ }
+
+ // platform-specific instruction annotations (like value of loaded constants)
+ static void annotate(address pc, outputStream* st) { };
+
#endif // CPU_AARCH64_DISASSEMBLER_AARCH64_HPP
--- a/src/hotspot/cpu/aarch64/gc/shared/barrierSetAssembler_aarch64.hpp Fri May 17 13:21:44 2019 +0100
+++ b/src/hotspot/cpu/aarch64/gc/shared/barrierSetAssembler_aarch64.hpp Thu May 23 11:07:37 2019 +0100
@@ -37,7 +37,7 @@
public:
virtual void arraycopy_prologue(MacroAssembler* masm, DecoratorSet decorators, bool is_oop,
- Register addr, Register count, RegSet saved_regs) {}
+ Register src, Register dst, Register count, RegSet saved_regs) {}
virtual void arraycopy_epilogue(MacroAssembler* masm, DecoratorSet decorators, bool is_oop,
Register start, Register end, Register tmp, RegSet saved_regs) {}
virtual void load_at(MacroAssembler* masm, DecoratorSet decorators, BasicType type,
--- a/src/hotspot/cpu/aarch64/gc/shared/modRefBarrierSetAssembler_aarch64.cpp Fri May 17 13:21:44 2019 +0100
+++ b/src/hotspot/cpu/aarch64/gc/shared/modRefBarrierSetAssembler_aarch64.cpp Thu May 23 11:07:37 2019 +0100
@@ -29,10 +29,10 @@
#define __ masm->
void ModRefBarrierSetAssembler::arraycopy_prologue(MacroAssembler* masm, DecoratorSet decorators, bool is_oop,
- Register addr, Register count, RegSet saved_regs) {
+ Register src, Register dst, Register count, RegSet saved_regs) {
if (is_oop) {
- gen_write_ref_array_pre_barrier(masm, decorators, addr, count, saved_regs);
+ gen_write_ref_array_pre_barrier(masm, decorators, dst, count, saved_regs);
}
}
--- a/src/hotspot/cpu/aarch64/gc/shared/modRefBarrierSetAssembler_aarch64.hpp Fri May 17 13:21:44 2019 +0100
+++ b/src/hotspot/cpu/aarch64/gc/shared/modRefBarrierSetAssembler_aarch64.hpp Thu May 23 11:07:37 2019 +0100
@@ -44,7 +44,7 @@
public:
virtual void arraycopy_prologue(MacroAssembler* masm, DecoratorSet decorators, bool is_oop,
- Register addr, Register count, RegSet saved_regs);
+ Register src, Register dst, Register count, RegSet saved_regs);
virtual void arraycopy_epilogue(MacroAssembler* masm, DecoratorSet decorators, bool is_oop,
Register start, Register count, Register tmp, RegSet saved_regs);
virtual void store_at(MacroAssembler* masm, DecoratorSet decorators, BasicType type,
--- a/src/hotspot/cpu/aarch64/gc/shenandoah/shenandoahBarrierSetAssembler_aarch64.cpp Fri May 17 13:21:44 2019 +0100
+++ b/src/hotspot/cpu/aarch64/gc/shenandoah/shenandoahBarrierSetAssembler_aarch64.cpp Thu May 23 11:07:37 2019 +0100
@@ -44,7 +44,7 @@
address ShenandoahBarrierSetAssembler::_shenandoah_lrb = NULL;
void ShenandoahBarrierSetAssembler::arraycopy_prologue(MacroAssembler* masm, DecoratorSet decorators, bool is_oop,
- Register addr, Register count, RegSet saved_regs) {
+ Register src, Register dst, Register count, RegSet saved_regs) {
if (is_oop) {
bool dest_uninitialized = (decorators & IS_DEST_UNINITIALIZED) != 0;
if (ShenandoahSATBBarrier && !dest_uninitialized && !ShenandoahHeap::heap()->heuristics()->can_do_traversal_gc()) {
@@ -61,17 +61,17 @@
__ push(saved_regs, sp);
if (count == c_rarg0) {
- if (addr == c_rarg1) {
+ if (dst == c_rarg1) {
// exactly backwards!!
__ mov(rscratch1, c_rarg0);
__ mov(c_rarg0, c_rarg1);
__ mov(c_rarg1, rscratch1);
} else {
__ mov(c_rarg1, count);
- __ mov(c_rarg0, addr);
+ __ mov(c_rarg0, dst);
}
} else {
- __ mov(c_rarg0, addr);
+ __ mov(c_rarg0, dst);
__ mov(c_rarg1, count);
}
if (UseCompressedOops) {
--- a/src/hotspot/cpu/aarch64/gc/shenandoah/shenandoahBarrierSetAssembler_aarch64.hpp Fri May 17 13:21:44 2019 +0100
+++ b/src/hotspot/cpu/aarch64/gc/shenandoah/shenandoahBarrierSetAssembler_aarch64.hpp Thu May 23 11:07:37 2019 +0100
@@ -73,7 +73,7 @@
#endif
virtual void arraycopy_prologue(MacroAssembler* masm, DecoratorSet decorators, bool is_oop,
- Register addr, Register count, RegSet saved_regs);
+ Register src, Register dst, Register count, RegSet saved_regs);
virtual void arraycopy_epilogue(MacroAssembler* masm, DecoratorSet decorators, bool is_oop,
Register start, Register count, Register tmp, RegSet saved_regs);
virtual void load_at(MacroAssembler* masm, DecoratorSet decorators, BasicType type,
--- a/src/hotspot/cpu/aarch64/stubGenerator_aarch64.cpp Fri May 17 13:21:44 2019 +0100
+++ b/src/hotspot/cpu/aarch64/stubGenerator_aarch64.cpp Thu May 23 11:07:37 2019 +0100
@@ -1364,7 +1364,7 @@
}
BarrierSetAssembler *bs = BarrierSet::barrier_set()->barrier_set_assembler();
- bs->arraycopy_prologue(_masm, decorators, is_oop, d, count, saved_reg);
+ bs->arraycopy_prologue(_masm, decorators, is_oop, s, d, count, saved_reg);
if (is_oop) {
// save regs before copy_memory
@@ -1436,7 +1436,7 @@
}
BarrierSetAssembler *bs = BarrierSet::barrier_set()->barrier_set_assembler();
- bs->arraycopy_prologue(_masm, decorators, is_oop, d, count, saved_regs);
+ bs->arraycopy_prologue(_masm, decorators, is_oop, s, d, count, saved_regs);
if (is_oop) {
// save regs before copy_memory
@@ -1796,7 +1796,7 @@
}
BarrierSetAssembler *bs = BarrierSet::barrier_set()->barrier_set_assembler();
- bs->arraycopy_prologue(_masm, decorators, is_oop, to, count, wb_pre_saved_regs);
+ bs->arraycopy_prologue(_masm, decorators, is_oop, from, to, count, wb_pre_saved_regs);
// save the original count
__ mov(count_save, count);
@@ -4035,14 +4035,14 @@
: "compare_long_string_different_encoding UL");
address entry = __ pc();
Label SMALL_LOOP, TAIL, TAIL_LOAD_16, LOAD_LAST, DIFF1, DIFF2,
- DONE, CALCULATE_DIFFERENCE, LARGE_LOOP_PREFETCH, SMALL_LOOP_ENTER,
+ DONE, CALCULATE_DIFFERENCE, LARGE_LOOP_PREFETCH, NO_PREFETCH,
LARGE_LOOP_PREFETCH_REPEAT1, LARGE_LOOP_PREFETCH_REPEAT2;
Register result = r0, str1 = r1, cnt1 = r2, str2 = r3, cnt2 = r4,
tmp1 = r10, tmp2 = r11, tmp3 = r12, tmp4 = r14;
FloatRegister vtmpZ = v0, vtmp = v1, vtmp3 = v2;
RegSet spilled_regs = RegSet::of(tmp3, tmp4);
- int prefetchLoopExitCondition = MAX(32, SoftwarePrefetchHintDistance/2);
+ int prefetchLoopExitCondition = MAX(64, SoftwarePrefetchHintDistance/2);
__ eor(vtmpZ, __ T16B, vtmpZ, vtmpZ);
// cnt2 == amount of characters left to compare
@@ -4069,7 +4069,7 @@
if (SoftwarePrefetchHintDistance >= 0) {
__ subs(rscratch2, cnt2, prefetchLoopExitCondition);
- __ br(__ LT, SMALL_LOOP);
+ __ br(__ LT, NO_PREFETCH);
__ bind(LARGE_LOOP_PREFETCH);
__ prfm(Address(tmp2, SoftwarePrefetchHintDistance));
__ mov(tmp4, 2);
@@ -4089,51 +4089,20 @@
__ br(__ GE, LARGE_LOOP_PREFETCH);
}
__ cbz(cnt2, LOAD_LAST); // no characters left except last load
+ __ bind(NO_PREFETCH);
__ subs(cnt2, cnt2, 16);
__ br(__ LT, TAIL);
- __ b(SMALL_LOOP_ENTER);
__ bind(SMALL_LOOP); // smaller loop
__ subs(cnt2, cnt2, 16);
- __ bind(SMALL_LOOP_ENTER);
compare_string_16_x_LU(tmpL, tmpU, DIFF1, DIFF2);
__ br(__ GE, SMALL_LOOP);
- __ cbz(cnt2, LOAD_LAST);
- __ bind(TAIL); // 1..15 characters left
- __ subs(zr, cnt2, -8);
- __ br(__ GT, TAIL_LOAD_16);
- __ ldrd(vtmp, Address(tmp2));
- __ zip1(vtmp3, __ T8B, vtmp, vtmpZ);
-
- __ ldr(tmpU, Address(__ post(cnt1, 8)));
- __ fmovd(tmpL, vtmp3);
- __ eor(rscratch2, tmp3, tmpL);
- __ cbnz(rscratch2, DIFF2);
- __ umov(tmpL, vtmp3, __ D, 1);
- __ eor(rscratch2, tmpU, tmpL);
- __ cbnz(rscratch2, DIFF1);
- __ b(LOAD_LAST);
- __ bind(TAIL_LOAD_16);
- __ ldrq(vtmp, Address(tmp2));
- __ ldr(tmpU, Address(__ post(cnt1, 8)));
- __ zip1(vtmp3, __ T16B, vtmp, vtmpZ);
- __ zip2(vtmp, __ T16B, vtmp, vtmpZ);
- __ fmovd(tmpL, vtmp3);
- __ eor(rscratch2, tmp3, tmpL);
- __ cbnz(rscratch2, DIFF2);
-
- __ ldr(tmp3, Address(__ post(cnt1, 8)));
- __ umov(tmpL, vtmp3, __ D, 1);
- __ eor(rscratch2, tmpU, tmpL);
- __ cbnz(rscratch2, DIFF1);
-
- __ ldr(tmpU, Address(__ post(cnt1, 8)));
- __ fmovd(tmpL, vtmp);
- __ eor(rscratch2, tmp3, tmpL);
- __ cbnz(rscratch2, DIFF2);
-
- __ umov(tmpL, vtmp, __ D, 1);
- __ eor(rscratch2, tmpU, tmpL);
- __ cbnz(rscratch2, DIFF1);
+ __ cmn(cnt2, (u1)16);
+ __ br(__ EQ, LOAD_LAST);
+ __ bind(TAIL); // 1..15 characters left until last load (last 4 characters)
+ __ add(cnt1, cnt1, cnt2, __ LSL, 1); // Address of 8 bytes before last 4 characters in UTF-16 string
+ __ add(tmp2, tmp2, cnt2); // Address of 16 bytes before last 4 characters in Latin1 string
+ __ ldr(tmp3, Address(cnt1, -8));
+ compare_string_16_x_LU(tmpL, tmpU, DIFF1, DIFF2); // last 16 characters before last load
__ b(LOAD_LAST);
__ bind(DIFF2);
__ mov(tmpU, tmp3);
@@ -4141,10 +4110,12 @@
__ pop(spilled_regs, sp);
__ b(CALCULATE_DIFFERENCE);
__ bind(LOAD_LAST);
+ // Last 4 UTF-16 characters are already pre-loaded into tmp3 by compare_string_16_x_LU.
+ // No need to load it again
+ __ mov(tmpU, tmp3);
__ pop(spilled_regs, sp);
__ ldrs(vtmp, Address(strL));
- __ ldr(tmpU, Address(strU));
__ zip1(vtmp, __ T8B, vtmp, vtmpZ);
__ fmovd(tmpL, vtmp);
@@ -4206,10 +4177,10 @@
compare_string_16_bytes_same(DIFF, DIFF2);
__ br(__ GT, LARGE_LOOP_PREFETCH);
__ cbz(cnt2, LAST_CHECK_AND_LENGTH_DIFF); // no more chars left?
- // less than 16 bytes left?
- __ subs(cnt2, cnt2, isLL ? 16 : 8);
- __ br(__ LT, TAIL);
}
+ // less than 16 bytes left?
+ __ subs(cnt2, cnt2, isLL ? 16 : 8);
+ __ br(__ LT, TAIL);
__ bind(SMALL_LOOP);
compare_string_16_bytes_same(DIFF, DIFF2);
__ subs(cnt2, cnt2, isLL ? 16 : 8);
@@ -4338,6 +4309,7 @@
__ ldr(ch1, Address(str1));
// Read whole register from str2. It is safe, because length >=8 here
__ ldr(ch2, Address(str2));
+ __ sub(cnt2, cnt2, cnt1);
__ andr(first, ch1, str1_isL ? 0xFF : 0xFFFF);
if (str1_isL != str2_isL) {
__ eor(v0, __ T16B, v0, v0);
--- a/src/hotspot/cpu/arm/assembler_arm_32.hpp Fri May 17 13:21:44 2019 +0100
+++ b/src/hotspot/cpu/arm/assembler_arm_32.hpp Thu May 23 11:07:37 2019 +0100
@@ -199,6 +199,14 @@
static const int LogInstructionSize = 2;
static const int InstructionSize = 1 << LogInstructionSize;
+ //---< calculate length of instruction >---
+ // We just use the values set above.
+ // instruction must start at passed address
+ static unsigned int instr_len(unsigned char *instr) { return InstructionSize; }
+
+ //---< longest instructions >---
+ static unsigned int instr_maxlen() { return InstructionSize; }
+
static inline AsmCondition inverse(AsmCondition cond) {
assert ((cond != al) && (cond != nv), "AL and NV conditions cannot be inversed");
return (AsmCondition)((int)cond ^ 1);
--- a/src/hotspot/cpu/arm/c2_globals_arm.hpp Fri May 17 13:21:44 2019 +0100
+++ b/src/hotspot/cpu/arm/c2_globals_arm.hpp Thu May 23 11:07:37 2019 +0100
@@ -97,7 +97,7 @@
// Ergonomics related flags
define_pd_global(uint64_t, MaxRAM, 4ULL*G);
#endif
-define_pd_global(uintx, CodeCacheMinBlockLength, 4);
+define_pd_global(uintx, CodeCacheMinBlockLength, 6);
define_pd_global(size_t, CodeCacheMinimumUseSpace, 400*K);
define_pd_global(bool, TrapBasedRangeChecks, false); // Not needed
--- a/src/hotspot/cpu/arm/disassembler_arm.hpp Fri May 17 13:21:44 2019 +0100
+++ b/src/hotspot/cpu/arm/disassembler_arm.hpp Thu May 23 11:07:37 2019 +0100
@@ -33,4 +33,24 @@
return "";
}
+ // Returns address of n-th instruction preceding addr,
+ // NULL if no preceding instruction can be found.
+ // On ARM, we assume a constant instruction length.
+ // It might be beneficial to check "is_readable" as we do on ppc and s390.
+ static address find_prev_instr(address addr, int n_instr) {
+ return addr - Assembler::InstructionSize*n_instr;
+ }
+
+ // special-case instruction decoding.
+ // There may be cases where the binutils disassembler doesn't do
+ // the perfect job. In those cases, decode_instruction0 may kick in
+ // and do it right.
+ // If nothing had to be done, just return "here", otherwise return "here + instr_len(here)"
+ static address decode_instruction0(address here, outputStream* st, address virtual_begin = NULL) {
+ return here;
+ }
+
+ // platform-specific instruction annotations (like value of loaded constants)
+ static void annotate(address pc, outputStream* st) { };
+
#endif // CPU_ARM_DISASSEMBLER_ARM_HPP
--- a/src/hotspot/cpu/ppc/assembler_ppc.hpp Fri May 17 13:21:44 2019 +0100
+++ b/src/hotspot/cpu/ppc/assembler_ppc.hpp Thu May 23 11:07:37 2019 +0100
@@ -929,11 +929,13 @@
enum Predict { pt = 1, pn = 0 }; // pt = predict taken
- // Instruction must start at passed address.
- static int instr_len(unsigned char *instr) { return BytesPerInstWord; }
+ //---< calculate length of instruction >---
+ // With PPC64 being a RISC architecture, this always is BytesPerInstWord
+ // instruction must start at passed address
+ static unsigned int instr_len(unsigned char *instr) { return BytesPerInstWord; }
- // longest instructions
- static int instr_maxlen() { return BytesPerInstWord; }
+ //---< longest instructions >---
+ static unsigned int instr_maxlen() { return BytesPerInstWord; }
// Test if x is within signed immediate range for nbits.
static bool is_simm(int x, unsigned int nbits) {
--- a/src/hotspot/cpu/ppc/c2_globals_ppc.hpp Fri May 17 13:21:44 2019 +0100
+++ b/src/hotspot/cpu/ppc/c2_globals_ppc.hpp Thu May 23 11:07:37 2019 +0100
@@ -1,6 +1,6 @@
/*
* Copyright (c) 2000, 2019, Oracle and/or its affiliates. All rights reserved.
- * Copyright (c) 2012, 2018 SAP SE. All rights reserved.
+ * Copyright (c) 2012, 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
@@ -90,7 +90,7 @@
// Ergonomics related flags
define_pd_global(uint64_t, MaxRAM, 128ULL*G);
-define_pd_global(uintx, CodeCacheMinBlockLength, 4);
+define_pd_global(uintx, CodeCacheMinBlockLength, 6);
define_pd_global(uintx, CodeCacheMinimumUseSpace, 400*K);
define_pd_global(bool, TrapBasedRangeChecks, true);
--- a/src/hotspot/cpu/ppc/c2_init_ppc.cpp Fri May 17 13:21:44 2019 +0100
+++ b/src/hotspot/cpu/ppc/c2_init_ppc.cpp Thu May 23 11:07:37 2019 +0100
@@ -36,18 +36,18 @@
// Power7 and later.
if (PowerArchitecturePPC64 > 6) {
if (FLAG_IS_DEFAULT(UsePopCountInstruction)) {
- FLAG_SET_ERGO(bool, UsePopCountInstruction, true);
+ FLAG_SET_ERGO(UsePopCountInstruction, true);
}
}
if (PowerArchitecturePPC64 == 6) {
if (FLAG_IS_DEFAULT(InsertEndGroupPPC64)) {
- FLAG_SET_ERGO(bool, InsertEndGroupPPC64, true);
+ FLAG_SET_ERGO(InsertEndGroupPPC64, true);
}
}
if (!VM_Version::has_isel() && FLAG_IS_DEFAULT(ConditionalMoveLimit)) {
- FLAG_SET_ERGO(intx, ConditionalMoveLimit, 0);
+ FLAG_SET_ERGO(ConditionalMoveLimit, 0);
}
if (OptimizeFill) {
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/hotspot/cpu/ppc/disassembler_ppc.cpp Thu May 23 11:07:37 2019 +0100
@@ -0,0 +1,201 @@
+/*
+ * 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.
+ *
+ */
+
+#include "asm/macroAssembler.inline.hpp"
+#include "code/codeCache.hpp"
+#include "compiler/disassembler.hpp"
+#include "depChecker_ppc.hpp"
+#include "gc/cms/concurrentMarkSweepGeneration.inline.hpp"
+#include "gc/cms/parOopClosures.inline.hpp"
+#include "gc/shared/collectedHeap.hpp"
+#include "gc/shared/cardTableBarrierSet.hpp"
+#include "gc/shared/genOopClosures.inline.hpp"
+#include "oops/oop.inline.hpp"
+#include "runtime/handles.inline.hpp"
+#include "runtime/stubCodeGenerator.hpp"
+#include "runtime/stubRoutines.hpp"
+
+// Macro to print instruction bits.
+// numbering of instruction bits on ppc64 is (highest) 0 1 ... 30 31 (lowest).
+#define print_instruction_bits(st, instruction, start_bit, end_bit) \
+ { assert((start_bit) <= (end_bit), "sanity check"); \
+ for (int i=(31-(start_bit));i>=(31-(end_bit));i--) { \
+ (st)->print("%d", ((instruction) >> i) & 0x1); \
+ } \
+ }
+
+// Macro to decode "bo" instruction bits.
+#define print_decoded_bo_bits(env, instruction, end_bit) \
+ { int bo_bits = (instruction >> (31 - (end_bit))) & 0x1f; \
+ if ( ((bo_bits & 0x1c) == 0x4) || ((bo_bits & 0x1c) == 0xc) ) { \
+ switch (bo_bits & 0x3) { \
+ case (0 << 1) | (0 << 0): env->print("[no_hint]"); break; \
+ case (0 << 1) | (1 << 0): env->print("[reserved]"); break; \
+ case (1 << 1) | (0 << 0): env->print("[not_taken]"); break; \
+ case (1 << 1) | (1 << 0): env->print("[taken]"); break; \
+ default: break; \
+ } \
+ } else if ( ((bo_bits & 0x14) == 0x10) ) { \
+ switch (bo_bits & 0x9) { \
+ case (0 << 3) | (0 << 0): env->print("[no_hint]"); break; \
+ case (0 << 3) | (1 << 0): env->print("[reserved]"); break; \
+ case (1 << 3) | (0 << 0): env->print("[not_taken]"); break; \
+ case (1 << 3) | (1 << 0): env->print("[taken]"); break; \
+ default: break; \
+ } \
+ } \
+ }
+
+// Macro to decode "bh" instruction bits.
+#define print_decoded_bh_bits(env, instruction, end_bit, is_bclr) \
+ { int bh_bits = (instruction >> (31 - (end_bit))) & 0x3; \
+ if (is_bclr) { \
+ switch (bh_bits) { \
+ case (0 << 1) | (0 << 0): env->print("[subroutine_return]"); break; \
+ case (0 << 1) | (1 << 0): env->print("[not_return_but_same]"); break; \
+ case (1 << 1) | (0 << 0): env->print("[reserved]"); break; \
+ case (1 << 1) | (1 << 0): env->print("[not_predictable]"); break; \
+ default: break; \
+ } \
+ } else { \
+ switch (bh_bits) { \
+ case (0 << 1) | (0 << 0): env->print("[not_return_but_same]"); break; \
+ case (0 << 1) | (1 << 0): env->print("[reserved]"); break; \
+ case (1 << 1) | (0 << 0): env->print("[reserved]"); break; \
+ case (1 << 1) | (1 << 0): env->print("[not_predictable]"); break; \
+ default: break; \
+ } \
+ } \
+ }
+
+address Disassembler::find_prev_instr(address here, int n_instr) {
+ if (!os::is_readable_pointer(here)) return NULL; // obviously a bad location to decode
+
+ // Find most distant possible starting point.
+ // Narrow down because we don't want to SEGV while printing.
+ address start = here - n_instr*Assembler::instr_maxlen(); // starting point can't be further away.
+ while ((start < here) && !os::is_readable_range(start, here)) {
+ start = align_down(start, os::min_page_size()) + os::min_page_size();
+ }
+ if (start >= here) {
+ // Strange. Can only happen with here on page boundary.
+ return NULL;
+ }
+ return start;
+}
+
+address Disassembler::decode_instruction0(address here, outputStream * st, address virtual_begin ) {
+ if (is_abstract()) {
+ // The disassembler library was not loaded (yet),
+ // use AbstractDisassembler's decode method.
+ return decode_instruction_abstract(here, st, Assembler::instr_len(here), Assembler::instr_maxlen());
+ }
+
+ // Currently, "special decoding" doesn't work when decoding error files.
+ // When decoding an instruction from a hs_err file, the given
+ // instruction address 'start' points to the instruction's virtual address
+ // which is not equal to the address where the instruction is located.
+ // Therefore, we will either crash or decode garbage.
+ if (is_decode_error_file()) {
+ return here;
+ }
+
+ //---< Decode some well-known "instructions" >---
+
+ address next;
+ uint32_t instruction = *(uint32_t*)here;
+
+ // Align at next tab position.
+ const uint tabspacing = 8;
+ const uint pos = st->position();
+ const uint aligned_pos = ((pos+tabspacing-1)/tabspacing)*tabspacing;
+ st->fill_to(aligned_pos);
+
+ if (instruction == 0x0) {
+ st->print("illtrap .data 0x0");
+ next = here + Assembler::instr_len(here);
+ } else if (instruction == 0xbadbabe) {
+ st->print(".data 0xbadbabe");
+ next = here + Assembler::instr_len(here);
+ } else if (Assembler::is_endgroup(instruction)) {
+ st->print("endgroup");
+ next = here + Assembler::instr_len(here);
+ } else {
+ next = here;
+ }
+ return next;
+}
+
+// print annotations (instruction control bits)
+void Disassembler::annotate(address here, outputStream* st) {
+ // Currently, annotation doesn't work when decoding error files.
+ // When decoding an instruction from a hs_err file, the given
+ // instruction address 'start' points to the instruction's virtual address
+ // which is not equal to the address where the instruction is located.
+ // Therefore, we will either crash or decode garbage.
+ if (is_decode_error_file()) {
+ return;
+ }
+
+ uint32_t instruction = *(uint32_t*)here;
+
+ // Align at next tab position.
+ const uint tabspacing = 8;
+ const uint pos = st->position();
+ const uint aligned_pos = ((pos+tabspacing-1)/tabspacing)*tabspacing;
+
+ if (MacroAssembler::is_bcxx(instruction)) {
+ st->print(",bo=0b");
+ print_instruction_bits(st, instruction, 6, 10);
+ print_decoded_bo_bits(st, instruction, 10);
+ } else if (MacroAssembler::is_bctr(instruction) ||
+ MacroAssembler::is_bctrl(instruction) ||
+ MacroAssembler::is_bclr(instruction)) {
+ st->fill_to(aligned_pos);
+ st->print("bo=0b");
+ print_instruction_bits(st, instruction, 6, 10);
+ print_decoded_bo_bits(st, instruction, 10);
+ st->print(",bh=0b");
+ print_instruction_bits(st, instruction, 19, 20);
+ print_decoded_bh_bits(st, instruction, 20,
+ !(MacroAssembler::is_bctr(instruction) ||
+ MacroAssembler::is_bctrl(instruction)));
+ } else if (MacroAssembler::is_trap_should_not_reach_here(instruction)) {
+ st->fill_to(aligned_pos + tabspacing);
+ st->print(";trap: should not reach here");
+ } else if (MacroAssembler::is_trap_null_check(instruction)) {
+ st->fill_to(aligned_pos + tabspacing);
+ st->print(";trap: null check");
+ } else if (MacroAssembler::is_trap_range_check(instruction)) {
+ st->fill_to(aligned_pos + tabspacing);
+ st->print(";trap: range check");
+ } else if (MacroAssembler::is_trap_ic_miss_check(instruction)) {
+ st->fill_to(aligned_pos + tabspacing);
+ st->print(";trap: ic miss check");
+ } else if (MacroAssembler::is_trap_zombie_not_entrant(instruction)) {
+ st->fill_to(aligned_pos + tabspacing);
+ st->print(";trap: zombie");
+ }
+}
--- a/src/hotspot/cpu/ppc/disassembler_ppc.hpp Fri May 17 13:21:44 2019 +0100
+++ b/src/hotspot/cpu/ppc/disassembler_ppc.hpp Thu May 23 11:07:37 2019 +0100
@@ -1,6 +1,6 @@
/*
* Copyright (c) 2002, 2019, Oracle and/or its affiliates. All rights reserved.
- * Copyright (c) 2012, 2013 SAP SE. All rights reserved.
+ * Copyright (c) 2012, 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
@@ -34,4 +34,23 @@
return "ppc64";
}
+ // Find preceding instruction.
+ //
+ // Starting at the passed location, the n-th preceding (towards lower addresses)
+ // location is searched, the contents of which - if interpreted as
+ // instructions - has the passed location as n-th successor.
+ // - If no such location exists, NULL is returned. The caller should then
+ // terminate its search and react properly.
+ static address find_prev_instr(address here, int n_instr);
+
+ // special-case instruction decoding.
+ // There may be cases where the binutils disassembler doesn't do
+ // the perfect job. In those cases, decode_instruction0 may kick in
+ // and do it right.
+ // If nothing had to be done, just return "here", otherwise return "here + instr_len(here)"
+ static address decode_instruction0(address here, outputStream* st, address virtual_begin = NULL);
+
+ // platform-specific instruction annotations (like value of loaded constants)
+ static void annotate(address pc, outputStream* st);
+
#endif // CPU_PPC_DISASSEMBLER_PPC_HPP
--- a/src/hotspot/cpu/ppc/vm_version_ppc.cpp Fri May 17 13:21:44 2019 +0100
+++ b/src/hotspot/cpu/ppc/vm_version_ppc.cpp Thu May 23 11:07:37 2019 +0100
@@ -67,17 +67,17 @@
// If PowerArchitecturePPC64 hasn't been specified explicitly determine from features.
if (FLAG_IS_DEFAULT(PowerArchitecturePPC64)) {
if (VM_Version::has_darn()) {
- FLAG_SET_ERGO(uintx, PowerArchitecturePPC64, 9);
+ FLAG_SET_ERGO(PowerArchitecturePPC64, 9);
} else if (VM_Version::has_lqarx()) {
- FLAG_SET_ERGO(uintx, PowerArchitecturePPC64, 8);
+ FLAG_SET_ERGO(PowerArchitecturePPC64, 8);
} else if (VM_Version::has_popcntw()) {
- FLAG_SET_ERGO(uintx, PowerArchitecturePPC64, 7);
+ FLAG_SET_ERGO(PowerArchitecturePPC64, 7);
} else if (VM_Version::has_cmpb()) {
- FLAG_SET_ERGO(uintx, PowerArchitecturePPC64, 6);
+ FLAG_SET_ERGO(PowerArchitecturePPC64, 6);
} else if (VM_Version::has_popcntb()) {
- FLAG_SET_ERGO(uintx, PowerArchitecturePPC64, 5);
+ FLAG_SET_ERGO(PowerArchitecturePPC64, 5);
} else {
- FLAG_SET_ERGO(uintx, PowerArchitecturePPC64, 0);
+ FLAG_SET_ERGO(PowerArchitecturePPC64, 0);
}
}
@@ -103,15 +103,15 @@
MSG(TrapBasedICMissChecks);
MSG(TrapBasedNotEntrantChecks);
MSG(TrapBasedNullChecks);
- FLAG_SET_ERGO(bool, TrapBasedNotEntrantChecks, false);
- FLAG_SET_ERGO(bool, TrapBasedNullChecks, false);
- FLAG_SET_ERGO(bool, TrapBasedICMissChecks, false);
+ FLAG_SET_ERGO(TrapBasedNotEntrantChecks, false);
+ FLAG_SET_ERGO(TrapBasedNullChecks, false);
+ FLAG_SET_ERGO(TrapBasedICMissChecks, false);
}
#ifdef COMPILER2
if (!UseSIGTRAP) {
MSG(TrapBasedRangeChecks);
- FLAG_SET_ERGO(bool, TrapBasedRangeChecks, false);
+ FLAG_SET_ERGO(TrapBasedRangeChecks, false);
}
// On Power6 test for section size.
@@ -123,7 +123,7 @@
if (PowerArchitecturePPC64 >= 8) {
if (FLAG_IS_DEFAULT(SuperwordUseVSX)) {
- FLAG_SET_ERGO(bool, SuperwordUseVSX, true);
+ FLAG_SET_ERGO(SuperwordUseVSX, true);
}
} else {
if (SuperwordUseVSX) {
@@ -135,10 +135,10 @@
if (PowerArchitecturePPC64 >= 9) {
if (FLAG_IS_DEFAULT(UseCountTrailingZerosInstructionsPPC64)) {
- FLAG_SET_ERGO(bool, UseCountTrailingZerosInstructionsPPC64, true);
+ FLAG_SET_ERGO(UseCountTrailingZerosInstructionsPPC64, true);
}
if (FLAG_IS_DEFAULT(UseCharacterCompareIntrinsics)) {
- FLAG_SET_ERGO(bool, UseCharacterCompareIntrinsics, true);
+ FLAG_SET_ERGO(UseCharacterCompareIntrinsics, true);
}
} else {
if (UseCountTrailingZerosInstructionsPPC64) {
@@ -708,6 +708,8 @@
uint32_t *code_end = (uint32_t *)a->pc();
a->flush();
+ cb.insts()->set_end((u_char*)code_end);
+
double loop1_seconds,loop2_seconds, rel_diff;
uint64_t start1, stop1;
@@ -725,10 +727,11 @@
rel_diff = (loop2_seconds - loop1_seconds) / loop1_seconds *100;
- if (PrintAssembly) {
+ if (PrintAssembly || PrintStubCode) {
ttyLocker ttyl;
tty->print_cr("Decoding section size detection stub at " INTPTR_FORMAT " before execution:", p2i(code));
- Disassembler::decode((u_char*)code, (u_char*)code_end, tty);
+ // Use existing decode function. This enables the [MachCode] format which is needed to DecodeErrorFile.
+ Disassembler::decode(&cb, (u_char*)code, (u_char*)code_end, tty);
tty->print_cr("Time loop1 :%f", loop1_seconds);
tty->print_cr("Time loop2 :%f", loop2_seconds);
tty->print_cr("(time2 - time1) / time1 = %f %%", rel_diff);
--- a/src/hotspot/cpu/s390/assembler_s390.hpp Fri May 17 13:21:44 2019 +0100
+++ b/src/hotspot/cpu/s390/assembler_s390.hpp Thu May 23 11:07:37 2019 +0100
@@ -1,6 +1,6 @@
/*
* Copyright (c) 2016, 2019, Oracle and/or its affiliates. All rights reserved.
- * Copyright (c) 2016, 2017 SAP SE. All rights reserved.
+ * Copyright (c) 2016, 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
@@ -1531,16 +1531,16 @@
//-----------------------------------------------
// Calculate length of instruction.
- static int instr_len(unsigned char *instr);
+ static unsigned int instr_len(unsigned char *instr);
// Longest instructions are 6 bytes on z/Architecture.
- static int instr_maxlen() { return 6; }
+ static unsigned int instr_maxlen() { return 6; }
// Average instruction is 4 bytes on z/Architecture (just a guess).
- static int instr_avglen() { return 4; }
+ static unsigned int instr_avglen() { return 4; }
// Shortest instructions are 2 bytes on z/Architecture.
- static int instr_minlen() { return 2; }
+ static unsigned int instr_minlen() { return 2; }
// Move instruction at pc right-justified into passed long int.
// Return instr len in bytes as function result.
--- a/src/hotspot/cpu/s390/assembler_s390.inline.hpp Fri May 17 13:21:44 2019 +0100
+++ b/src/hotspot/cpu/s390/assembler_s390.inline.hpp Thu May 23 11:07:37 2019 +0100
@@ -1344,7 +1344,7 @@
// Instruction must start at passed address.
// Extra check for illtraps with ID.
-inline int Assembler::instr_len(unsigned char *instr) {
+inline unsigned int Assembler::instr_len(unsigned char *instr) {
switch ((*instr) >> 6) {
case 0: return 2;
case 1: // fallthru
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/hotspot/cpu/s390/disassembler_s390.cpp Thu May 23 11:07:37 2019 +0100
@@ -0,0 +1,261 @@
+/*
+ * 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.
+ *
+ */
+
+#include "asm/assembler.inline.hpp"
+#include "asm/macroAssembler.hpp"
+#include "code/codeCache.hpp"
+#include "compiler/disassembler.hpp"
+#include "depChecker_s390.hpp"
+#include "gc/cms/concurrentMarkSweepGeneration.inline.hpp"
+#include "gc/cms/parOopClosures.inline.hpp"
+#include "gc/shared/collectedHeap.hpp"
+#include "gc/shared/cardTableBarrierSet.hpp"
+#include "gc/shared/genOopClosures.inline.hpp"
+#include "oops/oop.inline.hpp"
+#include "runtime/handles.inline.hpp"
+#include "runtime/stubCodeGenerator.hpp"
+#include "runtime/stubRoutines.hpp"
+#include "utilities/align.hpp"
+
+// List of all major opcodes, as of
+// Principles of Operation, Eleventh Edition, March 2015
+bool Disassembler::valid_opcodes[] =
+{ true, true, false, false, true, true, true, true, // 0x00..07
+ false, false, true, true, true, true, true, true, // 0x08..0f
+ true, true, true, true, true, true, true, true, // 0x10..17
+ true, true, true, true, true, true, true, true, // 0x18..1f
+ true, true, true, true, true, true, true, true, // 0x20..27
+ true, true, true, true, true, true, true, true, // 0x28..2f
+ true, true, true, true, true, true, true, true, // 0x30..37
+ true, true, true, true, true, true, true, true, // 0x38..3f
+ true, true, true, true, true, true, true, true, // 0x40..47
+ true, true, true, true, true, true, true, true, // 0x48..4f
+ true, true, false, false, true, true, true, true, // 0x50..57
+ true, true, true, true, true, true, true, true, // 0x58..5f
+ true, false, false, false, false, false, false, true, // 0x60..67
+ true, true, true, true, true, true, true, true, // 0x68..6f
+ true, true, false, false, false, false, false, false, // 0x70..77
+ true, true, true, true, true, true, true, true, // 0x78..7f
+ true, false, true, true, true, true, true, true, // 0x80..87
+ true, true, true, true, true, true, true, true, // 0x88..8f
+ true, true, true, true, true, true, true, true, // 0x90..97
+ true, true, true, true, false, false, false, false, // 0x98..9f
+ false, false, false, false, false, true, false, true, // 0xa0..a7
+ true, true, false, false, true, true, true, true, // 0xa8..af
+ false, true, true, true, false, false, true, true, // 0xb0..b7
+ false, true, true, true, false, true, true, true, // 0xb8..bf
+ true, false, true, false, true, false, true, false, // 0xc0..c7
+ true, false, false, false, true, false, false, false, // 0xc8..cf
+ true, true, true, true, true, true, true, true, // 0xd0..d7
+ false, true, true, true, true, true, true, true, // 0xd8..df
+ false, true, true, true, false, true, false, true, // 0xe0..e7
+ true, true, true, true, true, true, true, true, // 0xe8..ef
+ true, true, true, true, false, false, false, false, // 0xf0..f7
+ true, true, true, true, true, true, false, false, // 0xf8..ff
+};
+// Check for valid opcodes.
+//
+// The major opcode (one byte) at the passed location is inspected.
+// If the opcode found is assigned, the function returns true, false otherwise.
+// The true indication is not reliable. It may well be that the major opcode is
+// assigned, but there exists a minor opcode field in the instruction which
+// which has unassigned values.
+bool Disassembler::is_valid_opcode_at(address here) {
+ return valid_opcodes[*here];
+}
+
+// This method does plain instruction decoding, no frills.
+// It may be called before the binutils disassembler kicks in
+// to handle special cases the binutils disassembler does not.
+// Instruction address, comments, and the like have to be output by caller.
+address Disassembler::decode_instruction0(address here, outputStream * st, address virtual_begin) {
+ if (is_abstract()) {
+ // The disassembler library was not loaded (yet),
+ // use AbstractDisassembler's decode-method.
+ return decode_instruction_abstract(here, st, Assembler::instr_len(here), Assembler::instr_maxlen());
+ }
+
+ // Currently, "special decoding" doesn't work when decoding error files.
+ // When decoding an instruction from a hs_err file, the given
+ // instruction address 'start' points to the instruction's virtual address
+ // which is not equal to the address where the instruction is located.
+ // Therefore, we will either crash or decode garbage.
+ if (is_decode_error_file()) {
+ return here;
+ }
+
+ //---< Decode some well-known "instructions" >---
+
+ address next;
+ uint16_t instruction_2bytes = *(uint16_t*)here;
+
+ if (Assembler::is_z_nop((long)instruction_2bytes)) {
+#if 1
+ st->print("nop "); // fill up to operand column, leads to better code comment alignment
+ next = here + 2;
+#else
+ // Compact disassembler output. Does not work the easy way.
+ // Currently unusable, search does not terminate, risk of crash.
+ // TODO: rework required.
+ // Terminate search loop when reaching CodeEntryAlignment-aligned offset
+ // or, at the latest, when reaching the next page boundary.
+ int n_nops = 0;
+ while(is_same_page(here, here+2*n_nops) && Assembler::is_z_nop((long)instruction_2bytes)) {
+ n_nops++;
+ instruction_2bytes = *(uint16_t*)(here+2*n_nops);
+ }
+ if (n_nops <= 4) { // do not group few subsequent nops
+ st->print("nop "); // fill up to operand column, leads to better code comment alignment
+ next = here + 2;
+ } else {
+ st->print("nop count=%d", n_nops);
+ next = here + 2*n_nops;
+ }
+#endif
+ } else if (Assembler::is_z_sync((long)instruction_2bytes)) {
+ // Specific names. Make use of lightweight sync.
+ st->print("sync ");
+ if (Assembler::is_z_sync_full((long)instruction_2bytes) ) st->print("heavyweight");
+ if (Assembler::is_z_sync_light((long)instruction_2bytes)) st->print("lightweight");
+ next = here + 2;
+ } else if (instruction_2bytes == 0x0000) {
+#if 1
+ st->print("illtrap .nodata");
+ next = here + 2;
+#else
+ // Compact disassembler output. Does not work the easy way.
+ // Currently unusable, search does not terminate, risk of crash.
+ // TODO: rework required.
+ // Terminate search loop when reaching CodeEntryAlignment-aligned offset
+ // or, at the latest, when reaching the next page boundary.
+ int n_traps = 0;
+ while(is_same_page(here, here+2*n_nops) && (instruction_2bytes == 0x0000)) {
+ n_traps++;
+ instruction_2bytes = *(uint16_t*)(here+2*n_traps);
+ }
+ if (n_traps <= 4) { // do not group few subsequent illtraps
+ st->print("illtrap .nodata");
+ next = here + 2;
+ } else {
+ st->print("illtrap .nodata count=%d", n_traps);
+ next = here + 2*n_traps;
+ }
+#endif
+ } else if ((instruction_2bytes & 0xff00) == 0x0000) {
+ st->print("illtrap .data 0x%2.2x", instruction_2bytes & 0x00ff);
+ next = here + 2;
+ } else {
+ next = here;
+ }
+ return next;
+}
+
+// Count the instructions contained in the range [begin..end).
+// The range must exactly contain the instructions, i.e.
+// - the first instruction starts @begin
+// - the last instruction ends @(end-1)
+// The caller has to make sure that the given range is readable.
+// This function performs no safety checks!
+// Return value:
+// - The number of instructions, if there was exact containment.
+// - If there is no exact containment, a negative value is returned.
+// Its absolute value is the number of instructions from begin to end,
+// where the last instruction counted runs over the range end.
+// - 0 (zero) is returned if there was a parameter error
+// (inverted range, bad starting point).
+int Disassembler::count_instr(address begin, address end) {
+ if (end < begin+2) return 0; // no instructions in range
+ if (!Disassembler::is_valid_opcode_at(begin)) return 0; // bad starting point
+
+ address p = begin;
+ int n = 0;
+ while(p < end) {
+ p += Assembler::instr_len(p);
+ n++;
+ }
+ return (p == end) ? n : -n;
+}
+
+// Find preceding instruction.
+//
+// Starting at the passed location, the n-th preceding (towards lower addresses)
+// instruction is searched. With variable length instructions, there may be
+// more than one solution, or no solution at all (if the passed location
+// does not point to the start of an instruction or if the storage area
+// does not contain instructions at all).
+// instructions - has the passed location as n-th successor.
+// - If multiple such locations exist between (here-n*instr_maxlen()) and here,
+// the most distant location is selected.
+// - If no such location exists, NULL is returned. The caller should then
+// terminate its search and react properly.
+// Must be placed here in disassembler_s390.cpp. It does not compile
+// in the header. There the class 'Assembler' is not available.
+address Disassembler::find_prev_instr(address here, int n_instr) {
+ if (!os::is_readable_pointer(here)) return NULL; // obviously a bad location to decode
+
+ // Find most distant possible starting point.
+ // Narrow down because we don't want to SEGV while printing.
+ address start = here - n_instr*Assembler::instr_maxlen(); // starting point can't be further away.
+ while ((start < here) && !os::is_readable_range(start, here)) {
+ start = align_down(start, os::min_page_size()) + os::min_page_size();
+ }
+ if (start >= here) {
+ // Strange. Can only happen with here on page boundary.
+ return NULL;
+ }
+
+ //---< Find a starting point >---
+ int i_count = 0;
+ while ((start < here) && ((i_count = count_instr(start, here)) <= 0)) start += 2;
+ if (i_count == 0) return NULL; // There is something seriously wrong
+
+ //---< Narrow down distance (estimate was too large) >---
+ while(i_count-- > n_instr) {
+ start += Assembler::instr_len(start);
+ }
+ assert(n_instr >= count_instr(start, here), "just checking");
+ return start;
+}
+
+
+// Print annotations (value of loaded constant)
+void Disassembler::annotate(address here, outputStream* st) {
+ // Currently, annotation doesn't work when decoding error files.
+ // When decoding an instruction from a hs_err file, the given
+ // instruction address 'start' points to the instruction's virtual address
+ // which is not equal to the address where the instruction is located.
+ // Therefore, we will either crash or decode garbage.
+ if (is_decode_error_file()) {
+ return;
+ }
+
+ if (MacroAssembler::is_load_const(here)) {
+ long value = MacroAssembler::get_const(here);
+ const int tsize = 8;
+
+ st->fill_to(60);
+ st->print(";const %p | %ld | %23.15e", (void *)value, value, (double)value);
+ }
+}
--- a/src/hotspot/cpu/s390/disassembler_s390.hpp Fri May 17 13:21:44 2019 +0100
+++ b/src/hotspot/cpu/s390/disassembler_s390.hpp Thu May 23 11:07:37 2019 +0100
@@ -1,6 +1,6 @@
/*
* Copyright (c) 2016, 2019, Oracle and/or its affiliates. All rights reserved.
- * Copyright (c) 2016 SAP SE. All rights reserved.
+ * Copyright (c) 2016, 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
@@ -27,11 +27,36 @@
#define CPU_S390_DISASSEMBLER_S390_HPP
static int pd_instruction_alignment() {
- return 1;
+ return 2;
}
static const char* pd_cpu_opts() {
- return "zarch";
+ return "s390";
}
+ static bool valid_opcodes[256];
+ static bool is_valid_opcode_at(address here);
+
+ // Find preceding instruction.
+ //
+ // Starting at the passed location, the n-th preceding (towards lower addresses)
+ // location is searched, the contents of which - if interpreted as
+ // instructions - has the passed location as n-th successor.
+ // - If multiple such locations exist between (here-n*instr_maxlen()) and here,
+ // the most distant location is selected.
+ // - If no such location exists, NULL is returned. The caller should then
+ // terminate its search and react properly.
+ static address find_prev_instr(address here, int n_instr);
+ static int count_instr(address begin, address end);
+
+ // special-case instruction decoding.
+ // There may be cases where the binutils disassembler doesn't do
+ // the perfect job. In those cases, decode_instruction0 may kick in
+ // and do it right.
+ // If nothing had to be done, just return "here", otherwise return "here + instr_len(here)"
+ static address decode_instruction0(address here, outputStream* st, address virtual_begin = NULL);
+
+ // platform-specific instruction annotations (like value of loaded constants)
+ static void annotate(address pc, outputStream* st);
+
#endif // CPU_S390_DISASSEMBLER_S390_HPP
--- a/src/hotspot/cpu/s390/s390.ad Fri May 17 13:21:44 2019 +0100
+++ b/src/hotspot/cpu/s390/s390.ad Thu May 23 11:07:37 2019 +0100
@@ -1,6 +1,6 @@
//
-// Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
-// Copyright (c) 2017, SAP SE. All rights reserved.
+// Copyright (c) 2017, 2019, Oracle and/or its affiliates. All rights reserved.
+// Copyright (c) 2017, 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
@@ -1388,7 +1388,6 @@
__ z_br(R1_ic_miss_stub_addr);
__ bind(valid);
}
-
}
uint MachUEPNode::size(PhaseRegAlloc *ra_) const {
@@ -4318,7 +4317,7 @@
match(Set dst src);
ins_cost(DEFAULT_COST);
size(6);
- format %{ "LGFI $dst,$src\t # (int)" %}
+ format %{ "LGFI $dst,$src\t # (int)" %}
ins_encode %{ __ z_lgfi($dst$$Register, $src$$constant); %} // Sign-extend to 64 bit, it's at no cost.
ins_pipe(pipe_class_dummy);
%}
@@ -4327,7 +4326,7 @@
match(Set dst src);
ins_cost(DEFAULT_COST_LOW);
size(4);
- format %{ "LGHI $dst,$src\t # (int)" %}
+ format %{ "LGHI $dst,$src\t # (int)" %}
ins_encode %{ __ z_lghi($dst$$Register, $src$$constant); %} // Sign-extend to 64 bit, it's at no cost.
ins_pipe(pipe_class_dummy);
%}
@@ -4723,7 +4722,7 @@
match(Set dst (LoadN mem));
ins_cost(MEMORY_REF_COST);
size(Z_DISP3_SIZE);
- format %{ "LoadN $dst,$mem\t# (cOop)" %}
+ format %{ "LoadN $dst,$mem\t # (cOop)" %}
opcode(LLGF_ZOPC, LLGF_ZOPC);
ins_encode(z_form_rt_mem_opt(dst, mem));
ins_pipe(pipe_class_dummy);
@@ -4734,7 +4733,7 @@
match(Set dst (LoadNKlass mem));
ins_cost(MEMORY_REF_COST);
size(Z_DISP3_SIZE);
- format %{ "LoadNKlass $dst,$mem\t# (klass cOop)" %}
+ format %{ "LoadNKlass $dst,$mem\t # (klass cOop)" %}
opcode(LLGF_ZOPC, LLGF_ZOPC);
ins_encode(z_form_rt_mem_opt(dst, mem));
ins_pipe(pipe_class_dummy);
@@ -4787,7 +4786,7 @@
predicate(false && (CompressedOops::base()==NULL)&&(CompressedOops::shift()==0));
ins_cost(MEMORY_REF_COST);
size(Z_DISP3_SIZE);
- format %{ "DecodeLoadN $dst,$mem\t# (cOop Load+Decode)" %}
+ format %{ "DecodeLoadN $dst,$mem\t # (cOop Load+Decode)" %}
opcode(LLGF_ZOPC, LLGF_ZOPC);
ins_encode(z_form_rt_mem_opt(dst, mem));
ins_pipe(pipe_class_dummy);
@@ -4798,7 +4797,7 @@
predicate(false && (CompressedKlassPointers::base()==NULL)&&(CompressedKlassPointers::shift()==0));
ins_cost(MEMORY_REF_COST);
size(Z_DISP3_SIZE);
- format %{ "DecodeLoadNKlass $dst,$mem\t# (load/decode NKlass)" %}
+ format %{ "DecodeLoadNKlass $dst,$mem\t # (load/decode NKlass)" %}
opcode(LLGF_ZOPC, LLGF_ZOPC);
ins_encode(z_form_rt_mem_opt(dst, mem));
ins_pipe(pipe_class_dummy);
@@ -4826,7 +4825,7 @@
predicate(CompressedOops::base() == NULL || !ExpandLoadingBaseDecode);
ins_cost(MEMORY_REF_COST+3 * DEFAULT_COST + BRANCH_COST);
// TODO: s390 port size(VARIABLE_SIZE);
- format %{ "decodeN $dst,$src\t# (decode cOop)" %}
+ format %{ "decodeN $dst,$src\t # (decode cOop)" %}
ins_encode %{ __ oop_decoder($dst$$Register, $src$$Register, true); %}
ins_pipe(pipe_class_dummy);
%}
@@ -4850,7 +4849,7 @@
(CompressedOops::base()== NULL || !ExpandLoadingBaseDecode_NN));
ins_cost(MEMORY_REF_COST+2 * DEFAULT_COST);
// TODO: s390 port size(VARIABLE_SIZE);
- format %{ "decodeN $dst,$src\t# (decode cOop NN)" %}
+ format %{ "decodeN $dst,$src\t # (decode cOop NN)" %}
ins_encode %{ __ oop_decoder($dst$$Register, $src$$Register, false); %}
ins_pipe(pipe_class_dummy);
%}
@@ -4873,7 +4872,7 @@
effect(KILL cr);
predicate(false);
// TODO: s390 port size(VARIABLE_SIZE);
- format %{ "decodeN $dst = ($src == 0) ? NULL : ($src << 3) + $base + pow2_offset\t# (decode cOop)" %}
+ format %{ "decodeN $dst = ($src == 0) ? NULL : ($src << 3) + $base + pow2_offset\t # (decode cOop)" %}
ins_encode %{
__ oop_decoder($dst$$Register, $src$$Register, true, $base$$Register,
(jlong)MacroAssembler::get_oop_base_pow2_offset((uint64_t)(intptr_t)CompressedOops::base()));
@@ -4887,7 +4886,7 @@
effect(KILL cr);
predicate(false);
// TODO: s390 port size(VARIABLE_SIZE);
- format %{ "decodeN $dst = ($src << 3) + $base + pow2_offset\t# (decode cOop)" %}
+ format %{ "decodeN $dst = ($src << 3) + $base + pow2_offset\t # (decode cOop)" %}
ins_encode %{
__ oop_decoder($dst$$Register, $src$$Register, false, $base$$Register,
(jlong)MacroAssembler::get_oop_base_pow2_offset((uint64_t)(intptr_t)CompressedOops::base()));
@@ -4937,7 +4936,7 @@
!ExpandLoadingBaseEncode));
ins_cost(MEMORY_REF_COST+3 * DEFAULT_COST);
// TODO: s390 port size(VARIABLE_SIZE);
- format %{ "encodeP $dst,$src\t# (encode cOop)" %}
+ format %{ "encodeP $dst,$src\t # (encode cOop)" %}
ins_encode %{ __ oop_encoder($dst$$Register, $src$$Register, true, Z_R1_scratch, -1, all_outs_are_Stores(this)); %}
ins_pipe(pipe_class_dummy);
%}
@@ -4960,7 +4959,7 @@
!ExpandLoadingBaseEncode_NN));
ins_cost(MEMORY_REF_COST+3 * DEFAULT_COST);
// TODO: s390 port size(VARIABLE_SIZE);
- format %{ "encodeP $dst,$src\t# (encode cOop)" %}
+ format %{ "encodeP $dst,$src\t # (encode cOop)" %}
ins_encode %{ __ oop_encoder($dst$$Register, $src$$Register, false, Z_R1_scratch, -1, all_outs_are_Stores(this)); %}
ins_pipe(pipe_class_dummy);
%}
@@ -4972,7 +4971,7 @@
predicate(false);
ins_cost(MEMORY_REF_COST+2 * DEFAULT_COST);
// TODO: s390 port size(VARIABLE_SIZE);
- format %{ "encodeP $dst = ($src>>3) +$base + pow2_offset\t# (encode cOop)" %}
+ format %{ "encodeP $dst = ($src>>3) +$base + pow2_offset\t # (encode cOop)" %}
ins_encode %{
jlong offset = -(jlong)MacroAssembler::get_oop_base_pow2_offset
(((uint64_t)(intptr_t)CompressedOops::base()) >> CompressedOops::shift());
@@ -4988,7 +4987,7 @@
predicate(false);
ins_cost(MEMORY_REF_COST+2 * DEFAULT_COST);
// TODO: s390 port size(VARIABLE_SIZE);
- format %{ "encodeP $dst = ($src>>3) +$base + $pow2_offset\t# (encode cOop)" %}
+ format %{ "encodeP $dst = ($src>>3) +$base + $pow2_offset\t # (encode cOop)" %}
ins_encode %{ __ oop_encoder($dst$$Register, $src$$Register, false, $base$$Register, $pow2_offset$$constant); %}
ins_pipe(pipe_class_dummy);
%}
@@ -5041,7 +5040,7 @@
match(Set mem (StoreN mem src));
ins_cost(MEMORY_REF_COST);
size(Z_DISP_SIZE);
- format %{ "ST $src,$mem\t# (cOop)" %}
+ format %{ "ST $src,$mem\t # (cOop)" %}
opcode(STY_ZOPC, ST_ZOPC);
ins_encode(z_form_rt_mem_opt(src, mem));
ins_pipe(pipe_class_dummy);
@@ -5052,7 +5051,7 @@
match(Set mem (StoreNKlass mem src));
ins_cost(MEMORY_REF_COST);
size(Z_DISP_SIZE);
- format %{ "ST $src,$mem\t# (cKlass)" %}
+ format %{ "ST $src,$mem\t # (cKlass)" %}
opcode(STY_ZOPC, ST_ZOPC);
ins_encode(z_form_rt_mem_opt(src, mem));
ins_pipe(pipe_class_dummy);
@@ -5064,7 +5063,7 @@
match(Set cr (CmpN src1 src2));
ins_cost(DEFAULT_COST);
size(2);
- format %{ "CLR $src1,$src2\t# (cOop)" %}
+ format %{ "CLR $src1,$src2\t # (cOop)" %}
opcode(CLR_ZOPC);
ins_encode(z_rrform(src1, src2));
ins_pipe(pipe_class_dummy);
@@ -5074,7 +5073,7 @@
match(Set cr (CmpN src1 src2));
ins_cost(DEFAULT_COST);
size(6);
- format %{ "CLFI $src1,$src2\t# (cOop) compare immediate narrow" %}
+ format %{ "CLFI $src1,$src2\t # (cOop) compare immediate narrow" %}
ins_encode %{
AddressLiteral cOop = __ constant_oop_address((jobject)$src2$$constant);
__ relocate(cOop.rspec(), 1);
@@ -5087,7 +5086,7 @@
match(Set cr (CmpN src1 src2));
ins_cost(DEFAULT_COST);
size(6);
- format %{ "CLFI $src1,$src2\t# (NKlass) compare immediate narrow" %}
+ format %{ "CLFI $src1,$src2\t # (NKlass) compare immediate narrow" %}
ins_encode %{
AddressLiteral NKlass = __ constant_metadata_address((Metadata*)$src2$$constant);
__ relocate(NKlass.rspec(), 1);
@@ -5100,7 +5099,7 @@
match(Set cr (CmpN src1 src2));
ins_cost(DEFAULT_COST);
size(2);
- format %{ "LTR $src1,$src2\t# (cOop) LTR because comparing against zero" %}
+ format %{ "LTR $src1,$src2\t # (cOop) LTR because comparing against zero" %}
opcode(LTR_ZOPC);
ins_encode(z_rrform(src1, src1));
ins_pipe(pipe_class_dummy);
@@ -6795,7 +6794,7 @@
effect(KILL cr); // R1 is killed, too.
ins_cost(3 * DEFAULT_COST);
size(14);
- format %{ "SLL $dst,$src,[$nbits] & 31\t# use RISC-like SLLG also for int" %}
+ format %{ "SLL $dst,$src,[$nbits] & 31\t # use RISC-like SLLG also for int" %}
ins_encode %{
__ z_lgr(Z_R1_scratch, $nbits$$Register);
__ z_nill(Z_R1_scratch, BitsPerJavaInteger-1);
@@ -6809,7 +6808,7 @@
instruct sllI_reg_imm(iRegI dst, iRegI src, immI nbits) %{
match(Set dst (LShiftI src nbits));
size(6);
- format %{ "SLL $dst,$src,$nbits\t# use RISC-like SLLG also for int" %}
+ format %{ "SLL $dst,$src,$nbits\t # use RISC-like SLLG also for int" %}
ins_encode %{
int Nbit = $nbits$$constant;
assert((Nbit & (BitsPerJavaInteger - 1)) == Nbit, "Check shift mask in ideal graph");
@@ -7125,7 +7124,7 @@
instruct overflowNegI_rReg(flagsReg cr, immI_0 zero, iRegI op2) %{
match(Set cr (OverflowSubI zero op2));
effect(DEF cr, USE op2);
- format %{ "NEG $op2\t# overflow check int" %}
+ format %{ "NEG $op2\t # overflow check int" %}
ins_encode %{
__ clear_reg(Z_R0_scratch, false, false);
__ z_sr(Z_R0_scratch, $op2$$Register);
@@ -7136,7 +7135,7 @@
instruct overflowNegL_rReg(flagsReg cr, immL_0 zero, iRegL op2) %{
match(Set cr (OverflowSubL zero op2));
effect(DEF cr, USE op2);
- format %{ "NEGG $op2\t# overflow check long" %}
+ format %{ "NEGG $op2\t # overflow check long" %}
ins_encode %{
__ clear_reg(Z_R0_scratch, true, false);
__ z_sgr(Z_R0_scratch, $op2$$Register);
@@ -9191,7 +9190,7 @@
effect(USE lbl);
ins_cost(BRANCH_COST);
size(4);
- format %{ "branch_con_short,$cmp $cr, $lbl" %}
+ format %{ "branch_con_short,$cmp $lbl" %}
ins_encode(z_enc_branch_con_short(cmp, lbl));
ins_pipe(pipe_class_dummy);
// If set to 1 this indicates that the current instruction is a
@@ -9213,7 +9212,7 @@
// Make more expensive to prefer compare_and_branch over separate instructions.
ins_cost(2 * BRANCH_COST);
size(6);
- format %{ "branch_con_far,$cmp $cr, $lbl" %}
+ format %{ "branch_con_far,$cmp $lbl" %}
ins_encode(z_enc_branch_con_far(cmp, lbl));
ins_pipe(pipe_class_dummy);
// This is not a short variant of a branch, but the long variant..
@@ -9782,7 +9781,7 @@
match(TailCall jump_target method_oop);
ins_cost(CALL_COST);
size(2);
- format %{ "Jmp $jump_target\t# $method_oop holds method oop" %}
+ format %{ "Jmp $jump_target\t # $method_oop holds method oop" %}
ins_encode %{ __ z_br($jump_target$$Register); %}
ins_pipe(pipe_class_dummy);
%}
@@ -10790,7 +10789,7 @@
predicate(UseByteReverseInstruction); // See Matcher::match_rule_supported
ins_cost(DEFAULT_COST);
size(4);
- format %{ "LRVR $dst,$src\t# byte reverse int" %}
+ format %{ "LRVR $dst,$src\t # byte reverse int" %}
opcode(LRVR_ZOPC);
ins_encode(z_rreform(dst, src));
ins_pipe(pipe_class_dummy);
@@ -10801,7 +10800,7 @@
predicate(UseByteReverseInstruction); // See Matcher::match_rule_supported
ins_cost(DEFAULT_COST);
// TODO: s390 port size(FIXED_SIZE);
- format %{ "LRVGR $dst,$src\t# byte reverse long" %}
+ format %{ "LRVGR $dst,$src\t # byte reverse long" %}
opcode(LRVGR_ZOPC);
ins_encode(z_rreform(dst, src));
ins_pipe(pipe_class_dummy);
@@ -10821,8 +10820,8 @@
effect(KILL tmp, KILL cr);
ins_cost(3 * DEFAULT_COST);
size(14);
- format %{ "SLLG $dst,$src,32\t# no need to always count 32 zeroes first\n\t"
- "IILH $dst,0x8000 \t# insert \"stop bit\" to force result 32 for zero src.\n\t"
+ format %{ "SLLG $dst,$src,32\t # no need to always count 32 zeroes first\n\t"
+ "IILH $dst,0x8000 \t # insert \"stop bit\" to force result 32 for zero src.\n\t"
"FLOGR $dst,$dst"
%}
ins_encode %{
@@ -10859,7 +10858,7 @@
effect(KILL tmp, KILL cr);
ins_cost(DEFAULT_COST);
size(4);
- format %{ "FLOGR $dst,$src \t# count leading zeros (long)\n\t" %}
+ format %{ "FLOGR $dst,$src \t # count leading zeros (long)\n\t" %}
ins_encode %{ __ z_flogr($dst$$Register, $src$$Register); %}
ins_pipe(pipe_class_dummy);
%}
@@ -10884,14 +10883,14 @@
effect(TEMP_DEF dst, TEMP tmp, KILL cr);
ins_cost(8 * DEFAULT_COST);
// TODO: s390 port size(FIXED_SIZE); // Emitted code depends on PreferLAoverADD being on/off.
- format %{ "LLGFR $dst,$src \t# clear upper 32 bits (we are dealing with int)\n\t"
- "LCGFR $tmp,$src \t# load 2's complement (32->64 bit)\n\t"
- "AGHI $dst,-1 \t# tmp1 = src-1\n\t"
- "AGHI $tmp,-1 \t# tmp2 = -src-1 = ~src\n\t"
- "NGR $dst,$tmp \t# tmp3 = tmp1&tmp2\n\t"
- "FLOGR $dst,$dst \t# count trailing zeros (int)\n\t"
- "AHI $dst,-64 \t# tmp4 = 64-(trailing zeroes)-64\n\t"
- "LCR $dst,$dst \t# res = -tmp4"
+ format %{ "LLGFR $dst,$src \t # clear upper 32 bits (we are dealing with int)\n\t"
+ "LCGFR $tmp,$src \t # load 2's complement (32->64 bit)\n\t"
+ "AGHI $dst,-1 \t # tmp1 = src-1\n\t"
+ "AGHI $tmp,-1 \t # tmp2 = -src-1 = ~src\n\t"
+ "NGR $dst,$tmp \t # tmp3 = tmp1&tmp2\n\t"
+ "FLOGR $dst,$dst \t # count trailing zeros (int)\n\t"
+ "AHI $dst,-64 \t # tmp4 = 64-(trailing zeroes)-64\n\t"
+ "LCR $dst,$dst \t # res = -tmp4"
%}
ins_encode %{
Register Rdst = $dst$$Register;
@@ -10937,12 +10936,12 @@
effect(TEMP_DEF dst, KILL tmp, KILL cr);
ins_cost(8 * DEFAULT_COST);
// TODO: s390 port size(FIXED_SIZE); // Emitted code depends on PreferLAoverADD being on/off.
- format %{ "LCGR $dst,$src \t# preserve src\n\t"
- "NGR $dst,$src \t#"
- "AGHI $dst,-1 \t# tmp1 = src-1\n\t"
- "FLOGR $dst,$dst \t# count trailing zeros (long), kill $tmp\n\t"
- "AHI $dst,-64 \t# tmp4 = 64-(trailing zeroes)-64\n\t"
- "LCR $dst,$dst \t#"
+ format %{ "LCGR $dst,$src \t # preserve src\n\t"
+ "NGR $dst,$src \t #\n\t"
+ "AGHI $dst,-1 \t # tmp1 = src-1\n\t"
+ "FLOGR $dst,$dst \t # count trailing zeros (long), kill $tmp\n\t"
+ "AHI $dst,-64 \t # tmp4 = 64-(trailing zeroes)-64\n\t"
+ "LCR $dst,$dst \t #"
%}
ins_encode %{
Register Rdst = $dst$$Register;
@@ -10969,7 +10968,7 @@
predicate(UsePopCountInstruction && VM_Version::has_PopCount());
ins_cost(DEFAULT_COST);
size(24);
- format %{ "POPCNT $dst,$src\t# pop count int" %}
+ format %{ "POPCNT $dst,$src\t # pop count int" %}
ins_encode %{
Register Rdst = $dst$$Register;
Register Rsrc = $src$$Register;
@@ -10996,7 +10995,7 @@
predicate(UsePopCountInstruction && VM_Version::has_PopCount());
ins_cost(DEFAULT_COST);
// TODO: s390 port size(FIXED_SIZE);
- format %{ "POPCNT $dst,$src\t# pop count long" %}
+ format %{ "POPCNT $dst,$src\t # pop count long" %}
ins_encode %{
Register Rdst = $dst$$Register;
Register Rsrc = $src$$Register;
--- a/src/hotspot/cpu/s390/vm_version_s390.cpp Fri May 17 13:21:44 2019 +0100
+++ b/src/hotspot/cpu/s390/vm_version_s390.cpp Thu May 23 11:07:37 2019 +0100
@@ -804,6 +804,8 @@
address code_end = a->pc();
a->flush();
+ cbuf.insts()->set_end(code_end);
+
// Print the detection code.
bool printVerbose = Verbose || PrintAssembly || PrintStubCode;
if (printVerbose) {
@@ -812,8 +814,8 @@
tty->print_cr("Stub length is %ld bytes, codebuffer reserves %d bytes, %ld bytes spare.",
code_end-code, cbuf_size, cbuf_size-(code_end-code));
- // Use existing decode function. This enables the [Code] format which is needed to DecodeErrorFile.
- Disassembler::decode((u_char*)code, (u_char*)code_end, tty);
+ // Use existing decode function. This enables the [MachCode] format which is needed to DecodeErrorFile.
+ Disassembler::decode(&cbuf, code, code_end, tty);
}
// Prepare for detection code execution and clear work buffer.
--- a/src/hotspot/cpu/sparc/assembler_sparc.hpp Fri May 17 13:21:44 2019 +0100
+++ b/src/hotspot/cpu/sparc/assembler_sparc.hpp Thu May 23 11:07:37 2019 +0100
@@ -335,6 +335,14 @@
Lookaside = 1 << 4
};
+ //---< calculate length of instruction >---
+ // With SPARC being a RISC architecture, this always is BytesPerInstWord
+ // instruction must start at passed address
+ static unsigned int instr_len(unsigned char *instr) { return BytesPerInstWord; }
+
+ //---< longest instructions >---
+ static unsigned int instr_maxlen() { return BytesPerInstWord; }
+
static bool is_in_wdisp_range(address a, address b, int nbits) {
intptr_t d = intptr_t(b) - intptr_t(a);
return is_simm(d, nbits + 2);
--- a/src/hotspot/cpu/sparc/c2_globals_sparc.hpp Fri May 17 13:21:44 2019 +0100
+++ b/src/hotspot/cpu/sparc/c2_globals_sparc.hpp Thu May 23 11:07:37 2019 +0100
@@ -80,7 +80,7 @@
// Ergonomics related flags
define_pd_global(uint64_t,MaxRAM, 128ULL*G);
-define_pd_global(uintx, CodeCacheMinBlockLength, 4);
+define_pd_global(uintx, CodeCacheMinBlockLength, 6);
define_pd_global(uintx, CodeCacheMinimumUseSpace, 400*K);
define_pd_global(bool, TrapBasedRangeChecks, false); // Not needed on sparc.
--- a/src/hotspot/cpu/sparc/disassembler_sparc.hpp Fri May 17 13:21:44 2019 +0100
+++ b/src/hotspot/cpu/sparc/disassembler_sparc.hpp Thu May 23 11:07:37 2019 +0100
@@ -33,4 +33,24 @@
return "v9only";
}
+ // Returns address of n-th instruction preceding addr,
+ // NULL if no preceding instruction can be found.
+ // With SPARC being a RISC architecture, this always is BytesPerInstWord
+ // It might be beneficial to check "is_readable" as we do on ppc and s390.
+ static address find_prev_instr(address addr, int n_instr) {
+ return addr - BytesPerInstWord*n_instr;
+ }
+
+ // special-case instruction decoding.
+ // There may be cases where the binutils disassembler doesn't do
+ // the perfect job. In those cases, decode_instruction0 may kick in
+ // and do it right.
+ // If nothing had to be done, just return "here", otherwise return "here + instr_len(here)"
+ static address decode_instruction0(address here, outputStream* st, address virtual_begin = NULL) {
+ return here;
+ }
+
+ // platform-specific instruction annotations (like value of loaded constants)
+ static void annotate(address pc, outputStream* st) { };
+
#endif // CPU_SPARC_DISASSEMBLER_SPARC_HPP
--- a/src/hotspot/cpu/sparc/sparc.ad Fri May 17 13:21:44 2019 +0100
+++ b/src/hotspot/cpu/sparc/sparc.ad Thu May 23 11:07:37 2019 +0100
@@ -1,5 +1,5 @@
//
-// Copyright (c) 1998, 2017, Oracle and/or its affiliates. All rights reserved.
+// Copyright (c) 1998, 2019, Oracle and/or its affiliates. All rights reserved.
// DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
//
// This code is free software; you can redistribute it and/or modify it
@@ -1295,7 +1295,8 @@
#ifndef PRODUCT
ATTRIBUTE_PRINTF(2, 3)
static void print_helper(outputStream* st, const char* format, ...) {
- if (st->position() > 0) {
+ const int tab_size = 8;
+ if (st->position() > tab_size) {
st->cr();
st->sp();
}
--- a/src/hotspot/cpu/sparc/vm_version_sparc.cpp Fri May 17 13:21:44 2019 +0100
+++ b/src/hotspot/cpu/sparc/vm_version_sparc.cpp Thu May 23 11:07:37 2019 +0100
@@ -139,12 +139,12 @@
if (FLAG_IS_DEFAULT(AllocatePrefetchLines)) {
const int ap_lns = AllocatePrefetchLines;
const int ap_inc = cache_line_size < 64 ? ap_lns : (ap_lns + 1) / 2;
- FLAG_SET_ERGO(intx, AllocatePrefetchLines, ap_lns + ap_inc);
+ FLAG_SET_ERGO(AllocatePrefetchLines, ap_lns + ap_inc);
}
if (FLAG_IS_DEFAULT(AllocateInstancePrefetchLines)) {
const int ip_lns = AllocateInstancePrefetchLines;
const int ip_inc = cache_line_size < 64 ? ip_lns : (ip_lns + 1) / 2;
- FLAG_SET_ERGO(intx, AllocateInstancePrefetchLines, ip_lns + ip_inc);
+ FLAG_SET_ERGO(AllocateInstancePrefetchLines, ip_lns + ip_inc);
}
}
#endif /* COMPILER2 */
--- a/src/hotspot/cpu/x86/assembler_x86.hpp Fri May 17 13:21:44 2019 +0100
+++ b/src/hotspot/cpu/x86/assembler_x86.hpp Thu May 23 11:07:37 2019 +0100
@@ -630,6 +630,17 @@
_true = 7
};
+ //---< calculate length of instruction >---
+ // As instruction size can't be found out easily on x86/x64,
+ // we just use '4' for len and maxlen.
+ // instruction must start at passed address
+ static unsigned int instr_len(unsigned char *instr) { return 4; }
+
+ //---< longest instructions >---
+ // Max instruction length is not specified in architecture documentation.
+ // We could use a "safe enough" estimate (15), but just default to
+ // instruction length guess from above.
+ static unsigned int instr_maxlen() { return 4; }
// NOTE: The general philopsophy of the declarations here is that 64bit versions
// of instructions are freely declared without the need for wrapping them an ifdef.
--- a/src/hotspot/cpu/x86/c2_globals_x86.hpp Fri May 17 13:21:44 2019 +0100
+++ b/src/hotspot/cpu/x86/c2_globals_x86.hpp Thu May 23 11:07:37 2019 +0100
@@ -88,7 +88,7 @@
define_pd_global(uintx, NonProfiledCodeHeapSize, 21*M);
define_pd_global(uintx, ProfiledCodeHeapSize, 22*M);
define_pd_global(uintx, NonNMethodCodeHeapSize, 5*M );
-define_pd_global(uintx, CodeCacheMinBlockLength, 4);
+define_pd_global(uintx, CodeCacheMinBlockLength, 6);
define_pd_global(uintx, CodeCacheMinimumUseSpace, 400*K);
define_pd_global(bool, TrapBasedRangeChecks, false); // Not needed on x86.
--- a/src/hotspot/cpu/x86/disassembler_x86.hpp Fri May 17 13:21:44 2019 +0100
+++ b/src/hotspot/cpu/x86/disassembler_x86.hpp Thu May 23 11:07:37 2019 +0100
@@ -33,4 +33,25 @@
return "";
}
+ // Returns address of n-th instruction preceding addr,
+ // NULL if no preceding instruction can be found.
+ // On CISC architectures, it is difficult to impossible to step
+ // backwards in the instruction stream. Therefore just return NULL.
+ // It might be beneficial to check "is_readable" as we do on ppc and s390.
+ static address find_prev_instr(address addr, int n_instr) {
+ return NULL;
+ }
+
+ // special-case instruction decoding.
+ // There may be cases where the binutils disassembler doesn't do
+ // the perfect job. In those cases, decode_instruction0 may kick in
+ // and do it right.
+ // If nothing had to be done, just return "here", otherwise return "here + instr_len(here)"
+ static address decode_instruction0(address here, outputStream* st, address virtual_begin = NULL) {
+ return here;
+ }
+
+ // platform-specific instruction annotations (like value of loaded constants)
+ static void annotate(address pc, outputStream* st) { };
+
#endif // CPU_X86_DISASSEMBLER_X86_HPP
--- a/src/hotspot/cpu/x86/rdtsc_x86.cpp Fri May 17 13:21:44 2019 +0100
+++ b/src/hotspot/cpu/x86/rdtsc_x86.cpp Thu May 23 11:07:37 2019 +0100
@@ -145,7 +145,7 @@
static bool ergonomics() {
const bool invtsc_support = Rdtsc::is_supported();
if (FLAG_IS_DEFAULT(UseFastUnorderedTimeStamps) && invtsc_support) {
- FLAG_SET_ERGO(bool, UseFastUnorderedTimeStamps, true);
+ FLAG_SET_ERGO(UseFastUnorderedTimeStamps, true);
}
bool ft_enabled = UseFastUnorderedTimeStamps && invtsc_support;
--- a/src/hotspot/cpu/x86/x86_64.ad Fri May 17 13:21:44 2019 +0100
+++ b/src/hotspot/cpu/x86/x86_64.ad Thu May 23 11:07:37 2019 +0100
@@ -918,19 +918,19 @@
st->print("\t");
}
- st->print_cr("popq rbp");
+ st->print_cr("popq rbp");
if (do_polling() && C->is_method_compilation()) {
st->print("\t");
if (SafepointMechanism::uses_thread_local_poll()) {
- st->print_cr("movq rscratch1, poll_offset[r15_thread] #polling_page_address\n\t"
- "testl rax, [rscratch1]\t"
+ st->print_cr("movq rscratch1, poll_offset[r15_thread] #polling_page_address\n\t"
+ "testl rax, [rscratch1]\t"
"# Safepoint: poll for GC");
} else if (Assembler::is_polling_page_far()) {
- st->print_cr("movq rscratch1, #polling_page_address\n\t"
- "testl rax, [rscratch1]\t"
+ st->print_cr("movq rscratch1, #polling_page_address\n\t"
+ "testl rax, [rscratch1]\t"
"# Safepoint: poll for GC");
} else {
- st->print_cr("testl rax, [rip + #offset_to_poll_page]\t"
+ st->print_cr("testl rax, [rip + #offset_to_poll_page]\t"
"# Safepoint: poll for GC");
}
}
@@ -10303,10 +10303,10 @@
match(Set p (AddI (AndI (CmpLTMask p q) y) (SubI p q)));
effect(KILL cr);
ins_cost(300);
- format %{ "subl $p,$q\t# cadd_cmpLTMask\n\t"
- "jge done\n\t"
- "addl $p,$y\n"
- "done: " %}
+ format %{ "subl $p,$q\t# cadd_cmpLTMask\n\t"
+ "jge done\n\t"
+ "addl $p,$y\n"
+ "done: " %}
ins_encode %{
Register Rp = $p$$Register;
Register Rq = $q$$Register;
@@ -10328,10 +10328,10 @@
ins_cost(300);
- format %{ "cmpl $p, $q\t# and_cmpLTMask\n\t"
- "jlt done\n\t"
- "xorl $y, $y\n"
- "done: " %}
+ format %{ "cmpl $p, $q\t# and_cmpLTMask\n\t"
+ "jlt done\n\t"
+ "xorl $y, $y\n"
+ "done: " %}
ins_encode %{
Register Rp = $p$$Register;
Register Rq = $q$$Register;
@@ -11888,7 +11888,7 @@
%{
match(Set cr (CmpU src zero));
- format %{ "testl $src, $src\t# unsigned" %}
+ format %{ "testl $src, $src\t# unsigned" %}
opcode(0x85);
ins_encode(REX_reg_reg(src, src), OpcP, reg_reg(src, src));
ins_pipe(ialu_cr_reg_imm);
@@ -12431,7 +12431,7 @@
effect(USE labl);
ins_cost(300);
- format %{ "j$cop,u $labl" %}
+ format %{ "j$cop,u $labl" %}
size(6);
ins_encode %{
Label* L = $labl$$label;
@@ -12445,7 +12445,7 @@
effect(USE labl);
ins_cost(200);
- format %{ "j$cop,u $labl" %}
+ format %{ "j$cop,u $labl" %}
size(6);
ins_encode %{
Label* L = $labl$$label;
@@ -12461,10 +12461,10 @@
ins_cost(200);
format %{ $$template
if ($cop$$cmpcode == Assembler::notEqual) {
- $$emit$$"jp,u $labl\n\t"
+ $$emit$$"jp,u $labl\n\t"
$$emit$$"j$cop,u $labl"
} else {
- $$emit$$"jp,u done\n\t"
+ $$emit$$"jp,u done\n\t"
$$emit$$"j$cop,u $labl\n\t"
$$emit$$"done:"
}
@@ -12666,10 +12666,10 @@
ins_cost(300);
format %{ $$template
if ($cop$$cmpcode == Assembler::notEqual) {
- $$emit$$"jp,u,s $labl\n\t"
- $$emit$$"j$cop,u,s $labl"
+ $$emit$$"jp,u,s $labl\n\t"
+ $$emit$$"j$cop,u,s $labl"
} else {
- $$emit$$"jp,u,s done\n\t"
+ $$emit$$"jp,u,s done\n\t"
$$emit$$"j$cop,u,s $labl\n\t"
$$emit$$"done:"
}
@@ -12745,7 +12745,7 @@
match(SafePoint);
effect(KILL cr);
- format %{ "testl rax, [rip + #offset_to_poll_page]\t"
+ format %{ "testl rax, [rip + #offset_to_poll_page]\t"
"# Safepoint: poll for GC" %}
ins_cost(125);
ins_encode %{
@@ -12761,7 +12761,7 @@
match(SafePoint poll);
effect(KILL cr, USE poll);
- format %{ "testl rax, [$poll]\t"
+ format %{ "testl rax, [$poll]\t"
"# Safepoint: poll for GC" %}
ins_cost(125);
ins_encode %{
@@ -12777,7 +12777,7 @@
match(SafePoint poll);
effect(KILL cr, USE poll);
- format %{ "testl rax, [$poll]\t"
+ format %{ "testl rax, [$poll]\t"
"# Safepoint: poll for GC" %}
ins_cost(125);
size(4); /* setting an explicit size will cause debug builds to assert if size is incorrect */
--- a/src/hotspot/cpu/zero/assembler_zero.hpp Fri May 17 13:21:44 2019 +0100
+++ b/src/hotspot/cpu/zero/assembler_zero.hpp Thu May 23 11:07:37 2019 +0100
@@ -37,6 +37,12 @@
public:
void pd_patch_instruction(address branch, address target, const char* file, int line);
+
+ //---< calculate length of instruction >---
+ static unsigned int instr_len(unsigned char *instr) { return 1; }
+
+ //---< longest instructions >---
+ static unsigned int instr_maxlen() { return 1; }
};
class MacroAssembler : public Assembler {
--- a/src/hotspot/cpu/zero/disassembler_zero.hpp Fri May 17 13:21:44 2019 +0100
+++ b/src/hotspot/cpu/zero/disassembler_zero.hpp Thu May 23 11:07:37 2019 +0100
@@ -34,4 +34,24 @@
return "";
}
+ // Returns address of n-th instruction preceding addr,
+ // NULL if no preceding instruction can be found.
+ // On ZERO, we assume a constant instruction length of 1 byte.
+ // It might be beneficial to check "is_readable" as we do on ppc and s390.
+ static address find_prev_instr(address addr, int n_instr) {
+ return addr - 1*n_instr;
+ }
+
+ // special-case instruction decoding.
+ // There may be cases where the binutils disassembler doesn't do
+ // the perfect job. In those cases, decode_instruction0 may kick in
+ // and do it right.
+ // If nothing had to be done, just return "here", otherwise return "here + instr_len(here)"
+ static address decode_instruction0(address here, outputStream* st, address virtual_begin = NULL) {
+ return here;
+ }
+
+ // platform-specific instruction annotations (like value of loaded constants)
+ static void annotate(address pc, outputStream* st) { };
+
#endif // CPU_ZERO_DISASSEMBLER_ZERO_HPP
--- a/src/hotspot/os/aix/os_aix.cpp Fri May 17 13:21:44 2019 +0100
+++ b/src/hotspot/os/aix/os_aix.cpp Thu May 23 11:07:37 2019 +0100
@@ -3447,7 +3447,7 @@
// fall back to 4K paged mode and use mmap for everything.
trcVerbose("4K page mode");
Aix::_page_size = 4*K;
- FLAG_SET_ERGO(bool, Use64KPages, false);
+ FLAG_SET_ERGO(Use64KPages, false);
}
} else {
// datapsize = 64k. Data segment, thread stacks are 64k paged.
@@ -3457,11 +3457,11 @@
assert0(g_multipage_support.can_use_64K_pages);
Aix::_page_size = 64*K;
trcVerbose("64K page mode");
- FLAG_SET_ERGO(bool, Use64KPages, true);
+ FLAG_SET_ERGO(Use64KPages, true);
}
// For now UseLargePages is just ignored.
- FLAG_SET_ERGO(bool, UseLargePages, false);
+ FLAG_SET_ERGO(UseLargePages, false);
_page_sizes[0] = 0;
// debug trace
--- a/src/hotspot/os/windows/os_windows.cpp Fri May 17 13:21:44 2019 +0100
+++ b/src/hotspot/os/windows/os_windows.cpp Thu May 23 11:07:37 2019 +0100
@@ -4072,7 +4072,7 @@
init_page_sizes((size_t) win32::vm_page_size());
// This may be overridden later when argument processing is done.
- FLAG_SET_ERGO(bool, UseLargePagesIndividualAllocation, false);
+ FLAG_SET_ERGO(UseLargePagesIndividualAllocation, false);
// Initialize main_process and main_thread
main_process = GetCurrentProcess(); // Remember main_process is a pseudo handle
--- a/src/hotspot/os_cpu/linux_ppc/thread_linux_ppc.cpp Fri May 17 13:21:44 2019 +0100
+++ b/src/hotspot/os_cpu/linux_ppc/thread_linux_ppc.cpp Thu May 23 11:07:37 2019 +0100
@@ -1,6 +1,6 @@
/*
- * Copyright (c) 1997, 2018, Oracle and/or its affiliates. All rights reserved.
- * Copyright (c) 2012, 2014 SAP SE. All rights reserved.
+ * Copyright (c) 1997, 2019, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 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
@@ -92,9 +92,8 @@
return false;
}
-// Forte Analyzer AsyncGetCallTrace profiling support is not implemented on Linux/PPC.
+// Forte Analyzer AsyncGetCallTrace profiling support.
bool JavaThread::pd_get_top_frame_for_signal_handler(frame* fr_addr, void* ucontext, bool isInJava) {
- assert(this->is_Java_thread(), "must be JavaThread");
return pd_get_top_frame_for_profiling(fr_addr, ucontext, isInJava);
}
--- a/src/hotspot/os_cpu/linux_s390/thread_linux_s390.cpp Fri May 17 13:21:44 2019 +0100
+++ b/src/hotspot/os_cpu/linux_s390/thread_linux_s390.cpp Thu May 23 11:07:37 2019 +0100
@@ -90,10 +90,9 @@
return false;
}
-// Forte Analyzer AsyncGetCallTrace profiling support is not implemented on Linux/S390x.
+// Forte Analyzer AsyncGetCallTrace profiling support.
bool JavaThread::pd_get_top_frame_for_signal_handler(frame* fr_addr, void* ucontext, bool isInJava) {
- Unimplemented();
- return false;
+ return pd_get_top_frame_for_profiling(fr_addr, ucontext, isInJava);
}
void JavaThread::cache_global_variables() { }
--- a/src/hotspot/share/Xusage.txt Fri May 17 13:21:44 2019 +0100
+++ b/src/hotspot/share/Xusage.txt Thu May 23 11:07:37 2019 +0100
@@ -13,6 +13,7 @@
-Xmx<size> set maximum Java heap size
-Xss<size> set java thread stack size
-Xfuture enable strictest checks, anticipating future default
+ (deprecated)
-Xrs reduce use of OS signals by Java/VM (see documentation)
-Xcheck:jni perform additional checks for JNI functions
-Xshare:off do not attempt to use shared class data
--- a/src/hotspot/share/aot/aotLoader.hpp Fri May 17 13:21:44 2019 +0100
+++ b/src/hotspot/share/aot/aotLoader.hpp Thu May 23 11:07:37 2019 +0100
@@ -54,7 +54,7 @@
static void add_heap(AOTCodeHeap *heap);
static void add_library(AOTLib *lib);
#endif
- static void initialize() NOT_AOT({ FLAG_SET_ERGO(bool, UseAOT, false); });
+ static void initialize() NOT_AOT({ FLAG_SET_ERGO(UseAOT, false); });
static void universe_init() NOT_AOT_RETURN;
static void set_narrow_oop_shift() NOT_AOT_RETURN;
--- a/src/hotspot/share/asm/codeBuffer.cpp Fri May 17 13:21:44 2019 +0100
+++ b/src/hotspot/share/asm/codeBuffer.cpp Thu May 23 11:07:37 2019 +0100
@@ -86,7 +86,8 @@
// External buffer, in a predefined CodeBlob.
// Important: The code_start must be taken exactly, and not realigned.
CodeBuffer::CodeBuffer(CodeBlob* blob) {
- initialize_misc("static buffer");
+ // Provide code buffer with meaningful name
+ initialize_misc(blob->name());
initialize(blob->content_begin(), blob->content_size());
verify_section_allocation();
}
@@ -1035,7 +1036,9 @@
}
void CodeBuffer::block_comment(intptr_t offset, const char * comment) {
- _code_strings.add_comment(offset, comment);
+ if (_collect_comments) {
+ _code_strings.add_comment(offset, comment);
+ }
}
const char* CodeBuffer::code_string(const char* str) {
@@ -1148,15 +1151,23 @@
const char* CodeStrings::_prefix = " ;; "; // default: can be changed via set_prefix
+// Check if any block comments are pending for the given offset.
+bool CodeStrings::has_block_comment(intptr_t offset) const {
+ if (_strings == NULL) return false;
+ CodeString* c = find(offset);
+ return c != NULL;
+}
+
void CodeStrings::print_block_comment(outputStream* stream, intptr_t offset) const {
- check_valid();
- if (_strings != NULL) {
+ check_valid();
+ if (_strings != NULL) {
CodeString* c = find(offset);
while (c && c->offset() == offset) {
stream->bol();
stream->print("%s", _prefix);
// Don't interpret as format strings since it could contain %
- stream->print_raw_cr(c->string());
+ stream->print_raw(c->string());
+ stream->bol(); // advance to next line only if string didn't contain a cr() at the end.
c = c->next_comment();
}
}
@@ -1186,7 +1197,7 @@
void CodeBuffer::decode() {
ttyLocker ttyl;
- Disassembler::decode(decode_begin(), insts_end());
+ Disassembler::decode(decode_begin(), insts_end(), tty);
_decode_begin = insts_end();
}
@@ -1217,4 +1228,10 @@
}
}
+// Directly disassemble code buffer.
+void CodeBuffer::decode(address start, address end) {
+ ttyLocker ttyl;
+ Disassembler::decode(this, start, end, tty);
+}
+
#endif // PRODUCT
--- a/src/hotspot/share/asm/codeBuffer.hpp Fri May 17 13:21:44 2019 +0100
+++ b/src/hotspot/share/asm/codeBuffer.hpp Thu May 23 11:07:37 2019 +0100
@@ -289,6 +289,7 @@
const char* add_string(const char * string) PRODUCT_RETURN_(return NULL;);
void add_comment(intptr_t offset, const char * comment) PRODUCT_RETURN;
+ bool has_block_comment(intptr_t offset) const;
void print_block_comment(outputStream* stream, intptr_t offset) const PRODUCT_RETURN;
// MOVE strings from other to this; invalidate other.
void assign(CodeStrings& other) PRODUCT_RETURN;
@@ -296,6 +297,7 @@
void copy(CodeStrings& other) PRODUCT_RETURN;
// FREE strings; invalidate this.
void free() PRODUCT_RETURN;
+
// Guarantee that _strings are used at most once; assign and free invalidate a buffer.
inline void check_valid() const {
#ifdef ASSERT
@@ -377,6 +379,7 @@
OopRecorder* _oop_recorder;
CodeStrings _code_strings;
+ bool _collect_comments; // Indicate if we need to collect block comments at all.
OopRecorder _default_oop_recorder; // override with initialize_oop_recorder
Arena* _overflow_arena;
@@ -403,6 +406,14 @@
#if INCLUDE_AOT
_immutable_PIC = false;
#endif
+
+ // Collect block comments, but restrict collection to cases where a disassembly is output.
+ _collect_comments = ( PrintAssembly
+ || PrintStubCode
+ || PrintMethodHandleStubs
+ || PrintInterpreter
+ || PrintSignatureHandlers
+ );
}
void initialize(address code_start, csize_t code_size) {
@@ -604,6 +615,23 @@
}
}
+ // Directly disassemble code buffer.
+ // Print the comment associated with offset on stream, if there is one.
+ virtual void print_block_comment(outputStream* stream, address block_begin) {
+#ifndef PRODUCT
+ intptr_t offset = (intptr_t)(block_begin - _total_start); // I assume total_start is not correct for all code sections.
+ _code_strings.print_block_comment(stream, offset);
+#endif
+ }
+ bool has_block_comment(address block_begin) {
+#ifndef PRODUCT
+ intptr_t offset = (intptr_t)(block_begin - _total_start); // I assume total_start is not correct for all code sections.
+ return _code_strings.has_block_comment(offset);
+#else
+ return false;
+#endif
+ }
+
// Code generation
void relocate(address at, RelocationHolder const& rspec, int format = 0) {
_insts.relocate(at, rspec, format);
@@ -650,7 +678,8 @@
void decode();
void print();
#endif
-
+ // Directly disassemble code buffer.
+ void decode(address start, address end);
// The following header contains architecture-specific implementations
#include CPU_HEADER(codeBuffer)
--- a/src/hotspot/share/c1/c1_Runtime1.cpp Fri May 17 13:21:44 2019 +0100
+++ b/src/hotspot/share/c1/c1_Runtime1.cpp Thu May 23 11:07:37 2019 +0100
@@ -575,7 +575,7 @@
tempst.print("compiled method <%s>\n"
" at PC" INTPTR_FORMAT " for thread " INTPTR_FORMAT,
nm->method()->print_value_string(), p2i(pc), p2i(thread));
- Exceptions::log_exception(exception, tempst);
+ Exceptions::log_exception(exception, tempst.as_string());
}
// for AbortVMOnException flag
Exceptions::debug_check_abort(exception);
--- a/src/hotspot/share/c1/c1_globals.cpp Fri May 17 13:21:44 2019 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,37 +0,0 @@
-/*
- * Copyright (c) 2000, 2016, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- *
- */
-
-#include "precompiled.hpp"
-#include "c1/c1_globals.hpp"
-
-C1_FLAGS(MATERIALIZE_DEVELOPER_FLAG, \
- MATERIALIZE_PD_DEVELOPER_FLAG, \
- MATERIALIZE_PRODUCT_FLAG, \
- MATERIALIZE_PD_PRODUCT_FLAG, \
- MATERIALIZE_DIAGNOSTIC_FLAG, \
- MATERIALIZE_PD_DIAGNOSTIC_FLAG, \
- MATERIALIZE_NOTPRODUCT_FLAG, \
- IGNORE_RANGE, \
- IGNORE_CONSTRAINT, \
- IGNORE_WRITEABLE)
--- a/src/hotspot/share/c1/c1_globals.hpp Fri May 17 13:21:44 2019 +0100
+++ b/src/hotspot/share/c1/c1_globals.hpp Thu May 23 11:07:37 2019 +0100
@@ -25,7 +25,7 @@
#ifndef SHARE_C1_C1_GLOBALS_HPP
#define SHARE_C1_C1_GLOBALS_HPP
-#include "runtime/globals.hpp"
+#include "runtime/globals_shared.hpp"
#include "utilities/macros.hpp"
#include CPU_HEADER(c1_globals)
@@ -324,17 +324,5 @@
develop(bool, PrintCFGToFile, false, \
"print control flow graph to a separate file during compilation") \
\
-// Read default values for c1 globals
-
-C1_FLAGS(DECLARE_DEVELOPER_FLAG, \
- DECLARE_PD_DEVELOPER_FLAG, \
- DECLARE_PRODUCT_FLAG, \
- DECLARE_PD_PRODUCT_FLAG, \
- DECLARE_DIAGNOSTIC_FLAG, \
- DECLARE_PD_DIAGNOSTIC_FLAG, \
- DECLARE_NOTPRODUCT_FLAG, \
- IGNORE_RANGE, \
- IGNORE_CONSTRAINT, \
- IGNORE_WRITEABLE)
#endif // SHARE_C1_C1_GLOBALS_HPP
--- a/src/hotspot/share/classfile/classListParser.cpp Fri May 17 13:21:44 2019 +0100
+++ b/src/hotspot/share/classfile/classListParser.cpp Thu May 23 11:07:37 2019 +0100
@@ -295,14 +295,14 @@
if (!is_id_specified()) {
error("If source location is specified, id must be also specified");
}
- InstanceKlass* k = ClassLoaderExt::load_class(class_name, _source, CHECK_NULL);
-
if (strncmp(_class_name, "java/", 5) == 0) {
log_info(cds)("Prohibited package for non-bootstrap classes: %s.class from %s",
_class_name, _source);
return NULL;
}
+ InstanceKlass* k = ClassLoaderExt::load_class(class_name, _source, CHECK_NULL);
+
if (k != NULL) {
if (k->local_interfaces()->length() != _interfaces->length()) {
print_specified_interfaces();
@@ -461,4 +461,3 @@
ShouldNotReachHere();
return NULL;
}
-
--- a/src/hotspot/share/classfile/classLoader.cpp Fri May 17 13:21:44 2019 +0100
+++ b/src/hotspot/share/classfile/classLoader.cpp Thu May 23 11:07:37 2019 +0100
@@ -36,6 +36,7 @@
#include "classfile/klassFactory.hpp"
#include "classfile/symbolTable.hpp"
#include "classfile/systemDictionary.hpp"
+#include "classfile/systemDictionaryShared.hpp"
#include "classfile/vmSymbols.hpp"
#include "compiler/compileBroker.hpp"
#include "interpreter/bytecodeStream.hpp"
@@ -468,7 +469,7 @@
#if INCLUDE_CDS
void ClassLoader::exit_with_path_failure(const char* error, const char* message) {
- assert(DumpSharedSpaces, "only called at dump time");
+ assert(DumpSharedSpaces || DynamicDumpSharedSpaces, "only called at dump time");
tty->print_cr("Hint: enable -Xlog:class+path=info to diagnose the failure");
vm_exit_during_initialization(error, message);
}
@@ -534,7 +535,7 @@
trace_class_path("bootstrap loader class path=", sys_class_path);
}
#if INCLUDE_CDS
- if (DumpSharedSpaces) {
+ if (DumpSharedSpaces || DynamicDumpSharedSpaces) {
_shared_paths_misc_info->add_boot_classpath(sys_class_path);
}
#endif
@@ -550,16 +551,16 @@
return _shared_paths_misc_info->buffer();
}
-bool ClassLoader::check_shared_paths_misc_info(void *buf, int size) {
+bool ClassLoader::check_shared_paths_misc_info(void *buf, int size, bool is_static) {
SharedPathsMiscInfo* checker = new SharedPathsMiscInfo((char*)buf, size);
- bool result = checker->check();
+ bool result = checker->check(is_static);
delete checker;
return result;
}
void ClassLoader::setup_app_search_path(const char *class_path) {
- assert(DumpSharedSpaces, "Sanity");
+ assert(DumpSharedSpaces || DynamicDumpSharedSpaces, "Sanity");
Thread* THREAD = Thread::current();
int len = (int)strlen(class_path);
@@ -587,7 +588,7 @@
void ClassLoader::add_to_module_path_entries(const char* path,
ClassPathEntry* entry) {
assert(entry != NULL, "ClassPathEntry should not be NULL");
- assert(DumpSharedSpaces, "dump time only");
+ assert(DumpSharedSpaces || DynamicDumpSharedSpaces, "dump time only");
// The entry does not exist, add to the list
if (_module_path_entries == NULL) {
@@ -601,7 +602,7 @@
// Add a module path to the _module_path_entries list.
void ClassLoader::update_module_path_entry_list(const char *path, TRAPS) {
- assert(DumpSharedSpaces, "dump time only");
+ assert(DumpSharedSpaces || DynamicDumpSharedSpaces, "dump time only");
struct stat st;
if (os::stat(path, &st) != 0) {
tty->print_cr("os::stat error %d (%s). CDS dump aborted (path was \"%s\").",
@@ -709,7 +710,7 @@
bool set_base_piece = true;
#if INCLUDE_CDS
- if (DumpSharedSpaces) {
+ if (DumpSharedSpaces || DynamicDumpSharedSpaces) {
if (!Arguments::has_jimage()) {
vm_exit_during_initialization("CDS is not supported in exploded JDK build", NULL);
}
@@ -976,7 +977,7 @@
return true;
} else {
#if INCLUDE_CDS
- if (DumpSharedSpaces) {
+ if (DumpSharedSpaces || DynamicDumpSharedSpaces) {
_shared_paths_misc_info->add_nonexist_path(path);
}
#endif
@@ -1334,6 +1335,10 @@
// appear in the _patch_mod_entries. The runtime shared class visibility
// check will determine if a shared class is visible based on the runtime
// environemnt, including the runtime --patch-module setting.
+ //
+ // DynamicDumpSharedSpaces requires UseSharedSpaces to be enabled. Since --patch-module
+ // is not supported with UseSharedSpaces, it is not supported with DynamicDumpSharedSpaces.
+ assert(!DynamicDumpSharedSpaces, "sanity");
if (!DumpSharedSpaces) {
stream = search_module_entries(_patch_mod_entries, class_name, file_name, CHECK_NULL);
}
@@ -1423,7 +1428,7 @@
// Record the shared classpath index and loader type for classes loaded
// by the builtin loaders at dump time.
void ClassLoader::record_result(InstanceKlass* ik, const ClassFileStream* stream, TRAPS) {
- assert(DumpSharedSpaces, "sanity");
+ assert(DumpSharedSpaces || DynamicDumpSharedSpaces, "sanity");
assert(stream != NULL, "sanity");
if (ik->is_unsafe_anonymous()) {
@@ -1513,6 +1518,8 @@
// user defined classloader.
if (classpath_index < 0) {
assert(ik->shared_classpath_index() < 0, "Sanity");
+ ik->set_shared_classpath_index(UNREGISTERED_INDEX);
+ SystemDictionaryShared::set_shared_class_misc_info(ik, (ClassFileStream*)stream);
return;
}
} else {
@@ -1595,7 +1602,7 @@
load_jimage_library();
#if INCLUDE_CDS
// initialize search path
- if (DumpSharedSpaces) {
+ if (DumpSharedSpaces || DynamicDumpSharedSpaces) {
_shared_paths_misc_info = new SharedPathsMiscInfo();
}
#endif
@@ -1604,14 +1611,14 @@
#if INCLUDE_CDS
void ClassLoader::initialize_shared_path() {
- if (DumpSharedSpaces) {
+ if (DumpSharedSpaces || DynamicDumpSharedSpaces) {
ClassLoaderExt::setup_search_paths();
_shared_paths_misc_info->write_jint(0); // see comments in SharedPathsMiscInfo::check()
}
}
void ClassLoader::initialize_module_path(TRAPS) {
- if (DumpSharedSpaces) {
+ if (DumpSharedSpaces || DynamicDumpSharedSpaces) {
ClassLoaderExt::setup_module_paths(THREAD);
FileMapInfo::allocate_shared_path_table();
}
@@ -1677,6 +1684,7 @@
// entries will be added to the exploded build array.
if (!has_jrt_entry()) {
assert(!DumpSharedSpaces, "DumpSharedSpaces not supported with exploded module builds");
+ assert(!DynamicDumpSharedSpaces, "DynamicDumpSharedSpaces not supported with exploded module builds");
assert(!UseSharedSpaces, "UsedSharedSpaces not supported with exploded module builds");
// Set up the boot loader's _exploded_entries list. Note that this gets
// done before loading any classes, by the same thread that will
--- a/src/hotspot/share/classfile/classLoader.hpp Fri May 17 13:21:44 2019 +0100
+++ b/src/hotspot/share/classfile/classLoader.hpp Thu May 23 11:07:37 2019 +0100
@@ -398,7 +398,8 @@
// Helper function used by CDS code to get the number of module path
// entries during shared classpath setup time.
static int num_module_path_entries() {
- assert(DumpSharedSpaces, "Should only be called at CDS dump time");
+ assert(DumpSharedSpaces || DynamicDumpSharedSpaces,
+ "Should only be called at CDS dump time");
int num_entries = 0;
ClassPathEntry* e= ClassLoader::_module_path_entries;
while (e != NULL) {
@@ -410,7 +411,7 @@
static void finalize_shared_paths_misc_info();
static int get_shared_paths_misc_info_size();
static void* get_shared_paths_misc_info();
- static bool check_shared_paths_misc_info(void* info, int size);
+ static bool check_shared_paths_misc_info(void* info, int size, bool is_static);
static void exit_with_path_failure(const char* error, const char* message);
static char* skip_uri_protocol(char* source);
static void record_result(InstanceKlass* ik, const ClassFileStream* stream, TRAPS);
--- a/src/hotspot/share/classfile/classLoader.inline.hpp Fri May 17 13:21:44 2019 +0100
+++ b/src/hotspot/share/classfile/classLoader.inline.hpp Thu May 23 11:07:37 2019 +0100
@@ -62,7 +62,8 @@
// entries during shared classpath setup time.
inline int ClassLoader::num_boot_classpath_entries() {
- assert(DumpSharedSpaces, "Should only be called at CDS dump time");
+ assert(DumpSharedSpaces || DynamicDumpSharedSpaces,
+ "Should only be called at CDS dump time");
assert(has_jrt_entry(), "must have a java runtime image");
int num_entries = 1; // count the runtime image
ClassPathEntry* e = ClassLoader::_first_append_entry;
@@ -84,7 +85,8 @@
// Helper function used by CDS code to get the number of app classpath
// entries during shared classpath setup time.
inline int ClassLoader::num_app_classpath_entries() {
- assert(DumpSharedSpaces, "Should only be called at CDS dump time");
+ assert(DumpSharedSpaces || DynamicDumpSharedSpaces,
+ "Should only be called at CDS dump time");
int num_entries = 0;
ClassPathEntry* e= ClassLoader::_app_classpath_entries;
while (e != NULL) {
--- a/src/hotspot/share/classfile/classLoaderDataGraph.cpp Fri May 17 13:21:44 2019 +0100
+++ b/src/hotspot/share/classfile/classLoaderDataGraph.cpp Thu May 23 11:07:37 2019 +0100
@@ -596,14 +596,13 @@
DependencyContext::purge_dependency_contexts();
}
-int ClassLoaderDataGraph::resize_if_needed() {
+int ClassLoaderDataGraph::resize_dictionaries() {
assert(SafepointSynchronize::is_at_safepoint(), "must be at safepoint!");
int resized = 0;
- if (Dictionary::does_any_dictionary_needs_resizing()) {
- FOR_ALL_DICTIONARY(cld) {
- if (cld->dictionary()->resize_if_needed()) {
- resized++;
- }
+ assert (Dictionary::does_any_dictionary_needs_resizing(), "some dictionary should need resizing");
+ FOR_ALL_DICTIONARY(cld) {
+ if (cld->dictionary()->resize_if_needed()) {
+ resized++;
}
}
return resized;
--- a/src/hotspot/share/classfile/classLoaderDataGraph.hpp Fri May 17 13:21:44 2019 +0100
+++ b/src/hotspot/share/classfile/classLoaderDataGraph.hpp Thu May 23 11:07:37 2019 +0100
@@ -119,16 +119,14 @@
static GrowableArray<ClassLoaderData*>* new_clds();
static void set_should_purge(bool b) { _should_purge = b; }
- static void purge_if_needed() {
- // Only purge the CLDG for CMS if concurrent sweep is complete.
- if (_should_purge) {
- purge();
- // reset for next time.
- set_should_purge(false);
- }
+ static bool should_purge_and_reset() {
+ bool res = _should_purge;
+ // reset for next time.
+ set_should_purge(false);
+ return res;
}
- static int resize_if_needed();
+ static int resize_dictionaries();
static bool has_metaspace_oom() { return _metaspace_oom; }
static void set_metaspace_oom(bool value) { _metaspace_oom = value; }
--- a/src/hotspot/share/classfile/classLoaderExt.cpp Fri May 17 13:21:44 2019 +0100
+++ b/src/hotspot/share/classfile/classLoaderExt.cpp Thu May 23 11:07:37 2019 +0100
@@ -62,7 +62,8 @@
}
void ClassLoaderExt::setup_app_search_path() {
- assert(DumpSharedSpaces, "this function is only used with -Xshare:dump");
+ assert(DumpSharedSpaces || DynamicDumpSharedSpaces,
+ "this function is only used at CDS dump time");
_app_class_paths_start_index = ClassLoader::num_boot_classpath_entries();
char* app_class_path = os::strdup(Arguments::get_appclasspath());
@@ -92,7 +93,8 @@
}
}
void ClassLoaderExt::setup_module_paths(TRAPS) {
- assert(DumpSharedSpaces, "this function is only used with -Xshare:dump");
+ assert(DumpSharedSpaces || DynamicDumpSharedSpaces,
+ "this function is only used with CDS dump time");
_app_module_paths_start_index = ClassLoader::num_boot_classpath_entries() +
ClassLoader::num_app_classpath_entries();
Handle system_class_loader (THREAD, SystemDictionary::java_system_loader());
@@ -227,7 +229,7 @@
void ClassLoaderExt::record_result(const s2 classpath_index,
InstanceKlass* result,
TRAPS) {
- assert(DumpSharedSpaces, "Sanity");
+ assert(DumpSharedSpaces || DynamicDumpSharedSpaces, "Sanity");
// We need to remember where the class comes from during dumping.
oop loader = result->class_loader();
@@ -301,8 +303,6 @@
tty->print_cr("Preload Error: Failed to load %s", class_name);
return NULL;
}
- result->set_shared_classpath_index(UNREGISTERED_INDEX);
- SystemDictionaryShared::set_shared_class_misc_info(result, stream);
return result;
}
--- a/src/hotspot/share/classfile/compactHashtable.cpp Fri May 17 13:21:44 2019 +0100
+++ b/src/hotspot/share/classfile/compactHashtable.cpp Thu May 23 11:07:37 2019 +0100
@@ -27,6 +27,7 @@
#include "classfile/compactHashtable.hpp"
#include "classfile/javaClasses.hpp"
#include "logging/logMessage.hpp"
+#include "memory/dynamicArchive.hpp"
#include "memory/heapShared.inline.hpp"
#include "memory/metadataFactory.hpp"
#include "memory/metaspaceShared.hpp"
@@ -39,12 +40,14 @@
//
// The compact hash table writer implementations
//
-CompactHashtableWriter::CompactHashtableWriter(int num_buckets,
+CompactHashtableWriter::CompactHashtableWriter(int num_entries,
CompactHashtableStats* stats) {
- assert(DumpSharedSpaces, "dump-time only");
- assert(num_buckets > 0, "no buckets");
- _num_buckets = num_buckets;
- _num_entries = 0;
+ assert(DumpSharedSpaces || DynamicDumpSharedSpaces, "dump-time only");
+ assert(num_entries >= 0, "sanity");
+ _num_buckets = calculate_num_buckets(num_entries);
+ assert(_num_buckets > 0, "no buckets");
+
+ _num_entries_written = 0;
_buckets = NEW_C_HEAP_ARRAY(GrowableArray<Entry>*, _num_buckets, mtSymbol);
for (int i=0; i<_num_buckets; i++) {
_buckets[i] = new (ResourceObj::C_HEAP, mtSymbol) GrowableArray<Entry>(0, true, mtSymbol);
@@ -67,11 +70,24 @@
FREE_C_HEAP_ARRAY(GrowableArray<Entry>*, _buckets);
}
+size_t CompactHashtableWriter::estimate_size(int num_entries) {
+ int num_buckets = calculate_num_buckets(num_entries);
+ size_t bucket_bytes = MetaspaceShared::ro_array_bytesize<u4>(num_buckets + 1);
+
+ // In worst case, we have no VALUE_ONLY_BUCKET_TYPE, so each entry takes 2 slots
+ int entries_space = 2 * num_entries;
+ size_t entry_bytes = MetaspaceShared::ro_array_bytesize<u4>(entries_space);
+
+ return bucket_bytes
+ + entry_bytes
+ + SimpleCompactHashtable::calculate_header_size();
+}
+
// Add a symbol entry to the temporary hash table
void CompactHashtableWriter::add(unsigned int hash, u4 value) {
int index = hash % _num_buckets;
_buckets[index]->append_if_missing(Entry(hash, value));
- _num_entries++;
+ _num_entries_written++;
}
void CompactHashtableWriter::allocate_table() {
@@ -81,7 +97,7 @@
int bucket_size = bucket->length();
if (bucket_size == 1) {
entries_space++;
- } else {
+ } else if (bucket_size > 1) {
entries_space += 2 * bucket_size;
}
}
@@ -96,7 +112,7 @@
_stats->bucket_count = _num_buckets;
_stats->bucket_bytes = _compact_buckets->size() * BytesPerWord;
- _stats->hashentry_count = _num_entries;
+ _stats->hashentry_count = _num_entries_written;
_stats->hashentry_bytes = _compact_entries->size() * BytesPerWord;
}
@@ -144,19 +160,19 @@
dump_table(&summary);
int table_bytes = _stats->bucket_bytes + _stats->hashentry_bytes;
- address base_address = address(MetaspaceShared::shared_rs()->base());
- cht->init(base_address, _num_entries, _num_buckets,
+ address base_address = address(SharedBaseAddress);
+ cht->init(base_address, _num_entries_written, _num_buckets,
_compact_buckets->data(), _compact_entries->data());
LogMessage(cds, hashtables) msg;
if (msg.is_info()) {
double avg_cost = 0.0;
- if (_num_entries > 0) {
- avg_cost = double(table_bytes)/double(_num_entries);
+ if (_num_entries_written > 0) {
+ avg_cost = double(table_bytes)/double(_num_entries_written);
}
msg.info("Shared %s table stats -------- base: " PTR_FORMAT,
table_name, (intptr_t)base_address);
- msg.info("Number of entries : %9d", _num_entries);
+ msg.info("Number of entries : %9d", _num_entries_written);
msg.info("Total bytes used : %9d", table_bytes);
msg.info("Average bytes per entry : %9.3f", avg_cost);
msg.info("Average bucket size : %9.3f", summary.avg());
@@ -174,7 +190,28 @@
// The CompactHashtable implementation
//
+void SimpleCompactHashtable::init(address base_address, u4 entry_count, u4 bucket_count, u4* buckets, u4* entries) {
+ _bucket_count = bucket_count;
+ _entry_count = entry_count;
+ _base_address = base_address;
+ if (DynamicDumpSharedSpaces) {
+ _buckets = DynamicArchive::buffer_to_target(buckets);
+ _entries = DynamicArchive::buffer_to_target(entries);
+ } else {
+ _buckets = buckets;
+ _entries = entries;
+ }
+}
+
+size_t SimpleCompactHashtable::calculate_header_size() {
+ // We have 5 fields. Each takes up sizeof(intptr_t). See WriteClosure::do_u4
+ size_t bytes = sizeof(intptr_t) * 5;
+ return bytes;
+}
+
void SimpleCompactHashtable::serialize_header(SerializeClosure* soc) {
+ // NOTE: if you change this function, you MUST change the number 5 in
+ // calculate_header_size() accordingly.
soc->do_ptr((void**)&_base_address);
soc->do_u4(&_entry_count);
soc->do_u4(&_bucket_count);
--- a/src/hotspot/share/classfile/compactHashtable.hpp Fri May 17 13:21:44 2019 +0100
+++ b/src/hotspot/share/classfile/compactHashtable.hpp Thu May 23 11:07:37 2019 +0100
@@ -100,7 +100,7 @@
}; // class CompactHashtableWriter::Entry
private:
- int _num_entries;
+ int _num_entries_written;
int _num_buckets;
int _num_empty_buckets;
int _num_value_only_buckets;
@@ -112,7 +112,7 @@
public:
// This is called at dump-time only
- CompactHashtableWriter(int num_buckets, CompactHashtableStats* stats);
+ CompactHashtableWriter(int num_entries, CompactHashtableStats* stats);
~CompactHashtableWriter();
void add(unsigned int hash, u4 value);
@@ -120,18 +120,16 @@
private:
void allocate_table();
void dump_table(NumberSeq* summary);
+ static int calculate_num_buckets(int num_entries) {
+ int num_buckets = num_entries / SharedSymbolTableBucketSize;
+ // calculation of num_buckets can result in zero buckets, we need at least one
+ return (num_buckets < 1) ? 1 : num_buckets;
+ }
public:
void dump(SimpleCompactHashtable *cht, const char* table_name);
- static int default_num_buckets(size_t num_entries) {
- return default_num_buckets((int)num_entries);
- }
- static int default_num_buckets(int num_entries) {
- int num_buckets = num_entries / SharedSymbolTableBucketSize;
- // calculation of num_buckets can result in zero buckets, we need at least one
- return (num_buckets < 1) ? 1 : num_buckets;
- }
+ static size_t estimate_size(int num_entries);
};
#endif // INCLUDE_CDS
@@ -214,13 +212,7 @@
_entries = 0;
}
- void init(address base_address, u4 entry_count, u4 bucket_count, u4* buckets, u4* entries) {
- _base_address = base_address;
- _bucket_count = bucket_count;
- _entry_count = entry_count;
- _buckets = buckets;
- _entries = entries;
- }
+ void init(address base_address, u4 entry_count, u4 bucket_count, u4* buckets, u4* entries);
// Read/Write the table's header from/to the CDS archive
void serialize_header(SerializeClosure* soc) NOT_CDS_RETURN;
@@ -228,6 +220,8 @@
inline bool empty() {
return (_entry_count == 0);
}
+
+ static size_t calculate_header_size();
};
template <
--- a/src/hotspot/share/classfile/dictionary.cpp Fri May 17 13:21:44 2019 +0100
+++ b/src/hotspot/share/classfile/dictionary.cpp Thu May 23 11:07:37 2019 +0100
@@ -246,7 +246,7 @@
// Used to scan and relocate the classes during CDS archive dump.
void Dictionary::classes_do(MetaspaceClosure* it) {
- assert(DumpSharedSpaces, "dump-time only");
+ assert(DumpSharedSpaces || DynamicDumpSharedSpaces, "dump-time only");
for (int index = 0; index < table_size(); index++) {
for (DictionaryEntry* probe = bucket(index);
probe != NULL;
@@ -312,7 +312,6 @@
}
}
-
InstanceKlass* Dictionary::find_class(int index, unsigned int hash,
Symbol* name) {
assert_locked_or_safepoint(SystemDictionary_lock);
--- a/src/hotspot/share/classfile/klassFactory.cpp Fri May 17 13:21:44 2019 +0100
+++ b/src/hotspot/share/classfile/klassFactory.cpp Thu May 23 11:07:37 2019 +0100
@@ -218,7 +218,7 @@
JFR_ONLY(ON_KLASS_CREATION(result, parser, THREAD);)
#if INCLUDE_CDS
- if (DumpSharedSpaces) {
+ if (DumpSharedSpaces || DynamicDumpSharedSpaces) {
ClassLoader::record_result(result, stream, THREAD);
}
#endif // INCLUDE_CDS
--- a/src/hotspot/share/classfile/sharedPathsMiscInfo.cpp Fri May 17 13:21:44 2019 +0100
+++ b/src/hotspot/share/classfile/sharedPathsMiscInfo.cpp Thu May 23 11:07:37 2019 +0100
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2014, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2014, 2019, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -104,7 +104,7 @@
}
}
-bool SharedPathsMiscInfo::check() {
+bool SharedPathsMiscInfo::check(bool is_static) {
// The whole buffer must be 0 terminated so that we can use strlen and strcmp
// without fear.
_end_ptr -= sizeof(jint);
@@ -116,9 +116,10 @@
}
jshort cur_index = 0;
- jshort max_cp_index = FileMapInfo::current_info()->header()->max_used_path_index();
- jshort module_paths_start_index =
- FileMapInfo::current_info()->header()->app_module_paths_start_index();
+ FileMapHeader* header = is_static ? FileMapInfo::current_info()->header() :
+ FileMapInfo::dynamic_info()->header();
+ jshort max_cp_index = header->max_used_path_index();
+ jshort module_paths_start_index = header->app_module_paths_start_index();
while (_cur_ptr < _end_ptr) {
jint type;
const char* path = _cur_ptr;
@@ -136,7 +137,7 @@
}
// skip checking the class path(s) which was not referenced during CDS dump
if ((cur_index <= max_cp_index) || (cur_index >= module_paths_start_index)) {
- if (!check(type, path)) {
+ if (!check(type, path, is_static)) {
if (!PrintSharedArchiveAndExit) {
return false;
}
@@ -171,7 +172,7 @@
return p;
}
-bool SharedPathsMiscInfo::check(jint type, const char* path) {
+bool SharedPathsMiscInfo::check(jint type, const char* path, bool is_static) {
assert(UseSharedSpaces, "runtime only");
switch (type) {
case BOOT_PATH:
@@ -196,7 +197,9 @@
char* rp = skip_first_path_entry(runtime_boot_path);
char* dp = skip_first_path_entry(path);
- bool relaxed_check = !FileMapInfo::current_info()->header()->has_platform_or_app_classes();
+ bool relaxed_check = is_static ?
+ !FileMapInfo::current_info()->header()->has_platform_or_app_classes() :
+ !FileMapInfo::dynamic_info()->header()->has_platform_or_app_classes();
if (dp == NULL && rp == NULL) {
break; // ok, both runtime and dump time boot paths have modules_images only
} else if (dp == NULL && rp != NULL && relaxed_check) {
--- a/src/hotspot/share/classfile/sharedPathsMiscInfo.hpp Fri May 17 13:21:44 2019 +0100
+++ b/src/hotspot/share/classfile/sharedPathsMiscInfo.hpp Thu May 23 11:07:37 2019 +0100
@@ -67,7 +67,7 @@
protected:
static bool fail(const char* msg, const char* name = NULL);
- bool check(jint type, const char* path);
+ bool check(jint type, const char* path, bool is_static);
public:
enum {
@@ -162,7 +162,7 @@
}
public:
- bool check();
+ bool check(bool is_static);
};
#endif // SHARE_CLASSFILE_SHAREDPATHSMISCINFO_HPP
--- a/src/hotspot/share/classfile/stringTable.cpp Fri May 17 13:21:44 2019 +0100
+++ b/src/hotspot/share/classfile/stringTable.cpp Thu May 23 11:07:37 2019 +0100
@@ -372,16 +372,19 @@
bool rehash_warning;
do {
- if (_local_table->get(THREAD, lookup, stg, &rehash_warning)) {
- update_needs_rehash(rehash_warning);
- return stg.get_res_oop();
- }
+ // Callers have already looked up the String using the jchar* name, so just go to add.
WeakHandle<vm_string_table_data> wh = WeakHandle<vm_string_table_data>::create(string_h);
// The hash table takes ownership of the WeakHandle, even if it's not inserted.
if (_local_table->insert(THREAD, lookup, wh, &rehash_warning)) {
update_needs_rehash(rehash_warning);
return wh.resolve();
}
+ // In case another thread did a concurrent add, return value already in the table.
+ // This could fail if the String got gc'ed concurrently, so loop back until success.
+ if (_local_table->get(THREAD, lookup, stg, &rehash_warning)) {
+ update_needs_rehash(rehash_warning);
+ return stg.get_res_oop();
+ }
} while(true);
}
@@ -779,9 +782,7 @@
assert(HeapShared::is_heap_object_archiving_allowed(), "must be");
_shared_table.reset();
- int num_buckets = CompactHashtableWriter::default_num_buckets(_items_count);
- CompactHashtableWriter writer(num_buckets,
- &MetaspaceShared::stats()->string);
+ CompactHashtableWriter writer(_items_count, &MetaspaceShared::stats()->string);
// Copy the interned strings into the "string space" within the java heap
copy_shared_string_table(&writer);
--- a/src/hotspot/share/classfile/symbolTable.cpp Fri May 17 13:21:44 2019 +0100
+++ b/src/hotspot/share/classfile/symbolTable.cpp Thu May 23 11:07:37 2019 +0100
@@ -28,6 +28,7 @@
#include "classfile/javaClasses.hpp"
#include "classfile/symbolTable.hpp"
#include "memory/allocation.inline.hpp"
+#include "memory/dynamicArchive.hpp"
#include "memory/metaspaceClosure.hpp"
#include "memory/metaspaceShared.hpp"
#include "memory/resourceArea.hpp"
@@ -69,6 +70,11 @@
symbol_equals_compact_hashtable_entry
> _shared_table;
+static OffsetCompactHashtable<
+ const char*, Symbol*,
+ symbol_equals_compact_hashtable_entry
+> _dynamic_shared_table;
+
// --------------------------------------------------------------------------
typedef ConcurrentHashTable<Symbol*,
@@ -109,9 +115,11 @@
java_lang_String::hash_code((const jbyte*)s, len);
}
+#if INCLUDE_CDS
static uintx hash_shared_symbol(const char* s, int len) {
return java_lang_String::hash_code((const jbyte*)s, len);
}
+#endif
class SymbolTableConfig : public SymbolTableHash::BaseConfig {
private:
@@ -213,7 +221,7 @@
assert (len <= Symbol::max_length(), "should be checked by caller");
Symbol* sym;
- if (DumpSharedSpaces) {
+ if (DumpSharedSpaces || DynamicDumpSharedSpaces) {
c_heap = false;
}
if (c_heap) {
@@ -254,6 +262,7 @@
// all symbols from shared table
SharedSymbolIterator iter(cl);
_shared_table.iterate(&iter);
+ _dynamic_shared_table.iterate(&iter);
// all symbols from the dynamic table
SymbolsDo sd(cl);
@@ -275,7 +284,7 @@
};
void SymbolTable::metaspace_pointers_do(MetaspaceClosure* it) {
- assert(DumpSharedSpaces, "called only during dump time");
+ assert(DumpSharedSpaces || DynamicDumpSharedSpaces, "called only during dump time");
MetaspacePointersDo mpd(it);
_local_table->do_safepoint_scan(mpd);
}
@@ -287,19 +296,24 @@
return sym;
}
+#if INCLUDE_CDS
Symbol* SymbolTable::lookup_shared(const char* name,
int len, unsigned int hash) {
+ Symbol* sym = NULL;
if (!_shared_table.empty()) {
if (_alt_hash) {
// hash_code parameter may use alternate hashing algorithm but the shared table
// always uses the same original hash code.
hash = hash_shared_symbol(name, len);
}
- return _shared_table.lookup(name, hash, len);
- } else {
- return NULL;
+ sym = _shared_table.lookup(name, hash, len);
+ if (sym == NULL && DynamicArchive::is_mapped()) {
+ sym = _dynamic_shared_table.lookup(name, hash, len);
+ }
}
+ return sym;
}
+#endif
Symbol* SymbolTable::lookup_common(const char* name,
int len, unsigned int hash) {
@@ -467,14 +481,17 @@
Thread* THREAD = Thread::current();
do {
+ // Callers have looked up the symbol once, insert the symbol.
+ sym = allocate_symbol(name, len, heap);
+ if (_local_table->insert(THREAD, lookup, sym, &rehash_warning, &clean_hint)) {
+ break;
+ }
+ // In case another thread did a concurrent add, return value already in the table.
+ // This could fail if the symbol got deleted concurrently, so loop back until success.
if (_local_table->get(THREAD, lookup, stg, &rehash_warning)) {
sym = stg.get_res_sym();
break;
}
- sym = allocate_symbol(name, len, heap);
- if (_local_table->insert(THREAD, lookup, sym, &rehash_warning, &clean_hint)) {
- break;
- }
} while(true);
update_needs_rehash(rehash_warning);
@@ -588,6 +605,9 @@
unsigned int fixed_hash = hash_shared_symbol((const char*)sym->bytes(), sym->utf8_length());
assert(fixed_hash == hash_symbol((const char*)sym->bytes(), sym->utf8_length(), false),
"must not rehash during dumping");
+ if (DynamicDumpSharedSpaces) {
+ sym = DynamicArchive::original_to_target(sym);
+ }
_writer->add(fixed_hash, MetaspaceShared::object_delta_u4(sym));
return true;
}
@@ -598,30 +618,43 @@
_local_table->do_safepoint_scan(copy);
}
-void SymbolTable::write_to_archive() {
- _shared_table.reset();
+size_t SymbolTable::estimate_size_for_archive() {
+ return CompactHashtableWriter::estimate_size(int(_items_count));
+}
- int num_buckets = CompactHashtableWriter::default_num_buckets(
- _items_count);
- CompactHashtableWriter writer(num_buckets,
+void SymbolTable::write_to_archive(bool is_static_archive) {
+ _shared_table.reset();
+ _dynamic_shared_table.reset();
+
+ CompactHashtableWriter writer(int(_items_count),
&MetaspaceShared::stats()->symbol);
copy_shared_symbol_table(&writer);
- writer.dump(&_shared_table, "symbol");
+ if (is_static_archive) {
+ writer.dump(&_shared_table, "symbol");
- // Verify table is correct
- Symbol* sym = vmSymbols::java_lang_Object();
- const char* name = (const char*)sym->bytes();
- int len = sym->utf8_length();
- unsigned int hash = hash_symbol(name, len, _alt_hash);
- assert(sym == _shared_table.lookup(name, hash, len), "sanity");
+ // Verify table is correct
+ Symbol* sym = vmSymbols::java_lang_Object();
+ const char* name = (const char*)sym->bytes();
+ int len = sym->utf8_length();
+ unsigned int hash = hash_symbol(name, len, _alt_hash);
+ assert(sym == _shared_table.lookup(name, hash, len), "sanity");
+ } else {
+ writer.dump(&_dynamic_shared_table, "symbol");
+ }
}
-void SymbolTable::serialize_shared_table_header(SerializeClosure* soc) {
- _shared_table.serialize_header(soc);
-
+void SymbolTable::serialize_shared_table_header(SerializeClosure* soc,
+ bool is_static_archive) {
+ OffsetCompactHashtable<const char*, Symbol*, symbol_equals_compact_hashtable_entry> * table;
+ if (is_static_archive) {
+ table = &_shared_table;
+ } else {
+ table = &_dynamic_shared_table;
+ }
+ table->serialize_header(soc);
if (soc->writing()) {
// Sanity. Make sure we don't use the shared table at dump time
- _shared_table.reset();
+ table->reset();
}
}
#endif //INCLUDE_CDS
--- a/src/hotspot/share/classfile/symbolTable.hpp Fri May 17 13:21:44 2019 +0100
+++ b/src/hotspot/share/classfile/symbolTable.hpp Thu May 23 11:07:37 2019 +0100
@@ -137,7 +137,7 @@
const char** name, int* lengths,
int* cp_indices, unsigned int* hashValues);
- static Symbol* lookup_shared(const char* name, int len, unsigned int hash);
+ static Symbol* lookup_shared(const char* name, int len, unsigned int hash) NOT_CDS_RETURN_(NULL);
static Symbol* lookup_dynamic(const char* name, int len, unsigned int hash);
static Symbol* lookup_common(const char* name, int len, unsigned int hash);
@@ -209,8 +209,10 @@
private:
static void copy_shared_symbol_table(CompactHashtableWriter* ch_table);
public:
- static void write_to_archive() NOT_CDS_RETURN;
- static void serialize_shared_table_header(SerializeClosure* soc) NOT_CDS_RETURN;
+ static size_t estimate_size_for_archive() NOT_CDS_RETURN_(0);
+ static void write_to_archive(bool is_static_archive = true) NOT_CDS_RETURN;
+ static void serialize_shared_table_header(SerializeClosure* soc,
+ bool is_static_archive = true) NOT_CDS_RETURN;
static void metaspace_pointers_do(MetaspaceClosure* it);
// Jcmd
--- a/src/hotspot/share/classfile/systemDictionaryShared.cpp Fri May 17 13:21:44 2019 +0100
+++ b/src/hotspot/share/classfile/systemDictionaryShared.cpp Thu May 23 11:07:37 2019 +0100
@@ -44,6 +44,7 @@
#include "memory/oopFactory.hpp"
#include "memory/resourceArea.hpp"
#include "memory/universe.hpp"
+#include "memory/dynamicArchive.hpp"
#include "oops/instanceKlass.hpp"
#include "oops/klass.inline.hpp"
#include "oops/objArrayOop.inline.hpp"
@@ -61,9 +62,10 @@
objArrayOop SystemDictionaryShared::_shared_protection_domains = NULL;
objArrayOop SystemDictionaryShared::_shared_jar_urls = NULL;
objArrayOop SystemDictionaryShared::_shared_jar_manifests = NULL;
-DEBUG_ONLY(bool SystemDictionaryShared::_checked_excluded_classes = false;)
+DEBUG_ONLY(bool SystemDictionaryShared::_no_class_loading_should_happen = false;)
class DumpTimeSharedClassInfo: public CHeapObj<mtClass> {
+ bool _excluded;
public:
struct DTConstraint {
Symbol* _name;
@@ -76,7 +78,6 @@
int _id;
int _clsfile_size;
int _clsfile_crc32;
- bool _excluded;
GrowableArray<DTConstraint>* _verifier_constraints;
GrowableArray<char>* _verifier_constraint_flags;
@@ -115,6 +116,15 @@
}
}
}
+
+ void set_excluded() {
+ _excluded = true;
+ }
+
+ bool is_excluded() {
+ // _klass may become NULL due to DynamicArchiveBuilder::set_to_null
+ return _excluded || _klass == NULL;
+ }
};
class DumpTimeSharedClassTable: public ResourceHashtable<
@@ -131,8 +141,8 @@
DumpTimeSharedClassInfo* find_or_allocate_info_for(InstanceKlass* k) {
DumpTimeSharedClassInfo* p = get(k);
if (p == NULL) {
- assert(!SystemDictionaryShared::checked_excluded_classes(),
- "no new classes can be added after check_excluded_classes");
+ assert(!SystemDictionaryShared::no_class_loading_should_happen(),
+ "no new classes can be loaded while dumping archive");
put(k, DumpTimeSharedClassInfo());
p = get(k);
assert(p != NULL, "sanity");
@@ -146,16 +156,20 @@
public:
CountClassByCategory(DumpTimeSharedClassTable* table) : _table(table) {}
bool do_entry(InstanceKlass* k, DumpTimeSharedClassInfo& info) {
- if (SystemDictionaryShared::is_builtin(k)) {
- ++ _table->_builtin_count;
- } else {
- ++ _table->_unregistered_count;
+ if (!info.is_excluded()) {
+ if (info.is_builtin()) {
+ ++ _table->_builtin_count;
+ } else {
+ ++ _table->_unregistered_count;
+ }
}
return true; // keep on iterating
}
};
void update_counts() {
+ _builtin_count = 0;
+ _unregistered_count = 0;
CountClassByCategory counter(this);
iterate(&counter);
}
@@ -250,26 +264,36 @@
return (char*)(address(this) + verifier_constraint_flags_offset());
}
+ static u4 object_delta_u4(Symbol* sym) {
+ if (DynamicDumpSharedSpaces) {
+ sym = DynamicArchive::original_to_target(sym);
+ }
+ return MetaspaceShared::object_delta_u4(sym);
+ }
+
void init(DumpTimeSharedClassInfo& info) {
_klass = info._klass;
- _num_constraints = info.num_constraints();
if (!SystemDictionaryShared::is_builtin(_klass)) {
CrcInfo* c = crc();
c->_clsfile_size = info._clsfile_size;
c->_clsfile_crc32 = info._clsfile_crc32;
}
+ _num_constraints = info.num_constraints();
if (_num_constraints > 0) {
RTConstraint* constraints = verifier_constraints();
char* flags = verifier_constraint_flags();
int i;
for (i = 0; i < _num_constraints; i++) {
- constraints[i]._name = MetaspaceShared::object_delta_u4(info._verifier_constraints->at(i)._name);
- constraints[i]._from_name = MetaspaceShared::object_delta_u4(info._verifier_constraints->at(i)._from_name);
+ constraints[i]._name = object_delta_u4(info._verifier_constraints->at(i)._name);
+ constraints[i]._from_name = object_delta_u4(info._verifier_constraints->at(i)._from_name);
}
for (i = 0; i < _num_constraints; i++) {
flags[i] = info._verifier_constraint_flags->at(i);
}
}
+ if (DynamicDumpSharedSpaces) {
+ _klass = DynamicArchive::original_to_target(info._klass);
+ }
}
bool matches(int clsfile_size, int clsfile_crc32) const {
@@ -307,7 +331,12 @@
return *info_pointer_addr(klass);
}
static void set_for(InstanceKlass* klass, RunTimeSharedClassInfo* record) {
- *info_pointer_addr(klass) = record;
+ if (DynamicDumpSharedSpaces) {
+ klass = DynamicArchive::original_to_buffer(klass);
+ *info_pointer_addr(klass) = DynamicArchive::buffer_to_target(record);
+ } else {
+ *info_pointer_addr(klass) = record;
+ }
}
// Used by RunTimeSharedDictionary to implement OffsetCompactHashtable::EQUALS
@@ -323,8 +352,12 @@
RunTimeSharedClassInfo::EQUALS> {};
static DumpTimeSharedClassTable* _dumptime_table = NULL;
+// SystemDictionaries in the base layer static archive
static RunTimeSharedDictionary _builtin_dictionary;
static RunTimeSharedDictionary _unregistered_dictionary;
+// SystemDictionaries in the top layer dynamic archive
+static RunTimeSharedDictionary _dynamic_builtin_dictionary;
+static RunTimeSharedDictionary _dynamic_unregistered_dictionary;
oop SystemDictionaryShared::shared_protection_domain(int index) {
return _shared_protection_domains->obj_at(index);
@@ -710,6 +743,17 @@
return false;
}
+bool SystemDictionaryShared::has_platform_or_app_classes() {
+ if (FileMapInfo::current_info()->header()->has_platform_or_app_classes()) {
+ return true;
+ }
+ if (DynamicArchive::is_mapped() &&
+ FileMapInfo::dynamic_info()->header()->has_platform_or_app_classes()) {
+ return true;
+ }
+ return false;
+}
+
// The following stack shows how this code is reached:
//
// [0] SystemDictionaryShared::find_or_load_shared_class()
@@ -747,7 +791,7 @@
Symbol* name, Handle class_loader, TRAPS) {
InstanceKlass* k = NULL;
if (UseSharedSpaces) {
- if (!FileMapInfo::current_info()->header()->has_platform_or_app_classes()) {
+ if (!has_platform_or_app_classes()) {
return NULL;
}
@@ -864,11 +908,17 @@
const RunTimeSharedClassInfo* record = find_record(&_unregistered_dictionary, class_name);
if (record == NULL) {
- return NULL;
+ if (DynamicArchive::is_mapped()) {
+ record = find_record(&_dynamic_unregistered_dictionary, class_name);
+ }
+ if (record == NULL) {
+ return NULL;
+ }
}
int clsfile_size = cfs->length();
int clsfile_crc32 = ClassLoader::crc32(0, (const char*)cfs->buffer(), cfs->length());
+
if (!record->matches(clsfile_size, clsfile_crc32)) {
return NULL;
}
@@ -971,6 +1021,7 @@
}
DumpTimeSharedClassInfo* SystemDictionaryShared::find_or_allocate_info_for(InstanceKlass* k) {
+ MutexLocker ml(DumpTimeTable_lock, Mutex::_no_safepoint_check_flag);
if (_dumptime_table == NULL) {
_dumptime_table = new (ResourceObj::C_HEAP, mtClass)DumpTimeSharedClassTable();
}
@@ -978,7 +1029,7 @@
}
void SystemDictionaryShared::set_shared_class_misc_info(InstanceKlass* k, ClassFileStream* cfs) {
- assert(DumpSharedSpaces, "only when dumping");
+ assert(DumpSharedSpaces || DynamicDumpSharedSpaces, "only when dumping");
assert(!is_builtin(k), "must be unregistered class");
DumpTimeSharedClassInfo* info = find_or_allocate_info_for(k);
info->_clsfile_size = cfs->length();
@@ -990,6 +1041,28 @@
}
void SystemDictionaryShared::remove_dumptime_info(InstanceKlass* k) {
+ MutexLocker ml(DumpTimeTable_lock, Mutex::_no_safepoint_check_flag);
+ DumpTimeSharedClassInfo* p = _dumptime_table->get(k);
+ if (p == NULL) {
+ return;
+ }
+ if (p->_verifier_constraints != NULL) {
+ for (int i = 0; i < p->_verifier_constraints->length(); i++) {
+ DumpTimeSharedClassInfo::DTConstraint constraint = p->_verifier_constraints->at(i);
+ if (constraint._name != NULL ) {
+ constraint._name->decrement_refcount();
+ }
+ if (constraint._from_name != NULL ) {
+ constraint._from_name->decrement_refcount();
+ }
+ }
+ FREE_C_HEAP_ARRAY(DTConstraint, p->_verifier_constraints);
+ p->_verifier_constraints = NULL;
+ }
+ if (p->_verifier_constraint_flags != NULL) {
+ FREE_C_HEAP_ARRAY(char, p->_verifier_constraint_flags);
+ p->_verifier_constraint_flags = NULL;
+ }
_dumptime_table->remove(k);
}
@@ -1010,9 +1083,11 @@
bool SystemDictionaryShared::should_be_excluded(InstanceKlass* k) {
if (k->class_loader_data()->is_unsafe_anonymous()) {
+ warn_excluded(k, "Unsafe anonymous class");
return true; // unsafe anonymous classes are not archived, skip
}
if (k->is_in_error_state()) {
+ warn_excluded(k, "In error state");
return true;
}
if (k->shared_classpath_index() < 0 && is_builtin(k)) {
@@ -1036,6 +1111,44 @@
warn_excluded(k, "JFR event class");
return true;
}
+ if (k->init_state() < InstanceKlass::linked) {
+ // In static dumping, we will attempt to link all classes. Those that fail to link will
+ // be marked as in error state.
+ assert(DynamicDumpSharedSpaces, "must be");
+
+ // TODO -- rethink how this can be handled.
+ // We should try to link ik, however, we can't do it here because
+ // 1. We are at VM exit
+ // 2. linking a class may cause other classes to be loaded, which means
+ // a custom ClassLoader.loadClass() may be called, at a point where the
+ // class loader doesn't expect it.
+ warn_excluded(k, "Not linked");
+ return true;
+ }
+ if (k->major_version() < 50 /*JAVA_6_VERSION*/) {
+ ResourceMark rm;
+ log_warning(cds)("Pre JDK 6 class not supported by CDS: %u.%u %s",
+ k->major_version(), k->minor_version(), k->name()->as_C_string());
+ return true;
+ }
+
+ InstanceKlass* super = k->java_super();
+ if (super != NULL && should_be_excluded(super)) {
+ ResourceMark rm;
+ log_warning(cds)("Skipping %s: super class %s is excluded", k->name()->as_C_string(), super->name()->as_C_string());
+ return true;
+ }
+
+ Array<InstanceKlass*>* interfaces = k->local_interfaces();
+ int len = interfaces->length();
+ for (int i = 0; i < len; i++) {
+ InstanceKlass* intf = interfaces->at(i);
+ if (should_be_excluded(intf)) {
+ log_warning(cds)("Skipping %s: interface %s is excluded", k->name()->as_C_string(), intf->name()->as_C_string());
+ return true;
+ }
+ }
+
return false;
}
@@ -1044,8 +1157,9 @@
ResourceMark rm;
const char* name = k->name()->as_C_string();
DumpTimeSharedClassInfo* info = _dumptime_table->get(k);
+ assert(_no_class_loading_should_happen, "class loading must be disabled");
guarantee(info != NULL, "Class %s must be entered into _dumptime_table", name);
- guarantee(!info->_excluded, "Should not attempt to archive excluded class %s", name);
+ guarantee(!info->is_excluded(), "Should not attempt to archive excluded class %s", name);
if (is_builtin(k)) {
guarantee(k->loader_type() != 0,
"Class loader type must be set for BUILTIN class %s", name);
@@ -1059,7 +1173,7 @@
public:
bool do_entry(InstanceKlass* k, DumpTimeSharedClassInfo& info) {
if (SystemDictionaryShared::should_be_excluded(k)) {
- info._excluded = true;
+ info.set_excluded();
}
return true; // keep on iterating
}
@@ -1068,13 +1182,13 @@
void SystemDictionaryShared::check_excluded_classes() {
ExcludeDumpTimeSharedClasses excl;
_dumptime_table->iterate(&excl);
- DEBUG_ONLY(_checked_excluded_classes = true;)
+ _dumptime_table->update_counts();
}
bool SystemDictionaryShared::is_excluded_class(InstanceKlass* k) {
- assert(_checked_excluded_classes, "sanity");
- assert(DumpSharedSpaces, "only when dumping");
- return find_or_allocate_info_for(k)->_excluded;
+ assert(_no_class_loading_should_happen, "sanity");
+ assert(DumpSharedSpaces || DynamicDumpSharedSpaces, "only when dumping");
+ return find_or_allocate_info_for(k)->is_excluded();
}
class IterateDumpTimeSharedClassTable : StackObj {
@@ -1083,7 +1197,7 @@
IterateDumpTimeSharedClassTable(MetaspaceClosure* it) : _it(it) {}
bool do_entry(InstanceKlass* k, DumpTimeSharedClassInfo& info) {
- if (!info._excluded) {
+ if (!info.is_excluded()) {
info.metaspace_pointers_do(_it);
}
return true; // keep on iterating
@@ -1097,18 +1211,27 @@
bool SystemDictionaryShared::add_verification_constraint(InstanceKlass* k, Symbol* name,
Symbol* from_name, bool from_field_is_protected, bool from_is_array, bool from_is_object) {
- assert(DumpSharedSpaces, "called at dump time only");
+ assert(DumpSharedSpaces || DynamicDumpSharedSpaces, "called at dump time only");
DumpTimeSharedClassInfo* info = find_or_allocate_info_for(k);
info->add_verification_constraint(k, name, from_name, from_field_is_protected,
from_is_array, from_is_object);
- if (is_builtin(k)) {
- // For builtin class loaders, we can try to complete the verification check at dump time,
- // because we can resolve all the constraint classes.
+
+ if (DynamicDumpSharedSpaces) {
+ // For dynamic dumping, we can resolve all the constraint classes for all class loaders during
+ // the initial run prior to creating the archive before vm exit. We will also perform verification
+ // check when running with the archive.
return false;
} else {
- // For non-builtin class loaders, we cannot complete the verification check at dump time,
- // because at dump time we don't know how to resolve classes for such loaders.
- return true;
+ if (is_builtin(k)) {
+ // For builtin class loaders, we can try to complete the verification check at dump time,
+ // because we can resolve all the constraint classes. We will also perform verification check
+ // when running with the archive.
+ return false;
+ } else {
+ // For non-builtin class loaders, we cannot complete the verification check at dump time,
+ // because at dump time we don't know how to resolve classes for such loaders.
+ return true;
+ }
}
}
@@ -1139,9 +1262,9 @@
if (log_is_enabled(Trace, cds, verification)) {
ResourceMark rm;
- log_trace(cds, verification)("add_verification_constraint: %s: %s must be subclass of %s",
+ log_trace(cds, verification)("add_verification_constraint: %s: %s must be subclass of %s [0x%x]",
k->external_name(), from_name->as_klass_external_name(),
- name->as_klass_external_name());
+ name->as_klass_external_name(), c);
}
}
@@ -1157,6 +1280,13 @@
Symbol* from_name = record->get_constraint_from_name(i);
char c = record->get_constraint_flag(i);
+ if (log_is_enabled(Trace, cds, verification)) {
+ ResourceMark rm(THREAD);
+ log_trace(cds, verification)("check_verification_constraint: %s: %s must be subclass of %s [0x%x]",
+ klass->external_name(), from_name->as_klass_external_name(),
+ name->as_klass_external_name(), c);
+ }
+
bool from_field_is_protected = (c & SystemDictionaryShared::FROM_FIELD_IS_PROTECTED) ? true : false;
bool from_is_array = (c & SystemDictionaryShared::FROM_IS_ARRAY) ? true : false;
bool from_is_object = (c & SystemDictionaryShared::FROM_IS_OBJECT) ? true : false;
@@ -1178,22 +1308,72 @@
}
}
+class EstimateSizeForArchive : StackObj {
+ size_t _shared_class_info_size;
+ int _num_builtin_klasses;
+ int _num_unregistered_klasses;
+
+public:
+ EstimateSizeForArchive() {
+ _shared_class_info_size = 0;
+ _num_builtin_klasses = 0;
+ _num_unregistered_klasses = 0;
+ }
+
+ bool do_entry(InstanceKlass* k, DumpTimeSharedClassInfo& info) {
+ if (!info.is_excluded()) {
+ size_t byte_size = RunTimeSharedClassInfo::byte_size(info._klass, info.num_constraints());
+ _shared_class_info_size += align_up(byte_size, BytesPerWord);
+ }
+ return true; // keep on iterating
+ }
+
+ size_t total() {
+ return _shared_class_info_size;
+ }
+};
+
+size_t SystemDictionaryShared::estimate_size_for_archive() {
+ EstimateSizeForArchive est;
+ _dumptime_table->iterate(&est);
+ return est.total() +
+ CompactHashtableWriter::estimate_size(_dumptime_table->count_of(true)) +
+ CompactHashtableWriter::estimate_size(_dumptime_table->count_of(false));
+}
+
class CopySharedClassInfoToArchive : StackObj {
CompactHashtableWriter* _writer;
bool _is_builtin;
public:
- CopySharedClassInfoToArchive(CompactHashtableWriter* writer, bool is_builtin)
+ CopySharedClassInfoToArchive(CompactHashtableWriter* writer,
+ bool is_builtin,
+ bool is_static_archive)
: _writer(writer), _is_builtin(is_builtin) {}
bool do_entry(InstanceKlass* k, DumpTimeSharedClassInfo& info) {
- if (!info._excluded && info.is_builtin() == _is_builtin) {
+ if (!info.is_excluded() && info.is_builtin() == _is_builtin) {
size_t byte_size = RunTimeSharedClassInfo::byte_size(info._klass, info.num_constraints());
- RunTimeSharedClassInfo* record =
- (RunTimeSharedClassInfo*)MetaspaceShared::read_only_space_alloc(byte_size);
+ RunTimeSharedClassInfo* record;
+ record = (RunTimeSharedClassInfo*)MetaspaceShared::read_only_space_alloc(byte_size);
record->init(info);
- unsigned int hash = primitive_hash<Symbol*>(info._klass->name());
- _writer->add(hash, MetaspaceShared::object_delta_u4(record));
+ unsigned int hash;
+ Symbol* name = info._klass->name();
+ if (DynamicDumpSharedSpaces) {
+ name = DynamicArchive::original_to_target(name);
+ }
+ hash = primitive_hash<Symbol*>(name);
+ u4 delta;
+ if (DynamicDumpSharedSpaces) {
+ delta = MetaspaceShared::object_delta_u4(DynamicArchive::buffer_to_target(record));
+ } else {
+ delta = MetaspaceShared::object_delta_u4(record);
+ }
+ _writer->add(hash, delta);
+ if (log_is_enabled(Trace, cds, hashtables)) {
+ ResourceMark rm;
+ log_trace(cds,hashtables)("%s dictionary: %s", (_is_builtin ? "builtin" : "unregistered"), info._klass->external_name());
+ }
// Save this for quick runtime lookup of InstanceKlass* -> RunTimeSharedClassInfo*
RunTimeSharedClassInfo::set_for(info._klass, record);
@@ -1202,25 +1382,36 @@
}
};
-void SystemDictionaryShared::write_dictionary(RunTimeSharedDictionary* dictionary, bool is_builtin) {
+void SystemDictionaryShared::write_dictionary(RunTimeSharedDictionary* dictionary,
+ bool is_builtin,
+ bool is_static_archive) {
CompactHashtableStats stats;
dictionary->reset();
- int num_buckets = CompactHashtableWriter::default_num_buckets(_dumptime_table->count_of(is_builtin));
- CompactHashtableWriter writer(num_buckets, &stats);
- CopySharedClassInfoToArchive copy(&writer, is_builtin);
+ CompactHashtableWriter writer(_dumptime_table->count_of(is_builtin), &stats);
+ CopySharedClassInfoToArchive copy(&writer, is_builtin, is_static_archive);
_dumptime_table->iterate(©);
writer.dump(dictionary, is_builtin ? "builtin dictionary" : "unregistered dictionary");
}
-void SystemDictionaryShared::write_to_archive() {
- _dumptime_table->update_counts();
- write_dictionary(&_builtin_dictionary, true);
- write_dictionary(&_unregistered_dictionary, false);
+void SystemDictionaryShared::write_to_archive(bool is_static_archive) {
+ if (is_static_archive) {
+ write_dictionary(&_builtin_dictionary, true);
+ write_dictionary(&_unregistered_dictionary, false);
+ } else {
+ write_dictionary(&_dynamic_builtin_dictionary, true);
+ write_dictionary(&_dynamic_unregistered_dictionary, false);
+ }
}
-void SystemDictionaryShared::serialize_dictionary_headers(SerializeClosure* soc) {
- _builtin_dictionary.serialize_header(soc);
- _unregistered_dictionary.serialize_header(soc);
+void SystemDictionaryShared::serialize_dictionary_headers(SerializeClosure* soc,
+ bool is_static_archive) {
+ if (is_static_archive) {
+ _builtin_dictionary.serialize_header(soc);
+ _unregistered_dictionary.serialize_header(soc);
+ } else {
+ _dynamic_builtin_dictionary.serialize_header(soc);
+ _dynamic_unregistered_dictionary.serialize_header(soc);
+ }
}
const RunTimeSharedClassInfo*
@@ -1237,9 +1428,16 @@
const RunTimeSharedClassInfo* record = find_record(&_builtin_dictionary, name);
if (record) {
return record->_klass;
- } else {
- return NULL;
}
+
+ if (DynamicArchive::is_mapped()) {
+ record = find_record(&_dynamic_builtin_dictionary, name);
+ if (record) {
+ return record->_klass;
+ }
+ }
+
+ return NULL;
}
void SystemDictionaryShared::update_shared_entry(InstanceKlass* k, int id) {
@@ -1266,14 +1464,31 @@
SharedDictionaryPrinter p(st);
_builtin_dictionary.iterate(&p);
_unregistered_dictionary.iterate(&p);
+ if (DynamicArchive::is_mapped()) {
+ _dynamic_builtin_dictionary.iterate(&p);
+ _unregistered_dictionary.iterate(&p);
+ }
}
}
-void SystemDictionaryShared::print() { print_on(tty); }
-
void SystemDictionaryShared::print_table_statistics(outputStream* st) {
if (UseSharedSpaces) {
_builtin_dictionary.print_table_statistics(st, "Builtin Shared Dictionary");
_unregistered_dictionary.print_table_statistics(st, "Unregistered Shared Dictionary");
+ if (DynamicArchive::is_mapped()) {
+ _dynamic_builtin_dictionary.print_table_statistics(st, "Dynamic Builtin Shared Dictionary");
+ _dynamic_unregistered_dictionary.print_table_statistics(st, "Unregistered Shared Dictionary");
+ }
}
}
+
+bool SystemDictionaryShared::empty_dumptime_table() {
+ if (_dumptime_table == NULL) {
+ return true;
+ }
+ _dumptime_table->update_counts();
+ if (_dumptime_table->count_of(true) == 0 && _dumptime_table->count_of(false) == 0){
+ return true;
+ }
+ return false;
+}
--- a/src/hotspot/share/classfile/systemDictionaryShared.hpp Fri May 17 13:21:44 2019 +0100
+++ b/src/hotspot/share/classfile/systemDictionaryShared.hpp Thu May 23 11:07:37 2019 +0100
@@ -109,6 +109,7 @@
class RunTimeSharedDictionary;
class SystemDictionaryShared: public SystemDictionary {
+ friend class ExcludeDumpTimeSharedClasses;
public:
enum {
FROM_FIELD_IS_PROTECTED = 1 << 0,
@@ -211,16 +212,21 @@
const ClassFileStream* cfs,
TRAPS);
static DumpTimeSharedClassInfo* find_or_allocate_info_for(InstanceKlass* k);
- static void write_dictionary(RunTimeSharedDictionary* dictionary, bool is_builtin);
+ static void write_dictionary(RunTimeSharedDictionary* dictionary,
+ bool is_builtin,
+ bool is_static_archive = true);
static bool is_jfr_event_class(InstanceKlass *k);
static void warn_excluded(InstanceKlass* k, const char* reason);
+ static bool should_be_excluded(InstanceKlass* k);
- DEBUG_ONLY(static bool _checked_excluded_classes;)
+ DEBUG_ONLY(static bool _no_class_loading_should_happen;)
public:
static InstanceKlass* find_builtin_class(Symbol* class_name);
static const RunTimeSharedClassInfo* find_record(RunTimeSharedDictionary* dict, Symbol* name);
+ static bool has_platform_or_app_classes();
+
// Called by PLATFORM/APP loader only
static InstanceKlass* find_or_load_shared_class(Symbol* class_name,
Handle class_loader,
@@ -288,18 +294,34 @@
static bool is_builtin(InstanceKlass* k) {
return (k->shared_classpath_index() != UNREGISTERED_INDEX);
}
- static bool should_be_excluded(InstanceKlass* k);
static void check_excluded_classes();
static void validate_before_archiving(InstanceKlass* k);
static bool is_excluded_class(InstanceKlass* k);
static void dumptime_classes_do(class MetaspaceClosure* it);
- static void write_to_archive();
- static void serialize_dictionary_headers(class SerializeClosure* soc);
- static void print();
+ static size_t estimate_size_for_archive();
+ static void write_to_archive(bool is_static_archive = true);
+ static void serialize_dictionary_headers(class SerializeClosure* soc,
+ bool is_static_archive = true);
+ static void print() { return print_on(tty); }
static void print_on(outputStream* st) NOT_CDS_RETURN;
static void print_table_statistics(outputStream* st) NOT_CDS_RETURN;
+ static bool empty_dumptime_table() NOT_CDS_RETURN_(true);
- DEBUG_ONLY(static bool checked_excluded_classes() {return _checked_excluded_classes;})
+ DEBUG_ONLY(static bool no_class_loading_should_happen() {return _no_class_loading_should_happen;})
+
+#ifdef ASSERT
+ class NoClassLoadingMark: public StackObj {
+ public:
+ NoClassLoadingMark() {
+ assert(!_no_class_loading_should_happen, "must not be nested");
+ _no_class_loading_should_happen = true;
+ }
+ ~NoClassLoadingMark() {
+ _no_class_loading_should_happen = false;
+ }
+ };
+#endif
+
};
#endif // SHARE_CLASSFILE_SYSTEMDICTIONARYSHARED_HPP
--- a/src/hotspot/share/classfile/verificationType.cpp Fri May 17 13:21:44 2019 +0100
+++ b/src/hotspot/share/classfile/verificationType.cpp Thu May 23 11:07:37 2019 +0100
@@ -94,12 +94,14 @@
return true;
}
- if (DumpSharedSpaces && SystemDictionaryShared::add_verification_constraint(klass,
+ if (DumpSharedSpaces || DynamicDumpSharedSpaces) {
+ if (SystemDictionaryShared::add_verification_constraint(klass,
name(), from.name(), from_field_is_protected, from.is_array(),
from.is_object())) {
- // If add_verification_constraint() returns true, the resolution/check should be
- // delayed until runtime.
- return true;
+ // If add_verification_constraint() returns true, the resolution/check should be
+ // delayed until runtime.
+ return true;
+ }
}
return resolve_and_check_assignability(klass, name(), from.name(),
--- a/src/hotspot/share/code/codeBlob.cpp Fri May 17 13:21:44 2019 +0100
+++ b/src/hotspot/share/code/codeBlob.cpp Thu May 23 11:07:37 2019 +0100
@@ -183,8 +183,14 @@
jio_snprintf(stub_id, sizeof(stub_id), "%s%s", name1, name2);
if (PrintStubCode) {
ttyLocker ttyl;
+ tty->print_cr("- - - [BEGIN] - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
tty->print_cr("Decoding %s " INTPTR_FORMAT, stub_id, (intptr_t) stub);
- Disassembler::decode(stub->code_begin(), stub->code_end());
+ Disassembler::decode(stub->code_begin(), stub->code_end(), tty);
+ if ((stub->oop_maps() != NULL) && AbstractDisassembler::show_structs()) {
+ tty->print_cr("- - - [OOP MAPS]- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
+ stub->oop_maps()->print();
+ }
+ tty->print_cr("- - - [END] - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
tty->cr();
}
Forte::register_stub(stub_id, stub->code_begin(), stub->code_end());
@@ -263,6 +269,7 @@
}
void BufferBlob::free(BufferBlob *blob) {
+ assert(blob != NULL, "caller must check for NULL");
ThreadInVMfromUnknown __tiv; // get to VM state in case we block on CodeCache_lock
blob->flush();
{
--- a/src/hotspot/share/code/codeBlob.hpp Fri May 17 13:21:44 2019 +0100
+++ b/src/hotspot/share/code/codeBlob.hpp Thu May 23 11:07:37 2019 +0100
@@ -211,7 +211,7 @@
const ImmutableOopMap* oop_map_for_return_address(address return_address);
virtual void preserve_callee_argument_oops(frame fr, const RegisterMap* reg_map, OopClosure* f) = 0;
- // Frame support
+ // Frame support. Sizes are in word units.
int frame_size() const { return _frame_size; }
void set_frame_size(int size) { _frame_size = size; }
@@ -230,6 +230,10 @@
void dump_for_addr(address addr, outputStream* st, bool verbose) const;
void print_code();
+ bool has_block_comment(address block_begin) const {
+ intptr_t offset = (intptr_t)(block_begin - code_begin());
+ return _strings.has_block_comment(offset);
+ }
// Print the comment associated with offset on stream, if there is one
virtual void print_block_comment(outputStream* stream, address block_begin) const {
intptr_t offset = (intptr_t)(block_begin - code_begin());
--- a/src/hotspot/share/code/codeCache.cpp Fri May 17 13:21:44 2019 +0100
+++ b/src/hotspot/share/code/codeCache.cpp Thu May 23 11:07:37 2019 +0100
@@ -283,9 +283,9 @@
// Verify sizes and update flag values
assert(non_profiled_size + profiled_size + non_nmethod_size == cache_size, "Invalid code heap sizes");
- FLAG_SET_ERGO(uintx, NonNMethodCodeHeapSize, non_nmethod_size);
- FLAG_SET_ERGO(uintx, ProfiledCodeHeapSize, profiled_size);
- FLAG_SET_ERGO(uintx, NonProfiledCodeHeapSize, non_profiled_size);
+ FLAG_SET_ERGO(NonNMethodCodeHeapSize, non_nmethod_size);
+ FLAG_SET_ERGO(ProfiledCodeHeapSize, profiled_size);
+ FLAG_SET_ERGO(NonProfiledCodeHeapSize, non_profiled_size);
// If large page support is enabled, align code heaps according to large
// page size to make sure that code cache is covered by large pages.
@@ -941,9 +941,9 @@
initialize_heaps();
} else {
// Use a single code heap
- FLAG_SET_ERGO(uintx, NonNMethodCodeHeapSize, 0);
- FLAG_SET_ERGO(uintx, ProfiledCodeHeapSize, 0);
- FLAG_SET_ERGO(uintx, NonProfiledCodeHeapSize, 0);
+ FLAG_SET_ERGO(NonNMethodCodeHeapSize, 0);
+ FLAG_SET_ERGO(ProfiledCodeHeapSize, 0);
+ FLAG_SET_ERGO(NonProfiledCodeHeapSize, 0);
ReservedCodeSpace rs = reserve_heap_memory(ReservedCodeCacheSize);
add_heap(rs, "CodeCache", CodeBlobType::All);
}
--- a/src/hotspot/share/code/codeHeapState.cpp Fri May 17 13:21:44 2019 +0100
+++ b/src/hotspot/share/code/codeHeapState.cpp Thu May 23 11:07:37 2019 +0100
@@ -124,7 +124,7 @@
size_t _nlockedflush = 0; \
size_t _nflush_bytes = 0; \
size_t _capacity = _capa; \
- bufferedStream _sstobj = bufferedStream(_capa); \
+ bufferedStream _sstobj(_capa); \
bufferedStream* _sstbuf = &_sstobj; \
outputStream* _outbuf = _outst; \
bufferedStream* _anyst = &_sstobj; /* any stream. Use this to just print - no buffer flush. */
--- a/src/hotspot/share/code/exceptionHandlerTable.cpp Fri May 17 13:21:44 2019 +0100
+++ b/src/hotspot/share/code/exceptionHandlerTable.cpp Thu May 23 11:07:37 2019 +0100
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1998, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1998, 2019, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -185,10 +185,24 @@
}
void ImplicitExceptionTable::print(address base) const {
- tty->print("{");
- for( uint i=0; i<len(); i++ )
- tty->print("< " INTPTR_FORMAT ", " INTPTR_FORMAT " > ", p2i(base + *adr(i)), p2i(base + *(adr(i)+1)));
- tty->print_cr("}");
+ const uint n = len();
+ if (n > 0) {
+ const uint items_per_line = 3;
+ uint i;
+ tty->print_cr("ImplicitExceptionTable (size = %d entries, %d bytes):", n, size_in_bytes());
+ tty->print("{");
+ for (i = 0; i < n; i++) {
+ if (i%items_per_line == 0) {
+ tty->cr();
+ tty->fill_to(3);
+ }
+ tty->print("< " INTPTR_FORMAT ", " INTPTR_FORMAT " > ", p2i(base + *adr(i)), p2i(base + *(adr(i)+1)));
+ }
+ tty->bol();
+ tty->print_cr("}");
+ } else {
+ tty->print_cr("ImplicitExceptionTable is empty");
+ }
}
ImplicitExceptionTable::ImplicitExceptionTable(const nmethod* nm) {
--- a/src/hotspot/share/code/nmethod.cpp Fri May 17 13:21:44 2019 +0100
+++ b/src/hotspot/share/code/nmethod.cpp Thu May 23 11:07:37 2019 +0100
@@ -24,6 +24,7 @@
#include "precompiled.hpp"
#include "jvm.h"
+#include "asm/assembler.inline.hpp"
#include "code/codeCache.hpp"
#include "code/compiledIC.hpp"
#include "code/compiledMethod.inline.hpp"
@@ -456,14 +457,17 @@
{
MutexLocker mu(CodeCache_lock, Mutex::_no_safepoint_check_flag);
int native_nmethod_size = CodeBlob::allocation_size(code_buffer, sizeof(nmethod));
+
CodeOffsets offsets;
offsets.set_value(CodeOffsets::Verified_Entry, vep_offset);
offsets.set_value(CodeOffsets::Frame_Complete, frame_complete);
- nm = new (native_nmethod_size, CompLevel_none) nmethod(method(), compiler_none, native_nmethod_size,
- compile_id, &offsets,
- code_buffer, frame_size,
- basic_lock_owner_sp_offset,
- basic_lock_sp_offset, oop_maps);
+ nm = new (native_nmethod_size, CompLevel_none)
+ nmethod(method(), compiler_none, native_nmethod_size,
+ compile_id, &offsets,
+ code_buffer, frame_size,
+ basic_lock_owner_sp_offset,
+ basic_lock_sp_offset,
+ oop_maps);
NOT_PRODUCT(if (nm != NULL) native_nmethod_stats.note_native_nmethod(nm));
}
@@ -593,9 +597,9 @@
_native_basic_lock_sp_offset(basic_lock_sp_offset)
{
{
- int scopes_data_offset = 0;
- int deoptimize_offset = 0;
- int deoptimize_mh_offset = 0;
+ int scopes_data_offset = 0;
+ int deoptimize_offset = 0;
+ int deoptimize_mh_offset = 0;
debug_only(NoSafepointVerifier nsv;)
assert_locked_or_safepoint(CodeCache_lock);
@@ -658,18 +662,32 @@
xtty->stamp();
xtty->end_head(" address='" INTPTR_FORMAT "'", (intptr_t) this);
}
- // print the header part first
- print();
- // then print the requested information
+ // Print the header part, then print the requested information.
+ // This is both handled in decode2(), called via print_code() -> decode()
if (PrintNativeNMethods) {
+ tty->print_cr("-------------------------- Assembly (native nmethod) ---------------------------");
print_code();
- if (oop_maps != NULL) {
- oop_maps->print();
+ tty->print_cr("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ");
+#if defined(SUPPORT_DATA_STRUCTS)
+ if (AbstractDisassembler::show_structs()) {
+ if (oop_maps != NULL) {
+ tty->print("oop maps:"); // oop_maps->print_on(tty) outputs a cr() at the beginning
+ oop_maps->print_on(tty);
+ tty->print_cr("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ");
+ }
+ }
+#endif
+ } else {
+ print(); // print the header part only.
+ }
+#if defined(SUPPORT_DATA_STRUCTS)
+ if (AbstractDisassembler::show_structs()) {
+ if (PrintRelocations) {
+ print_relocations();
+ tty->print_cr("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ");
}
}
- if (PrintRelocations) {
- print_relocations();
- }
+#endif
if (xtty != NULL) {
xtty->tail("print_native_nmethod");
}
@@ -746,22 +764,21 @@
} else {
_deopt_mh_handler_begin = NULL;
}
- } else {
+ } else
#endif
- // Exception handler and deopt handler are in the stub section
- assert(offsets->value(CodeOffsets::Exceptions) != -1, "must be set");
- assert(offsets->value(CodeOffsets::Deopt ) != -1, "must be set");
-
- _exception_offset = _stub_offset + offsets->value(CodeOffsets::Exceptions);
- _deopt_handler_begin = (address) this + _stub_offset + offsets->value(CodeOffsets::Deopt);
- if (offsets->value(CodeOffsets::DeoptMH) != -1) {
- _deopt_mh_handler_begin = (address) this + _stub_offset + offsets->value(CodeOffsets::DeoptMH);
- } else {
- _deopt_mh_handler_begin = NULL;
+ {
+ // Exception handler and deopt handler are in the stub section
+ assert(offsets->value(CodeOffsets::Exceptions) != -1, "must be set");
+ assert(offsets->value(CodeOffsets::Deopt ) != -1, "must be set");
+
+ _exception_offset = _stub_offset + offsets->value(CodeOffsets::Exceptions);
+ _deopt_handler_begin = (address) this + _stub_offset + offsets->value(CodeOffsets::Deopt);
+ if (offsets->value(CodeOffsets::DeoptMH) != -1) {
+ _deopt_mh_handler_begin = (address) this + _stub_offset + offsets->value(CodeOffsets::DeoptMH);
+ } else {
+ _deopt_mh_handler_begin = NULL;
+ }
}
-#if INCLUDE_JVMCI
- }
-#endif
if (offsets->value(CodeOffsets::UnwindHandler) != -1) {
_unwind_handler_offset = code_offset() + offsets->value(CodeOffsets::UnwindHandler);
} else {
@@ -787,8 +804,7 @@
_verified_entry_point = code_begin() + offsets->value(CodeOffsets::Verified_Entry);
_osr_entry_point = code_begin() + offsets->value(CodeOffsets::OSR_Entry);
_exception_cache = NULL;
-
- _scopes_data_begin = (address) this + scopes_data_offset;
+ _scopes_data_begin = (address) this + scopes_data_offset;
_pc_desc_container.reset_to(scopes_pcs_begin());
@@ -909,33 +925,72 @@
xtty->stamp();
xtty->end_head();
}
- // print the header part first
- print();
- // then print the requested information
+ // Print the header part, then print the requested information.
+ // This is both handled in decode2().
if (printmethod) {
- print_code();
- print_pcs();
- if (oop_maps()) {
- oop_maps()->print();
+ HandleMark hm;
+ ResourceMark m;
+ if (is_compiled_by_c1()) {
+ tty->cr();
+ tty->print_cr("============================= C1-compiled nmethod ==============================");
+ }
+ if (is_compiled_by_jvmci()) {
+ tty->cr();
+ tty->print_cr("=========================== JVMCI-compiled nmethod =============================");
+ }
+ tty->print_cr("----------------------------------- Assembly -----------------------------------");
+ decode2(tty);
+#if defined(SUPPORT_DATA_STRUCTS)
+ if (AbstractDisassembler::show_structs()) {
+ // Print the oops from the underlying CodeBlob as well.
+ tty->print_cr("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ");
+ print_oops(tty);
+ tty->print_cr("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ");
+ print_metadata(tty);
+ tty->print_cr("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ");
+ print_pcs();
+ tty->print_cr("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ");
+ if (oop_maps() != NULL) {
+ tty->print("oop maps:"); // oop_maps()->print_on(tty) outputs a cr() at the beginning
+ oop_maps()->print_on(tty);
+ tty->print_cr("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ");
+ }
+ }
+#endif
+ } else {
+ print(); // print the header part only.
+ }
+
+#if defined(SUPPORT_DATA_STRUCTS)
+ if (AbstractDisassembler::show_structs()) {
+ if (printmethod || PrintDebugInfo || CompilerOracle::has_option_string(_method, "PrintDebugInfo")) {
+ print_scopes();
+ tty->print_cr("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ");
+ }
+ if (printmethod || PrintRelocations || CompilerOracle::has_option_string(_method, "PrintRelocations")) {
+ print_relocations();
+ tty->print_cr("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ");
+ }
+ if (printmethod || PrintDependencies || CompilerOracle::has_option_string(_method, "PrintDependencies")) {
+ print_dependencies();
+ tty->print_cr("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ");
+ }
+ if (printmethod || PrintExceptionHandlers) {
+ print_handler_table();
+ tty->print_cr("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ");
+ print_nul_chk_table();
+ tty->print_cr("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ");
+ }
+
+ if (printmethod) {
+ print_recorded_oops();
+ tty->print_cr("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ");
+ print_recorded_metadata();
+ tty->print_cr("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ");
}
}
- if (printmethod || PrintDebugInfo || CompilerOracle::has_option_string(_method, "PrintDebugInfo")) {
- print_scopes();
- }
- if (printmethod || PrintRelocations || CompilerOracle::has_option_string(_method, "PrintRelocations")) {
- print_relocations();
- }
- if (printmethod || PrintDependencies || CompilerOracle::has_option_string(_method, "PrintDependencies")) {
- print_dependencies();
- }
- if (printmethod || PrintExceptionHandlers) {
- print_handler_table();
- print_nul_chk_table();
- }
- if (printmethod) {
- print_recorded_oops();
- print_recorded_metadata();
- }
+#endif
+
if (xtty != NULL) {
xtty->tail("print_nmethod");
}
@@ -2062,10 +2117,9 @@
assert(cb != NULL && cb == this, "");
ttyLocker ttyl;
tty->print_cr("implicit exception happened at " INTPTR_FORMAT, p2i(pc));
- print();
+ // Print all available nmethod info.
+ print_nmethod(true);
method()->print_codes();
- print_code();
- print_pcs();
}
#endif
if (cont_offset == 0) {
@@ -2076,7 +2130,6 @@
}
-
void nmethod_init() {
// make sure you didn't forget to adjust the filler fields
assert(sizeof(nmethod) % oopSize == 0, "nmethod size must be multiple of a word");
@@ -2124,12 +2177,14 @@
bool ok() { return _ok; }
virtual void do_oop(oop* p) {
if (oopDesc::is_oop_or_null(*p)) return;
+ // Print diagnostic information before calling print_nmethod().
+ // Assertions therein might prevent call from returning.
+ tty->print_cr("*** non-oop " PTR_FORMAT " found at " PTR_FORMAT " (offset %d)",
+ p2i(*p), p2i(p), (int)((intptr_t)p - (intptr_t)_nm));
if (_ok) {
_nm->print_nmethod(true);
_ok = false;
}
- tty->print_cr("*** non-oop " PTR_FORMAT " found at " PTR_FORMAT " (offset %d)",
- p2i(*p), p2i(p), (int)((intptr_t)p - (intptr_t)_nm));
}
virtual void do_oop(narrowOop* p) { ShouldNotReachHere(); }
};
@@ -2238,107 +2293,104 @@
// Printing operations
void nmethod::print() const {
+ ttyLocker ttyl; // keep the following output all in one block
+ print(tty);
+}
+
+void nmethod::print(outputStream* st) const {
ResourceMark rm;
- ttyLocker ttyl; // keep the following output all in one block
-
- tty->print("Compiled method ");
+
+ st->print("Compiled method ");
if (is_compiled_by_c1()) {
- tty->print("(c1) ");
+ st->print("(c1) ");
} else if (is_compiled_by_c2()) {
- tty->print("(c2) ");
+ st->print("(c2) ");
} else if (is_compiled_by_jvmci()) {
- tty->print("(JVMCI) ");
+ st->print("(JVMCI) ");
} else {
- tty->print("(nm) ");
+ st->print("(n/a) ");
}
print_on(tty, NULL);
if (WizardMode) {
- tty->print("((nmethod*) " INTPTR_FORMAT ") ", p2i(this));
- tty->print(" for method " INTPTR_FORMAT , p2i(method()));
- tty->print(" { ");
- tty->print_cr("%s ", state());
- tty->print_cr("}:");
+ st->print("((nmethod*) " INTPTR_FORMAT ") ", p2i(this));
+ st->print(" for method " INTPTR_FORMAT , p2i(method()));
+ st->print(" { ");
+ st->print_cr("%s ", state());
+ st->print_cr("}:");
}
- if (size () > 0) tty->print_cr(" total in heap [" INTPTR_FORMAT "," INTPTR_FORMAT "] = %d",
- p2i(this),
- p2i(this) + size(),
- size());
- if (relocation_size () > 0) tty->print_cr(" relocation [" INTPTR_FORMAT "," INTPTR_FORMAT "] = %d",
- p2i(relocation_begin()),
- p2i(relocation_end()),
- relocation_size());
- if (consts_size () > 0) tty->print_cr(" constants [" INTPTR_FORMAT "," INTPTR_FORMAT "] = %d",
- p2i(consts_begin()),
- p2i(consts_end()),
- consts_size());
- if (insts_size () > 0) tty->print_cr(" main code [" INTPTR_FORMAT "," INTPTR_FORMAT "] = %d",
- p2i(insts_begin()),
- p2i(insts_end()),
- insts_size());
- if (stub_size () > 0) tty->print_cr(" stub code [" INTPTR_FORMAT "," INTPTR_FORMAT "] = %d",
- p2i(stub_begin()),
- p2i(stub_end()),
- stub_size());
- if (oops_size () > 0) tty->print_cr(" oops [" INTPTR_FORMAT "," INTPTR_FORMAT "] = %d",
- p2i(oops_begin()),
- p2i(oops_end()),
- oops_size());
- if (metadata_size () > 0) tty->print_cr(" metadata [" INTPTR_FORMAT "," INTPTR_FORMAT "] = %d",
- p2i(metadata_begin()),
- p2i(metadata_end()),
- metadata_size());
- if (scopes_data_size () > 0) tty->print_cr(" scopes data [" INTPTR_FORMAT "," INTPTR_FORMAT "] = %d",
- p2i(scopes_data_begin()),
- p2i(scopes_data_end()),
- scopes_data_size());
- if (scopes_pcs_size () > 0) tty->print_cr(" scopes pcs [" INTPTR_FORMAT "," INTPTR_FORMAT "] = %d",
- p2i(scopes_pcs_begin()),
- p2i(scopes_pcs_end()),
- scopes_pcs_size());
- if (dependencies_size () > 0) tty->print_cr(" dependencies [" INTPTR_FORMAT "," INTPTR_FORMAT "] = %d",
- p2i(dependencies_begin()),
- p2i(dependencies_end()),
- dependencies_size());
- if (handler_table_size() > 0) tty->print_cr(" handler table [" INTPTR_FORMAT "," INTPTR_FORMAT "] = %d",
- p2i(handler_table_begin()),
- p2i(handler_table_end()),
- handler_table_size());
- if (nul_chk_table_size() > 0) tty->print_cr(" nul chk table [" INTPTR_FORMAT "," INTPTR_FORMAT "] = %d",
- p2i(nul_chk_table_begin()),
- p2i(nul_chk_table_end()),
- nul_chk_table_size());
+ if (size () > 0) st->print_cr(" total in heap [" INTPTR_FORMAT "," INTPTR_FORMAT "] = %d",
+ p2i(this),
+ p2i(this) + size(),
+ size());
+ if (relocation_size () > 0) st->print_cr(" relocation [" INTPTR_FORMAT "," INTPTR_FORMAT "] = %d",
+ p2i(relocation_begin()),
+ p2i(relocation_end()),
+ relocation_size());
+ if (consts_size () > 0) st->print_cr(" constants [" INTPTR_FORMAT "," INTPTR_FORMAT "] = %d",
+ p2i(consts_begin()),
+ p2i(consts_end()),
+ consts_size());
+ if (insts_size () > 0) st->print_cr(" main code [" INTPTR_FORMAT "," INTPTR_FORMAT "] = %d",
+ p2i(insts_begin()),
+ p2i(insts_end()),
+ insts_size());
+ if (stub_size () > 0) st->print_cr(" stub code [" INTPTR_FORMAT "," INTPTR_FORMAT "] = %d",
+ p2i(stub_begin()),
+ p2i(stub_end()),
+ stub_size());
+ if (oops_size () > 0) st->print_cr(" oops [" INTPTR_FORMAT "," INTPTR_FORMAT "] = %d",
+ p2i(oops_begin()),
+ p2i(oops_end()),
+ oops_size());
+ if (metadata_size () > 0) st->print_cr(" metadata [" INTPTR_FORMAT "," INTPTR_FORMAT "] = %d",
+ p2i(metadata_begin()),
+ p2i(metadata_end()),
+ metadata_size());
+ if (scopes_data_size () > 0) st->print_cr(" scopes data [" INTPTR_FORMAT "," INTPTR_FORMAT "] = %d",
+ p2i(scopes_data_begin()),
+ p2i(scopes_data_end()),
+ scopes_data_size());
+ if (scopes_pcs_size () > 0) st->print_cr(" scopes pcs [" INTPTR_FORMAT "," INTPTR_FORMAT "] = %d",
+ p2i(scopes_pcs_begin()),
+ p2i(scopes_pcs_end()),
+ scopes_pcs_size());
+ if (dependencies_size () > 0) st->print_cr(" dependencies [" INTPTR_FORMAT "," INTPTR_FORMAT "] = %d",
+ p2i(dependencies_begin()),
+ p2i(dependencies_end()),
+ dependencies_size());
+ if (handler_table_size() > 0) st->print_cr(" handler table [" INTPTR_FORMAT "," INTPTR_FORMAT "] = %d",
+ p2i(handler_table_begin()),
+ p2i(handler_table_end()),
+ handler_table_size());
+ if (nul_chk_table_size() > 0) st->print_cr(" nul chk table [" INTPTR_FORMAT "," INTPTR_FORMAT "] = %d",
+ p2i(nul_chk_table_begin()),
+ p2i(nul_chk_table_end()),
+ nul_chk_table_size());
#if INCLUDE_JVMCI
- if (speculations_size () > 0) tty->print_cr(" speculations [" INTPTR_FORMAT "," INTPTR_FORMAT "] = %d",
- p2i(speculations_begin()),
- p2i(speculations_end()),
- speculations_size());
- if (jvmci_data_size () > 0) tty->print_cr(" JVMCI data [" INTPTR_FORMAT "," INTPTR_FORMAT "] = %d",
- p2i(jvmci_data_begin()),
- p2i(jvmci_data_end()),
- jvmci_data_size());
+ if (speculations_size () > 0) st->print_cr(" speculations [" INTPTR_FORMAT "," INTPTR_FORMAT "] = %d",
+ p2i(speculations_begin()),
+ p2i(speculations_end()),
+ speculations_size());
+ if (jvmci_data_size () > 0) st->print_cr(" JVMCI data [" INTPTR_FORMAT "," INTPTR_FORMAT "] = %d",
+ p2i(jvmci_data_begin()),
+ p2i(jvmci_data_end()),
+ jvmci_data_size());
#endif
}
-#ifndef PRODUCT
-
-void nmethod::print_scopes() {
- // Find the first pc desc for all scopes in the code and print it.
- ResourceMark rm;
- for (PcDesc* p = scopes_pcs_begin(); p < scopes_pcs_end(); p++) {
- if (p->scope_decode_offset() == DebugInformationRecorder::serialized_null)
- continue;
-
- ScopeDesc* sd = scope_desc_at(p->real_pc(this));
- while (sd != NULL) {
- sd->print_on(tty, p);
- sd = sd->sender();
- }
- }
+void nmethod::print_code() {
+ HandleMark hm;
+ ResourceMark m;
+ ttyLocker ttyl;
+ // Call the specialized decode method of this class.
+ decode(tty);
}
+#ifndef PRODUCT // called InstanceKlass methods are available only then. Declared as PRODUCT_RETURN
+
void nmethod::print_dependencies() {
ResourceMark rm;
ttyLocker ttyl; // keep the following output all in one block
@@ -2354,57 +2406,379 @@
deps.log_dependency(); // put it into the xml log also
}
}
-
-
+#endif
+
+#if defined(SUPPORT_DATA_STRUCTS)
+
+// Print the oops from the underlying CodeBlob.
+void nmethod::print_oops(outputStream* st) {
+ HandleMark hm;
+ ResourceMark m;
+ st->print("Oops:");
+ if (oops_begin() < oops_end()) {
+ st->cr();
+ for (oop* p = oops_begin(); p < oops_end(); p++) {
+ Disassembler::print_location((unsigned char*)p, (unsigned char*)oops_begin(), (unsigned char*)oops_end(), st, true, false);
+ st->print(PTR_FORMAT " ", *((uintptr_t*)p));
+ if (*p == Universe::non_oop_word()) {
+ st->print_cr("NON_OOP");
+ continue; // skip non-oops
+ }
+ if (*p == NULL) {
+ st->print_cr("NULL-oop");
+ continue; // skip non-oops
+ }
+ (*p)->print_value_on(st);
+ st->cr();
+ }
+ } else {
+ st->print_cr(" <list empty>");
+ }
+}
+
+// Print metadata pool.
+void nmethod::print_metadata(outputStream* st) {
+ HandleMark hm;
+ ResourceMark m;
+ st->print("Metadata:");
+ if (metadata_begin() < metadata_end()) {
+ st->cr();
+ for (Metadata** p = metadata_begin(); p < metadata_end(); p++) {
+ Disassembler::print_location((unsigned char*)p, (unsigned char*)metadata_begin(), (unsigned char*)metadata_end(), st, true, false);
+ st->print(PTR_FORMAT " ", *((uintptr_t*)p));
+ if (*p && *p != Universe::non_oop_word()) {
+ (*p)->print_value_on(st);
+ }
+ st->cr();
+ }
+ } else {
+ st->print_cr(" <list empty>");
+ }
+}
+
+#ifndef PRODUCT // ScopeDesc::print_on() is available only then. Declared as PRODUCT_RETURN
+void nmethod::print_scopes_on(outputStream* st) {
+ // Find the first pc desc for all scopes in the code and print it.
+ ResourceMark rm;
+ st->print("scopes:");
+ if (scopes_pcs_begin() < scopes_pcs_end()) {
+ st->cr();
+ for (PcDesc* p = scopes_pcs_begin(); p < scopes_pcs_end(); p++) {
+ if (p->scope_decode_offset() == DebugInformationRecorder::serialized_null)
+ continue;
+
+ ScopeDesc* sd = scope_desc_at(p->real_pc(this));
+ while (sd != NULL) {
+ sd->print_on(st, p); // print output ends with a newline
+ sd = sd->sender();
+ }
+ }
+ } else {
+ st->print_cr(" <list empty>");
+ }
+}
+#endif
+
+#ifndef PRODUCT // RelocIterator does support printing only then.
void nmethod::print_relocations() {
ResourceMark m; // in case methods get printed via the debugger
tty->print_cr("relocations:");
RelocIterator iter(this);
iter.print();
}
-
-
-void nmethod::print_pcs() {
+#endif
+
+void nmethod::print_pcs_on(outputStream* st) {
ResourceMark m; // in case methods get printed via debugger
- tty->print_cr("pc-bytecode offsets:");
- for (PcDesc* p = scopes_pcs_begin(); p < scopes_pcs_end(); p++) {
- p->print(this);
+ st->print("pc-bytecode offsets:");
+ if (scopes_pcs_begin() < scopes_pcs_end()) {
+ st->cr();
+ for (PcDesc* p = scopes_pcs_begin(); p < scopes_pcs_end(); p++) {
+ p->print_on(st, this); // print output ends with a newline
+ }
+ } else {
+ st->print_cr(" <list empty>");
}
}
+void nmethod::print_handler_table() {
+ ExceptionHandlerTable(this).print();
+}
+
+void nmethod::print_nul_chk_table() {
+ ImplicitExceptionTable(this).print(code_begin());
+}
+
void nmethod::print_recorded_oops() {
- tty->print_cr("Recorded oops:");
- for (int i = 0; i < oops_count(); i++) {
- oop o = oop_at(i);
- tty->print("#%3d: " INTPTR_FORMAT " ", i, p2i(o));
- if (o == Universe::non_oop_word()) {
- tty->print("non-oop word");
- } else {
- if (o != NULL) {
- o->print_value();
+ const int n = oops_count();
+ const int log_n = (n<10) ? 1 : (n<100) ? 2 : (n<1000) ? 3 : (n<10000) ? 4 : 6;
+ tty->print("Recorded oops:");
+ if (n > 0) {
+ tty->cr();
+ for (int i = 0; i < n; i++) {
+ oop o = oop_at(i);
+ tty->print("#%*d: " INTPTR_FORMAT " ", log_n, i, p2i(o));
+ if (o == (oop)Universe::non_oop_word()) {
+ tty->print("non-oop word");
+ } else if (o == NULL) {
+ tty->print("NULL-oop");
} else {
- tty->print_cr("NULL");
+ o->print_value_on(tty);
}
+ tty->cr();
}
- tty->cr();
+ } else {
+ tty->print_cr(" <list empty>");
}
}
void nmethod::print_recorded_metadata() {
- tty->print_cr("Recorded metadata:");
- for (int i = 0; i < metadata_count(); i++) {
- Metadata* m = metadata_at(i);
- tty->print("#%3d: " INTPTR_FORMAT " ", i, p2i(m));
- if (m == (Metadata*)Universe::non_oop_word()) {
- tty->print("non-metadata word");
- } else {
- Metadata::print_value_on_maybe_null(tty, m);
+ const int n = metadata_count();
+ const int log_n = (n<10) ? 1 : (n<100) ? 2 : (n<1000) ? 3 : (n<10000) ? 4 : 6;
+ tty->print("Recorded metadata:");
+ if (n > 0) {
+ tty->cr();
+ for (int i = 0; i < n; i++) {
+ Metadata* m = metadata_at(i);
+ tty->print("#%*d: " INTPTR_FORMAT " ", log_n, i, p2i(m));
+ if (m == (Metadata*)Universe::non_oop_word()) {
+ tty->print("non-metadata word");
+ } else if (m == NULL) {
+ tty->print("NULL-oop");
+ } else {
+ Metadata::print_value_on_maybe_null(tty, m);
+ }
+ tty->cr();
}
- tty->cr();
+ } else {
+ tty->print_cr(" <list empty>");
}
}
-
-#endif // PRODUCT
+#endif
+
+#if defined(SUPPORT_ASSEMBLY) || defined(SUPPORT_ABSTRACT_ASSEMBLY)
+
+void nmethod::print_constant_pool(outputStream* st) {
+ //-----------------------------------
+ //---< Print the constant pool >---
+ //-----------------------------------
+ int consts_size = this->consts_size();
+ if ( consts_size > 0 ) {
+ unsigned char* cstart = this->consts_begin();
+ unsigned char* cp = cstart;
+ unsigned char* cend = cp + consts_size;
+ unsigned int bytes_per_line = 4;
+ unsigned int CP_alignment = 8;
+ unsigned int n;
+
+ st->cr();
+
+ //---< print CP header to make clear what's printed >---
+ if( ((uintptr_t)cp&(CP_alignment-1)) == 0 ) {
+ n = bytes_per_line;
+ st->print_cr("[Constant Pool]");
+ Disassembler::print_location(cp, cstart, cend, st, true, true);
+ Disassembler::print_hexdata(cp, n, st, true);
+ st->cr();
+ } else {
+ n = (uintptr_t)cp&(bytes_per_line-1);
+ st->print_cr("[Constant Pool (unaligned)]");
+ }
+
+ //---< print CP contents, bytes_per_line at a time >---
+ while (cp < cend) {
+ Disassembler::print_location(cp, cstart, cend, st, true, false);
+ Disassembler::print_hexdata(cp, n, st, false);
+ cp += n;
+ n = bytes_per_line;
+ st->cr();
+ }
+
+ //---< Show potential alignment gap between constant pool and code >---
+ cend = code_begin();
+ if( cp < cend ) {
+ n = 4;
+ st->print_cr("[Code entry alignment]");
+ while (cp < cend) {
+ Disassembler::print_location(cp, cstart, cend, st, false, false);
+ cp += n;
+ st->cr();
+ }
+ }
+ } else {
+ st->print_cr("[Constant Pool (empty)]");
+ }
+ st->cr();
+}
+
+#endif
+
+// Disassemble this nmethod.
+// Print additional debug information, if requested. This could be code
+// comments, block comments, profiling counters, etc.
+// The undisassembled format is useful no disassembler library is available.
+// The resulting hex dump (with markers) can be disassembled later, or on
+// another system, when/where a disassembler library is available.
+void nmethod::decode2(outputStream* ost) const {
+
+ // Called from frame::back_trace_with_decode without ResourceMark.
+ ResourceMark rm;
+
+ // Make sure we have a valid stream to print on.
+ outputStream* st = ost ? ost : tty;
+
+#if defined(SUPPORT_ABSTRACT_ASSEMBLY) && ! defined(SUPPORT_ASSEMBLY)
+ const bool use_compressed_format = true;
+ const bool compressed_with_comments = use_compressed_format && (AbstractDisassembler::show_comment() ||
+ AbstractDisassembler::show_block_comment());
+#else
+ const bool use_compressed_format = Disassembler::is_abstract();
+ const bool compressed_with_comments = use_compressed_format && (AbstractDisassembler::show_comment() ||
+ AbstractDisassembler::show_block_comment());
+#endif
+
+ st->cr();
+ this->print(st);
+ st->cr();
+
+#if defined(SUPPORT_ASSEMBLY)
+ //----------------------------------
+ //---< Print real disassembly >---
+ //----------------------------------
+ if (! use_compressed_format) {
+ Disassembler::decode(const_cast<nmethod*>(this), st);
+ return;
+ }
+#endif
+
+#if defined(SUPPORT_ABSTRACT_ASSEMBLY)
+
+ // Compressed undisassembled disassembly format.
+ // The following stati are defined/supported:
+ // = 0 - currently at bol() position, nothing printed yet on current line.
+ // = 1 - currently at position after print_location().
+ // > 1 - in the midst of printing instruction stream bytes.
+ int compressed_format_idx = 0;
+ int code_comment_column = 0;
+ const int instr_maxlen = Assembler::instr_maxlen();
+ const uint tabspacing = 8;
+ unsigned char* start = this->code_begin();
+ unsigned char* p = this->code_begin();
+ unsigned char* end = this->code_end();
+ unsigned char* pss = p; // start of a code section (used for offsets)
+
+ if ((start == NULL) || (end == NULL)) {
+ st->print_cr("PrintAssembly not possible due to uninitialized section pointers");
+ return;
+ }
+#endif
+
+#if defined(SUPPORT_ABSTRACT_ASSEMBLY)
+ //---< plain abstract disassembly, no comments or anything, just section headers >---
+ if (use_compressed_format && ! compressed_with_comments) {
+ const_cast<nmethod*>(this)->print_constant_pool(st);
+
+ //---< Open the output (Marker for post-mortem disassembler) >---
+ st->print_cr("[MachCode]");
+ const char* header = NULL;
+ address p0 = p;
+ while (p < end) {
+ address pp = p;
+ while ((p < end) && (header == NULL)) {
+ header = nmethod_section_label(p);
+ pp = p;
+ p += Assembler::instr_len(p);
+ }
+ if (pp > p0) {
+ AbstractDisassembler::decode_range_abstract(p0, pp, start, end, st, Assembler::instr_maxlen());
+ p0 = pp;
+ p = pp;
+ header = NULL;
+ } else if (header != NULL) {
+ st->bol();
+ st->print_cr("%s", header);
+ header = NULL;
+ }
+ }
+ //---< Close the output (Marker for post-mortem disassembler) >---
+ st->bol();
+ st->print_cr("[/MachCode]");
+ return;
+ }
+#endif
+
+#if defined(SUPPORT_ABSTRACT_ASSEMBLY)
+ //---< abstract disassembly with comments and section headers merged in >---
+ if (compressed_with_comments) {
+ const_cast<nmethod*>(this)->print_constant_pool(st);
+
+ //---< Open the output (Marker for post-mortem disassembler) >---
+ st->print_cr("[MachCode]");
+ while ((p < end) && (p != NULL)) {
+ const int instruction_size_in_bytes = Assembler::instr_len(p);
+
+ //---< Block comments for nmethod. Interrupts instruction stream, if any. >---
+ // Outputs a bol() before and a cr() after, but only if a comment is printed.
+ // Prints nmethod_section_label as well.
+ if (AbstractDisassembler::show_block_comment()) {
+ print_block_comment(st, p);
+ if (st->position() == 0) {
+ compressed_format_idx = 0;
+ }
+ }
+
+ //---< New location information after line break >---
+ if (compressed_format_idx == 0) {
+ code_comment_column = Disassembler::print_location(p, pss, end, st, false, false);
+ compressed_format_idx = 1;
+ }
+
+ //---< Code comment for current instruction. Address range [p..(p+len)) >---
+ unsigned char* p_end = p + (ssize_t)instruction_size_in_bytes;
+ S390_ONLY(if (p_end > end) p_end = end;) // avoid getting past the end
+
+ if (AbstractDisassembler::show_comment() && const_cast<nmethod*>(this)->has_code_comment(p, p_end)) {
+ //---< interrupt instruction byte stream for code comment >---
+ if (compressed_format_idx > 1) {
+ st->cr(); // interrupt byte stream
+ st->cr(); // add an empty line
+ code_comment_column = Disassembler::print_location(p, pss, end, st, false, false);
+ }
+ const_cast<nmethod*>(this)->print_code_comment_on(st, code_comment_column, p, p_end );
+ st->bol();
+ compressed_format_idx = 0;
+ }
+
+ //---< New location information after line break >---
+ if (compressed_format_idx == 0) {
+ code_comment_column = Disassembler::print_location(p, pss, end, st, false, false);
+ compressed_format_idx = 1;
+ }
+
+ //---< Nicely align instructions for readability >---
+ if (compressed_format_idx > 1) {
+ Disassembler::print_delimiter(st);
+ }
+
+ //---< Now, finally, print the actual instruction bytes >---
+ unsigned char* p0 = p;
+ p = Disassembler::decode_instruction_abstract(p, st, instruction_size_in_bytes, instr_maxlen);
+ compressed_format_idx += p - p0;
+
+ if (Disassembler::start_newline(compressed_format_idx-1)) {
+ st->cr();
+ compressed_format_idx = 0;
+ }
+ }
+ //---< Close the output (Marker for post-mortem disassembler) >---
+ st->bol();
+ st->print_cr("[/MachCode]");
+ return;
+ }
+#endif
+}
+
+#if defined(SUPPORT_ASSEMBLY) || defined(SUPPORT_ABSTRACT_ASSEMBLY)
const char* nmethod::reloc_string_for(u_char* begin, u_char* end) {
RelocIterator iter(this, begin, end);
@@ -2414,7 +2788,9 @@
switch (iter.type()) {
case relocInfo::none: return "no_reloc";
case relocInfo::oop_type: {
- stringStream st;
+ // Get a non-resizable resource-allocated stringStream.
+ // Our callees make use of (nested) ResourceMarks.
+ stringStream st(NEW_RESOURCE_ARRAY(char, 1024), 1024);
oop_Relocation* r = iter.oop_reloc();
oop obj = r->oop_value();
st.print("oop(");
@@ -2516,17 +2892,28 @@
return NULL;
}
-void nmethod::print_nmethod_labels(outputStream* stream, address block_begin) const {
- if (block_begin == entry_point()) stream->print_cr("[Entry Point]");
- if (block_begin == verified_entry_point()) stream->print_cr("[Verified Entry Point]");
- if (JVMCI_ONLY(_exception_offset >= 0 &&) block_begin == exception_begin()) stream->print_cr("[Exception Handler]");
- if (block_begin == stub_begin()) stream->print_cr("[Stub Code]");
- if (JVMCI_ONLY(_deopt_handler_begin != NULL &&) block_begin == deopt_handler_begin()) stream->print_cr("[Deopt Handler Code]");
-
- if (has_method_handle_invokes())
- if (block_begin == deopt_mh_handler_begin()) stream->print_cr("[Deopt MH Handler Code]");
-
- if (block_begin == consts_begin()) stream->print_cr("[Constants]");
+const char* nmethod::nmethod_section_label(address pos) const {
+ const char* label = NULL;
+ if (pos == code_begin()) label = "[Instructions begin]";
+ if (pos == entry_point()) label = "[Entry Point]";
+ if (pos == verified_entry_point()) label = "[Verified Entry Point]";
+ if (has_method_handle_invokes() && (pos == deopt_mh_handler_begin())) label = "[Deopt MH Handler Code]";
+ if (pos == consts_begin() && pos != insts_begin()) label = "[Constants]";
+ // Check stub_code before checking exception_handler or deopt_handler.
+ if (pos == this->stub_begin()) label = "[Stub Code]";
+ if (JVMCI_ONLY(_exception_offset >= 0 &&) pos == exception_begin()) label = "[Exception Handler]";
+ if (JVMCI_ONLY(_deopt_handler_begin != NULL &&) pos == deopt_handler_begin()) label = "[Deopt Handler Code]";
+ return label;
+}
+
+void nmethod::print_nmethod_labels(outputStream* stream, address block_begin, bool print_section_labels) const {
+ if (print_section_labels) {
+ const char* label = nmethod_section_label(block_begin);
+ if (label != NULL) {
+ stream->bol();
+ stream->print_cr("%s", label);
+ }
+ }
if (block_begin == entry_point()) {
methodHandle m = method();
@@ -2623,7 +3010,24 @@
}
}
-void nmethod::print_code_comment_on(outputStream* st, int column, u_char* begin, u_char* end) {
+// Returns whether this nmethod has code comments.
+bool nmethod::has_code_comment(address begin, address end) {
+ // scopes?
+ ScopeDesc* sd = scope_desc_in(begin, end);
+ if (sd != NULL) return true;
+
+ // relocations?
+ const char* str = reloc_string_for(begin, end);
+ if (str != NULL) return true;
+
+ // implicit exceptions?
+ int cont_offset = ImplicitExceptionTable(this).at(begin - code_begin());
+ if (cont_offset != 0) return true;
+
+ return false;
+}
+
+void nmethod::print_code_comment_on(outputStream* st, int column, address begin, address end) {
// First, find an oopmap in (begin, end].
// We use the odd half-closed interval so that oop maps and scope descs
// which are tied to the byte after a call are printed with the call itself.
@@ -2636,7 +3040,7 @@
address pc = base + pair->pc_offset();
if (pc > begin) {
if (pc <= end) {
- st->move_to(column);
+ st->move_to(column, 6, 0);
st->print("; ");
om->print_on(st);
}
@@ -2648,7 +3052,7 @@
// Print any debug info present at this pc.
ScopeDesc* sd = scope_desc_in(begin, end);
if (sd != NULL) {
- st->move_to(column);
+ st->move_to(column, 6, 0);
if (sd->bci() == SynchronizationEntryBCI) {
st->print(";*synchronization entry");
} else if (sd->bci() == AfterBci) {
@@ -2704,8 +3108,11 @@
// Print all scopes
for (;sd != NULL; sd = sd->sender()) {
- st->move_to(column);
+ st->move_to(column, 6, 0);
st->print("; -");
+ if (sd->should_reexecute()) {
+ st->print(" (reexecute)");
+ }
if (sd->method() == NULL) {
st->print("method is NULL");
} else {
@@ -2722,20 +3129,24 @@
}
// Print relocation information
+ // Prevent memory leak: allocating without ResourceMark.
+ ResourceMark rm;
const char* str = reloc_string_for(begin, end);
if (str != NULL) {
if (sd != NULL) st->cr();
- st->move_to(column);
+ st->move_to(column, 6, 0);
st->print("; {%s}", str);
}
int cont_offset = ImplicitExceptionTable(this).at(begin - code_begin());
if (cont_offset != 0) {
- st->move_to(column);
+ st->move_to(column, 6, 0);
st->print("; implicit exception: dispatches to " INTPTR_FORMAT, p2i(code_begin() + cont_offset));
}
}
+#endif
+
class DirectNativeCallWrapper: public NativeCallWrapper {
private:
NativeCall* _call;
@@ -2842,12 +3253,14 @@
return CompiledDirectStaticCall::before(return_addr);
}
-#ifndef PRODUCT
-
+#if defined(SUPPORT_DATA_STRUCTS)
void nmethod::print_value_on(outputStream* st) const {
st->print("nmethod");
print_on(st, NULL);
}
+#endif
+
+#ifndef PRODUCT
void nmethod::print_calls(outputStream* st) {
RelocIterator iter(this);
@@ -2869,14 +3282,6 @@
}
}
-void nmethod::print_handler_table() {
- ExceptionHandlerTable(this).print();
-}
-
-void nmethod::print_nul_chk_table() {
- ImplicitExceptionTable(this).print(code_begin());
-}
-
void nmethod::print_statistics() {
ttyLocker ttyl;
if (xtty != NULL) xtty->head("statistics type='nmethod'");
--- a/src/hotspot/share/code/nmethod.hpp Fri May 17 13:21:44 2019 +0100
+++ b/src/hotspot/share/code/nmethod.hpp Thu May 23 11:07:37 2019 +0100
@@ -377,6 +377,7 @@
void make_unloaded();
bool has_dependencies() { return dependencies_size() != 0; }
+ void print_dependencies() PRODUCT_RETURN;
void flush_dependencies(bool delete_immediately);
bool has_flushed_dependencies() { return _has_flushed_dependencies; }
void set_has_flushed_dependencies() {
@@ -505,18 +506,40 @@
void verify_scopes();
void verify_interrupt_point(address interrupt_point);
+ // Disassemble this nmethod with additional debug information, e.g. information about blocks.
+ void decode2(outputStream* st) const;
+ void print_constant_pool(outputStream* st);
+
+ // Avoid hiding of parent's 'decode(outputStream*)' method.
+ void decode(outputStream* st) const { decode2(st); } // just delegate here.
+
// printing support
void print() const;
+ void print(outputStream* st) const;
+ void print_code();
+
+#if defined(SUPPORT_DATA_STRUCTS)
+ // print output in opt build for disassembler library
void print_relocations() PRODUCT_RETURN;
- void print_pcs() PRODUCT_RETURN;
- void print_scopes() PRODUCT_RETURN;
- void print_dependencies() PRODUCT_RETURN;
- void print_value_on(outputStream* st) const PRODUCT_RETURN;
+ void print_pcs() { print_pcs_on(tty); }
+ void print_pcs_on(outputStream* st);
+ void print_scopes() { print_scopes_on(tty); }
+ void print_scopes_on(outputStream* st) PRODUCT_RETURN;
+ void print_value_on(outputStream* st) const;
+ void print_handler_table();
+ void print_nul_chk_table();
+ void print_recorded_oops();
+ void print_recorded_metadata();
+
+ void print_oops(outputStream* st); // oops from the underlying CodeBlob.
+ void print_metadata(outputStream* st); // metadata in metadata pool.
+#else
+ // void print_pcs() PRODUCT_RETURN;
+ void print_pcs() { return; }
+#endif
+
void print_calls(outputStream* st) PRODUCT_RETURN;
- void print_handler_table() PRODUCT_RETURN;
- void print_nul_chk_table() PRODUCT_RETURN;
- void print_recorded_oops() PRODUCT_RETURN;
- void print_recorded_metadata() PRODUCT_RETURN;
+ static void print_statistics() PRODUCT_RETURN;
void maybe_print_nmethod(DirectiveSet* directive);
void print_nmethod(bool print_code);
@@ -532,14 +555,21 @@
// Prints block-level comments, including nmethod specific block labels:
virtual void print_block_comment(outputStream* stream, address block_begin) const {
+#if defined(SUPPORT_ASSEMBLY) || defined(SUPPORT_ABSTRACT_ASSEMBLY)
print_nmethod_labels(stream, block_begin);
CodeBlob::print_block_comment(stream, block_begin);
+#endif
}
- void print_nmethod_labels(outputStream* stream, address block_begin) const;
+ bool has_block_comment(address block_begin) {
+ return CodeBlob::has_block_comment(block_begin);
+ }
+ void print_nmethod_labels(outputStream* stream, address block_begin, bool print_section_labels=true) const;
+ const char* nmethod_section_label(address pos) const;
+ // returns whether this nmethod has code comments.
+ bool has_code_comment(address begin, address end);
// Prints a comment for one native instruction (reloc info, pc desc)
void print_code_comment_on(outputStream* st, int column, address begin, address end);
- static void print_statistics() PRODUCT_RETURN;
// Compiler task identification. Note that all OSR methods
// are numbered in an independent sequence if CICountOSR is true,
--- a/src/hotspot/share/code/pcDesc.cpp Fri May 17 13:21:44 2019 +0100
+++ b/src/hotspot/share/code/pcDesc.cpp Thu May 23 11:07:37 2019 +0100
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997, 2016, 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
@@ -40,19 +40,24 @@
return code->code_begin() + pc_offset();
}
-void PcDesc::print(CompiledMethod* code) {
+void PcDesc::print_on(outputStream* st, CompiledMethod* code) {
#ifndef PRODUCT
ResourceMark rm;
- tty->print_cr("PcDesc(pc=" PTR_FORMAT " offset=%x bits=%x):", p2i(real_pc(code)), pc_offset(), _flags);
+ st->print("PcDesc(pc=" PTR_FORMAT " offset=%x bits=%x):", p2i(real_pc(code)), pc_offset(), _flags);
if (scope_decode_offset() == DebugInformationRecorder::serialized_null) {
+ st->cr();
return;
}
+ int tab = 8;
+ int pos = st->position() + 2; // current column plus two spaces
+ pos = ((pos+tab-1)/tab)*tab;
+
for (ScopeDesc* sd = code->scope_desc_at(real_pc(code));
sd != NULL;
sd = sd->sender()) {
- sd->print_on(tty);
+ sd->print_on(st);
}
#endif
}
--- a/src/hotspot/share/code/pcDesc.hpp Fri May 17 13:21:44 2019 +0100
+++ b/src/hotspot/share/code/pcDesc.hpp Thu May 23 11:07:37 2019 +0100
@@ -92,7 +92,8 @@
// Returns the real pc
address real_pc(const CompiledMethod* code) const;
- void print(CompiledMethod* code);
+ void print(CompiledMethod* code) { print_on(tty, code); }
+ void print_on(outputStream* st, CompiledMethod* code);
bool verify(CompiledMethod* code);
};
--- a/src/hotspot/share/code/vmreg.cpp Fri May 17 13:21:44 2019 +0100
+++ b/src/hotspot/share/code/vmreg.cpp Thu May 23 11:07:37 2019 +0100
@@ -39,7 +39,7 @@
void VMRegImpl::print_on(outputStream* st) const {
if( is_reg() ) {
- assert( VMRegImpl::regName[value()], "" );
+ assert(VMRegImpl::regName[value()], "VMRegImpl::regName[" INTPTR_FORMAT "] returns NULL", value());
st->print("%s",VMRegImpl::regName[value()]);
} else if (is_stack()) {
int stk = value() - stack0->value();
--- a/src/hotspot/share/code/vtableStubs.cpp Fri May 17 13:21:44 2019 +0100
+++ b/src/hotspot/share/code/vtableStubs.cpp Thu May 23 11:07:37 2019 +0100
@@ -80,7 +80,7 @@
void VtableStub::print_on(outputStream* st) const {
- st->print("vtable stub (index = %d, receiver_location = " INTX_FORMAT ", code = [" INTPTR_FORMAT ", " INTPTR_FORMAT "[)",
+ st->print("vtable stub (index = %d, receiver_location = " INTX_FORMAT ", code = [" INTPTR_FORMAT ", " INTPTR_FORMAT "])",
index(), p2i(receiver_location()), p2i(code_begin()), p2i(code_end()));
}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/hotspot/share/compiler/abstractDisassembler.cpp Thu May 23 11:07:37 2019 +0100
@@ -0,0 +1,363 @@
+/*
+ * 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.
+ *
+ */
+
+// AbstractDisassembler is the base class for
+// platform-specific Disassembler classes.
+
+#include "precompiled.hpp"
+#include "asm/assembler.inline.hpp"
+#include "compiler/abstractDisassembler.hpp"
+#include "oops/oop.inline.hpp"
+#include "utilities/debug.hpp"
+#include "utilities/ostream.hpp"
+
+// Default values for what is being printed as line prefix when disassembling a single instruction.
+// Can be overridden by command line parameter PrintAssemblyOptions.
+bool AbstractDisassembler::_show_data_hex = true;
+bool AbstractDisassembler::_show_data_int = false;
+bool AbstractDisassembler::_show_data_float = false;
+bool AbstractDisassembler::_align_instr = false;
+bool AbstractDisassembler::_show_pc = true;
+bool AbstractDisassembler::_show_offset = false;
+bool AbstractDisassembler::_show_structs = false;
+bool AbstractDisassembler::_show_comment = false;
+bool AbstractDisassembler::_show_block_comment = false;
+
+// set "true" to see what's in memory bit by bit
+// might prove cumbersome on platforms where instr_len is hard to find out
+bool AbstractDisassembler::_show_bytes = false;
+
+// Return #bytes printed. Callers may use that for output alignment.
+// Print instruction address, and offset from blob begin.
+// Offset width (2, 4, 6, 8 bytes) is adapted to size of blob.
+// Working assumption: we are at st->bol() upon entry. If not, it's the
+// caller's responsibility to guarantee proper alignment.
+int AbstractDisassembler::print_location(address here, address begin, address end, outputStream* st, bool align, bool print_header) {
+ const int pos_0 = st->position();
+
+ if (show_pc() || show_offset()) {
+ st->print(" ");
+ }
+
+ if (show_pc()) {
+ if (print_header) {
+ st->print(" %*s", 18, "Address");
+ } else {
+ st->print(" " PTR_FORMAT, p2i(here));
+ }
+ }
+
+ if (show_offset()) {
+#ifdef ASSERT
+ if ((uintptr_t)begin > (uintptr_t)here) st->print(">>begin(" PTR_FORMAT ") > here(" PTR_FORMAT ")<<", p2i(begin), p2i(here));
+ if ((uintptr_t)end < (uintptr_t)here) st->print(">> end(" PTR_FORMAT ") < here(" PTR_FORMAT ")<<", p2i(end), p2i(here));
+ assert((uintptr_t)begin <= (uintptr_t)end, "inverted address range");
+#endif
+ const int blob_len = end - begin;
+ const int offset = here - begin;
+ const int width = (blob_len < (1<< 8)) ? 2 : (blob_len < (1<<16)) ? 4 : (blob_len < (1<<24)) ? 6 : 8;
+ if (print_header) {
+ st->print(" %*s", width+5, "offset");
+ } else {
+ st->print(" (+0x%*.*x)", width, width, offset);
+ }
+ }
+
+ if ((show_pc() || show_offset()) && !print_header) {
+ st->print(": ");
+ }
+
+ if (align) {
+ const uint tabspacing = 8;
+ const uint pos = st->position();
+ const uint aligned_pos = ((pos+tabspacing-1)/tabspacing)*tabspacing /* - 1 */;
+ st->fill_to(aligned_pos);
+ }
+
+ return st->position() - pos_0;
+}
+
+
+// Return #bytes printed. Callers may use that for output alignment.
+// Print instruction in hexadecimal representation, using 2-byte blocks.
+// Used with real disassemblies. Not so useful with abstract disassemblies.
+int AbstractDisassembler::print_instruction(address here, int len, int max_len, outputStream* st, bool align, bool print_header) {
+ if (show_bytes()) {
+ const int block_bytes = 2;
+ const int pos_0 = st->position();
+ address pos = here;
+
+ //---< print instruction bytes in blocks >---
+ // must print byte by byte: address might be unaligned.
+ for (; pos <= here + len - block_bytes; pos += block_bytes) {
+ for (address byte = pos; byte < pos + block_bytes; byte++) {
+ st->print("%2.2x", *byte);
+ }
+ st->print(" ");
+ }
+
+ //---< Print the remaining bytes of the instruction >---
+ if ((len & (block_bytes - 1)) != 0) {
+ for (; pos < here + len; pos++) {
+ st->print("%2.2x", *pos);
+ }
+ }
+
+ //---< filler for shorter than max_len instructions >---
+ for (int i = len+1; i < max_len; i++) {
+ st->print(" ");
+ }
+
+ st->print(" "); // separator space.
+ print_delimiter(st);
+ return st->position() - pos_0;
+ }
+
+ if (align) {
+ const uint tabspacing = 8;
+ const uint pos = st->position();
+ const uint aligned_pos = ((pos+tabspacing-1)/tabspacing)*tabspacing /* - 1 */;
+ st->fill_to(aligned_pos);
+ }
+
+ return 0;
+}
+
+
+// Return #bytes printed. Callers may use that for output alignment.
+// Print data (e.g. constant pool entries) in hex format.
+// Depending on the alignment, short, int, and long entities are printed.
+// If selected, data is formatted as int/long and float/double values in addition.
+int AbstractDisassembler::print_hexdata(address here, int len, outputStream* st, bool print_header) {
+ const int tsize = 8;
+ const int pos_0 = st->position();
+ int pos = pos_0;
+ int align = ((pos+tsize-1)/tsize)*tsize;
+ st->fill_to(align);
+
+ //---< printing hex data >---
+ if (show_data_hex()) {
+ switch (len) {
+ case 1: if (print_header) {
+ st->print("hex1");
+ } else {
+ st->print("0x%02x", *here);
+ }
+ st->fill_to(align += tsize);
+ case 2: if (print_header) {
+ st->print(" hex2");
+ } else {
+ if (((uintptr_t)(here)&0x01) == 0) {
+ st->print("0x%04x", *((jushort*)here));
+ }
+ }
+ st->fill_to(align += tsize);
+ case 4: if (print_header) {
+ st->print(" hex4");
+ } else {
+ if (((uintptr_t)(here)&0x03) == 0) {
+ st->print("0x%08x", *((juint*)here));
+ }
+ }
+ st->fill_to(align += 2*tsize);
+ case 8: if (print_header) {
+ st->print(" hex8");
+ } else {
+ if (((uintptr_t)(here)&0x07) == 0) {
+ st->print(PTR_FORMAT, *((uintptr_t*)here));
+ }
+ }
+ st->fill_to(align += 3*tsize);
+ break;
+ default: ;
+ }
+ pos = st->position();
+ align = ((pos+tsize-1)/tsize)*tsize;
+ st->fill_to(align);
+ }
+
+ //---< printing int/long data >---
+ if (show_data_int()) {
+ switch (len) {
+ case 4: if (print_header) {
+ st->print(" int");
+ } else {
+ if (((uintptr_t)(here)&0x03) == 0) {
+ st->print("%12.1d", *((jint*)here));
+ }
+ }
+ st->fill_to(align += 2*tsize);
+ case 8: if (print_header) {
+ st->print(" long");
+ } else {
+ if (((uintptr_t)(here)&0x07) == 0) {
+ st->print("%23.1ld", *((jlong*)here));
+ }
+ }
+ st->fill_to(align += 3*tsize);
+ break;
+ default: ;
+ }
+ pos = st->position();
+ align = ((pos+tsize-1)/tsize)*tsize;
+ st->fill_to(align);
+ }
+
+ //---< printing float/double data >---
+ if (show_data_float()) {
+ switch (len) {
+ case 4: if (print_header) {
+ st->print(" float");
+ } else {
+ if (((uintptr_t)(here)&0x03) == 0) {
+ st->print("%15.7e", (double)*((float*)here));
+ }
+ }
+ st->fill_to(align += 2*tsize);
+ case 8: if (print_header) {
+ st->print(" double");
+ } else {
+ if (((uintptr_t)(here)&0x07) == 0) {
+ st->print("%23.15e", *((double*)here));
+ }
+ }
+ st->fill_to(align += 3*tsize);
+ break;
+ default: ;
+ }
+ }
+
+ return st->position() - pos_0;
+}
+
+
+// Return #bytes printed. Callers may use that for output alignment.
+// Print an instruction delimiter.
+int AbstractDisassembler::print_delimiter(outputStream* st) {
+ if (align_instr()) { st->print("| "); return 2; }
+ else return 0;
+}
+
+
+// Decodes the one instruction at address start in a platform-independent format.
+// Returns the start of the next instruction (which is 'start' plus 'instruction_size_in_bytes').
+// The parameter max_instr_size_in_bytes is used for output alignment purposes only.
+address AbstractDisassembler::decode_instruction_abstract(address start,
+ outputStream* st,
+ const int instruction_size_in_bytes,
+ const int max_instr_size_in_bytes) {
+ assert(instruction_size_in_bytes > 0, "no zero-size instructions!");
+ assert(max_instr_size_in_bytes >= instruction_size_in_bytes, "inconsistent call parameters");
+
+ //---< current instruction is at the start address >---
+ unsigned char* current = (unsigned char*) start;
+ int filler_limit = align_instr() ? max_instr_size_in_bytes : ((instruction_size_in_bytes+abstract_instruction_bytes_per_block-1)/abstract_instruction_bytes_per_block)
+ *abstract_instruction_bytes_per_block;
+
+ //---< print the instruction's bytes >---
+ for (int i = 1; i <= instruction_size_in_bytes; i++) {
+ st->print("%02x", *current);
+ ++current;
+ if (abstract_instruction_bytes_per_block <= max_instr_size_in_bytes) {
+ if (i%abstract_instruction_bytes_per_block == 0) st->print(" ");
+ } else {
+ if (i == instruction_size_in_bytes) st->print(" ");
+ }
+ }
+
+ //---< print some filler spaces to column-align instructions >---
+ for (int i = instruction_size_in_bytes+1; i <= filler_limit; i++) {
+ st->print(" ");
+ if (abstract_instruction_bytes_per_block <= max_instr_size_in_bytes) {
+ if (i%abstract_instruction_bytes_per_block == 0) st->print(" ");
+ } else {
+ if (i == instruction_size_in_bytes) st->print(" ");
+ }
+ }
+
+ //---< the address of the next instruction >---
+ return (address) current;
+}
+
+
+// Decodes all instructions in the given range [start..end)
+// calling decode_instruction_abstract for each instruction.
+// The format is platform dependent only to the extend that
+// it respects the actual instruction length where possible.
+// Does not print any markers or decorators.
+void AbstractDisassembler::decode_range_abstract(address range_start, address range_end,
+ address start, address end,
+ outputStream* st,
+ const int max_instr_size_in_bytes) {
+ assert(st != NULL, "need an output stream (no default)!");
+ int idx = 0;
+ address pos = range_start;
+
+ while ((pos != NULL) && (pos < range_end)) {
+ int instr_size_in_bytes = Assembler::instr_len(pos);
+
+ if (idx == 0) print_location(pos, start, end, st, false, false);
+ else print_delimiter(st);
+
+ //---< print the instruction's bytes >---
+ // don't access storage beyond end of range
+ if (pos + instr_size_in_bytes <= range_end) {
+ pos = decode_instruction_abstract(pos, st, instr_size_in_bytes, max_instr_size_in_bytes);
+ } else {
+ // If the range to be decoded contains garbage at the end (e.g. 0xcc initializer bytes),
+ // instruction size calculation may run out of sync. Just terminate in that case.
+ pos = range_end;
+ }
+
+ idx += instr_size_in_bytes;
+ if (start_newline(idx)) {
+ st->cr();
+ idx = 0;
+ }
+ }
+}
+
+
+// Decodes all instructions in the given range [start..end).
+// The output is enclosed in [MachCode] and [/MachCode] tags for later recognition.
+// The format is platform dependent only to the extend that
+// it respects the actual instruction length where possible.
+void AbstractDisassembler::decode_abstract(address start, address end, outputStream* ost,
+ const int max_instr_size_in_bytes) {
+ int idx = 0;
+ address pos = start;
+
+ outputStream* st = (ost == NULL) ? tty : ost;
+
+ //---< Open the output (Marker for post-mortem disassembler) >---
+ st->bol();
+ st->print_cr("[MachCode]");
+
+ decode_range_abstract(start, end, start, end, st, max_instr_size_in_bytes);
+
+ //---< Close the output (Marker for post-mortem disassembler) >---
+ st->bol();
+ st->print_cr("[/MachCode]");
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/hotspot/share/compiler/abstractDisassembler.hpp Thu May 23 11:07:37 2019 +0100
@@ -0,0 +1,118 @@
+/*
+ * 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.
+ *
+ */
+
+#ifndef SHARE_COMPILER_ABSTRACTDISASSEMBLER_HPP
+#define SHARE_COMPILER_ABSTRACTDISASSEMBLER_HPP
+
+// AbstractDisassembler is the base class for
+// platform-specific Disassembler classes.
+
+#include "utilities/globalDefinitions.hpp"
+
+class AbstractDisassembler {
+
+ private:
+ // These are some general settings which control
+ // abstract disassembly output.
+ enum {
+ // that many bytes are dumped in one line.
+ abstract_instruction_bytes_per_line = 32,
+ // instruction bytes are grouped in blocks of that many bytes.
+ abstract_instruction_bytes_per_block = 2,
+ // instructions have this default len.
+ abstract_instruction_size_in_bytes = 1,
+ // instructions have this maximum len.
+ abstract_instruction_maxsize_in_bytes = 1
+ };
+
+ static bool _align_instr; // vertical alignment of instructions in abstract disassembly
+ static bool _show_pc; // print the instruction address
+ static bool _show_offset; // print the instruction offset (from start of blob)
+ static bool _show_bytes; // print instruction bytes
+ static bool _show_data_hex; // print instruction bytes
+ static bool _show_data_int; // print instruction bytes
+ static bool _show_data_float; // print instruction bytes
+ static bool _show_structs; // print compiler data structures (relocations, oop maps, scopes, metadata, ...)
+ static bool _show_comment; // print instruction comments
+ static bool _show_block_comment; // print block comments
+
+ public:
+ // Platform-independent location and instruction formatting.
+ // All functions return #characters printed.
+ static int print_location(address here, address begin, address end, outputStream* st, bool align, bool print_header);
+ static int print_instruction(address here, int len, int max_len, outputStream* st, bool align, bool print_header);
+ static int print_hexdata(address here, int len, outputStream* st, bool print_header = false);
+ static int print_delimiter(outputStream* st);
+ static bool start_newline(int byte_count) { return byte_count >= abstract_instruction_bytes_per_line; }
+
+ static void toggle_align_instr() { _align_instr = !_align_instr; }
+ static void toggle_show_pc() { _show_pc = !_show_pc; }
+ static void toggle_show_offset() { _show_offset = !_show_offset; }
+ static void toggle_show_bytes() { _show_bytes = !_show_bytes; }
+ static void toggle_show_data_hex() { _show_data_hex = !_show_data_hex; }
+ static void toggle_show_data_int() { _show_data_int = !_show_data_int; }
+ static void toggle_show_data_float() { _show_data_float = !_show_data_float; }
+ static void toggle_show_structs() { _show_structs = !_show_structs; }
+ static void toggle_show_comment() { _show_comment = !_show_comment; }
+ static void toggle_show_block_comment() { _show_block_comment = !_show_block_comment; }
+
+ static bool align_instr() { return _align_instr; }
+ static bool show_pc() { return _show_pc; }
+ static bool show_offset() { return _show_offset; }
+ static bool show_bytes() { return _show_bytes; }
+ static bool show_data_hex() { return _show_data_hex; }
+ static bool show_data_int() { return _show_data_int; }
+ static bool show_data_float() { return _show_data_float; }
+ static bool show_structs() { return _show_structs; }
+ static bool show_comment() { return _show_comment; }
+ static bool show_block_comment() { return _show_block_comment; }
+
+ // Decodes the one instruction at address start in a platform-independent
+ // format. Returns the start of the next instruction (which is
+ // 'start' plus 'instruction_size_in_bytes'). The parameter max_instr_size_in_bytes
+ // is used for output alignment purposes only.
+ static address decode_instruction_abstract(address start,
+ outputStream* st,
+ const int instruction_size_in_bytes,
+ const int max_instr_size_in_bytes = abstract_instruction_maxsize_in_bytes);
+
+ // Decodes all instructions in the given range [start..end)
+ // calling decode_instruction_abstract for each instruction.
+ // The format is platform dependent only to the extend that
+ // it respects the actual instruction length where possible.
+ // Does not print any markers or decorators.
+ static void decode_range_abstract(address range_start, address range_end,
+ address start, address end,
+ outputStream* st,
+ const int max_instr_size_in_bytes = abstract_instruction_maxsize_in_bytes);
+
+ // Decodes all instructions in the given range in a platform-independent
+ // format, calling decode_instruction_abstract for each instruction.
+ static void decode_abstract(address start, address end,
+ outputStream* st,
+ const int max_instr_size_in_bytes = abstract_instruction_maxsize_in_bytes);
+};
+
+#endif // SHARE_COMPILER_ABSTRACTDISASSEMBLER_HPP
--- a/src/hotspot/share/compiler/compileBroker.cpp Fri May 17 13:21:44 2019 +0100
+++ b/src/hotspot/share/compiler/compileBroker.cpp Thu May 23 11:07:37 2019 +0100
@@ -192,7 +192,7 @@
void log_compile(JavaThread* thread, CompileTask* task) {
StringLogMessage lm;
- stringStream sstr = lm.stream();
+ stringStream sstr(lm.buffer(), lm.size());
// msg.time_stamp().update_to(tty->time_stamp().ticks());
task->print(&sstr, NULL, true, false);
log(thread, "%s", (const char*)lm);
--- a/src/hotspot/share/compiler/compilerDefinitions.cpp Fri May 17 13:21:44 2019 +0100
+++ b/src/hotspot/share/compiler/compilerDefinitions.cpp Thu May 23 11:07:37 2019 +0100
@@ -117,38 +117,38 @@
Compilation_mode = CompMode_client;
CompLevel_highest_tier = CompLevel_simple;
CompLevel_initial_compile = CompLevel_simple;
- FLAG_SET_ERGO(bool, TieredCompilation, false);
- FLAG_SET_ERGO(bool, ProfileInterpreter, false);
+ FLAG_SET_ERGO(TieredCompilation, false);
+ FLAG_SET_ERGO(ProfileInterpreter, false);
#if INCLUDE_JVMCI
- FLAG_SET_ERGO(bool, EnableJVMCI, false);
- FLAG_SET_ERGO(bool, UseJVMCICompiler, false);
+ FLAG_SET_ERGO(EnableJVMCI, false);
+ FLAG_SET_ERGO(UseJVMCICompiler, false);
#endif
#if INCLUDE_AOT
- FLAG_SET_ERGO(bool, UseAOT, false);
+ FLAG_SET_ERGO(UseAOT, false);
#endif
if (FLAG_IS_DEFAULT(NeverActAsServerClassMachine)) {
- FLAG_SET_ERGO(bool, NeverActAsServerClassMachine, true);
+ FLAG_SET_ERGO(NeverActAsServerClassMachine, true);
}
if (FLAG_IS_DEFAULT(InitialCodeCacheSize)) {
- FLAG_SET_ERGO(uintx, InitialCodeCacheSize, 160*K);
+ FLAG_SET_ERGO(InitialCodeCacheSize, 160*K);
}
if (FLAG_IS_DEFAULT(ReservedCodeCacheSize)) {
- FLAG_SET_ERGO(uintx, ReservedCodeCacheSize, 32*M);
+ FLAG_SET_ERGO(ReservedCodeCacheSize, 32*M);
}
if (FLAG_IS_DEFAULT(NonProfiledCodeHeapSize)) {
- FLAG_SET_ERGO(uintx, NonProfiledCodeHeapSize, 27*M);
+ FLAG_SET_ERGO(NonProfiledCodeHeapSize, 27*M);
}
if (FLAG_IS_DEFAULT(ProfiledCodeHeapSize)) {
- FLAG_SET_ERGO(uintx, ProfiledCodeHeapSize, 0);
+ FLAG_SET_ERGO(ProfiledCodeHeapSize, 0);
}
if (FLAG_IS_DEFAULT(NonNMethodCodeHeapSize)) {
- FLAG_SET_ERGO(uintx, NonNMethodCodeHeapSize, 5*M);
+ FLAG_SET_ERGO(NonNMethodCodeHeapSize, 5*M);
}
if (FLAG_IS_DEFAULT(CodeCacheExpansionSize)) {
- FLAG_SET_ERGO(uintx, CodeCacheExpansionSize, 32*K);
+ FLAG_SET_ERGO(CodeCacheExpansionSize, 32*K);
}
if (FLAG_IS_DEFAULT(MetaspaceSize)) {
- FLAG_SET_ERGO(size_t, MetaspaceSize, MIN2(12*M, MaxMetaspaceSize));
+ FLAG_SET_ERGO(MetaspaceSize, MIN2(12*M, MaxMetaspaceSize));
}
if (FLAG_IS_DEFAULT(MaxRAM)) {
// Do not use FLAG_SET_ERGO to update MaxRAM, as this will impact
@@ -156,13 +156,13 @@
FLAG_SET_DEFAULT(MaxRAM, 1ULL*G);
}
if (FLAG_IS_DEFAULT(CompileThreshold)) {
- FLAG_SET_ERGO(intx, CompileThreshold, 1500);
+ FLAG_SET_ERGO(CompileThreshold, 1500);
}
if (FLAG_IS_DEFAULT(OnStackReplacePercentage)) {
- FLAG_SET_ERGO(intx, OnStackReplacePercentage, 933);
+ FLAG_SET_ERGO(OnStackReplacePercentage, 933);
}
if (FLAG_IS_DEFAULT(CICompilerCount)) {
- FLAG_SET_ERGO(intx, CICompilerCount, 1);
+ FLAG_SET_ERGO(CICompilerCount, 1);
}
}
@@ -177,7 +177,7 @@
void select_compilation_mode_ergonomically() {
#if defined(_WINDOWS) && !defined(_LP64)
if (FLAG_IS_DEFAULT(NeverActAsServerClassMachine)) {
- FLAG_SET_ERGO(bool, NeverActAsServerClassMachine, true);
+ FLAG_SET_ERGO(NeverActAsServerClassMachine, true);
}
#endif
if (NeverActAsServerClassMachine) {
@@ -198,14 +198,14 @@
}
// Increase the code cache size - tiered compiles a lot more.
if (FLAG_IS_DEFAULT(ReservedCodeCacheSize)) {
- FLAG_SET_ERGO(uintx, ReservedCodeCacheSize,
+ FLAG_SET_ERGO(ReservedCodeCacheSize,
MIN2(CODE_CACHE_DEFAULT_LIMIT, (size_t)ReservedCodeCacheSize * 5));
}
// Enable SegmentedCodeCache if TieredCompilation is enabled, ReservedCodeCacheSize >= 240M
// and the code cache contains at least 8 pages (segmentation disables advantage of huge pages).
if (FLAG_IS_DEFAULT(SegmentedCodeCache) && ReservedCodeCacheSize >= 240*M &&
8 * CodeCache::page_size() <= ReservedCodeCacheSize) {
- FLAG_SET_ERGO(bool, SegmentedCodeCache, true);
+ FLAG_SET_ERGO(SegmentedCodeCache, true);
}
if (!UseInterpreter) { // -Xcomp
Tier3InvokeNotifyFreqLog = 0;
@@ -219,29 +219,29 @@
// Scale tiered compilation thresholds.
// CompileThresholdScaling == 0.0 is equivalent to -Xint and leaves compilation thresholds unchanged.
if (!FLAG_IS_DEFAULT(CompileThresholdScaling) && CompileThresholdScaling > 0.0) {
- FLAG_SET_ERGO(intx, Tier0InvokeNotifyFreqLog, scaled_freq_log(Tier0InvokeNotifyFreqLog));
- FLAG_SET_ERGO(intx, Tier0BackedgeNotifyFreqLog, scaled_freq_log(Tier0BackedgeNotifyFreqLog));
+ FLAG_SET_ERGO(Tier0InvokeNotifyFreqLog, scaled_freq_log(Tier0InvokeNotifyFreqLog));
+ FLAG_SET_ERGO(Tier0BackedgeNotifyFreqLog, scaled_freq_log(Tier0BackedgeNotifyFreqLog));
- FLAG_SET_ERGO(intx, Tier3InvocationThreshold, scaled_compile_threshold(Tier3InvocationThreshold));
- FLAG_SET_ERGO(intx, Tier3MinInvocationThreshold, scaled_compile_threshold(Tier3MinInvocationThreshold));
- FLAG_SET_ERGO(intx, Tier3CompileThreshold, scaled_compile_threshold(Tier3CompileThreshold));
- FLAG_SET_ERGO(intx, Tier3BackEdgeThreshold, scaled_compile_threshold(Tier3BackEdgeThreshold));
+ FLAG_SET_ERGO(Tier3InvocationThreshold, scaled_compile_threshold(Tier3InvocationThreshold));
+ FLAG_SET_ERGO(Tier3MinInvocationThreshold, scaled_compile_threshold(Tier3MinInvocationThreshold));
+ FLAG_SET_ERGO(Tier3CompileThreshold, scaled_compile_threshold(Tier3CompileThreshold));
+ FLAG_SET_ERGO(Tier3BackEdgeThreshold, scaled_compile_threshold(Tier3BackEdgeThreshold));
// Tier2{Invocation,MinInvocation,Compile,Backedge}Threshold should be scaled here
// once these thresholds become supported.
- FLAG_SET_ERGO(intx, Tier2InvokeNotifyFreqLog, scaled_freq_log(Tier2InvokeNotifyFreqLog));
- FLAG_SET_ERGO(intx, Tier2BackedgeNotifyFreqLog, scaled_freq_log(Tier2BackedgeNotifyFreqLog));
+ FLAG_SET_ERGO(Tier2InvokeNotifyFreqLog, scaled_freq_log(Tier2InvokeNotifyFreqLog));
+ FLAG_SET_ERGO(Tier2BackedgeNotifyFreqLog, scaled_freq_log(Tier2BackedgeNotifyFreqLog));
- FLAG_SET_ERGO(intx, Tier3InvokeNotifyFreqLog, scaled_freq_log(Tier3InvokeNotifyFreqLog));
- FLAG_SET_ERGO(intx, Tier3BackedgeNotifyFreqLog, scaled_freq_log(Tier3BackedgeNotifyFreqLog));
+ FLAG_SET_ERGO(Tier3InvokeNotifyFreqLog, scaled_freq_log(Tier3InvokeNotifyFreqLog));
+ FLAG_SET_ERGO(Tier3BackedgeNotifyFreqLog, scaled_freq_log(Tier3BackedgeNotifyFreqLog));
- FLAG_SET_ERGO(intx, Tier23InlineeNotifyFreqLog, scaled_freq_log(Tier23InlineeNotifyFreqLog));
+ FLAG_SET_ERGO(Tier23InlineeNotifyFreqLog, scaled_freq_log(Tier23InlineeNotifyFreqLog));
- FLAG_SET_ERGO(intx, Tier4InvocationThreshold, scaled_compile_threshold(Tier4InvocationThreshold));
- FLAG_SET_ERGO(intx, Tier4MinInvocationThreshold, scaled_compile_threshold(Tier4MinInvocationThreshold));
- FLAG_SET_ERGO(intx, Tier4CompileThreshold, scaled_compile_threshold(Tier4CompileThreshold));
- FLAG_SET_ERGO(intx, Tier4BackEdgeThreshold, scaled_compile_threshold(Tier4BackEdgeThreshold));
+ FLAG_SET_ERGO(Tier4InvocationThreshold, scaled_compile_threshold(Tier4InvocationThreshold));
+ FLAG_SET_ERGO(Tier4MinInvocationThreshold, scaled_compile_threshold(Tier4MinInvocationThreshold));
+ FLAG_SET_ERGO(Tier4CompileThreshold, scaled_compile_threshold(Tier4CompileThreshold));
+ FLAG_SET_ERGO(Tier4BackEdgeThreshold, scaled_compile_threshold(Tier4BackEdgeThreshold));
}
}
@@ -256,7 +256,7 @@
if (TieredStopAtLevel != CompLevel_full_optimization) {
// Currently JVMCI compiler can only work at the full optimization level
warning("forcing TieredStopAtLevel to full optimization because JVMCI is enabled");
- FLAG_SET_ERGO(intx, TieredStopAtLevel, CompLevel_full_optimization);
+ FLAG_SET_ERGO(TieredStopAtLevel, CompLevel_full_optimization);
}
if (FLAG_IS_DEFAULT(TypeProfileLevel)) {
FLAG_SET_DEFAULT(TypeProfileLevel, 0);
@@ -338,7 +338,7 @@
if (!FLAG_IS_DEFAULT(BackgroundCompilation)) {
warning("BackgroundCompilation disabled due to ReplayCompiles option.");
}
- FLAG_SET_CMDLINE(bool, BackgroundCompilation, false);
+ FLAG_SET_CMDLINE(BackgroundCompilation, false);
}
#ifdef COMPILER2
@@ -346,7 +346,7 @@
if (!FLAG_IS_DEFAULT(PostLoopMultiversioning)) {
warning("PostLoopMultiversioning disabled because RangeCheckElimination is disabled.");
}
- FLAG_SET_CMDLINE(bool, PostLoopMultiversioning, false);
+ FLAG_SET_CMDLINE(PostLoopMultiversioning, false);
}
if (UseCountedLoopSafepoints && LoopStripMiningIter == 0) {
if (!FLAG_IS_DEFAULT(UseCountedLoopSafepoints) || !FLAG_IS_DEFAULT(LoopStripMiningIter)) {
@@ -366,27 +366,27 @@
if (!FLAG_IS_DEFAULT(UseCompiler)) {
warning("UseCompiler disabled due to -Xint.");
}
- FLAG_SET_CMDLINE(bool, UseCompiler, false);
+ FLAG_SET_CMDLINE(UseCompiler, false);
}
if (ProfileInterpreter) {
if (!FLAG_IS_DEFAULT(ProfileInterpreter)) {
warning("ProfileInterpreter disabled due to -Xint.");
}
- FLAG_SET_CMDLINE(bool, ProfileInterpreter, false);
+ FLAG_SET_CMDLINE(ProfileInterpreter, false);
}
if (TieredCompilation) {
if (!FLAG_IS_DEFAULT(TieredCompilation)) {
warning("TieredCompilation disabled due to -Xint.");
}
- FLAG_SET_CMDLINE(bool, TieredCompilation, false);
+ FLAG_SET_CMDLINE(TieredCompilation, false);
}
#if INCLUDE_JVMCI
if (EnableJVMCI) {
if (!FLAG_IS_DEFAULT(EnableJVMCI) || !FLAG_IS_DEFAULT(UseJVMCICompiler)) {
warning("JVMCI Compiler disabled due to -Xint.");
}
- FLAG_SET_CMDLINE(bool, EnableJVMCI, false);
- FLAG_SET_CMDLINE(bool, UseJVMCICompiler, false);
+ FLAG_SET_CMDLINE(EnableJVMCI, false);
+ FLAG_SET_CMDLINE(UseJVMCICompiler, false);
}
#endif
} else {
@@ -434,7 +434,7 @@
// Scale CompileThreshold
// CompileThresholdScaling == 0.0 is equivalent to -Xint and leaves CompileThreshold unchanged.
if (!FLAG_IS_DEFAULT(CompileThresholdScaling) && CompileThresholdScaling > 0.0) {
- FLAG_SET_ERGO(intx, CompileThreshold, scaled_compile_threshold(CompileThreshold));
+ FLAG_SET_ERGO(CompileThreshold, scaled_compile_threshold(CompileThreshold));
}
}
@@ -455,7 +455,7 @@
AlwaysIncrementalInline = false;
}
if (PrintIdealGraphLevel > 0) {
- FLAG_SET_ERGO(bool, PrintIdealGraph, true);
+ FLAG_SET_ERGO(PrintIdealGraph, true);
}
#endif
if (!UseTypeSpeculation && FLAG_IS_DEFAULT(TypeProfileLevel)) {
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/hotspot/share/compiler/compiler_globals.hpp Thu May 23 11:07:37 2019 +0100
@@ -0,0 +1,82 @@
+/*
+ * 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
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#ifndef SHARE_COMPILER_COMPILER_GLOBALS_HPP
+#define SHARE_COMPILER_COMPILER_GLOBALS_HPP
+
+#include "runtime/globals_shared.hpp"
+#ifdef COMPILER1
+#include "c1/c1_globals.hpp"
+#endif // COMPILER1
+#ifdef COMPILER2
+#include "opto/c2_globals.hpp"
+#endif // COMPILER2
+#if INCLUDE_JVMCI
+#include "jvmci/jvmci_globals.hpp"
+#endif
+
+#if !defined(COMPILER1) && !defined(COMPILER2) && !INCLUDE_JVMCI
+define_pd_global(bool, BackgroundCompilation, false);
+define_pd_global(bool, UseTLAB, false);
+define_pd_global(bool, CICompileOSR, false);
+define_pd_global(bool, UseTypeProfile, false);
+define_pd_global(bool, UseOnStackReplacement, false);
+define_pd_global(bool, InlineIntrinsics, false);
+define_pd_global(bool, PreferInterpreterNativeStubs, true);
+define_pd_global(bool, ProfileInterpreter, false);
+define_pd_global(bool, ProfileTraps, false);
+define_pd_global(bool, TieredCompilation, false);
+
+define_pd_global(intx, CompileThreshold, 0);
+
+define_pd_global(intx, OnStackReplacePercentage, 0);
+define_pd_global(bool, ResizeTLAB, false);
+define_pd_global(intx, FreqInlineSize, 0);
+define_pd_global(size_t, NewSizeThreadIncrease, 4*K);
+define_pd_global(bool, InlineClassNatives, true);
+define_pd_global(bool, InlineUnsafeOps, true);
+define_pd_global(uintx, InitialCodeCacheSize, 160*K);
+define_pd_global(uintx, ReservedCodeCacheSize, 32*M);
+define_pd_global(uintx, NonProfiledCodeHeapSize, 0);
+define_pd_global(uintx, ProfiledCodeHeapSize, 0);
+define_pd_global(uintx, NonNMethodCodeHeapSize, 32*M);
+
+define_pd_global(uintx, CodeCacheExpansionSize, 32*K);
+define_pd_global(uintx, CodeCacheMinBlockLength, 1);
+define_pd_global(uintx, CodeCacheMinimumUseSpace, 200*K);
+define_pd_global(size_t, MetaspaceSize, ScaleForWordSize(4*M));
+define_pd_global(bool, NeverActAsServerClassMachine, true);
+define_pd_global(uint64_t,MaxRAM, 1ULL*G);
+#define CI_COMPILER_COUNT 0
+#else
+
+#if COMPILER2_OR_JVMCI
+#define CI_COMPILER_COUNT 2
+#else
+#define CI_COMPILER_COUNT 1
+#endif // COMPILER2_OR_JVMCI
+
+#endif // no compilers
+
+#endif // SHARE_COMPILER_COMPILER_GLOBALS_HPP
--- a/src/hotspot/share/compiler/disassembler.cpp Fri May 17 13:21:44 2019 +0100
+++ b/src/hotspot/share/compiler/disassembler.cpp Thu May 23 11:07:37 2019 +0100
@@ -23,6 +23,7 @@
*/
#include "precompiled.hpp"
+#include "asm/assembler.inline.hpp"
#include "asm/macroAssembler.hpp"
#include "ci/ciUtilities.hpp"
#include "classfile/javaClasses.hpp"
@@ -43,6 +44,7 @@
void* Disassembler::_library = NULL;
bool Disassembler::_tried_to_load_library = false;
+bool Disassembler::_library_usable = false;
// This routine is in the shared library:
Disassembler::decode_func_virtual Disassembler::_decode_instructions_virtual = NULL;
@@ -55,127 +57,46 @@
#define COMMENT_COLUMN 52 LP64_ONLY(+8) /*could be an option*/
#define BYTES_COMMENT ";..." /* funky byte display comment */
-bool Disassembler::load_library() {
- if (_decode_instructions_virtual != NULL || _decode_instructions != NULL) {
- // Already succeeded.
- return true;
- }
- if (_tried_to_load_library) {
- // Do not try twice.
- // To force retry in debugger: assign _tried_to_load_library=0
- return false;
- }
- // Try to load it.
- char ebuf[1024];
- char buf[JVM_MAXPATHLEN];
- os::jvm_path(buf, sizeof(buf));
- int jvm_offset = -1;
- int lib_offset = -1;
-#ifdef STATIC_BUILD
- char* p = strrchr(buf, '/');
- *p = '\0';
- strcat(p, "/lib/");
- lib_offset = jvm_offset = strlen(buf);
-#else
- {
- // Match "jvm[^/]*" in jvm_path.
- const char* base = buf;
- const char* p = strrchr(buf, *os::file_separator());
- if (p != NULL) lib_offset = p - base + 1;
- p = strstr(p ? p : base, "jvm");
- if (p != NULL) jvm_offset = p - base;
- }
-#endif
- // Find the disassembler shared library.
- // Search for several paths derived from libjvm, in this order:
- // 1. <home>/jre/lib/<arch>/<vm>/libhsdis-<arch>.so (for compatibility)
- // 2. <home>/jre/lib/<arch>/<vm>/hsdis-<arch>.so
- // 3. <home>/jre/lib/<arch>/hsdis-<arch>.so
- // 4. hsdis-<arch>.so (using LD_LIBRARY_PATH)
- if (jvm_offset >= 0) {
- // 1. <home>/jre/lib/<arch>/<vm>/libhsdis-<arch>.so
- strcpy(&buf[jvm_offset], hsdis_library_name);
- strcat(&buf[jvm_offset], os::dll_file_extension());
- _library = os::dll_load(buf, ebuf, sizeof ebuf);
- if (_library == NULL && lib_offset >= 0) {
- // 2. <home>/jre/lib/<arch>/<vm>/hsdis-<arch>.so
- strcpy(&buf[lib_offset], hsdis_library_name);
- strcat(&buf[lib_offset], os::dll_file_extension());
- _library = os::dll_load(buf, ebuf, sizeof ebuf);
- }
- if (_library == NULL && lib_offset > 0) {
- // 3. <home>/jre/lib/<arch>/hsdis-<arch>.so
- buf[lib_offset - 1] = '\0';
- const char* p = strrchr(buf, *os::file_separator());
- if (p != NULL) {
- lib_offset = p - buf + 1;
- strcpy(&buf[lib_offset], hsdis_library_name);
- strcat(&buf[lib_offset], os::dll_file_extension());
- _library = os::dll_load(buf, ebuf, sizeof ebuf);
- }
- }
- }
- if (_library == NULL) {
- // 4. hsdis-<arch>.so (using LD_LIBRARY_PATH)
- strcpy(&buf[0], hsdis_library_name);
- strcat(&buf[0], os::dll_file_extension());
- _library = os::dll_load(buf, ebuf, sizeof ebuf);
- }
- if (_library != NULL) {
- _decode_instructions_virtual = CAST_TO_FN_PTR(Disassembler::decode_func_virtual,
- os::dll_lookup(_library, decode_instructions_virtual_name));
- }
- if (_decode_instructions_virtual == NULL && _library != NULL) {
- // could not spot in new version, try old version
- _decode_instructions = CAST_TO_FN_PTR(Disassembler::decode_func,
- os::dll_lookup(_library, decode_instructions_name));
- use_new_version = false;
- } else {
- use_new_version = true;
- }
- _tried_to_load_library = true;
- if (_decode_instructions_virtual == NULL && _decode_instructions == NULL) {
- tty->print_cr("Could not load %s; %s; %s", buf,
- ((_library != NULL)
- ? "entry point is missing"
- : (WizardMode || PrintMiscellaneous)
- ? (const char*)ebuf
- : "library not loadable"),
- "PrintAssembly is disabled");
- return false;
- }
-
- // Success.
- tty->print_cr("Loaded disassembler from %s", buf);
- return true;
-}
-
-
class decode_env {
private:
- nmethod* _nm;
- CodeBlob* _code;
+ outputStream* _output; // where the disassembly is directed to
+ CodeBuffer* _codeBuffer; // != NULL only when decoding a CodeBuffer
+ CodeBlob* _codeBlob; // != NULL only when decoding a CodeBlob
+ nmethod* _nm; // != NULL only when decoding a nmethod
CodeStrings _strings;
- outputStream* _output;
- address _start, _end;
- ptrdiff_t _offset;
+ address _start; // != NULL when decoding a range of unknown type
+ address _end; // != NULL when decoding a range of unknown type
char _option_buf[512];
char _print_raw;
- bool _print_pc;
- bool _print_bytes;
- address _cur_insn;
- int _bytes_per_line; // arch-specific formatting option
+ address _cur_insn; // address of instruction currently being decoded
+ int _bytes_per_line; // arch-specific formatting option
+ int _pre_decode_alignment;
+ int _post_decode_alignment;
bool _print_file_name;
+ bool _print_help;
+ bool _helpPrinted;
+ static bool _optionsParsed;
+ enum {
+ tabspacing = 8
+ };
+
+ // Check if the event matches the expected tag
+ // The tag must be a substring of the event, and
+ // the tag must be a token in the event, i.e. separated by delimiters
static bool match(const char* event, const char* tag) {
- size_t taglen = strlen(tag);
- if (strncmp(event, tag, taglen) != 0)
+ size_t eventlen = strlen(event);
+ size_t taglen = strlen(tag);
+ if (eventlen < taglen) // size mismatch
+ return false;
+ if (strncmp(event, tag, taglen) != 0) // string mismatch
return false;
char delim = event[taglen];
return delim == '\0' || delim == ' ' || delim == '/' || delim == '=';
}
+ // Merge new option string with previously recorded options
void collect_options(const char* p) {
if (p == NULL || p[0] == '\0') return;
size_t opt_so_far = strlen(_option_buf);
@@ -187,14 +108,56 @@
char* q = fillp;
while ((q = strpbrk(q, " \t\n")) != NULL)
*q++ = ',';
- // Note that multiple PrintAssemblyOptions flags accumulate with \n,
- // which we want to be changed to a comma...
}
+ void process_options(outputStream* ost);
+
void print_insn_labels();
- void print_insn_bytes(address pc0, address pc);
+ void print_insn_prefix();
void print_address(address value);
+ // Properly initializes _start/_end. Overwritten too often if
+ // printing of instructions is called for each instruction.
+ void set_start(address s) { _start = s; }
+ void set_end (address e) { _end = e; }
+ void set_nm (nmethod* nm) { _nm = nm; }
+ void set_output(outputStream* st) { _output = st; }
+
+#if defined(SUPPORT_ASSEMBLY) || defined(SUPPORT_ABSTRACT_ASSEMBLY)
+ // The disassembler library (sometimes) uses tabs to nicely align the instruction operands.
+ // Depending on the mnemonic length and the column position where the
+ // mnemonic is printed, alignment may turn out to be not so nice.
+ // To improve, we assume 8-character tab spacing and left-align the mnemonic on a tab position.
+ // Instruction comments are aligned 4 tab positions to the right of the mnemonic.
+ void calculate_alignment() {
+ _pre_decode_alignment = ((output()->position()+tabspacing-1)/tabspacing)*tabspacing;
+ _post_decode_alignment = _pre_decode_alignment + 4*tabspacing;
+ }
+
+ void start_insn(address pc) {
+ _cur_insn = pc;
+ output()->bol();
+ print_insn_labels();
+ print_insn_prefix();
+ }
+
+ void end_insn(address pc) {
+ address pc0 = cur_insn();
+ outputStream* st = output();
+
+ if (AbstractDisassembler::show_comment()) {
+ if ((_nm != NULL) && _nm->has_code_comment(pc0, pc)) {
+ _nm->print_code_comment_on(st, _post_decode_alignment, pc0, pc);
+ // this calls reloc_string_for which calls oop::print_value_on
+ }
+ print_hook_comments(pc0, _nm != NULL);
+ }
+ Disassembler::annotate(pc0, output());
+ // follow each complete insn by a nice newline
+ st->bol();
+ }
+#endif
+
struct SourceFileInfo {
struct Link : public CHeapObj<mtCode> {
const char* file;
@@ -241,40 +204,28 @@
static GrowableArray<const char*>* _cached_src_lines;
public:
- decode_env(CodeBlob* code, outputStream* output,
- CodeStrings c = CodeStrings(), ptrdiff_t offset = 0);
-
- address decode_instructions(address start, address end);
-
- void start_insn(address pc) {
- _cur_insn = pc;
- output()->bol();
- print_insn_labels();
- }
+ decode_env(CodeBuffer* code, outputStream* output);
+ decode_env(CodeBlob* code, outputStream* output, CodeStrings c = CodeStrings() /* , ptrdiff_t offset */);
+ decode_env(nmethod* code, outputStream* output, CodeStrings c = CodeStrings());
+ // Constructor for a 'decode_env' to decode an arbitrary
+ // piece of memory, hopefully containing code.
+ decode_env(address start, address end, outputStream* output);
- void end_insn(address pc) {
- address pc0 = cur_insn();
- outputStream* st = output();
- if (_print_bytes && pc > pc0)
- print_insn_bytes(pc0, pc);
- if (_nm != NULL) {
- _nm->print_code_comment_on(st, COMMENT_COLUMN, pc0, pc);
- // this calls reloc_string_for which calls oop::print_value_on
- }
- print_hook_comments(pc0, _nm != NULL);
- // follow each complete insn by a nice newline
- st->cr();
- }
+ // Add 'original_start' argument which is the the original address
+ // the instructions were located at (if this is not equal to 'start').
+ address decode_instructions(address start, address end, address original_start = NULL);
address handle_event(const char* event, address arg);
- outputStream* output() { return _output; }
- address cur_insn() { return _cur_insn; }
- const char* options() { return _option_buf; }
- static void hook(const char* file, int line, address pc);
+ outputStream* output() { return _output; }
+ address cur_insn() { return _cur_insn; }
+ const char* options() { return _option_buf; }
+ static void hook(const char* file, int line, address pc);
void print_hook_comments(address pc, bool newline);
};
+bool decode_env::_optionsParsed = false;
+
decode_env::SourceFileInfoTable decode_env::_src_table;
const char* decode_env::_cached_src = NULL;
GrowableArray<const char*>* decode_env::_cached_src_lines = NULL;
@@ -361,50 +312,185 @@
}
}
-decode_env::decode_env(CodeBlob* code, outputStream* output, CodeStrings c,
- ptrdiff_t offset) : _nm(NULL),
- _start(NULL),
- _end(NULL),
- _option_buf(),
- _print_raw('\0'),
- _cur_insn(NULL) {
+decode_env::decode_env(CodeBuffer* code, outputStream* output) {
+ memset(this, 0, sizeof(*this));
+ _output = output ? output : tty;
+ _codeBlob = NULL;
+ _codeBuffer = code;
+ _helpPrinted = false;
+
+ process_options(_output);
+}
+
+decode_env::decode_env(CodeBlob* code, outputStream* output, CodeStrings c) {
+ memset(this, 0, sizeof(*this)); // Beware, this zeroes bits of fields.
+ _output = output ? output : tty;
+ _codeBlob = code;
+ _codeBuffer = NULL;
+ _helpPrinted = false;
+ if (_codeBlob != NULL && _codeBlob->is_nmethod()) {
+ _nm = (nmethod*) code;
+ }
+ _strings.copy(c);
+
+ process_options(_output);
+}
+
+decode_env::decode_env(nmethod* code, outputStream* output, CodeStrings c) {
+ memset(this, 0, sizeof(*this)); // Beware, this zeroes bits of fields.
_output = output ? output : tty;
- _code = code;
- if (code != NULL && code->is_nmethod())
- _nm = (nmethod*) code;
+ _codeBlob = NULL;
+ _codeBuffer = NULL;
+ _nm = code;
+ _start = _nm->code_begin();
+ _end = _nm->code_end();
+ _helpPrinted = false;
_strings.copy(c);
- _offset = offset;
+
+ process_options(_output);
+}
+// Constructor for a 'decode_env' to decode a memory range [start, end)
+// of unknown origin, assuming it contains code.
+decode_env::decode_env(address start, address end, outputStream* output) {
+ assert(start < end, "Range must have a positive size, [" PTR_FORMAT ".." PTR_FORMAT ").", p2i(start), p2i(end));
+ memset(this, 0, sizeof(*this));
+ _output = output ? output : tty;
+ _codeBlob = NULL;
+ _codeBuffer = NULL;
+ _start = start;
+ _end = end;
+ _helpPrinted = false;
+
+ process_options(_output);
+}
+
+void decode_env::process_options(outputStream* ost) {
// by default, output pc but not bytes:
- _print_pc = true;
- _print_bytes = false;
- _bytes_per_line = Disassembler::pd_instruction_alignment();
- _print_file_name= true;
+ _print_help = false;
+ _bytes_per_line = Disassembler::pd_instruction_alignment();
+ _print_file_name = true;
+
+ if (_optionsParsed) return; // parse only once
// parse the global option string:
collect_options(Disassembler::pd_cpu_opts());
collect_options(PrintAssemblyOptions);
- if (strstr(options(), "hsdis-")) {
- if (strstr(options(), "hsdis-print-raw"))
- _print_raw = (strstr(options(), "xml") ? 2 : 1);
- if (strstr(options(), "hsdis-print-pc"))
- _print_pc = !_print_pc;
- if (strstr(options(), "hsdis-print-bytes"))
- _print_bytes = !_print_bytes;
+ if (strstr(options(), "print-raw")) {
+ _print_raw = (strstr(options(), "xml") ? 2 : 1);
+ }
+
+ if (strstr(options(), "help")) {
+ _print_help = true;
+ }
+ if (strstr(options(), "align-instr")) {
+ AbstractDisassembler::toggle_align_instr();
+ }
+ if (strstr(options(), "show-pc")) {
+ AbstractDisassembler::toggle_show_pc();
+ }
+ if (strstr(options(), "show-offset")) {
+ AbstractDisassembler::toggle_show_offset();
+ }
+ if (strstr(options(), "show-bytes")) {
+ AbstractDisassembler::toggle_show_bytes();
+ }
+ if (strstr(options(), "show-data-hex")) {
+ AbstractDisassembler::toggle_show_data_hex();
+ }
+ if (strstr(options(), "show-data-int")) {
+ AbstractDisassembler::toggle_show_data_int();
+ }
+ if (strstr(options(), "show-data-float")) {
+ AbstractDisassembler::toggle_show_data_float();
}
- if (strstr(options(), "help")) {
- tty->print_cr("PrintAssemblyOptions help:");
- tty->print_cr(" hsdis-print-raw test plugin by requesting raw output");
- tty->print_cr(" hsdis-print-raw-xml test plugin by requesting raw xml");
- tty->print_cr(" hsdis-print-pc turn off PC printing (on by default)");
- tty->print_cr(" hsdis-print-bytes turn on instruction byte output");
- tty->print_cr("combined options: %s", options());
+ if (strstr(options(), "show-structs")) {
+ AbstractDisassembler::toggle_show_structs();
+ }
+ if (strstr(options(), "show-comment")) {
+ AbstractDisassembler::toggle_show_comment();
+ }
+ if (strstr(options(), "show-block-comment")) {
+ AbstractDisassembler::toggle_show_block_comment();
+ }
+ _optionsParsed = true;
+
+ if (_print_help && ! _helpPrinted) {
+ _helpPrinted = true;
+ ost->print_cr("PrintAssemblyOptions help:");
+ ost->print_cr(" print-raw test plugin by requesting raw output");
+ ost->print_cr(" print-raw-xml test plugin by requesting raw xml");
+ ost->cr();
+ ost->print_cr(" show-pc toggle printing current pc, currently %s", AbstractDisassembler::show_pc() ? "ON" : "OFF");
+ ost->print_cr(" show-offset toggle printing current offset, currently %s", AbstractDisassembler::show_offset() ? "ON" : "OFF");
+ ost->print_cr(" show-bytes toggle printing instruction bytes, currently %s", AbstractDisassembler::show_bytes() ? "ON" : "OFF");
+ ost->print_cr(" show-data-hex toggle formatting data as hex, currently %s", AbstractDisassembler::show_data_hex() ? "ON" : "OFF");
+ ost->print_cr(" show-data-int toggle formatting data as int, currently %s", AbstractDisassembler::show_data_int() ? "ON" : "OFF");
+ ost->print_cr(" show-data-float toggle formatting data as float, currently %s", AbstractDisassembler::show_data_float() ? "ON" : "OFF");
+ ost->print_cr(" show-structs toggle compiler data structures, currently %s", AbstractDisassembler::show_structs() ? "ON" : "OFF");
+ ost->print_cr(" show-comment toggle instruction comments, currently %s", AbstractDisassembler::show_comment() ? "ON" : "OFF");
+ ost->print_cr(" show-block-comment toggle block comments, currently %s", AbstractDisassembler::show_block_comment() ? "ON" : "OFF");
+ ost->print_cr(" align-instr toggle instruction alignment, currently %s", AbstractDisassembler::align_instr() ? "ON" : "OFF");
+ ost->print_cr("combined options: %s", options());
}
}
+// Disassembly Event Handler.
+// This method receives events from the disassembler library hsdis
+// via event_to_env for each decoding step (installed by
+// Disassembler::decode_instructions(), replacing the default
+// callback method). This enables dumping additional info
+// and custom line formatting.
+// In a future extension, calling a custom decode method will be
+// supported. We can use such a method to decode instructions the
+// binutils decoder does not handle to our liking (suboptimal
+// formatting, incomplete information, ...).
+// Returns:
+// - NULL for all standard invocations. The function result is not
+// examined (as of now, 20190409) by the hsdis decoder loop.
+// - next for 'insn0' invocations.
+// next == arg: the custom decoder didn't do anything.
+// next > arg: the custom decoder did decode the instruction.
+// next points to the next undecoded instruction
+// (continuation point for decoder loop).
+//
+// "Normal" sequence of events:
+// insns - start of instruction stream decoding
+// mach - display architecture
+// format - display bytes-per-line
+// for each instruction:
+// insn - start of instruction decoding
+// insn0 - custom decoder invocation (if any)
+// addr - print address value
+// /insn - end of instruction decoding
+// /insns - premature end of instruction stream due to no progress
+//
address decode_env::handle_event(const char* event, address arg) {
- if (match(event, "insn")) {
+
+#if defined(SUPPORT_ASSEMBLY) || defined(SUPPORT_ABSTRACT_ASSEMBLY)
+
+ //---< Event: end decoding loop (error, no progress) >---
+ if (decode_env::match(event, "/insns")) {
+ // Nothing to be done here.
+ return NULL;
+ }
+
+ //---< Event: start decoding loop >---
+ if (decode_env::match(event, "insns")) {
+ // Nothing to be done here.
+ return NULL;
+ }
+
+ //---< Event: finish decoding an instruction >---
+ if (decode_env::match(event, "/insn")) {
+ output()->fill_to(_post_decode_alignment);
+ end_insn(arg);
+ return NULL;
+ }
+
+ //---< Event: start decoding an instruction >---
+ if (decode_env::match(event, "insn")) {
start_insn(arg);
} else if (match(event, "/insn")) {
end_insn(arg);
@@ -413,26 +499,59 @@
print_address(arg);
return arg;
}
- } else if (match(event, "mach")) {
- static char buffer[32] = { 0, };
- if (strcmp(buffer, (const char*)arg) != 0 ||
- strlen((const char*)arg) > sizeof(buffer) - 1) {
+ calculate_alignment();
+ output()->fill_to(_pre_decode_alignment);
+ return NULL;
+ }
+
+ //---< Event: call custom decoder (platform specific) >---
+ if (decode_env::match(event, "insn0")) {
+ return Disassembler::decode_instruction0(arg, output(), arg);
+ }
+
+ //---< Event: Print address >---
+ if (decode_env::match(event, "addr")) {
+ print_address(arg);
+ return arg;
+ }
+
+ //---< Event: mach (inform about machine architecture) >---
+ // This event is problematic because it messes up the output.
+ // The event is fired after the instruction address has already
+ // been printed. The decoded instruction (event "insn") is
+ // printed afterwards. That doesn't look nice.
+ if (decode_env::match(event, "mach")) {
+ guarantee(arg != NULL, "event_to_env - arg must not be NULL for event 'mach'");
+ static char buffer[64] = { 0, };
+ // Output suppressed because it messes up disassembly.
+ // Only print this when the mach changes.
+ if (false && (strcmp(buffer, (const char*)arg) != 0 ||
+ strlen((const char*)arg) > sizeof(buffer) - 1)) {
// Only print this when the mach changes
strncpy(buffer, (const char*)arg, sizeof(buffer) - 1);
buffer[sizeof(buffer) - 1] = '\0';
- output()->print_cr("[Disassembling for mach='%s']", arg);
+ output()->print_cr("[Disassembling for mach='%s']", (const char*)arg);
}
- } else if (match(event, "format bytes-per-line")) {
+ return NULL;
+ }
+
+ //---< Event: format bytes-per-line >---
+ if (decode_env::match(event, "format bytes-per-line")) {
_bytes_per_line = (int) (intptr_t) arg;
- } else {
- // ignore unrecognized markup
+ return NULL;
}
+#endif
return NULL;
}
+static void* event_to_env(void* env_pv, const char* event, void* arg) {
+ decode_env* env = (decode_env*) env_pv;
+ return env->handle_event(event, (address) arg);
+}
+
// called by the disassembler to print out jump targets and data addresses
void decode_env::print_address(address adr) {
- outputStream* st = _output;
+ outputStream* st = output();
if (adr == NULL) {
st->print("NULL");
@@ -477,9 +596,11 @@
if (_nm == NULL) {
// Don't do this for native methods, as the function name will be printed in
// nmethod::reloc_string_for().
- ResourceMark rm;
+ // Allocate the buffer on the stack instead of as RESOURCE array.
+ // In case we do DecodeErrorFile, Thread will not be initialized,
+ // causing a "assert(current != __null) failed" failure.
const int buflen = 1024;
- char* buf = NEW_RESOURCE_ARRAY(char, buflen);
+ char buf[buflen];
int offset;
if (os::dll_address_to_function_name(adr, buf, buflen, &offset)) {
st->print(PTR_FORMAT " = %s", p2i(adr), buf);
@@ -495,54 +616,31 @@
}
void decode_env::print_insn_labels() {
- address p = cur_insn();
- outputStream* st = output();
- CodeBlob* cb = _code;
- if (cb != NULL) {
- cb->print_block_comment(st, p);
- }
- _strings.print_block_comment(st, (intptr_t)(p - _start + _offset));
- if (_print_pc) {
- st->print(" " PTR_FORMAT ": ", p2i(p));
+ if (AbstractDisassembler::show_block_comment()) {
+ address p = cur_insn();
+ outputStream* st = output();
+
+ //---< Block comments for nmethod >---
+ // Outputs a bol() before and a cr() after, but only if a comment is printed.
+ // Prints nmethod_section_label as well.
+ if (_nm != NULL) {
+ _nm->print_block_comment(st, p);
+ }
+ if (_codeBlob != NULL) {
+ _codeBlob->print_block_comment(st, p);
+ }
+ if (_codeBuffer != NULL) {
+ _codeBuffer->print_block_comment(st, p);
+ }
+ _strings.print_block_comment(st, (intptr_t)(p - _start));
}
}
-void decode_env::print_insn_bytes(address pc, address pc_limit) {
+void decode_env::print_insn_prefix() {
+ address p = cur_insn();
outputStream* st = output();
- size_t incr = 1;
- size_t perline = _bytes_per_line;
- if ((size_t) Disassembler::pd_instruction_alignment() >= sizeof(int)
- && !((uintptr_t)pc % sizeof(int))
- && !((uintptr_t)pc_limit % sizeof(int))) {
- incr = sizeof(int);
- if (perline % incr) perline += incr - (perline % incr);
- }
- while (pc < pc_limit) {
- // tab to the desired column:
- st->move_to(COMMENT_COLUMN);
- address pc0 = pc;
- address pc1 = pc + perline;
- if (pc1 > pc_limit) pc1 = pc_limit;
- for (; pc < pc1; pc += incr) {
- if (pc == pc0) {
- st->print(BYTES_COMMENT);
- } else if ((uint)(pc - pc0) % sizeof(int) == 0) {
- st->print(" "); // put out a space on word boundaries
- }
- if (incr == sizeof(int)) {
- st->print("%08x", *(int*)pc);
- } else {
- st->print("%02x", (*pc)&0xFF);
- }
- }
- st->cr();
- }
-}
-
-
-static void* event_to_env(void* env_pv, const char* event, void* arg) {
- decode_env* env = (decode_env*) env_pv;
- return env->handle_event(event, (address) arg);
+ AbstractDisassembler::print_location(p, _start, _end, st, false, false);
+ AbstractDisassembler::print_instruction(p, Assembler::instr_len(p), Assembler::instr_maxlen(), st, true, false);
}
ATTRIBUTE_PRINTF(2, 3)
@@ -575,16 +673,31 @@
return (int)(cnt1 - cnt0);
}
-address decode_env::decode_instructions(address start, address end) {
- _start = start; _end = end;
-
- assert(((((intptr_t)start | (intptr_t)end) % Disassembler::pd_instruction_alignment()) == 0), "misaligned insn addr");
+// The 'original_start' argument holds the the original address where
+// the instructions were located in the originating system. If zero (NULL)
+// is passed in, there is no original address.
+address decode_env::decode_instructions(address start, address end, address original_start /* = 0*/) {
+ // CodeComment in Stubs.
+ // Properly initialize _start/_end. Overwritten too often if
+ // printing of instructions is called for each instruction.
+ assert((_start == NULL) || (start == NULL) || (_start == start), "don't overwrite CTOR values");
+ assert((_end == NULL) || (end == NULL) || (_end == end ), "don't overwrite CTOR values");
+ if (start != NULL) set_start(start);
+ if (end != NULL) set_end(end);
+ if (original_start == NULL) {
+ original_start = start;
+ }
- const int show_bytes = false; // for disassembler debugging
+ //---< Check (and correct) alignment >---
+ // Don't check alignment of end, it is not aligned.
+ if (((uint64_t)start & ((uint64_t)Disassembler::pd_instruction_alignment() - 1)) != 0) {
+ output()->print_cr("Decode range start:" PTR_FORMAT ": ... (unaligned)", p2i(start));
+ start = (address)((uint64_t)start & ~((uint64_t)Disassembler::pd_instruction_alignment() - 1));
+ }
- //_version = Disassembler::pd_cpu_version();
-
- if (!Disassembler::can_decode()) {
+ // Trying to decode instructions doesn't make sense if we
+ // couldn't load the disassembler library.
+ if (Disassembler::is_abstract()) {
return NULL;
}
@@ -625,16 +738,177 @@
options());
}
+// ----------------------------------------------------------------------------
+// Disassembler
+// Used as a static wrapper for decode_env.
+// Each method will create a decode_env before decoding.
+// You can call the decode_env methods directly if you already have one.
-void Disassembler::decode(CodeBlob* cb, outputStream* st) {
- ttyLocker ttyl;
- if (!load_library()) return;
- if (cb->is_nmethod()) {
- decode((nmethod*)cb, st);
+
+bool Disassembler::load_library(outputStream* st) {
+ // Do not try to load multiple times. Failed once -> fails always.
+ // To force retry in debugger: assign _tried_to_load_library=0
+ if (_tried_to_load_library) {
+ return _library_usable;
+ }
+
+#if defined(SUPPORT_ASSEMBLY) || defined(SUPPORT_ABSTRACT_ASSEMBLY)
+ // Print to given stream, if any.
+ // Print to tty if Verbose is on and no stream given.
+ st = ((st == NULL) && Verbose) ? tty : st;
+
+ // Compute fully qualified library name.
+ char ebuf[1024];
+ char buf[JVM_MAXPATHLEN];
+ os::jvm_path(buf, sizeof(buf));
+ int jvm_offset = -1;
+ int lib_offset = -1;
+#ifdef STATIC_BUILD
+ char* p = strrchr(buf, '/');
+ *p = '\0';
+ strcat(p, "/lib/");
+ lib_offset = jvm_offset = strlen(buf);
+#else
+ {
+ // Match "libjvm" instead of "jvm" on *nix platforms. Creates better matches.
+ // Match "[lib]jvm[^/]*" in jvm_path.
+ const char* base = buf;
+ const char* p = strrchr(buf, *os::file_separator());
+#ifdef _WIN32
+ p = strstr(p ? p : base, "jvm");
+#else
+ p = strstr(p ? p : base, "libjvm");
+#endif
+ if (p != NULL) lib_offset = p - base + 1;
+ if (p != NULL) jvm_offset = p - base;
+ }
+#endif
+
+ // Find the disassembler shared library.
+ // Search for several paths derived from libjvm, in this order:
+ // 1. <home>/jre/lib/<arch>/<vm>/libhsdis-<arch>.so (for compatibility)
+ // 2. <home>/jre/lib/<arch>/<vm>/hsdis-<arch>.so
+ // 3. <home>/jre/lib/<arch>/hsdis-<arch>.so
+ // 4. hsdis-<arch>.so (using LD_LIBRARY_PATH)
+ if (jvm_offset >= 0) {
+ // 1. <home>/jre/lib/<arch>/<vm>/libhsdis-<arch>.so
+ strcpy(&buf[jvm_offset], hsdis_library_name);
+ strcat(&buf[jvm_offset], os::dll_file_extension());
+ _library = os::dll_load(buf, ebuf, sizeof ebuf);
+ if (_library == NULL && lib_offset >= 0) {
+ // 2. <home>/jre/lib/<arch>/<vm>/hsdis-<arch>.so
+ strcpy(&buf[lib_offset], hsdis_library_name);
+ strcat(&buf[lib_offset], os::dll_file_extension());
+ _library = os::dll_load(buf, ebuf, sizeof ebuf);
+ }
+ if (_library == NULL && lib_offset > 0) {
+ // 3. <home>/jre/lib/<arch>/hsdis-<arch>.so
+ buf[lib_offset - 1] = '\0';
+ const char* p = strrchr(buf, *os::file_separator());
+ if (p != NULL) {
+ lib_offset = p - buf + 1;
+ strcpy(&buf[lib_offset], hsdis_library_name);
+ strcat(&buf[lib_offset], os::dll_file_extension());
+ _library = os::dll_load(buf, ebuf, sizeof ebuf);
+ }
+ }
+ }
+ if (_library == NULL) {
+ // 4. hsdis-<arch>.so (using LD_LIBRARY_PATH)
+ strcpy(&buf[0], hsdis_library_name);
+ strcat(&buf[0], os::dll_file_extension());
+ _library = os::dll_load(buf, ebuf, sizeof ebuf);
+ }
+
+ // load the decoder function to use (new or old version).
+ if (_library != NULL) {
+ _decode_instructions_virtual = CAST_TO_FN_PTR(Disassembler::decode_func_virtual,
+ os::dll_lookup(_library, decode_instructions_virtual_name));
+ }
+ if (_decode_instructions_virtual == NULL && _library != NULL) {
+ // could not spot in new version, try old version
+ _decode_instructions = CAST_TO_FN_PTR(Disassembler::decode_func,
+ os::dll_lookup(_library, decode_instructions_name));
+ use_new_version = false;
+ } else {
+ use_new_version = true;
+ }
+ _tried_to_load_library = true;
+ _library_usable = _decode_instructions_virtual != NULL || _decode_instructions != NULL;
+
+ // Create a dummy environment to initialize PrintAssemblyOptions.
+ // The PrintAssemblyOptions must be known for abstract disassemblies as well.
+ decode_env dummy((unsigned char*)(&buf[0]), (unsigned char*)(&buf[1]), st);
+
+ // Report problems during dll_load or dll_lookup, if any.
+ if (st != NULL) {
+ // Success.
+ if (_library_usable) {
+ st->print_cr("Loaded disassembler from %s", buf);
+ } else {
+ st->print_cr("Could not load %s; %s; %s",
+ buf,
+ ((_library != NULL)
+ ? "entry point is missing"
+ : ((WizardMode || PrintMiscellaneous)
+ ? (const char*)ebuf
+ : "library not loadable")),
+ "PrintAssembly defaults to abstract disassembly.");
+ }
+ }
+#endif
+ return _library_usable;
+}
+
+
+// Directly disassemble code buffer.
+void Disassembler::decode(CodeBuffer* cb, address start, address end, outputStream* st) {
+#if defined(SUPPORT_ASSEMBLY) || defined(SUPPORT_ABSTRACT_ASSEMBLY)
+ //---< Test memory before decoding >---
+ if (!(cb->contains(start) && cb->contains(end))) {
+ //---< Allow output suppression, but prevent writing to a NULL stream. Could happen with +PrintStubCode. >---
+ if (st != NULL) {
+ st->print("Memory range [" PTR_FORMAT ".." PTR_FORMAT "] not contained in CodeBuffer", p2i(start), p2i(end));
+ }
return;
}
+ if (!os::is_readable_range(start, end)) {
+ //---< Allow output suppression, but prevent writing to a NULL stream. Could happen with +PrintStubCode. >---
+ if (st != NULL) {
+ st->print("Memory range [" PTR_FORMAT ".." PTR_FORMAT "] not readable", p2i(start), p2i(end));
+ }
+ return;
+ }
+
decode_env env(cb, st);
- env.output()->print_cr("----------------------------------------------------------------------");
+ env.output()->print_cr("--------------------------------------------------------------------------------");
+ env.output()->print("Decoding CodeBuffer (" PTR_FORMAT ")", p2i(cb));
+ if (cb->name() != NULL) {
+ env.output()->print(", name: %s,", cb->name());
+ }
+ env.output()->print_cr(" at [" PTR_FORMAT ", " PTR_FORMAT "] " JLONG_FORMAT " bytes", p2i(start), p2i(end), ((jlong)(end - start)));
+
+ if (is_abstract()) {
+ AbstractDisassembler::decode_abstract(start, end, env.output(), Assembler::instr_maxlen());
+ } else {
+ env.decode_instructions(start, end);
+ }
+ env.output()->print_cr("--------------------------------------------------------------------------------");
+#endif
+}
+
+// Directly disassemble code blob.
+void Disassembler::decode(CodeBlob* cb, outputStream* st, CodeStrings c) {
+#if defined(SUPPORT_ASSEMBLY) || defined(SUPPORT_ABSTRACT_ASSEMBLY)
+ if (cb->is_nmethod()) {
+ // If we have an nmethod at hand,
+ // call the specialized decoder directly.
+ decode((nmethod*)cb, st, c);
+ return;
+ }
+
+ decode_env env(cb, st);
+ env.output()->print_cr("--------------------------------------------------------------------------------");
if (cb->is_aot()) {
env.output()->print("A ");
if (cb->is_compiled()) {
@@ -648,57 +922,78 @@
env.output()->print_cr("%s", cb->name());
}
} else {
- env.output()->print_cr("%s", cb->name());
+ env.output()->print("Decoding CodeBlob");
+ if (cb->name() != NULL) {
+ env.output()->print(", name: %s,", cb->name());
+ }
}
- env.output()->print_cr(" at [" PTR_FORMAT ", " PTR_FORMAT "] " JLONG_FORMAT " bytes", p2i(cb->code_begin()), p2i(cb->code_end()), ((jlong)(cb->code_end() - cb->code_begin())) * sizeof(unsigned char*));
- env.decode_instructions(cb->code_begin(), cb->code_end());
-}
+ env.output()->print_cr(" at [" PTR_FORMAT ", " PTR_FORMAT "] " JLONG_FORMAT " bytes", p2i(cb->code_begin()), p2i(cb->code_end()), ((jlong)(cb->code_end() - cb->code_begin())));
-void Disassembler::decode(address start, address end, outputStream* st, CodeStrings c,
- ptrdiff_t offset) {
- ttyLocker ttyl;
- if (!load_library()) return;
- decode_env env(CodeCache::find_blob_unsafe(start), st, c, offset);
- env.decode_instructions(start, end);
+ if (is_abstract()) {
+ AbstractDisassembler::decode_abstract(cb->code_begin(), cb->code_end(), env.output(), Assembler::instr_maxlen());
+ } else {
+ env.decode_instructions(cb->code_begin(), cb->code_end());
+ }
+ env.output()->print_cr("--------------------------------------------------------------------------------");
+#endif
}
-void Disassembler::decode(nmethod* nm, outputStream* st) {
+// Decode a nmethod.
+// This includes printing the constant pool and all code segments.
+// The nmethod data structures (oop maps, relocations and the like) are not printed.
+void Disassembler::decode(nmethod* nm, outputStream* st, CodeStrings c) {
+#if defined(SUPPORT_ASSEMBLY) || defined(SUPPORT_ABSTRACT_ASSEMBLY)
ttyLocker ttyl;
- if (!load_library()) return;
+
decode_env env(nm, st);
- env.output()->print_cr("----------------------------------------------------------------------");
-
- unsigned char* p = nm->code_begin();
- unsigned char* end = nm->code_end();
+ env.output()->print_cr("--------------------------------------------------------------------------------");
+ nm->print_constant_pool(env.output());
+ env.output()->print_cr("--------------------------------------------------------------------------------");
+ env.output()->cr();
+ if (is_abstract()) {
+ AbstractDisassembler::decode_abstract(nm->code_begin(), nm->code_end(), env.output(), Assembler::instr_maxlen());
+ } else {
+ env.decode_instructions(nm->code_begin(), nm->code_end());
+ }
+ env.output()->print_cr("--------------------------------------------------------------------------------");
+#endif
+}
- nm->method()->method_holder()->name()->print_symbol_on(env.output());
- env.output()->print(".");
- nm->method()->name()->print_symbol_on(env.output());
- nm->method()->signature()->print_symbol_on(env.output());
-#if INCLUDE_JVMCI
+// Decode a range, given as [start address, end address)
+void Disassembler::decode(address start, address end, outputStream* st, CodeStrings c /*, ptrdiff_t offset */) {
+#if defined(SUPPORT_ASSEMBLY) || defined(SUPPORT_ABSTRACT_ASSEMBLY)
+ //---< Test memory before decoding >---
+ if (!os::is_readable_range(start, end)) {
+ //---< Allow output suppression, but prevent writing to a NULL stream. Could happen with +PrintStubCode. >---
+ if (st != NULL) {
+ st->print("Memory range [" PTR_FORMAT ".." PTR_FORMAT "] not readable", p2i(start), p2i(end));
+ }
+ return;
+ }
+
+ if (is_abstract()) {
+ AbstractDisassembler::decode_abstract(start, end, st, Assembler::instr_maxlen());
+ return;
+ }
+
+// Don't do that fancy stuff. If we just have two addresses, live with it
+// and treat the memory contents as "amorphic" piece of code.
+#if 0
+ CodeBlob* cb = CodeCache::find_blob_unsafe(start);
+ if (cb != NULL) {
+ // If we have an CodeBlob at hand,
+ // call the specialized decoder directly.
+ decode(cb, st, c);
+ } else
+#endif
{
- const char* jvmciName = nm->jvmci_name();
- if (jvmciName != NULL) {
- env.output()->print(" (%s)", jvmciName);
- }
+ // This seems to be just a chunk of memory.
+ decode_env env(start, end, st);
+ env.output()->print_cr("--------------------------------------------------------------------------------");
+ env.decode_instructions(start, end);
+ env.output()->print_cr("--------------------------------------------------------------------------------");
}
#endif
- env.output()->print_cr(" [" PTR_FORMAT ", " PTR_FORMAT "] " JLONG_FORMAT " bytes", p2i(p), p2i(end), ((jlong)(end - p)));
-
- // Print constant table.
- if (nm->consts_size() > 0) {
- nm->print_nmethod_labels(env.output(), nm->consts_begin());
- int offset = 0;
- for (address p = nm->consts_begin(); p < nm->consts_end(); p += 4, offset += 4) {
- if ((offset % 8) == 0) {
- env.output()->print_cr(" " PTR_FORMAT " (offset: %4d): " PTR32_FORMAT " " PTR64_FORMAT, p2i(p), offset, *((int32_t*) p), *((int64_t*) p));
- } else {
- env.output()->print_cr(" " PTR_FORMAT " (offset: %4d): " PTR32_FORMAT, p2i(p), offset, *((int32_t*) p));
- }
- }
- }
-
- env.decode_instructions(p, end);
}
// To prevent excessive code expansion in the interpreter generator, we
--- a/src/hotspot/share/compiler/disassembler.hpp Fri May 17 13:21:44 2019 +0100
+++ b/src/hotspot/share/compiler/disassembler.hpp Thu May 23 11:07:37 2019 +0100
@@ -25,7 +25,11 @@
#ifndef SHARE_COMPILER_DISASSEMBLER_HPP
#define SHARE_COMPILER_DISASSEMBLER_HPP
+#include "utilities/globalDefinitions.hpp"
+
+#include "asm/assembler.hpp"
#include "asm/codeBuffer.hpp"
+#include "compiler/abstractDisassembler.hpp"
#include "runtime/globals.hpp"
#include "utilities/macros.hpp"
@@ -34,7 +38,8 @@
// The disassembler prints out assembly code annotated
// with Java specific information.
-class Disassembler {
+// Disassembler inherits from AbstractDisassembler
+class Disassembler : public AbstractDisassembler {
friend class decode_env;
private:
// this is the type of the dll entry point:
@@ -57,26 +62,58 @@
static void* _library;
// bailout
static bool _tried_to_load_library;
+ static bool _library_usable;
// points to the decode function.
static decode_func_virtual _decode_instructions_virtual;
static decode_func _decode_instructions;
- // tries to load library and return whether it succedded.
- static bool load_library();
+
+ // tries to load library and return whether it succeeded.
+ // Allow (diagnostic) output redirection.
+ // No output at all if stream is NULL. Can be overridden
+ // with -Verbose flag, in which case output goes to tty.
+ static bool load_library(outputStream* st = NULL);
+
+ // Check if the two addresses are on the same page.
+ static bool is_same_page(address a1, address a2) {
+ return (((uintptr_t)a1 ^ (uintptr_t)a2) & (~0x0fffUL)) == 0L;
+ }
// Machine dependent stuff
#include CPU_HEADER(disassembler)
public:
- static bool can_decode() {
- ttyLocker tl;
- return (_decode_instructions_virtual != NULL) ||
- (_decode_instructions != NULL) ||
- load_library();
+ // We can always decode code blobs.
+ // Either we have a disassembler library available (successfully loaded)
+ // or we will resort to the abstract disassembler. This method informs
+ // about which decoding format is used.
+ // We can also enforce using the abstract disassembler.
+ static bool is_abstract() {
+ if (!_tried_to_load_library /* && !UseAbstractDisassembler */) {
+ load_library();
+ }
+ return ! _library_usable /* || UseAbstractDisassembler */; // Not available until DecodeErrorFile is supported.
}
- static void decode(CodeBlob *cb, outputStream* st = NULL);
- static void decode(nmethod* nm, outputStream* st = NULL);
- static void decode(address begin, address end, outputStream* st = NULL,
- CodeStrings c = CodeStrings(), ptrdiff_t offset = 0);
+
+ // Check out if we are doing a live disassembly or a post-mortem
+ // disassembly where the binary data was loaded from a hs_err file.
+ static bool is_decode_error_file() {
+// Activate once post-mortem disassembly (from hs-err file) is available.
+#if 0
+ return DecodeErrorFile && (strlen(DecodeErrorFile) != 0);
+#else
+ return false;
+#endif
+ }
+
+ // Directly disassemble code buffer.
+ static void decode(CodeBuffer* cb, address start, address end, outputStream* st = NULL);
+ // Directly disassemble code blob.
+ static void decode(CodeBlob *cb, outputStream* st = NULL, CodeStrings c = CodeStrings());
+ // Directly disassemble nmethod.
+ static void decode(nmethod* nm, outputStream* st = NULL, CodeStrings c = CodeStrings());
+ // Disassemble an arbitrary memory range.
+ static void decode(address start, address end, outputStream* st = NULL, CodeStrings c = CodeStrings() /* , ptrdiff_t offset */);
+
static void _hook(const char* file, int line, class MacroAssembler* masm);
// This functions makes it easy to generate comments in the generated
--- a/src/hotspot/share/compiler/oopMap.cpp Fri May 17 13:21:44 2019 +0100
+++ b/src/hotspot/share/compiler/oopMap.cpp Thu May 23 11:07:37 2019 +0100
@@ -511,7 +511,7 @@
void ImmutableOopMap::print_on(outputStream* st) const {
OopMapValue omv;
- st->print("ImmutableOopMap{");
+ st->print("ImmutableOopMap {");
for(OopMapStream oms(this); !oms.is_done(); oms.next()) {
omv = oms.current();
omv.print_on(st);
@@ -523,44 +523,51 @@
void OopMap::print_on(outputStream* st) const {
OopMapValue omv;
- st->print("OopMap{");
+ st->print("OopMap {");
for(OopMapStream oms((OopMap*)this); !oms.is_done(); oms.next()) {
omv = oms.current();
omv.print_on(st);
}
- st->print("off=%d}", (int) offset());
+ // Print hex offset in addition.
+ st->print("off=%d/0x%x}", (int) offset(), (int) offset());
}
void OopMap::print() const { print_on(tty); }
void ImmutableOopMapSet::print_on(outputStream* st) const {
const ImmutableOopMap* last = NULL;
- for (int i = 0; i < _count; ++i) {
+ const int len = count();
+
+ st->print_cr("ImmutableOopMapSet contains %d OopMaps", len);
+
+ for (int i = 0; i < len; i++) {
const ImmutableOopMapPair* pair = pair_at(i);
const ImmutableOopMap* map = pair->get_from(this);
if (map != last) {
st->cr();
map->print_on(st);
- st->print("pc offsets: ");
+ st->print(" pc offsets: ");
}
last = map;
st->print("%d ", pair->pc_offset());
}
+ st->cr();
}
void ImmutableOopMapSet::print() const { print_on(tty); }
void OopMapSet::print_on(outputStream* st) const {
- int i, len = om_count();
+ const int len = om_count();
- st->print_cr("OopMapSet contains %d OopMaps\n",len);
+ st->print_cr("OopMapSet contains %d OopMaps", len);
- for( i = 0; i < len; i++) {
+ for( int i = 0; i < len; i++) {
OopMap* m = at(i);
st->print_cr("#%d ",i);
m->print_on(st);
st->cr();
}
+ st->cr();
}
void OopMapSet::print() const { print_on(tty); }
@@ -580,15 +587,17 @@
const ImmutableOopMap* ImmutableOopMapSet::find_map_at_offset(int pc_offset) const {
ImmutableOopMapPair* pairs = get_pairs();
+ ImmutableOopMapPair* last = NULL;
- int i;
- for (i = 0; i < _count; ++i) {
+ for (int i = 0; i < _count; ++i) {
if (pairs[i].pc_offset() >= pc_offset) {
+ last = &pairs[i];
break;
}
}
- ImmutableOopMapPair* last = &pairs[i];
+ // Heal Coverity issue: potential index out of bounds access.
+ guarantee(last != NULL, "last may not be null");
assert(last->pc_offset() == pc_offset, "oopmap not found");
return last->get_from(this);
}
--- a/src/hotspot/share/gc/cms/cmsArguments.cpp Fri May 17 13:21:44 2019 +0100
+++ b/src/hotspot/share/gc/cms/cmsArguments.cpp Thu May 23 11:07:37 2019 +0100
@@ -106,7 +106,7 @@
}
if (!ClassUnloading) {
- FLAG_SET_CMDLINE(bool, CMSClassUnloadingEnabled, false);
+ FLAG_SET_CMDLINE(CMSClassUnloadingEnabled, false);
}
// Set CMS global values
@@ -142,9 +142,9 @@
// NewSize was set on the command line and it is larger than
// preferred_max_new_size.
if (!FLAG_IS_DEFAULT(NewSize)) { // NewSize explicitly set at command-line
- FLAG_SET_ERGO(size_t, MaxNewSize, MAX2(NewSize, preferred_max_new_size));
+ FLAG_SET_ERGO(MaxNewSize, MAX2(NewSize, preferred_max_new_size));
} else {
- FLAG_SET_ERGO(size_t, MaxNewSize, preferred_max_new_size);
+ FLAG_SET_ERGO(MaxNewSize, preferred_max_new_size);
}
log_trace(gc, heap)("CMS ergo set MaxNewSize: " SIZE_FORMAT, MaxNewSize);
@@ -159,15 +159,15 @@
// Unless explicitly requested otherwise, make young gen
// at least min_new, and at most preferred_max_new_size.
if (FLAG_IS_DEFAULT(NewSize)) {
- FLAG_SET_ERGO(size_t, NewSize, MAX2(NewSize, min_new));
- FLAG_SET_ERGO(size_t, NewSize, MIN2(preferred_max_new_size, NewSize));
+ FLAG_SET_ERGO(NewSize, MAX2(NewSize, min_new));
+ FLAG_SET_ERGO(NewSize, MIN2(preferred_max_new_size, NewSize));
log_trace(gc, heap)("CMS ergo set NewSize: " SIZE_FORMAT, NewSize);
}
// Unless explicitly requested otherwise, size old gen
// so it's NewRatio x of NewSize.
if (FLAG_IS_DEFAULT(OldSize)) {
if (max_heap > NewSize) {
- FLAG_SET_ERGO(size_t, OldSize, MIN2(NewRatio*NewSize, max_heap - NewSize));
+ FLAG_SET_ERGO(OldSize, MIN2(NewRatio*NewSize, max_heap - NewSize));
log_trace(gc, heap)("CMS ergo set OldSize: " SIZE_FORMAT, OldSize);
}
}
@@ -177,14 +177,14 @@
// promote all objects surviving "tenuring_default" scavenges.
if (FLAG_IS_DEFAULT(MaxTenuringThreshold) &&
FLAG_IS_DEFAULT(SurvivorRatio)) {
- FLAG_SET_ERGO(uintx, MaxTenuringThreshold, tenuring_default);
+ FLAG_SET_ERGO(MaxTenuringThreshold, tenuring_default);
}
// If we decided above (or user explicitly requested)
// `promote all' (via MaxTenuringThreshold := 0),
// prefer minuscule survivor spaces so as not to waste
// space for (non-existent) survivors
if (FLAG_IS_DEFAULT(SurvivorRatio) && MaxTenuringThreshold == 0) {
- FLAG_SET_ERGO(uintx, SurvivorRatio, MAX2((uintx)1024, SurvivorRatio));
+ FLAG_SET_ERGO(SurvivorRatio, MAX2((uintx)1024, SurvivorRatio));
}
// OldPLABSize is interpreted in CMS as not the size of the PLAB in words,
@@ -195,7 +195,7 @@
// OldPLAB sizing manually turned off: Use a larger default setting,
// unless it was manually specified. This is because a too-low value
// will slow down scavenges.
- FLAG_SET_ERGO(size_t, OldPLABSize, CompactibleFreeListSpaceLAB::_default_static_old_plab_size); // default value before 6631166
+ FLAG_SET_ERGO(OldPLABSize, CompactibleFreeListSpaceLAB::_default_static_old_plab_size); // default value before 6631166
} else {
FLAG_SET_DEFAULT(OldPLABSize, CompactibleFreeListSpaceLAB::_default_dynamic_old_plab_size); // old CMSParPromoteBlocksToClaim default
}
--- a/src/hotspot/share/gc/epsilon/epsilonHeap.hpp Fri May 17 13:21:44 2019 +0100
+++ b/src/hotspot/share/gc/epsilon/epsilonHeap.hpp Thu May 23 11:07:37 2019 +0100
@@ -29,7 +29,6 @@
#include "gc/shared/space.hpp"
#include "gc/epsilon/epsilonMonitoringSupport.hpp"
#include "gc/epsilon/epsilonBarrierSet.hpp"
-#include "gc/epsilon/epsilon_globals.hpp"
#include "services/memoryManager.hpp"
class EpsilonHeap : public CollectedHeap {
--- a/src/hotspot/share/gc/epsilon/epsilon_globals.hpp Fri May 17 13:21:44 2019 +0100
+++ b/src/hotspot/share/gc/epsilon/epsilon_globals.hpp Thu May 23 11:07:37 2019 +0100
@@ -25,7 +25,8 @@
#ifndef SHARE_GC_EPSILON_EPSILON_GLOBALS_HPP
#define SHARE_GC_EPSILON_EPSILON_GLOBALS_HPP
-#include "runtime/globals.hpp"
+#include "runtime/globals_shared.hpp"
+
//
// Defines all globals flags used by the Epsilon GC.
//
--- a/src/hotspot/share/gc/g1/g1Arguments.cpp Fri May 17 13:21:44 2019 +0100
+++ b/src/hotspot/share/gc/g1/g1Arguments.cpp Thu May 23 11:07:37 2019 +0100
@@ -110,11 +110,11 @@
// triggering a full collection. To get as low fragmentation as
// possible we only use one worker thread.
if (DumpSharedSpaces) {
- FLAG_SET_ERGO(uint, ParallelGCThreads, 1);
+ FLAG_SET_ERGO(ParallelGCThreads, 1);
}
if (FLAG_IS_DEFAULT(G1ConcRefinementThreads)) {
- FLAG_SET_ERGO(uint, G1ConcRefinementThreads, ParallelGCThreads);
+ FLAG_SET_ERGO(G1ConcRefinementThreads, ParallelGCThreads);
}
// MarkStackSize will be set (if it hasn't been set by the user)
@@ -162,7 +162,7 @@
// By default do not let the target stack size to be more than 1/4 of the entries
if (FLAG_IS_DEFAULT(GCDrainStackTargetSize)) {
- FLAG_SET_ERGO(uintx, GCDrainStackTargetSize, MIN2(GCDrainStackTargetSize, (uintx)TASKQUEUE_SIZE / 4));
+ FLAG_SET_ERGO(GCDrainStackTargetSize, MIN2(GCDrainStackTargetSize, (uintx)TASKQUEUE_SIZE / 4));
}
#ifdef COMPILER2
--- a/src/hotspot/share/gc/g1/g1CollectedHeap.hpp Fri May 17 13:21:44 2019 +0100
+++ b/src/hotspot/share/gc/g1/g1CollectedHeap.hpp Thu May 23 11:07:37 2019 +0100
@@ -1111,7 +1111,7 @@
public:
- inline G1HeapRegionAttr region_attr(const oop obj);
+ inline G1HeapRegionAttr region_attr(const void* obj);
// Return "TRUE" iff the given object address is in the reserved
// region of g1.
--- a/src/hotspot/share/gc/g1/g1CollectedHeap.inline.hpp Fri May 17 13:21:44 2019 +0100
+++ b/src/hotspot/share/gc/g1/g1CollectedHeap.inline.hpp Thu May 23 11:07:37 2019 +0100
@@ -29,6 +29,7 @@
#include "gc/g1/g1CollectedHeap.hpp"
#include "gc/g1/g1CollectorState.hpp"
#include "gc/g1/g1Policy.hpp"
+#include "gc/g1/g1RemSet.hpp"
#include "gc/g1/heapRegionManager.inline.hpp"
#include "gc/g1/heapRegionRemSet.hpp"
#include "gc/g1/heapRegionSet.inline.hpp"
@@ -162,8 +163,8 @@
return _region_attr.is_in_cset_or_humongous((HeapWord*)obj);
}
-G1HeapRegionAttr G1CollectedHeap::region_attr(const oop obj) {
- return _region_attr.at((HeapWord*)obj);
+G1HeapRegionAttr G1CollectedHeap::region_attr(const void* addr) {
+ return _region_attr.at((HeapWord*)addr);
}
void G1CollectedHeap::register_humongous_region_with_region_attr(uint index) {
@@ -176,6 +177,7 @@
void G1CollectedHeap::register_old_region_with_region_attr(HeapRegion* r) {
_region_attr.set_in_old(r->hrm_index(), r->rem_set()->is_tracked());
+ _rem_set->prepare_for_scan_rem_set(r->hrm_index());
}
void G1CollectedHeap::register_optional_region_with_region_attr(HeapRegion* r) {
--- a/src/hotspot/share/gc/g1/g1ConcurrentMark.cpp Fri May 17 13:21:44 2019 +0100
+++ b/src/hotspot/share/gc/g1/g1ConcurrentMark.cpp Thu May 23 11:07:37 2019 +0100
@@ -425,7 +425,7 @@
// Calculate the number of concurrent worker threads by scaling
// the number of parallel GC threads.
uint marking_thread_num = scale_concurrent_worker_threads(ParallelGCThreads);
- FLAG_SET_ERGO(uint, ConcGCThreads, marking_thread_num);
+ FLAG_SET_ERGO(ConcGCThreads, marking_thread_num);
}
assert(ConcGCThreads > 0, "ConcGCThreads have been set.");
@@ -456,7 +456,7 @@
mark_stack_size, MarkStackSizeMax);
return;
}
- FLAG_SET_ERGO(size_t, MarkStackSize, mark_stack_size);
+ FLAG_SET_ERGO(MarkStackSize, mark_stack_size);
} else {
// Verify MarkStackSize is in range.
if (FLAG_IS_CMDLINE(MarkStackSize)) {
--- a/src/hotspot/share/gc/g1/g1DirtyCardQueue.cpp Fri May 17 13:21:44 2019 +0100
+++ b/src/hotspot/share/gc/g1/g1DirtyCardQueue.cpp Thu May 23 11:07:37 2019 +0100
@@ -66,8 +66,21 @@
flush();
}
+void G1DirtyCardQueue::handle_completed_buffer() {
+ assert(_buf != NULL, "precondition");
+ BufferNode* node = BufferNode::make_node_from_buffer(_buf, index());
+ G1DirtyCardQueueSet* dcqs = dirty_card_qset();
+ if (dcqs->process_or_enqueue_completed_buffer(node)) {
+ reset(); // Buffer fully processed, reset index.
+ } else {
+ allocate_buffer(); // Buffer enqueued, get a new one.
+ }
+}
+
G1DirtyCardQueueSet::G1DirtyCardQueueSet(bool notify_when_complete) :
PtrQueueSet(notify_when_complete),
+ _max_completed_buffers(MaxCompletedBuffersUnlimited),
+ _completed_buffers_padding(0),
_free_ids(NULL),
_processed_buffers_mut(0),
_processed_buffers_rs_thread(0),
@@ -136,6 +149,24 @@
} while (0)
#endif // ASSERT
+bool G1DirtyCardQueueSet::process_or_enqueue_completed_buffer(BufferNode* node) {
+ if (Thread::current()->is_Java_thread()) {
+ // If the number of buffers exceeds the limit, make this Java
+ // thread do the processing itself. We don't lock to access
+ // buffer count or padding; it is fine to be imprecise here. The
+ // add of padding could overflow, which is treated as unlimited.
+ size_t max_buffers = max_completed_buffers();
+ size_t limit = max_buffers + completed_buffers_padding();
+ if ((completed_buffers_num() > limit) && (limit >= max_buffers)) {
+ if (mut_process_buffer(node)) {
+ return true;
+ }
+ }
+ }
+ enqueue_completed_buffer(node);
+ return false;
+}
+
bool G1DirtyCardQueueSet::mut_process_buffer(BufferNode* node) {
guarantee(_free_ids != NULL, "must be");
--- a/src/hotspot/share/gc/g1/g1DirtyCardQueue.hpp Fri May 17 13:21:44 2019 +0100
+++ b/src/hotspot/share/gc/g1/g1DirtyCardQueue.hpp Thu May 23 11:07:37 2019 +0100
@@ -47,6 +47,9 @@
// A ptrQueue whose elements are "oops", pointers to object heads.
class G1DirtyCardQueue: public PtrQueue {
+protected:
+ virtual void handle_completed_buffer();
+
public:
G1DirtyCardQueue(G1DirtyCardQueueSet* qset);
@@ -57,6 +60,8 @@
// Process queue entries and release resources.
void flush() { flush_impl(); }
+ inline G1DirtyCardQueueSet* dirty_card_qset() const;
+
// Compiler support.
static ByteSize byte_offset_of_index() {
return PtrQueue::byte_offset_of_index<G1DirtyCardQueue>();
@@ -102,6 +107,12 @@
bool mut_process_buffer(BufferNode* node);
+ // If the queue contains more buffers than configured here, the
+ // mutator must start doing some of the concurrent refinement work,
+ size_t _max_completed_buffers;
+ size_t _completed_buffers_padding;
+ static const size_t MaxCompletedBuffersUnlimited = ~size_t(0);
+
G1FreeIdSet* _free_ids;
// The number of completed buffers processed by mutator and rs thread,
@@ -126,6 +137,11 @@
static void handle_zero_index_for_thread(Thread* t);
+ // Either process the entire buffer and return true, or enqueue the
+ // buffer and return false. If the buffer is completely processed,
+ // it can be reused in place.
+ bool process_or_enqueue_completed_buffer(BufferNode* node);
+
// Apply G1RefineCardConcurrentlyClosure to completed buffers until there are stop_at
// completed buffers remaining.
bool refine_completed_buffer_concurrently(uint worker_i, size_t stop_at);
@@ -147,6 +163,20 @@
// If any threads have partial logs, add them to the global list of logs.
void concatenate_logs();
+ void set_max_completed_buffers(size_t m) {
+ _max_completed_buffers = m;
+ }
+ size_t max_completed_buffers() const {
+ return _max_completed_buffers;
+ }
+
+ void set_completed_buffers_padding(size_t padding) {
+ _completed_buffers_padding = padding;
+ }
+ size_t completed_buffers_padding() const {
+ return _completed_buffers_padding;
+ }
+
jint processed_buffers_mut() {
return _processed_buffers_mut;
}
@@ -156,4 +186,8 @@
};
+inline G1DirtyCardQueueSet* G1DirtyCardQueue::dirty_card_qset() const {
+ return static_cast<G1DirtyCardQueueSet*>(qset());
+}
+
#endif // SHARE_GC_G1_G1DIRTYCARDQUEUE_HPP
--- a/src/hotspot/share/gc/g1/g1EvacFailure.cpp Fri May 17 13:21:44 2019 +0100
+++ b/src/hotspot/share/gc/g1/g1EvacFailure.cpp Thu May 23 11:07:37 2019 +0100
@@ -30,7 +30,6 @@
#include "gc/g1/g1EvacFailure.hpp"
#include "gc/g1/g1HeapVerifier.hpp"
#include "gc/g1/g1OopClosures.inline.hpp"
-#include "gc/g1/g1_globals.hpp"
#include "gc/g1/heapRegion.hpp"
#include "gc/g1/heapRegionRemSet.hpp"
#include "gc/shared/preservedMarks.inline.hpp"
--- a/src/hotspot/share/gc/g1/g1EvacStats.cpp Fri May 17 13:21:44 2019 +0100
+++ b/src/hotspot/share/gc/g1/g1EvacStats.cpp Thu May 23 11:07:37 2019 +0100
@@ -23,7 +23,6 @@
*/
#include "precompiled.hpp"
-#include "gc/g1/g1_globals.hpp"
#include "gc/g1/g1EvacStats.hpp"
#include "gc/shared/gcId.hpp"
#include "logging/log.hpp"
--- a/src/hotspot/share/gc/g1/g1HotCardCache.hpp Fri May 17 13:21:44 2019 +0100
+++ b/src/hotspot/share/gc/g1/g1HotCardCache.hpp Thu May 23 11:07:37 2019 +0100
@@ -26,7 +26,6 @@
#define SHARE_GC_G1_G1HOTCARDCACHE_HPP
#include "gc/g1/g1CardCounts.hpp"
-#include "gc/g1/g1_globals.hpp"
#include "memory/allocation.hpp"
#include "runtime/safepoint.hpp"
#include "runtime/thread.hpp"
--- a/src/hotspot/share/gc/g1/g1OopClosures.hpp Fri May 17 13:21:44 2019 +0100
+++ b/src/hotspot/share/gc/g1/g1OopClosures.hpp Thu May 23 11:07:37 2019 +0100
@@ -73,9 +73,10 @@
// Used during Optional RS scanning to make sure we trim the queues in a timely manner.
class G1ScanRSForOptionalClosure : public OopClosure {
+ G1CollectedHeap* _g1h;
G1ScanCardClosure* _scan_cl;
public:
- G1ScanRSForOptionalClosure(G1ScanCardClosure* cl) : _scan_cl(cl) { }
+ G1ScanRSForOptionalClosure(G1CollectedHeap* g1h, G1ScanCardClosure* cl) : _g1h(g1h), _scan_cl(cl) { }
template <class T> void do_oop_work(T* p);
virtual void do_oop(oop* p) { do_oop_work(p); }
--- a/src/hotspot/share/gc/g1/g1OopClosures.inline.hpp Fri May 17 13:21:44 2019 +0100
+++ b/src/hotspot/share/gc/g1/g1OopClosures.inline.hpp Thu May 23 11:07:37 2019 +0100
@@ -169,11 +169,14 @@
check_obj_during_refinement(p, obj);
- // We can not check for references from the collection set: the remembered sets
- // may contain such entries and we do not filter them before.
+ assert(!_g1h->is_in_cset((HeapWord*)p),
+ "Oop originates from " PTR_FORMAT " (region: %u) which is in the collection set.",
+ p2i(p), _g1h->addr_to_region((HeapWord*)p));
const G1HeapRegionAttr region_attr = _g1h->region_attr(obj);
if (region_attr.is_in_cset()) {
+ // Since the source is always from outside the collection set, here we implicitly know
+ // that this is a cross-region reference too.
prefetch_and_push(p, obj);
} else if (!HeapRegion::is_in_same_region(p, obj)) {
handle_non_cset_obj_common(region_attr, p, obj);
@@ -183,6 +186,13 @@
template <class T>
inline void G1ScanRSForOptionalClosure::do_oop_work(T* p) {
+ const G1HeapRegionAttr region_attr = _g1h->region_attr(p);
+ // Entries in the optional collection set may start to originate from the collection
+ // set after one or more increments. In this case, previously optional regions
+ // became actual collection set regions. Filter them out here.
+ if (region_attr.is_in_cset()) {
+ return;
+ }
_scan_cl->do_oop_work(p);
_scan_cl->trim_queue_partially();
}
--- a/src/hotspot/share/gc/g1/g1ParScanThreadState.inline.hpp Fri May 17 13:21:44 2019 +0100
+++ b/src/hotspot/share/gc/g1/g1ParScanThreadState.inline.hpp Thu May 23 11:07:37 2019 +0100
@@ -208,6 +208,8 @@
inline void G1ParScanThreadState::remember_root_into_optional_region(T* p) {
oop o = RawAccess<IS_NOT_NULL>::oop_load(p);
uint index = _g1h->heap_region_containing(o)->index_in_opt_cset();
+ assert(index < _num_optional_regions,
+ "Trying to access optional region idx %u beyond " SIZE_FORMAT, index, _num_optional_regions);
_oops_into_optional_regions[index].push_root(p);
}
@@ -215,11 +217,16 @@
inline void G1ParScanThreadState::remember_reference_into_optional_region(T* p) {
oop o = RawAccess<IS_NOT_NULL>::oop_load(p);
uint index = _g1h->heap_region_containing(o)->index_in_opt_cset();
+ assert(index < _num_optional_regions,
+ "Trying to access optional region idx %u beyond " SIZE_FORMAT, index, _num_optional_regions);
_oops_into_optional_regions[index].push_oop(p);
DEBUG_ONLY(verify_ref(p);)
}
G1OopStarChunkedList* G1ParScanThreadState::oops_into_optional_region(const HeapRegion* hr) {
+ assert(hr->index_in_opt_cset() < _num_optional_regions,
+ "Trying to access optional region idx %u beyond " SIZE_FORMAT " " HR_FORMAT,
+ hr->index_in_opt_cset(), _num_optional_regions, HR_FORMAT_PARAMS(hr));
return &_oops_into_optional_regions[hr->index_in_opt_cset()];
}
--- a/src/hotspot/share/gc/g1/g1RemSet.cpp Fri May 17 13:21:44 2019 +0100
+++ b/src/hotspot/share/gc/g1/g1RemSet.cpp Thu May 23 11:07:37 2019 +0100
@@ -188,7 +188,7 @@
void reset() {
for (uint i = 0; i < _max_regions; i++) {
_iter_states[i] = Unclaimed;
- _scan_top[i] = NULL;
+ clear_scan_top(i);
}
G1ResetScanTopClosure cl(_scan_top);
@@ -253,6 +253,10 @@
return _scan_top[region_idx];
}
+ void clear_scan_top(uint region_idx) {
+ _scan_top[region_idx] = NULL;
+ }
+
// Clear the card table of "dirty" regions.
void clear_card_table(WorkGang* workers) {
if (_cur_dirty_region == 0) {
@@ -304,158 +308,198 @@
_scan_state->initialize(max_regions);
}
-G1ScanRSForRegionClosure::G1ScanRSForRegionClosure(G1RemSetScanState* scan_state,
- G1ScanCardClosure* scan_obj_on_card,
- G1ParScanThreadState* pss,
- G1GCPhaseTimes::GCParPhases phase,
- uint worker_i) :
- _g1h(G1CollectedHeap::heap()),
- _ct(_g1h->card_table()),
- _pss(pss),
- _scan_objs_on_card_cl(scan_obj_on_card),
- _scan_state(scan_state),
- _phase(phase),
- _worker_i(worker_i),
- _opt_refs_scanned(0),
- _opt_refs_memory_used(0),
- _cards_scanned(0),
- _cards_claimed(0),
- _cards_skipped(0),
- _rem_set_root_scan_time(),
- _rem_set_trim_partially_time(),
- _strong_code_root_scan_time(),
- _strong_code_trim_partially_time() {
-}
+class G1ScanRSForRegionClosure : public HeapRegionClosure {
+ G1CollectedHeap* _g1h;
+ G1CardTable *_ct;
-void G1ScanRSForRegionClosure::claim_card(size_t card_index, const uint region_idx_for_card){
- _ct->set_card_claimed(card_index);
- _scan_state->add_dirty_region(region_idx_for_card);
-}
+ G1ParScanThreadState* _pss;
+ G1ScanCardClosure* _scan_objs_on_card_cl;
+
+ G1RemSetScanState* _scan_state;
+
+ G1GCPhaseTimes::GCParPhases _phase;
+
+ uint _worker_i;
-void G1ScanRSForRegionClosure::scan_card(MemRegion mr, uint region_idx_for_card) {
- HeapRegion* const card_region = _g1h->region_at(region_idx_for_card);
- assert(!card_region->is_young(), "Should not scan card in young region %u", region_idx_for_card);
- card_region->oops_on_card_seq_iterate_careful<true>(mr, _scan_objs_on_card_cl);
- _scan_objs_on_card_cl->trim_queue_partially();
- _cards_scanned++;
-}
+ size_t _opt_refs_scanned;
+ size_t _opt_refs_memory_used;
-void G1ScanRSForRegionClosure::scan_opt_rem_set_roots(HeapRegion* r) {
- EventGCPhaseParallel event;
-
- G1OopStarChunkedList* opt_rem_set_list = _pss->oops_into_optional_region(r);
+ size_t _cards_scanned;
+ size_t _cards_claimed;
+ size_t _cards_skipped;
- G1ScanCardClosure scan_cl(_g1h, _pss);
- G1ScanRSForOptionalClosure cl(&scan_cl);
- _opt_refs_scanned += opt_rem_set_list->oops_do(&cl, _pss->closures()->raw_strong_oops());
- _opt_refs_memory_used += opt_rem_set_list->used_memory();
-
- event.commit(GCId::current(), _worker_i, G1GCPhaseTimes::phase_name(_phase));
-}
+ Tickspan _rem_set_root_scan_time;
+ Tickspan _rem_set_trim_partially_time;
-void G1ScanRSForRegionClosure::scan_rem_set_roots(HeapRegion* r) {
- EventGCPhaseParallel event;
- uint const region_idx = r->hrm_index();
+ Tickspan _strong_code_root_scan_time;
+ Tickspan _strong_code_trim_partially_time;
- if (_scan_state->claim_iter(region_idx)) {
- // If we ever free the collection set concurrently, we should also
- // clear the card table concurrently therefore we won't need to
- // add regions of the collection set to the dirty cards region.
- _scan_state->add_dirty_region(region_idx);
+ void claim_card(size_t card_index, const uint region_idx_for_card) {
+ _ct->set_card_claimed(card_index);
+ _scan_state->add_dirty_region(region_idx_for_card);
}
- if (r->rem_set()->cardset_is_empty()) {
- return;
+ void scan_card(MemRegion mr, uint region_idx_for_card) {
+ HeapRegion* const card_region = _g1h->region_at(region_idx_for_card);
+ assert(!card_region->is_young(), "Should not scan card in young region %u", region_idx_for_card);
+ card_region->oops_on_card_seq_iterate_careful<true>(mr, _scan_objs_on_card_cl);
+ _scan_objs_on_card_cl->trim_queue_partially();
+ _cards_scanned++;
+ }
+
+ void scan_opt_rem_set_roots(HeapRegion* r) {
+ EventGCPhaseParallel event;
+
+ G1OopStarChunkedList* opt_rem_set_list = _pss->oops_into_optional_region(r);
+
+ G1ScanCardClosure scan_cl(_g1h, _pss);
+ G1ScanRSForOptionalClosure cl(_g1h, &scan_cl);
+ _opt_refs_scanned += opt_rem_set_list->oops_do(&cl, _pss->closures()->raw_strong_oops());
+ _opt_refs_memory_used += opt_rem_set_list->used_memory();
+
+ event.commit(GCId::current(), _worker_i, G1GCPhaseTimes::phase_name(_phase));
}
- // We claim cards in blocks so as to reduce the contention.
- size_t const block_size = G1RSetScanBlockSize;
-
- HeapRegionRemSetIterator iter(r->rem_set());
- size_t card_index;
+ void scan_rem_set_roots(HeapRegion* r) {
+ EventGCPhaseParallel event;
+ uint const region_idx = r->hrm_index();
- size_t claimed_card_block = _scan_state->iter_claimed_next(region_idx, block_size);
- for (size_t current_card = 0; iter.has_next(card_index); current_card++) {
- if (current_card >= claimed_card_block + block_size) {
- claimed_card_block = _scan_state->iter_claimed_next(region_idx, block_size);
- }
- if (current_card < claimed_card_block) {
- _cards_skipped++;
- continue;
- }
- _cards_claimed++;
-
- HeapWord* const card_start = _g1h->bot()->address_for_index_raw(card_index);
- uint const region_idx_for_card = _g1h->addr_to_region(card_start);
-
-#ifdef ASSERT
- HeapRegion* hr = _g1h->region_at_or_null(region_idx_for_card);
- assert(hr == NULL || hr->is_in_reserved(card_start),
- "Card start " PTR_FORMAT " to scan outside of region %u", p2i(card_start), _g1h->region_at(region_idx_for_card)->hrm_index());
-#endif
- HeapWord* const top = _scan_state->scan_top(region_idx_for_card);
- if (card_start >= top) {
- continue;
+ if (_scan_state->claim_iter(region_idx)) {
+ // If we ever free the collection set concurrently, we should also
+ // clear the card table concurrently therefore we won't need to
+ // add regions of the collection set to the dirty cards region.
+ _scan_state->add_dirty_region(region_idx);
}
- // If the card is dirty, then G1 will scan it during Update RS.
- if (_ct->is_card_claimed(card_index) || _ct->is_card_dirty(card_index)) {
- continue;
+ if (r->rem_set()->cardset_is_empty()) {
+ return;
}
- // We claim lazily (so races are possible but they're benign), which reduces the
- // number of duplicate scans (the rsets of the regions in the cset can intersect).
- // Claim the card after checking bounds above: the remembered set may contain
- // random cards into current survivor, and we would then have an incorrectly
- // claimed card in survivor space. Card table clear does not reset the card table
- // of survivor space regions.
- claim_card(card_index, region_idx_for_card);
+ // We claim cards in blocks so as to reduce the contention.
+ size_t const block_size = G1RSetScanBlockSize;
+
+ HeapRegionRemSetIterator iter(r->rem_set());
+ size_t card_index;
- MemRegion const mr(card_start, MIN2(card_start + BOTConstants::N_words, top));
+ size_t claimed_card_block = _scan_state->iter_claimed_next(region_idx, block_size);
+ for (size_t current_card = 0; iter.has_next(card_index); current_card++) {
+ if (current_card >= claimed_card_block + block_size) {
+ claimed_card_block = _scan_state->iter_claimed_next(region_idx, block_size);
+ }
+ if (current_card < claimed_card_block) {
+ _cards_skipped++;
+ continue;
+ }
+ _cards_claimed++;
- scan_card(mr, region_idx_for_card);
- }
- event.commit(GCId::current(), _worker_i, G1GCPhaseTimes::phase_name(_phase));
-}
+ HeapWord* const card_start = _g1h->bot()->address_for_index_raw(card_index);
+ uint const region_idx_for_card = _g1h->addr_to_region(card_start);
-void G1ScanRSForRegionClosure::scan_strong_code_roots(HeapRegion* r) {
- EventGCPhaseParallel event;
- // We pass a weak code blobs closure to the remembered set scanning because we want to avoid
- // treating the nmethods visited to act as roots for concurrent marking.
- // We only want to make sure that the oops in the nmethods are adjusted with regard to the
- // objects copied by the current evacuation.
- r->strong_code_roots_do(_pss->closures()->weak_codeblobs());
- event.commit(GCId::current(), _worker_i, G1GCPhaseTimes::phase_name(G1GCPhaseTimes::CodeRoots));
-}
+#ifdef ASSERT
+ HeapRegion* hr = _g1h->region_at_or_null(region_idx_for_card);
+ assert(hr == NULL || hr->is_in_reserved(card_start),
+ "Card start " PTR_FORMAT " to scan outside of region %u", p2i(card_start), _g1h->region_at(region_idx_for_card)->hrm_index());
+#endif
+ HeapWord* const top = _scan_state->scan_top(region_idx_for_card);
+ if (card_start >= top) {
+ continue;
+ }
-bool G1ScanRSForRegionClosure::do_heap_region(HeapRegion* r) {
- assert(r->in_collection_set(), "Region %u is not in the collection set.", r->hrm_index());
- uint const region_idx = r->hrm_index();
+ // If the card is dirty, then G1 will scan it during Update RS.
+ if (_ct->is_card_claimed(card_index) || _ct->is_card_dirty(card_index)) {
+ continue;
+ }
- // The individual references for the optional remembered set are per-worker, so we
- // always need to scan them.
- if (r->has_index_in_opt_cset()) {
- G1EvacPhaseWithTrimTimeTracker timer(_pss, _rem_set_root_scan_time, _rem_set_trim_partially_time);
- scan_opt_rem_set_roots(r);
+ // We claim lazily (so races are possible but they're benign), which reduces the
+ // number of duplicate scans (the rsets of the regions in the cset can intersect).
+ // Claim the card after checking bounds above: the remembered set may contain
+ // random cards into current survivor, and we would then have an incorrectly
+ // claimed card in survivor space. Card table clear does not reset the card table
+ // of survivor space regions.
+ claim_card(card_index, region_idx_for_card);
+
+ MemRegion const mr(card_start, MIN2(card_start + BOTConstants::N_words, top));
+
+ scan_card(mr, region_idx_for_card);
+ }
+ event.commit(GCId::current(), _worker_i, G1GCPhaseTimes::phase_name(_phase));
}
- // Do an early out if we know we are complete.
- if (_scan_state->iter_is_complete(region_idx)) {
+ void scan_strong_code_roots(HeapRegion* r) {
+ EventGCPhaseParallel event;
+ // We pass a weak code blobs closure to the remembered set scanning because we want to avoid
+ // treating the nmethods visited to act as roots for concurrent marking.
+ // We only want to make sure that the oops in the nmethods are adjusted with regard to the
+ // objects copied by the current evacuation.
+ r->strong_code_roots_do(_pss->closures()->weak_codeblobs());
+ event.commit(GCId::current(), _worker_i, G1GCPhaseTimes::phase_name(G1GCPhaseTimes::CodeRoots));
+ }
+
+public:
+ G1ScanRSForRegionClosure(G1RemSetScanState* scan_state,
+ G1ScanCardClosure* scan_obj_on_card,
+ G1ParScanThreadState* pss,
+ G1GCPhaseTimes::GCParPhases phase,
+ uint worker_i) :
+ _g1h(G1CollectedHeap::heap()),
+ _ct(_g1h->card_table()),
+ _pss(pss),
+ _scan_objs_on_card_cl(scan_obj_on_card),
+ _scan_state(scan_state),
+ _phase(phase),
+ _worker_i(worker_i),
+ _opt_refs_scanned(0),
+ _opt_refs_memory_used(0),
+ _cards_scanned(0),
+ _cards_claimed(0),
+ _cards_skipped(0),
+ _rem_set_root_scan_time(),
+ _rem_set_trim_partially_time(),
+ _strong_code_root_scan_time(),
+ _strong_code_trim_partially_time() { }
+
+ bool do_heap_region(HeapRegion* r) {
+ assert(r->in_collection_set(), "Region %u is not in the collection set.", r->hrm_index());
+ uint const region_idx = r->hrm_index();
+
+ // The individual references for the optional remembered set are per-worker, so we
+ // always need to scan them.
+ if (r->has_index_in_opt_cset()) {
+ G1EvacPhaseWithTrimTimeTracker timer(_pss, _rem_set_root_scan_time, _rem_set_trim_partially_time);
+ scan_opt_rem_set_roots(r);
+ }
+
+ // Do an early out if we know we are complete.
+ if (_scan_state->iter_is_complete(region_idx)) {
+ return false;
+ }
+
+ {
+ G1EvacPhaseWithTrimTimeTracker timer(_pss, _rem_set_root_scan_time, _rem_set_trim_partially_time);
+ scan_rem_set_roots(r);
+ }
+
+ if (_scan_state->set_iter_complete(region_idx)) {
+ G1EvacPhaseWithTrimTimeTracker timer(_pss, _strong_code_root_scan_time, _strong_code_trim_partially_time);
+ // Scan the strong code root list attached to the current region
+ scan_strong_code_roots(r);
+ }
return false;
}
- {
- G1EvacPhaseWithTrimTimeTracker timer(_pss, _rem_set_root_scan_time, _rem_set_trim_partially_time);
- scan_rem_set_roots(r);
- }
+ Tickspan rem_set_root_scan_time() const { return _rem_set_root_scan_time; }
+ Tickspan rem_set_trim_partially_time() const { return _rem_set_trim_partially_time; }
+
+ Tickspan strong_code_root_scan_time() const { return _strong_code_root_scan_time; }
+ Tickspan strong_code_root_trim_partially_time() const { return _strong_code_trim_partially_time; }
- if (_scan_state->set_iter_complete(region_idx)) {
- G1EvacPhaseWithTrimTimeTracker timer(_pss, _strong_code_root_scan_time, _strong_code_trim_partially_time);
- // Scan the strong code root list attached to the current region
- scan_strong_code_roots(r);
- }
- return false;
-}
+ size_t cards_scanned() const { return _cards_scanned; }
+ size_t cards_claimed() const { return _cards_claimed; }
+ size_t cards_skipped() const { return _cards_skipped; }
+
+ size_t opt_refs_scanned() const { return _opt_refs_scanned; }
+ size_t opt_refs_memory_used() const { return _opt_refs_memory_used; }
+};
void G1RemSet::scan_rem_set(G1ParScanThreadState* pss,
uint worker_i,
@@ -550,6 +594,10 @@
_scan_state->reset();
}
+void G1RemSet::prepare_for_scan_rem_set(uint region_idx) {
+ _scan_state->clear_scan_top(region_idx);
+}
+
void G1RemSet::cleanup_after_scan_rem_set() {
G1GCPhaseTimes* phase_times = _g1h->phase_times();
--- a/src/hotspot/share/gc/g1/g1RemSet.hpp Fri May 17 13:21:44 2019 +0100
+++ b/src/hotspot/share/gc/g1/g1RemSet.hpp Thu May 23 11:07:37 2019 +0100
@@ -98,10 +98,12 @@
// into the collection set or update the remembered set.
void update_rem_set(G1ParScanThreadState* pss, uint worker_i);
- // Prepare for and cleanup after scanning the remembered sets. Must be called
+ // Prepare for and cleanup after scanning the remembered sets. Must be called
// once before and after in sequential code.
void prepare_for_scan_rem_set();
void cleanup_after_scan_rem_set();
+ // Prepares the given region for remembered set scanning.
+ void prepare_for_scan_rem_set(uint region_idx);
G1RemSetScanState* scan_state() const { return _scan_state; }
@@ -128,59 +130,4 @@
void rebuild_rem_set(G1ConcurrentMark* cm, WorkGang* workers, uint worker_id_offset);
};
-class G1ScanRSForRegionClosure : public HeapRegionClosure {
- G1CollectedHeap* _g1h;
- G1CardTable *_ct;
-
- G1ParScanThreadState* _pss;
- G1ScanCardClosure* _scan_objs_on_card_cl;
-
- G1RemSetScanState* _scan_state;
-
- G1GCPhaseTimes::GCParPhases _phase;
-
- uint _worker_i;
-
- size_t _opt_refs_scanned;
- size_t _opt_refs_memory_used;
-
- size_t _cards_scanned;
- size_t _cards_claimed;
- size_t _cards_skipped;
-
- Tickspan _rem_set_root_scan_time;
- Tickspan _rem_set_trim_partially_time;
-
- Tickspan _strong_code_root_scan_time;
- Tickspan _strong_code_trim_partially_time;
-
- void claim_card(size_t card_index, const uint region_idx_for_card);
- void scan_card(MemRegion mr, uint region_idx_for_card);
-
- void scan_opt_rem_set_roots(HeapRegion* r);
- void scan_rem_set_roots(HeapRegion* r);
- void scan_strong_code_roots(HeapRegion* r);
-public:
- G1ScanRSForRegionClosure(G1RemSetScanState* scan_state,
- G1ScanCardClosure* scan_obj_on_card,
- G1ParScanThreadState* pss,
- G1GCPhaseTimes::GCParPhases phase,
- uint worker_i);
-
- bool do_heap_region(HeapRegion* r);
-
- Tickspan rem_set_root_scan_time() const { return _rem_set_root_scan_time; }
- Tickspan rem_set_trim_partially_time() const { return _rem_set_trim_partially_time; }
-
- Tickspan strong_code_root_scan_time() const { return _strong_code_root_scan_time; }
- Tickspan strong_code_root_trim_partially_time() const { return _strong_code_trim_partially_time; }
-
- size_t cards_scanned() const { return _cards_scanned; }
- size_t cards_claimed() const { return _cards_claimed; }
- size_t cards_skipped() const { return _cards_skipped; }
-
- size_t opt_refs_scanned() const { return _opt_refs_scanned; }
- size_t opt_refs_memory_used() const { return _opt_refs_memory_used; }
-};
-
#endif // SHARE_GC_G1_G1REMSET_HPP
--- a/src/hotspot/share/gc/g1/g1YoungGenSizer.cpp Fri May 17 13:21:44 2019 +0100
+++ b/src/hotspot/share/gc/g1/g1YoungGenSizer.cpp Thu May 23 11:07:37 2019 +0100
@@ -48,7 +48,7 @@
"A new max generation size of " SIZE_FORMAT "k will be used.",
NewSize/K, MaxNewSize/K, NewSize/K);
}
- FLAG_SET_ERGO(size_t, MaxNewSize, NewSize);
+ FLAG_SET_ERGO(MaxNewSize, NewSize);
}
if (FLAG_IS_CMDLINE(NewSize)) {
@@ -121,7 +121,7 @@
size_t max_young_size = result * HeapRegion::GrainBytes;
if (max_young_size != MaxNewSize) {
- FLAG_SET_ERGO(size_t, MaxNewSize, max_young_size);
+ FLAG_SET_ERGO(MaxNewSize, max_young_size);
}
}
--- a/src/hotspot/share/gc/g1/g1_globals.hpp Fri May 17 13:21:44 2019 +0100
+++ b/src/hotspot/share/gc/g1/g1_globals.hpp Thu May 23 11:07:37 2019 +0100
@@ -25,7 +25,8 @@
#ifndef SHARE_GC_G1_G1_GLOBALS_HPP
#define SHARE_GC_G1_G1_GLOBALS_HPP
-#include <float.h> // for DBL_MAX
+#include "runtime/globals_shared.hpp"
+
//
// Defines all globals flags used by the garbage-first compiler.
//
--- a/src/hotspot/share/gc/g1/heapRegion.cpp Fri May 17 13:21:44 2019 +0100
+++ b/src/hotspot/share/gc/g1/heapRegion.cpp Thu May 23 11:07:37 2019 +0100
@@ -106,7 +106,7 @@
CardsPerRegion = GrainBytes >> G1CardTable::card_shift;
if (G1HeapRegionSize != GrainBytes) {
- FLAG_SET_ERGO(size_t, G1HeapRegionSize, GrainBytes);
+ FLAG_SET_ERGO(G1HeapRegionSize, GrainBytes);
}
}
--- a/src/hotspot/share/gc/parallel/parallelArguments.cpp Fri May 17 13:21:44 2019 +0100
+++ b/src/hotspot/share/gc/parallel/parallelArguments.cpp Thu May 23 11:07:37 2019 +0100
@@ -113,11 +113,11 @@
// default gc, which adds 2 to the ratio value. We need to
// make sure the values are valid before using them.
if (MinSurvivorRatio < 3) {
- FLAG_SET_ERGO(uintx, MinSurvivorRatio, 3);
+ FLAG_SET_ERGO(MinSurvivorRatio, 3);
}
if (InitialSurvivorRatio < 3) {
- FLAG_SET_ERGO(uintx, InitialSurvivorRatio, 3);
+ FLAG_SET_ERGO(InitialSurvivorRatio, 3);
}
}
--- a/src/hotspot/share/gc/shared/gcArguments.cpp Fri May 17 13:21:44 2019 +0100
+++ b/src/hotspot/share/gc/shared/gcArguments.cpp Thu May 23 11:07:37 2019 +0100
@@ -54,12 +54,12 @@
if (MinHeapFreeRatio == 100) {
// Keeping the heap 100% free is hard ;-) so limit it to 99%.
- FLAG_SET_ERGO(uintx, MinHeapFreeRatio, 99);
+ FLAG_SET_ERGO(MinHeapFreeRatio, 99);
}
if (!ClassUnloading) {
// If class unloading is disabled, also disable concurrent class unloading.
- FLAG_SET_CMDLINE(bool, ClassUnloadingWithConcurrentMark, false);
+ FLAG_SET_CMDLINE(ClassUnloadingWithConcurrentMark, false);
}
if (!FLAG_IS_DEFAULT(AllocateOldGenAt)) {
@@ -172,10 +172,10 @@
// Write back to flags if the values changed
if (aligned_initial_heap_size != InitialHeapSize) {
- FLAG_SET_ERGO(size_t, InitialHeapSize, aligned_initial_heap_size);
+ FLAG_SET_ERGO(InitialHeapSize, aligned_initial_heap_size);
}
if (aligned_max_heap_size != MaxHeapSize) {
- FLAG_SET_ERGO(size_t, MaxHeapSize, aligned_max_heap_size);
+ FLAG_SET_ERGO(MaxHeapSize, aligned_max_heap_size);
}
if (FLAG_IS_CMDLINE(InitialHeapSize) && MinHeapSize != 0 &&
@@ -183,15 +183,15 @@
vm_exit_during_initialization("Incompatible minimum and initial heap sizes specified");
}
if (!FLAG_IS_DEFAULT(InitialHeapSize) && InitialHeapSize > MaxHeapSize) {
- FLAG_SET_ERGO(size_t, MaxHeapSize, InitialHeapSize);
+ FLAG_SET_ERGO(MaxHeapSize, InitialHeapSize);
} else if (!FLAG_IS_DEFAULT(MaxHeapSize) && InitialHeapSize > MaxHeapSize) {
- FLAG_SET_ERGO(size_t, InitialHeapSize, MaxHeapSize);
+ FLAG_SET_ERGO(InitialHeapSize, MaxHeapSize);
if (InitialHeapSize < MinHeapSize) {
MinHeapSize = InitialHeapSize;
}
}
- FLAG_SET_ERGO(size_t, MinHeapDeltaBytes, align_up(MinHeapDeltaBytes, SpaceAlignment));
+ FLAG_SET_ERGO(MinHeapDeltaBytes, align_up(MinHeapDeltaBytes, SpaceAlignment));
DEBUG_ONLY(assert_flags();)
}
--- a/src/hotspot/share/gc/shared/gcCause.cpp Fri May 17 13:21:44 2019 +0100
+++ b/src/hotspot/share/gc/shared/gcCause.cpp Thu May 23 11:07:37 2019 +0100
@@ -141,6 +141,9 @@
case _z_proactive:
return "Proactive";
+ case _z_high_usage:
+ return "High Usage";
+
case _last_gc_cause:
return "ILLEGAL VALUE - last gc cause - ILLEGAL VALUE";
--- a/src/hotspot/share/gc/shared/gcCause.hpp Fri May 17 13:21:44 2019 +0100
+++ b/src/hotspot/share/gc/shared/gcCause.hpp Thu May 23 11:07:37 2019 +0100
@@ -91,6 +91,7 @@
_z_allocation_rate,
_z_allocation_stall,
_z_proactive,
+ _z_high_usage,
_last_gc_cause
};
--- a/src/hotspot/share/gc/shared/gcConfig.cpp Fri May 17 13:21:44 2019 +0100
+++ b/src/hotspot/share/gc/shared/gcConfig.cpp Thu May 23 11:07:37 2019 +0100
@@ -109,15 +109,15 @@
void GCConfig::select_gc_ergonomically() {
if (os::is_server_class_machine()) {
#if INCLUDE_G1GC
- FLAG_SET_ERGO_IF_DEFAULT(bool, UseG1GC, true);
+ FLAG_SET_ERGO_IF_DEFAULT(UseG1GC, true);
#elif INCLUDE_PARALLELGC
- FLAG_SET_ERGO_IF_DEFAULT(bool, UseParallelGC, true);
+ FLAG_SET_ERGO_IF_DEFAULT(UseParallelGC, true);
#elif INCLUDE_SERIALGC
- FLAG_SET_ERGO_IF_DEFAULT(bool, UseSerialGC, true);
+ FLAG_SET_ERGO_IF_DEFAULT(UseSerialGC, true);
#endif
} else {
#if INCLUDE_SERIALGC
- FLAG_SET_ERGO_IF_DEFAULT(bool, UseSerialGC, true);
+ FLAG_SET_ERGO_IF_DEFAULT(UseSerialGC, true);
#endif
}
}
--- a/src/hotspot/share/gc/shared/gc_globals.hpp Fri May 17 13:21:44 2019 +0100
+++ b/src/hotspot/share/gc/shared/gc_globals.hpp Thu May 23 11:07:37 2019 +0100
@@ -25,6 +25,7 @@
#ifndef SHARE_GC_SHARED_GC_GLOBALS_HPP
#define SHARE_GC_SHARED_GC_GLOBALS_HPP
+#include "runtime/globals_shared.hpp"
#include "utilities/macros.hpp"
#if INCLUDE_CMSGC
#include "gc/cms/cms_globals.hpp"
--- a/src/hotspot/share/gc/shared/genArguments.cpp Fri May 17 13:21:44 2019 +0100
+++ b/src/hotspot/share/gc/shared/genArguments.cpp Thu May 23 11:07:37 2019 +0100
@@ -86,20 +86,20 @@
size_t smallest_heap_size = align_up(smallest_new_size + old_gen_size_lower_bound(),
HeapAlignment);
if (MaxHeapSize < smallest_heap_size) {
- FLAG_SET_ERGO(size_t, MaxHeapSize, smallest_heap_size);
+ FLAG_SET_ERGO(MaxHeapSize, smallest_heap_size);
}
// If needed, synchronize MinHeapSize size and InitialHeapSize
if (MinHeapSize < smallest_heap_size) {
MinHeapSize = smallest_heap_size;
if (InitialHeapSize < MinHeapSize) {
- FLAG_SET_ERGO(size_t, InitialHeapSize, smallest_heap_size);
+ FLAG_SET_ERGO(InitialHeapSize, smallest_heap_size);
}
}
// Make sure NewSize allows an old generation to fit even if set on the command line
if (FLAG_IS_CMDLINE(NewSize) && NewSize >= InitialHeapSize) {
log_warning(gc, ergo)("NewSize was set larger than initial heap size, will use initial heap size.");
- FLAG_SET_ERGO(size_t, NewSize, bound_minus_alignment(NewSize, InitialHeapSize, GenAlignment));
+ FLAG_SET_ERGO(NewSize, bound_minus_alignment(NewSize, InitialHeapSize, GenAlignment));
}
// Now take the actual NewSize into account. We will silently increase NewSize
@@ -107,7 +107,7 @@
size_t bounded_new_size = bound_minus_alignment(NewSize, MaxHeapSize, GenAlignment);
bounded_new_size = MAX2(smallest_new_size, align_down(bounded_new_size, GenAlignment));
if (bounded_new_size != NewSize) {
- FLAG_SET_ERGO(size_t, NewSize, bounded_new_size);
+ FLAG_SET_ERGO(NewSize, bounded_new_size);
}
MinNewSize = smallest_new_size;
@@ -120,14 +120,14 @@
"heap (" SIZE_FORMAT "k). A new max generation size of " SIZE_FORMAT "k will be used.",
MaxNewSize/K, MaxHeapSize/K, smaller_max_new_size/K);
}
- FLAG_SET_ERGO(size_t, MaxNewSize, smaller_max_new_size);
+ FLAG_SET_ERGO(MaxNewSize, smaller_max_new_size);
if (NewSize > MaxNewSize) {
- FLAG_SET_ERGO(size_t, NewSize, MaxNewSize);
+ FLAG_SET_ERGO(NewSize, MaxNewSize);
}
} else if (MaxNewSize < NewSize) {
- FLAG_SET_ERGO(size_t, MaxNewSize, NewSize);
+ FLAG_SET_ERGO(MaxNewSize, NewSize);
} else if (!is_aligned(MaxNewSize, GenAlignment)) {
- FLAG_SET_ERGO(size_t, MaxNewSize, align_down(MaxNewSize, GenAlignment));
+ FLAG_SET_ERGO(MaxNewSize, align_down(MaxNewSize, GenAlignment));
}
}
@@ -139,7 +139,7 @@
"A new max generation size of " SIZE_FORMAT "k will be used.",
NewSize/K, MaxNewSize/K, NewSize/K);
}
- FLAG_SET_ERGO(size_t, MaxNewSize, NewSize);
+ FLAG_SET_ERGO(MaxNewSize, NewSize);
}
if (SurvivorRatio < 1 || NewRatio < 1) {
@@ -147,10 +147,10 @@
}
if (OldSize < old_gen_size_lower_bound()) {
- FLAG_SET_ERGO(size_t, OldSize, old_gen_size_lower_bound());
+ FLAG_SET_ERGO(OldSize, old_gen_size_lower_bound());
}
if (!is_aligned(OldSize, GenAlignment)) {
- FLAG_SET_ERGO(size_t, OldSize, align_down(OldSize, GenAlignment));
+ FLAG_SET_ERGO(OldSize, align_down(OldSize, GenAlignment));
}
if (FLAG_IS_CMDLINE(OldSize) && FLAG_IS_DEFAULT(MaxHeapSize)) {
@@ -161,8 +161,8 @@
size_t calculated_heapsize = (OldSize / NewRatio) * (NewRatio + 1);
calculated_heapsize = align_up(calculated_heapsize, HeapAlignment);
- FLAG_SET_ERGO(size_t, MaxHeapSize, calculated_heapsize);
- FLAG_SET_ERGO(size_t, InitialHeapSize, calculated_heapsize);
+ FLAG_SET_ERGO(MaxHeapSize, calculated_heapsize);
+ FLAG_SET_ERGO(InitialHeapSize, calculated_heapsize);
}
// Adjust NewSize and OldSize or MaxHeapSize to match each other
@@ -173,15 +173,15 @@
size_t calculated_size = NewSize + OldSize;
double shrink_factor = (double) MaxHeapSize / calculated_size;
size_t smaller_new_size = align_down((size_t)(NewSize * shrink_factor), GenAlignment);
- FLAG_SET_ERGO(size_t, NewSize, MAX2(young_gen_size_lower_bound(), smaller_new_size));
+ FLAG_SET_ERGO(NewSize, MAX2(young_gen_size_lower_bound(), smaller_new_size));
// OldSize is already aligned because above we aligned MaxHeapSize to
// HeapAlignment, and we just made sure that NewSize is aligned to
// GenAlignment. In initialize_flags() we verified that HeapAlignment
// is a multiple of GenAlignment.
- FLAG_SET_ERGO(size_t, OldSize, MaxHeapSize - NewSize);
+ FLAG_SET_ERGO(OldSize, MaxHeapSize - NewSize);
} else {
- FLAG_SET_ERGO(size_t, MaxHeapSize, align_up(NewSize + OldSize, HeapAlignment));
+ FLAG_SET_ERGO(MaxHeapSize, align_up(NewSize + OldSize, HeapAlignment));
}
}
@@ -191,7 +191,7 @@
if (OldSize < InitialHeapSize) {
size_t new_size = InitialHeapSize - OldSize;
if (new_size >= MinNewSize && new_size <= MaxNewSize) {
- FLAG_SET_ERGO(size_t, NewSize, new_size);
+ FLAG_SET_ERGO(NewSize, new_size);
}
}
}
@@ -341,15 +341,15 @@
// Write back to flags if necessary.
if (NewSize != initial_young_size) {
- FLAG_SET_ERGO(size_t, NewSize, initial_young_size);
+ FLAG_SET_ERGO(NewSize, initial_young_size);
}
if (MaxNewSize != max_young_size) {
- FLAG_SET_ERGO(size_t, MaxNewSize, max_young_size);
+ FLAG_SET_ERGO(MaxNewSize, max_young_size);
}
if (OldSize != initial_old_size) {
- FLAG_SET_ERGO(size_t, OldSize, initial_old_size);
+ FLAG_SET_ERGO(OldSize, initial_old_size);
}
log_trace(gc, heap)("Minimum old " SIZE_FORMAT " Initial old " SIZE_FORMAT " Maximum old " SIZE_FORMAT,
--- a/src/hotspot/share/gc/shared/jvmFlagConstraintsGC.cpp Fri May 17 13:21:44 2019 +0100
+++ b/src/hotspot/share/gc/shared/jvmFlagConstraintsGC.cpp Thu May 23 11:07:37 2019 +0100
@@ -45,12 +45,6 @@
#if INCLUDE_PARALLELGC
#include "gc/parallel/jvmFlagConstraintsParallel.hpp"
#endif
-#ifdef COMPILER1
-#include "c1/c1_globals.hpp"
-#endif // COMPILER1
-#ifdef COMPILER2
-#include "opto/c2_globals.hpp"
-#endif // COMPILER2
// Some flags that have default values that indicate that the
// JVM should automatically determine an appropriate value
--- a/src/hotspot/share/gc/shared/ptrQueue.cpp Fri May 17 13:21:44 2019 +0100
+++ b/src/hotspot/share/gc/shared/ptrQueue.cpp Thu May 23 11:07:37 2019 +0100
@@ -62,7 +62,6 @@
}
}
-
void PtrQueue::enqueue_known_active(void* ptr) {
while (_index == 0) {
handle_zero_index();
@@ -75,6 +74,35 @@
_buf[index()] = ptr;
}
+void PtrQueue::handle_zero_index() {
+ assert(index() == 0, "precondition");
+
+ if (_buf != NULL) {
+ handle_completed_buffer();
+ } else {
+ // Bootstrapping kludge; lazily initialize capacity. The initial
+ // thread's queues are constructed before the second phase of the
+ // two-phase initialization of the associated qsets. As a result,
+ // we can't initialize _capacity_in_bytes in the queue constructor.
+ if (_capacity_in_bytes == 0) {
+ _capacity_in_bytes = index_to_byte_index(qset()->buffer_size());
+ }
+ allocate_buffer();
+ }
+}
+
+void PtrQueue::allocate_buffer() {
+ _buf = qset()->allocate_buffer();
+ reset();
+}
+
+void PtrQueue::enqueue_completed_buffer() {
+ assert(_buf != NULL, "precondition");
+ BufferNode* node = BufferNode::make_node_from_buffer(_buf, index());
+ qset()->enqueue_completed_buffer(node);
+ allocate_buffer();
+}
+
BufferNode* BufferNode::allocate(size_t size) {
size_t byte_size = size * sizeof(void*);
void* data = NEW_C_HEAP_ARRAY(char, buffer_offset() + byte_size, mtGC);
@@ -231,8 +259,6 @@
_process_completed_buffers_threshold(ProcessCompletedBuffersThresholdNever),
_process_completed_buffers(false),
_notify_when_complete(notify_when_complete),
- _max_completed_buffers(MaxCompletedBuffersUnlimited),
- _completed_buffers_padding(0),
_all_active(false)
{}
@@ -258,52 +284,6 @@
_allocator->release(node);
}
-void PtrQueue::handle_zero_index() {
- assert(index() == 0, "precondition");
-
- // This thread records the full buffer and allocates a new one (while
- // holding the lock if there is one).
- if (_buf != NULL) {
- if (!should_enqueue_buffer()) {
- assert(index() > 0, "the buffer can only be re-used if it's not full");
- return;
- }
-
- BufferNode* node = BufferNode::make_node_from_buffer(_buf, index());
- if (qset()->process_or_enqueue_completed_buffer(node)) {
- // Recycle the buffer. No allocation.
- assert(_buf == BufferNode::make_buffer_from_node(node), "invariant");
- assert(capacity() == qset()->buffer_size(), "invariant");
- reset();
- return;
- }
- }
- // Set capacity in case this is the first allocation.
- set_capacity(qset()->buffer_size());
- // Allocate a new buffer.
- _buf = qset()->allocate_buffer();
- reset();
-}
-
-bool PtrQueueSet::process_or_enqueue_completed_buffer(BufferNode* node) {
- if (Thread::current()->is_Java_thread()) {
- // If the number of buffers exceeds the limit, make this Java
- // thread do the processing itself. We don't lock to access
- // buffer count or padding; it is fine to be imprecise here. The
- // add of padding could overflow, which is treated as unlimited.
- size_t limit = _max_completed_buffers + _completed_buffers_padding;
- if ((_n_completed_buffers > limit) && (limit >= _max_completed_buffers)) {
- if (mut_process_buffer(node)) {
- // Successfully processed; return true to allow buffer reuse.
- return true;
- }
- }
- }
- // The buffer will be enqueued. The caller will have to get a new one.
- enqueue_completed_buffer(node);
- return false;
-}
-
void PtrQueueSet::enqueue_completed_buffer(BufferNode* cbn) {
MutexLocker x(_cbl_mon, Mutex::_no_safepoint_check_flag);
cbn->set_next(NULL);
--- a/src/hotspot/share/gc/shared/ptrQueue.hpp Fri May 17 13:21:44 2019 +0100
+++ b/src/hotspot/share/gc/shared/ptrQueue.hpp Thu May 23 11:07:37 2019 +0100
@@ -71,14 +71,6 @@
return _capacity_in_bytes;
}
- void set_capacity(size_t entries) {
- size_t byte_capacity = index_to_byte_index(entries);
- assert(_capacity_in_bytes == 0 || _capacity_in_bytes == byte_capacity,
- "changing capacity " SIZE_FORMAT " -> " SIZE_FORMAT,
- _capacity_in_bytes, byte_capacity);
- _capacity_in_bytes = byte_capacity;
- }
-
static size_t byte_index_to_index(size_t ind) {
assert(is_aligned(ind, _element_size), "precondition");
return ind / _element_size;
@@ -106,11 +98,20 @@
return byte_index_to_index(capacity_in_bytes());
}
- PtrQueueSet* qset() { return _qset; }
+ PtrQueueSet* qset() const { return _qset; }
// Process queue entries and release resources.
void flush_impl();
+ // Process (some of) the buffer and leave it in place for further use,
+ // or enqueue the buffer and allocate a new one.
+ virtual void handle_completed_buffer() = 0;
+
+ void allocate_buffer();
+
+ // Enqueue the current buffer in the qset and allocate a new buffer.
+ void enqueue_completed_buffer();
+
// Initialize this queue to contain a null buffer, and be part of the
// given PtrQueueSet.
PtrQueue(PtrQueueSet* qset, bool active = false);
@@ -137,14 +138,6 @@
else enqueue_known_active(ptr);
}
- // This method is called when we're doing the zero index handling
- // and gives a chance to the queues to do any pre-enqueueing
- // processing they might want to do on the buffer. It should return
- // true if the buffer should be enqueued, or false if enough
- // entries were cleared from it so that it can be re-used. It should
- // not return false if the buffer is still full (otherwise we can
- // get into an infinite loop).
- virtual bool should_enqueue_buffer() { return true; }
void handle_zero_index();
void enqueue_known_active(void* ptr);
@@ -306,7 +299,7 @@
Monitor* _cbl_mon; // Protects the fields below.
BufferNode* _completed_buffers_head;
BufferNode* _completed_buffers_tail;
- size_t _n_completed_buffers;
+ volatile size_t _n_completed_buffers;
size_t _process_completed_buffers_threshold;
volatile bool _process_completed_buffers;
@@ -314,24 +307,11 @@
// If true, notify_all on _cbl_mon when the threshold is reached.
bool _notify_when_complete;
- // Maximum number of elements allowed on completed queue: after that,
- // enqueuer does the work itself.
- size_t _max_completed_buffers;
- size_t _completed_buffers_padding;
-
void assert_completed_buffers_list_len_correct_locked() NOT_DEBUG_RETURN;
protected:
bool _all_active;
- // A mutator thread does the the work of processing a buffer.
- // Returns "true" iff the work is complete (and the buffer may be
- // deallocated).
- virtual bool mut_process_buffer(BufferNode* node) {
- ShouldNotReachHere();
- return false;
- }
-
// Create an empty ptr queue set.
PtrQueueSet(bool notify_when_complete = false);
~PtrQueueSet();
@@ -365,9 +345,6 @@
// return a completed buffer from the list. Otherwise, return NULL.
BufferNode* get_completed_buffer(size_t stop_at = 0);
- // To be invoked by the mutator.
- bool process_or_enqueue_completed_buffer(BufferNode* node);
-
bool process_completed_buffers() { return _process_completed_buffers; }
void set_process_completed_buffers(bool x) { _process_completed_buffers = x; }
@@ -392,21 +369,6 @@
void merge_bufferlists(PtrQueueSet* src);
- void set_max_completed_buffers(size_t m) {
- _max_completed_buffers = m;
- }
- size_t max_completed_buffers() const {
- return _max_completed_buffers;
- }
- static const size_t MaxCompletedBuffersUnlimited = ~size_t(0);
-
- void set_completed_buffers_padding(size_t padding) {
- _completed_buffers_padding = padding;
- }
- size_t completed_buffers_padding() const {
- return _completed_buffers_padding;
- }
-
// Notify the consumer if the number of buffers crossed the threshold
void notify_if_necessary();
};
--- a/src/hotspot/share/gc/shared/satbMarkQueue.cpp Fri May 17 13:21:44 2019 +0100
+++ b/src/hotspot/share/gc/shared/satbMarkQueue.cpp Thu May 23 11:07:37 2019 +0100
@@ -56,7 +56,7 @@
// retains a small enough collection in the buffer, we can continue to
// use the buffer as-is, instead of enqueueing and replacing it.
-bool SATBMarkQueue::should_enqueue_buffer() {
+void SATBMarkQueue::handle_completed_buffer() {
// This method should only be called if there is a non-NULL buffer
// that is full.
assert(index() == 0, "pre-condition");
@@ -64,15 +64,18 @@
filter();
- SATBMarkQueueSet* satb_qset = static_cast<SATBMarkQueueSet*>(qset());
- size_t threshold = satb_qset->buffer_enqueue_threshold();
+ size_t threshold = satb_qset()->buffer_enqueue_threshold();
// Ensure we'll enqueue completely full buffers.
assert(threshold > 0, "enqueue threshold = 0");
// Ensure we won't enqueue empty buffers.
assert(threshold <= capacity(),
"enqueue threshold " SIZE_FORMAT " exceeds capacity " SIZE_FORMAT,
threshold, capacity());
- return index() < threshold;
+
+ if (index() < threshold) {
+ // Buffer is sufficiently full; enqueue and allocate a new one.
+ enqueue_completed_buffer();
+ } // Else continue to accumulate in buffer.
}
void SATBMarkQueue::apply_closure_and_empty(SATBBufferClosure* cl) {
--- a/src/hotspot/share/gc/shared/satbMarkQueue.hpp Fri May 17 13:21:44 2019 +0100
+++ b/src/hotspot/share/gc/shared/satbMarkQueue.hpp Thu May 23 11:07:37 2019 +0100
@@ -54,20 +54,21 @@
template<typename Filter>
inline void apply_filter(Filter filter_out);
+protected:
+ virtual void handle_completed_buffer();
+
public:
SATBMarkQueue(SATBMarkQueueSet* qset);
// Process queue entries and free resources.
void flush();
+ inline SATBMarkQueueSet* satb_qset() const;
+
// Apply cl to the active part of the buffer.
// Prerequisite: Must be at a safepoint.
void apply_closure_and_empty(SATBBufferClosure* cl);
- // Overrides PtrQueue::should_enqueue_buffer(). See the method's
- // definition for more information.
- virtual bool should_enqueue_buffer();
-
#ifndef PRODUCT
// Helpful for debugging
void print(const char* name);
@@ -140,8 +141,12 @@
void abandon_partial_marking();
};
+inline SATBMarkQueueSet* SATBMarkQueue::satb_qset() const {
+ return static_cast<SATBMarkQueueSet*>(qset());
+}
+
inline void SATBMarkQueue::filter() {
- static_cast<SATBMarkQueueSet*>(qset())->filter(this);
+ satb_qset()->filter(this);
}
// Removes entries from the buffer that are no longer needed, as
--- a/src/hotspot/share/gc/shenandoah/shenandoahConcurrentMark.cpp Fri May 17 13:21:44 2019 +0100
+++ b/src/hotspot/share/gc/shenandoah/shenandoahConcurrentMark.cpp Thu May 23 11:07:37 2019 +0100
@@ -81,10 +81,10 @@
template<UpdateRefsMode UPDATE_REFS>
class ShenandoahInitMarkRootsTask : public AbstractGangTask {
private:
- ShenandoahRootProcessor* _rp;
+ ShenandoahAllRootScanner* _rp;
bool _process_refs;
public:
- ShenandoahInitMarkRootsTask(ShenandoahRootProcessor* rp, bool process_refs) :
+ ShenandoahInitMarkRootsTask(ShenandoahAllRootScanner* rp, bool process_refs) :
AbstractGangTask("Shenandoah init mark roots task"),
_rp(rp),
_process_refs(process_refs) {
@@ -115,45 +115,21 @@
// cache, because there could be the case of embedded class/oop in the generated code,
// which we will never visit during mark. Without code cache invalidation, as in (a),
// we risk executing that code cache blob, and crashing.
- // c. With ShenandoahConcurrentScanCodeRoots, we avoid scanning the entire code cache here,
- // and instead do that in concurrent phase under the relevant lock. This saves init mark
- // pause time.
-
- CLDToOopClosure clds_cl(oops, ClassLoaderData::_claim_strong);
- MarkingCodeBlobClosure blobs_cl(oops, ! CodeBlobToOopClosure::FixRelocations);
-
- ResourceMark m;
if (heap->unload_classes()) {
- _rp->process_strong_roots(oops, &clds_cl, &blobs_cl, NULL, worker_id);
+ _rp->strong_roots_do(worker_id, oops);
} else {
- if (ShenandoahConcurrentScanCodeRoots) {
- CodeBlobClosure* code_blobs = NULL;
-#ifdef ASSERT
- ShenandoahAssertToSpaceClosure assert_to_space_oops;
- CodeBlobToOopClosure assert_to_space(&assert_to_space_oops, !CodeBlobToOopClosure::FixRelocations);
- // If conc code cache evac is disabled, code cache should have only to-space ptrs.
- // Otherwise, it should have to-space ptrs only if mark does not update refs.
- if (!heap->has_forwarded_objects()) {
- code_blobs = &assert_to_space;
- }
-#endif
- _rp->process_all_roots(oops, &clds_cl, code_blobs, NULL, worker_id);
- } else {
- _rp->process_all_roots(oops, &clds_cl, &blobs_cl, NULL, worker_id);
- }
+ _rp->roots_do(worker_id, oops);
}
}
};
class ShenandoahUpdateRootsTask : public AbstractGangTask {
private:
- ShenandoahRootProcessor* _rp;
- const bool _update_code_cache;
+ ShenandoahRootUpdater* _root_updater;
public:
- ShenandoahUpdateRootsTask(ShenandoahRootProcessor* rp, bool update_code_cache) :
+ ShenandoahUpdateRootsTask(ShenandoahRootUpdater* root_updater) :
AbstractGangTask("Shenandoah update roots task"),
- _rp(rp),
- _update_code_cache(update_code_cache) {
+ _root_updater(root_updater) {
}
void work(uint worker_id) {
@@ -162,22 +138,8 @@
ShenandoahHeap* heap = ShenandoahHeap::heap();
ShenandoahUpdateRefsClosure cl;
- CLDToOopClosure cldCl(&cl, ClassLoaderData::_claim_strong);
-
- CodeBlobClosure* code_blobs;
- CodeBlobToOopClosure update_blobs(&cl, CodeBlobToOopClosure::FixRelocations);
-#ifdef ASSERT
- ShenandoahAssertToSpaceClosure assert_to_space_oops;
- CodeBlobToOopClosure assert_to_space(&assert_to_space_oops, !CodeBlobToOopClosure::FixRelocations);
-#endif
- if (_update_code_cache) {
- code_blobs = &update_blobs;
- } else {
- code_blobs =
- DEBUG_ONLY(&assert_to_space)
- NOT_DEBUG(NULL);
- }
- _rp->update_all_roots<AlwaysTrueClosure>(&cl, &cldCl, code_blobs, NULL, worker_id);
+ AlwaysTrueClosure always_true;
+ _root_updater->roots_do<AlwaysTrueClosure, ShenandoahUpdateRefsClosure>(worker_id, &always_true, &cl);
}
};
@@ -265,9 +227,12 @@
rp = NULL;
}
- // Degenerated cycle may bypass concurrent cycle, so code roots might not be scanned,
- // let's check here.
- _cm->concurrent_scan_code_roots(worker_id, rp);
+ if (heap->is_degenerated_gc_in_progress()) {
+ // Degenerated cycle may bypass concurrent cycle, so code roots might not be scanned,
+ // let's check here.
+ _cm->concurrent_scan_code_roots(worker_id, rp);
+ }
+
_cm->mark_loop(worker_id, _terminator, rp,
false, // not cancellable
_dedup_string);
@@ -289,7 +254,7 @@
assert(nworkers <= task_queues()->size(), "Just check");
- ShenandoahRootProcessor root_proc(heap, nworkers, root_phase);
+ ShenandoahAllRootScanner root_proc(nworkers, root_phase);
TASKQUEUE_STATS_ONLY(task_queues()->reset_taskqueue_stats());
task_queues()->reserve(nworkers);
@@ -333,8 +298,8 @@
uint nworkers = _heap->workers()->active_workers();
- ShenandoahRootProcessor root_proc(_heap, nworkers, root_phase);
- ShenandoahUpdateRootsTask update_roots(&root_proc, update_code_cache);
+ ShenandoahRootUpdater root_updater(nworkers, root_phase, update_code_cache);
+ ShenandoahUpdateRootsTask update_roots(&root_updater);
_heap->workers()->run_task(&update_roots);
#if defined(COMPILER2) || INCLUDE_JVMCI
@@ -342,6 +307,34 @@
#endif
}
+class ShenandoahUpdateThreadRootsTask : public AbstractGangTask {
+private:
+ ShenandoahThreadRoots _thread_roots;
+ ShenandoahPhaseTimings::Phase _phase;
+public:
+ ShenandoahUpdateThreadRootsTask(bool is_par, ShenandoahPhaseTimings::Phase phase) :
+ AbstractGangTask("Shenandoah Update Thread Roots"),
+ _thread_roots(is_par),
+ _phase(phase) {
+ ShenandoahHeap::heap()->phase_timings()->record_workers_start(_phase);
+ }
+
+ ~ShenandoahUpdateThreadRootsTask() {
+ ShenandoahHeap::heap()->phase_timings()->record_workers_end(_phase);
+ }
+ void work(uint worker_id) {
+ ShenandoahUpdateRefsClosure cl;
+ _thread_roots.oops_do(&cl, NULL, worker_id);
+ }
+};
+
+void ShenandoahConcurrentMark::update_thread_roots(ShenandoahPhaseTimings::Phase root_phase) {
+ WorkGang* workers = _heap->workers();
+ bool is_par = workers->active_workers() > 1;
+ ShenandoahUpdateThreadRootsTask task(is_par, root_phase);
+ workers->run_task(&task);
+}
+
void ShenandoahConcurrentMark::initialize(uint workers) {
_heap = ShenandoahHeap::heap();
--- a/src/hotspot/share/gc/shenandoah/shenandoahConcurrentMark.hpp Fri May 17 13:21:44 2019 +0100
+++ b/src/hotspot/share/gc/shenandoah/shenandoahConcurrentMark.hpp Thu May 23 11:07:37 2019 +0100
@@ -79,6 +79,7 @@
void mark_roots(ShenandoahPhaseTimings::Phase root_phase);
void update_roots(ShenandoahPhaseTimings::Phase root_phase);
+ void update_thread_roots(ShenandoahPhaseTimings::Phase root_phase);
// ---------- Weak references
//
--- a/src/hotspot/share/gc/shenandoah/shenandoahHeap.cpp Fri May 17 13:21:44 2019 +0100
+++ b/src/hotspot/share/gc/shenandoah/shenandoahHeap.cpp Thu May 23 11:07:37 2019 +0100
@@ -52,7 +52,7 @@
#include "gc/shenandoah/shenandoahMonitoringSupport.hpp"
#include "gc/shenandoah/shenandoahOopClosures.inline.hpp"
#include "gc/shenandoah/shenandoahPacer.inline.hpp"
-#include "gc/shenandoah/shenandoahRootProcessor.hpp"
+#include "gc/shenandoah/shenandoahRootProcessor.inline.hpp"
#include "gc/shenandoah/shenandoahStringDedup.hpp"
#include "gc/shenandoah/shenandoahTaskqueue.hpp"
#include "gc/shenandoah/shenandoahUtils.hpp"
@@ -67,6 +67,10 @@
#include "gc/shenandoah/heuristics/shenandoahPassiveHeuristics.hpp"
#include "gc/shenandoah/heuristics/shenandoahStaticHeuristics.hpp"
#include "gc/shenandoah/heuristics/shenandoahTraversalHeuristics.hpp"
+#if INCLUDE_JFR
+#include "gc/shenandoah/shenandoahJfrSupport.hpp"
+#endif
+
#include "memory/metaspace.hpp"
#include "oops/compressedOops.inline.hpp"
#include "runtime/globals.hpp"
@@ -596,6 +600,8 @@
ref_processing_init();
_heuristics->initialize();
+
+ JFR_ONLY(ShenandoahJFRSupport::register_jfr_type_serializers());
}
size_t ShenandoahHeap::used() const {
@@ -1111,7 +1117,7 @@
ShenandoahEvacOOMScope oom_evac_scope;
ShenandoahEvacuateUpdateRootsClosure cl;
MarkingCodeBlobClosure blobsCl(&cl, CodeBlobToOopClosure::FixRelocations);
- _rp->process_evacuate_roots(&cl, &blobsCl, worker_id);
+ _rp->roots_do(worker_id, &cl);
}
};
@@ -1122,7 +1128,7 @@
assert(ShenandoahSafepoint::is_at_shenandoah_safepoint(), "Only iterate roots while world is stopped");
{
- ShenandoahRootEvacuator rp(this, workers()->active_workers(), ShenandoahPhaseTimings::init_evac);
+ ShenandoahRootEvacuator rp(workers()->active_workers(), ShenandoahPhaseTimings::init_evac);
ShenandoahEvacuateUpdateRootsTask roots_task(&rp);
workers()->run_task(&roots_task);
}
@@ -1326,11 +1332,9 @@
Stack<oop,mtGC> oop_stack;
// First, we process all GC roots. This populates the work stack with initial objects.
- ShenandoahRootProcessor rp(this, 1, ShenandoahPhaseTimings::_num_phases);
+ ShenandoahAllRootScanner rp(1, ShenandoahPhaseTimings::_num_phases);
ObjectIterateScanRootClosure oops(&_aux_bit_map, &oop_stack);
- CLDToOopClosure clds(&oops, ClassLoaderData::_claim_none);
- CodeBlobToOopClosure blobs(&oops, false);
- rp.process_all_roots(&oops, &clds, &blobs, NULL, 0);
+ rp.roots_do(0, &oops);
// Work through the oop stack to traverse heap.
while (! oop_stack.is_empty()) {
@@ -1501,10 +1505,14 @@
if (!cancelled_gc()) {
concurrent_mark()->finish_mark_from_roots(/* full_gc = */ false);
- // Degen may be caused by failed evacuation of roots
- if (is_degenerated_gc_in_progress() && has_forwarded_objects()) {
- concurrent_mark()->update_roots(ShenandoahPhaseTimings::degen_gc_update_roots);
- }
+ if (has_forwarded_objects()) {
+ // Degen may be caused by failed evacuation of roots
+ if (is_degenerated_gc_in_progress()) {
+ concurrent_mark()->update_roots(ShenandoahPhaseTimings::degen_gc_update_roots);
+ } else {
+ concurrent_mark()->update_thread_roots(ShenandoahPhaseTimings::update_roots);
+ }
+ }
if (ShenandoahVerify) {
verifier()->verify_roots_no_forwarded();
@@ -2202,9 +2210,11 @@
verifier()->verify_roots_no_forwarded_except(ShenandoahRootVerifier::ThreadRoots);
}
- concurrent_mark()->update_roots(is_degenerated_gc_in_progress() ?
- ShenandoahPhaseTimings::degen_gc_update_roots:
- ShenandoahPhaseTimings::final_update_refs_roots);
+ if (is_degenerated_gc_in_progress()) {
+ concurrent_mark()->update_roots(ShenandoahPhaseTimings::degen_gc_update_roots);
+ } else {
+ concurrent_mark()->update_thread_roots(ShenandoahPhaseTimings::final_update_refs_roots);
+ }
ShenandoahGCPhase final_update_refs(ShenandoahPhaseTimings::final_update_refs_recycle);
--- a/src/hotspot/share/gc/shenandoah/shenandoahHeap.hpp Fri May 17 13:21:44 2019 +0100
+++ b/src/hotspot/share/gc/shenandoah/shenandoahHeap.hpp Thu May 23 11:07:37 2019 +0100
@@ -40,6 +40,7 @@
class ShenandoahCollectorPolicy;
class ShenandoahControlThread;
class ShenandoahGCSession;
+class ShenandoahGCStateResetter;
class ShenandoahHeuristics;
class ShenandoahMarkingContext;
class ShenandoahPhaseTimings;
@@ -111,6 +112,7 @@
friend class ShenandoahAsserts;
friend class VMStructs;
friend class ShenandoahGCSession;
+ friend class ShenandoahGCStateResetter;
// ---------- Locks that guard important data structures in Heap
//
--- a/src/hotspot/share/gc/shenandoah/shenandoahHeapRegion.cpp Fri May 17 13:21:44 2019 +0100
+++ b/src/hotspot/share/gc/shenandoah/shenandoahHeapRegion.cpp Thu May 23 11:07:37 2019 +0100
@@ -30,6 +30,7 @@
#include "gc/shenandoah/shenandoahMarkingContext.inline.hpp"
#include "gc/shenandoah/shenandoahTraversalGC.hpp"
#include "gc/shared/space.inline.hpp"
+#include "jfr/jfrEvents.hpp"
#include "memory/iterator.inline.hpp"
#include "memory/resourceArea.hpp"
#include "memory/universe.hpp"
@@ -93,7 +94,7 @@
case _empty_uncommitted:
do_commit();
case _empty_committed:
- _state = _regular;
+ set_state(_regular);
case _regular:
case _pinned:
return;
@@ -114,10 +115,10 @@
case _cset:
case _humongous_start:
case _humongous_cont:
- _state = _regular;
+ set_state(_regular);
return;
case _pinned_cset:
- _state = _pinned;
+ set_state(_pinned);
return;
case _regular:
case _pinned:
@@ -133,7 +134,7 @@
case _empty_uncommitted:
do_commit();
case _empty_committed:
- _state = _humongous_start;
+ set_state(_humongous_start);
return;
default:
report_illegal_transition("humongous start allocation");
@@ -149,7 +150,7 @@
case _regular:
case _humongous_start:
case _humongous_cont:
- _state = _humongous_start;
+ set_state(_humongous_start);
return;
default:
report_illegal_transition("humongous start bypass");
@@ -162,7 +163,7 @@
case _empty_uncommitted:
do_commit();
case _empty_committed:
- _state = _humongous_cont;
+ set_state(_humongous_cont);
return;
default:
report_illegal_transition("humongous continuation allocation");
@@ -178,7 +179,7 @@
case _regular:
case _humongous_start:
case _humongous_cont:
- _state = _humongous_cont;
+ set_state(_humongous_cont);
return;
default:
report_illegal_transition("humongous continuation bypass");
@@ -190,14 +191,14 @@
switch (_state) {
case _regular:
assert (_critical_pins == 0, "sanity");
- _state = _pinned;
+ set_state(_pinned);
case _pinned_cset:
case _pinned:
_critical_pins++;
return;
case _humongous_start:
assert (_critical_pins == 0, "sanity");
- _state = _pinned_humongous_start;
+ set_state(_pinned_humongous_start);
case _pinned_humongous_start:
_critical_pins++;
return;
@@ -219,7 +220,7 @@
assert (_critical_pins > 0, "sanity");
_critical_pins--;
if (_critical_pins == 0) {
- _state = _regular;
+ set_state(_regular);
}
return;
case _regular:
@@ -231,14 +232,14 @@
assert (_critical_pins > 0, "sanity");
_critical_pins--;
if (_critical_pins == 0) {
- _state = _cset;
+ set_state(_cset);
}
return;
case _pinned_humongous_start:
assert (_critical_pins > 0, "sanity");
_critical_pins--;
if (_critical_pins == 0) {
- _state = _humongous_start;
+ set_state(_humongous_start);
}
return;
default:
@@ -250,7 +251,7 @@
_heap->assert_heaplock_owned_by_current_thread();
switch (_state) {
case _regular:
- _state = _cset;
+ set_state(_cset);
case _cset:
return;
default:
@@ -268,7 +269,7 @@
// Reclaiming humongous regions
case _regular:
// Immediate region reclaim
- _state = _trash;
+ set_state(_trash);
return;
default:
report_illegal_transition("trashing");
@@ -287,7 +288,7 @@
_heap->assert_heaplock_owned_by_current_thread();
switch (_state) {
case _trash:
- _state = _empty_committed;
+ set_state(_empty_committed);
_empty_time = os::elapsedTime();
return;
default:
@@ -300,7 +301,7 @@
switch (_state) {
case _empty_committed:
do_uncommit();
- _state = _empty_uncommitted;
+ set_state(_empty_uncommitted);
return;
default:
report_illegal_transition("uncommiting");
@@ -314,7 +315,7 @@
switch (_state) {
case _empty_uncommitted:
do_commit();
- _state = _empty_committed;
+ set_state(_empty_committed);
return;
default:
report_illegal_transition("commit bypass");
@@ -679,3 +680,16 @@
}
_heap->decrease_committed(ShenandoahHeapRegion::region_size_bytes());
}
+
+void ShenandoahHeapRegion::set_state(RegionState to) {
+ EventShenandoahHeapRegionStateChange evt;
+ if (evt.should_commit()){
+ evt.set_index((unsigned)region_number());
+ evt.set_start((uintptr_t)bottom());
+ evt.set_used(used());
+ evt.set_from(_state);
+ evt.set_to(to);
+ evt.commit();
+ }
+ _state = to;
+}
--- a/src/hotspot/share/gc/shenandoah/shenandoahHeapRegion.hpp Fri May 17 13:21:44 2019 +0100
+++ b/src/hotspot/share/gc/shenandoah/shenandoahHeapRegion.hpp Thu May 23 11:07:37 2019 +0100
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2013, 2018, Red Hat, Inc. All rights reserved.
+ * Copyright (c) 2013, 2019, Red Hat, Inc. All rights reserved.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
@@ -32,9 +32,11 @@
#include "utilities/sizes.hpp"
class VMStructs;
+class ShenandoahHeapRegionStateConstant;
class ShenandoahHeapRegion : public ContiguousSpace {
friend class VMStructs;
+ friend class ShenandoahHeapRegionStateConstant;
private:
/*
Region state is described by a state machine. Transitions are guarded by
@@ -114,10 +116,11 @@
_cset, // region is in collection set
_pinned, // region is pinned
_pinned_cset, // region is pinned and in cset (evac failure path)
- _trash // region contains only trash
+ _trash, // region contains only trash
+ _REGION_STATES_NUM // last
};
- const char* region_state_to_string(RegionState s) const {
+ static const char* region_state_to_string(RegionState s) {
switch (s) {
case _empty_uncommitted: return "Empty Uncommitted";
case _empty_committed: return "Empty Committed";
@@ -157,6 +160,10 @@
void report_illegal_transition(const char* method);
public:
+ static const int region_states_num() {
+ return _REGION_STATES_NUM;
+ }
+
// Allowed transitions from the outside code:
void make_regular_allocation();
void make_regular_bypass();
@@ -424,6 +431,8 @@
void oop_iterate_humongous(OopIterateClosure* cl);
inline void internal_increase_live_data(size_t s);
+
+ void set_state(RegionState to);
};
#endif // SHARE_GC_SHENANDOAH_SHENANDOAHHEAPREGION_HPP
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/hotspot/share/gc/shenandoah/shenandoahJfrSupport.cpp Thu May 23 11:07:37 2019 +0100
@@ -0,0 +1,71 @@
+/*
+ * Copyright (c) 2019, Red Hat, Inc. All rights reserved.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#include "precompiled.hpp"
+#include "gc/shenandoah/shenandoahHeap.hpp"
+#include "gc/shenandoah/shenandoahHeapRegion.hpp"
+#include "gc/shenandoah/shenandoahJfrSupport.hpp"
+#include "jfr/jfrEvents.hpp"
+#if INCLUDE_JFR
+#include "jfr/metadata/jfrSerializer.hpp"
+#endif
+
+#if INCLUDE_JFR
+
+class ShenandoahHeapRegionStateConstant : public JfrSerializer {
+ friend class ShenandoahHeapRegion;
+public:
+ virtual void serialize(JfrCheckpointWriter& writer) {
+ static const u4 nof_entries = ShenandoahHeapRegion::region_states_num();
+ writer.write_count(nof_entries);
+ for (u4 i = 0; i < nof_entries; ++i) {
+ writer.write_key(i);
+ writer.write(ShenandoahHeapRegion::region_state_to_string((ShenandoahHeapRegion::RegionState)i));
+ }
+ }
+};
+
+void ShenandoahJFRSupport::register_jfr_type_serializers() {
+ JfrSerializer::register_serializer(TYPE_SHENANDOAHHEAPREGIONSTATE,
+ false,
+ true,
+ new ShenandoahHeapRegionStateConstant());
+}
+#endif
+
+class ShenandoahDumpHeapRegionInfoClosure : public ShenandoahHeapRegionClosure {
+public:
+ virtual void heap_region_do(ShenandoahHeapRegion* r) {
+ EventShenandoahHeapRegionInformation evt;
+ evt.set_index((unsigned)r->region_number());
+ evt.set_state((u8)r->state());
+ evt.set_start((uintptr_t)r->bottom());
+ evt.set_used(r->used());
+ evt.commit();
+ }
+};
+
+void VM_ShenandoahSendHeapRegionInfoEvents::doit() {
+ ShenandoahDumpHeapRegionInfoClosure c;
+ ShenandoahHeap::heap()->heap_region_iterate(&c);
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/hotspot/share/gc/shenandoah/shenandoahJfrSupport.hpp Thu May 23 11:07:37 2019 +0100
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2019, Red Hat, Inc. All rights reserved.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#ifndef SHARE_GC_SHENANDOAH_SHENANDOAHJFRSUPPORT_HPP
+#define SHARE_GC_SHENANDOAH_SHENANDOAHJFRSUPPORT_HPP
+
+#include "runtime/vmOperations.hpp"
+
+class VM_ShenandoahSendHeapRegionInfoEvents : public VM_Operation {
+public:
+ virtual void doit();
+ virtual VMOp_Type type() const { return VMOp_HeapIterateOperation; }
+};
+
+class ShenandoahJFRSupport {
+public:
+ static void register_jfr_type_serializers();
+};
+
+#endif // SHARE_VM_GC_SHENANDOAH_SHENANDOAHJFRSUPPORT_HPP
--- a/src/hotspot/share/gc/shenandoah/shenandoahMarkCompact.cpp Fri May 17 13:21:44 2019 +0100
+++ b/src/hotspot/share/gc/shenandoah/shenandoahMarkCompact.cpp Thu May 23 11:07:37 2019 +0100
@@ -561,22 +561,16 @@
class ShenandoahAdjustRootPointersTask : public AbstractGangTask {
private:
- ShenandoahRootProcessor* _rp;
+ ShenandoahRootAdjuster* _rp;
public:
- ShenandoahAdjustRootPointersTask(ShenandoahRootProcessor* rp) :
+ ShenandoahAdjustRootPointersTask(ShenandoahRootAdjuster* rp) :
AbstractGangTask("Shenandoah Adjust Root Pointers Task"),
_rp(rp) {}
void work(uint worker_id) {
ShenandoahAdjustPointersClosure cl;
- CLDToOopClosure adjust_cld_closure(&cl, ClassLoaderData::_claim_strong);
- MarkingCodeBlobClosure adjust_code_closure(&cl,
- CodeBlobToOopClosure::FixRelocations);
-
- _rp->update_all_roots<AlwaysTrueClosure>(&cl,
- &adjust_cld_closure,
- &adjust_code_closure, NULL, worker_id);
+ _rp->roots_do(worker_id, &cl);
}
};
@@ -592,7 +586,7 @@
#if COMPILER2_OR_JVMCI
DerivedPointerTable::clear();
#endif
- ShenandoahRootProcessor rp(heap, nworkers, ShenandoahPhaseTimings::full_gc_roots);
+ ShenandoahRootAdjuster rp(nworkers, ShenandoahPhaseTimings::full_gc_roots);
ShenandoahAdjustRootPointersTask task(&rp);
workers->run_task(&task);
#if COMPILER2_OR_JVMCI
--- a/src/hotspot/share/gc/shenandoah/shenandoahRootProcessor.cpp Fri May 17 13:21:44 2019 +0100
+++ b/src/hotspot/share/gc/shenandoah/shenandoahRootProcessor.cpp Thu May 23 11:07:37 2019 +0100
@@ -28,8 +28,9 @@
#include "classfile/systemDictionary.hpp"
#include "code/codeCache.hpp"
#include "gc/shenandoah/shenandoahClosures.inline.hpp"
-#include "gc/shenandoah/shenandoahRootProcessor.hpp"
+#include "gc/shenandoah/shenandoahRootProcessor.inline.hpp"
#include "gc/shenandoah/shenandoahHeap.hpp"
+#include "gc/shenandoah/shenandoahHeuristics.hpp"
#include "gc/shenandoah/shenandoahPhaseTimings.hpp"
#include "gc/shenandoah/shenandoahStringDedup.hpp"
#include "gc/shenandoah/shenandoahTimingTracker.hpp"
@@ -43,248 +44,157 @@
#include "runtime/thread.hpp"
#include "services/management.hpp"
-ShenandoahRootProcessor::ShenandoahRootProcessor(ShenandoahHeap* heap, uint n_workers,
- ShenandoahPhaseTimings::Phase phase) :
- _process_strong_tasks(new SubTasksDone(SHENANDOAH_RP_PS_NumElements)),
- _srs(n_workers),
- _phase(phase),
- _coderoots_all_iterator(ShenandoahCodeRoots::iterator()),
- _weak_processor_timings(n_workers),
- _weak_processor_task(&_weak_processor_timings, n_workers),
- _processed_weak_roots(false) {
- heap->phase_timings()->record_workers_start(_phase);
+ShenandoahSerialRoot::ShenandoahSerialRoot(ShenandoahSerialRoot::OopsDo oops_do, ShenandoahPhaseTimings::GCParPhases phase) :
+ _claimed(false), _oops_do(oops_do), _phase(phase) {
+}
+
+void ShenandoahSerialRoot::oops_do(OopClosure* cl, uint worker_id) {
+ if (!_claimed && Atomic::cmpxchg(true, &_claimed, false) == false) {
+ ShenandoahWorkerTimings* worker_times = ShenandoahHeap::heap()->phase_timings()->worker_times();
+ ShenandoahWorkerTimingsTracker timer(worker_times, _phase, worker_id);
+ _oops_do(cl);
+ }
+}
+
+ShenandoahSerialRoots::ShenandoahSerialRoots() :
+ _universe_root(&Universe::oops_do, ShenandoahPhaseTimings::UniverseRoots),
+ _object_synchronizer_root(&ObjectSynchronizer::oops_do, ShenandoahPhaseTimings::ObjectSynchronizerRoots),
+ _management_root(&Management::oops_do, ShenandoahPhaseTimings::ManagementRoots),
+ _system_dictionary_root(&SystemDictionary::oops_do, ShenandoahPhaseTimings::SystemDictionaryRoots),
+ _jvmti_root(&JvmtiExport::oops_do, ShenandoahPhaseTimings::JVMTIRoots),
+ _jni_handle_root(&JNIHandles::oops_do, ShenandoahPhaseTimings::JNIRoots) {
+}
+
+void ShenandoahSerialRoots::oops_do(OopClosure* cl, uint worker_id) {
+ _universe_root.oops_do(cl, worker_id);
+ _object_synchronizer_root.oops_do(cl, worker_id);
+ _management_root.oops_do(cl, worker_id);
+ _system_dictionary_root.oops_do(cl, worker_id);
+ _jvmti_root.oops_do(cl, worker_id);
+ _jni_handle_root.oops_do(cl, worker_id);
+}
+ShenandoahThreadRoots::ShenandoahThreadRoots(bool is_par) : _is_par(is_par) {
+ Threads::change_thread_claim_token();
+}
+
+void ShenandoahThreadRoots::oops_do(OopClosure* oops_cl, CodeBlobClosure* code_cl, uint worker_id) {
+ ShenandoahWorkerTimings* worker_times = ShenandoahHeap::heap()->phase_timings()->worker_times();
+ ShenandoahWorkerTimingsTracker timer(worker_times, ShenandoahPhaseTimings::ThreadRoots, worker_id);
+ ResourceMark rm;
+ Threads::possibly_parallel_oops_do(_is_par, oops_cl, code_cl);
+}
+
+void ShenandoahThreadRoots::threads_do(ThreadClosure* tc, uint worker_id) {
+ ShenandoahWorkerTimings* worker_times = ShenandoahHeap::heap()->phase_timings()->worker_times();
+ ShenandoahWorkerTimingsTracker timer(worker_times, ShenandoahPhaseTimings::ThreadRoots, worker_id);
+ ResourceMark rm;
+ Threads::possibly_parallel_threads_do(_is_par, tc);
+}
+
+ShenandoahThreadRoots::~ShenandoahThreadRoots() {
+ Threads::assert_all_threads_claimed();
+}
+
+ShenandoahWeakRoots::ShenandoahWeakRoots(uint n_workers) :
+ _process_timings(n_workers),
+ _task(&_process_timings, n_workers) {
+}
+
+ShenandoahWeakRoots::~ShenandoahWeakRoots() {
+ ShenandoahWorkerTimings* worker_times = ShenandoahHeap::heap()->phase_timings()->worker_times();
+ ShenandoahTimingConverter::weak_processing_timing_to_shenandoah_timing(&_process_timings,
+ worker_times);
+}
+
+ShenandoahStringDedupRoots::ShenandoahStringDedupRoots() {
if (ShenandoahStringDedup::is_enabled()) {
StringDedup::gc_prologue(false);
}
}
-ShenandoahRootProcessor::~ShenandoahRootProcessor() {
- delete _process_strong_tasks;
+ShenandoahStringDedupRoots::~ShenandoahStringDedupRoots() {
if (ShenandoahStringDedup::is_enabled()) {
StringDedup::gc_epilogue();
}
-
- if (_processed_weak_roots) {
- assert(_weak_processor_timings.max_threads() == n_workers(), "Must match");
- ShenandoahWorkerTimings* worker_times = ShenandoahHeap::heap()->phase_timings()->worker_times();
- ShenandoahTimingConverter::weak_processing_timing_to_shenandoah_timing(&_weak_processor_timings,
- worker_times);
- }
-
- ShenandoahHeap::heap()->phase_timings()->record_workers_end(_phase);
-}
-
-void ShenandoahRootProcessor::process_strong_roots(OopClosure* oops,
- CLDClosure* clds,
- CodeBlobClosure* blobs,
- ThreadClosure* thread_cl,
- uint worker_id) {
-
- process_java_roots(oops, clds, NULL, blobs, thread_cl, worker_id);
- process_vm_roots(oops, worker_id);
-
- _process_strong_tasks->all_tasks_completed(n_workers());
}
-void ShenandoahRootProcessor::process_all_roots(OopClosure* oops,
- CLDClosure* clds,
- CodeBlobClosure* blobs,
- ThreadClosure* thread_cl,
- uint worker_id) {
-
- ShenandoahWorkerTimings* worker_times = ShenandoahHeap::heap()->phase_timings()->worker_times();
- process_java_roots(oops, clds, clds, blobs, thread_cl, worker_id);
- process_vm_roots(oops, worker_id);
-
- if (blobs != NULL) {
- ShenandoahWorkerTimingsTracker timer(worker_times, ShenandoahPhaseTimings::CodeCacheRoots, worker_id);
- _coderoots_all_iterator.possibly_parallel_blobs_do(blobs);
- }
-
- _process_strong_tasks->all_tasks_completed(n_workers());
-
-}
-
-class ShenandoahParallelOopsDoThreadClosure : public ThreadClosure {
-private:
- OopClosure* _f;
- CodeBlobClosure* _cf;
- ThreadClosure* _thread_cl;
-public:
- ShenandoahParallelOopsDoThreadClosure(OopClosure* f, CodeBlobClosure* cf, ThreadClosure* thread_cl) :
- _f(f), _cf(cf), _thread_cl(thread_cl) {}
-
- void do_thread(Thread* t) {
- if (_thread_cl != NULL) {
- _thread_cl->do_thread(t);
- }
- t->oops_do(_f, _cf);
- }
-};
-
-void ShenandoahRootProcessor::process_java_roots(OopClosure* strong_roots,
- CLDClosure* strong_clds,
- CLDClosure* weak_clds,
- CodeBlobClosure* strong_code,
- ThreadClosure* thread_cl,
- uint worker_id)
-{
- ShenandoahWorkerTimings* worker_times = ShenandoahHeap::heap()->phase_timings()->worker_times();
- // Iterating over the CLDG and the Threads are done early to allow us to
- // first process the strong CLDs and nmethods and then, after a barrier,
- // let the thread process the weak CLDs and nmethods.
- {
- ShenandoahWorkerTimingsTracker timer(worker_times, ShenandoahPhaseTimings::CLDGRoots, worker_id);
- _cld_iterator.root_cld_do(strong_clds, weak_clds);
- }
-
- {
- ShenandoahWorkerTimingsTracker timer(worker_times, ShenandoahPhaseTimings::ThreadRoots, worker_id);
- bool is_par = n_workers() > 1;
- ResourceMark rm;
- ShenandoahParallelOopsDoThreadClosure cl(strong_roots, strong_code, thread_cl);
- Threads::possibly_parallel_threads_do(is_par, &cl);
+void ShenandoahStringDedupRoots::oops_do(BoolObjectClosure* is_alive, OopClosure* keep_alive, uint worker_id) {
+ if (ShenandoahStringDedup::is_enabled()) {
+ ShenandoahStringDedup::parallel_oops_do(is_alive, keep_alive, worker_id);
}
}
-void ShenandoahRootProcessor::process_vm_roots(OopClosure* strong_roots,
- uint worker_id) {
- ShenandoahWorkerTimings* worker_times = ShenandoahHeap::heap()->phase_timings()->worker_times();
- if (_process_strong_tasks->try_claim_task(SHENANDOAH_RP_PS_Universe_oops_do)) {
- ShenandoahWorkerTimingsTracker timer(worker_times, ShenandoahPhaseTimings::UniverseRoots, worker_id);
- Universe::oops_do(strong_roots);
- }
-
- if (_process_strong_tasks->try_claim_task(SHENANDOAH_RP_PS_JNIHandles_oops_do)) {
- ShenandoahWorkerTimingsTracker timer(worker_times, ShenandoahPhaseTimings::JNIRoots, worker_id);
- JNIHandles::oops_do(strong_roots);
- }
- if (_process_strong_tasks->try_claim_task(SHENANDOAH_RP_PS_Management_oops_do)) {
- ShenandoahWorkerTimingsTracker timer(worker_times, ShenandoahPhaseTimings::ManagementRoots, worker_id);
- Management::oops_do(strong_roots);
- }
- if (_process_strong_tasks->try_claim_task(SHENANDOAH_RP_PS_jvmti_oops_do)) {
- ShenandoahWorkerTimingsTracker timer(worker_times, ShenandoahPhaseTimings::JVMTIRoots, worker_id);
- JvmtiExport::oops_do(strong_roots);
- }
- if (_process_strong_tasks->try_claim_task(SHENANDOAH_RP_PS_SystemDictionary_oops_do)) {
- ShenandoahWorkerTimingsTracker timer(worker_times, ShenandoahPhaseTimings::SystemDictionaryRoots, worker_id);
- SystemDictionary::oops_do(strong_roots);
- }
-
- {
- ShenandoahWorkerTimingsTracker timer(worker_times, ShenandoahPhaseTimings::ObjectSynchronizerRoots, worker_id);
- if (_process_strong_tasks->try_claim_task(SHENANDOAH_RP_PS_ObjectSynchronizer_oops_do)) {
- ObjectSynchronizer::oops_do(strong_roots);
- }
- }
-}
-
-uint ShenandoahRootProcessor::n_workers() const {
- return _srs.n_threads();
-}
-
-ShenandoahRootEvacuator::ShenandoahRootEvacuator(ShenandoahHeap* heap, uint n_workers, ShenandoahPhaseTimings::Phase phase) :
- _evacuation_tasks(new SubTasksDone(SHENANDOAH_EVAC_NumElements)),
- _srs(n_workers),
- _phase(phase),
- _coderoots_cset_iterator(ShenandoahCodeRoots::cset_iterator()),
- _weak_processor_timings(n_workers),
- _weak_processor_task(&_weak_processor_timings, n_workers) {
- 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();
- }
-
- ShenandoahWorkerTimings* worker_times = ShenandoahHeap::heap()->phase_timings()->worker_times();
- assert(_weak_processor_timings.max_threads() == n_workers(), "Must match");
- ShenandoahTimingConverter::weak_processing_timing_to_shenandoah_timing(&_weak_processor_timings,
- worker_times);
-
- ShenandoahHeap::heap()->phase_timings()->record_workers_end(_phase);
-}
-
-void ShenandoahRootEvacuator::process_evacuate_roots(OopClosure* oops,
- CodeBlobClosure* blobs,
- uint worker_id) {
-
- AlwaysTrueClosure always_true;
- ShenandoahWorkerTimings* worker_times = ShenandoahHeap::heap()->phase_timings()->worker_times();
- {
- bool is_par = n_workers() > 1;
- ResourceMark rm;
- ShenandoahWorkerTimingsTracker timer(worker_times, ShenandoahPhaseTimings::ThreadRoots, worker_id);
- Threads::possibly_parallel_oops_do(is_par, oops, NULL);
- }
-
- {
- ShenandoahWorkerTimingsTracker timer(worker_times, ShenandoahPhaseTimings::CLDGRoots, worker_id);
- CLDToOopClosure clds(oops, ClassLoaderData::_claim_strong);
- _cld_iterator.root_cld_do(&clds, &clds);
- }
-
- if (blobs != NULL) {
- ShenandoahWorkerTimingsTracker timer(worker_times, ShenandoahPhaseTimings::CodeCacheRoots, worker_id);
- _coderoots_cset_iterator.possibly_parallel_blobs_do(blobs);
- }
-
- if (ShenandoahStringDedup::is_enabled()) {
- ShenandoahStringDedup::parallel_oops_do(&always_true, 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_JNIHandles_oops_do)) {
- ShenandoahWorkerTimingsTracker timer(worker_times, ShenandoahPhaseTimings::JNIRoots, worker_id);
- JNIHandles::oops_do(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);
- }
-
- _weak_processor_task.work<AlwaysTrueClosure, OopClosure>(worker_id, &always_true, oops);
-}
-
-uint ShenandoahRootEvacuator::n_workers() const {
- return _srs.n_threads();
-}
-
-// Implemenation of ParallelCLDRootIterator
-ParallelCLDRootIterator::ParallelCLDRootIterator() {
- assert(SafepointSynchronize::is_at_safepoint(), "Must at safepoint");
+ShenandoahClassLoaderDataRoots::ShenandoahClassLoaderDataRoots() {
ClassLoaderDataGraph::clear_claimed_marks();
}
-void ParallelCLDRootIterator::root_cld_do(CLDClosure* strong, CLDClosure* weak) {
- ClassLoaderDataGraph::roots_cld_do(strong, weak);
+void ShenandoahClassLoaderDataRoots::clds_do(CLDClosure* strong_clds, CLDClosure* weak_clds, uint worker_id) {
+ ShenandoahWorkerTimings* worker_times = ShenandoahHeap::heap()->phase_timings()->worker_times();
+ ShenandoahWorkerTimingsTracker timer(worker_times, ShenandoahPhaseTimings::CLDGRoots, worker_id);
+ ClassLoaderDataGraph::roots_cld_do(strong_clds, weak_clds);
+}
+
+ShenandoahRootProcessor::ShenandoahRootProcessor(ShenandoahPhaseTimings::Phase phase) :
+ _heap(ShenandoahHeap::heap()),
+ _phase(phase) {
+ assert(SafepointSynchronize::is_at_safepoint(), "Must at safepoint");
+ _heap->phase_timings()->record_workers_start(_phase);
+}
+
+ShenandoahRootProcessor::~ShenandoahRootProcessor() {
+ assert(SafepointSynchronize::is_at_safepoint(), "Must at safepoint");
+ _heap->phase_timings()->record_workers_end(_phase);
+}
+
+ShenandoahRootEvacuator::ShenandoahRootEvacuator(uint n_workers, ShenandoahPhaseTimings::Phase phase) :
+ ShenandoahRootProcessor(phase),
+ _thread_roots(n_workers > 1),
+ _weak_roots(n_workers) {
}
+
+void ShenandoahRootEvacuator::roots_do(uint worker_id, OopClosure* oops) {
+ MarkingCodeBlobClosure blobsCl(oops, CodeBlobToOopClosure::FixRelocations);
+ CLDToOopClosure clds(oops, ClassLoaderData::_claim_strong);
+ CLDToOopClosure* weak_clds = ShenandoahHeap::heap()->unload_classes() ? NULL : &clds;
+
+ AlwaysTrueClosure always_true;
+
+ _serial_roots.oops_do(oops, worker_id);
+
+ _thread_roots.oops_do(oops, NULL, worker_id);
+ _cld_roots.clds_do(&clds, &clds, worker_id);
+ _code_roots.code_blobs_do(&blobsCl, worker_id);
+
+ _weak_roots.oops_do<AlwaysTrueClosure, OopClosure>(&always_true, oops, worker_id);
+ _dedup_roots.oops_do(&always_true, oops, worker_id);
+}
+
+ShenandoahRootUpdater::ShenandoahRootUpdater(uint n_workers, ShenandoahPhaseTimings::Phase phase, bool update_code_cache) :
+ ShenandoahRootProcessor(phase),
+ _thread_roots(n_workers > 1),
+ _weak_roots(n_workers),
+ _update_code_cache(update_code_cache) {
+}
+
+ShenandoahRootAdjuster::ShenandoahRootAdjuster(uint n_workers, ShenandoahPhaseTimings::Phase phase) :
+ ShenandoahRootProcessor(phase),
+ _thread_roots(n_workers > 1),
+ _weak_roots(n_workers) {
+ assert(ShenandoahHeap::heap()->is_full_gc_in_progress(), "Full GC only");
+}
+
+void ShenandoahRootAdjuster::roots_do(uint worker_id, OopClosure* oops) {
+ CodeBlobToOopClosure adjust_code_closure(oops, CodeBlobToOopClosure::FixRelocations);
+ CLDToOopClosure adjust_cld_closure(oops, ClassLoaderData::_claim_strong);
+ AlwaysTrueClosure always_true;
+
+ _serial_roots.oops_do(oops, worker_id);
+
+ _thread_roots.oops_do(oops, NULL, worker_id);
+ _cld_roots.clds_do(&adjust_cld_closure, NULL, worker_id);
+ _code_roots.code_blobs_do(&adjust_code_closure, worker_id);
+
+ _weak_roots.oops_do<AlwaysTrueClosure, OopClosure>(&always_true, oops, worker_id);
+ _dedup_roots.oops_do(&always_true, oops, worker_id);
+}
--- a/src/hotspot/share/gc/shenandoah/shenandoahRootProcessor.hpp Fri May 17 13:21:44 2019 +0100
+++ b/src/hotspot/share/gc/shenandoah/shenandoahRootProcessor.hpp Thu May 23 11:07:37 2019 +0100
@@ -36,110 +36,164 @@
#include "memory/allocation.hpp"
#include "memory/iterator.hpp"
-class ParallelCLDRootIterator {
+class ShenandoahSerialRoot {
+public:
+ typedef void (*OopsDo)(OopClosure*);
+private:
+ volatile bool _claimed;
+ const OopsDo _oops_do;
+ const ShenandoahPhaseTimings::GCParPhases _phase;
+
public:
- ParallelCLDRootIterator();
- void root_cld_do(CLDClosure* strong, CLDClosure* weak);
+ ShenandoahSerialRoot(OopsDo oops_do, ShenandoahPhaseTimings::GCParPhases);
+ void oops_do(OopClosure* cl, uint worker_id);
+};
+
+class ShenandoahSerialRoots {
+private:
+ ShenandoahSerialRoot _universe_root;
+ ShenandoahSerialRoot _object_synchronizer_root;
+ ShenandoahSerialRoot _management_root;
+ ShenandoahSerialRoot _system_dictionary_root;
+ ShenandoahSerialRoot _jvmti_root;
+ ShenandoahSerialRoot _jni_handle_root;
+public:
+ ShenandoahSerialRoots();
+ void oops_do(OopClosure* cl, uint worker_id);
+};
+
+class ShenandoahThreadRoots {
+private:
+ const bool _is_par;
+public:
+ ShenandoahThreadRoots(bool is_par);
+ ~ShenandoahThreadRoots();
+
+ void oops_do(OopClosure* oops_cl, CodeBlobClosure* code_cl, uint worker_id);
+ void threads_do(ThreadClosure* tc, uint worker_id);
};
-enum Shenandoah_process_roots_tasks {
- SHENANDOAH_RP_PS_Universe_oops_do,
- SHENANDOAH_RP_PS_JNIHandles_oops_do,
- SHENANDOAH_RP_PS_ObjectSynchronizer_oops_do,
- SHENANDOAH_RP_PS_Management_oops_do,
- SHENANDOAH_RP_PS_SystemDictionary_oops_do,
- SHENANDOAH_RP_PS_jvmti_oops_do,
- // Leave this one last.
- SHENANDOAH_RP_PS_NumElements
+class ShenandoahWeakRoots {
+private:
+ WeakProcessorPhaseTimes _process_timings;
+ WeakProcessor::Task _task;
+public:
+ ShenandoahWeakRoots(uint n_workers);
+ ~ShenandoahWeakRoots();
+
+ template <typename IsAlive, typename KeepAlive>
+ void oops_do(IsAlive* is_alive, KeepAlive* keep_alive, uint worker_id);
+};
+
+class ShenandoahStringDedupRoots {
+public:
+ ShenandoahStringDedupRoots();
+ ~ShenandoahStringDedupRoots();
+
+ void oops_do(BoolObjectClosure* is_alive, OopClosure* keep_alive, uint worker_id);
+};
+
+template <typename ITR>
+class ShenandoahCodeCacheRoots {
+private:
+ ITR _coderoots_iterator;
+public:
+ ShenandoahCodeCacheRoots();
+ ~ShenandoahCodeCacheRoots();
+
+ void code_blobs_do(CodeBlobClosure* blob_cl, uint worker_id);
+};
+
+class ShenandoahClassLoaderDataRoots {
+public:
+ ShenandoahClassLoaderDataRoots();
+
+ void clds_do(CLDClosure* strong_clds, CLDClosure* weak_clds, uint worker_id);
};
class ShenandoahRootProcessor : public StackObj {
- SubTasksDone* _process_strong_tasks;
- StrongRootsScope _srs;
- ShenandoahPhaseTimings::Phase _phase;
- ParallelCLDRootIterator _cld_iterator;
- ShenandoahAllCodeRootsIterator _coderoots_all_iterator;
- CodeBlobClosure* _threads_nmethods_cl;
- WeakProcessorPhaseTimes _weak_processor_timings;
- WeakProcessor::Task _weak_processor_task;
- bool _processed_weak_roots;
-
- void process_java_roots(OopClosure* scan_non_heap_roots,
- CLDClosure* scan_strong_clds,
- CLDClosure* scan_weak_clds,
- CodeBlobClosure* scan_strong_code,
- ThreadClosure* thread_cl,
- uint worker_i);
-
- void process_vm_roots(OopClosure* scan_non_heap_roots,
- uint worker_i);
-
- void weak_processor_timing_to_shenandoah_timing(const WeakProcessorPhases::Phase wpp,
- const ShenandoahPhaseTimings::GCParPhases spp,
- ShenandoahWorkerTimings* worker_times) const;
-
+private:
+ ShenandoahHeap* const _heap;
+ const ShenandoahPhaseTimings::Phase _phase;
public:
- ShenandoahRootProcessor(ShenandoahHeap* heap, uint n_workers,
- ShenandoahPhaseTimings::Phase phase);
+ ShenandoahRootProcessor(ShenandoahPhaseTimings::Phase phase);
~ShenandoahRootProcessor();
- // Apply oops, clds and blobs to all strongly reachable roots in the system.
- // Optionally, apply class loader closure to weak clds, depending on class unloading
- // for the particular GC cycles.
- void process_strong_roots(OopClosure* oops,
- CLDClosure* clds,
- CodeBlobClosure* blobs,
- ThreadClosure* thread_cl,
- uint worker_id);
+ ShenandoahHeap* heap() const { return _heap; }
+};
- // Apply oops, clds and blobs to strongly reachable roots in the system
- void process_all_roots(OopClosure* oops,
- CLDClosure* clds,
- CodeBlobClosure* blobs,
- ThreadClosure* thread_cl,
- uint worker_id);
+template <typename ITR>
+class ShenandoahRootScanner : public ShenandoahRootProcessor {
+private:
+ ShenandoahSerialRoots _serial_roots;
+ ShenandoahClassLoaderDataRoots _cld_roots;
+ ShenandoahThreadRoots _thread_roots;
+ ShenandoahCodeCacheRoots<ITR> _code_roots;
+public:
+ ShenandoahRootScanner(uint n_workers, ShenandoahPhaseTimings::Phase phase);
- // Apply oops, clds and blobs to strongly and weakly reachable roots in the system
- template <typename IsAlive>
- void update_all_roots(OopClosure* oops,
- CLDClosure* clds,
- CodeBlobClosure* blobs,
- ThreadClosure* thread_cl,
- uint worker_id);
+ // Apply oops, clds and blobs to all strongly reachable roots in the system,
+ // during class unloading cycle
+ void strong_roots_do(uint worker_id, OopClosure* cl);
+ void strong_roots_do(uint worker_id, OopClosure* oops, CLDClosure* clds, CodeBlobClosure* code, ThreadClosure* tc = NULL);
- // Number of worker threads used by the root processor.
- uint n_workers() const;
+ // Apply oops, clds and blobs to all strongly reachable roots and weakly reachable
+ // roots when class unloading is disabled during this cycle
+ void roots_do(uint worker_id, OopClosure* cl);
+ void roots_do(uint worker_id, OopClosure* oops, CLDClosure* clds, CodeBlobClosure* code, ThreadClosure* tc = NULL);
};
-class ShenandoahRootEvacuator : public StackObj {
- SubTasksDone* _evacuation_tasks;
- StrongRootsScope _srs;
- ShenandoahPhaseTimings::Phase _phase;
- ShenandoahCsetCodeRootsIterator _coderoots_cset_iterator;
- ParallelCLDRootIterator _cld_iterator;
- WeakProcessorPhaseTimes _weak_processor_timings;
- WeakProcessor::Task _weak_processor_task;
+typedef ShenandoahRootScanner<ShenandoahAllCodeRootsIterator> ShenandoahAllRootScanner;
+typedef ShenandoahRootScanner<ShenandoahCsetCodeRootsIterator> ShenandoahCSetRootScanner;
+
+// Evacuate all roots at a safepoint
+class ShenandoahRootEvacuator : public ShenandoahRootProcessor {
+private:
+ ShenandoahSerialRoots _serial_roots;
+ ShenandoahClassLoaderDataRoots _cld_roots;
+ ShenandoahThreadRoots _thread_roots;
+ ShenandoahWeakRoots _weak_roots;
+ ShenandoahStringDedupRoots _dedup_roots;
+ ShenandoahCodeCacheRoots<ShenandoahCsetCodeRootsIterator> _code_roots;
+
+public:
+ ShenandoahRootEvacuator(uint n_workers, ShenandoahPhaseTimings::Phase phase);
+
+ void roots_do(uint worker_id, OopClosure* oops);
+};
- enum Shenandoah_evacuate_roots_tasks {
- 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,
- SHENANDOAH_EVAC_JNIHandles_oops_do,
- // Leave this one last.
- SHENANDOAH_EVAC_NumElements
- };
+// Update all roots at a safepoint
+class ShenandoahRootUpdater : public ShenandoahRootProcessor {
+private:
+ ShenandoahSerialRoots _serial_roots;
+ ShenandoahClassLoaderDataRoots _cld_roots;
+ ShenandoahThreadRoots _thread_roots;
+ ShenandoahWeakRoots _weak_roots;
+ ShenandoahStringDedupRoots _dedup_roots;
+ ShenandoahCodeCacheRoots<ShenandoahCsetCodeRootsIterator> _code_roots;
+ const bool _update_code_cache;
+
public:
- ShenandoahRootEvacuator(ShenandoahHeap* heap, uint n_workers,
- ShenandoahPhaseTimings::Phase phase);
- ~ShenandoahRootEvacuator();
+ ShenandoahRootUpdater(uint n_workers, ShenandoahPhaseTimings::Phase phase, bool update_code_cache);
+
+ template<typename IsAlive, typename KeepAlive>
+ void roots_do(uint worker_id, IsAlive* is_alive, KeepAlive* keep_alive);
+};
- void process_evacuate_roots(OopClosure* oops,
- CodeBlobClosure* blobs,
- uint worker_id);
+// Adjuster all roots at a safepoint during full gc
+class ShenandoahRootAdjuster : public ShenandoahRootProcessor {
+private:
+ ShenandoahSerialRoots _serial_roots;
+ ShenandoahClassLoaderDataRoots _cld_roots;
+ ShenandoahThreadRoots _thread_roots;
+ ShenandoahWeakRoots _weak_roots;
+ ShenandoahStringDedupRoots _dedup_roots;
+ ShenandoahCodeCacheRoots<ShenandoahAllCodeRootsIterator> _code_roots;
- // Number of worker threads used by the root processor.
- uint n_workers() const;
+public:
+ ShenandoahRootAdjuster(uint n_workers, ShenandoahPhaseTimings::Phase phase);
+
+ void roots_do(uint worker_id, OopClosure* oops);
};
+
#endif // SHARE_GC_SHENANDOAH_SHENANDOAHROOTPROCESSOR_HPP
--- a/src/hotspot/share/gc/shenandoah/shenandoahRootProcessor.inline.hpp Fri May 17 13:21:44 2019 +0100
+++ b/src/hotspot/share/gc/shenandoah/shenandoahRootProcessor.inline.hpp Thu May 23 11:07:37 2019 +0100
@@ -24,23 +24,118 @@
#ifndef SHARE_GC_SHENANDOAH_SHENANDOAHROOTPROCESSOR_INLINE_HPP
#define SHARE_GC_SHENANDOAH_SHENANDOAHROOTPROCESSOR_INLINE_HPP
+#include "gc/shenandoah/shenandoahHeuristics.hpp"
#include "gc/shenandoah/shenandoahRootProcessor.hpp"
+#include "gc/shenandoah/shenandoahTimingTracker.hpp"
+#include "memory/resourceArea.hpp"
+
+template <typename IsAlive, typename KeepAlive>
+void ShenandoahWeakRoots::oops_do(IsAlive* is_alive, KeepAlive* keep_alive, uint worker_id) {
+ _task.work<IsAlive, KeepAlive>(worker_id, is_alive, keep_alive);
+}
+
+template <typename ITR>
+ShenandoahCodeCacheRoots<ITR>::ShenandoahCodeCacheRoots() {
+ nmethod::oops_do_marking_prologue();
+}
+
+template <typename ITR>
+void ShenandoahCodeCacheRoots<ITR>::code_blobs_do(CodeBlobClosure* blob_cl, uint worker_id) {
+ ShenandoahWorkerTimings* worker_times = ShenandoahHeap::heap()->phase_timings()->worker_times();
+ ShenandoahWorkerTimingsTracker timer(worker_times, ShenandoahPhaseTimings::CodeCacheRoots, worker_id);
+ _coderoots_iterator.possibly_parallel_blobs_do(blob_cl);
+}
+
+template <typename ITR>
+ShenandoahCodeCacheRoots<ITR>::~ShenandoahCodeCacheRoots() {
+ nmethod::oops_do_marking_epilogue();
+}
+
+class ShenandoahParallelOopsDoThreadClosure : public ThreadClosure {
+private:
+ OopClosure* _f;
+ CodeBlobClosure* _cf;
+ ThreadClosure* _thread_cl;
+public:
+ ShenandoahParallelOopsDoThreadClosure(OopClosure* f, CodeBlobClosure* cf, ThreadClosure* thread_cl) :
+ _f(f), _cf(cf), _thread_cl(thread_cl) {}
-template <typename IsAlive>
-void ShenandoahRootProcessor::update_all_roots(OopClosure* oops,
- CLDClosure* clds,
- CodeBlobClosure* blobs,
- ThreadClosure* thread_cl,
- uint worker_id) {
- process_all_roots(oops, clds, blobs, thread_cl, worker_id);
+ void do_thread(Thread* t) {
+ if (_thread_cl != NULL) {
+ _thread_cl->do_thread(t);
+ }
+ t->oops_do(_f, _cf);
+ }
+};
+
+template <typename ITR>
+ShenandoahRootScanner<ITR>::ShenandoahRootScanner(uint n_workers, ShenandoahPhaseTimings::Phase phase) :
+ ShenandoahRootProcessor(phase),
+ _thread_roots(n_workers > 1) {
+}
+
+template <typename ITR>
+void ShenandoahRootScanner<ITR>::roots_do(uint worker_id, OopClosure* oops) {
+ CLDToOopClosure clds_cl(oops, ClassLoaderData::_claim_strong);
+ MarkingCodeBlobClosure blobs_cl(oops, !CodeBlobToOopClosure::FixRelocations);
+ roots_do(worker_id, oops, &clds_cl, &blobs_cl);
+}
- IsAlive is_alive;
- _weak_processor_task.work<IsAlive, OopClosure>(worker_id, &is_alive, oops);
- _processed_weak_roots = true;
+template <typename ITR>
+void ShenandoahRootScanner<ITR>::strong_roots_do(uint worker_id, OopClosure* oops) {
+ CLDToOopClosure clds_cl(oops, ClassLoaderData::_claim_strong);
+ MarkingCodeBlobClosure blobs_cl(oops, !CodeBlobToOopClosure::FixRelocations);
+ strong_roots_do(worker_id, oops, &clds_cl, &blobs_cl);
+}
- if (ShenandoahStringDedup::is_enabled()) {
- ShenandoahStringDedup::parallel_oops_do(&is_alive, oops, worker_id);
+template <typename ITR>
+void ShenandoahRootScanner<ITR>::roots_do(uint worker_id, OopClosure* oops, CLDClosure* clds, CodeBlobClosure* code, ThreadClosure *tc) {
+ assert(!ShenandoahHeap::heap()->unload_classes() ||
+ ShenandoahHeap::heap()->heuristics()->can_do_traversal_gc(),
+ "No class unloading or traversal GC");
+ ShenandoahParallelOopsDoThreadClosure tc_cl(oops, code, tc);
+ ResourceMark rm;
+
+ _serial_roots.oops_do(oops, worker_id);
+ _cld_roots.clds_do(clds, clds, worker_id);
+ _thread_roots.threads_do(&tc_cl, worker_id);
+
+ // With ShenandoahConcurrentScanCodeRoots, we avoid scanning the entire code cache here,
+ // and instead do that in concurrent phase under the relevant lock. This saves init mark
+ // pause time.
+ if (code != NULL && !ShenandoahConcurrentScanCodeRoots) {
+ _code_roots.code_blobs_do(code, worker_id);
}
}
+template <typename ITR>
+void ShenandoahRootScanner<ITR>::strong_roots_do(uint worker_id, OopClosure* oops, CLDClosure* clds, CodeBlobClosure* code, ThreadClosure* tc) {
+ assert(ShenandoahHeap::heap()->unload_classes(), "Should be used during class unloading");
+ ShenandoahParallelOopsDoThreadClosure tc_cl(oops, code, tc);
+ ResourceMark rm;
+
+ _serial_roots.oops_do(oops, worker_id);
+ _cld_roots.clds_do(clds, NULL, worker_id);
+ _thread_roots.threads_do(&tc_cl, worker_id);
+}
+
+template <typename IsAlive, typename KeepAlive>
+void ShenandoahRootUpdater::roots_do(uint worker_id, IsAlive* is_alive, KeepAlive* keep_alive) {
+ CodeBlobToOopClosure update_blobs(keep_alive, CodeBlobToOopClosure::FixRelocations);
+ CLDToOopClosure clds(keep_alive, ClassLoaderData::_claim_strong);
+ CLDToOopClosure* weak_clds = ShenandoahHeap::heap()->unload_classes() ? NULL : &clds;
+
+ _serial_roots.oops_do(keep_alive, worker_id);
+
+ _thread_roots.oops_do(keep_alive, NULL, worker_id);
+ _cld_roots.clds_do(&clds, weak_clds, worker_id);
+
+ if(_update_code_cache) {
+ _code_roots.code_blobs_do(&update_blobs, worker_id);
+ }
+
+ _weak_roots.oops_do<IsAlive, KeepAlive>(is_alive, keep_alive, worker_id);
+ _dedup_roots.oops_do(is_alive, keep_alive, worker_id);
+}
+
#endif // SHARE_GC_SHENANDOAH_SHENANDOAHROOTPROCESSOR_INLINE_HPP
--- a/src/hotspot/share/gc/shenandoah/shenandoahSATBMarkQueueSet.cpp Fri May 17 13:21:44 2019 +0100
+++ b/src/hotspot/share/gc/shenandoah/shenandoahSATBMarkQueueSet.cpp Thu May 23 11:07:37 2019 +0100
@@ -70,19 +70,17 @@
}
}
-bool ShenandoahSATBMarkQueue::should_enqueue_buffer() {
- bool should_enqueue = SATBMarkQueue::should_enqueue_buffer();
- size_t cap = capacity();
- Thread* t = Thread::current();
- if (ShenandoahThreadLocalData::is_force_satb_flush(t)) {
- if (!should_enqueue && cap != index()) {
+void ShenandoahSATBMarkQueue::handle_completed_buffer() {
+ SATBMarkQueue::handle_completed_buffer();
+ if (!is_empty()) {
+ Thread* t = Thread::current();
+ if (ShenandoahThreadLocalData::is_force_satb_flush(t)) {
// Non-empty buffer is compacted, and we decided not to enqueue it.
// We still want to know about leftover work in that buffer eventually.
// This avoid dealing with these leftovers during the final-mark, after
// the buffers are drained completely. See JDK-8205353 for more discussion.
- should_enqueue = true;
+ ShenandoahThreadLocalData::set_force_satb_flush(t, false);
+ enqueue_completed_buffer();
}
- ShenandoahThreadLocalData::set_force_satb_flush(t, false);
}
- return should_enqueue;
}
--- a/src/hotspot/share/gc/shenandoah/shenandoahSATBMarkQueueSet.hpp Fri May 17 13:21:44 2019 +0100
+++ b/src/hotspot/share/gc/shenandoah/shenandoahSATBMarkQueueSet.hpp Thu May 23 11:07:37 2019 +0100
@@ -30,9 +30,10 @@
#include "runtime/thread.hpp"
class ShenandoahSATBMarkQueue: public SATBMarkQueue {
+protected:
+ virtual void handle_completed_buffer();
public:
ShenandoahSATBMarkQueue(SATBMarkQueueSet* qset) : SATBMarkQueue(qset) {}
- virtual bool should_enqueue_buffer();
};
class ShenandoahSATBMarkQueueSet : public SATBMarkQueueSet {
--- a/src/hotspot/share/gc/shenandoah/shenandoahTraversalGC.cpp Fri May 17 13:21:44 2019 +0100
+++ b/src/hotspot/share/gc/shenandoah/shenandoahTraversalGC.cpp Thu May 23 11:07:37 2019 +0100
@@ -161,15 +161,16 @@
class ShenandoahInitTraversalCollectionTask : public AbstractGangTask {
private:
- ShenandoahRootProcessor* _rp;
+ ShenandoahCSetRootScanner* _rp;
ShenandoahHeap* _heap;
ShenandoahCsetCodeRootsIterator* _cset_coderoots;
+ ShenandoahStringDedupRoots _dedup_roots;
+
public:
- ShenandoahInitTraversalCollectionTask(ShenandoahRootProcessor* rp, ShenandoahCsetCodeRootsIterator* cset_coderoots) :
+ ShenandoahInitTraversalCollectionTask(ShenandoahCSetRootScanner* rp) :
AbstractGangTask("Shenandoah Init Traversal Collection"),
_rp(rp),
- _heap(ShenandoahHeap::heap()),
- _cset_coderoots(cset_coderoots) {}
+ _heap(ShenandoahHeap::heap()) {}
void work(uint worker_id) {
ShenandoahParallelWorkerSession worker_session(worker_id);
@@ -191,18 +192,13 @@
ShenandoahMarkCLDClosure cld_cl(&roots_cl);
MarkingCodeBlobClosure code_cl(&roots_cl, CodeBlobToOopClosure::FixRelocations);
if (unload_classes) {
- _rp->process_strong_roots(&roots_cl, &cld_cl, NULL, NULL, worker_id);
- // Need to pre-evac code roots here. Otherwise we might see from-space constants.
- ShenandoahWorkerTimings* worker_times = _heap->phase_timings()->worker_times();
- ShenandoahWorkerTimingsTracker timer(worker_times, ShenandoahPhaseTimings::CodeCacheRoots, worker_id);
- _cset_coderoots->possibly_parallel_blobs_do(&code_cl);
+ _rp->roots_do(worker_id, &roots_cl, NULL, &code_cl);
} else {
- _rp->process_all_roots(&roots_cl, &cld_cl, &code_cl, NULL, worker_id);
+ _rp->roots_do(worker_id, &roots_cl, &cld_cl, &code_cl);
}
- if (ShenandoahStringDedup::is_enabled()) {
- AlwaysTrueClosure is_alive;
- ShenandoahStringDedup::parallel_oops_do(&is_alive, &roots_cl, worker_id);
- }
+
+ AlwaysTrueClosure is_alive;
+ _dedup_roots.oops_do(&is_alive, &roots_cl, worker_id);
}
}
};
@@ -230,11 +226,11 @@
class ShenandoahFinalTraversalCollectionTask : public AbstractGangTask {
private:
- ShenandoahRootProcessor* _rp;
+ ShenandoahAllRootScanner* _rp;
ShenandoahTaskTerminator* _terminator;
ShenandoahHeap* _heap;
public:
- ShenandoahFinalTraversalCollectionTask(ShenandoahRootProcessor* rp, ShenandoahTaskTerminator* terminator) :
+ ShenandoahFinalTraversalCollectionTask(ShenandoahAllRootScanner* rp, ShenandoahTaskTerminator* terminator) :
AbstractGangTask("Shenandoah Final Traversal Collection"),
_rp(rp),
_terminator(terminator),
@@ -273,23 +269,23 @@
// roots here.
if (!_heap->is_degenerated_gc_in_progress()) {
ShenandoahTraversalClosure roots_cl(q, rp);
- CLDToOopClosure cld_cl(&roots_cl, ClassLoaderData::_claim_strong);
ShenandoahTraversalSATBThreadsClosure tc(&satb_cl);
if (unload_classes) {
ShenandoahRemarkCLDClosure remark_cld_cl(&roots_cl);
- _rp->process_strong_roots(&roots_cl, &remark_cld_cl, NULL, &tc, worker_id);
+ _rp->strong_roots_do(worker_id, &roots_cl, &remark_cld_cl, NULL, &tc);
} else {
- _rp->process_all_roots(&roots_cl, &cld_cl, NULL, &tc, worker_id);
+ CLDToOopClosure cld_cl(&roots_cl, ClassLoaderData::_claim_strong);
+ _rp->roots_do(worker_id, &roots_cl, &cld_cl, NULL, &tc);
}
} else {
ShenandoahTraversalDegenClosure roots_cl(q, rp);
- CLDToOopClosure cld_cl(&roots_cl, ClassLoaderData::_claim_strong);
ShenandoahTraversalSATBThreadsClosure tc(&satb_cl);
if (unload_classes) {
ShenandoahRemarkCLDClosure remark_cld_cl(&roots_cl);
- _rp->process_strong_roots(&roots_cl, &remark_cld_cl, NULL, &tc, worker_id);
+ _rp->strong_roots_do(worker_id, &roots_cl, &remark_cld_cl, NULL, &tc);
} else {
- _rp->process_all_roots(&roots_cl, &cld_cl, NULL, &tc, worker_id);
+ CLDToOopClosure cld_cl(&roots_cl, ClassLoaderData::_claim_strong);
+ _rp->roots_do(worker_id, &roots_cl, &cld_cl, NULL, &tc);
}
}
@@ -309,6 +305,9 @@
_task_queues(new ShenandoahObjToScanQueueSet(heap->max_workers())),
_traversal_set(ShenandoahHeapRegionSet()) {
+ // Traversal does not support concurrent code root scanning
+ FLAG_SET_DEFAULT(ShenandoahConcurrentScanCodeRoots, false);
+
uint num_queues = heap->max_workers();
for (uint i = 0; i < num_queues; ++i) {
ShenandoahObjToScanQueue* task_queue = new ShenandoahObjToScanQueue();
@@ -411,11 +410,8 @@
{
uint nworkers = _heap->workers()->active_workers();
task_queues()->reserve(nworkers);
- ShenandoahRootProcessor rp(_heap, nworkers, ShenandoahPhaseTimings::init_traversal_gc_work);
-
- ShenandoahCsetCodeRootsIterator cset_coderoots = ShenandoahCodeRoots::cset_iterator();
-
- ShenandoahInitTraversalCollectionTask traversal_task(&rp, &cset_coderoots);
+ ShenandoahCSetRootScanner rp(nworkers, ShenandoahPhaseTimings::init_traversal_gc_work);
+ ShenandoahInitTraversalCollectionTask traversal_task(&rp);
_heap->workers()->run_task(&traversal_task);
}
@@ -584,7 +580,7 @@
task_queues()->reserve(nworkers);
// Finish traversal
- ShenandoahRootProcessor rp(_heap, nworkers, ShenandoahPhaseTimings::final_traversal_gc_work);
+ ShenandoahAllRootScanner rp(nworkers, ShenandoahPhaseTimings::final_traversal_gc_work);
ShenandoahTerminationTracker term(ShenandoahPhaseTimings::final_traversal_gc_termination);
ShenandoahTaskTerminator terminator(nworkers, task_queues());
@@ -693,10 +689,10 @@
class ShenandoahTraversalFixRootsTask : public AbstractGangTask {
private:
- ShenandoahRootProcessor* _rp;
+ ShenandoahRootUpdater* _rp;
public:
- ShenandoahTraversalFixRootsTask(ShenandoahRootProcessor* rp) :
+ ShenandoahTraversalFixRootsTask(ShenandoahRootUpdater* rp) :
AbstractGangTask("Shenandoah traversal fix roots"),
_rp(rp) {
assert(ShenandoahHeap::heap()->has_forwarded_objects(), "Must be");
@@ -705,9 +701,8 @@
void work(uint worker_id) {
ShenandoahParallelWorkerSession worker_session(worker_id);
ShenandoahTraversalFixRootsClosure cl;
- MarkingCodeBlobClosure blobsCl(&cl, CodeBlobToOopClosure::FixRelocations);
- CLDToOopClosure cldCl(&cl, ClassLoaderData::_claim_strong);
- _rp->update_all_roots<ShenandoahForwardedIsAliveClosure>(&cl, &cldCl, &blobsCl, NULL, worker_id);
+ ShenandoahForwardedIsAliveClosure is_alive;
+ _rp->roots_do<ShenandoahForwardedIsAliveClosure, ShenandoahTraversalFixRootsClosure>(worker_id, &is_alive, &cl);
}
};
@@ -715,7 +710,7 @@
#if defined(COMPILER2) || INCLUDE_JVMCI
DerivedPointerTable::clear();
#endif
- ShenandoahRootProcessor rp(_heap, _heap->workers()->active_workers(), ShenandoahPhaseTimings::final_traversal_update_roots);
+ ShenandoahRootUpdater rp(_heap->workers()->active_workers(), ShenandoahPhaseTimings::final_traversal_update_roots, true /* update code cache */);
ShenandoahTraversalFixRootsTask update_roots_task(&rp);
_heap->workers()->run_task(&update_roots_task);
#if defined(COMPILER2) || INCLUDE_JVMCI
--- a/src/hotspot/share/gc/shenandoah/shenandoahVerifier.cpp Fri May 17 13:21:44 2019 +0100
+++ b/src/hotspot/share/gc/shenandoah/shenandoahVerifier.cpp Thu May 23 11:07:37 2019 +0100
@@ -604,6 +604,23 @@
}
};
+class ShenandoahGCStateResetter : public StackObj {
+private:
+ ShenandoahHeap* const _heap;
+ char _gc_state;
+
+public:
+ ShenandoahGCStateResetter() : _heap(ShenandoahHeap::heap()) {
+ _gc_state = _heap->gc_state();
+ _heap->_gc_state.clear();
+ }
+
+ ~ShenandoahGCStateResetter() {
+ _heap->_gc_state.set(_gc_state);
+ assert(_heap->gc_state() == _gc_state, "Should be restored");
+ }
+};
+
void ShenandoahVerifier::verify_at_safepoint(const char *label,
VerifyForwarded forwarded, VerifyMarked marked,
VerifyCollectionSet cset,
@@ -653,6 +670,9 @@
}
}
+ // Deactivate barriers temporarily: Verifier wants plain heap accesses
+ ShenandoahGCStateResetter resetter;
+
// Heap size checks
{
ShenandoahHeapLocker lock(_heap->lock());
--- a/src/hotspot/share/gc/z/zDirector.cpp Fri May 17 13:21:44 2019 +0100
+++ b/src/hotspot/share/gc/z/zDirector.cpp Thu May 23 11:07:37 2019 +0100
@@ -181,6 +181,25 @@
return time_until_gc <= 0;
}
+bool ZDirector::rule_high_usage() const {
+ // Perform GC if the amount of free memory is 5% or less. This is a preventive
+ // meassure in the case where the application has a very low allocation rate,
+ // such that the allocation rate rule doesn't trigger, but the amount of free
+ // memory is still slowly but surely heading towards zero. In this situation,
+ // we start a GC cycle to avoid a potential allocation stall later.
+
+ // Calculate amount of free memory available to Java threads. Note that
+ // the heap reserve is not available to Java threads and is therefore not
+ // considered part of the free memory.
+ const size_t max_capacity = ZHeap::heap()->current_max_capacity();
+ const size_t max_reserve = ZHeap::heap()->max_reserve();
+ const size_t used = ZHeap::heap()->used();
+ const size_t free_with_reserve = max_capacity - used;
+ const size_t free = free_with_reserve - MIN2(free_with_reserve, max_reserve);
+
+ return percent_of(free, max_capacity) <= 5.0;
+}
+
GCCause::Cause ZDirector::make_gc_decision() const {
// Rule 0: Timer
if (rule_timer()) {
@@ -202,6 +221,11 @@
return GCCause::_z_proactive;
}
+ // Rule 4: High usage
+ if (rule_high_usage()) {
+ return GCCause::_z_high_usage;
+ }
+
// No GC
return GCCause::_no_gc;
}
--- a/src/hotspot/share/gc/z/zDirector.hpp Fri May 17 13:21:44 2019 +0100
+++ b/src/hotspot/share/gc/z/zDirector.hpp Thu May 23 11:07:37 2019 +0100
@@ -43,6 +43,7 @@
bool rule_warmup() const;
bool rule_allocation_rate() const;
bool rule_proactive() const;
+ bool rule_high_usage() const;
GCCause::Cause make_gc_decision() const;
protected:
--- a/src/hotspot/share/gc/z/zDriver.cpp Fri May 17 13:21:44 2019 +0100
+++ b/src/hotspot/share/gc/z/zDriver.cpp Thu May 23 11:07:37 2019 +0100
@@ -234,6 +234,7 @@
case GCCause::_z_allocation_rate:
case GCCause::_z_allocation_stall:
case GCCause::_z_proactive:
+ case GCCause::_z_high_usage:
case GCCause::_metadata_GC_threshold:
// Start asynchronous GC
_gc_cycle_port.send_async(cause);
--- a/src/hotspot/share/include/cds.h Fri May 17 13:21:44 2019 +0100
+++ b/src/hotspot/share/include/cds.h Thu May 23 11:07:37 2019 +0100
@@ -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
@@ -35,6 +35,7 @@
#define NUM_CDS_REGIONS 9
#define CDS_ARCHIVE_MAGIC 0xf00baba2
+#define CDS_DYNAMIC_ARCHIVE_MAGIC 0xf00baba8
#define CURRENT_CDS_ARCHIVE_VERSION 5
#define INVALID_CDS_ARCHIVE_VERSION -1
--- a/src/hotspot/share/interpreter/bytecodeInterpreter.cpp Fri May 17 13:21:44 2019 +0100
+++ b/src/hotspot/share/interpreter/bytecodeInterpreter.cpp Thu May 23 11:07:37 2019 +0100
@@ -2871,7 +2871,7 @@
METHOD->print_value_string(),
(int)(istate->bcp() - METHOD->code_base()),
(int)continuation_bci, p2i(THREAD));
- Exceptions::log_exception(except_oop, tempst);
+ Exceptions::log_exception(except_oop, tempst.as_string());
}
// for AbortVMOnException flag
Exceptions::debug_check_abort(except_oop);
@@ -2888,7 +2888,7 @@
METHOD->print_value_string(),
(int)(istate->bcp() - METHOD->code_base()),
p2i(THREAD));
- Exceptions::log_exception(except_oop, tempst);
+ Exceptions::log_exception(except_oop, tempst.as_string());
}
// for AbortVMOnException flag
Exceptions::debug_check_abort(except_oop);
--- a/src/hotspot/share/interpreter/interpreterRuntime.cpp Fri May 17 13:21:44 2019 +0100
+++ b/src/hotspot/share/interpreter/interpreterRuntime.cpp Thu May 23 11:07:37 2019 +0100
@@ -543,7 +543,7 @@
tempst.print("interpreter method <%s>\n"
" at bci %d for thread " INTPTR_FORMAT " (%s)",
h_method->print_value_string(), current_bci, p2i(thread), thread->name());
- Exceptions::log_exception(h_exception, tempst);
+ Exceptions::log_exception(h_exception, tempst.as_string());
}
// Don't go paging in something which won't be used.
// else if (extable->length() == 0) {
--- a/src/hotspot/share/jfr/metadata/metadata.xml Fri May 17 13:21:44 2019 +0100
+++ b/src/hotspot/share/jfr/metadata/metadata.xml Thu May 23 11:07:37 2019 +0100
@@ -983,6 +983,27 @@
<Field type="ulong" name="value" label="Value" />
</Event>
+ <Event name="ShenandoahHeapRegionStateChange" category="Java Virtual Machine, GC, Detailed" label="Shenandoah Heap Region State Change" description="Information about a Shenandoah heap region state change"
+ startTime="false">
+ <Field type="uint" name="index" label="Index" />
+ <Field type="ShenandoahHeapRegionState" name="from" label="From" />
+ <Field type="ShenandoahHeapRegionState" name="to" label="To" />
+ <Field type="ulong" contentType="address" name="start" label="Start" />
+ <Field type="ulong" contentType="bytes" name="used" label="Used" />
+ </Event>
+
+ <Event name="ShenandoahHeapRegionInformation" category="Java Virtual Machine, GC, Detailed" label="Shenandoah Heap Region Information" description="Information about a specific heap region in the Shenandoah GC"
+ period="everyChunk">
+ <Field type="uint" name="index" label="Index" />
+ <Field type="ShenandoahHeapRegionState" name="state" label="State" />
+ <Field type="ulong" contentType="address" name="start" label="Start" />
+ <Field type="ulong" contentType="bytes" name="used" label="Used" />
+ </Event>
+
+ <Type name="ShenandoahHeapRegionState" label="Shenandoah Heap Region State">
+ <Field type="string" name="state" label="State" />
+ </Type>
+
<Type name="ZStatisticsCounterType" label="Z Statistics Counter">
<Field type="string" name="counter" label="Counter" />
</Type>
--- a/src/hotspot/share/jfr/periodic/jfrPeriodic.cpp Fri May 17 13:21:44 2019 +0100
+++ b/src/hotspot/share/jfr/periodic/jfrPeriodic.cpp Thu May 23 11:07:37 2019 +0100
@@ -65,7 +65,9 @@
#include "services/threadService.hpp"
#include "utilities/exceptions.hpp"
#include "utilities/globalDefinitions.hpp"
-
+#if INCLUDE_SHENANDOAHGC
+#include "gc/shenandoah/shenandoahJfrSupport.hpp"
+#endif
/**
* JfrPeriodic class
* Implementation of declarations in
@@ -626,3 +628,14 @@
event.set_flushingEnabled(UseCodeCacheFlushing);
event.commit();
}
+
+
+TRACE_REQUEST_FUNC(ShenandoahHeapRegionInformation) {
+#if INCLUDE_SHENANDOAHGC
+ if (UseShenandoahGC) {
+ VM_ShenandoahSendHeapRegionInfoEvents op;
+ VMThread::execute(&op);
+ }
+#endif
+}
+
--- a/src/hotspot/share/jfr/recorder/checkpoint/jfrCheckpointManager.cpp Fri May 17 13:21:44 2019 +0100
+++ b/src/hotspot/share/jfr/recorder/checkpoint/jfrCheckpointManager.cpp Thu May 23 11:07:37 2019 +0100
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2016, 2019, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -136,6 +136,8 @@
void JfrCheckpointManager::register_full(BufferPtr t, Thread* thread) {
// nothing here at the moment
+ assert(t != NULL, "invariant");
+ assert(t->acquired_by(thread), "invariant");
assert(t->retired(), "invariant");
}
--- a/src/hotspot/share/jfr/recorder/jfrRecorder.cpp Fri May 17 13:21:44 2019 +0100
+++ b/src/hotspot/share/jfr/recorder/jfrRecorder.cpp Thu May 23 11:07:37 2019 +0100
@@ -57,7 +57,7 @@
static bool enable() {
assert(!_enabled, "invariant");
- FLAG_SET_MGMT(bool, FlightRecorder, true);
+ FLAG_SET_MGMT(FlightRecorder, true);
_enabled = FlightRecorder;
assert(_enabled, "invariant");
return _enabled;
@@ -168,7 +168,7 @@
static bool is_cds_dump_requested() {
// we will not be able to launch recordings if a cds dump is being requested
- if (DumpSharedSpaces && (JfrOptionSet::startup_recording_options() != NULL)) {
+ if ((DumpSharedSpaces || DynamicDumpSharedSpaces) && (JfrOptionSet::startup_recording_options() != NULL)) {
warning("JFR will be disabled during CDS dumping");
teardown_startup_support();
return true;
--- a/src/hotspot/share/jfr/recorder/storage/jfrBuffer.cpp Fri May 17 13:21:44 2019 +0100
+++ b/src/hotspot/share/jfr/recorder/storage/jfrBuffer.cpp Thu May 23 11:07:37 2019 +0100
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2011, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011, 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
@@ -136,6 +136,14 @@
_identity = NULL;
}
+bool JfrBuffer::acquired_by(const void* id) const {
+ return identity() == id;
+}
+
+bool JfrBuffer::acquired_by_self() const {
+ return acquired_by(Thread::current());
+}
+
#ifdef ASSERT
static bool validate_to(const JfrBuffer* const to, size_t size) {
assert(to != NULL, "invariant");
@@ -153,10 +161,6 @@
assert(t->top() + size <= t->pos(), "invariant");
return true;
}
-
-bool JfrBuffer::acquired_by_self() const {
- return identity() == Thread::current();
-}
#endif // ASSERT
void JfrBuffer::move(JfrBuffer* const to, size_t size) {
@@ -183,7 +187,6 @@
set_concurrent_top(start());
}
-// flags
enum FLAG {
RETIRED = 1,
TRANSIENT = 2,
--- a/src/hotspot/share/jfr/recorder/storage/jfrBuffer.hpp Fri May 17 13:21:44 2019 +0100
+++ b/src/hotspot/share/jfr/recorder/storage/jfrBuffer.hpp Thu May 23 11:07:37 2019 +0100
@@ -57,7 +57,6 @@
u4 _size;
const u1* stable_top() const;
- void clear_flags();
public:
JfrBuffer();
@@ -150,6 +149,8 @@
void acquire(const void* id);
bool try_acquire(const void* id);
+ bool acquired_by(const void* id) const;
+ bool acquired_by_self() const;
void release();
void move(JfrBuffer* const to, size_t size);
@@ -166,8 +167,6 @@
bool retired() const;
void set_retired();
void clear_retired();
-
- debug_only(bool acquired_by_self() const;)
};
class JfrAgeNode : public JfrBuffer {
--- a/src/hotspot/share/jfr/recorder/storage/jfrMemorySpace.inline.hpp Fri May 17 13:21:44 2019 +0100
+++ b/src/hotspot/share/jfr/recorder/storage/jfrMemorySpace.inline.hpp Thu May 23 11:07:37 2019 +0100
@@ -346,19 +346,19 @@
template <typename Mspace>
inline bool ReleaseOp<Mspace>::process(typename Mspace::Type* t) {
assert(t != NULL, "invariant");
- if (t->retired() || t->try_acquire(_thread)) {
- if (t->transient()) {
- if (_release_full) {
- mspace_release_full_critical(t, _mspace);
- } else {
- mspace_release_free_critical(t, _mspace);
- }
- return true;
+ // assumes some means of exclusive access to t
+ if (t->transient()) {
+ if (_release_full) {
+ mspace_release_full_critical(t, _mspace);
+ } else {
+ mspace_release_free_critical(t, _mspace);
}
- t->reinitialize();
- assert(t->empty(), "invariant");
- t->release(); // publish
+ return true;
}
+ t->reinitialize();
+ assert(t->empty(), "invariant");
+ assert(!t->retired(), "invariant");
+ t->release(); // publish
return true;
}
--- a/src/hotspot/share/jfr/recorder/storage/jfrStorage.cpp Fri May 17 13:21:44 2019 +0100
+++ b/src/hotspot/share/jfr/recorder/storage/jfrStorage.cpp Thu May 23 11:07:37 2019 +0100
@@ -339,9 +339,9 @@
void JfrStorage::register_full(BufferPtr buffer, Thread* thread) {
assert(buffer != NULL, "invariant");
assert(buffer->retired(), "invariant");
+ assert(buffer->acquired_by(thread), "invariant");
if (!full_buffer_registration(buffer, _age_mspace, control(), thread)) {
handle_registration_failure(buffer);
- buffer->release();
}
if (control().should_post_buffer_full_message()) {
_post_box.post(MSG_FULLBUFFER);
@@ -376,8 +376,8 @@
}
}
assert(buffer->empty(), "invariant");
+ assert(buffer->identity() != NULL, "invariant");
control().increment_dead();
- buffer->release();
buffer->set_retired();
}
@@ -738,13 +738,14 @@
Scavenger(JfrStorageControl& control, Mspace* mspace) : _control(control), _mspace(mspace), _count(0), _amount(0) {}
bool process(Type* t) {
if (t->retired()) {
+ assert(t->identity() != NULL, "invariant");
+ assert(t->empty(), "invariant");
assert(!t->transient(), "invariant");
assert(!t->lease(), "invariant");
- assert(t->empty(), "invariant");
- assert(t->identity() == NULL, "invariant");
++_count;
_amount += t->total_size();
t->clear_retired();
+ t->release();
_control.decrement_dead();
mspace_release_full_critical(t, _mspace);
}
--- a/src/hotspot/share/jfr/recorder/storage/jfrStorageUtils.hpp Fri May 17 13:21:44 2019 +0100
+++ b/src/hotspot/share/jfr/recorder/storage/jfrStorageUtils.hpp Thu May 23 11:07:37 2019 +0100
@@ -92,7 +92,6 @@
size_t processed() const { return ConcurrentWriteOp<Operation>::processed(); }
};
-
template <typename Operation>
class MutexedWriteOp {
private:
@@ -104,6 +103,15 @@
size_t processed() const { return _operation.processed(); }
};
+template <typename Operation>
+class ExclusiveOp : private MutexedWriteOp<Operation> {
+ public:
+ typedef typename Operation::Type Type;
+ ExclusiveOp(Operation& operation) : MutexedWriteOp<Operation>(operation) {}
+ bool process(Type* t);
+ size_t processed() const { return MutexedWriteOp<Operation>::processed(); }
+};
+
enum jfr_operation_mode {
mutexed = 1,
concurrent
--- a/src/hotspot/share/jfr/recorder/storage/jfrStorageUtils.inline.hpp Fri May 17 13:21:44 2019 +0100
+++ b/src/hotspot/share/jfr/recorder/storage/jfrStorageUtils.inline.hpp Thu May 23 11:07:37 2019 +0100
@@ -26,6 +26,7 @@
#define SHARE_JFR_RECORDER_STORAGE_JFRSTORAGEUTILS_INLINE_HPP
#include "jfr/recorder/storage/jfrStorageUtils.hpp"
+#include "runtime/thread.inline.hpp"
template <typename T>
inline bool UnBufferedWriteToChunk<T>::write(T* t, const u1* data, size_t size) {
@@ -75,6 +76,28 @@
return result;
}
+template <typename Type>
+static void retired_sensitive_acquire(Type* t) {
+ assert(t != NULL, "invariant");
+ if (t->retired()) {
+ return;
+ }
+ Thread* const thread = Thread::current();
+ while (!t->try_acquire(thread)) {
+ if (t->retired()) {
+ return;
+ }
+ }
+}
+
+template <typename Operation>
+inline bool ExclusiveOp<Operation>::process(typename Operation::Type* t) {
+ retired_sensitive_acquire(t);
+ assert(t->acquired_by_self() || t->retired(), "invariant");
+ // User is required to ensure proper release of the acquisition
+ return MutexedWriteOp<Operation>::process(t);
+}
+
template <typename Operation>
inline bool DiscardOp<Operation>::process(typename Operation::Type* t) {
assert(t != NULL, "invariant");
--- a/src/hotspot/share/jfr/recorder/stringpool/jfrStringPool.cpp Fri May 17 13:21:44 2019 +0100
+++ b/src/hotspot/share/jfr/recorder/stringpool/jfrStringPool.cpp Thu May 23 11:07:37 2019 +0100
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2016, 2019, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -140,93 +140,76 @@
return current_epoch;
}
-class StringPoolWriteOp {
+template <template <typename> class Operation>
+class StringPoolOp {
public:
typedef JfrStringPoolBuffer Type;
private:
- UnBufferedWriteToChunk<Type> _writer;
+ Operation<Type> _op;
Thread* _thread;
size_t _strings_processed;
public:
- StringPoolWriteOp(JfrChunkWriter& writer, Thread* thread) : _writer(writer), _thread(thread), _strings_processed(0) {}
+ StringPoolOp() : _op(), _thread(Thread::current()), _strings_processed(0) {}
+ StringPoolOp(JfrChunkWriter& writer, Thread* thread) : _op(writer), _thread(thread), _strings_processed(0) {}
bool write(Type* buffer, const u1* data, size_t size) {
- buffer->acquire(_thread); // blocking
+ assert(buffer->acquired_by(_thread) || buffer->retired(), "invariant");
const uint64_t nof_strings_used = buffer->string_count();
assert(nof_strings_used > 0, "invariant");
buffer->set_string_top(buffer->string_top() + nof_strings_used);
// "size processed" for string pool buffers is the number of processed string elements
_strings_processed += nof_strings_used;
- const bool ret = _writer.write(buffer, data, size);
- buffer->release();
- return ret;
+ return _op.write(buffer, data, size);
}
size_t processed() { return _strings_processed; }
};
-typedef StringPoolWriteOp WriteOperation;
-typedef ConcurrentWriteOp<WriteOperation> ConcurrentWriteOperation;
+template <typename Type>
+class StringPoolDiscarderStub {
+ public:
+ bool write(Type* buffer, const u1* data, size_t size) {
+ // stub only, discard happens at higher level
+ return true;
+ }
+};
+
+typedef StringPoolOp<UnBufferedWriteToChunk> WriteOperation;
+typedef StringPoolOp<StringPoolDiscarderStub> DiscardOperation;
+typedef ExclusiveOp<WriteOperation> ExclusiveWriteOperation;
+typedef ExclusiveOp<DiscardOperation> ExclusiveDiscardOperation;
+typedef ReleaseOp<JfrStringPoolMspace> StringPoolReleaseOperation;
+typedef CompositeOperation<ExclusiveWriteOperation, StringPoolReleaseOperation> StringPoolWriteOperation;
+typedef CompositeOperation<ExclusiveDiscardOperation, StringPoolReleaseOperation> StringPoolDiscardOperation;
size_t JfrStringPool::write() {
Thread* const thread = Thread::current();
WriteOperation wo(_chunkwriter, thread);
- ConcurrentWriteOperation cwo(wo);
- assert(_free_list_mspace->is_full_empty(), "invariant");
- process_free_list(cwo, _free_list_mspace);
- return wo.processed();
-}
-
-typedef MutexedWriteOp<WriteOperation> MutexedWriteOperation;
-typedef ReleaseOp<JfrStringPoolMspace> StringPoolReleaseOperation;
-typedef CompositeOperation<MutexedWriteOperation, StringPoolReleaseOperation> StringPoolWriteOperation;
-
-size_t JfrStringPool::write_at_safepoint() {
- assert(SafepointSynchronize::is_at_safepoint(), "invariant");
- Thread* const thread = Thread::current();
- WriteOperation wo(_chunkwriter, thread);
- MutexedWriteOperation mwo(wo);
+ ExclusiveWriteOperation ewo(wo);
StringPoolReleaseOperation spro(_free_list_mspace, thread, false);
- StringPoolWriteOperation spwo(&mwo, &spro);
+ StringPoolWriteOperation spwo(&ewo, &spro);
assert(_free_list_mspace->is_full_empty(), "invariant");
process_free_list(spwo, _free_list_mspace);
return wo.processed();
}
-class StringPoolBufferDiscarder {
- private:
- Thread* _thread;
- size_t _processed;
- public:
- typedef JfrStringPoolBuffer Type;
- StringPoolBufferDiscarder() : _thread(Thread::current()), _processed(0) {}
- bool process(Type* buffer) {
- buffer->acquire(_thread); // serialized access
- const u1* const current_top = buffer->top();
- const size_t unflushed_size = buffer->pos() - current_top;
- if (unflushed_size == 0) {
- assert(buffer->string_count() == 0, "invariant");
- buffer->release();
- return true;
- }
- buffer->set_top(current_top + unflushed_size);
- const uint64_t nof_strings_used = buffer->string_count();
- buffer->set_string_top(buffer->string_top() + nof_strings_used);
- // "size processed" for string pool buffers is the number of string elements
- _processed += (size_t)nof_strings_used;
- buffer->release();
- return true;
- }
- size_t processed() const { return _processed; }
-};
+size_t JfrStringPool::write_at_safepoint() {
+ assert(SafepointSynchronize::is_at_safepoint(), "invariant");
+ return write();
+}
size_t JfrStringPool::clear() {
- StringPoolBufferDiscarder discard_operation;
+ DiscardOperation discard_operation;
+ ExclusiveDiscardOperation edo(discard_operation);
+ StringPoolReleaseOperation spro(_free_list_mspace, Thread::current(), false);
+ StringPoolDiscardOperation spdo(&edo, &spro);
assert(_free_list_mspace->is_full_empty(), "invariant");
- process_free_list(discard_operation, _free_list_mspace);
+ process_free_list(spdo, _free_list_mspace);
return discard_operation.processed();
}
void JfrStringPool::register_full(BufferPtr t, Thread* thread) {
// nothing here at the moment
+ assert(t != NULL, "invariant");
+ assert(t->acquired_by(thread), "invariant");
assert(t->retired(), "invariant");
}
--- a/src/hotspot/share/jfr/recorder/stringpool/jfrStringPoolBuffer.cpp Fri May 17 13:21:44 2019 +0100
+++ b/src/hotspot/share/jfr/recorder/stringpool/jfrStringPoolBuffer.cpp Thu May 23 11:07:37 2019 +0100
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2016, 2019, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -29,11 +29,9 @@
void JfrStringPoolBuffer::reinitialize() {
assert(acquired_by_self() || retired(), "invariant");
- concurrent_top();
- set_pos((start()));
set_string_pos(0);
set_string_top(0);
- set_concurrent_top(start());
+ JfrBuffer::reinitialize();
}
uint64_t JfrStringPoolBuffer::string_pos() const {
@@ -57,7 +55,7 @@
}
void JfrStringPoolBuffer::increment(uint64_t value) {
- assert(acquired_by_self() || retired(), "invariant");
+ assert(acquired_by_self(), "invariant");
++_string_count_pos;
}
--- a/src/hotspot/share/jvmci/jvmci.cpp Fri May 17 13:21:44 2019 +0100
+++ b/src/hotspot/share/jvmci/jvmci.cpp Thu May 23 11:07:37 2019 +0100
@@ -26,7 +26,6 @@
#include "gc/shared/collectedHeap.hpp"
#include "gc/shared/oopStorage.inline.hpp"
#include "jvmci/jvmci.hpp"
-#include "jvmci/jvmci_globals.hpp"
#include "jvmci/jvmciJavaClasses.hpp"
#include "jvmci/jvmciRuntime.hpp"
#include "jvmci/metadataHandleBlock.hpp"
--- a/src/hotspot/share/jvmci/jvmciRuntime.cpp Fri May 17 13:21:44 2019 +0100
+++ b/src/hotspot/share/jvmci/jvmciRuntime.cpp Thu May 23 11:07:37 2019 +0100
@@ -311,7 +311,7 @@
tempst.print("compiled method <%s>\n"
" at PC" INTPTR_FORMAT " for thread " INTPTR_FORMAT,
cm->method()->print_value_string(), p2i(pc), p2i(thread));
- Exceptions::log_exception(exception, tempst);
+ Exceptions::log_exception(exception, tempst.as_string());
}
// for AbortVMOnException flag
NOT_PRODUCT(Exceptions::debug_check_abort(exception));
--- a/src/hotspot/share/jvmci/jvmci_globals.cpp Fri May 17 13:21:44 2019 +0100
+++ b/src/hotspot/share/jvmci/jvmci_globals.cpp Thu May 23 11:07:37 2019 +0100
@@ -32,18 +32,6 @@
fileStream* JVMCIGlobals::_jni_config_file = NULL;
-JVMCI_FLAGS(MATERIALIZE_DEVELOPER_FLAG, \
- MATERIALIZE_PD_DEVELOPER_FLAG, \
- MATERIALIZE_PRODUCT_FLAG, \
- MATERIALIZE_PD_PRODUCT_FLAG, \
- MATERIALIZE_DIAGNOSTIC_FLAG, \
- MATERIALIZE_PD_DIAGNOSTIC_FLAG, \
- MATERIALIZE_EXPERIMENTAL_FLAG, \
- MATERIALIZE_NOTPRODUCT_FLAG,
- IGNORE_RANGE, \
- IGNORE_CONSTRAINT, \
- IGNORE_WRITEABLE)
-
// Return true if jvmci flags are consistent.
bool JVMCIGlobals::check_jvmci_flags_are_consistent() {
--- a/src/hotspot/share/jvmci/jvmci_globals.hpp Fri May 17 13:21:44 2019 +0100
+++ b/src/hotspot/share/jvmci/jvmci_globals.hpp Thu May 23 11:07:37 2019 +0100
@@ -25,7 +25,7 @@
#ifndef SHARE_JVMCI_JVMCI_GLOBALS_HPP
#define SHARE_JVMCI_JVMCI_GLOBALS_HPP
-#include "utilities/ostream.hpp"
+class fileStream;
//
// Defines all global flags used by the JVMCI compiler. Only flags that need
@@ -129,21 +129,6 @@
NOT_COMPILER2(diagnostic(bool, UseMontgomerySquareIntrinsic, false, \
"Enables intrinsification of BigInteger.montgomerySquare()"))
-
-// Read default values for JVMCI globals
-
-JVMCI_FLAGS(DECLARE_DEVELOPER_FLAG, \
- DECLARE_PD_DEVELOPER_FLAG, \
- DECLARE_PRODUCT_FLAG, \
- DECLARE_PD_PRODUCT_FLAG, \
- DECLARE_DIAGNOSTIC_FLAG, \
- DECLARE_PD_DIAGNOSTIC_FLAG, \
- DECLARE_EXPERIMENTAL_FLAG, \
- DECLARE_NOTPRODUCT_FLAG, \
- IGNORE_RANGE, \
- IGNORE_CONSTRAINT, \
- IGNORE_WRITEABLE)
-
// The base name for the shared library containing the JVMCI based compiler
#define JVMCI_SHARED_LIBRARY_NAME "jvmcicompiler"
--- a/src/hotspot/share/logging/logTag.hpp Fri May 17 13:21:44 2019 +0100
+++ b/src/hotspot/share/logging/logTag.hpp Thu May 23 11:07:37 2019 +0100
@@ -66,6 +66,7 @@
LOG_TAG(defaultmethods) \
LOG_TAG(director) \
LOG_TAG(dump) \
+ LOG_TAG(dynamic) \
LOG_TAG(ergo) \
LOG_TAG(event) \
LOG_TAG(exceptions) \
--- a/src/hotspot/share/memory/allocation.hpp Fri May 17 13:21:44 2019 +0100
+++ b/src/hotspot/share/memory/allocation.hpp Thu May 23 11:07:37 2019 +0100
@@ -254,10 +254,9 @@
// into a single contiguous memory block, so we can use these
// two pointers to quickly determine if something is in the
// shared metaspace.
- //
// When CDS is not enabled, both pointers are set to NULL.
- static void* _shared_metaspace_base; // (inclusive) low address
- static void* _shared_metaspace_top; // (exclusive) high address
+ static void* _shared_metaspace_base; // (inclusive) low address
+ static void* _shared_metaspace_top; // (exclusive) high address
public:
@@ -269,7 +268,8 @@
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*)p) < _shared_metaspace_top && ((void*)p) >= _shared_metaspace_base);
+ return (((void*)p) < _shared_metaspace_top &&
+ ((void*)p) >= _shared_metaspace_base);
}
bool is_shared() const { return MetaspaceObj::is_shared(this); }
@@ -279,6 +279,12 @@
_shared_metaspace_base = base;
_shared_metaspace_top = top;
}
+
+ static void expand_shared_metaspace_range(void* top) {
+ assert(top >= _shared_metaspace_top, "must be");
+ _shared_metaspace_top = top;
+ }
+
static void* shared_metaspace_base() { return _shared_metaspace_base; }
static void* shared_metaspace_top() { return _shared_metaspace_top; }
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/hotspot/share/memory/dynamicArchive.cpp Thu May 23 11:07:37 2019 +0100
@@ -0,0 +1,1147 @@
+/*
+ * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#include "precompiled.hpp"
+#include "jvm.h"
+#include "classfile/classLoaderData.inline.hpp"
+#include "classfile/symbolTable.hpp"
+#include "classfile/systemDictionary.hpp"
+#include "classfile/systemDictionaryShared.hpp"
+#include "logging/log.hpp"
+#include "memory/metadataFactory.hpp"
+#include "memory/metaspace.hpp"
+#include "memory/metaspaceClosure.hpp"
+#include "memory/metaspaceShared.hpp"
+#include "memory/resourceArea.hpp"
+#include "memory/dynamicArchive.hpp"
+#include "oops/compressedOops.hpp"
+#include "oops/objArrayKlass.hpp"
+#include "prims/jvmtiRedefineClasses.hpp"
+#include "runtime/handles.inline.hpp"
+#include "runtime/os.inline.hpp"
+#include "runtime/sharedRuntime.hpp"
+#include "runtime/vmThread.hpp"
+#include "runtime/vmOperations.hpp"
+#include "utilities/bitMap.inline.hpp"
+
+#ifndef O_BINARY // if defined (Win32) use binary files.
+#define O_BINARY 0 // otherwise do nothing.
+#endif
+
+class DynamicArchiveBuilder : ResourceObj {
+ CHeapBitMap _ptrmap;
+ static unsigned my_hash(const address& a) {
+ return primitive_hash<address>(a);
+ }
+ static bool my_equals(const address& a0, const address& a1) {
+ return primitive_equals<address>(a0, a1);
+ }
+ typedef ResourceHashtable<
+ address, address,
+ DynamicArchiveBuilder::my_hash, // solaris compiler doesn't like: primitive_hash<address>
+ DynamicArchiveBuilder::my_equals, // solaris compiler doesn't like: primitive_equals<address>
+ 16384, ResourceObj::C_HEAP> RelocationTable;
+ RelocationTable _new_loc_table;
+
+ intx _buffer_to_target_delta;
+
+ DumpRegion* _current_dump_space;
+
+ static size_t reserve_alignment() {
+ return Metaspace::reserve_alignment();
+ }
+
+ static const int _total_dump_regions = 3;
+ int _num_dump_regions_used;
+
+public:
+ void mark_pointer(address* ptr_loc) {
+ if (is_in_buffer_space(ptr_loc)) {
+ size_t idx = pointer_delta(ptr_loc, _alloc_bottom, sizeof(address));
+ _ptrmap.set_bit(idx);
+ }
+ }
+
+ DumpRegion* current_dump_space() const {
+ return _current_dump_space;
+ }
+
+ bool is_in_buffer_space(address p) const {
+ return (_alloc_bottom <= p && p < (address)current_dump_space()->top());
+ }
+
+ template <typename T> bool is_in_target_space(T target_obj) const {
+ address buff_obj = address(target_obj) - _buffer_to_target_delta;
+ return is_in_buffer_space(buff_obj);
+ }
+
+ template <typename T> bool is_in_buffer_space(T obj) const {
+ return is_in_buffer_space(address(obj));
+ }
+
+ template <typename T> T to_target_no_check(T obj) const {
+ return (T)(address(obj) + _buffer_to_target_delta);
+ }
+
+ template <typename T> T to_target(T obj) const {
+ assert(is_in_buffer_space(obj), "must be");
+ return (T)(address(obj) + _buffer_to_target_delta);
+ }
+
+ template <typename T> T get_new_loc(T obj) {
+ address* pp = _new_loc_table.get((address)obj);
+ if (pp == NULL) {
+ // Excluded klasses are not copied
+ return NULL;
+ } else {
+ return (T)*pp;
+ }
+ }
+
+ address get_new_loc(MetaspaceClosure::Ref* ref) {
+ return get_new_loc(ref->obj());
+ }
+
+ template <typename T> bool has_new_loc(T obj) {
+ address* pp = _new_loc_table.get((address)obj);
+ return pp != NULL;
+ }
+
+protected:
+ enum FollowMode {
+ make_a_copy, point_to_it, set_to_null
+ };
+
+public:
+ void copy(MetaspaceClosure::Ref* ref, bool read_only) {
+ int bytes = ref->size() * BytesPerWord;
+ address old_obj = ref->obj();
+ address new_obj = copy_impl(ref, read_only, bytes);
+
+ assert(new_obj != NULL, "must be");
+ assert(new_obj != old_obj, "must be");
+ bool isnew = _new_loc_table.put(old_obj, new_obj);
+ assert(isnew, "must be");
+ }
+
+ // Make a shallow copy of each eligible MetaspaceObj into the buffer.
+ class ShallowCopier: public UniqueMetaspaceClosure {
+ DynamicArchiveBuilder* _builder;
+ bool _read_only;
+ public:
+ ShallowCopier(DynamicArchiveBuilder* shuffler, bool read_only)
+ : _builder(shuffler), _read_only(read_only) {}
+
+ virtual bool do_unique_ref(Ref* orig_obj, bool read_only) {
+ // This method gets called on each *original* object
+ // reachable from _builder->iterate_roots(). Each orig_obj is
+ // called exactly once.
+ FollowMode mode = _builder->follow_ref(orig_obj);
+
+ if (mode == point_to_it) {
+ if (read_only == _read_only) {
+ log_debug(cds, dynamic)("ptr : " PTR_FORMAT " %s", p2i(orig_obj->obj()),
+ MetaspaceObj::type_name(orig_obj->msotype()));
+ address p = orig_obj->obj();
+ bool isnew = _builder->_new_loc_table.put(p, p);
+ assert(isnew, "must be");
+ }
+ return false;
+ }
+
+ if (mode == set_to_null) {
+ log_debug(cds, dynamic)("nul : " PTR_FORMAT " %s", p2i(orig_obj->obj()),
+ MetaspaceObj::type_name(orig_obj->msotype()));
+ return false;
+ }
+
+ if (read_only == _read_only) {
+ // Make a shallow copy of orig_obj in a buffer (maintained
+ // by copy_impl in a subclass of DynamicArchiveBuilder).
+ _builder->copy(orig_obj, read_only);
+ }
+ return true;
+ }
+ };
+
+ // Relocate all embedded pointer fields within a MetaspaceObj's shallow copy
+ class ShallowCopyEmbeddedRefRelocator: public UniqueMetaspaceClosure {
+ DynamicArchiveBuilder* _builder;
+ public:
+ ShallowCopyEmbeddedRefRelocator(DynamicArchiveBuilder* shuffler)
+ : _builder(shuffler) {}
+
+ // This method gets called on each *original* object reachable
+ // from _builder->iterate_roots(). Each orig_obj is
+ // called exactly once.
+ virtual bool do_unique_ref(Ref* orig_ref, bool read_only) {
+ FollowMode mode = _builder->follow_ref(orig_ref);
+
+ if (mode == point_to_it) {
+ // We did not make a copy of this object
+ // and we have nothing to update
+ assert(_builder->get_new_loc(orig_ref) == NULL ||
+ _builder->get_new_loc(orig_ref) == orig_ref->obj(), "must be");
+ return false;
+ }
+
+ if (mode == set_to_null) {
+ // We did not make a copy of this object
+ // and we have nothing to update
+ assert(!_builder->has_new_loc(orig_ref->obj()), "must not be copied or pointed to");
+ return false;
+ }
+
+ // - orig_obj points to the original object.
+ // - new_obj points to the shallow copy (created by ShallowCopier)
+ // of orig_obj. new_obj is NULL if the orig_obj is excluded
+ address orig_obj = orig_ref->obj();
+ address new_obj = _builder->get_new_loc(orig_ref);
+
+ assert(new_obj != orig_obj, "must be");
+#ifdef ASSERT
+ if (new_obj == NULL) {
+ if (orig_ref->msotype() == MetaspaceObj::ClassType) {
+ Klass* k = (Klass*)orig_obj;
+ assert(k->is_instance_klass() &&
+ SystemDictionaryShared::is_excluded_class(InstanceKlass::cast(k)),
+ "orig_obj must be excluded Class");
+ }
+ }
+#endif
+
+ log_debug(cds, dynamic)("Relocating " PTR_FORMAT " %s", p2i(new_obj),
+ MetaspaceObj::type_name(orig_ref->msotype()));
+ if (new_obj != NULL) {
+ EmbeddedRefUpdater updater(_builder, orig_obj, new_obj);
+ orig_ref->metaspace_pointers_do(&updater);
+ }
+
+ return true; // keep recursing until every object is visited exactly once.
+ }
+ };
+
+ class EmbeddedRefUpdater: public MetaspaceClosure {
+ DynamicArchiveBuilder* _builder;
+ address _orig_obj;
+ address _new_obj;
+ public:
+ EmbeddedRefUpdater(DynamicArchiveBuilder* shuffler, address orig_obj, address new_obj) :
+ _builder(shuffler), _orig_obj(orig_obj), _new_obj(new_obj) {}
+
+ // This method gets called once for each pointer field F of orig_obj.
+ // We update new_obj->F to point to the new location of orig_obj->F.
+ //
+ // Example: Klass* 0x100 is copied to 0x400
+ // Symbol* 0x200 is copied to 0x500
+ //
+ // Let orig_obj == 0x100; and
+ // new_obj == 0x400; and
+ // ((Klass*)orig_obj)->_name == 0x200;
+ // Then this function effectively assigns
+ // ((Klass*)new_obj)->_name = 0x500;
+ virtual bool do_ref(Ref* ref, bool read_only) {
+ address new_pointee = NULL;
+
+ if (ref->not_null()) {
+ address old_pointee = ref->obj();
+
+ FollowMode mode = _builder->follow_ref(ref);
+ if (mode == point_to_it) {
+ new_pointee = old_pointee;
+ } else if (mode == set_to_null) {
+ new_pointee = NULL;
+ } else {
+ new_pointee = _builder->get_new_loc(old_pointee);
+ }
+ }
+
+ const char* kind = MetaspaceObj::type_name(ref->msotype());
+ // offset of this field inside the original object
+ intx offset = (address)ref->addr() - _orig_obj;
+ _builder->update_pointer((address*)(_new_obj + offset), new_pointee, kind, offset);
+
+ // We can't mark the pointer here, because DynamicArchiveBuilder::sort_methods
+ // may re-layout the [iv]tables, which would change the offset(s) in an InstanceKlass
+ // that would contain pointers. Therefore, we must mark the pointers after
+ // sort_methods(), using PointerMarker.
+ return false; // Do not recurse.
+ }
+ };
+
+ class ExternalRefUpdater: public MetaspaceClosure {
+ DynamicArchiveBuilder* _builder;
+
+ public:
+ ExternalRefUpdater(DynamicArchiveBuilder* shuffler) : _builder(shuffler) {}
+
+ virtual bool do_ref(Ref* ref, bool read_only) {
+ // ref is a pointer that lives OUTSIDE of the buffer, but points to an object inside the buffer
+ if (ref->not_null()) {
+ address new_loc = _builder->get_new_loc(ref);
+ const char* kind = MetaspaceObj::type_name(ref->msotype());
+ _builder->update_pointer(ref->addr(), new_loc, kind, 0);
+ _builder->mark_pointer(ref->addr());
+ }
+ return false; // Do not recurse.
+ }
+ };
+
+ class PointerMarker: public UniqueMetaspaceClosure {
+ DynamicArchiveBuilder* _builder;
+
+ public:
+ PointerMarker(DynamicArchiveBuilder* shuffler) : _builder(shuffler) {}
+
+ virtual bool do_unique_ref(Ref* ref, bool read_only) {
+ if (_builder->is_in_buffer_space(ref->obj())) {
+ EmbeddedRefMarker ref_marker(_builder);
+ ref->metaspace_pointers_do(&ref_marker);
+ return true; // keep recursing until every buffered object is visited exactly once.
+ } else {
+ return false;
+ }
+ }
+ };
+
+ class EmbeddedRefMarker: public MetaspaceClosure {
+ DynamicArchiveBuilder* _builder;
+
+ public:
+ EmbeddedRefMarker(DynamicArchiveBuilder* shuffler) : _builder(shuffler) {}
+ virtual bool do_ref(Ref* ref, bool read_only) {
+ if (ref->not_null() && _builder->is_in_buffer_space(ref->obj())) {
+ _builder->mark_pointer(ref->addr());
+ }
+ return false; // Do not recurse.
+ }
+ };
+
+ void update_pointer(address* addr, address value, const char* kind, uintx offset, bool is_mso_pointer=true) {
+ // Propagate the the mask bits to the new value -- see comments above MetaspaceClosure::obj()
+ if (is_mso_pointer) {
+ const uintx FLAG_MASK = 0x03;
+ uintx mask_bits = uintx(*addr) & FLAG_MASK;
+ value = (address)(uintx(value) | mask_bits);
+ }
+
+ if (*addr != value) {
+ log_debug(cds, dynamic)("Update (%18s*) %3d [" PTR_FORMAT "] " PTR_FORMAT " -> " PTR_FORMAT,
+ kind, int(offset), p2i(addr), p2i(*addr), p2i(value));
+ *addr = value;
+ }
+ }
+
+private:
+ GrowableArray<Symbol*>* _symbols; // symbols to dump
+ GrowableArray<InstanceKlass*>* _klasses; // klasses to dump
+
+ void append(InstanceKlass* k) { _klasses->append(k); }
+ void append(Symbol* s) { _symbols->append(s); }
+
+ class GatherKlassesAndSymbols : public UniqueMetaspaceClosure {
+ DynamicArchiveBuilder* _builder;
+ bool _read_only;
+
+ public:
+ GatherKlassesAndSymbols(DynamicArchiveBuilder* builder)
+ : _builder(builder) {}
+
+ virtual bool do_unique_ref(Ref* ref, bool read_only) {
+ if (_builder->follow_ref(ref) != make_a_copy) {
+ return false;
+ }
+ if (ref->msotype() == MetaspaceObj::ClassType) {
+ Klass* klass = (Klass*)ref->obj();
+ assert(klass->is_klass(), "must be");
+ if (klass->is_instance_klass()) {
+ InstanceKlass* ik = InstanceKlass::cast(klass);
+ assert(!SystemDictionaryShared::is_excluded_class(ik), "must be");
+ _builder->append(ik);
+ _builder->_estimated_metsapceobj_bytes += BytesPerWord; // See RunTimeSharedClassInfo::get_for()
+ }
+ } else if (ref->msotype() == MetaspaceObj::SymbolType) {
+ _builder->append((Symbol*)ref->obj());
+ }
+
+ int bytes = ref->size() * BytesPerWord;
+ _builder->_estimated_metsapceobj_bytes += bytes;
+
+ return true;
+ }
+ };
+
+ FollowMode follow_ref(MetaspaceClosure::Ref *ref) {
+ address obj = ref->obj();
+ if (MetaspaceShared::is_in_shared_metaspace(obj)) {
+ // Don't dump existing shared metadata again.
+ return point_to_it;
+ } else if (ref->msotype() == MetaspaceObj::MethodDataType) {
+ return set_to_null;
+ } else {
+ if (ref->msotype() == MetaspaceObj::ClassType) {
+ Klass* klass = (Klass*)ref->obj();
+ assert(klass->is_klass(), "must be");
+ if (klass->is_instance_klass()) {
+ InstanceKlass* ik = InstanceKlass::cast(klass);
+ if (SystemDictionaryShared::is_excluded_class(ik)) {
+ ResourceMark rm;
+ log_debug(cds, dynamic)("Skipping class (excluded): %s", klass->external_name());
+ return set_to_null;
+ }
+ } else if (klass->is_array_klass()) {
+ // Don't support archiving of array klasses for now.
+ ResourceMark rm;
+ log_debug(cds, dynamic)("Skipping class (array): %s", klass->external_name());
+ return set_to_null;
+ }
+ }
+
+ return make_a_copy;
+ }
+ }
+
+ address copy_impl(MetaspaceClosure::Ref* ref, bool read_only, int bytes) {
+ if (ref->msotype() == MetaspaceObj::ClassType) {
+ // Save a pointer immediate in front of an InstanceKlass, so
+ // we can do a quick lookup from InstanceKlass* -> RunTimeSharedClassInfo*
+ // without building another hashtable. See RunTimeSharedClassInfo::get_for()
+ // in systemDictionaryShared.cpp.
+ address obj = ref->obj();
+ Klass* klass = (Klass*)obj;
+ if (klass->is_instance_klass()) {
+ SystemDictionaryShared::validate_before_archiving(InstanceKlass::cast(klass));
+ current_dump_space()->allocate(sizeof(address), BytesPerWord);
+ }
+ }
+ address p = (address)current_dump_space()->allocate(bytes);
+ address obj = ref->obj();
+ log_debug(cds, dynamic)("COPY: " PTR_FORMAT " ==> " PTR_FORMAT " %5d %s",
+ p2i(obj), p2i(p), bytes,
+ MetaspaceObj::type_name(ref->msotype()));
+ memcpy(p, obj, bytes);
+
+ intptr_t* cloned_vtable = MetaspaceShared::fix_cpp_vtable_for_dynamic_archive(ref->msotype(), p);
+ if (cloned_vtable != NULL) {
+ update_pointer((address*)p, (address)cloned_vtable, "vtb", 0, /*is_mso_pointer*/false);
+ }
+
+ return (address)p;
+ }
+
+ DynamicArchiveHeader *_header;
+ address _alloc_bottom;
+ address _last_verified_top;
+ size_t _other_region_used_bytes;
+
+ // Conservative estimate for number of bytes needed for:
+ size_t _estimated_metsapceobj_bytes; // all archived MetsapceObj's.
+ size_t _estimated_hashtable_bytes; // symbol table and dictionaries
+ size_t _estimated_trampoline_bytes; // method entry trampolines
+
+ size_t estimate_archive_size();
+ size_t estimate_trampoline_size();
+ size_t estimate_class_file_size();
+ address reserve_space_and_init_buffer_to_target_delta();
+ void init_header(address addr);
+ void make_trampolines();
+ void make_klasses_shareable();
+ void sort_methods(InstanceKlass* ik) const;
+ void set_symbols_permanent();
+ void relocate_buffer_to_target();
+ void write_archive(char* read_only_tables_start);
+
+ void init_first_dump_space(address reserved_bottom) {
+ address first_space_base = reserved_bottom;
+ DumpRegion* rw_space = MetaspaceShared::read_write_dump_space();
+ MetaspaceShared::init_shared_dump_space(rw_space, first_space_base);
+ _current_dump_space = rw_space;
+ _last_verified_top = first_space_base;
+ _num_dump_regions_used = 1;
+ }
+
+public:
+ DynamicArchiveBuilder() {
+ _klasses = new (ResourceObj::C_HEAP, mtClass) GrowableArray<InstanceKlass*>(100, true, mtInternal);
+ _symbols = new (ResourceObj::C_HEAP, mtClass) GrowableArray<Symbol*>(1000, true, mtInternal);
+
+ _estimated_metsapceobj_bytes = 0;
+ _estimated_hashtable_bytes = 0;
+ _estimated_trampoline_bytes = 0;
+
+ _num_dump_regions_used = 0;
+ }
+
+ void start_dump_space(DumpRegion* next) {
+ address bottom = _last_verified_top;
+ address top = (address)(current_dump_space()->top());
+ _other_region_used_bytes += size_t(top - bottom);
+
+ MetaspaceShared::pack_dump_space(current_dump_space(), next, MetaspaceShared::shared_rs());
+ _current_dump_space = next;
+ _num_dump_regions_used ++;
+
+ _last_verified_top = (address)(current_dump_space()->top());
+ }
+
+ void verify_estimate_size(size_t estimate, const char* which) {
+ address bottom = _last_verified_top;
+ address top = (address)(current_dump_space()->top());
+ size_t used = size_t(top - bottom) + _other_region_used_bytes;
+ int diff = int(estimate) - int(used);
+
+ log_info(cds)("%s estimate = " SIZE_FORMAT " used = " SIZE_FORMAT "; diff = %d bytes", which, estimate, used, diff);
+ assert(diff >= 0, "Estimate is too small");
+
+ _last_verified_top = top;
+ _other_region_used_bytes = 0;
+ }
+
+ // Do this before and after the archive dump to see if any corruption
+ // is caused by dynamic dumping.
+ void verify_universe(const char* info) {
+ if (VerifyBeforeExit) {
+ log_info(cds)("Verify %s", info);
+ HandleMark hm;
+ // Among other things, this ensures that Eden top is correct.
+ Universe::heap()->prepare_for_verify();
+ Universe::verify(info);
+ }
+ }
+
+ void doit() {
+ verify_universe("Before CDS dynamic dump");
+ DEBUG_ONLY(SystemDictionaryShared::NoClassLoadingMark nclm);
+ SystemDictionaryShared::check_excluded_classes();
+
+ {
+ ResourceMark rm;
+ GatherKlassesAndSymbols gatherer(this);
+
+ SystemDictionaryShared::dumptime_classes_do(&gatherer);
+ SymbolTable::metaspace_pointers_do(&gatherer);
+ FileMapInfo::metaspace_pointers_do(&gatherer);
+
+ gatherer.finish();
+ }
+
+ // rw space starts ...
+ address reserved_bottom = reserve_space_and_init_buffer_to_target_delta();
+ init_header(reserved_bottom);
+
+ verify_estimate_size(sizeof(DynamicArchiveHeader), "header");
+
+ log_info(cds, dynamic)("Copying %d klasses and %d symbols",
+ _klasses->length(), _symbols->length());
+
+ {
+ assert(current_dump_space() == MetaspaceShared::read_write_dump_space(),
+ "Current dump space is not rw space");
+ // shallow-copy RW objects, if necessary
+ ResourceMark rm;
+ ShallowCopier rw_copier(this, false);
+ iterate_roots(&rw_copier);
+ }
+
+ // ro space starts ...
+ DumpRegion* ro_space = MetaspaceShared::read_only_dump_space();
+ {
+ start_dump_space(ro_space);
+
+ // shallow-copy RO objects, if necessary
+ ResourceMark rm;
+ ShallowCopier ro_copier(this, true);
+ iterate_roots(&ro_copier);
+ }
+
+ size_t bitmap_size = pointer_delta(current_dump_space()->top(),
+ _alloc_bottom, sizeof(address));
+ _ptrmap.initialize(bitmap_size);
+
+ {
+ log_info(cds)("Relocating embedded pointers ... ");
+ ResourceMark rm;
+ ShallowCopyEmbeddedRefRelocator emb_reloc(this);
+ iterate_roots(&emb_reloc);
+ }
+
+ {
+ log_info(cds)("Relocating external roots ... ");
+ ResourceMark rm;
+ ExternalRefUpdater ext_reloc(this);
+ iterate_roots(&ext_reloc);
+ }
+
+ verify_estimate_size(_estimated_metsapceobj_bytes, "MetaspaceObjs");
+
+ char* read_only_tables_start;
+ {
+ set_symbols_permanent();
+
+ // Write the symbol table and system dictionaries to the RO space.
+ // Note that these tables still point to the *original* objects
+ // (because they were not processed by ExternalRefUpdater), so
+ // they would need to call DynamicArchive::original_to_target() to
+ // get the correct addresses.
+ assert(current_dump_space() == ro_space, "Must be RO space");
+ SymbolTable::write_to_archive(false);
+ SystemDictionaryShared::write_to_archive(false);
+
+ read_only_tables_start = ro_space->top();
+ WriteClosure wc(ro_space);
+ SymbolTable::serialize_shared_table_header(&wc, false);
+ SystemDictionaryShared::serialize_dictionary_headers(&wc, false);
+ }
+
+ verify_estimate_size(_estimated_hashtable_bytes, "Hashtables");
+
+ // mc space starts ...
+ {
+ start_dump_space(MetaspaceShared::misc_code_dump_space());
+ make_trampolines();
+ }
+
+ verify_estimate_size(_estimated_trampoline_bytes, "Trampolines");
+
+ make_klasses_shareable();
+
+ {
+ log_info(cds)("Final relocation of pointers ... ");
+ ResourceMark rm;
+ PointerMarker marker(this);
+ iterate_roots(&marker);
+ relocate_buffer_to_target();
+ }
+
+ write_archive(read_only_tables_start);
+
+ assert(_num_dump_regions_used == _total_dump_regions, "must be");
+ verify_universe("After CDS dynamic dump");
+ }
+
+ void iterate_roots(MetaspaceClosure* it) {
+ int i;
+ int num_klasses = _klasses->length();
+ for (i = 0; i < num_klasses; i++) {
+ it->push(&_klasses->at(i));
+ }
+
+ int num_symbols = _symbols->length();
+ for (i = 0; i < num_symbols; i++) {
+ it->push(&_symbols->at(i));
+ }
+
+ _header->_shared_path_table.metaspace_pointers_do(it);
+
+ // Do not call these again, as we have already collected all the classes and symbols
+ // that we want to archive. Also, these calls would corrupt the tables when
+ // ExternalRefUpdater is used.
+ //
+ // SystemDictionaryShared::dumptime_classes_do(it);
+ // SymbolTable::metaspace_pointers_do(it);
+
+ it->finish();
+ }
+};
+
+size_t DynamicArchiveBuilder::estimate_archive_size() {
+ // size of the symbol table and two dictionaries, plus the RunTimeSharedClassInfo's
+ _estimated_hashtable_bytes = 0;
+ _estimated_hashtable_bytes += SymbolTable::estimate_size_for_archive();
+ _estimated_hashtable_bytes += SystemDictionaryShared::estimate_size_for_archive();
+
+ _estimated_trampoline_bytes = estimate_trampoline_size();
+
+ size_t total = 0;
+
+ total += _estimated_metsapceobj_bytes;
+ total += _estimated_hashtable_bytes;
+ total += _estimated_trampoline_bytes;
+
+ // allow fragmentation at the end of each dump region
+ total += _total_dump_regions * reserve_alignment();
+
+ return align_up(total, reserve_alignment());
+}
+
+address DynamicArchiveBuilder::reserve_space_and_init_buffer_to_target_delta() {
+ size_t total = estimate_archive_size();
+ bool large_pages = false; // No large pages when dumping the CDS archive.
+ size_t increment = align_up(1*G, reserve_alignment());
+ char* addr = (char*)align_up(CompressedKlassPointers::base() + MetaspaceSize + increment,
+ reserve_alignment());
+
+ ReservedSpace* rs = MetaspaceShared::reserve_shared_rs(
+ total, reserve_alignment(), large_pages, addr);
+ while (!rs->is_reserved() && (addr + increment > addr)) {
+ addr += increment;
+ rs = MetaspaceShared::reserve_shared_rs(
+ total, reserve_alignment(), large_pages, addr);
+ }
+ if (!rs->is_reserved()) {
+ log_error(cds, dynamic)("Failed to reserve %d bytes of output buffer.", (int)total);
+ vm_direct_exit(0);
+ }
+
+ address buffer_base = (address)rs->base();
+ log_info(cds, dynamic)("Reserved output buffer space at : " PTR_FORMAT " [%d bytes]",
+ p2i(buffer_base), (int)total);
+
+ // At run time, we will mmap the dynamic archive at target_space_bottom.
+ // However, at dump time, we may not be able to write into the target_space,
+ // as it's occupied by dynamically loaded Klasses. So we allocate a buffer
+ // at an arbitrary location chosen by the OS. We will write all the dynamically
+ // archived classes into this buffer. At the final stage of dumping, we relocate
+ // all pointers that are inside the buffer_space to point to their (runtime)
+ // target location inside thetarget_space.
+ address target_space_bottom =
+ (address)align_up(MetaspaceShared::shared_metaspace_top(), reserve_alignment());
+ _buffer_to_target_delta = intx(target_space_bottom) - intx(buffer_base);
+
+ log_info(cds, dynamic)("Target archive space at : " PTR_FORMAT, p2i(target_space_bottom));
+ log_info(cds, dynamic)("Buffer-space to target-space delta : " PTR_FORMAT, p2i((address)_buffer_to_target_delta));
+
+ return buffer_base;
+}
+
+void DynamicArchiveBuilder::init_header(address reserved_bottom) {
+ _alloc_bottom = reserved_bottom;
+ _last_verified_top = reserved_bottom;
+ _other_region_used_bytes = 0;
+
+ init_first_dump_space(reserved_bottom);
+
+ FileMapInfo* mapinfo = new FileMapInfo(false);
+ _header = (DynamicArchiveHeader*)mapinfo->_header;
+
+ Thread* THREAD = Thread::current();
+ FileMapInfo* base_info = FileMapInfo::current_info();
+ int* crc = _header->_base_archive_crc;
+ *crc++ = base_info->crc(); // base archive header crc
+ for (int i = 0; i < MetaspaceShared::n_regions; i++) {
+ *crc++ = base_info->space_crc(i);
+ }
+ _header->populate(base_info, os::vm_allocation_granularity());
+}
+
+size_t DynamicArchiveBuilder::estimate_trampoline_size() {
+ size_t total = 0;
+ size_t each_method_bytes =
+ align_up(SharedRuntime::trampoline_size(), BytesPerWord) +
+ align_up(sizeof(AdapterHandlerEntry*), BytesPerWord);
+
+ for (int i = 0; i < _klasses->length(); i++) {
+ InstanceKlass* ik = _klasses->at(i);
+ Array<Method*>* methods = ik->methods();
+ total += each_method_bytes * methods->length();
+ }
+ return total;
+}
+
+void DynamicArchiveBuilder::make_trampolines() {
+ for (int i = 0; i < _klasses->length(); i++) {
+ InstanceKlass* ik = _klasses->at(i);
+ Array<Method*>* methods = ik->methods();
+ for (int j = 0; j < methods->length(); j++) {
+ Method* m = methods->at(j);
+ address c2i_entry_trampoline =
+ (address)MetaspaceShared::misc_code_space_alloc(SharedRuntime::trampoline_size());
+ m->set_from_compiled_entry(to_target(c2i_entry_trampoline));
+ AdapterHandlerEntry** adapter_trampoline =
+ (AdapterHandlerEntry**)MetaspaceShared::misc_code_space_alloc(sizeof(AdapterHandlerEntry*));
+ *adapter_trampoline = NULL;
+ m->set_adapter_trampoline(to_target(adapter_trampoline));
+ }
+ }
+}
+
+void DynamicArchiveBuilder::make_klasses_shareable() {
+ int i, count = _klasses->length();
+
+ for (i = 0; i < count; i++) {
+ InstanceKlass* ik = _klasses->at(i);
+ sort_methods(ik);
+ }
+
+ for (i = 0; i < count; i++) {
+ InstanceKlass* ik = _klasses->at(i);
+ ClassLoaderData *cld = ik->class_loader_data();
+ if (cld->is_boot_class_loader_data()) {
+ ik->set_class_loader_type(ClassLoader::BOOT_LOADER);
+ }
+ else if (cld->is_platform_class_loader_data()) {
+ ik->set_class_loader_type(ClassLoader::PLATFORM_LOADER);
+ }
+ else if (cld->is_system_class_loader_data()) {
+ ik->set_class_loader_type(ClassLoader::APP_LOADER);
+ }
+
+ MetaspaceShared::rewrite_nofast_bytecodes_and_calculate_fingerprints(ik);
+ ik->remove_unshareable_info();
+
+ assert(ik->array_klasses() == NULL, "sanity");
+
+ if (log_is_enabled(Debug, cds, dynamic)) {
+ ResourceMark rm;
+ log_debug(cds, dynamic)("klasses[%4i] = " PTR_FORMAT " %s", i, p2i(to_target(ik)), ik->external_name());
+ }
+ }
+}
+
+// The address order of the copied Symbols may be different than when the original
+// klasses were created. Re-sort all the tables. See Method::sort_methods().
+void DynamicArchiveBuilder::sort_methods(InstanceKlass* ik) const {
+ assert(ik != NULL, "DynamicArchiveBuilder currently doesn't support dumping the base archive");
+ if (MetaspaceShared::is_in_shared_metaspace(ik)) {
+ // We have reached a supertype that's already in the base archive
+ return;
+ }
+
+ if (ik->java_mirror() == NULL) {
+ // NULL mirror means this class has already been visited and methods are already sorted
+ return;
+ }
+ ik->remove_java_mirror();
+
+ if (log_is_enabled(Debug, cds, dynamic)) {
+ ResourceMark rm;
+ log_debug(cds, dynamic)("sorting methods for " PTR_FORMAT " %s", p2i(to_target(ik)), ik->external_name());
+ }
+
+ // Make sure all supertypes have been sorted
+ sort_methods(ik->java_super());
+ Array<InstanceKlass*>* interfaces = ik->local_interfaces();
+ int len = interfaces->length();
+ for (int i = 0; i < len; i++) {
+ sort_methods(interfaces->at(i));
+ }
+
+#ifdef ASSERT
+ {
+ for (int m = 0; m < ik->methods()->length(); m++) {
+ Symbol* name = ik->methods()->at(m)->name();
+ assert(MetaspaceShared::is_in_shared_metaspace(name) || is_in_buffer_space(name), "must be");
+ }
+ }
+#endif
+
+ Thread* THREAD = Thread::current();
+ Method::sort_methods(ik->methods());
+ if (ik->default_methods() != NULL) {
+ Method::sort_methods(ik->default_methods(), /*set_idnums=*/false);
+ }
+ ik->vtable().initialize_vtable(true, THREAD); assert(!HAS_PENDING_EXCEPTION, "cannot fail");
+ ik->itable().initialize_itable(true, THREAD); assert(!HAS_PENDING_EXCEPTION, "cannot fail");
+}
+
+void DynamicArchiveBuilder::set_symbols_permanent() {
+ int count = _symbols->length();
+ for (int i=0; i<count; i++) {
+ Symbol* s = _symbols->at(i);
+ s->set_permanent();
+
+ if (log_is_enabled(Trace, cds, dynamic)) {
+ ResourceMark rm;
+ log_trace(cds, dynamic)("symbols[%4i] = " PTR_FORMAT " %s", i, p2i(to_target(s)), s->as_quoted_ascii());
+ }
+ }
+}
+
+class RelocateBufferToTarget: public BitMapClosure {
+ DynamicArchiveBuilder *_builder;
+ address* _buffer_bottom;
+ intx _buffer_to_target_delta;
+ public:
+ RelocateBufferToTarget(DynamicArchiveBuilder* builder, address* bottom, intx delta) :
+ _builder(builder), _buffer_bottom(bottom), _buffer_to_target_delta(delta) {}
+
+ bool do_bit(size_t offset) {
+ address* p = _buffer_bottom + offset;
+ assert(_builder->is_in_buffer_space(p), "pointer must live in buffer space");
+
+ address old_ptr = *p;
+ if (_builder->is_in_buffer_space(old_ptr)) {
+ address new_ptr = old_ptr + _buffer_to_target_delta;
+ log_trace(cds, dynamic)("Final patch: @%6d [" PTR_FORMAT " -> " PTR_FORMAT "] " PTR_FORMAT " => " PTR_FORMAT,
+ (int)offset, p2i(p), p2i(_builder->to_target(p)),
+ p2i(old_ptr), p2i(new_ptr));
+ *p = new_ptr;
+ }
+
+ return true; // keep iterating
+ }
+};
+
+
+void DynamicArchiveBuilder::relocate_buffer_to_target() {
+ RelocateBufferToTarget patcher(this, (address*)_alloc_bottom, _buffer_to_target_delta);
+ _ptrmap.iterate(&patcher);
+
+ Array<u8>* table = _header->_shared_path_table.table();
+ table = to_target(table);
+ _header->_shared_path_table.set_table(table);
+}
+
+static void write_archive_info(FileMapInfo* dynamic_info, DynamicArchiveHeader *header) {
+ dynamic_info->write_header();
+ dynamic_info->align_file_position();
+ dynamic_info->write_region(MetaspaceShared::rw,
+ MetaspaceShared::read_write_dump_space()->base(),
+ MetaspaceShared::read_write_dump_space()->used(),
+ /*read_only=*/false,/*allow_exec=*/false);
+ dynamic_info->write_region(MetaspaceShared::ro,
+ MetaspaceShared::read_only_dump_space()->base(),
+ MetaspaceShared::read_only_dump_space()->used(),
+ /*read_only=*/true, /*allow_exec=*/false);
+ dynamic_info->write_region(MetaspaceShared::mc,
+ MetaspaceShared::misc_code_dump_space()->base(),
+ MetaspaceShared::misc_code_dump_space()->used(),
+ /*read_only=*/false,/*allow_exec=*/true);
+}
+
+void DynamicArchiveBuilder::write_archive(char* read_only_tables_start) {
+ int num_klasses = _klasses->length();
+ int num_symbols = _symbols->length();
+
+ _header->_read_only_tables_start = to_target(read_only_tables_start);
+
+ FileMapInfo* dynamic_info = FileMapInfo::dynamic_info();
+ assert(dynamic_info != NULL, "Sanity");
+
+ // Populate the file offsets, region crcs, etc. No data is written out.
+ write_archive_info(dynamic_info, _header);
+
+ // the header will no longer change. Compute its crc.
+ dynamic_info->set_header_crc(dynamic_info->compute_header_crc());
+
+ // Now write the archived data including the file offsets.
+ const char* archive_name = Arguments::GetSharedDynamicArchivePath();
+ dynamic_info->open_for_write(archive_name);
+ write_archive_info(dynamic_info, _header);
+ dynamic_info->close();
+
+
+ address base = to_target(_alloc_bottom);
+ address top = address(current_dump_space()->top()) + _buffer_to_target_delta;
+ int file_size = int(top - base);
+
+ log_info(cds, dynamic)("Written dynamic archive " PTR_FORMAT " - " PTR_FORMAT " [%d bytes header, %d bytes total]",
+ p2i(base), p2i(top), (int)_header->_header_size, file_size);
+ log_info(cds, dynamic)("%d klasses; %d symbols", num_klasses, num_symbols);
+}
+
+
+class VM_PopulateDynamicDumpSharedSpace: public VM_Operation {
+ DynamicArchiveBuilder* _builder;
+public:
+ VM_PopulateDynamicDumpSharedSpace(DynamicArchiveBuilder* builder) : _builder(builder) {}
+ VMOp_Type type() const { return VMOp_PopulateDumpSharedSpace; }
+ void doit() {
+ ResourceMark rm;
+ if (SystemDictionaryShared::empty_dumptime_table()) {
+ log_warning(cds, dynamic)("There is no class to be included in the dynamic archive.");
+ return;
+ }
+ if (AllowArchivingWithJavaAgent) {
+ warning("This archive was created with AllowArchivingWithJavaAgent. It should be used "
+ "for testing purposes only and should not be used in a production environment");
+ }
+ FileMapInfo::check_nonempty_dir_in_shared_path_table();
+
+ _builder->doit();
+ }
+};
+
+
+void DynamicArchive::dump() {
+ if (Arguments::GetSharedDynamicArchivePath() == NULL) {
+ log_warning(cds, dynamic)("SharedDynamicArchivePath is not specified");
+ return;
+ }
+
+ DynamicArchiveBuilder builder;
+ _builder = &builder;
+ VM_PopulateDynamicDumpSharedSpace op(&builder);
+ VMThread::execute(&op);
+ _builder = NULL;
+}
+
+address DynamicArchive::original_to_buffer_impl(address orig_obj) {
+ assert(DynamicDumpSharedSpaces, "must be");
+ address buff_obj = _builder->get_new_loc(orig_obj);
+ assert(buff_obj != NULL, "orig_obj must be used by the dynamic archive");
+ assert(buff_obj != orig_obj, "call this only when you know orig_obj must be copied and not just referenced");
+ assert(_builder->is_in_buffer_space(buff_obj), "must be");
+ return buff_obj;
+}
+
+address DynamicArchive::buffer_to_target_impl(address buff_obj) {
+ assert(DynamicDumpSharedSpaces, "must be");
+ assert(_builder->is_in_buffer_space(buff_obj), "must be");
+ return _builder->to_target(buff_obj);
+}
+
+address DynamicArchive::original_to_target_impl(address orig_obj) {
+ assert(DynamicDumpSharedSpaces, "must be");
+ if (MetaspaceShared::is_in_shared_metaspace(orig_obj)) {
+ // This happens when the top archive points to a Symbol* in the base archive.
+ return orig_obj;
+ }
+ address buff_obj = _builder->get_new_loc(orig_obj);
+ assert(buff_obj != NULL, "orig_obj must be used by the dynamic archive");
+ if (buff_obj == orig_obj) {
+ // We are storing a pointer to an original object into the dynamic buffer. E.g.,
+ // a Symbol* that used by both the base and top archives.
+ assert(MetaspaceShared::is_in_shared_metaspace(orig_obj), "must be");
+ return orig_obj;
+ } else {
+ return _builder->to_target(buff_obj);
+ }
+}
+
+uintx DynamicArchive::object_delta_uintx(void* buff_obj) {
+ assert(DynamicDumpSharedSpaces, "must be");
+ address target_obj = _builder->to_target_no_check(address(buff_obj));
+ assert(uintx(target_obj) >= SharedBaseAddress, "must be");
+ return uintx(target_obj) - SharedBaseAddress;
+}
+
+bool DynamicArchive::is_in_target_space(void *obj) {
+ assert(DynamicDumpSharedSpaces, "must be");
+ return _builder->is_in_target_space(obj);
+}
+
+
+static DynamicArchiveHeader *_dynamic_header = NULL;
+DynamicArchiveBuilder* DynamicArchive::_builder = NULL;
+
+void DynamicArchive::map_failed(FileMapInfo* mapinfo) {
+ if (mapinfo->_header != NULL) {
+ os::free(mapinfo->_header);
+ }
+ delete mapinfo;
+}
+
+// Returns the top of the mapped address space
+address DynamicArchive::map() {
+ assert(UseSharedSpaces, "Sanity");
+
+ // Create the dynamic archive map info
+ FileMapInfo* mapinfo;
+ const char* filename = Arguments::GetSharedDynamicArchivePath();
+ struct stat st;
+ address result;
+ if ((filename != NULL) && (os::stat(filename, &st) == 0)) {
+ mapinfo = new FileMapInfo(false);
+ if (!mapinfo->open_for_read(filename)) {
+ result = NULL;
+ }
+ result = map_impl(mapinfo);
+ if (result == NULL) {
+ map_failed(mapinfo);
+ mapinfo->restore_shared_path_table();
+ }
+ } else {
+ if (filename != NULL) {
+ log_warning(cds, dynamic)("specified dynamic archive doesn't exist: %s", filename);
+ }
+ result = NULL;
+ }
+ return result;
+}
+
+address DynamicArchive::map_impl(FileMapInfo* mapinfo) {
+
+
+ // Read header
+ if (!mapinfo->initialize(false)) {
+ return NULL;
+ }
+
+ _dynamic_header = (DynamicArchiveHeader*)mapinfo->header();
+
+ int regions[] = {MetaspaceShared::rw,
+ MetaspaceShared::ro,
+ MetaspaceShared::mc};
+
+ size_t len = sizeof(regions)/sizeof(int);
+ char* saved_base[] = {NULL, NULL, NULL};
+ char* top = mapinfo->map_regions(regions, saved_base, len);
+ if (top == NULL) {
+ mapinfo->unmap_regions(regions, saved_base, len);
+ FileMapInfo::fail_continue("Unable to use dynamic archive. Failed map_region for using -Xshare:on.");
+ return NULL;
+ }
+
+ if (!validate(mapinfo)) {
+ return NULL;
+ }
+
+ if (_dynamic_header == NULL) {
+ return NULL;
+ }
+
+ intptr_t* buffer = (intptr_t*)_dynamic_header->_read_only_tables_start;
+ ReadClosure rc(&buffer);
+ SymbolTable::serialize_shared_table_header(&rc, false);
+ SystemDictionaryShared::serialize_dictionary_headers(&rc, false);
+
+ return (address)top;
+}
+
+bool DynamicArchive::validate(FileMapInfo* dynamic_info) {
+ // Check if the recorded base archive matches with the current one
+ FileMapInfo* base_info = FileMapInfo::current_info();
+ DynamicArchiveHeader* dynamic_header = (DynamicArchiveHeader*)dynamic_info->header();
+ int* crc = dynamic_header->_base_archive_crc;
+
+ // Check the header crc
+ if (*crc++ != base_info->crc()) {
+ FileMapInfo::fail_continue("Archive header checksum verification failed.");
+ return false;
+ }
+
+ // Check each space's crc
+ for (int i = 0; i < MetaspaceShared::n_regions; i++) {
+ if (*crc++ != base_info->space_crc(i)) {
+ FileMapInfo::fail_continue("Archive region #%d checksum verification failed.", i);
+ return false;
+ }
+ }
+
+ // Validate the dynamic archived shared path table, and set the global
+ // _shared_path_table to that.
+ if (!dynamic_info->validate_shared_path_table()) {
+ return false;
+ }
+ return true;
+}
+
+bool DynamicArchive::is_mapped() {
+ return (_dynamic_header != NULL);
+}
+
+void DynamicArchive::disable() {
+ _dynamic_header = NULL;
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/hotspot/share/memory/dynamicArchive.hpp Thu May 23 11:07:37 2019 +0100
@@ -0,0 +1,99 @@
+/*
+ * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#ifndef SHARE_VM_MEMORY_DYNAMICARCHIVE_HPP
+#define SHARE_VM_MEMORY_DYNAMICARCHIVE_HPP
+
+#if INCLUDE_CDS
+
+#include "classfile/compactHashtable.hpp"
+#include "memory/allocation.hpp"
+#include "memory/filemap.hpp"
+#include "memory/memRegion.hpp"
+#include "memory/virtualspace.hpp"
+#include "oops/oop.hpp"
+#include "utilities/exceptions.hpp"
+#include "utilities/macros.hpp"
+#include "utilities/resourceHash.hpp"
+
+// We want to include all archive header information in the dynamic archive.
+// This helps simplify the process if the base layer archive is missing at
+// dynamic archiving time.
+struct DynamicArchiveHeader : public FileMapHeader {
+ // crc for the base archive header and regions
+ int _base_archive_crc[MetaspaceShared::n_regions+1];
+};
+
+class DynamicArchive : AllStatic {
+ static class DynamicArchiveBuilder* _builder;
+ static address original_to_target_impl(address orig_obj);
+ static address original_to_buffer_impl(address orig_obj);
+ static address buffer_to_target_impl(address buff_obj);
+
+public:
+ static void dump();
+
+ // obj is a copy of a MetaspaceObj, stored in the dumping buffer.
+ //
+ // The return value is the runtime targeted location of this object as
+ // mapped from the dynamic archive.
+ template <typename T> static T buffer_to_target(T buff_obj) {
+ return (T)buffer_to_target_impl(address(buff_obj));
+ }
+
+ // obj is an original MetaspaceObj used by the JVM (e.g., a valid Symbol* in the
+ // SymbolTable).
+ //
+ // The return value is the runtime targeted location of this object as
+ // mapped from the dynamic archive.
+ template <typename T> static T original_to_target(T obj) {
+ return (T)original_to_target_impl(address(obj));
+ }
+
+ // obj is an original MetaspaceObj use by the JVM (e.g., a valid Symbol* in the
+ // SymbolTable).
+ //
+ // The return value is the location of this object in the dump time
+ // buffer space
+ template <typename T> static T original_to_buffer(T obj) {
+ return (T)original_to_buffer_impl(address(obj));
+ }
+
+ // Delta of this object from SharedBaseAddress
+ static uintx object_delta_uintx(void* buff_obj);
+
+ // Does obj point to an address inside the runtime target space of the dynamic
+ // archive?
+ static bool is_in_target_space(void *obj);
+
+ static address map();
+ static bool is_mapped();
+ static bool validate(FileMapInfo* dynamic_info);
+ static void disable();
+private:
+ static address map_impl(FileMapInfo* mapinfo);
+ static void map_failed(FileMapInfo* mapinfo);
+};
+#endif // INCLUDE_CDS
+#endif // SHARE_VM_MEMORY_DYNAMICARCHIVE_HPP
--- a/src/hotspot/share/memory/filemap.cpp Fri May 17 13:21:44 2019 +0100
+++ b/src/hotspot/share/memory/filemap.cpp Thu May 23 11:07:37 2019 +0100
@@ -34,6 +34,7 @@
#include "logging/log.hpp"
#include "logging/logStream.hpp"
#include "logging/logMessage.hpp"
+#include "memory/dynamicArchive.hpp"
#include "memory/filemap.hpp"
#include "memory/heapShared.inline.hpp"
#include "memory/iterator.inline.hpp"
@@ -42,6 +43,7 @@
#include "memory/metaspaceShared.hpp"
#include "memory/oopFactory.hpp"
#include "memory/universe.hpp"
+#include "oops/compressedOops.hpp"
#include "oops/compressedOops.inline.hpp"
#include "oops/objArrayOop.hpp"
#include "oops/oop.inline.hpp"
@@ -101,7 +103,12 @@
void FileMapInfo::fail_continue(const char *msg, ...) {
va_list ap;
va_start(ap, msg);
- MetaspaceShared::set_archive_loading_failed();
+ if (_dynamic_archive_info == NULL) {
+ MetaspaceShared::set_archive_loading_failed();
+ } else {
+ // _dynamic_archive_info has been setup after mapping the base archive
+ DynamicArchive::disable();
+ }
if (PrintSharedArchiveAndExit && _validating_shared_path_table) {
// If we are doing PrintSharedArchiveAndExit and some of the classpath entries
// do not validate, we can still continue "limping" to validate the remaining
@@ -120,9 +127,15 @@
ls.vprint_cr(msg, ap);
}
}
- UseSharedSpaces = false;
- assert(current_info() != NULL, "singleton must be registered");
- current_info()->close();
+ if (_dynamic_archive_info == NULL) {
+ UseSharedSpaces = false;
+ assert(current_info() != NULL, "singleton must be registered");
+ current_info()->close();
+ } else {
+ // We are failing when loading the top archive, but the base archive should
+ // continue to work.
+ log_warning(cds, dynamic)("Unable to use shared archive. The top archive failed to load: %s", _dynamic_archive_info->_full_path);
+ }
}
va_end(ap);
}
@@ -159,20 +172,36 @@
}
}
-FileMapInfo::FileMapInfo() {
- assert(_current_info == NULL, "must be singleton"); // not thread safe
- _current_info = this;
+FileMapInfo::FileMapInfo(bool is_static) {
memset((void*)this, 0, sizeof(FileMapInfo));
+ _is_static = is_static;
+ size_t header_size;
+ if (is_static) {
+ assert(_current_info == NULL, "must be singleton"); // not thread safe
+ _current_info = this;
+ header_size = sizeof(FileMapHeader);
+ } else {
+ assert(_dynamic_archive_info == NULL, "must be singleton"); // not thread safe
+ _dynamic_archive_info = this;
+ header_size = sizeof(DynamicArchiveHeader);
+ }
+ _header = (FileMapHeader*)os::malloc(header_size, mtInternal);
+ memset((void*)_header, 0, header_size);
+ _header->_header_size = header_size;
+ _header->_version = INVALID_CDS_ARCHIVE_VERSION;
+ _header->_has_platform_or_app_classes = true;
_file_offset = 0;
_file_open = false;
- _header = (FileMapHeader*)os::malloc(sizeof(FileMapHeader), mtInternal);
- _header->_version = INVALID_CDS_ARCHIVE_VERSION;
- _header->_has_platform_or_app_classes = true;
}
FileMapInfo::~FileMapInfo() {
- assert(_current_info == this, "must be singleton"); // not thread safe
- _current_info = NULL;
+ if (_is_static) {
+ assert(_current_info == this, "must be singleton"); // not thread safe
+ _current_info = NULL;
+ } else {
+ assert(_dynamic_archive_info == this, "must be singleton"); // not thread safe
+ _dynamic_archive_info = NULL;
+ }
}
void FileMapInfo::populate_header(size_t alignment) {
@@ -180,7 +209,11 @@
}
void FileMapHeader::populate(FileMapInfo* mapinfo, size_t alignment) {
- _magic = CDS_ARCHIVE_MAGIC;
+ if (DynamicDumpSharedSpaces) {
+ _magic = CDS_DYNAMIC_ARCHIVE_MAGIC;
+ } else {
+ _magic = CDS_ARCHIVE_MAGIC;
+ }
_version = CURRENT_CDS_ARCHIVE_VERSION;
_alignment = alignment;
_obj_alignment = ObjectAlignmentInBytes;
@@ -191,9 +224,7 @@
_max_heap_size = MaxHeapSize;
_narrow_klass_base = CompressedKlassPointers::base();
_narrow_klass_shift = CompressedKlassPointers::shift();
- _shared_path_table_size = mapinfo->_shared_path_table_size;
_shared_path_table = mapinfo->_shared_path_table;
- _shared_path_entry_size = mapinfo->_shared_path_entry_size;
if (HeapShared::is_heap_object_archiving_allowed()) {
_heap_reserved = Universe::heap()->reserved_region();
}
@@ -208,6 +239,7 @@
ClassLoaderExt::finalize_shared_paths_misc_info();
_app_class_paths_start_index = ClassLoaderExt::app_class_paths_start_index();
_app_module_paths_start_index = ClassLoaderExt::app_module_paths_start_index();
+ _num_module_paths = ClassLoader::num_module_path_entries();
_max_used_path_index = ClassLoaderExt::max_used_path_index();
_verify_local = BytecodeVerificationLocal;
@@ -215,10 +247,13 @@
_has_platform_or_app_classes = ClassLoaderExt::has_platform_or_app_classes();
_shared_base_address = SharedBaseAddress;
_allow_archiving_with_java_agent = AllowArchivingWithJavaAgent;
+ // the following 2 fields will be set in write_header for dynamic archive header
+ _base_archive_name_size = 0;
+ _base_archive_is_default = false;
}
void SharedClassPathEntry::init(const char* name, bool is_modules_image, TRAPS) {
- assert(DumpSharedSpaces, "dump time only");
+ assert(DumpSharedSpaces || DynamicDumpSharedSpaces, "dump time only");
_timestamp = 0;
_filesize = 0;
@@ -297,6 +332,7 @@
// If PrintSharedArchiveAndExit is enabled, don't report failure to the
// caller. Please see above comments for more details.
ok = true;
+ MetaspaceShared::set_archive_loading_failed();
}
return ok;
}
@@ -306,8 +342,27 @@
it->push(&_manifest);
}
+void SharedPathTable::metaspace_pointers_do(MetaspaceClosure* it) {
+ it->push(&_table);
+ for (int i=0; i<_size; i++) {
+ path_at(i)->metaspace_pointers_do(it);
+ }
+}
+
+void SharedPathTable::dumptime_init(ClassLoaderData* loader_data, Thread* THREAD) {
+ size_t entry_size = sizeof(SharedClassPathEntry);
+ int num_boot_classpath_entries = ClassLoader::num_boot_classpath_entries();
+ int num_app_classpath_entries = ClassLoader::num_app_classpath_entries();
+ int num_module_path_entries = ClassLoader::num_module_path_entries();
+ int num_entries = num_boot_classpath_entries + num_app_classpath_entries + num_module_path_entries;
+ size_t bytes = entry_size * num_entries;
+
+ _table = MetadataFactory::new_array<u8>(loader_data, (int)(bytes + 7 / 8), THREAD);
+ _size = num_entries;
+}
+
void FileMapInfo::allocate_shared_path_table() {
- assert(DumpSharedSpaces, "Sanity");
+ assert(DumpSharedSpaces || DynamicDumpSharedSpaces, "Sanity");
Thread* THREAD = Thread::current();
ClassLoaderData* loader_data = ClassLoaderData::the_null_class_loader_data();
@@ -316,16 +371,7 @@
assert(jrt != NULL,
"No modular java runtime image present when allocating the CDS classpath entry table");
- size_t entry_size = sizeof(SharedClassPathEntry); // assert ( should be 8 byte aligned??)
- int num_boot_classpath_entries = ClassLoader::num_boot_classpath_entries();
- int num_app_classpath_entries = ClassLoader::num_app_classpath_entries();
- int num_module_path_entries = ClassLoader::num_module_path_entries();
- int num_entries = num_boot_classpath_entries + num_app_classpath_entries + num_module_path_entries;
- size_t bytes = entry_size * num_entries;
-
- _shared_path_table = MetadataFactory::new_array<u8>(loader_data, (int)(bytes + 7 / 8), THREAD);
- _shared_path_table_size = num_entries;
- _shared_path_entry_size = entry_size;
+ _shared_path_table.dumptime_init(loader_data, THREAD);
// 1. boot class path
int i = 0;
@@ -343,7 +389,7 @@
cpe = ClassLoader::get_next_boot_classpath_entry(cpe);
i++;
}
- assert(i == num_boot_classpath_entries,
+ assert(i == ClassLoader::num_boot_classpath_entries(),
"number of boot class path entry mismatch");
// 2. app class path
@@ -369,15 +415,15 @@
mpe = mpe->next();
i++;
}
- assert(i == num_entries, "number of shared path entry mismatch");
+ assert(i == _shared_path_table.size(), "number of shared path entry mismatch");
}
void FileMapInfo::check_nonempty_dir_in_shared_path_table() {
- assert(DumpSharedSpaces, "dump time only");
+ assert(DumpSharedSpaces || DynamicDumpSharedSpaces, "dump time only");
bool has_nonempty_dir = false;
- int last = _shared_path_table_size - 1;
+ int last = _shared_path_table.size() - 1;
if (last > ClassLoaderExt::max_used_path_index()) {
// no need to check any path beyond max_used_path_index
last = ClassLoaderExt::max_used_path_index();
@@ -479,9 +525,29 @@
assert(UseSharedSpaces, "runtime only");
_validating_shared_path_table = true;
+
+ // Load the shared path table info from the archive header
_shared_path_table = _header->_shared_path_table;
- _shared_path_entry_size = _header->_shared_path_entry_size;
- _shared_path_table_size = _header->_shared_path_table_size;
+ if (DynamicDumpSharedSpaces) {
+ // Only support dynamic dumping with the usage of the default CDS archive
+ // or a simple base archive.
+ // If the base layer archive contains additional path component besides
+ // the runtime image and the -cp, dynamic dumping is disabled.
+ //
+ // When dynamic archiving is enabled, the _shared_path_table is overwritten
+ // to include the application path and stored in the top layer archive.
+ assert(shared_path(0)->is_modules_image(), "first shared_path must be the modules image");
+ if (_header->_app_class_paths_start_index > 1) {
+ DynamicDumpSharedSpaces = false;
+ warning(
+ "Dynamic archiving is disabled because base layer archive has appended boot classpath");
+ }
+ if (_header->_num_module_paths > 0) {
+ DynamicDumpSharedSpaces = false;
+ warning(
+ "Dynamic archiving is disabled because base layer archive has module path");
+ }
+ }
int module_paths_start_index = _header->_app_module_paths_start_index;
@@ -491,14 +557,18 @@
if (shared_path(i)->validate()) {
log_info(class, path)("ok");
} else {
- assert(!UseSharedSpaces, "UseSharedSpaces should be disabled");
+ if (_dynamic_archive_info != NULL && _dynamic_archive_info->_is_static) {
+ assert(!UseSharedSpaces, "UseSharedSpaces should be disabled");
+ }
return false;
}
} else if (i >= module_paths_start_index) {
if (shared_path(i)->validate(false /* not a class path entry */)) {
log_info(class, path)("ok");
} else {
- assert(!UseSharedSpaces, "UseSharedSpaces should be disabled");
+ if (_dynamic_archive_info != NULL && _dynamic_archive_info->_is_static) {
+ assert(!UseSharedSpaces, "UseSharedSpaces should be disabled");
+ }
return false;
}
}
@@ -510,18 +580,151 @@
if (_classpath_entries_for_jvmti != NULL) {
os::free(_classpath_entries_for_jvmti);
}
- size_t sz = sizeof(ClassPathEntry*) * _shared_path_table_size;
+ size_t sz = sizeof(ClassPathEntry*) * get_number_of_shared_paths();
_classpath_entries_for_jvmti = (ClassPathEntry**)os::malloc(sz, mtClass);
- memset(_classpath_entries_for_jvmti, 0, sz);
+ memset((void*)_classpath_entries_for_jvmti, 0, sz);
#endif
return true;
}
+bool FileMapInfo::same_files(const char* file1, const char* file2) {
+ if (strcmp(file1, file2) == 0) {
+ return true;
+ }
+
+ bool is_same = false;
+ // if the two paths diff only in case
+ struct stat st1;
+ struct stat st2;
+ int ret1;
+ int ret2;
+ ret1 = os::stat(file1, &st1);
+ ret2 = os::stat(file2, &st2);
+ if (ret1 < 0 || ret2 < 0) {
+ // one of the files is invalid. So they are not the same.
+ is_same = false;
+ } else if (st1.st_dev != st2.st_dev || st1.st_ino != st2.st_ino) {
+ // different files
+ is_same = false;
+#ifndef _WINDOWS
+ } else if (st1.st_dev == st2.st_dev && st1.st_ino == st2.st_ino) {
+ // same files
+ is_same = true;
+#else
+ } else if ((st1.st_size == st2.st_size) && (st1.st_ctime == st2.st_ctime) &&
+ (st1.st_mtime == st2.st_mtime)) {
+ // same files
+ is_same = true;
+#endif
+ }
+ return is_same;
+}
+
+bool FileMapInfo::check_archive(const char* archive_name, bool is_static) {
+ int fd = os::open(archive_name, O_RDONLY | O_BINARY, 0);
+ if (fd < 0) {
+ // do not vm_exit_during_initialization here because Arguments::init_shared_archive_paths()
+ // requires a shared archive name. The open_for_read() function will log a message regarding
+ // failure in opening a shared archive.
+ return false;
+ }
+
+ size_t sz = is_static ? sizeof(FileMapHeader) : sizeof(DynamicArchiveHeader);
+ void* header = os::malloc(sz, mtInternal);
+ memset(header, 0, sz);
+ size_t n = os::read(fd, header, (unsigned int)sz);
+ if (n != sz) {
+ os::free(header);
+ os::close(fd);
+ vm_exit_during_initialization("Unable to read header from shared archive", archive_name);
+ return false;
+ }
+ if (is_static) {
+ FileMapHeader* static_header = (FileMapHeader*)header;
+ if (static_header->_magic != CDS_ARCHIVE_MAGIC) {
+ os::free(header);
+ os::close(fd);
+ vm_exit_during_initialization("Not a base shared archive", archive_name);
+ return false;
+ }
+ } else {
+ DynamicArchiveHeader* dynamic_header = (DynamicArchiveHeader*)header;
+ if (dynamic_header->_magic != CDS_DYNAMIC_ARCHIVE_MAGIC) {
+ os::free(header);
+ os::close(fd);
+ vm_exit_during_initialization("Not a top shared archive", archive_name);
+ return false;
+ }
+ }
+ os::free(header);
+ os::close(fd);
+ return true;
+}
+
+bool FileMapInfo::get_base_archive_name_from_header(const char* archive_name,
+ int* size, char** base_archive_name) {
+ int fd = os::open(archive_name, O_RDONLY | O_BINARY, 0);
+ if (fd < 0) {
+ *size = 0;
+ return false;
+ }
+
+ // read the header as a dynamic archive header
+ size_t sz = sizeof(DynamicArchiveHeader);
+ DynamicArchiveHeader* dynamic_header = (DynamicArchiveHeader*)os::malloc(sz, mtInternal);
+ size_t n = os::read(fd, dynamic_header, (unsigned int)sz);
+ if (n != sz) {
+ fail_continue("Unable to read the file header.");
+ os::free(dynamic_header);
+ os::close(fd);
+ return false;
+ }
+ if (dynamic_header->_magic != CDS_DYNAMIC_ARCHIVE_MAGIC) {
+ // Not a dynamic header, no need to proceed further.
+ *size = 0;
+ os::free(dynamic_header);
+ os::close(fd);
+ return false;
+ }
+ if (dynamic_header->_base_archive_is_default) {
+ *base_archive_name = Arguments::get_default_shared_archive_path();
+ } else {
+ // skip over the _paths_misc_info
+ sz = dynamic_header->_paths_misc_info_size;
+ lseek(fd, (long)sz, SEEK_CUR);
+ // read the base archive name
+ size_t name_size = dynamic_header->_base_archive_name_size;
+ if (name_size == 0) {
+ os::free(dynamic_header);
+ os::close(fd);
+ return false;
+ }
+ *base_archive_name = NEW_C_HEAP_ARRAY(char, name_size, mtInternal);
+ n = os::read(fd, *base_archive_name, (unsigned int)name_size);
+ if (n != name_size) {
+ fail_continue("Unable to read the base archive name from the header.");
+ FREE_C_HEAP_ARRAY(char, *base_archive_name);
+ *base_archive_name = NULL;
+ os::free(dynamic_header);
+ os::close(fd);
+ return false;
+ }
+ }
+
+ os::free(dynamic_header);
+ os::close(fd);
+ return true;
+}
+
+void FileMapInfo::restore_shared_path_table() {
+ _shared_path_table = _current_info->_header->_shared_path_table;
+}
+
// Read the FileMapInfo information from the file.
-bool FileMapInfo::init_from_file(int fd) {
- size_t sz = sizeof(FileMapHeader);
+bool FileMapInfo::init_from_file(int fd, bool is_static) {
+ size_t sz = is_static ? sizeof(FileMapHeader) : sizeof(DynamicArchiveHeader);
size_t n = os::read(fd, _header, (unsigned int)sz);
if (n != sz) {
fail_continue("Unable to read the file header.");
@@ -531,14 +734,10 @@
fail_continue("The shared archive file has the wrong version.");
return false;
}
- _file_offset = (long)n;
+ _file_offset = n;
size_t info_size = _header->_paths_misc_info_size;
- _paths_misc_info = NEW_C_HEAP_ARRAY_RETURN_NULL(char, info_size, mtClass);
- if (_paths_misc_info == NULL) {
- fail_continue("Unable to read the file header.");
- return false;
- }
+ _paths_misc_info = NEW_C_HEAP_ARRAY(char, info_size, mtClass);
n = os::read(fd, _paths_misc_info, (unsigned int)info_size);
if (n != info_size) {
fail_continue("Unable to read the shared path info header.");
@@ -546,29 +745,45 @@
_paths_misc_info = NULL;
return false;
}
+ _file_offset += n + _header->_base_archive_name_size; // accounts for the size of _base_archive_name
- size_t len = lseek(fd, 0, SEEK_END);
- CDSFileMapRegion* si = space_at(MetaspaceShared::last_valid_region);
- // The last space might be empty
- if (si->_file_offset > len || len - si->_file_offset < si->_used) {
- fail_continue("The shared archive file has been truncated.");
- return false;
+ if (is_static) {
+ if (_header->_magic != CDS_ARCHIVE_MAGIC) {
+ fail_continue("Incorrect static archive magic number");
+ return false;
+ }
+ // just checking the last region is sufficient since the archive is written
+ // in sequential order
+ size_t len = lseek(fd, 0, SEEK_END);
+ CDSFileMapRegion* si = space_at(MetaspaceShared::last_valid_region);
+ // The last space might be empty
+ if (si->_file_offset > len || len - si->_file_offset < si->_used) {
+ fail_continue("The shared archive file has been truncated.");
+ return false;
+ }
+
+ SharedBaseAddress = _header->_shared_base_address;
}
- _file_offset += (long)n;
- SharedBaseAddress = _header->_shared_base_address;
return true;
}
// Read the FileMapInfo information from the file.
-bool FileMapInfo::open_for_read() {
- _full_path = Arguments::GetSharedArchivePath();
+bool FileMapInfo::open_for_read(const char* path) {
+ if (_file_open) {
+ return true;
+ }
+ if (path == NULL) {
+ _full_path = Arguments::GetSharedArchivePath();
+ } else {
+ _full_path = path;
+ }
int fd = os::open(_full_path, O_RDONLY | O_BINARY, 0);
if (fd < 0) {
if (errno == ENOENT) {
// Not locating the shared archive is ok.
- fail_continue("Specified shared archive not found.");
+ fail_continue("Specified shared archive not found (%s).", _full_path);
} else {
fail_continue("Failed to open shared archive file (%s).",
os::strerror(errno));
@@ -581,11 +796,14 @@
return true;
}
-
// Write the FileMapInfo information to the file.
-void FileMapInfo::open_for_write() {
- _full_path = Arguments::GetSharedArchivePath();
+void FileMapInfo::open_for_write(const char* path) {
+ if (path == NULL) {
+ _full_path = Arguments::GetSharedArchivePath();
+ } else {
+ _full_path = path;
+ }
LogMessage(cds) msg;
if (msg.is_info()) {
msg.info("Dumping shared data to file: ");
@@ -593,7 +811,7 @@
}
#ifdef _WINDOWS // On Windows, need WRITE permission to remove the file.
- chmod(_full_path, _S_IREAD | _S_IWRITE);
+ chmod(_full_path, _S_IREAD | _S_IWRITE);
#endif
// Use remove() to delete the existing file because, on Unix, this will
@@ -617,40 +835,59 @@
_header->_paths_misc_info_size = info_size;
- align_file_position();
- write_bytes(_header, sizeof(FileMapHeader));
+ char* base_archive_name = NULL;
+ if (_header->_magic == CDS_DYNAMIC_ARCHIVE_MAGIC) {
+ base_archive_name = (char*)Arguments::GetSharedArchivePath();
+ _header->_base_archive_name_size = (int)strlen(base_archive_name) + 1;
+ _header->_base_archive_is_default = FLAG_IS_DEFAULT(SharedArchiveFile);
+ }
+
+ assert(is_file_position_aligned(), "must be");
+ write_bytes(_header, _header->_header_size);
write_bytes(ClassLoader::get_shared_paths_misc_info(), (size_t)info_size);
+ if (base_archive_name != NULL) {
+ write_bytes(base_archive_name, (size_t)_header->_base_archive_name_size);
+ }
align_file_position();
}
-
// Dump region to file.
-
+// This is called twice for each region during archiving, once before
+// the archive file is open (_file_open is false) and once after.
void FileMapInfo::write_region(int region, char* base, size_t size,
bool read_only, bool allow_exec) {
+ assert(DumpSharedSpaces || DynamicDumpSharedSpaces, "Dump time only");
+
CDSFileMapRegion* si = space_at(region);
+ char* target_base = base;
+ if (DynamicDumpSharedSpaces) {
+ target_base = DynamicArchive::buffer_to_target(base);
+ }
if (_file_open) {
guarantee(si->_file_offset == _file_offset, "file offset mismatch.");
log_info(cds)("Shared file region %d: " SIZE_FORMAT_HEX_W(08)
" bytes, addr " INTPTR_FORMAT " file offset " SIZE_FORMAT_HEX_W(08),
- region, size, p2i(base), _file_offset);
+ region, size, p2i(target_base), _file_offset);
} else {
si->_file_offset = _file_offset;
}
+
if (HeapShared::is_heap_region(region)) {
- assert((base - (char*)CompressedOops::base()) % HeapWordSize == 0, "Sanity");
- if (base != NULL) {
- si->_addr._offset = (intx)CompressedOops::encode_not_null((oop)base);
+ assert((target_base - (char*)CompressedKlassPointers::base()) % HeapWordSize == 0, "Sanity");
+ if (target_base != NULL) {
+ si->_addr._offset = (intx)CompressedOops::encode_not_null((oop)target_base);
} else {
si->_addr._offset = 0;
}
} else {
- si->_addr._base = base;
+ si->_addr._base = target_base;
}
si->_used = size;
si->_read_only = read_only;
si->_allow_exec = allow_exec;
+
+ // Use the current 'base' when computing the CRC value and writing out data
si->_crc = ClassLoader::crc32(0, base, (jint)size);
if (base != NULL) {
write_bytes_aligned(base, size);
@@ -734,8 +971,7 @@
if (_file_open) {
size_t n = os::write(_fd, buffer, (unsigned int)nbytes);
if (n != nbytes) {
- // It is dangerous to leave the corrupted shared archive file around,
- // close and remove the file. See bug 6372906.
+ // If the shared archive is corrupted, close it and remove it.
close();
remove(_full_path);
fail_stop("Unable to write to shared archive file.");
@@ -744,6 +980,10 @@
_file_offset += nbytes;
}
+bool FileMapInfo::is_file_position_aligned() const {
+ return _file_offset == align_up(_file_offset,
+ os::vm_allocation_granularity());
+}
// Align file position to an allocation unit boundary.
@@ -843,6 +1083,30 @@
static const char* shared_region_name[] = { "MiscData", "ReadWrite", "ReadOnly", "MiscCode", "OptionalData",
"String1", "String2", "OpenArchive1", "OpenArchive2" };
+char* FileMapInfo::map_regions(int regions[], char* saved_base[], size_t len) {
+ char* prev_top = NULL;
+ char* curr_base;
+ char* curr_top;
+ int i = 0;
+ for (i = 0; i < (int)len; i++) {
+ curr_base = map_region(regions[i], &curr_top);
+ if (curr_base == NULL) {
+ return NULL;
+ }
+ if (i > 0) {
+ // We require that mc->rw->ro->md->od to be laid out consecutively, with no
+ // gaps between them. That way, we can ensure that the OS won't be able to
+ // allocate any new memory spaces inside _shared_metaspace_{base,top}, which
+ // would mess up the simple comparision in MetaspaceShared::is_in_shared_metaspace().
+ assert(curr_base == prev_top, "must be");
+ }
+ log_info(cds)("Mapped region #%d at base %p top %p", regions[i], curr_base, curr_top);
+ saved_base[i] = curr_base;
+ prev_top = curr_top;
+ }
+ return curr_top;
+}
+
char* FileMapInfo::map_region(int i, char** top_ret) {
assert(!HeapShared::is_heap_region(i), "sanity");
CDSFileMapRegion* si = space_at(i);
@@ -869,6 +1133,7 @@
si->_allow_exec);
if (base == NULL || base != requested_addr) {
fail_continue("Unable to map %s shared space at required address.", shared_region_name[i]);
+ _memory_mapping_failed = true;
return NULL;
}
#ifdef _WINDOWS
@@ -885,6 +1150,18 @@
return base;
}
+size_t FileMapInfo::read_bytes(void* buffer, size_t count) {
+ assert(_file_open, "Archive file is not open");
+ size_t n = os::read(_fd, buffer, (unsigned int)count);
+ if (n != count) {
+ // Close the file if there's a problem reading it.
+ close();
+ return 0;
+ }
+ _file_offset += count;
+ return count;
+}
+
address FileMapInfo::decode_start_address(CDSFileMapRegion* spc, bool with_current_oop_encoding_mode) {
if (with_current_oop_encoding_mode) {
return (address)CompressedOops::decode_not_null(offset_of_space(spc));
@@ -1126,13 +1403,13 @@
p2i(addr), regions[i].byte_size());
return false;
}
- }
- if (!verify_mapped_heap_regions(first, region_num)) {
- // dealloc the regions from java heap
- dealloc_archive_heap_regions(regions, region_num, is_open_archive);
- log_info(cds)("UseSharedSpaces: mapped heap regions are corrupt");
- return false;
+ if (VerifySharedSpaces && !region_crc_check(addr, regions[i].byte_size(), si->_crc)) {
+ // dealloc the regions from java heap
+ dealloc_archive_heap_regions(regions, region_num, is_open_archive);
+ log_info(cds)("UseSharedSpaces: mapped heap regions are corrupt");
+ return false;
+ }
}
// the shared heap data is mapped successfully
@@ -1141,18 +1418,6 @@
return true;
}
-bool FileMapInfo::verify_mapped_heap_regions(int first, int num) {
- assert(num > 0, "sanity");
- if (VerifySharedSpaces) {
- for (int i = first; i < first + num; i++) {
- if (!verify_region_checksum(i)) {
- return false;
- }
- }
- }
- return true;
-}
-
void FileMapInfo::patch_archived_heap_embedded_pointers() {
if (!_heap_pointers_need_patching) {
return;
@@ -1205,6 +1470,15 @@
}
#endif // INCLUDE_CDS_JAVA_HEAP
+bool FileMapInfo::region_crc_check(char* buf, size_t size, int expected_crc) {
+ int crc = ClassLoader::crc32(0, buf, (jint)size);
+ if (crc != expected_crc) {
+ fail_continue("Checksum verification failed.");
+ return false;
+ }
+ return true;
+}
+
bool FileMapInfo::verify_region_checksum(int i) {
assert(VerifySharedSpaces, "sanity");
@@ -1213,19 +1487,16 @@
if (sz == 0) {
return true; // no data
}
- if ((HeapShared::is_closed_archive_heap_region(i) &&
- !HeapShared::closed_archive_heap_region_mapped()) ||
- (HeapShared::is_open_archive_heap_region(i) &&
- !HeapShared::open_archive_heap_region_mapped())) {
- return true; // archived heap data is not mapped
+
+ return region_crc_check(region_addr(i), sz, space_at(i)->_crc);
+}
+
+void FileMapInfo::unmap_regions(int regions[], char* saved_base[], size_t len) {
+ for (int i = 0; i < (int)len; i++) {
+ if (saved_base[i] != NULL) {
+ unmap_region(regions[i]);
+ }
}
- const char* buf = region_addr(i);
- int crc = ClassLoader::crc32(0, buf, (jint)sz);
- if (crc != space_at(i)->_crc) {
- fail_continue("Checksum verification failed.");
- return false;
- }
- return true;
}
// Unmap a memory region in the address space.
@@ -1253,19 +1524,15 @@
}
void FileMapInfo::metaspace_pointers_do(MetaspaceClosure* it) {
- it->push(&_shared_path_table);
- for (int i=0; i<_shared_path_table_size; i++) {
- shared_path(i)->metaspace_pointers_do(it);
- }
+ _shared_path_table.metaspace_pointers_do(it);
}
-
FileMapInfo* FileMapInfo::_current_info = NULL;
+FileMapInfo* FileMapInfo::_dynamic_archive_info = NULL;
bool FileMapInfo::_heap_pointers_need_patching = false;
-Array<u8>* FileMapInfo::_shared_path_table = NULL;
-int FileMapInfo::_shared_path_table_size = 0;
-size_t FileMapInfo::_shared_path_entry_size = 0x1234baad;
+SharedPathTable FileMapInfo::_shared_path_table;
bool FileMapInfo::_validating_shared_path_table = false;
+bool FileMapInfo::_memory_mapping_failed = false;
// Open the shared archive file, read and validate the header
// information (version, boot classpath, etc.). If initialization
@@ -1277,7 +1544,7 @@
// [1] validate_header() - done here. This checks the header, including _paths_misc_info.
// [2] validate_shared_path_table - this is done later, because the table is in the RW
// region of the archive, which is not mapped yet.
-bool FileMapInfo::initialize() {
+bool FileMapInfo::initialize(bool is_static) {
assert(UseSharedSpaces, "UseSharedSpaces expected.");
if (JvmtiExport::should_post_class_file_load_hook() && JvmtiExport::has_early_class_hook_env()) {
@@ -1293,8 +1560,8 @@
return false;
}
- init_from_file(_fd);
- if (!validate_header()) {
+ init_from_file(_fd, is_static);
+ if (!validate_header(is_static)) {
return false;
}
return true;
@@ -1315,7 +1582,7 @@
char* start = (char*)this;
// start computing from the field after _crc
char* buf = (char*)&_crc + sizeof(_crc);
- size_t sz = sizeof(FileMapHeader) - (buf - start);
+ size_t sz = _header_size - (buf - start);
int crc = ClassLoader::crc32(0, buf, (jint)sz);
return crc;
}
@@ -1336,7 +1603,7 @@
FileMapInfo::fail_continue("The shared archive file is the wrong version.");
return false;
}
- if (_magic != CDS_ARCHIVE_MAGIC) {
+ if (_magic != CDS_ARCHIVE_MAGIC && _magic != CDS_DYNAMIC_ARCHIVE_MAGIC) {
FileMapInfo::fail_continue("The shared archive file has a bad magic number.");
return false;
}
@@ -1401,11 +1668,11 @@
return true;
}
-bool FileMapInfo::validate_header() {
+bool FileMapInfo::validate_header(bool is_static) {
bool status = _header->validate();
if (status) {
- if (!ClassLoader::check_shared_paths_misc_info(_paths_misc_info, _header->_paths_misc_info_size)) {
+ if (!ClassLoader::check_shared_paths_misc_info(_paths_misc_info, _header->_paths_misc_info_size, is_static)) {
if (!PrintSharedArchiveAndExit) {
fail_continue("shared class paths mismatch (hint: enable -Xlog:class+path=info to diagnose the failure)");
status = false;
@@ -1435,7 +1702,7 @@
// Unmap mapped regions of shared space.
void FileMapInfo::stop_sharing_and_unmap(const char* msg) {
- MetaspaceObj::set_shared_metaspace_range(NULL, NULL);
+ MetaspaceShared::set_shared_metaspace_range(NULL, NULL);
FileMapInfo *map_info = FileMapInfo::current_info();
if (map_info) {
@@ -1502,7 +1769,7 @@
ClassFileStream* FileMapInfo::open_stream_for_jvmti(InstanceKlass* ik, Handle class_loader, TRAPS) {
int path_index = ik->shared_classpath_index();
assert(path_index >= 0, "should be called for shared built-in classes only");
- assert(path_index < (int)_shared_path_table_size, "sanity");
+ assert(path_index < (int)get_number_of_shared_paths(), "sanity");
ClassPathEntry* cpe = get_classpath_entry_for_jvmti(path_index, CHECK_NULL);
assert(cpe != NULL, "must be");
--- a/src/hotspot/share/memory/filemap.hpp Fri May 17 13:21:44 2019 +0100
+++ b/src/hotspot/share/memory/filemap.hpp Thu May 23 11:07:37 2019 +0100
@@ -93,7 +93,32 @@
size_t _oopmap_size_in_bits;
};
+class SharedPathTable {
+ Array<u8>* _table;
+ int _size;
+public:
+ void dumptime_init(ClassLoaderData* loader_data, Thread* THREAD);
+ void metaspace_pointers_do(MetaspaceClosure* it);
+
+ int size() {
+ return _size;
+ }
+ SharedClassPathEntry* path_at(int index) {
+ if (index < 0) {
+ return NULL;
+ }
+ assert(index < _size, "sanity");
+ char* p = (char*)_table->data();
+ p += sizeof(SharedClassPathEntry) * index;
+ return (SharedClassPathEntry*)p;
+ }
+ Array<u8>* table() {return _table;}
+ void set_table(Array<u8>* table) {_table = table;}
+
+};
+
struct FileMapHeader : public CDSFileMapHeaderBase {
+ size_t _header_size;
size_t _alignment; // how shared archive should be aligned
int _obj_alignment; // value of ObjectAlignmentInBytes
address _narrow_oop_base; // compressed oop encoding base
@@ -110,12 +135,16 @@
size_t _core_spaces_size; // number of bytes allocated by the core spaces
// (mc, md, ro, rw and od).
MemRegion _heap_reserved; // reserved region for the entire heap at dump time.
+ bool _base_archive_is_default; // indicates if the base archive is the system default one
// The following fields are all sanity checks for whether this archive
// will function correctly with this JVM and the bootclasspath it's
// invoked with.
char _jvm_ident[JVM_IDENT_MAX]; // identifier for jvm
+ // size of the base archive name including NULL terminator
+ int _base_archive_name_size;
+
// The _paths_misc_info is a variable-size structure that records "miscellaneous"
// information during dumping. It is generated and validated by the
// SharedPathsMiscInfo class. See SharedPathsMiscInfo.hpp for
@@ -140,12 +169,11 @@
// FIXME -- if JAR files in the tail of the list were specified but not used during dumping,
// they should be removed from this table, to save space and to avoid spurious
// loading failures during runtime.
- int _shared_path_table_size;
- size_t _shared_path_entry_size;
- Array<u8>* _shared_path_table;
+ SharedPathTable _shared_path_table;
jshort _app_class_paths_start_index; // Index of first app classpath entry
jshort _app_module_paths_start_index; // Index of first module path entry
+ jshort _num_module_paths; // number of module path entries
jshort _max_used_path_index; // max path index referenced during CDS dump
bool _verify_local; // BytecodeVerificationLocal setting
bool _verify_remote; // BytecodeVerificationRemote setting
@@ -161,13 +189,14 @@
jshort app_module_paths_start_index() { return _app_module_paths_start_index; }
bool validate();
- void populate(FileMapInfo* info, size_t alignment);
int compute_crc();
CDSFileMapRegion* space_at(int i) {
assert(i >= 0 && i < NUM_CDS_REGIONS, "invalid region");
return &_space[i];
}
+public:
+ void populate(FileMapInfo* info, size_t alignment);
};
class FileMapInfo : public CHeapObj<mtInternal> {
@@ -176,14 +205,14 @@
friend class VMStructs;
friend struct FileMapHeader;
+ bool _is_static;
bool _file_open;
int _fd;
size_t _file_offset;
private:
- static Array<u8>* _shared_path_table;
- static int _shared_path_table_size;
- static size_t _shared_path_entry_size;
+ // TODO: Probably change the following to be non-static
+ static SharedPathTable _shared_path_table;
static bool _validating_shared_path_table;
// FileMapHeader describes the shared space data in the file to be
@@ -202,24 +231,31 @@
const char* _full_path;
char* _paths_misc_info;
+ char* _base_archive_name;
static FileMapInfo* _current_info;
+ static FileMapInfo* _dynamic_archive_info;
static bool _heap_pointers_need_patching;
-
- bool init_from_file(int fd);
- void align_file_position();
- bool validate_header_impl();
+ static bool _memory_mapping_failed;
+ static bool get_base_archive_name_from_header(const char* archive_name,
+ int* size, char** base_archive_name);
+ static bool check_archive(const char* archive_name, bool is_static);
+ static bool same_files(const char* file1, const char* file2);
+ void restore_shared_path_table();
+ bool init_from_file(int fd, bool is_static);
static void metaspace_pointers_do(MetaspaceClosure* it);
public:
- FileMapInfo();
+ FileMapInfo(bool is_static);
~FileMapInfo();
int compute_header_crc() { return _header->compute_crc(); }
void set_header_crc(int crc) { _header->_crc = crc; }
+ int space_crc(int i) { return space_at(i)->_crc; }
void populate_header(size_t alignment);
- bool validate_header();
+ bool validate_header(bool is_static);
void invalidate();
+ int crc() { return _header->_crc; }
int version() { return _header->_version; }
size_t alignment() { return _header->_alignment; }
CompressedOops::Mode narrow_oop_mode() { return _header->_narrow_oop_mode; }
@@ -234,6 +270,9 @@
char* read_only_tables_start() { return _header->_read_only_tables_start; }
void set_read_only_tables_start(char* p) { _header->_read_only_tables_start = p; }
+ bool is_file_position_aligned() const;
+ void align_file_position();
+
address cds_i2i_entry_code_buffers() {
return _header->_cds_i2i_entry_code_buffers;
}
@@ -254,12 +293,21 @@
NOT_CDS(return NULL;)
}
+ static void set_current_info(FileMapInfo* info) {
+ CDS_ONLY(_current_info = info;)
+ }
+
+ static FileMapInfo* dynamic_info() {
+ CDS_ONLY(return _dynamic_archive_info;)
+ NOT_CDS(return NULL;)
+ }
+
static void assert_mark(bool check);
// File manipulation.
- bool initialize() NOT_CDS_RETURN_(false);
- bool open_for_read();
- void open_for_write();
+ bool initialize(bool is_static) NOT_CDS_RETURN_(false);
+ bool open_for_read(const char* path = NULL);
+ void open_for_write(const char* path = NULL);
void write_header();
void write_region(int region, char* base, size_t size,
bool read_only, bool allow_exec);
@@ -269,6 +317,8 @@
bool print_log);
void write_bytes(const void* buffer, size_t count);
void write_bytes_aligned(const void* buffer, size_t count);
+ size_t read_bytes(void* buffer, size_t count);
+ char* map_regions(int regions[], char* saved_base[], size_t len);
char* map_region(int i, char** top_ret);
void map_heap_regions_impl() NOT_CDS_JAVA_HEAP_RETURN;
void map_heap_regions() NOT_CDS_JAVA_HEAP_RETURN;
@@ -278,6 +328,7 @@
int first_region_idx) NOT_CDS_JAVA_HEAP_RETURN;
bool has_heap_regions() NOT_CDS_JAVA_HEAP_RETURN_(false);
MemRegion get_heap_regions_range_with_current_oop_encoding_mode() NOT_CDS_JAVA_HEAP_RETURN_(MemRegion());
+ void unmap_regions(int regions[], char* saved_base[], size_t len);
void unmap_region(int i);
bool verify_region_checksum(int i);
void close();
@@ -291,7 +342,10 @@
// Errors.
static void fail_stop(const char *msg, ...) ATTRIBUTE_PRINTF(1, 2);
static void fail_continue(const char *msg, ...) ATTRIBUTE_PRINTF(1, 2);
-
+ static bool memory_mapping_failed() {
+ CDS_ONLY(return _memory_mapping_failed;)
+ NOT_CDS(return false;)
+ }
bool is_in_shared_region(const void* p, int idx) NOT_CDS_RETURN_(false);
// Stop CDS sharing and unmap CDS regions.
@@ -307,13 +361,7 @@
#endif
static SharedClassPathEntry* shared_path(int index) {
- if (index < 0) {
- return NULL;
- }
- assert(index < _shared_path_table_size, "sanity");
- char* p = (char*)_shared_path_table->data();
- p += _shared_path_entry_size * index;
- return (SharedClassPathEntry*)p;
+ return _shared_path_table.path_at(index);
}
static const char* shared_path_name(int index) {
@@ -322,7 +370,7 @@
}
static int get_number_of_shared_paths() {
- return _shared_path_table_size;
+ return _shared_path_table.size();
}
char* region_addr(int idx);
@@ -330,7 +378,7 @@
private:
bool map_heap_data(MemRegion **heap_mem, int first, int max, int* num,
bool is_open = false) NOT_CDS_JAVA_HEAP_RETURN_(false);
- bool verify_mapped_heap_regions(int first, int num) NOT_CDS_JAVA_HEAP_RETURN_(false);
+ bool region_crc_check(char* buf, size_t size, int expected_crc) NOT_CDS_RETURN_(false);
void dealloc_archive_heap_regions(MemRegion* regions, int num, bool is_open) NOT_CDS_JAVA_HEAP_RETURN;
CDSFileMapRegion* space_at(int i) {
--- a/src/hotspot/share/memory/heap.cpp Fri May 17 13:21:44 2019 +0100
+++ b/src/hotspot/share/memory/heap.cpp Thu May 23 11:07:37 2019 +0100
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997, 2015, 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
@@ -55,31 +55,67 @@
}
+// The segmap is marked free for that part of the heap
+// which has not been allocated yet (beyond _next_segment).
+// "Allocated" space in this context means there exists a
+// HeapBlock or a FreeBlock describing this space.
+// This method takes segment map indices as range boundaries
void CodeHeap::mark_segmap_as_free(size_t beg, size_t end) {
- assert( beg < _number_of_committed_segments, "interval begin out of bounds");
- assert(beg < end && end <= _number_of_committed_segments, "interval end out of bounds");
- // setup _segmap pointers for faster indexing
- address p = (address)_segmap.low() + beg;
- address q = (address)_segmap.low() + end;
- // initialize interval
- while (p < q) *p++ = free_sentinel;
+ assert( beg < _number_of_committed_segments, "interval begin out of bounds");
+ assert(beg < end && end <= _number_of_committed_segments, "interval end out of bounds");
+ // Don't do unpredictable things in PRODUCT build
+ if (beg < end) {
+ // setup _segmap pointers for faster indexing
+ address p = (address)_segmap.low() + beg;
+ address q = (address)_segmap.low() + end;
+ // initialize interval
+ memset(p, free_sentinel, q-p);
+ }
}
-
+// Don't get confused here.
+// All existing blocks, no matter if they are used() or free(),
+// have their segmap marked as used. This allows to find the
+// block header (HeapBlock or FreeBlock) for any pointer
+// within the allocated range (upper limit: _next_segment).
+// This method takes segment map indices as range boundaries
void CodeHeap::mark_segmap_as_used(size_t beg, size_t end) {
- assert( beg < _number_of_committed_segments, "interval begin out of bounds");
- assert(beg < end && end <= _number_of_committed_segments, "interval end out of bounds");
- // setup _segmap pointers for faster indexing
- address p = (address)_segmap.low() + beg;
- address q = (address)_segmap.low() + end;
- // initialize interval
- int i = 0;
- while (p < q) {
- *p++ = i++;
- if (i == free_sentinel) i = 1;
+ assert( beg < _number_of_committed_segments, "interval begin out of bounds");
+ assert(beg < end && end <= _number_of_committed_segments, "interval end out of bounds");
+ // Don't do unpredictable things in PRODUCT build
+ if (beg < end) {
+ // setup _segmap pointers for faster indexing
+ address p = (address)_segmap.low() + beg;
+ address q = (address)_segmap.low() + end;
+ // initialize interval
+ int i = 0;
+ while (p < q) {
+ *p++ = i++;
+ if (i == free_sentinel) i = 1;
+ }
}
}
+void CodeHeap::invalidate(size_t beg, size_t end, size_t hdr_size) {
+#ifndef PRODUCT
+ // Fill the given range with some bad value.
+ // length is expected to be in segment_size units.
+ // This prevents inadvertent execution of code leftover from previous use.
+ char* p = low_boundary() + segments_to_size(beg) + hdr_size;
+ memset(p, badCodeHeapNewVal, segments_to_size(end-beg)-hdr_size);
+#endif
+}
+
+void CodeHeap::clear(size_t beg, size_t end) {
+ mark_segmap_as_free(beg, end);
+ invalidate(beg, end, 0);
+}
+
+void CodeHeap::clear() {
+ _next_segment = 0;
+ clear(_next_segment, _number_of_committed_segments);
+}
+
static size_t align_to_page_size(size_t size) {
const size_t alignment = (size_t)os::vm_page_size();
@@ -140,7 +176,7 @@
assert(_segmap.reserved_size() >= (size_t) _number_of_reserved_segments , "could not reserve enough space for segment map");
assert(_segmap.reserved_size() >= _segmap.committed_size() , "just checking");
- // initialize remaining instance variables
+ // initialize remaining instance variables, heap memory and segmap
clear();
return true;
}
@@ -167,17 +203,12 @@
return false;
}
assert(_segmap.committed_size() >= (size_t) _number_of_committed_segments, "just checking");
- // initialize additional segmap entries
- mark_segmap_as_free(i, _number_of_committed_segments);
+ // initialize additional space (heap memory and segmap)
+ clear(i, _number_of_committed_segments);
}
return true;
}
-void CodeHeap::clear() {
- _next_segment = 0;
- mark_segmap_as_free(0, _number_of_committed_segments);
-}
-
void* CodeHeap::allocate(size_t instance_size) {
size_t number_of_segments = size_to_segments(instance_size + header_size());
@@ -189,13 +220,14 @@
NOT_PRODUCT(verify());
if (block != NULL) {
- assert(block->length() >= number_of_segments && block->length() < number_of_segments + CodeCacheMinBlockLength, "sanity check");
assert(!block->free(), "must be marked free");
guarantee((char*) block >= _memory.low_boundary() && (char*) block < _memory.high(),
"The newly allocated block " INTPTR_FORMAT " is not within the heap "
"starting with " INTPTR_FORMAT " and ending with " INTPTR_FORMAT,
p2i(block), p2i(_memory.low_boundary()), p2i(_memory.high()));
- DEBUG_ONLY(memset((void*)block->allocated_space(), badCodeHeapNewVal, instance_size));
+ // Invalidate the additional space that FreeBlock occupies. The rest of the block should already be invalidated.
+ // This is necessary due to a dubious assert in nmethod.cpp(PcDescCache::reset_to()).
+ DEBUG_ONLY(memset((void*)block->allocated_space(), badCodeHeapNewVal, sizeof(FreeBlock) - sizeof(HeapBlock)));
_max_allocated_capacity = MAX2(_max_allocated_capacity, allocated_capacity());
_blob_count++;
return block->allocated_space();
@@ -213,7 +245,6 @@
"The newly allocated block " INTPTR_FORMAT " is not within the heap "
"starting with " INTPTR_FORMAT " and ending with " INTPTR_FORMAT,
p2i(b), p2i(_memory.low_boundary()), p2i(_memory.high()));
- DEBUG_ONLY(memset((void *)b->allocated_space(), badCodeHeapNewVal, instance_size));
_max_allocated_capacity = MAX2(_max_allocated_capacity, allocated_capacity());
_blob_count++;
return b->allocated_space();
@@ -222,19 +253,45 @@
}
}
+// Split the given block into two at the given segment.
+// This is helpful when a block was allocated too large
+// to trim off the unused space at the end (interpreter).
+// It also helps with splitting a large free block during allocation.
+// Usage state (used or free) must be set by caller since
+// we don't know if the resulting blocks will be used or free.
+// split_at is the segment number (relative to segment_for(b))
+// where the split happens. The segment with relative
+// number split_at is the first segment of the split-off block.
+HeapBlock* CodeHeap::split_block(HeapBlock *b, size_t split_at) {
+ if (b == NULL) return NULL;
+ // After the split, both blocks must have a size of at least CodeCacheMinBlockLength
+ assert((split_at >= CodeCacheMinBlockLength) && (split_at + CodeCacheMinBlockLength <= b->length()),
+ "split position(%d) out of range [0..%d]", (int)split_at, (int)b->length());
+ size_t split_segment = segment_for(b) + split_at;
+ size_t b_size = b->length();
+ size_t newb_size = b_size - split_at;
+
+ HeapBlock* newb = block_at(split_segment);
+ newb->set_length(newb_size);
+ mark_segmap_as_used(segment_for(newb), segment_for(newb) + newb_size);
+ b->set_length(split_at);
+ return newb;
+}
+
void CodeHeap::deallocate_tail(void* p, size_t used_size) {
assert(p == find_start(p), "illegal deallocation");
// Find start of HeapBlock
HeapBlock* b = (((HeapBlock *)p) - 1);
assert(b->allocated_space() == p, "sanity check");
- size_t used_number_of_segments = size_to_segments(used_size + header_size());
+
size_t actual_number_of_segments = b->length();
+ size_t used_number_of_segments = size_to_segments(used_size + header_size());
+ size_t unused_number_of_segments = actual_number_of_segments - used_number_of_segments;
guarantee(used_number_of_segments <= actual_number_of_segments, "Must be!");
- guarantee(b == block_at(_next_segment - actual_number_of_segments), "Intermediate allocation!");
- size_t number_of_segments_to_deallocate = actual_number_of_segments - used_number_of_segments;
- _next_segment -= number_of_segments_to_deallocate;
- mark_segmap_as_free(_next_segment, _next_segment + number_of_segments_to_deallocate);
- b->initialize(used_number_of_segments);
+
+ HeapBlock* f = split_block(b, used_number_of_segments);
+ add_to_freelist(f);
+ NOT_PRODUCT(verify());
}
void CodeHeap::deallocate(void* p) {
@@ -246,8 +303,6 @@
"The block to be deallocated " INTPTR_FORMAT " is not within the heap "
"starting with " INTPTR_FORMAT " and ending with " INTPTR_FORMAT,
p2i(b), p2i(_memory.low_boundary()), p2i(_memory.high()));
- DEBUG_ONLY(memset((void *)b->allocated_space(), badCodeHeapFreeVal,
- segments_to_size(b->length()) - sizeof(HeapBlock)));
add_to_freelist(b);
NOT_PRODUCT(verify());
}
@@ -410,6 +465,7 @@
// Update find_start map
size_t beg = segment_for(a);
mark_segmap_as_used(beg, beg + a->length());
+ invalidate(beg, beg + a->length(), sizeof(FreeBlock));
_freelist_length--;
return true;
}
@@ -419,19 +475,20 @@
void CodeHeap::add_to_freelist(HeapBlock* a) {
FreeBlock* b = (FreeBlock*)a;
+ size_t bseg = segment_for(b);
_freelist_length++;
assert(b != _freelist, "cannot be removed twice");
-
// Mark as free and update free space count
_freelist_segments += b->length();
b->set_free();
+ invalidate(bseg, bseg + b->length(), sizeof(FreeBlock));
// First element in list?
if (_freelist == NULL) {
+ b->set_link(NULL);
_freelist = b;
- b->set_link(NULL);
return;
}
@@ -463,23 +520,31 @@
* Search freelist for an entry on the list with the best fit.
* @return NULL, if no one was found
*/
-FreeBlock* CodeHeap::search_freelist(size_t length) {
- FreeBlock* found_block = NULL;
- FreeBlock* found_prev = NULL;
- size_t found_length = 0;
+HeapBlock* CodeHeap::search_freelist(size_t length) {
+ FreeBlock* found_block = NULL;
+ FreeBlock* found_prev = NULL;
+ size_t found_length = _next_segment; // max it out to begin with
+ HeapBlock* res = NULL;
FreeBlock* prev = NULL;
- FreeBlock* cur = _freelist;
+ FreeBlock* cur = _freelist;
+
+ length = length < CodeCacheMinBlockLength ? CodeCacheMinBlockLength : length;
- // Search for first block that fits
+ // Search for best-fitting block
while(cur != NULL) {
- if (cur->length() >= length) {
- // Remember block, its previous element, and its length
- found_block = cur;
- found_prev = prev;
- found_length = found_block->length();
-
+ size_t cur_length = cur->length();
+ if (cur_length == length) {
+ // We have a perfect fit
+ found_block = cur;
+ found_prev = prev;
+ found_length = cur_length;
break;
+ } else if ((cur_length > length) && (cur_length < found_length)) {
+ // This is a new, closer fit. Remember block, its previous element, and its length
+ found_block = cur;
+ found_prev = prev;
+ found_length = cur_length;
}
// Next element in list
prev = cur;
@@ -504,20 +569,18 @@
// Unmap element
found_prev->set_link(found_block->link());
}
+ res = found_block;
} else {
- // Truncate block and return a pointer to the following block
- // Set used bit and length on new block
- found_block->set_length(found_length - length);
- found_block = following_block(found_block);
-
- size_t beg = segment_for(found_block);
- mark_segmap_as_used(beg, beg + length);
- found_block->set_length(length);
+ // Truncate the free block and return the truncated part
+ // as new HeapBlock. The remaining free block does not
+ // need to be updated, except for it's length. Truncating
+ // the segment map does not invalidate the leading part.
+ res = split_block(found_block, found_length - length);
}
- found_block->set_used();
+ res->set_used();
_freelist_segments -= length;
- return found_block;
+ return res;
}
//----------------------------------------------------------------------------
@@ -549,6 +612,28 @@
// than free blocks found on the full list.
assert(count == 0, "missing free blocks");
+ //---< all free block memory must have been invalidated >---
+ for(FreeBlock* b = _freelist; b != NULL; b = b->link()) {
+ for (char* c = (char*)b + sizeof(FreeBlock); c < (char*)b + segments_to_size(b->length()); c++) {
+ assert(*c == (char)badCodeHeapNewVal, "FreeBlock@" PTR_FORMAT "(" PTR_FORMAT ") not invalidated @byte %d", p2i(b), b->length(), (int)(c - (char*)b));
+ }
+ }
+
+ // Verify segment map marking.
+ // All allocated segments, no matter if in a free or used block,
+ // must be marked "in use".
+ address seg_map = (address)_segmap.low();
+ size_t nseg = 0;
+ for(HeapBlock* b = first_block(); b != NULL; b = next_block(b)) {
+ size_t seg1 = segment_for(b);
+ size_t segn = seg1 + b->length();
+ for (size_t i = seg1; i < segn; i++) {
+ nseg++;
+ assert(!is_segment_unused(seg_map[i]), "CodeHeap: unused segment. %d [%d..%d], %s block", (int)i, (int)seg1, (int)segn, b->free()? "free":"used");
+ }
+ }
+ assert(nseg == _next_segment, "CodeHeap: segment count mismatch. found %d, expected %d.", (int)nseg, (int)_next_segment);
+
// Verify that the number of free blocks is not out of hand.
static int free_block_threshold = 10000;
if (count > free_block_threshold) {
--- a/src/hotspot/share/memory/heap.hpp Fri May 17 13:21:44 2019 +0100
+++ b/src/hotspot/share/memory/heap.hpp Thu May 23 11:07:37 2019 +0100
@@ -51,6 +51,8 @@
public:
// Initialization
void initialize(size_t length) { _header._length = length; set_used(); }
+ // Merging/splitting
+ void set_length(size_t length) { _header._length = length; }
// Accessors
void* allocated_space() const { return (void*)(this + 1); }
@@ -71,9 +73,6 @@
// Initialization
void initialize(size_t length) { HeapBlock::initialize(length); _link= NULL; }
- // Merging
- void set_length(size_t l) { _header._length = l; }
-
// Accessors
FreeBlock* link() const { return _link; }
void set_link(FreeBlock* link) { _link = link; }
@@ -115,8 +114,12 @@
bool is_segment_unused(int val) const { return val == free_sentinel; }
HeapBlock* block_at(size_t i) const { return (HeapBlock*)(_memory.low() + (i << _log2_segment_size)); }
- void mark_segmap_as_free(size_t beg, size_t end);
- void mark_segmap_as_used(size_t beg, size_t end);
+ // These methods take segment map indices as range boundaries
+ void mark_segmap_as_free(size_t beg, size_t end);
+ void mark_segmap_as_used(size_t beg, size_t end);
+ void invalidate(size_t beg, size_t end, size_t header_bytes);
+ void clear(size_t beg, size_t end);
+ void clear(); // clears all heap contents
// Freelist management helpers
FreeBlock* following_block(FreeBlock* b);
@@ -125,7 +128,7 @@
// Toplevel freelist management
void add_to_freelist(HeapBlock* b);
- FreeBlock* search_freelist(size_t length);
+ HeapBlock* search_freelist(size_t length);
// Iteration helpers
void* next_used(HeapBlock* b) const;
@@ -133,7 +136,6 @@
// to perform additional actions on creation of executable code
void on_code_mapping(char* base, size_t size);
- void clear(); // clears all heap contents
public:
CodeHeap(const char* name, const int code_blob_type);
@@ -180,6 +182,7 @@
size_t segment_size() const { return _segment_size; } // for CodeHeapState
HeapBlock* first_block() const; // for CodeHeapState
HeapBlock* next_block(HeapBlock* b) const; // for CodeHeapState
+ HeapBlock* split_block(HeapBlock* b, size_t split_seg); // split one block into two
FreeBlock* freelist() const { return _freelist; } // for CodeHeapState
--- a/src/hotspot/share/memory/heapShared.cpp Fri May 17 13:21:44 2019 +0100
+++ b/src/hotspot/share/memory/heapShared.cpp Thu May 23 11:07:37 2019 +0100
@@ -418,8 +418,7 @@
_run_time_subgraph_info_table.reset();
- int num_buckets = CompactHashtableWriter::default_num_buckets(d_table->_count);
- CompactHashtableWriter writer(num_buckets, &stats);
+ CompactHashtableWriter writer(d_table->_count, &stats);
CopyKlassSubGraphInfoToArchive copy(&writer);
d_table->iterate(©);
--- a/src/hotspot/share/memory/heapShared.hpp Fri May 17 13:21:44 2019 +0100
+++ b/src/hotspot/share/memory/heapShared.hpp Thu May 23 11:07:37 2019 +0100
@@ -286,16 +286,6 @@
idx <= MetaspaceShared::last_open_archive_heap_region));
NOT_CDS_JAVA_HEAP_RETURN_(false);
}
- static bool is_closed_archive_heap_region(int idx) {
- CDS_JAVA_HEAP_ONLY(return (idx >= MetaspaceShared::first_closed_archive_heap_region &&
- idx <= MetaspaceShared::last_closed_archive_heap_region));
- NOT_CDS_JAVA_HEAP_RETURN_(false);
- }
- static bool is_open_archive_heap_region(int idx) {
- CDS_JAVA_HEAP_ONLY(return (idx >= MetaspaceShared::first_open_archive_heap_region &&
- idx <= MetaspaceShared::last_open_archive_heap_region));
- NOT_CDS_JAVA_HEAP_RETURN_(false);
- }
static void set_closed_archive_heap_region_mapped() {
CDS_JAVA_HEAP_ONLY(_closed_archive_heap_region_mapped = true);
--- a/src/hotspot/share/memory/memRegion.cpp Fri May 17 13:21:44 2019 +0100
+++ b/src/hotspot/share/memory/memRegion.cpp Thu May 23 11:07:37 2019 +0100
@@ -118,4 +118,3 @@
void MemRegion::operator delete [](void* p) {
FreeHeap(p);
}
-
--- a/src/hotspot/share/memory/metaspace.cpp Fri May 17 13:21:44 2019 +0100
+++ b/src/hotspot/share/memory/metaspace.cpp Thu May 23 11:07:37 2019 +0100
@@ -1152,7 +1152,7 @@
void Metaspace::ergo_initialize() {
if (DumpSharedSpaces) {
// Using large pages when dumping the shared archive is currently not implemented.
- FLAG_SET_ERGO(bool, UseLargePagesInMetaspace, false);
+ FLAG_SET_ERGO(UseLargePagesInMetaspace, false);
}
size_t page_size = os::vm_page_size();
@@ -1194,12 +1194,12 @@
if (min_metaspace_sz >= MaxMetaspaceSize) {
vm_exit_during_initialization("MaxMetaspaceSize is too small.");
} else {
- FLAG_SET_ERGO(size_t, CompressedClassSpaceSize,
+ FLAG_SET_ERGO(CompressedClassSpaceSize,
MaxMetaspaceSize - min_metaspace_sz);
}
}
} else if (min_metaspace_sz >= MaxMetaspaceSize) {
- FLAG_SET_ERGO(size_t, InitialBootClassLoaderMetaspaceSize,
+ FLAG_SET_ERGO(InitialBootClassLoaderMetaspaceSize,
min_metaspace_sz);
}
@@ -1220,6 +1220,10 @@
MetaspaceShared::initialize_runtime_shared_and_meta_spaces();
}
+ if (DynamicDumpSharedSpaces && !UseSharedSpaces) {
+ vm_exit_during_initialization("DynamicDumpSharedSpaces not supported when base CDS archive is not loaded", NULL);
+ }
+
if (!DumpSharedSpaces && !UseSharedSpaces)
#endif // INCLUDE_CDS
{
--- a/src/hotspot/share/memory/metaspaceClosure.cpp Fri May 17 13:21:44 2019 +0100
+++ b/src/hotspot/share/memory/metaspaceClosure.cpp Thu May 23 11:07:37 2019 +0100
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2017, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2017, 2019, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -34,9 +34,20 @@
*(address*)mpp() = (address)p;
}
-void MetaspaceClosure::push_impl(MetaspaceClosure::Ref* ref, Writability w) {
- if (ref->not_null()) {
+void MetaspaceClosure::push_impl(MetaspaceClosure::Ref* ref) {
+ if (_nest_level < MAX_NEST_LEVEL) {
+ do_push(ref);
+ delete ref;
+ } else {
+ ref->set_next(_pending_refs);
+ _pending_refs = ref;
+ }
+}
+
+void MetaspaceClosure::do_push(MetaspaceClosure::Ref* ref) {
+ if (ref->not_null()) { // FIXME: make this configurable, so DynamicArchiveBuilder mark all pointers
bool read_only;
+ Writability w = ref->writability();
switch (w) {
case _writable:
read_only = false;
@@ -48,12 +59,29 @@
assert(w == _default, "must be");
read_only = ref->is_read_only_by_default();
}
+ _nest_level ++;
if (do_ref(ref, read_only)) { // true means we want to iterate the embedded pointer in <ref>
ref->metaspace_pointers_do(this);
}
+ _nest_level --;
}
}
+void MetaspaceClosure::finish() {
+ assert(_nest_level == 0, "must be");
+ while (_pending_refs != NULL) {
+ Ref* ref = _pending_refs;
+ _pending_refs = _pending_refs->next();
+ do_push(ref);
+ delete ref;
+ }
+}
+
+MetaspaceClosure::~MetaspaceClosure() {
+ assert(_pending_refs == NULL,
+ "you must explicitly call MetaspaceClosure::finish() to process all refs!");
+}
+
bool UniqueMetaspaceClosure::do_ref(MetaspaceClosure::Ref* ref, bool read_only) {
bool* found = _has_been_visited.lookup(ref->obj());
if (found != NULL) {
@@ -64,7 +92,6 @@
if (_has_been_visited.maybe_grow(MAX_TABLE_SIZE)) {
log_info(cds, hashtables)("Expanded _has_been_visited table to %d", _has_been_visited.table_size());
}
- do_unique_ref(ref, read_only);
- return true; // Saw this for the first time: iterate the embedded pointers.
+ return do_unique_ref(ref, read_only);
}
}
--- a/src/hotspot/share/memory/metaspaceClosure.hpp Fri May 17 13:21:44 2019 +0100
+++ b/src/hotspot/share/memory/metaspaceClosure.hpp Thu May 23 11:07:37 2019 +0100
@@ -101,9 +101,15 @@
// Symbol* bar() { return (Symbol*) _obj; }
//
// [2] All Array<T> dimensions are statically declared.
- class Ref {
+ class Ref : public CHeapObj<mtInternal> {
+ Writability _writability;
+ Ref* _next;
+ // Noncopyable.
+ Ref(const Ref&);
+ Ref& operator=(const Ref&);
protected:
virtual void** mpp() const = 0;
+ Ref(Writability w) : _writability(w), _next(NULL) {}
public:
virtual bool not_null() const = 0;
virtual int size() const = 0;
@@ -111,6 +117,7 @@
virtual void metaspace_pointers_do_at(MetaspaceClosure *it, address new_loc) const = 0;
virtual MetaspaceObj::Type msotype() const = 0;
virtual bool is_read_only_by_default() const = 0;
+ virtual ~Ref() {}
address obj() const {
// In some rare cases (see CPSlot in constantPool.hpp) we store some flags in the lowest
@@ -119,8 +126,16 @@
return (address)(p & (~FLAG_MASK));
}
+ address* addr() const {
+ return (address*)mpp();
+ }
+
void update(address new_loc) const;
+ Writability writability() const { return _writability; };
+ void set_next(Ref* n) { _next = n; }
+ Ref* next() const { return _next; }
+
private:
static const uintx FLAG_MASK = 0x03;
@@ -143,7 +158,7 @@
}
public:
- ObjectRef(T** mpp) : _mpp(mpp) {}
+ ObjectRef(T** mpp, Writability w) : Ref(w), _mpp(mpp) {}
virtual bool is_read_only_by_default() const { return T::is_read_only_by_default(); }
virtual bool not_null() const { return dereference() != NULL; }
@@ -170,7 +185,7 @@
}
public:
- PrimitiveArrayRef(Array<T>** mpp) : _mpp(mpp) {}
+ PrimitiveArrayRef(Array<T>** mpp, Writability w) : Ref(w), _mpp(mpp) {}
// all Arrays are read-only by default
virtual bool is_read_only_by_default() const { return true; }
@@ -200,7 +215,7 @@
}
public:
- PointerArrayRef(Array<T*>** mpp) : _mpp(mpp) {}
+ PointerArrayRef(Array<T*>** mpp, Writability w) : Ref(w), _mpp(mpp) {}
// all Arrays are read-only by default
virtual bool is_read_only_by_default() const { return true; }
@@ -224,9 +239,21 @@
}
};
- void push_impl(Ref* ref, Writability w);
+ // If recursion is too deep, save the Refs in _pending_refs, and push them later using
+ // MetaspaceClosure::finish()
+ static const int MAX_NEST_LEVEL = 5;
+ Ref* _pending_refs;
+ int _nest_level;
+
+ void push_impl(Ref* ref);
+ void do_push(Ref* ref);
public:
+ MetaspaceClosure(): _pending_refs(NULL), _nest_level(0) {}
+ ~MetaspaceClosure();
+
+ void finish();
+
// returns true if we want to keep iterating the pointers embedded inside <ref>
virtual bool do_ref(Ref* ref, bool read_only) = 0;
@@ -237,22 +264,19 @@
// C++ will try to match the "most specific" template function. This one will
// will be matched if possible (if mpp is an Array<> of any pointer type).
template <typename T> void push(Array<T*>** mpp, Writability w = _default) {
- PointerArrayRef<T> ref(mpp);
- push_impl(&ref, w);
+ push_impl(new PointerArrayRef<T>(mpp, w));
}
// If the above function doesn't match (mpp is an Array<>, but T is not a pointer type), then
// this is the second choice.
template <typename T> void push(Array<T>** mpp, Writability w = _default) {
- PrimitiveArrayRef<T> ref(mpp);
- push_impl(&ref, w);
+ push_impl(new PrimitiveArrayRef<T>(mpp, w));
}
// If the above function doesn't match (mpp is not an Array<> type), then
// this will be matched by default.
template <class T> void push(T** mpp, Writability w = _default) {
- ObjectRef<T> ref(mpp);
- push_impl(&ref, w);
+ push_impl(new ObjectRef<T>(mpp, w));
}
};
@@ -266,7 +290,7 @@
public:
// Gets called the first time we discover an object.
- virtual void do_unique_ref(Ref* ref, bool read_only) = 0;
+ virtual bool do_unique_ref(Ref* ref, bool read_only) = 0;
UniqueMetaspaceClosure() : _has_been_visited(INITIAL_TABLE_SIZE) {}
private:
--- a/src/hotspot/share/memory/metaspaceShared.cpp Fri May 17 13:21:44 2019 +0100
+++ b/src/hotspot/share/memory/metaspaceShared.cpp Thu May 23 11:07:37 2019 +0100
@@ -48,10 +48,12 @@
#include "memory/metaspaceShared.hpp"
#include "memory/resourceArea.hpp"
#include "memory/universe.hpp"
+#include "memory/dynamicArchive.hpp"
#include "oops/compressedOops.inline.hpp"
#include "oops/instanceClassLoaderKlass.hpp"
#include "oops/instanceMirrorKlass.hpp"
#include "oops/instanceRefKlass.hpp"
+#include "oops/methodData.hpp"
#include "oops/objArrayKlass.hpp"
#include "oops/objArrayOop.hpp"
#include "oops/oop.inline.hpp"
@@ -81,6 +83,7 @@
address MetaspaceShared::_cds_i2i_entry_code_buffers = NULL;
size_t MetaspaceShared::_cds_i2i_entry_code_buffers_size = 0;
size_t MetaspaceShared::_core_spaces_size = 0;
+void* MetaspaceShared::_shared_metaspace_static_top = NULL;
// The CDS archive is divided into the following regions:
// mc - misc code (the method entry trampolines)
@@ -112,105 +115,97 @@
// The s0/s1 and oa0/oa1 regions are populated inside HeapShared::archive_java_heap_objects.
// Their layout is independent of the other 5 regions.
-class DumpRegion {
-private:
- const char* _name;
- char* _base;
- char* _top;
- char* _end;
- bool _is_packed;
-
- char* expand_top_to(char* newtop) {
- assert(is_allocatable(), "must be initialized and not packed");
- assert(newtop >= _top, "must not grow backwards");
- if (newtop > _end) {
- MetaspaceShared::report_out_of_space(_name, newtop - _top);
- ShouldNotReachHere();
- }
- uintx delta = MetaspaceShared::object_delta_uintx(newtop);
- if (delta > MAX_SHARED_DELTA) {
- // This is just a sanity check and should not appear in any real world usage. This
- // happens only if you allocate more than 2GB of shared objects and would require
- // millions of shared classes.
- vm_exit_during_initialization("Out of memory in the CDS archive",
- "Please reduce the number of shared classes.");
- }
-
- MetaspaceShared::commit_shared_space_to(newtop);
- _top = newtop;
- return _top;
+char* DumpRegion::expand_top_to(char* newtop) {
+ assert(is_allocatable(), "must be initialized and not packed");
+ assert(newtop >= _top, "must not grow backwards");
+ if (newtop > _end) {
+ MetaspaceShared::report_out_of_space(_name, newtop - _top);
+ ShouldNotReachHere();
}
-
-public:
- DumpRegion(const char* name) : _name(name), _base(NULL), _top(NULL), _end(NULL), _is_packed(false) {}
-
- char* allocate(size_t num_bytes, size_t alignment=BytesPerWord) {
- char* p = (char*)align_up(_top, alignment);
- char* newtop = p + align_up(num_bytes, alignment);
- expand_top_to(newtop);
- memset(p, 0, newtop - p);
- return p;
+ uintx delta;
+ if (DynamicDumpSharedSpaces) {
+ delta = DynamicArchive::object_delta_uintx(newtop);
+ } else {
+ delta = MetaspaceShared::object_delta_uintx(newtop);
}
-
- void append_intptr_t(intptr_t n) {
- assert(is_aligned(_top, sizeof(intptr_t)), "bad alignment");
- intptr_t *p = (intptr_t*)_top;
- char* newtop = _top + sizeof(intptr_t);
- expand_top_to(newtop);
- *p = n;
+ if (delta > MAX_SHARED_DELTA) {
+ // This is just a sanity check and should not appear in any real world usage. This
+ // happens only if you allocate more than 2GB of shared objects and would require
+ // millions of shared classes.
+ vm_exit_during_initialization("Out of memory in the CDS archive",
+ "Please reduce the number of shared classes.");
}
- char* base() const { return _base; }
- char* top() const { return _top; }
- char* end() const { return _end; }
- size_t reserved() const { return _end - _base; }
- size_t used() const { return _top - _base; }
- bool is_packed() const { return _is_packed; }
- bool is_allocatable() const {
- return !is_packed() && _base != NULL;
- }
+ MetaspaceShared::commit_shared_space_to(newtop);
+ _top = newtop;
+ return _top;
+}
+
+char* DumpRegion::allocate(size_t num_bytes, size_t alignment) {
+ char* p = (char*)align_up(_top, alignment);
+ char* newtop = p + align_up(num_bytes, alignment);
+ expand_top_to(newtop);
+ memset(p, 0, newtop - p);
+ return p;
+}
- void print(size_t total_bytes) const {
- tty->print_cr("%-3s space: " SIZE_FORMAT_W(9) " [ %4.1f%% of total] out of " SIZE_FORMAT_W(9) " bytes [%5.1f%% used] at " INTPTR_FORMAT,
- _name, used(), percent_of(used(), total_bytes), reserved(), percent_of(used(), reserved()), p2i(_base));
+void DumpRegion::print(size_t total_bytes) const {
+ tty->print_cr("%-3s space: " SIZE_FORMAT_W(9) " [ %4.1f%% of total] out of " SIZE_FORMAT_W(9) " bytes [%5.1f%% used] at " INTPTR_FORMAT,
+ _name, used(), percent_of(used(), total_bytes), reserved(), percent_of(used(), reserved()), p2i(_base));
+}
+
+void DumpRegion::print_out_of_space_msg(const char* failing_region, size_t needed_bytes) {
+ tty->print("[%-8s] " PTR_FORMAT " - " PTR_FORMAT " capacity =%9d, allocated =%9d",
+ _name, p2i(_base), p2i(_top), int(_end - _base), int(_top - _base));
+ if (strcmp(_name, failing_region) == 0) {
+ tty->print_cr(" required = %d", int(needed_bytes));
+ } else {
+ tty->cr();
}
- void print_out_of_space_msg(const char* failing_region, size_t needed_bytes) {
- tty->print("[%-8s] " PTR_FORMAT " - " PTR_FORMAT " capacity =%9d, allocated =%9d",
- _name, p2i(_base), p2i(_top), int(_end - _base), int(_top - _base));
- if (strcmp(_name, failing_region) == 0) {
- tty->print_cr(" required = %d", int(needed_bytes));
- } else {
- tty->cr();
- }
- }
+}
- void init(const ReservedSpace* rs) {
- _base = _top = rs->base();
- _end = rs->end();
+void DumpRegion::pack(DumpRegion* next) {
+ assert(!is_packed(), "sanity");
+ _end = (char*)align_up(_top, Metaspace::reserve_alignment());
+ _is_packed = true;
+ if (next != NULL) {
+ next->_base = next->_top = this->_end;
+ next->_end = MetaspaceShared::shared_rs()->end();
}
- void init(char* b, char* t, char* e) {
- _base = b;
- _top = t;
- _end = e;
- }
+}
+
+DumpRegion _mc_region("mc"), _ro_region("ro"), _rw_region("rw"), _md_region("md"), _od_region("od");
+size_t _total_closed_archive_region_size = 0, _total_open_archive_region_size = 0;
- void pack(DumpRegion* next = NULL) {
- assert(!is_packed(), "sanity");
- _end = (char*)align_up(_top, Metaspace::reserve_alignment());
- _is_packed = true;
- if (next != NULL) {
- next->_base = next->_top = this->_end;
- next->_end = MetaspaceShared::shared_rs()->end();
- }
+void MetaspaceShared::init_shared_dump_space(DumpRegion* first_space, address first_space_bottom) {
+ // Start with 0 committed bytes. The memory will be committed as needed by
+ // MetaspaceShared::commit_shared_space_to().
+ if (!_shared_vs.initialize(_shared_rs, 0)) {
+ vm_exit_during_initialization("Unable to allocate memory for shared space");
}
- bool contains(char* p) {
- return base() <= p && p < top();
- }
-};
+ first_space->init(&_shared_rs, (char*)first_space_bottom);
+}
+
+DumpRegion* MetaspaceShared::misc_code_dump_space() {
+ return &_mc_region;
+}
+
+DumpRegion* MetaspaceShared::read_write_dump_space() {
+ return &_rw_region;
+}
+DumpRegion* MetaspaceShared::read_only_dump_space() {
+ return &_ro_region;
+}
-DumpRegion _mc_region("mc"), _ro_region("ro"), _rw_region("rw"), _md_region("md");
-size_t _total_closed_archive_region_size = 0, _total_open_archive_region_size = 0;
+DumpRegion* MetaspaceShared::optional_data_dump_space() {
+ return &_od_region;
+}
+
+void MetaspaceShared::pack_dump_space(DumpRegion* current, DumpRegion* next,
+ ReservedSpace* rs) {
+ current->pack(next);
+}
char* MetaspaceShared::misc_code_space_alloc(size_t num_bytes) {
return _mc_region.allocate(num_bytes);
@@ -226,20 +221,23 @@
// If using shared space, open the file that contains the shared space
// and map in the memory before initializing the rest of metaspace (so
// the addresses don't conflict)
- address cds_address = NULL;
- FileMapInfo* mapinfo = new FileMapInfo();
+ FileMapInfo* mapinfo = new FileMapInfo(true);
// Open the shared archive file, read and validate the header. If
// initialization fails, shared spaces [UseSharedSpaces] are
// disabled and the file is closed.
// Map in spaces now also
- if (mapinfo->initialize() && map_shared_spaces(mapinfo)) {
+ if (mapinfo->initialize(true) && map_shared_spaces(mapinfo)) {
size_t cds_total = core_spaces_size();
- cds_address = (address)mapinfo->region_addr(0);
+ address cds_address = (address)mapinfo->region_addr(0);
+ char* cds_end = (char *)align_up(cds_address + cds_total,
+ Metaspace::reserve_alignment());
+
+ // Mapping the dynamic archive before allocating the class space
+ cds_end = initialize_dynamic_runtime_shared_spaces((char*)cds_address, cds_end);
+
#ifdef _LP64
if (Metaspace::using_class_space()) {
- char* cds_end = (char*)(cds_address + cds_total);
- cds_end = (char *)align_up(cds_end, Metaspace::reserve_alignment());
// If UseCompressedClassPointers is set then allocate the metaspace area
// above the heap and above the CDS area (if it exists).
Metaspace::allocate_metaspace_compressed_klass_ptrs(cds_end, cds_address);
@@ -255,6 +253,31 @@
}
}
+char* MetaspaceShared::initialize_dynamic_runtime_shared_spaces(
+ char* static_start, char* static_end) {
+ assert(UseSharedSpaces, "must be runtime");
+ char* cds_end = static_end;
+ if (!DynamicDumpSharedSpaces) {
+ address dynamic_top = DynamicArchive::map();
+ if (dynamic_top != NULL) {
+ assert(dynamic_top > (address)static_start, "Unexpected layout");
+ MetaspaceObj::expand_shared_metaspace_range(dynamic_top);
+ cds_end = (char *)align_up(dynamic_top, Metaspace::reserve_alignment());
+ }
+ }
+ return cds_end;
+}
+
+ReservedSpace* MetaspaceShared::reserve_shared_rs(size_t size, size_t alignment,
+ bool large, char* requested_address) {
+ if (requested_address != NULL) {
+ _shared_rs = ReservedSpace(size, alignment, large, requested_address);
+ } else {
+ _shared_rs = ReservedSpace(size, alignment, large);
+ }
+ return &_shared_rs;
+}
+
void MetaspaceShared::initialize_dumptime_shared_and_meta_spaces() {
assert(DumpSharedSpaces, "should be called for dump time only");
const size_t reserve_alignment = Metaspace::reserve_alignment();
@@ -280,12 +303,14 @@
#endif
// First try to reserve the space at the specified SharedBaseAddress.
- _shared_rs = ReservedSpace(cds_total, reserve_alignment, large_pages, shared_base);
+ //_shared_rs = ReservedSpace(cds_total, reserve_alignment, large_pages, shared_base);
+ reserve_shared_rs(cds_total, reserve_alignment, large_pages, shared_base);
if (_shared_rs.is_reserved()) {
assert(shared_base == 0 || _shared_rs.base() == shared_base, "should match");
} else {
// Get a mmap region anywhere if the SharedBaseAddress fails.
- _shared_rs = ReservedSpace(cds_total, reserve_alignment, large_pages);
+ //_shared_rs = ReservedSpace(cds_total, reserve_alignment, large_pages);
+ reserve_shared_rs(cds_total, reserve_alignment, large_pages, NULL);
}
if (!_shared_rs.is_reserved()) {
vm_exit_during_initialization("Unable to reserve memory for shared space",
@@ -324,13 +349,7 @@
CompressedClassSpaceSize, p2i(tmp_class_space.base()));
#endif
- // Start with 0 committed bytes. The memory will be committed as needed by
- // MetaspaceShared::commit_shared_space_to().
- if (!_shared_vs.initialize(_shared_rs, 0)) {
- vm_exit_during_initialization("Unable to allocate memory for shared space");
- }
-
- _mc_region.init(&_shared_rs);
+ init_shared_dump_space(&_mc_region);
SharedBaseAddress = (size_t)_shared_rs.base();
tty->print_cr("Allocated shared space: " SIZE_FORMAT " bytes at " PTR_FORMAT,
_shared_rs.size(), p2i(_shared_rs.base()));
@@ -342,9 +361,16 @@
int size = FileMapInfo::get_number_of_shared_paths();
if (size > 0) {
SystemDictionaryShared::allocate_shared_data_arrays(size, THREAD);
- FileMapHeader* header = FileMapInfo::current_info()->header();
- ClassLoaderExt::init_paths_start_index(header->_app_class_paths_start_index);
- ClassLoaderExt::init_app_module_paths_start_index(header->_app_module_paths_start_index);
+ if (!DynamicDumpSharedSpaces) {
+ FileMapHeader* header;
+ if (FileMapInfo::dynamic_info() == NULL) {
+ header = FileMapInfo::current_info()->header();
+ } else {
+ header = FileMapInfo::dynamic_info()->header();
+ }
+ ClassLoaderExt::init_paths_start_index(header->_app_class_paths_start_index);
+ ClassLoaderExt::init_app_module_paths_start_index(header->_app_module_paths_start_index);
+ }
}
}
}
@@ -405,7 +431,7 @@
}
void MetaspaceShared::commit_shared_space_to(char* newtop) {
- assert(DumpSharedSpaces, "dump-time only");
+ assert(DumpSharedSpaces || DynamicDumpSharedSpaces, "dump-time only");
char* base = _shared_rs.base();
size_t need_committed_size = newtop - base;
size_t has_committed_size = _shared_vs.committed_size();
@@ -417,7 +443,8 @@
size_t preferred_bytes = 1 * M;
size_t uncommitted = _shared_vs.reserved_size() - has_committed_size;
- size_t commit = MAX2(min_bytes, preferred_bytes);
+ size_t commit =MAX2(min_bytes, preferred_bytes);
+ commit = MIN2(commit, uncommitted);
assert(commit <= uncommitted, "sanity");
bool result = _shared_vs.expand_by(commit, false);
@@ -465,6 +492,9 @@
InstanceMirrorKlass::serialize_offsets(soc);
soc->do_tag(--tag);
+ serialize_cloned_cpp_vtptrs(soc);
+ soc->do_tag(--tag);
+
soc->do_tag(666);
}
@@ -484,6 +514,19 @@
return _cds_i2i_entry_code_buffers;
}
+uintx MetaspaceShared::object_delta_uintx(void* obj) {
+ assert(DumpSharedSpaces || DynamicDumpSharedSpaces,
+ "supported only for dumping");
+ if (DumpSharedSpaces) {
+ assert(shared_rs()->contains(obj), "must be");
+ } else {
+ assert(is_in_shared_metaspace(obj) || DynamicArchive::is_in_target_space(obj), "must be");
+ }
+ address base_address = address(SharedBaseAddress);
+ uintx deltax = address(obj) - base_address;
+ return deltax;
+}
+
// Global object for holding classes that have been loaded. Since this
// is run at a safepoint just before exit, this is the entire set of classes.
static GrowableArray<Klass*>* _global_klass_objects;
@@ -589,17 +632,21 @@
Klass* k = _global_klass_objects->at(i);
if (k->is_instance_klass()) {
InstanceKlass* ik = InstanceKlass::cast(k);
- for (int i = 0; i < ik->methods()->length(); i++) {
- Method* m = ik->methods()->at(i);
- rewrite_nofast_bytecode(m);
- Fingerprinter fp(m);
- // The side effect of this call sets method's fingerprint field.
- fp.fingerprint();
- }
+ MetaspaceShared::rewrite_nofast_bytecodes_and_calculate_fingerprints(ik);
}
}
}
+void MetaspaceShared::rewrite_nofast_bytecodes_and_calculate_fingerprints(InstanceKlass* ik) {
+ for (int i = 0; i < ik->methods()->length(); i++) {
+ Method* m = ik->methods()->at(i);
+ rewrite_nofast_bytecode(m);
+ Fingerprinter fp(m);
+ // The side effect of this call sets method's fingerprint field.
+ fp.fingerprint();
+ }
+}
+
// Objects of the Metadata types (such as Klass and ConstantPool) have C++ vtables.
// (In GCC this is the field <Type>::_vptr, i.e., first word in the object.)
//
@@ -686,7 +733,7 @@
intptr_t* p = clone_vtable(name, _info);
assert((char*)p == _md_region.top(), "must be");
- return p;
+ return _info->cloned_vtable();
}
template <class T>
@@ -759,7 +806,7 @@
}
#define ALLOC_CPP_VTABLE_CLONE(c) \
- CppVtableCloner<c>::allocate(#c);
+ _cloned_cpp_vtptrs[c##_Kind] = CppVtableCloner<c>::allocate(#c);
#define CLONE_CPP_VTABLE(c) \
p = CppVtableCloner<c>::clone_vtable(#c, (CppVtableInfo*)p);
@@ -767,6 +814,85 @@
#define ZERO_CPP_VTABLE(c) \
CppVtableCloner<c>::zero_vtable_clone();
+//------------------------------ for DynamicDumpSharedSpaces - start
+#define DECLARE_CLONED_VTABLE_KIND(c) c ## _Kind,
+
+enum {
+ CPP_VTABLE_PATCH_TYPES_DO(DECLARE_CLONED_VTABLE_KIND)
+ _num_cloned_vtable_kinds
+};
+
+static intptr_t** _cloned_cpp_vtptrs = NULL;
+
+void MetaspaceShared::serialize_cloned_cpp_vtptrs(SerializeClosure* soc) {
+ soc->do_ptr((void**)&_cloned_cpp_vtptrs);
+}
+
+intptr_t* MetaspaceShared::fix_cpp_vtable_for_dynamic_archive(MetaspaceObj::Type msotype, address obj) {
+ assert(DynamicDumpSharedSpaces, "must");
+ int kind = -1;
+ switch (msotype) {
+ case MetaspaceObj::SymbolType:
+ case MetaspaceObj::TypeArrayU1Type:
+ case MetaspaceObj::TypeArrayU2Type:
+ case MetaspaceObj::TypeArrayU4Type:
+ case MetaspaceObj::TypeArrayU8Type:
+ case MetaspaceObj::TypeArrayOtherType:
+ case MetaspaceObj::ConstMethodType:
+ case MetaspaceObj::ConstantPoolCacheType:
+ case MetaspaceObj::AnnotationsType:
+ case MetaspaceObj::MethodCountersType:
+ // These have no vtables.
+ break;
+ case MetaspaceObj::ClassType:
+ {
+ Klass* k = (Klass*)obj;
+ assert(k->is_klass(), "must be");
+ if (k->is_instance_klass()) {
+ kind = InstanceKlass_Kind;
+ } else {
+ assert(k->is_objArray_klass(),
+ "We shouldn't archive any other klasses in DynamicDumpSharedSpaces");
+ kind = ObjArrayKlass_Kind;
+ }
+ }
+ break;
+
+ case MetaspaceObj::MethodType:
+ {
+ Method* m = (Method*)obj;
+ assert(m->is_method(), "must be");
+ kind = Method_Kind;
+ }
+ break;
+
+ case MetaspaceObj::MethodDataType:
+ // We don't archive MethodData <-- should have been removed in removed_unsharable_info
+ ShouldNotReachHere();
+ break;
+
+ case MetaspaceObj::ConstantPoolType:
+ {
+ ConstantPool *cp = (ConstantPool*)obj;
+ assert(cp->is_constantPool(), "must be");
+ kind = ConstantPool_Kind;
+ }
+ break;
+
+ default:
+ ShouldNotReachHere();
+ }
+
+ if (kind >= 0) {
+ assert(kind < _num_cloned_vtable_kinds, "must be");
+ return _cloned_cpp_vtptrs[kind];
+ } else {
+ return NULL;
+ }
+}
+
+//------------------------------ for DynamicDumpSharedSpaces - end
+
// This can be called at both dump time and run time.
intptr_t* MetaspaceShared::clone_cpp_vtables(intptr_t* p) {
assert(DumpSharedSpaces || UseSharedSpaces, "sanity");
@@ -830,55 +956,27 @@
return CppVtableCloner<Method>::is_valid_shared_object(m);
}
-// Closure for serializing initialization data out to a data area to be
-// written to the shared file.
-
-class WriteClosure : public SerializeClosure {
-private:
- DumpRegion* _dump_region;
-
-public:
- WriteClosure(DumpRegion* r) {
- _dump_region = r;
+void WriteClosure::do_oop(oop* o) {
+ if (*o == NULL) {
+ _dump_region->append_intptr_t(0);
+ } else {
+ assert(HeapShared::is_heap_object_archiving_allowed(),
+ "Archiving heap object is not allowed");
+ _dump_region->append_intptr_t(
+ (intptr_t)CompressedOops::encode_not_null(*o));
}
-
- void do_ptr(void** p) {
- _dump_region->append_intptr_t((intptr_t)*p);
- }
-
- void do_u4(u4* p) {
- void* ptr = (void*)(uintx(*p));
- do_ptr(&ptr);
- }
-
- void do_tag(int tag) {
- _dump_region->append_intptr_t((intptr_t)tag);
- }
+}
- void do_oop(oop* o) {
- if (*o == NULL) {
- _dump_region->append_intptr_t(0);
- } else {
- assert(HeapShared::is_heap_object_archiving_allowed(),
- "Archiving heap object is not allowed");
- _dump_region->append_intptr_t(
- (intptr_t)CompressedOops::encode_not_null(*o));
- }
+void WriteClosure::do_region(u_char* start, size_t size) {
+ assert((intptr_t)start % sizeof(intptr_t) == 0, "bad alignment");
+ assert(size % sizeof(intptr_t) == 0, "bad size");
+ do_tag((int)size);
+ while (size > 0) {
+ _dump_region->append_intptr_t(*(intptr_t*)start);
+ start += sizeof(intptr_t);
+ size -= sizeof(intptr_t);
}
-
- void do_region(u_char* start, size_t size) {
- assert((intptr_t)start % sizeof(intptr_t) == 0, "bad alignment");
- assert(size % sizeof(intptr_t) == 0, "bad size");
- do_tag((int)size);
- while (size > 0) {
- _dump_region->append_intptr_t(*(intptr_t*)start);
- start += sizeof(intptr_t);
- size -= sizeof(intptr_t);
- }
- }
-
- bool reading() const { return false; }
-};
+}
// This is for dumping detailed statistics for the allocations
// in the shared spaces.
@@ -1166,20 +1264,22 @@
public:
ShallowCopier(bool read_only) : _read_only(read_only) {}
- virtual void do_unique_ref(Ref* ref, bool read_only) {
+ virtual bool do_unique_ref(Ref* ref, bool read_only) {
if (read_only == _read_only) {
allocate(ref, read_only);
}
+ return true; // recurse into ref.obj()
}
};
// Relocate embedded pointers within a MetaspaceObj's shallow copy
class ShallowCopyEmbeddedRefRelocator: public UniqueMetaspaceClosure {
public:
- virtual void do_unique_ref(Ref* ref, bool read_only) {
+ virtual bool do_unique_ref(Ref* ref, bool read_only) {
address new_loc = get_new_loc(ref);
RefRelocator refer;
ref->metaspace_pointers_do_at(&refer, new_loc);
+ return true; // recurse into ref.obj()
}
};
@@ -1294,6 +1394,8 @@
Universe::metaspace_pointers_do(it);
SymbolTable::metaspace_pointers_do(it);
vmSymbols::metaspace_pointers_do(it);
+
+ it->finish();
}
static Klass* get_relocated_klass(Klass* orig_klass) {
@@ -1336,6 +1438,9 @@
char* start = _ro_region.top();
+ size_t vtptrs_bytes = _num_cloned_vtable_kinds * sizeof(intptr_t*);
+ _cloned_cpp_vtptrs = (intptr_t**)_ro_region.allocate(vtptrs_bytes, sizeof(intptr_t*));
+
// Write the other data to the output array.
WriteClosure wc(&_ro_region);
MetaspaceShared::serialize(&wc);
@@ -1354,6 +1459,7 @@
// in the VM thread.
// (2) ArchiveCompactor needs to work with a stable set of MetaspaceObjs.
Metaspace::freeze();
+ DEBUG_ONLY(SystemDictionaryShared::NoClassLoadingMark nclm);
Thread* THREAD = VMThread::vm_thread();
@@ -1441,7 +1547,7 @@
// Create and write the archive file that maps the shared spaces.
- FileMapInfo* mapinfo = new FileMapInfo();
+ FileMapInfo* mapinfo = new FileMapInfo(true);
mapinfo->populate_header(os::vm_allocation_granularity());
mapinfo->set_read_only_tables_start(read_only_tables_start);
mapinfo->set_misc_data_patching_start(vtbl_list);
@@ -1816,67 +1922,55 @@
}
#endif // INCLUDE_CDS_JAVA_HEAP
-// Closure for serializing initialization data in from a data area
-// (ptr_array) read from the shared file.
-
-class ReadClosure : public SerializeClosure {
-private:
- intptr_t** _ptr_array;
-
- inline intptr_t nextPtr() {
- return *(*_ptr_array)++;
- }
+void ReadClosure::do_ptr(void** p) {
+ assert(*p == NULL, "initializing previous initialized pointer.");
+ intptr_t obj = nextPtr();
+ assert((intptr_t)obj >= 0 || (intptr_t)obj < -100,
+ "hit tag while initializing ptrs.");
+ *p = (void*)obj;
+}
-public:
- ReadClosure(intptr_t** ptr_array) { _ptr_array = ptr_array; }
+void ReadClosure::do_u4(u4* p) {
+ intptr_t obj = nextPtr();
+ *p = (u4)(uintx(obj));
+}
- void do_ptr(void** p) {
- assert(*p == NULL, "initializing previous initialized pointer.");
- intptr_t obj = nextPtr();
- assert((intptr_t)obj >= 0 || (intptr_t)obj < -100,
- "hit tag while initializing ptrs.");
- *p = (void*)obj;
- }
-
- void do_u4(u4* p) {
- intptr_t obj = nextPtr();
- *p = (u4)(uintx(obj));
- }
+void ReadClosure::do_tag(int tag) {
+ int old_tag;
+ old_tag = (int)(intptr_t)nextPtr();
+ // do_int(&old_tag);
+ assert(tag == old_tag, "old tag doesn't match");
+ FileMapInfo::assert_mark(tag == old_tag);
+}
- void do_tag(int tag) {
- int old_tag;
- old_tag = (int)(intptr_t)nextPtr();
- // do_int(&old_tag);
- assert(tag == old_tag, "old tag doesn't match");
- FileMapInfo::assert_mark(tag == old_tag);
+void ReadClosure::do_oop(oop *p) {
+ narrowOop o = (narrowOop)nextPtr();
+ if (o == 0 || !HeapShared::open_archive_heap_region_mapped()) {
+ p = NULL;
+ } else {
+ assert(HeapShared::is_heap_object_archiving_allowed(),
+ "Archived heap object is not allowed");
+ assert(HeapShared::open_archive_heap_region_mapped(),
+ "Open archive heap region is not mapped");
+ *p = HeapShared::decode_from_archive(o);
}
+}
- void do_oop(oop *p) {
- narrowOop o = (narrowOop)nextPtr();
- if (o == 0 || !HeapShared::open_archive_heap_region_mapped()) {
- p = NULL;
- } else {
- assert(HeapShared::is_heap_object_archiving_allowed(),
- "Archived heap object is not allowed");
- assert(HeapShared::open_archive_heap_region_mapped(),
- "Open archive heap region is not mapped");
- *p = HeapShared::decode_from_archive(o);
- }
+void ReadClosure::do_region(u_char* start, size_t size) {
+ assert((intptr_t)start % sizeof(intptr_t) == 0, "bad alignment");
+ assert(size % sizeof(intptr_t) == 0, "bad size");
+ do_tag((int)size);
+ while (size > 0) {
+ *(intptr_t*)start = nextPtr();
+ start += sizeof(intptr_t);
+ size -= sizeof(intptr_t);
}
+}
- void do_region(u_char* start, size_t size) {
- assert((intptr_t)start % sizeof(intptr_t) == 0, "bad alignment");
- assert(size % sizeof(intptr_t) == 0, "bad size");
- do_tag((int)size);
- while (size > 0) {
- *(intptr_t*)start = nextPtr();
- start += sizeof(intptr_t);
- size -= sizeof(intptr_t);
- }
- }
-
- bool reading() const { return true; }
-};
+void MetaspaceShared::set_shared_metaspace_range(void* base, void* top) {
+ _shared_metaspace_static_top = top;
+ MetaspaceObj::set_shared_metaspace_range(base, top);
+}
// Return true if given address is in the misc data region
bool MetaspaceShared::is_in_shared_region(const void* p, int idx) {
@@ -1890,6 +1984,15 @@
return false;
}
+bool MetaspaceShared::is_shared_dynamic(void* p) {
+ if ((p < MetaspaceObj::shared_metaspace_top()) &&
+ (p >= _shared_metaspace_static_top)) {
+ return true;
+ } else {
+ return false;
+ }
+}
+
// Map shared spaces at requested addresses and return if succeeded.
bool MetaspaceShared::map_shared_spaces(FileMapInfo* mapinfo) {
size_t image_alignment = mapinfo->alignment();
@@ -1904,42 +2007,23 @@
assert(!DumpSharedSpaces, "Should not be called with DumpSharedSpaces");
- char* ro_base = NULL; char* ro_top;
- char* rw_base = NULL; char* rw_top;
- char* mc_base = NULL; char* mc_top;
- char* md_base = NULL; char* md_top;
+ // Map each shared region
+ int regions[] = {mc, rw, ro, md};
+ size_t len = sizeof(regions)/sizeof(int);
+ char* saved_base[] = {NULL, NULL, NULL, NULL};
+ char* top = mapinfo->map_regions(regions, saved_base, len );
- // Map each shared region
- if ((mc_base = mapinfo->map_region(mc, &mc_top)) != NULL &&
- (rw_base = mapinfo->map_region(rw, &rw_top)) != NULL &&
- (ro_base = mapinfo->map_region(ro, &ro_top)) != NULL &&
- (md_base = mapinfo->map_region(md, &md_top)) != NULL &&
+ if (top != NULL &&
(image_alignment == (size_t)os::vm_allocation_granularity()) &&
mapinfo->validate_shared_path_table()) {
// Success -- set up MetaspaceObj::_shared_metaspace_{base,top} for
// fast checking in MetaspaceShared::is_in_shared_metaspace() and
// MetaspaceObj::is_shared().
- //
- // We require that mc->rw->ro->md to be laid out consecutively, with no
- // gaps between them. That way, we can ensure that the OS won't be able to
- // allocate any new memory spaces inside _shared_metaspace_{base,top}, which
- // would mess up the simple comparision in MetaspaceShared::is_in_shared_metaspace().
- assert(mc_base < ro_base && mc_base < rw_base && mc_base < md_base, "must be");
- assert(md_top > ro_top && md_top > rw_top && md_top > mc_top , "must be");
- assert(mc_top == rw_base, "must be");
- assert(rw_top == ro_base, "must be");
- assert(ro_top == md_base, "must be");
-
_core_spaces_size = mapinfo->core_spaces_size();
- MetaspaceObj::set_shared_metaspace_range((void*)mc_base, (void*)md_top);
+ set_shared_metaspace_range((void*)saved_base[0], (void*)top);
return true;
} else {
- // If there was a failure in mapping any of the spaces, unmap the ones
- // that succeeded
- if (ro_base != NULL) mapinfo->unmap_region(ro);
- if (rw_base != NULL) mapinfo->unmap_region(rw);
- if (mc_base != NULL) mapinfo->unmap_region(mc);
- if (md_base != NULL) mapinfo->unmap_region(md);
+ mapinfo->unmap_regions(regions, saved_base, len);
#ifndef _WINDOWS
// Release the entire mapped region
shared_rs.release();
@@ -1970,6 +2054,9 @@
// The rest of the data is now stored in the RW region
buffer = mapinfo->read_only_tables_start();
+ // Skip over _cloned_cpp_vtptrs;
+ buffer += _num_cloned_vtable_kinds * sizeof(intptr_t*);
+
// Verify various attributes of the archive, plus initialize the
// shared string/symbol tables
intptr_t* array = (intptr_t*)buffer;
@@ -2009,6 +2096,12 @@
if (!mapinfo->remap_shared_readonly_as_readwrite()) {
return false;
}
+ if (FileMapInfo::dynamic_info() != NULL) {
+ mapinfo = FileMapInfo::dynamic_info();
+ if (!mapinfo->remap_shared_readonly_as_readwrite()) {
+ return false;
+ }
+ }
_remapped_readwrite = true;
}
return true;
--- a/src/hotspot/share/memory/metaspaceShared.hpp Fri May 17 13:21:44 2019 +0100
+++ b/src/hotspot/share/memory/metaspaceShared.hpp Thu May 23 11:07:37 2019 +0100
@@ -47,6 +47,124 @@
CompactHashtableStats string;
};
+#if INCLUDE_CDS
+class DumpRegion {
+private:
+ const char* _name;
+ char* _base;
+ char* _top;
+ char* _end;
+ bool _is_packed;
+
+public:
+ DumpRegion(const char* name) : _name(name), _base(NULL), _top(NULL), _end(NULL), _is_packed(false) {}
+
+ char* expand_top_to(char* newtop);
+ char* allocate(size_t num_bytes, size_t alignment=BytesPerWord);
+
+ void append_intptr_t(intptr_t n) {
+ assert(is_aligned(_top, sizeof(intptr_t)), "bad alignment");
+ intptr_t *p = (intptr_t*)_top;
+ char* newtop = _top + sizeof(intptr_t);
+ expand_top_to(newtop);
+ *p = n;
+ }
+
+ char* base() const { return _base; }
+ char* top() const { return _top; }
+ char* end() const { return _end; }
+ size_t reserved() const { return _end - _base; }
+ size_t used() const { return _top - _base; }
+ bool is_packed() const { return _is_packed; }
+ bool is_allocatable() const {
+ return !is_packed() && _base != NULL;
+ }
+
+ void print(size_t total_bytes) const;
+ void print_out_of_space_msg(const char* failing_region, size_t needed_bytes);
+
+ void init(const ReservedSpace* rs, char* base) {
+ if (base == NULL) {
+ base = rs->base();
+ }
+ assert(rs->contains(base), "must be");
+ _base = _top = base;
+ _end = rs->end();
+ }
+ void init(char* b, char* t, char* e) {
+ _base = b;
+ _top = t;
+ _end = e;
+ }
+
+ void pack(DumpRegion* next = NULL);
+
+ bool contains(char* p) {
+ return base() <= p && p < top();
+ }
+};
+
+// Closure for serializing initialization data out to a data area to be
+// written to the shared file.
+
+class WriteClosure : public SerializeClosure {
+private:
+ DumpRegion* _dump_region;
+
+public:
+ WriteClosure(DumpRegion* r) {
+ _dump_region = r;
+ }
+
+ void do_ptr(void** p) {
+ _dump_region->append_intptr_t((intptr_t)*p);
+ }
+
+ void do_u4(u4* p) {
+ void* ptr = (void*)(uintx(*p));
+ do_ptr(&ptr);
+ }
+
+ void do_tag(int tag) {
+ _dump_region->append_intptr_t((intptr_t)tag);
+ }
+
+ void do_oop(oop* o);
+
+ void do_region(u_char* start, size_t size);
+
+ bool reading() const { return false; }
+};
+
+// Closure for serializing initialization data in from a data area
+// (ptr_array) read from the shared file.
+
+class ReadClosure : public SerializeClosure {
+private:
+ intptr_t** _ptr_array;
+
+ inline intptr_t nextPtr() {
+ return *(*_ptr_array)++;
+ }
+
+public:
+ ReadClosure(intptr_t** ptr_array) { _ptr_array = ptr_array; }
+
+ void do_ptr(void** p);
+
+ void do_u4(u4* p);
+
+ void do_tag(int tag);
+
+ void do_oop(oop *p);
+
+ void do_region(u_char* start, size_t size);
+
+ bool reading() const { return true; }
+};
+
+#endif
+
// Class Data Sharing Support
class MetaspaceShared : AllStatic {
@@ -61,6 +179,7 @@
static address _cds_i2i_entry_code_buffers;
static size_t _cds_i2i_entry_code_buffers_size;
static size_t _core_spaces_size;
+ static void* _shared_metaspace_static_top;
public:
enum {
// core archive spaces
@@ -102,16 +221,12 @@
}
static void initialize_dumptime_shared_and_meta_spaces() NOT_CDS_RETURN;
static void initialize_runtime_shared_and_meta_spaces() NOT_CDS_RETURN;
+ static char* initialize_dynamic_runtime_shared_spaces(
+ char* static_start, char* static_end) NOT_CDS_RETURN_(NULL);
static void post_initialize(TRAPS) NOT_CDS_RETURN;
- // Delta of this object from the bottom of the archive.
- static uintx object_delta_uintx(void* obj) {
- assert(DumpSharedSpaces, "supported only for dumping");
- assert(shared_rs()->contains(obj), "must be");
- address base_address = address(shared_rs()->base());
- uintx deltax = address(obj) - base_address;
- return deltax;
- }
+ // Delta of this object from SharedBaseAddress
+ static uintx object_delta_uintx(void* obj);
static u4 object_delta_u4(void* obj) {
// offset is guaranteed to be less than MAX_SHARED_DELTA in DumpRegion::expand_top_to()
@@ -134,15 +249,25 @@
return (p < MetaspaceObj::shared_metaspace_top() && p >= MetaspaceObj::shared_metaspace_base());
}
+ static address shared_metaspace_top() {
+ return (address)MetaspaceObj::shared_metaspace_top();
+ }
+
+ static void set_shared_metaspace_range(void* base, void* top) NOT_CDS_RETURN;
+
// Return true if given address is in the shared region corresponding to the idx
static bool is_in_shared_region(const void* p, int idx) NOT_CDS_RETURN_(false);
static bool is_in_trampoline_frame(address addr) NOT_CDS_RETURN_(false);
+ static bool is_shared_dynamic(void* p) NOT_CDS_RETURN_(false);
+
static void allocate_cpp_vtable_clones();
static intptr_t* clone_cpp_vtables(intptr_t* p);
static void zero_cpp_vtable_clones_for_writing();
static void patch_cpp_vtable_pointers();
+ static void serialize_cloned_cpp_vtptrs(SerializeClosure* sc);
+
static bool is_valid_shared_method(const Method* m) NOT_CDS_RETURN_(false);
static void serialize(SerializeClosure* sc) NOT_CDS_RETURN;
@@ -165,6 +290,20 @@
static bool try_link_class(InstanceKlass* ik, TRAPS);
static void link_and_cleanup_shared_classes(TRAPS);
+#if INCLUDE_CDS
+ static ReservedSpace* reserve_shared_rs(size_t size, size_t alignment,
+ bool large, char* requested_address);
+ static void init_shared_dump_space(DumpRegion* first_space, address first_space_bottom = NULL);
+ static DumpRegion* misc_code_dump_space();
+ static DumpRegion* read_write_dump_space();
+ static DumpRegion* read_only_dump_space();
+ static DumpRegion* optional_data_dump_space();
+ static void pack_dump_space(DumpRegion* current, DumpRegion* next,
+ ReservedSpace* rs);
+
+ static void rewrite_nofast_bytecodes_and_calculate_fingerprints(InstanceKlass* ik);
+#endif
+
// Allocate a block of memory from the "mc", "ro", or "rw" regions.
static char* misc_code_space_alloc(size_t num_bytes);
static char* read_only_space_alloc(size_t num_bytes);
@@ -181,6 +320,12 @@
#endif
}
+ template <typename T>
+ static size_t ro_array_bytesize(int length) {
+ size_t byte_size = Array<T>::byte_sizeof(length, sizeof(T));
+ return align_up(byte_size, BytesPerWord);
+ }
+
static address cds_i2i_entry_code_buffers(size_t total_size);
static address cds_i2i_entry_code_buffers() {
@@ -193,6 +338,8 @@
static Klass* get_relocated_klass(Klass *k);
+ static intptr_t* fix_cpp_vtable_for_dynamic_archive(MetaspaceObj::Type msotype, address obj);
+
private:
static void read_extra_data(const char* filename, TRAPS) NOT_CDS_RETURN;
};
--- a/src/hotspot/share/memory/universe.cpp Fri May 17 13:21:44 2019 +0100
+++ b/src/hotspot/share/memory/universe.cpp Thu May 23 11:07:37 2019 +0100
@@ -711,13 +711,14 @@
{
SymbolTable::create_table();
StringTable::create_table();
+ }
#if INCLUDE_CDS
- if (DumpSharedSpaces) {
- MetaspaceShared::prepare_for_dumping();
- }
+ if (DumpSharedSpaces || DynamicDumpSharedSpaces) {
+ MetaspaceShared::prepare_for_dumping();
+ }
#endif
- }
+
if (strlen(VerifySubSet) > 0) {
Universe::initialize_verify_flags();
}
--- a/src/hotspot/share/oops/constMethod.hpp Fri May 17 13:21:44 2019 +0100
+++ b/src/hotspot/share/oops/constMethod.hpp Thu May 23 11:07:37 2019 +0100
@@ -288,12 +288,16 @@
// adapter
void set_adapter_entry(AdapterHandlerEntry* adapter) {
- assert(!is_shared(), "shared methods have fixed adapter_trampoline");
+ assert(!is_shared(),
+ "shared methods in archive have fixed adapter_trampoline");
_adapter = adapter;
}
void set_adapter_trampoline(AdapterHandlerEntry** trampoline) {
- assert(DumpSharedSpaces, "must be");
- assert(*trampoline == NULL, "must be NULL during dump time, to be initialized at run time");
+ assert(DumpSharedSpaces || DynamicDumpSharedSpaces, "must be");
+ if (DumpSharedSpaces) {
+ assert(*trampoline == NULL,
+ "must be NULL during dump time, to be initialized at run time");
+ }
_adapter_trampoline = trampoline;
}
void update_adapter_trampoline(AdapterHandlerEntry* adapter) {
--- a/src/hotspot/share/oops/constantPool.cpp Fri May 17 13:21:44 2019 +0100
+++ b/src/hotspot/share/oops/constantPool.cpp Thu May 23 11:07:37 2019 +0100
@@ -371,7 +371,9 @@
// If archiving heap objects is not allowed, clear the resolved references.
// Otherwise, it is cleared after the resolved references array is cached
// (see archive_resolved_references()).
- if (!HeapShared::is_heap_object_archiving_allowed()) {
+ // If DynamicDumpSharedSpaces is enabled, clear the resolved references also
+ // as java objects are not archived in the top layer.
+ if (!HeapShared::is_heap_object_archiving_allowed() || DynamicDumpSharedSpaces) {
set_resolved_references(NULL);
}
@@ -382,7 +384,16 @@
_flags |= (_on_stack | _is_shared);
int num_klasses = 0;
for (int index = 1; index < length(); index++) { // Index 0 is unused
- assert(!tag_at(index).is_unresolved_klass_in_error(), "This must not happen during dump time");
+ if (!DynamicDumpSharedSpaces) {
+ assert(!tag_at(index).is_unresolved_klass_in_error(), "This must not happen during static dump time");
+ } else {
+ if (tag_at(index).is_unresolved_klass_in_error() ||
+ tag_at(index).is_method_handle_in_error() ||
+ tag_at(index).is_method_type_in_error() ||
+ tag_at(index).is_dynamic_constant_in_error()) {
+ tag_at_put(index, JVM_CONSTANT_UnresolvedClass);
+ }
+ }
if (tag_at(index).is_klass()) {
// This class was resolved as a side effect of executing Java code
// during dump time. We need to restore it back to an UnresolvedClass,
--- a/src/hotspot/share/oops/cpCache.cpp Fri May 17 13:21:44 2019 +0100
+++ b/src/hotspot/share/oops/cpCache.cpp Thu May 23 11:07:37 2019 +0100
@@ -697,7 +697,7 @@
}
void ConstantPoolCache::walk_entries_for_initialization(bool check_only) {
- assert(DumpSharedSpaces, "sanity");
+ assert(DumpSharedSpaces || DynamicDumpSharedSpaces, "sanity");
// When dumping the archive, we want to clean up the ConstantPoolCache
// to remove any effect of linking due to the execution of Java code --
// each ConstantPoolCacheEntry will have the same contents as if
--- a/src/hotspot/share/oops/instanceKlass.cpp Fri May 17 13:21:44 2019 +0100
+++ b/src/hotspot/share/oops/instanceKlass.cpp Thu May 23 11:07:37 2019 +0100
@@ -451,7 +451,7 @@
assert(is_instance_klass(), "is layout incorrect?");
assert(size_helper() == parser.layout_size(), "incorrect size_helper?");
- if (DumpSharedSpaces) {
+ if (DumpSharedSpaces || DynamicDumpSharedSpaces) {
SystemDictionaryShared::init_dumptime_info(this);
}
}
@@ -601,7 +601,7 @@
}
set_annotations(NULL);
- if (DumpSharedSpaces) {
+ if (DumpSharedSpaces || DynamicDumpSharedSpaces) {
SystemDictionaryShared::remove_dumptime_info(this);
}
}
@@ -2225,8 +2225,8 @@
// (1) We are running AOT to generate a shared library.
return true;
}
- if (DumpSharedSpaces) {
- // (2) We are running -Xshare:dump to create a shared archive
+ if (DumpSharedSpaces || DynamicDumpSharedSpaces) {
+ // (2) We are running -Xshare:dump or -XX:ArchiveClassesAtExit to create a shared archive
return true;
}
if (UseAOT && is_unsafe_anonymous) {
@@ -2346,15 +2346,13 @@
array_klasses()->remove_unshareable_info();
}
- // These are not allocated from metaspace, but they should should all be empty
- // during dump time, so we don't need to worry about them in InstanceKlass::iterate().
- guarantee(_source_debug_extension == NULL, "must be");
- guarantee(_dep_context == NULL, "must be");
- guarantee(_osr_nmethods_head == NULL, "must be");
-
+ // These are not allocated from metaspace. They are safe to set to NULL.
+ _source_debug_extension = NULL;
+ _dep_context = NULL;
+ _osr_nmethods_head = NULL;
#if INCLUDE_JVMTI
- guarantee(_breakpoints == NULL, "must be");
- guarantee(_previous_versions == NULL, "must be");
+ _breakpoints = NULL;
+ _previous_versions = NULL;
_cached_class_file = NULL;
#endif
@@ -2475,6 +2473,10 @@
// notify ClassLoadingService of class unload
ClassLoadingService::notify_class_unloaded(ik);
+ if (DumpSharedSpaces || DynamicDumpSharedSpaces) {
+ SystemDictionaryShared::remove_dumptime_info(ik);
+ }
+
if (log_is_enabled(Info, class, unload)) {
ResourceMark rm;
log_info(class, unload)("unloading class %s " INTPTR_FORMAT, ik->external_name(), p2i(ik));
@@ -3422,7 +3424,12 @@
info_stream.print(" source: %s", class_loader->klass()->external_name());
}
} else {
- info_stream.print(" source: shared objects file");
+ assert(this->is_shared(), "must be");
+ if (MetaspaceShared::is_shared_dynamic((void*)this)) {
+ info_stream.print(" source: shared objects file (top)");
+ } else {
+ info_stream.print(" source: shared objects file");
+ }
}
msg.info("%s", info_stream.as_string());
--- a/src/hotspot/share/oops/klass.cpp Fri May 17 13:21:44 2019 +0100
+++ b/src/hotspot/share/oops/klass.cpp Thu May 23 11:07:37 2019 +0100
@@ -525,7 +525,8 @@
}
void Klass::remove_unshareable_info() {
- assert (DumpSharedSpaces, "only called for DumpSharedSpaces");
+ assert (DumpSharedSpaces || DynamicDumpSharedSpaces,
+ "only called during CDS dump time");
JFR_ONLY(REMOVE_ID(this);)
if (log_is_enabled(Trace, cds, unshareable)) {
ResourceMark rm;
@@ -542,7 +543,7 @@
}
void Klass::remove_java_mirror() {
- assert (DumpSharedSpaces, "only called for DumpSharedSpaces");
+ assert(DumpSharedSpaces || DynamicDumpSharedSpaces, "only called during CDS dump time");
if (log_is_enabled(Trace, cds, unshareable)) {
ResourceMark rm;
log_trace(cds, unshareable)("remove java_mirror: %s", external_name());
--- a/src/hotspot/share/oops/method.cpp Fri May 17 13:21:44 2019 +0100
+++ b/src/hotspot/share/oops/method.cpp Thu May 23 11:07:37 2019 +0100
@@ -958,23 +958,30 @@
void Method::unlink_method() {
_code = NULL;
- assert(DumpSharedSpaces, "dump time only");
+ assert(DumpSharedSpaces || DynamicDumpSharedSpaces, "dump time only");
// Set the values to what they should be at run time. Note that
// this Method can no longer be executed during dump time.
_i2i_entry = Interpreter::entry_for_cds_method(this);
_from_interpreted_entry = _i2i_entry;
+ if (DynamicDumpSharedSpaces) {
+ assert(_from_compiled_entry != NULL, "sanity");
+ } else {
+ // TODO: Simplify the adapter trampoline allocation for static archiving.
+ // Remove the use of CDSAdapterHandlerEntry.
+ CDSAdapterHandlerEntry* cds_adapter = (CDSAdapterHandlerEntry*)adapter();
+ constMethod()->set_adapter_trampoline(cds_adapter->get_adapter_trampoline());
+ _from_compiled_entry = cds_adapter->get_c2i_entry_trampoline();
+ assert(*((int*)_from_compiled_entry) == 0,
+ "must be NULL during dump time, to be initialized at run time");
+ }
+
if (is_native()) {
*native_function_addr() = NULL;
set_signature_handler(NULL);
}
NOT_PRODUCT(set_compiled_invocation_count(0);)
- CDSAdapterHandlerEntry* cds_adapter = (CDSAdapterHandlerEntry*)adapter();
- constMethod()->set_adapter_trampoline(cds_adapter->get_adapter_trampoline());
- _from_compiled_entry = cds_adapter->get_c2i_entry_trampoline();
- assert(*((int*)_from_compiled_entry) == 0, "must be NULL during dump time, to be initialized at run time");
-
set_method_data(NULL);
clear_method_counters();
}
--- a/src/hotspot/share/oops/method.hpp Fri May 17 13:21:44 2019 +0100
+++ b/src/hotspot/share/oops/method.hpp Thu May 23 11:07:37 2019 +0100
@@ -468,9 +468,15 @@
void set_adapter_entry(AdapterHandlerEntry* adapter) {
constMethod()->set_adapter_entry(adapter);
}
+ void set_adapter_trampoline(AdapterHandlerEntry** trampoline) {
+ constMethod()->set_adapter_trampoline(trampoline);
+ }
void update_adapter_trampoline(AdapterHandlerEntry* adapter) {
constMethod()->update_adapter_trampoline(adapter);
}
+ void set_from_compiled_entry(address entry) {
+ _from_compiled_entry = entry;
+ }
address get_i2c_entry();
address get_c2i_entry();
@@ -511,7 +517,8 @@
address interpreter_entry() const { return _i2i_entry; }
// Only used when first initialize so we can set _i2i_entry and _from_interpreted_entry
void set_interpreter_entry(address entry) {
- assert(!is_shared(), "shared method's interpreter entry should not be changed at run time");
+ assert(!is_shared(),
+ "shared method's interpreter entry should not be changed at run time");
if (_i2i_entry != entry) {
_i2i_entry = entry;
}
--- a/src/hotspot/share/oops/methodData.hpp Fri May 17 13:21:44 2019 +0100
+++ b/src/hotspot/share/oops/methodData.hpp Thu May 23 11:07:37 2019 +0100
@@ -31,9 +31,6 @@
#include "oops/oop.hpp"
#include "runtime/atomic.hpp"
#include "utilities/align.hpp"
-#if INCLUDE_JVMCI
-#include "jvmci/jvmci_globals.hpp"
-#endif
class BytecodeStream;
class KlassSizeStats;
--- a/src/hotspot/share/oops/symbol.cpp Fri May 17 13:21:44 2019 +0100
+++ b/src/hotspot/share/oops/symbol.cpp Thu May 23 11:07:37 2019 +0100
@@ -74,6 +74,13 @@
FreeHeap(p);
}
+void Symbol::set_permanent() {
+ // This is called at a safepoint during dumping of a dynamic CDS archive.
+ assert(SafepointSynchronize::is_at_safepoint(), "must be at a safepoint");
+ _length_and_refcount = pack_length_and_refcount(length(), PERM_REFCOUNT);
+}
+
+
// ------------------------------------------------------------------
// Symbol::starts_with
//
--- a/src/hotspot/share/oops/symbol.hpp Fri May 17 13:21:44 2019 +0100
+++ b/src/hotspot/share/oops/symbol.hpp Thu May 23 11:07:37 2019 +0100
@@ -169,6 +169,7 @@
bool is_permanent() {
return (refcount() == PERM_REFCOUNT);
}
+ void set_permanent();
void make_permanent();
// Function char_at() returns the Symbol's selected u1 byte as a char type.
--- a/src/hotspot/share/opto/arraycopynode.cpp Fri May 17 13:21:44 2019 +0100
+++ b/src/hotspot/share/opto/arraycopynode.cpp Thu May 23 11:07:37 2019 +0100
@@ -296,6 +296,10 @@
src_offset = Compile::conv_I2X_index(phase, src_offset, ary_src->size());
dest_offset = Compile::conv_I2X_index(phase, dest_offset, ary_dest->size());
+ if (src_offset->is_top() || dest_offset->is_top()) {
+ // Offset is out of bounds (the ArrayCopyNode will be removed)
+ return false;
+ }
Node* src_scale = phase->transform(new LShiftXNode(src_offset, phase->intcon(shift)));
Node* dest_scale = phase->transform(new LShiftXNode(dest_offset, phase->intcon(shift)));
--- a/src/hotspot/share/opto/block.cpp Fri May 17 13:21:44 2019 +0100
+++ b/src/hotspot/share/opto/block.cpp Thu May 23 11:07:37 2019 +0100
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997, 2016, 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
@@ -267,7 +267,7 @@
#ifndef PRODUCT
void Block::dump_bidx(const Block* orig, outputStream* st) const {
- if (_pre_order) st->print("B%d",_pre_order);
+ if (_pre_order) st->print("B%d", _pre_order);
else st->print("N%d", head()->_idx);
if (Verbose && orig != this) {
@@ -291,30 +291,36 @@
}
void Block::dump_head(const PhaseCFG* cfg, outputStream* st) const {
- // Print the basic block
+ // Print the basic block.
dump_bidx(this, st);
- st->print(": #\t");
+ st->print(": ");
- // Print the incoming CFG edges and the outgoing CFG edges
+ // Print the outgoing CFG edges.
+ st->print("#\tout( ");
for( uint i=0; i<_num_succs; i++ ) {
non_connector_successor(i)->dump_bidx(_succs[i], st);
st->print(" ");
}
- st->print("<- ");
+
+ // Print the incoming CFG edges.
+ st->print(") <- ");
if( head()->is_block_start() ) {
+ st->print("in( ");
for (uint i=1; i<num_preds(); i++) {
Node *s = pred(i);
if (cfg != NULL) {
Block *p = cfg->get_block_for_node(s);
p->dump_pred(cfg, p, st);
} else {
- while (!s->is_block_start())
+ while (!s->is_block_start()) {
s = s->in(0);
+ }
st->print("N%d ", s->_idx );
}
}
+ st->print(") ");
} else {
- st->print("BLOCK HEAD IS JUNK ");
+ st->print("BLOCK HEAD IS JUNK ");
}
// Print loop, if any
@@ -327,12 +333,15 @@
while (bx->is_connector()) {
bx = cfg->get_block_for_node(bx->pred(1));
}
- st->print("\tLoop: B%d-B%d ", bhead->_pre_order, bx->_pre_order);
+ st->print("Loop( B%d-B%d ", bhead->_pre_order, bx->_pre_order);
// Dump any loop-specific bits, especially for CountedLoops.
loop->dump_spec(st);
+ st->print(")");
} else if (has_loop_alignment()) {
- st->print(" top-of-loop");
+ st->print("top-of-loop");
}
+
+ // Print frequency and other optimization-relevant information
st->print(" Freq: %g",_freq);
if( Verbose || WizardMode ) {
st->print(" IDom: %d/#%d", _idom ? _idom->_pre_order : 0, _dom_depth);
--- a/src/hotspot/share/opto/c2_globals.cpp Fri May 17 13:21:44 2019 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,38 +0,0 @@
-/*
- * Copyright (c) 2000, 2016, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- *
- */
-
-#include "precompiled.hpp"
-#include "opto/c2_globals.hpp"
-
-C2_FLAGS(MATERIALIZE_DEVELOPER_FLAG, \
- MATERIALIZE_PD_DEVELOPER_FLAG, \
- MATERIALIZE_PRODUCT_FLAG, \
- MATERIALIZE_PD_PRODUCT_FLAG, \
- MATERIALIZE_DIAGNOSTIC_FLAG, \
- MATERIALIZE_PD_DIAGNOSTIC_FLAG, \
- MATERIALIZE_EXPERIMENTAL_FLAG, \
- MATERIALIZE_NOTPRODUCT_FLAG, \
- IGNORE_RANGE, \
- IGNORE_CONSTRAINT, \
- IGNORE_WRITEABLE)
--- a/src/hotspot/share/opto/c2_globals.hpp Fri May 17 13:21:44 2019 +0100
+++ b/src/hotspot/share/opto/c2_globals.hpp Thu May 23 11:07:37 2019 +0100
@@ -25,7 +25,7 @@
#ifndef SHARE_OPTO_C2_GLOBALS_HPP
#define SHARE_OPTO_C2_GLOBALS_HPP
-#include "runtime/globals.hpp"
+#include "runtime/globals_shared.hpp"
#include "utilities/macros.hpp"
#include CPU_HEADER(c2_globals)
@@ -758,16 +758,4 @@
product(bool, UseProfiledLoopPredicate, true, \
"move predicates out of loops based on profiling data") \
-C2_FLAGS(DECLARE_DEVELOPER_FLAG, \
- DECLARE_PD_DEVELOPER_FLAG, \
- DECLARE_PRODUCT_FLAG, \
- DECLARE_PD_PRODUCT_FLAG, \
- DECLARE_DIAGNOSTIC_FLAG, \
- DECLARE_PD_DIAGNOSTIC_FLAG, \
- DECLARE_EXPERIMENTAL_FLAG, \
- DECLARE_NOTPRODUCT_FLAG, \
- IGNORE_RANGE, \
- IGNORE_CONSTRAINT, \
- IGNORE_WRITEABLE)
-
#endif // SHARE_OPTO_C2_GLOBALS_HPP
--- a/src/hotspot/share/opto/compile.cpp Fri May 17 13:21:44 2019 +0100
+++ b/src/hotspot/share/opto/compile.cpp Thu May 23 11:07:37 2019 +0100
@@ -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
@@ -713,16 +713,19 @@
TraceTime t1("Total compilation time", &_t_totalCompilation, CITime, CITimeVerbose);
TraceTime t2(NULL, &_t_methodCompilation, CITime, false);
-#ifndef PRODUCT
+#if defined(SUPPORT_ASSEMBLY) || defined(SUPPORT_ABSTRACT_ASSEMBLY)
bool print_opto_assembly = directive->PrintOptoAssemblyOption;
- if (!print_opto_assembly) {
- bool print_assembly = directive->PrintAssemblyOption;
- if (print_assembly && !Disassembler::can_decode()) {
- tty->print_cr("PrintAssembly request changed to PrintOptoAssembly");
- print_opto_assembly = true;
- }
- }
- set_print_assembly(print_opto_assembly);
+ // We can always print a disassembly, either abstract (hex dump) or
+ // with the help of a suitable hsdis library. Thus, we should not
+ // couple print_assembly and print_opto_assembly controls.
+ // But: always print opto and regular assembly on compile command 'print'.
+ bool print_assembly = directive->PrintAssemblyOption;
+ set_print_assembly(print_opto_assembly || print_assembly);
+#else
+ set_print_assembly(false); // must initialize.
+#endif
+
+#ifndef PRODUCT
set_parsed_irreducible_loop(false);
if (directive->ReplayInlineOption) {
@@ -1027,6 +1030,8 @@
#ifndef PRODUCT
set_print_assembly(PrintFrameConverterAssembly);
set_parsed_irreducible_loop(false);
+#else
+ set_print_assembly(false); // Must initialize.
#endif
set_has_irreducible_loop(false); // no loops
@@ -2552,12 +2557,25 @@
//------------------------------dump_asm---------------------------------------
// Dump formatted assembly
-#ifndef PRODUCT
-void Compile::dump_asm(int *pcs, uint pc_limit) {
+#if defined(SUPPORT_OPTO_ASSEMBLY)
+void Compile::dump_asm_on(outputStream* st, int* pcs, uint pc_limit) {
+
+ int pc_digits = 3; // #chars required for pc
+ int sb_chars = 3; // #chars for "start bundle" indicator
+ int tab_size = 8;
+ if (pcs != NULL) {
+ int max_pc = 0;
+ for (uint i = 0; i < pc_limit; i++) {
+ max_pc = (max_pc < pcs[i]) ? pcs[i] : max_pc;
+ }
+ pc_digits = ((max_pc < 4096) ? 3 : ((max_pc < 65536) ? 4 : ((max_pc < 65536*256) ? 6 : 8))); // #chars required for pc
+ }
+ int prefix_len = ((pc_digits + sb_chars + tab_size - 1)/tab_size)*tab_size;
+
bool cut_short = false;
- tty->print_cr("#");
- tty->print("# "); _tf->dump(); tty->cr();
- tty->print_cr("#");
+ st->print_cr("#");
+ st->print("# "); _tf->dump_on(st); st->cr();
+ st->print_cr("#");
// For all blocks
int pc = 0x0; // Program counter
@@ -2575,16 +2593,18 @@
continue;
}
n = block->head();
- if (pcs && n->_idx < pc_limit) {
- tty->print("%3.3x ", pcs[n->_idx]);
- } else {
- tty->print(" ");
+ if ((pcs != NULL) && (n->_idx < pc_limit)) {
+ pc = pcs[n->_idx];
+ st->print("%*.*x", pc_digits, pc_digits, pc);
}
- block->dump_head(_cfg);
+ st->fill_to(prefix_len);
+ block->dump_head(_cfg, st);
if (block->is_connector()) {
- tty->print_cr(" # Empty connector block");
+ st->fill_to(prefix_len);
+ st->print_cr("# Empty connector block");
} else if (block->num_preds() == 2 && block->pred(1)->is_CatchProj() && block->pred(1)->as_CatchProj()->_con == CatchProjNode::fall_through_index) {
- tty->print_cr(" # Block is sole successor of call");
+ st->fill_to(prefix_len);
+ st->print_cr("# Block is sole successor of call");
}
// For all instructions
@@ -2620,34 +2640,39 @@
!n->is_top() && // Debug info table constants
!(n->is_Con() && !n->is_Mach())// Debug info table constants
) {
- if (pcs && n->_idx < pc_limit)
- tty->print("%3.3x", pcs[n->_idx]);
- else
- tty->print(" ");
- tty->print(" %c ", starts_bundle);
+ if ((pcs != NULL) && (n->_idx < pc_limit)) {
+ pc = pcs[n->_idx];
+ st->print("%*.*x", pc_digits, pc_digits, pc);
+ } else {
+ st->fill_to(pc_digits);
+ }
+ st->print(" %c ", starts_bundle);
starts_bundle = ' ';
- tty->print("\t");
- n->format(_regalloc, tty);
- tty->cr();
+ st->fill_to(prefix_len);
+ n->format(_regalloc, st);
+ st->cr();
}
// If we have an instruction with a delay slot, and have seen a delay,
// then back up and print it
if (valid_bundle_info(n) && node_bundling(n)->use_unconditional_delay()) {
- assert(delay != NULL, "no unconditional delay instruction");
+ // Coverity finding - Explicit null dereferenced.
+ guarantee(delay != NULL, "no unconditional delay instruction");
if (WizardMode) delay->dump();
if (node_bundling(delay)->starts_bundle())
starts_bundle = '+';
- if (pcs && n->_idx < pc_limit)
- tty->print("%3.3x", pcs[n->_idx]);
- else
- tty->print(" ");
- tty->print(" %c ", starts_bundle);
+ if ((pcs != NULL) && (n->_idx < pc_limit)) {
+ pc = pcs[n->_idx];
+ st->print("%*.*x", pc_digits, pc_digits, pc);
+ } else {
+ st->fill_to(pc_digits);
+ }
+ st->print(" %c ", starts_bundle);
starts_bundle = ' ';
- tty->print("\t");
- delay->format(_regalloc, tty);
- tty->cr();
+ st->fill_to(prefix_len);
+ delay->format(_regalloc, st);
+ st->cr();
delay = NULL;
}
@@ -2656,19 +2681,13 @@
// Print the exception table for this offset
_handler_table.print_subtable_for(pc);
}
+ st->bol(); // Make sure we start on a new line
}
-
- if (pcs && n->_idx < pc_limit)
- tty->print_cr("%3.3x", pcs[n->_idx]);
- else
- tty->cr();
-
+ st->cr(); // one empty line between blocks
assert(cut_short || delay == NULL, "no unconditional delay branch");
-
} // End of per-block dump
- tty->cr();
-
- if (cut_short) tty->print_cr("*** disassembly is cut short ***");
+
+ if (cut_short) st->print_cr("*** disassembly is cut short ***");
}
#endif
--- a/src/hotspot/share/opto/compile.hpp Fri May 17 13:21:44 2019 +0100
+++ b/src/hotspot/share/opto/compile.hpp Thu May 23 11:07:37 2019 +0100
@@ -1348,7 +1348,13 @@
static void print_statistics() PRODUCT_RETURN;
// Dump formatted assembly
- void dump_asm(int *pcs = NULL, uint pc_limit = 0) PRODUCT_RETURN;
+#if defined(SUPPORT_OPTO_ASSEMBLY)
+ void dump_asm_on(outputStream* ost, int* pcs, uint pc_limit);
+ void dump_asm(int* pcs = NULL, uint pc_limit = 0) { dump_asm_on(tty, pcs, pc_limit); }
+#else
+ void dump_asm_on(outputStream* ost, int* pcs, uint pc_limit) { return; }
+ void dump_asm(int* pcs = NULL, uint pc_limit = 0) { return; }
+#endif
void dump_pc(int *pcs, int pc_limit, Node *n);
// Verify ADLC assumptions during startup
--- a/src/hotspot/share/opto/graphKit.cpp Fri May 17 13:21:44 2019 +0100
+++ b/src/hotspot/share/opto/graphKit.cpp Thu May 23 11:07:37 2019 +0100
@@ -1859,6 +1859,18 @@
}
}
+// Keep track of MergeMems feeding into other MergeMems
+static void add_mergemem_users_to_worklist(Unique_Node_List& wl, Node* mem) {
+ if (!mem->is_MergeMem()) {
+ return;
+ }
+ for (SimpleDUIterator i(mem); i.has_next(); i.next()) {
+ Node* use = i.get();
+ if (use->is_MergeMem()) {
+ wl.push(use);
+ }
+ }
+}
// Replace the call with the current state of the kit.
void GraphKit::replace_call(CallNode* call, Node* result, bool do_replaced_nodes) {
@@ -1877,6 +1889,7 @@
CallProjections callprojs;
call->extract_projections(&callprojs, true);
+ Unique_Node_List wl;
Node* init_mem = call->in(TypeFunc::Memory);
Node* final_mem = final_state->in(TypeFunc::Memory);
Node* final_ctl = final_state->in(TypeFunc::Control);
@@ -1892,6 +1905,7 @@
final_mem = _gvn.transform(final_mem);
}
C->gvn_replace_by(callprojs.fallthrough_memproj, final_mem);
+ add_mergemem_users_to_worklist(wl, final_mem);
}
if (callprojs.fallthrough_ioproj != NULL) {
C->gvn_replace_by(callprojs.fallthrough_ioproj, final_io);
@@ -1931,7 +1945,9 @@
ex_ctl = ekit.control();
}
if (callprojs.catchall_memproj != NULL) {
- C->gvn_replace_by(callprojs.catchall_memproj, ekit.reset_memory());
+ Node* ex_mem = ekit.reset_memory();
+ C->gvn_replace_by(callprojs.catchall_memproj, ex_mem);
+ add_mergemem_users_to_worklist(wl, ex_mem);
}
if (callprojs.catchall_ioproj != NULL) {
C->gvn_replace_by(callprojs.catchall_ioproj, ekit.i_o());
@@ -1949,17 +1965,8 @@
// Clean up any MergeMems that feed other MergeMems since the
// optimizer doesn't like that.
- if (final_mem->is_MergeMem()) {
- Node_List wl;
- for (SimpleDUIterator i(final_mem); i.has_next(); i.next()) {
- Node* m = i.get();
- if (m->is_MergeMem() && !wl.contains(m)) {
- wl.push(m);
- }
- }
- while (wl.size() > 0) {
- _gvn.transform(wl.pop());
- }
+ while (wl.size() > 0) {
+ _gvn.transform(wl.pop());
}
if (callprojs.fallthrough_catchproj != NULL && !final_ctl->is_top() && do_replaced_nodes) {
--- a/src/hotspot/share/opto/output.cpp Fri May 17 13:21:44 2019 +0100
+++ b/src/hotspot/share/opto/output.cpp Thu May 23 11:07:37 2019 +0100
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1998, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1998, 2019, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -1106,12 +1106,17 @@
#endif
// Create an array of unused labels, one for each basic block, if printing is enabled
-#ifndef PRODUCT
+#if defined(SUPPORT_OPTO_ASSEMBLY)
int *node_offsets = NULL;
uint node_offset_limit = unique();
- if (print_assembly())
- node_offsets = NEW_RESOURCE_ARRAY(int, node_offset_limit);
+ if (print_assembly()) {
+ node_offsets = NEW_RESOURCE_ARRAY(int, node_offset_limit);
+ }
+ if (node_offsets != NULL) {
+ // We need to initialize. Unused array elements may contain garbage and mess up PrintOptoAssembly.
+ memset(node_offsets, 0, node_offset_limit*sizeof(int));
+ }
#endif
NonSafepointEmitter non_safepoints(this); // emit non-safepoints lazily
@@ -1381,9 +1386,10 @@
}
// Save the offset for the listing
-#ifndef PRODUCT
- if (node_offsets && n->_idx < node_offset_limit)
+#if defined(SUPPORT_OPTO_ASSEMBLY)
+ if ((node_offsets != NULL) && (n->_idx < node_offset_limit)) {
node_offsets[n->_idx] = cb->insts_size();
+ }
#endif
// "Normal" instruction case
@@ -1430,9 +1436,10 @@
cb->set_insts_end(cb->insts_end() - Pipeline::instr_unit_size());
// Save the offset for the listing
-#ifndef PRODUCT
- if (node_offsets && delay_slot->_idx < node_offset_limit)
+#if defined(SUPPORT_OPTO_ASSEMBLY)
+ if ((node_offsets != NULL) && (delay_slot->_idx < node_offset_limit)) {
node_offsets[delay_slot->_idx] = cb->insts_size();
+ }
#endif
// Support a SafePoint in the delay slot
@@ -1541,7 +1548,14 @@
return;
}
-#ifndef PRODUCT
+#if defined(SUPPORT_ABSTRACT_ASSEMBLY) || defined(SUPPORT_ASSEMBLY) || defined(SUPPORT_OPTO_ASSEMBLY)
+ if (print_assembly()) {
+ tty->cr();
+ tty->print_cr("============================= C2-compiled nmethod ==============================");
+ }
+#endif
+
+#if defined(SUPPORT_OPTO_ASSEMBLY)
// Dump the assembly code, including basic-block numbers
if (print_assembly()) {
ttyLocker ttyl; // keep the following output all in one block
@@ -1555,11 +1569,15 @@
"");
}
if (method() != NULL) {
+ tty->print_cr("----------------------------------- MetaData -----------------------------------");
method()->print_metadata();
} else if (stub_name() != NULL) {
- tty->print_cr("Generating RuntimeStub - %s", stub_name());
+ tty->print_cr("----------------------------- RuntimeStub %s -------------------------------", stub_name());
}
+ tty->cr();
+ tty->print_cr("--------------------------------- OptoAssembly ---------------------------------");
dump_asm(node_offsets, node_offset_limit);
+ tty->print_cr("--------------------------------------------------------------------------------");
if (xtty != NULL) {
// print_metadata and dump_asm above may safepoint which makes us loose the ttylock.
// Retake lock too make sure the end tag is coherent, and that xmlStream->pop_tag is done
@@ -1570,7 +1588,6 @@
}
}
#endif
-
}
void Compile::FillExceptionTables(uint cnt, uint *call_returns, uint *inct_starts, Label *blk_labels) {
--- a/src/hotspot/share/prims/cdsoffsets.cpp Fri May 17 13:21:44 2019 +0100
+++ b/src/hotspot/share/prims/cdsoffsets.cpp Thu May 23 11:07:37 2019 +0100
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2014, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2014, 2019, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -26,6 +26,7 @@
#include "utilities/macros.hpp"
#if INCLUDE_CDS
#include "runtime/os.hpp"
+#include "memory/dynamicArchive.hpp"
#include "memory/filemap.hpp"
#include "memory/allocation.hpp"
#include "memory/allocation.inline.hpp"
@@ -44,6 +45,7 @@
#define CREATE_OFFSET_MAPS \
_all = new CDSOffsets("size_t_size", sizeof(size_t), NULL); \
+ ADD_NEXT(_all, "int_size", sizeof(int)); \
ADD_NEXT(_all, "FileMapHeader::_magic", offset_of(FileMapHeader, _magic)); \
ADD_NEXT(_all, "FileMapHeader::_crc", offset_of(FileMapHeader, _crc)); \
ADD_NEXT(_all, "FileMapHeader::_version", offset_of(FileMapHeader, _version)); \
@@ -52,6 +54,7 @@
ADD_NEXT(_all, "CDSFileMapRegion::_used", offset_of(CDSFileMapRegion, _used)); \
ADD_NEXT(_all, "FileMapHeader::_paths_misc_info_size", offset_of(FileMapHeader, _paths_misc_info_size)); \
ADD_NEXT(_all, "file_header_size", sizeof(FileMapHeader)); \
+ ADD_NEXT(_all, "DynamicArchiveHeader::_base_archive_crc", offset_of(DynamicArchiveHeader, _base_archive_crc)); \
ADD_NEXT(_all, "CDSFileMapRegion_size", sizeof(CDSFileMapRegion));
int CDSOffsets::find_offset(const char* name) {
--- a/src/hotspot/share/prims/forte.cpp Fri May 17 13:21:44 2019 +0100
+++ b/src/hotspot/share/prims/forte.cpp Thu May 23 11:07:37 2019 +0100
@@ -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
@@ -70,7 +70,7 @@
// Native interfaces for use by Forte tools.
-#if !defined(IA64) && !defined(PPC64)
+#if !defined(IA64)
class vframeStreamForte : public vframeStreamCommon {
public:
@@ -639,16 +639,16 @@
#endif // !_WINDOWS
} // end extern "C"
-#endif // !IA64 && !PPC64
+#endif // !IA64
void Forte::register_stub(const char* name, address start, address end) {
-#if !defined(_WINDOWS) && !defined(IA64) && !defined(PPC64)
+#if !defined(_WINDOWS) && !defined(IA64)
assert(pointer_delta(end, start, sizeof(jbyte)) < INT_MAX,
"Code size exceeds maximum range");
collector_func_load((char*)name, NULL, NULL, start,
pointer_delta(end, start, sizeof(jbyte)), 0, NULL);
-#endif // !_WINDOWS && !IA64 && !PPC64
+#endif // !_WINDOWS && !IA64
}
#else // INCLUDE_JVMTI
--- a/src/hotspot/share/prims/jvm.cpp Fri May 17 13:21:44 2019 +0100
+++ b/src/hotspot/share/prims/jvm.cpp Thu May 23 11:07:37 2019 +0100
@@ -64,6 +64,7 @@
#include "runtime/init.hpp"
#include "runtime/interfaceSupport.inline.hpp"
#include "runtime/deoptimization.hpp"
+#include "runtime/handshake.hpp"
#include "runtime/java.hpp"
#include "runtime/javaCalls.hpp"
#include "runtime/jfieldIDWorkaround.hpp"
@@ -3006,31 +3007,47 @@
return JNIHandles::make_local(env, jthread);
JVM_END
+class CountStackFramesTC : public ThreadClosure {
+ int _count;
+ bool _suspended;
+ public:
+ CountStackFramesTC() : _count(0), _suspended(false) {}
+ virtual void do_thread(Thread* thread) {
+ JavaThread* jt = (JavaThread*)thread;
+ if (!jt->is_external_suspend()) {
+ // To keep same behavior we fail this operation,
+ // even if it would work perfectly.
+ return;
+ }
+ _suspended = true;
+ // Count all java activation, i.e., number of vframes.
+ for (vframeStream vfst(jt); !vfst.at_end(); vfst.next()) {
+ // Native frames are not counted.
+ if (!vfst.method()->is_native()) _count++;
+ }
+ }
+ int count() { return _count; }
+ int suspended() { return _suspended; }
+};
JVM_ENTRY(jint, JVM_CountStackFrames(JNIEnv* env, jobject jthread))
JVMWrapper("JVM_CountStackFrames");
- uint32_t debug_bits = 0;
ThreadsListHandle tlh(thread);
JavaThread* receiver = NULL;
bool is_alive = tlh.cv_internal_thread_to_JavaThread(jthread, &receiver, NULL);
- int count = 0;
if (is_alive) {
// jthread refers to a live JavaThread.
- if (receiver->is_thread_fully_suspended(true /* wait for suspend completion */, &debug_bits)) {
- // Count all java activation, i.e., number of vframes.
- for (vframeStream vfst(receiver); !vfst.at_end(); vfst.next()) {
- // Native frames are not counted.
- if (!vfst.method()->is_native()) count++;
- }
- } else {
+ CountStackFramesTC csf;
+ Handshake::execute(&csf, receiver);
+ if (!csf.suspended()) {
THROW_MSG_0(vmSymbols::java_lang_IllegalThreadStateException(),
"this thread is not suspended");
}
+ return csf.count();
}
// Implied else: if JavaThread is not alive simply return a count of 0.
-
- return count;
+ return 0;
JVM_END
--- a/src/hotspot/share/prims/whitebox.cpp Fri May 17 13:21:44 2019 +0100
+++ b/src/hotspot/share/prims/whitebox.cpp Thu May 23 11:07:37 2019 +0100
@@ -38,6 +38,7 @@
#include "gc/shared/genArguments.hpp"
#include "gc/shared/genCollectedHeap.hpp"
#include "jvmtifiles/jvmtiEnv.hpp"
+#include "memory/filemap.hpp"
#include "memory/heapShared.inline.hpp"
#include "memory/metaspaceShared.hpp"
#include "memory/metadataFactory.hpp"
@@ -1883,6 +1884,10 @@
return UseSharedSpaces;
WB_END
+WB_ENTRY(jboolean, WB_CDSMemoryMappingFailed(JNIEnv* env, jobject wb))
+ return FileMapInfo::memory_mapping_failed();
+WB_END
+
WB_ENTRY(jboolean, WB_IsShared(JNIEnv* env, jobject wb, jobject obj))
oop obj_oop = JNIHandles::resolve(obj);
return HeapShared::is_archived_object(obj_oop);
@@ -1908,6 +1913,15 @@
}
WB_END
+WB_ENTRY(void, WB_LinkClass(JNIEnv* env, jobject wb, jclass clazz))
+ Klass *k = java_lang_Class::as_Klass(JNIHandles::resolve_non_null(clazz));
+ if (!k->is_instance_klass()) {
+ return;
+ }
+ InstanceKlass *ik = InstanceKlass::cast(k);
+ ik->link_class(THREAD); // may throw verification error
+WB_END
+
WB_ENTRY(jboolean, WB_AreOpenArchiveHeapObjectsMapped(JNIEnv* env))
return HeapShared::open_archive_heap_region_mapped();
WB_END
@@ -2342,10 +2356,12 @@
{CC"isSharedClass", CC"(Ljava/lang/Class;)Z", (void*)&WB_IsSharedClass },
{CC"areSharedStringsIgnored", CC"()Z", (void*)&WB_AreSharedStringsIgnored },
{CC"getResolvedReferences", CC"(Ljava/lang/Class;)Ljava/lang/Object;", (void*)&WB_GetResolvedReferences},
+ {CC"linkClass", CC"(Ljava/lang/Class;)V", (void*)&WB_LinkClass},
{CC"areOpenArchiveHeapObjectsMapped", CC"()Z", (void*)&WB_AreOpenArchiveHeapObjectsMapped},
{CC"isCDSIncludedInVmBuild", CC"()Z", (void*)&WB_IsCDSIncludedInVmBuild },
{CC"isJFRIncludedInVmBuild", CC"()Z", (void*)&WB_IsJFRIncludedInVmBuild },
- {CC"isJavaHeapArchiveSupported", CC"()Z", (void*)&WB_IsJavaHeapArchiveSupported },
+ {CC"isJavaHeapArchiveSupported", CC"()Z", (void*)&WB_IsJavaHeapArchiveSupported },
+ {CC"cdsMemoryMappingFailed", CC"()Z", (void*)&WB_CDSMemoryMappingFailed },
{CC"clearInlineCaches0", CC"(Z)V", (void*)&WB_ClearInlineCaches },
{CC"handshakeWalkStack", CC"(Ljava/lang/Thread;Z)I", (void*)&WB_HandshakeWalkStack },
--- a/src/hotspot/share/runtime/arguments.cpp Fri May 17 13:21:44 2019 +0100
+++ b/src/hotspot/share/runtime/arguments.cpp Thu May 23 11:07:37 2019 +0100
@@ -36,6 +36,7 @@
#include "logging/logStream.hpp"
#include "logging/logTag.hpp"
#include "memory/allocation.inline.hpp"
+#include "memory/filemap.hpp"
#include "oops/oop.inline.hpp"
#include "prims/jvmtiExport.hpp"
#include "runtime/arguments.hpp"
@@ -95,6 +96,7 @@
bool Arguments::_enable_preview = false;
char* Arguments::SharedArchivePath = NULL;
+char* Arguments::SharedDynamicArchivePath = NULL;
AgentLibraryList Arguments::_libraryList;
AgentLibraryList Arguments::_agentList;
@@ -1469,7 +1471,8 @@
"--patch-module"
};
void Arguments::check_unsupported_dumping_properties() {
- assert(DumpSharedSpaces, "this function is only used with -Xshare:dump");
+ assert(DumpSharedSpaces || DynamicDumpSharedSpaces,
+ "this function is only used with CDS dump time");
assert(ARRAY_SIZE(unsupported_properties) == ARRAY_SIZE(unsupported_options), "must be");
// If a vm option is found in the unsupported_options array, vm will exit with an error message.
SystemProperty* sp = system_properties();
@@ -1492,6 +1495,13 @@
bool Arguments::check_unsupported_cds_runtime_properties() {
assert(UseSharedSpaces, "this function is only used with -Xshare:{on,auto}");
assert(ARRAY_SIZE(unsupported_properties) == ARRAY_SIZE(unsupported_options), "must be");
+ if (ArchiveClassesAtExit != NULL) {
+ // dynamic dumping, just return false for now.
+ // check_unsupported_dumping_properties() will be called later to check the same set of
+ // properties, and will exit the VM with the correct error message if the unsupported properties
+ // are used.
+ return false;
+ }
for (uint i = 0; i < ARRAY_SIZE(unsupported_properties); i++) {
if (get_property(unsupported_properties[i]) != NULL) {
if (RequireSharedSpaces) {
@@ -1624,7 +1634,7 @@
if (max_heap_size <= max_heap_for_compressed_oops()) {
#if !defined(COMPILER1) || defined(TIERED)
if (FLAG_IS_DEFAULT(UseCompressedOops)) {
- FLAG_SET_ERGO(bool, UseCompressedOops, true);
+ FLAG_SET_ERGO(UseCompressedOops, true);
}
#endif
} else {
@@ -1653,7 +1663,7 @@
} else {
// Turn on UseCompressedClassPointers too
if (FLAG_IS_DEFAULT(UseCompressedClassPointers)) {
- FLAG_SET_ERGO(bool, UseCompressedClassPointers, true);
+ FLAG_SET_ERGO(UseCompressedClassPointers, true);
}
// Check the CompressedClassSpaceSize to make sure we use compressed klass ptrs.
if (UseCompressedClassPointers) {
@@ -1761,7 +1771,7 @@
DefaultHeapBaseMinAddress,
DefaultHeapBaseMinAddress/G,
HeapBaseMinAddress);
- FLAG_SET_ERGO(size_t, HeapBaseMinAddress, DefaultHeapBaseMinAddress);
+ FLAG_SET_ERGO(HeapBaseMinAddress, DefaultHeapBaseMinAddress);
}
}
@@ -1783,7 +1793,7 @@
}
log_trace(gc, heap)(" Maximum heap size " SIZE_FORMAT, (size_t) reasonable_max);
- FLAG_SET_ERGO(size_t, MaxHeapSize, (size_t)reasonable_max);
+ FLAG_SET_ERGO(MaxHeapSize, (size_t)reasonable_max);
}
// If the minimum or initial heap_size have not been set or requested to be set
@@ -1804,7 +1814,7 @@
reasonable_initial = limit_by_allocatable_memory(reasonable_initial);
log_trace(gc, heap)(" Initial heap size " SIZE_FORMAT, (size_t)reasonable_initial);
- FLAG_SET_ERGO(size_t, InitialHeapSize, (size_t)reasonable_initial);
+ FLAG_SET_ERGO(InitialHeapSize, (size_t)reasonable_initial);
}
// If the minimum heap size has not been set (via -Xms),
// synchronize with InitialHeapSize to avoid errors with the default value.
@@ -1845,10 +1855,10 @@
initHeapSize = limit_by_allocatable_memory(initHeapSize);
if (FLAG_IS_DEFAULT(MaxHeapSize)) {
- if (FLAG_SET_CMDLINE(size_t, MaxHeapSize, initHeapSize) != JVMFlag::SUCCESS) {
+ if (FLAG_SET_CMDLINE(MaxHeapSize, initHeapSize) != JVMFlag::SUCCESS) {
return JNI_EINVAL;
}
- if (FLAG_SET_CMDLINE(size_t, InitialHeapSize, initHeapSize) != JVMFlag::SUCCESS) {
+ if (FLAG_SET_CMDLINE(InitialHeapSize, initHeapSize) != JVMFlag::SUCCESS) {
return JNI_EINVAL;
}
// Currently the minimum size and the initial heap sizes are the same.
@@ -1856,11 +1866,11 @@
}
if (FLAG_IS_DEFAULT(NewSize)) {
// Make the young generation 3/8ths of the total heap.
- if (FLAG_SET_CMDLINE(size_t, NewSize,
+ if (FLAG_SET_CMDLINE(NewSize,
((julong) MaxHeapSize / (julong) 8) * (julong) 3) != JVMFlag::SUCCESS) {
return JNI_EINVAL;
}
- if (FLAG_SET_CMDLINE(size_t, MaxNewSize, NewSize) != JVMFlag::SUCCESS) {
+ if (FLAG_SET_CMDLINE(MaxNewSize, NewSize) != JVMFlag::SUCCESS) {
return JNI_EINVAL;
}
}
@@ -1870,20 +1880,20 @@
#endif
// Increase some data structure sizes for efficiency
- if (FLAG_SET_CMDLINE(size_t, BaseFootPrintEstimate, MaxHeapSize) != JVMFlag::SUCCESS) {
+ if (FLAG_SET_CMDLINE(BaseFootPrintEstimate, MaxHeapSize) != JVMFlag::SUCCESS) {
return JNI_EINVAL;
}
- if (FLAG_SET_CMDLINE(bool, ResizeTLAB, false) != JVMFlag::SUCCESS) {
+ if (FLAG_SET_CMDLINE(ResizeTLAB, false) != JVMFlag::SUCCESS) {
return JNI_EINVAL;
}
- if (FLAG_SET_CMDLINE(size_t, TLABSize, 256 * K) != JVMFlag::SUCCESS) {
+ if (FLAG_SET_CMDLINE(TLABSize, 256 * K) != JVMFlag::SUCCESS) {
return JNI_EINVAL;
}
// See the OldPLABSize comment below, but replace 'after promotion'
// with 'after copying'. YoungPLABSize is the size of the survivor
// space per-gc-thread buffers. The default is 4kw.
- if (FLAG_SET_CMDLINE(size_t, YoungPLABSize, 256 * K) != JVMFlag::SUCCESS) { // Note: this is in words
+ if (FLAG_SET_CMDLINE(YoungPLABSize, 256 * K) != JVMFlag::SUCCESS) { // Note: this is in words
return JNI_EINVAL;
}
@@ -1900,29 +1910,29 @@
// locality. A minor effect may be that larger PLABs reduce the
// number of PLAB allocation events during gc. The value of 8kw
// was arrived at by experimenting with specjbb.
- if (FLAG_SET_CMDLINE(size_t, OldPLABSize, 8 * K) != JVMFlag::SUCCESS) { // Note: this is in words
+ if (FLAG_SET_CMDLINE(OldPLABSize, 8 * K) != JVMFlag::SUCCESS) { // Note: this is in words
return JNI_EINVAL;
}
// Enable parallel GC and adaptive generation sizing
- if (FLAG_SET_CMDLINE(bool, UseParallelGC, true) != JVMFlag::SUCCESS) {
+ if (FLAG_SET_CMDLINE(UseParallelGC, true) != JVMFlag::SUCCESS) {
return JNI_EINVAL;
}
// Encourage steady state memory management
- if (FLAG_SET_CMDLINE(uintx, ThresholdTolerance, 100) != JVMFlag::SUCCESS) {
+ if (FLAG_SET_CMDLINE(ThresholdTolerance, 100) != JVMFlag::SUCCESS) {
return JNI_EINVAL;
}
// This appears to improve mutator locality
- if (FLAG_SET_CMDLINE(bool, ScavengeBeforeFullGC, false) != JVMFlag::SUCCESS) {
+ if (FLAG_SET_CMDLINE(ScavengeBeforeFullGC, false) != JVMFlag::SUCCESS) {
return JNI_EINVAL;
}
// Get around early Solaris scheduling bug
// (affinity vs other jobs on system)
// but disallow DR and offlining (5008695).
- if (FLAG_SET_CMDLINE(bool, BindGCTaskThreadsToCPUs, true) != JVMFlag::SUCCESS) {
+ if (FLAG_SET_CMDLINE(BindGCTaskThreadsToCPUs, true) != JVMFlag::SUCCESS) {
return JNI_EINVAL;
}
@@ -2043,7 +2053,7 @@
#ifndef SUPPORT_RESERVED_STACK_AREA
if (StackReservedPages != 0) {
- FLAG_SET_CMDLINE(intx, StackReservedPages, 0);
+ FLAG_SET_CMDLINE(StackReservedPages, 0);
warning("Reserved Stack Area not supported on this platform");
}
#endif
@@ -2362,7 +2372,7 @@
} else if (!strcmp(tail, ":gc")) {
LogConfiguration::configure_stdout(LogLevel::Info, true, LOG_TAGS(gc));
} else if (!strcmp(tail, ":jni")) {
- if (FLAG_SET_CMDLINE(bool, PrintJNIResolving, true) != JVMFlag::SUCCESS) {
+ if (FLAG_SET_CMDLINE(PrintJNIResolving, true) != JVMFlag::SUCCESS) {
return JNI_EINVAL;
}
}
@@ -2505,24 +2515,24 @@
set_enable_preview();
// -Xnoclassgc
} else if (match_option(option, "-Xnoclassgc")) {
- if (FLAG_SET_CMDLINE(bool, ClassUnloading, false) != JVMFlag::SUCCESS) {
+ if (FLAG_SET_CMDLINE(ClassUnloading, false) != JVMFlag::SUCCESS) {
return JNI_EINVAL;
}
// -Xconcgc
} else if (match_option(option, "-Xconcgc")) {
- if (FLAG_SET_CMDLINE(bool, UseConcMarkSweepGC, true) != JVMFlag::SUCCESS) {
+ if (FLAG_SET_CMDLINE(UseConcMarkSweepGC, true) != JVMFlag::SUCCESS) {
return JNI_EINVAL;
}
handle_extra_cms_flags("-Xconcgc uses UseConcMarkSweepGC");
// -Xnoconcgc
} else if (match_option(option, "-Xnoconcgc")) {
- if (FLAG_SET_CMDLINE(bool, UseConcMarkSweepGC, false) != JVMFlag::SUCCESS) {
+ if (FLAG_SET_CMDLINE(UseConcMarkSweepGC, false) != JVMFlag::SUCCESS) {
return JNI_EINVAL;
}
handle_extra_cms_flags("-Xnoconcgc uses UseConcMarkSweepGC");
// -Xbatch
} else if (match_option(option, "-Xbatch")) {
- if (FLAG_SET_CMDLINE(bool, BackgroundCompilation, false) != JVMFlag::SUCCESS) {
+ if (FLAG_SET_CMDLINE(BackgroundCompilation, false) != JVMFlag::SUCCESS) {
return JNI_EINVAL;
}
// -Xmn for compatibility with other JVM vendors
@@ -2535,10 +2545,10 @@
describe_range_error(errcode);
return JNI_EINVAL;
}
- if (FLAG_SET_CMDLINE(size_t, MaxNewSize, (size_t)long_initial_young_size) != JVMFlag::SUCCESS) {
+ if (FLAG_SET_CMDLINE(MaxNewSize, (size_t)long_initial_young_size) != JVMFlag::SUCCESS) {
return JNI_EINVAL;
}
- if (FLAG_SET_CMDLINE(size_t, NewSize, (size_t)long_initial_young_size) != JVMFlag::SUCCESS) {
+ if (FLAG_SET_CMDLINE(NewSize, (size_t)long_initial_young_size) != JVMFlag::SUCCESS) {
return JNI_EINVAL;
}
// -Xms
@@ -2555,7 +2565,7 @@
MinHeapSize = (size_t)long_initial_heap_size;
// Currently the minimum size and the initial heap sizes are the same.
// Can be overridden with -XX:InitialHeapSize.
- if (FLAG_SET_CMDLINE(size_t, InitialHeapSize, (size_t)long_initial_heap_size) != JVMFlag::SUCCESS) {
+ if (FLAG_SET_CMDLINE(InitialHeapSize, (size_t)long_initial_heap_size) != JVMFlag::SUCCESS) {
return JNI_EINVAL;
}
// -Xmx
@@ -2568,7 +2578,7 @@
describe_range_error(errcode);
return JNI_EINVAL;
}
- if (FLAG_SET_CMDLINE(size_t, MaxHeapSize, (size_t)long_max_heap_size) != JVMFlag::SUCCESS) {
+ if (FLAG_SET_CMDLINE(MaxHeapSize, (size_t)long_max_heap_size) != JVMFlag::SUCCESS) {
return JNI_EINVAL;
}
// Xmaxf
@@ -2581,7 +2591,7 @@
option->optionString);
return JNI_EINVAL;
} else {
- if (FLAG_SET_CMDLINE(uintx, MaxHeapFreeRatio, maxf) != JVMFlag::SUCCESS) {
+ if (FLAG_SET_CMDLINE(MaxHeapFreeRatio, maxf) != JVMFlag::SUCCESS) {
return JNI_EINVAL;
}
}
@@ -2595,7 +2605,7 @@
option->optionString);
return JNI_EINVAL;
} else {
- if (FLAG_SET_CMDLINE(uintx, MinHeapFreeRatio, minf) != JVMFlag::SUCCESS) {
+ if (FLAG_SET_CMDLINE(MinHeapFreeRatio, minf) != JVMFlag::SUCCESS) {
return JNI_EINVAL;
}
}
@@ -2606,7 +2616,7 @@
if (err != JNI_OK) {
return err;
}
- if (FLAG_SET_CMDLINE(intx, ThreadStackSize, value) != JVMFlag::SUCCESS) {
+ if (FLAG_SET_CMDLINE(ThreadStackSize, value) != JVMFlag::SUCCESS) {
return JNI_EINVAL;
}
} else if (match_option(option, "-Xmaxjitcodesize", &tail) ||
@@ -2619,7 +2629,7 @@
"Invalid maximum code cache size: %s.\n", option->optionString);
return JNI_EINVAL;
}
- if (FLAG_SET_CMDLINE(uintx, ReservedCodeCacheSize, (uintx)long_ReservedCodeCacheSize) != JVMFlag::SUCCESS) {
+ if (FLAG_SET_CMDLINE(ReservedCodeCacheSize, (uintx)long_ReservedCodeCacheSize) != JVMFlag::SUCCESS) {
return JNI_EINVAL;
}
// -green
@@ -2633,7 +2643,7 @@
// -Xrs
} else if (match_option(option, "-Xrs")) {
// Classic/EVM option, new functionality
- if (FLAG_SET_CMDLINE(bool, ReduceSignalUsage, true) != JVMFlag::SUCCESS) {
+ if (FLAG_SET_CMDLINE(ReduceSignalUsage, true) != JVMFlag::SUCCESS) {
return JNI_EINVAL;
}
// -Xprof
@@ -2685,7 +2695,7 @@
// Out of the box management support
if (match_option(option, "-Dcom.sun.management", &tail)) {
#if INCLUDE_MANAGEMENT
- if (FLAG_SET_CMDLINE(bool, ManagementServer, true) != JVMFlag::SUCCESS) {
+ if (FLAG_SET_CMDLINE(ManagementServer, true) != JVMFlag::SUCCESS) {
return JNI_EINVAL;
}
// management agent in module jdk.management.agent
@@ -2710,55 +2720,54 @@
set_mode_flags(_comp);
// -Xshare:dump
} else if (match_option(option, "-Xshare:dump")) {
- if (FLAG_SET_CMDLINE(bool, DumpSharedSpaces, true) != JVMFlag::SUCCESS) {
+ if (FLAG_SET_CMDLINE(DumpSharedSpaces, true) != JVMFlag::SUCCESS) {
return JNI_EINVAL;
}
- set_mode_flags(_int); // Prevent compilation, which creates objects
// -Xshare:on
} else if (match_option(option, "-Xshare:on")) {
- if (FLAG_SET_CMDLINE(bool, UseSharedSpaces, true) != JVMFlag::SUCCESS) {
+ if (FLAG_SET_CMDLINE(UseSharedSpaces, true) != JVMFlag::SUCCESS) {
return JNI_EINVAL;
}
- if (FLAG_SET_CMDLINE(bool, RequireSharedSpaces, true) != JVMFlag::SUCCESS) {
+ if (FLAG_SET_CMDLINE(RequireSharedSpaces, true) != JVMFlag::SUCCESS) {
return JNI_EINVAL;
}
- // -Xshare:auto
+ // -Xshare:auto || -XX:ArchiveClassesAtExit=<archive file>
} else if (match_option(option, "-Xshare:auto")) {
- if (FLAG_SET_CMDLINE(bool, UseSharedSpaces, true) != JVMFlag::SUCCESS) {
+ if (FLAG_SET_CMDLINE(UseSharedSpaces, true) != JVMFlag::SUCCESS) {
return JNI_EINVAL;
}
- if (FLAG_SET_CMDLINE(bool, RequireSharedSpaces, false) != JVMFlag::SUCCESS) {
+ if (FLAG_SET_CMDLINE(RequireSharedSpaces, false) != JVMFlag::SUCCESS) {
return JNI_EINVAL;
}
// -Xshare:off
} else if (match_option(option, "-Xshare:off")) {
- if (FLAG_SET_CMDLINE(bool, UseSharedSpaces, false) != JVMFlag::SUCCESS) {
+ if (FLAG_SET_CMDLINE(UseSharedSpaces, false) != JVMFlag::SUCCESS) {
return JNI_EINVAL;
}
- if (FLAG_SET_CMDLINE(bool, RequireSharedSpaces, false) != JVMFlag::SUCCESS) {
+ if (FLAG_SET_CMDLINE(RequireSharedSpaces, false) != JVMFlag::SUCCESS) {
return JNI_EINVAL;
}
// -Xverify
} else if (match_option(option, "-Xverify", &tail)) {
if (strcmp(tail, ":all") == 0 || strcmp(tail, "") == 0) {
- if (FLAG_SET_CMDLINE(bool, BytecodeVerificationLocal, true) != JVMFlag::SUCCESS) {
+ if (FLAG_SET_CMDLINE(BytecodeVerificationLocal, true) != JVMFlag::SUCCESS) {
return JNI_EINVAL;
}
- if (FLAG_SET_CMDLINE(bool, BytecodeVerificationRemote, true) != JVMFlag::SUCCESS) {
+ if (FLAG_SET_CMDLINE(BytecodeVerificationRemote, true) != JVMFlag::SUCCESS) {
return JNI_EINVAL;
}
} else if (strcmp(tail, ":remote") == 0) {
- if (FLAG_SET_CMDLINE(bool, BytecodeVerificationLocal, false) != JVMFlag::SUCCESS) {
+ if (FLAG_SET_CMDLINE(BytecodeVerificationLocal, false) != JVMFlag::SUCCESS) {
return JNI_EINVAL;
}
- if (FLAG_SET_CMDLINE(bool, BytecodeVerificationRemote, true) != JVMFlag::SUCCESS) {
+ if (FLAG_SET_CMDLINE(BytecodeVerificationRemote, true) != JVMFlag::SUCCESS) {
return JNI_EINVAL;
}
} else if (strcmp(tail, ":none") == 0) {
- if (FLAG_SET_CMDLINE(bool, BytecodeVerificationLocal, false) != JVMFlag::SUCCESS) {
+ if (FLAG_SET_CMDLINE(BytecodeVerificationLocal, false) != JVMFlag::SUCCESS) {
return JNI_EINVAL;
}
- if (FLAG_SET_CMDLINE(bool, BytecodeVerificationRemote, false) != JVMFlag::SUCCESS) {
+ if (FLAG_SET_CMDLINE(BytecodeVerificationRemote, false) != JVMFlag::SUCCESS) {
return JNI_EINVAL;
}
warning("Options -Xverify:none and -noverify were deprecated in JDK 13 and will likely be removed in a future release.");
@@ -2818,23 +2827,23 @@
// Need to keep consistency of MaxTenuringThreshold and AlwaysTenure/NeverTenure;
// and the last option wins.
} else if (match_option(option, "-XX:+NeverTenure")) {
- if (FLAG_SET_CMDLINE(bool, NeverTenure, true) != JVMFlag::SUCCESS) {
+ if (FLAG_SET_CMDLINE(NeverTenure, true) != JVMFlag::SUCCESS) {
return JNI_EINVAL;
}
- if (FLAG_SET_CMDLINE(bool, AlwaysTenure, false) != JVMFlag::SUCCESS) {
+ if (FLAG_SET_CMDLINE(AlwaysTenure, false) != JVMFlag::SUCCESS) {
return JNI_EINVAL;
}
- if (FLAG_SET_CMDLINE(uintx, MaxTenuringThreshold, markOopDesc::max_age + 1) != JVMFlag::SUCCESS) {
+ if (FLAG_SET_CMDLINE(MaxTenuringThreshold, markOopDesc::max_age + 1) != JVMFlag::SUCCESS) {
return JNI_EINVAL;
}
} else if (match_option(option, "-XX:+AlwaysTenure")) {
- if (FLAG_SET_CMDLINE(bool, NeverTenure, false) != JVMFlag::SUCCESS) {
+ if (FLAG_SET_CMDLINE(NeverTenure, false) != JVMFlag::SUCCESS) {
return JNI_EINVAL;
}
- if (FLAG_SET_CMDLINE(bool, AlwaysTenure, true) != JVMFlag::SUCCESS) {
+ if (FLAG_SET_CMDLINE(AlwaysTenure, true) != JVMFlag::SUCCESS) {
return JNI_EINVAL;
}
- if (FLAG_SET_CMDLINE(uintx, MaxTenuringThreshold, 0) != JVMFlag::SUCCESS) {
+ if (FLAG_SET_CMDLINE(MaxTenuringThreshold, 0) != JVMFlag::SUCCESS) {
return JNI_EINVAL;
}
} else if (match_option(option, "-XX:MaxTenuringThreshold=", &tail)) {
@@ -2845,65 +2854,65 @@
return JNI_EINVAL;
}
- if (FLAG_SET_CMDLINE(uintx, MaxTenuringThreshold, max_tenuring_thresh) != JVMFlag::SUCCESS) {
+ if (FLAG_SET_CMDLINE(MaxTenuringThreshold, max_tenuring_thresh) != JVMFlag::SUCCESS) {
return JNI_EINVAL;
}
if (MaxTenuringThreshold == 0) {
- if (FLAG_SET_CMDLINE(bool, NeverTenure, false) != JVMFlag::SUCCESS) {
+ if (FLAG_SET_CMDLINE(NeverTenure, false) != JVMFlag::SUCCESS) {
return JNI_EINVAL;
}
- if (FLAG_SET_CMDLINE(bool, AlwaysTenure, true) != JVMFlag::SUCCESS) {
+ if (FLAG_SET_CMDLINE(AlwaysTenure, true) != JVMFlag::SUCCESS) {
return JNI_EINVAL;
}
} else {
- if (FLAG_SET_CMDLINE(bool, NeverTenure, false) != JVMFlag::SUCCESS) {
+ if (FLAG_SET_CMDLINE(NeverTenure, false) != JVMFlag::SUCCESS) {
return JNI_EINVAL;
}
- if (FLAG_SET_CMDLINE(bool, AlwaysTenure, false) != JVMFlag::SUCCESS) {
+ if (FLAG_SET_CMDLINE(AlwaysTenure, false) != JVMFlag::SUCCESS) {
return JNI_EINVAL;
}
}
} else if (match_option(option, "-XX:+DisplayVMOutputToStderr")) {
- if (FLAG_SET_CMDLINE(bool, DisplayVMOutputToStdout, false) != JVMFlag::SUCCESS) {
+ if (FLAG_SET_CMDLINE(DisplayVMOutputToStdout, false) != JVMFlag::SUCCESS) {
return JNI_EINVAL;
}
- if (FLAG_SET_CMDLINE(bool, DisplayVMOutputToStderr, true) != JVMFlag::SUCCESS) {
+ if (FLAG_SET_CMDLINE(DisplayVMOutputToStderr, true) != JVMFlag::SUCCESS) {
return JNI_EINVAL;
}
} else if (match_option(option, "-XX:+DisplayVMOutputToStdout")) {
- if (FLAG_SET_CMDLINE(bool, DisplayVMOutputToStderr, false) != JVMFlag::SUCCESS) {
+ if (FLAG_SET_CMDLINE(DisplayVMOutputToStderr, false) != JVMFlag::SUCCESS) {
return JNI_EINVAL;
}
- if (FLAG_SET_CMDLINE(bool, DisplayVMOutputToStdout, true) != JVMFlag::SUCCESS) {
+ if (FLAG_SET_CMDLINE(DisplayVMOutputToStdout, true) != JVMFlag::SUCCESS) {
return JNI_EINVAL;
}
} else if (match_option(option, "-XX:+ErrorFileToStderr")) {
- if (FLAG_SET_CMDLINE(bool, ErrorFileToStdout, false) != JVMFlag::SUCCESS) {
+ if (FLAG_SET_CMDLINE(ErrorFileToStdout, false) != JVMFlag::SUCCESS) {
return JNI_EINVAL;
}
- if (FLAG_SET_CMDLINE(bool, ErrorFileToStderr, true) != JVMFlag::SUCCESS) {
+ if (FLAG_SET_CMDLINE(ErrorFileToStderr, true) != JVMFlag::SUCCESS) {
return JNI_EINVAL;
}
} else if (match_option(option, "-XX:+ErrorFileToStdout")) {
- if (FLAG_SET_CMDLINE(bool, ErrorFileToStderr, false) != JVMFlag::SUCCESS) {
+ if (FLAG_SET_CMDLINE(ErrorFileToStderr, false) != JVMFlag::SUCCESS) {
return JNI_EINVAL;
}
- if (FLAG_SET_CMDLINE(bool, ErrorFileToStdout, true) != JVMFlag::SUCCESS) {
+ if (FLAG_SET_CMDLINE(ErrorFileToStdout, true) != JVMFlag::SUCCESS) {
return JNI_EINVAL;
}
} else if (match_option(option, "-XX:+ExtendedDTraceProbes")) {
#if defined(DTRACE_ENABLED)
- if (FLAG_SET_CMDLINE(bool, ExtendedDTraceProbes, true) != JVMFlag::SUCCESS) {
+ if (FLAG_SET_CMDLINE(ExtendedDTraceProbes, true) != JVMFlag::SUCCESS) {
return JNI_EINVAL;
}
- if (FLAG_SET_CMDLINE(bool, DTraceMethodProbes, true) != JVMFlag::SUCCESS) {
+ if (FLAG_SET_CMDLINE(DTraceMethodProbes, true) != JVMFlag::SUCCESS) {
return JNI_EINVAL;
}
- if (FLAG_SET_CMDLINE(bool, DTraceAllocProbes, true) != JVMFlag::SUCCESS) {
+ if (FLAG_SET_CMDLINE(DTraceAllocProbes, true) != JVMFlag::SUCCESS) {
return JNI_EINVAL;
}
- if (FLAG_SET_CMDLINE(bool, DTraceMonitorProbes, true) != JVMFlag::SUCCESS) {
+ if (FLAG_SET_CMDLINE(DTraceMonitorProbes, true) != JVMFlag::SUCCESS) {
return JNI_EINVAL;
}
#else // defined(DTRACE_ENABLED)
@@ -2913,11 +2922,11 @@
#endif // defined(DTRACE_ENABLED)
#ifdef ASSERT
} else if (match_option(option, "-XX:+FullGCALot")) {
- if (FLAG_SET_CMDLINE(bool, FullGCALot, true) != JVMFlag::SUCCESS) {
+ if (FLAG_SET_CMDLINE(FullGCALot, true) != JVMFlag::SUCCESS) {
return JNI_EINVAL;
}
// disable scavenge before parallel mark-compact
- if (FLAG_SET_CMDLINE(bool, ScavengeBeforeFullGC, false) != JVMFlag::SUCCESS) {
+ if (FLAG_SET_CMDLINE(ScavengeBeforeFullGC, false) != JVMFlag::SUCCESS) {
return JNI_EINVAL;
}
#endif
@@ -2950,10 +2959,10 @@
// -Xshare:on
// -Xlog:class+path=info
if (PrintSharedArchiveAndExit) {
- if (FLAG_SET_CMDLINE(bool, UseSharedSpaces, true) != JVMFlag::SUCCESS) {
+ if (FLAG_SET_CMDLINE(UseSharedSpaces, true) != JVMFlag::SUCCESS) {
return JNI_EINVAL;
}
- if (FLAG_SET_CMDLINE(bool, RequireSharedSpaces, true) != JVMFlag::SUCCESS) {
+ if (FLAG_SET_CMDLINE(RequireSharedSpaces, true) != JVMFlag::SUCCESS) {
return JNI_EINVAL;
}
LogConfiguration::configure_stdout(LogLevel::Info, true, LOG_TAGS(class, path));
@@ -3078,7 +3087,7 @@
// eventually fix up InitialTenuringThreshold if only MaxTenuringThreshold is set
if (FLAG_IS_DEFAULT(InitialTenuringThreshold) && (InitialTenuringThreshold > MaxTenuringThreshold)) {
- FLAG_SET_ERGO(uintx, InitialTenuringThreshold, MaxTenuringThreshold);
+ FLAG_SET_ERGO(InitialTenuringThreshold, MaxTenuringThreshold);
}
#if !COMPILER2_OR_JVMCI
@@ -3110,15 +3119,24 @@
// the archived Klasses and Java string objects (at dump time only).
UseBiasedLocking = false;
+ // Compiler threads may concurrently update the class metadata (such as method entries), so it's
+ // unsafe with DumpSharedSpaces (which modifies the class metadata in place). Let's disable
+ // compiler just to be safe.
+ //
+ // Note: this is not a concern for DynamicDumpSharedSpaces, which makes a copy of the class metadata
+ // instead of modifying them in place. The copy is inaccessible to the compiler.
+ // TODO: revisit the following for the static archive case.
+ set_mode_flags(_int);
+ }
+ if (DumpSharedSpaces || ArchiveClassesAtExit != NULL) {
// Always verify non-system classes during CDS dump
if (!BytecodeVerificationRemote) {
BytecodeVerificationRemote = true;
log_info(cds)("All non-system classes will be verified (-Xverify:remote) during CDS dump time.");
}
-
- // Compilation is already disabled if the user specifies -Xshare:dump.
- // Disable compilation in case user specifies -XX:+DumpSharedSpaces instead of -Xshare:dump.
- set_mode_flags(_int);
+ }
+ if (ArchiveClassesAtExit == NULL) {
+ FLAG_SET_DEFAULT(DynamicDumpSharedSpaces, false);
}
if (UseSharedSpaces && patch_mod_javabase) {
no_shared_spaces("CDS is disabled when " JAVA_BASE_NAME " module is patched.");
@@ -3427,6 +3445,7 @@
}
}
+#if INCLUDE_CDS
// Sharing support
// Construct the path to the archive
char* Arguments::get_default_shared_archive_path() {
@@ -3446,15 +3465,104 @@
return default_archive_path;
}
-static char* get_shared_archive_path() {
- char *shared_archive_path;
+int Arguments::num_archives(const char* archive_path) {
+ if (archive_path == NULL) {
+ return 0;
+ }
+ int npaths = 1;
+ char* p = (char*)archive_path;
+ while (*p != '\0') {
+ if (*p == os::path_separator()[0]) {
+ npaths++;
+ }
+ p++;
+ }
+ return npaths;
+}
+
+void Arguments::extract_shared_archive_paths(const char* archive_path,
+ char** base_archive_path,
+ char** top_archive_path) {
+ char* begin_ptr = (char*)archive_path;
+ char* end_ptr = strchr((char*)archive_path, os::path_separator()[0]);
+ if (end_ptr == NULL || end_ptr == begin_ptr) {
+ vm_exit_during_initialization("Base archive was not specified", archive_path);
+ }
+ size_t len = end_ptr - begin_ptr;
+ char* cur_path = NEW_C_HEAP_ARRAY(char, len + 1, mtInternal);
+ strncpy(cur_path, begin_ptr, len);
+ cur_path[len] = '\0';
+ FileMapInfo::check_archive((const char*)cur_path, true /*is_static*/);
+ *base_archive_path = cur_path;
+
+ begin_ptr = ++end_ptr;
+ if (*begin_ptr == '\0') {
+ vm_exit_during_initialization("Top archive was not specified", archive_path);
+ }
+ end_ptr = strchr(begin_ptr, '\0');
+ assert(end_ptr != NULL, "sanity");
+ len = end_ptr - begin_ptr;
+ cur_path = NEW_C_HEAP_ARRAY(char, len + 1, mtInternal);
+ strncpy(cur_path, begin_ptr, len + 1);
+ //cur_path[len] = '\0';
+ FileMapInfo::check_archive((const char*)cur_path, false /*is_static*/);
+ *top_archive_path = cur_path;
+}
+
+bool Arguments::init_shared_archive_paths() {
+ if (ArchiveClassesAtExit != NULL) {
+ if (DumpSharedSpaces) {
+ vm_exit_during_initialization("-XX:ArchiveClassesAtExit cannot be used with -Xshare:dump");
+ }
+ if (FLAG_SET_CMDLINE(DynamicDumpSharedSpaces, true) != JVMFlag::SUCCESS) {
+ return false;
+ }
+ check_unsupported_dumping_properties();
+ SharedDynamicArchivePath = os::strdup_check_oom(ArchiveClassesAtExit, mtArguments);
+ }
if (SharedArchiveFile == NULL) {
- shared_archive_path = Arguments::get_default_shared_archive_path();
+ SharedArchivePath = get_default_shared_archive_path();
} else {
- shared_archive_path = os::strdup_check_oom(SharedArchiveFile, mtArguments);
+ int archives = num_archives(SharedArchiveFile);
+ if (DynamicDumpSharedSpaces || DumpSharedSpaces) {
+ if (archives > 1) {
+ vm_exit_during_initialization(
+ "Cannot have more than 1 archive file specified in -XX:SharedArchiveFile during CDS dumping");
+ }
+ if (DynamicDumpSharedSpaces) {
+ if (FileMapInfo::same_files(SharedArchiveFile, ArchiveClassesAtExit)) {
+ vm_exit_during_initialization(
+ "Cannot have the same archive file specified for -XX:SharedArchiveFile and -XX:ArchiveClassesAtExit",
+ SharedArchiveFile);
+ }
+ }
+ }
+ if (!DynamicDumpSharedSpaces && !DumpSharedSpaces){
+ if (archives > 2) {
+ vm_exit_during_initialization(
+ "Cannot have more than 2 archive files specified in the -XX:SharedArchiveFile option");
+ }
+ if (archives == 1) {
+ char* temp_archive_path = os::strdup_check_oom(SharedArchiveFile, mtArguments);
+ int name_size;
+ bool success =
+ FileMapInfo::get_base_archive_name_from_header(temp_archive_path, &name_size, &SharedArchivePath);
+ if (!success) {
+ SharedArchivePath = temp_archive_path;
+ } else {
+ SharedDynamicArchivePath = temp_archive_path;
+ }
+ } else {
+ extract_shared_archive_paths((const char*)SharedArchiveFile,
+ &SharedArchivePath, &SharedDynamicArchivePath);
+ }
+ } else { // CDS dumping
+ SharedArchivePath = os::strdup_check_oom(SharedArchiveFile, mtArguments);
+ }
}
- return shared_archive_path;
+ return (SharedArchivePath != NULL);
}
+#endif // INCLUDE_CDS
#ifndef PRODUCT
// Determine whether LogVMOutput should be implicitly turned on.
@@ -3786,11 +3894,12 @@
return result;
}
- // Call get_shared_archive_path() here, after possible SharedArchiveFile option got parsed.
- SharedArchivePath = get_shared_archive_path();
- if (SharedArchivePath == NULL) {
+#if INCLUDE_CDS
+ // Initialize shared archive paths which could include both base and dynamic archive paths
+ if (!init_shared_archive_paths()) {
return JNI_ENOMEM;
}
+#endif
// Delay warning until here so that we've had a chance to process
// the -XX:-PrintWarnings flag
@@ -3958,7 +4067,7 @@
#if defined(IA32)
// Only server compiler can optimize safepoints well enough.
if (!is_server_compilation_mode_vm()) {
- FLAG_SET_ERGO_IF_DEFAULT(bool, ThreadLocalHandshakes, false);
+ FLAG_SET_ERGO_IF_DEFAULT(ThreadLocalHandshakes, false);
}
#endif
@@ -3975,7 +4084,7 @@
jint Arguments::adjust_after_os() {
if (UseNUMA) {
if (!FLAG_IS_DEFAULT(AllocateHeapAt)) {
- FLAG_SET_ERGO(bool, UseNUMA, false);
+ FLAG_SET_ERGO(UseNUMA, false);
} else if (UseParallelGC || UseParallelOldGC) {
if (FLAG_IS_DEFAULT(MinHeapDeltaBytes)) {
FLAG_SET_DEFAULT(MinHeapDeltaBytes, 64*M);
@@ -3990,7 +4099,7 @@
// all platforms and ParallelGC on Windows will interleave all
// of the heap spaces across NUMA nodes.
if (FLAG_IS_DEFAULT(UseNUMAInterleaving)) {
- FLAG_SET_ERGO(bool, UseNUMAInterleaving, true);
+ FLAG_SET_ERGO(UseNUMAInterleaving, true);
}
}
return JNI_OK;
--- a/src/hotspot/share/runtime/arguments.hpp Fri May 17 13:21:44 2019 +0100
+++ b/src/hotspot/share/runtime/arguments.hpp Thu May 23 11:07:37 2019 +0100
@@ -484,6 +484,11 @@
static AliasedLoggingFlag catch_logging_aliases(const char* name, bool on);
static char* SharedArchivePath;
+ static char* SharedDynamicArchivePath;
+ static int num_archives(const char* archive_path) NOT_CDS_RETURN_(0);
+ static void extract_shared_archive_paths(const char* archive_path,
+ char** base_archive_path,
+ char** top_archive_path) NOT_CDS_RETURN;
public:
// Parses the arguments, first phase
@@ -563,6 +568,7 @@
static vfprintf_hook_t vfprintf_hook() { return _vfprintf_hook; }
static const char* GetSharedArchivePath() { return SharedArchivePath; }
+ static const char* GetSharedDynamicArchivePath() { return SharedDynamicArchivePath; }
// Java launcher properties
static void process_sun_java_launcher_properties(JavaVMInitArgs* args);
@@ -625,7 +631,8 @@
static char* get_appclasspath() { return _java_class_path->value(); }
static void fix_appclasspath();
- static char* get_default_shared_archive_path();
+ static char* get_default_shared_archive_path() NOT_CDS_RETURN_(NULL);
+ static bool init_shared_archive_paths() NOT_CDS_RETURN_(false);
// Operation modi
static Mode mode() { return _mode; }
--- a/src/hotspot/share/runtime/compilationPolicy.cpp Fri May 17 13:21:44 2019 +0100
+++ b/src/hotspot/share/runtime/compilationPolicy.cpp Thu May 23 11:07:37 2019 +0100
@@ -232,7 +232,7 @@
// Lower the compiler count such that all buffers fit into the code cache
_compiler_count = MAX2(max_count, 1);
}
- FLAG_SET_ERGO(intx, CICompilerCount, _compiler_count);
+ FLAG_SET_ERGO(CICompilerCount, _compiler_count);
} else {
_compiler_count = CICompilerCount;
}
--- a/src/hotspot/share/runtime/flags/jvmFlag.cpp Fri May 17 13:21:44 2019 +0100
+++ b/src/hotspot/share/runtime/flags/jvmFlag.cpp Thu May 23 11:07:37 2019 +0100
@@ -957,24 +957,24 @@
}
// Returns the address of the index'th element
-static JVMFlag* address_of_flag(JVMFlagsWithType flag) {
+static JVMFlag* address_of_flag(JVMFlagsEnum flag) {
assert((size_t)flag < JVMFlag::numFlags, "bad command line flag index");
return &JVMFlag::flags[flag];
}
-bool JVMFlagEx::is_default(JVMFlags flag) {
+bool JVMFlagEx::is_default(JVMFlagsEnum flag) {
assert((size_t)flag < JVMFlag::numFlags, "bad command line flag index");
JVMFlag* f = &JVMFlag::flags[flag];
return f->is_default();
}
-bool JVMFlagEx::is_ergo(JVMFlags flag) {
+bool JVMFlagEx::is_ergo(JVMFlagsEnum flag) {
assert((size_t)flag < JVMFlag::numFlags, "bad command line flag index");
JVMFlag* f = &JVMFlag::flags[flag];
return f->is_ergonomic();
}
-bool JVMFlagEx::is_cmdline(JVMFlags flag) {
+bool JVMFlagEx::is_cmdline(JVMFlagsEnum flag) {
assert((size_t)flag < JVMFlag::numFlags, "bad command line flag index");
JVMFlag* f = &JVMFlag::flags[flag];
return f->is_command_line();
@@ -987,7 +987,7 @@
return true;
}
-void JVMFlagEx::setOnCmdLine(JVMFlagsWithType flag) {
+void JVMFlagEx::setOnCmdLine(JVMFlagsEnum flag) {
JVMFlag* faddr = address_of_flag(flag);
assert(faddr != NULL, "Unknown flag");
faddr->set_command_line();
@@ -1040,7 +1040,7 @@
return boolAtPut(result, value, origin);
}
-JVMFlag::Error JVMFlagEx::boolAtPut(JVMFlagsWithType flag, bool value, JVMFlag::Flags origin) {
+JVMFlag::Error JVMFlagEx::boolAtPut(JVMFlagsEnum flag, bool value, JVMFlag::Flags origin) {
JVMFlag* faddr = address_of_flag(flag);
guarantee(faddr != NULL && faddr->is_bool(), "wrong flag type");
return JVMFlag::boolAtPut(faddr, &value, origin);
@@ -1089,7 +1089,7 @@
return intAtPut(result, value, origin);
}
-JVMFlag::Error JVMFlagEx::intAtPut(JVMFlagsWithType flag, int value, JVMFlag::Flags origin) {
+JVMFlag::Error JVMFlagEx::intAtPut(JVMFlagsEnum flag, int value, JVMFlag::Flags origin) {
JVMFlag* faddr = address_of_flag(flag);
guarantee(faddr != NULL && faddr->is_int(), "wrong flag type");
return JVMFlag::intAtPut(faddr, &value, origin);
@@ -1138,7 +1138,7 @@
return uintAtPut(result, value, origin);
}
-JVMFlag::Error JVMFlagEx::uintAtPut(JVMFlagsWithType flag, uint value, JVMFlag::Flags origin) {
+JVMFlag::Error JVMFlagEx::uintAtPut(JVMFlagsEnum flag, uint value, JVMFlag::Flags origin) {
JVMFlag* faddr = address_of_flag(flag);
guarantee(faddr != NULL && faddr->is_uint(), "wrong flag type");
return JVMFlag::uintAtPut(faddr, &value, origin);
@@ -1187,7 +1187,7 @@
return intxAtPut(result, value, origin);
}
-JVMFlag::Error JVMFlagEx::intxAtPut(JVMFlagsWithType flag, intx value, JVMFlag::Flags origin) {
+JVMFlag::Error JVMFlagEx::intxAtPut(JVMFlagsEnum flag, intx value, JVMFlag::Flags origin) {
JVMFlag* faddr = address_of_flag(flag);
guarantee(faddr != NULL && faddr->is_intx(), "wrong flag type");
return JVMFlag::intxAtPut(faddr, &value, origin);
@@ -1236,7 +1236,7 @@
return uintxAtPut(result, value, origin);
}
-JVMFlag::Error JVMFlagEx::uintxAtPut(JVMFlagsWithType flag, uintx value, JVMFlag::Flags origin) {
+JVMFlag::Error JVMFlagEx::uintxAtPut(JVMFlagsEnum flag, uintx value, JVMFlag::Flags origin) {
JVMFlag* faddr = address_of_flag(flag);
guarantee(faddr != NULL && faddr->is_uintx(), "wrong flag type");
return JVMFlag::uintxAtPut(faddr, &value, origin);
@@ -1285,7 +1285,7 @@
return uint64_tAtPut(result, value, origin);
}
-JVMFlag::Error JVMFlagEx::uint64_tAtPut(JVMFlagsWithType flag, uint64_t value, JVMFlag::Flags origin) {
+JVMFlag::Error JVMFlagEx::uint64_tAtPut(JVMFlagsEnum flag, uint64_t value, JVMFlag::Flags origin) {
JVMFlag* faddr = address_of_flag(flag);
guarantee(faddr != NULL && faddr->is_uint64_t(), "wrong flag type");
return JVMFlag::uint64_tAtPut(faddr, &value, origin);
@@ -1335,7 +1335,7 @@
return size_tAtPut(result, value, origin);
}
-JVMFlag::Error JVMFlagEx::size_tAtPut(JVMFlagsWithType flag, size_t value, JVMFlag::Flags origin) {
+JVMFlag::Error JVMFlagEx::size_tAtPut(JVMFlagsEnum flag, size_t value, JVMFlag::Flags origin) {
JVMFlag* faddr = address_of_flag(flag);
guarantee(faddr != NULL && faddr->is_size_t(), "wrong flag type");
return JVMFlag::size_tAtPut(faddr, &value, origin);
@@ -1384,7 +1384,7 @@
return doubleAtPut(result, value, origin);
}
-JVMFlag::Error JVMFlagEx::doubleAtPut(JVMFlagsWithType flag, double value, JVMFlag::Flags origin) {
+JVMFlag::Error JVMFlagEx::doubleAtPut(JVMFlagsEnum flag, double value, JVMFlag::Flags origin) {
JVMFlag* faddr = address_of_flag(flag);
guarantee(faddr != NULL && faddr->is_double(), "wrong flag type");
return JVMFlag::doubleAtPut(faddr, &value, origin);
@@ -1418,7 +1418,7 @@
return check;
}
-JVMFlag::Error JVMFlagEx::ccstrAtPut(JVMFlagsWithType flag, ccstr value, JVMFlag::Flags origin) {
+JVMFlag::Error JVMFlagEx::ccstrAtPut(JVMFlagsEnum flag, ccstr value, JVMFlag::Flags origin) {
JVMFlag* faddr = address_of_flag(flag);
guarantee(faddr != NULL && faddr->is_ccstr(), "wrong flag type");
ccstr old_value = faddr->get_ccstr();
@@ -1511,4 +1511,3 @@
va_end(listPointer);
}
}
-
--- a/src/hotspot/share/runtime/flags/jvmFlagConstraintList.cpp Fri May 17 13:21:44 2019 +0100
+++ b/src/hotspot/share/runtime/flags/jvmFlagConstraintList.cpp Thu May 23 11:07:37 2019 +0100
@@ -31,14 +31,9 @@
#include "runtime/flags/jvmFlagConstraintList.hpp"
#include "runtime/flags/jvmFlagConstraintsCompiler.hpp"
#include "runtime/flags/jvmFlagConstraintsRuntime.hpp"
+#include "runtime/globals.hpp"
#include "runtime/os.hpp"
#include "utilities/macros.hpp"
-#ifdef COMPILER1
-#include "c1/c1_globals.hpp"
-#endif
-#ifdef COMPILER2
-#include "opto/c2_globals.hpp"
-#endif
class JVMFlagConstraint_bool : public JVMFlagConstraint {
JVMFlagConstraintFunc_bool _constraint;
@@ -241,27 +236,31 @@
}
// Generate code to call emit_constraint_xxx function
-#define EMIT_CONSTRAINT_PRODUCT_FLAG(type, name, value, doc) ); emit_constraint_##type(#name,&name
-#define EMIT_CONSTRAINT_DIAGNOSTIC_FLAG(type, name, value, doc) ); emit_constraint_##type(#name,&name
-#define EMIT_CONSTRAINT_EXPERIMENTAL_FLAG(type, name, value, doc) ); emit_constraint_##type(#name,&name
-#define EMIT_CONSTRAINT_MANAGEABLE_FLAG(type, name, value, doc) ); emit_constraint_##type(#name,&name
-#define EMIT_CONSTRAINT_PRODUCT_RW_FLAG(type, name, value, doc) ); emit_constraint_##type(#name,&name
-#define EMIT_CONSTRAINT_PD_PRODUCT_FLAG(type, name, doc) ); emit_constraint_##type(#name,&name
-#define EMIT_CONSTRAINT_PD_DIAGNOSTIC_FLAG(type, name, doc) ); emit_constraint_##type(#name,&name
+#define EMIT_CONSTRAINT_START (void)(0
+#define EMIT_CONSTRAINT(type, name) ); emit_constraint_##type(#name, &name
+#define EMIT_CONSTRAINT_NO ); emit_constraint_no(0
+#define EMIT_CONSTRAINT_PRODUCT_FLAG(type, name, value, doc) EMIT_CONSTRAINT(type, name)
+#define EMIT_CONSTRAINT_DIAGNOSTIC_FLAG(type, name, value, doc) EMIT_CONSTRAINT(type, name)
+#define EMIT_CONSTRAINT_EXPERIMENTAL_FLAG(type, name, value, doc) EMIT_CONSTRAINT(type, name)
+#define EMIT_CONSTRAINT_MANAGEABLE_FLAG(type, name, value, doc) EMIT_CONSTRAINT(type, name)
+#define EMIT_CONSTRAINT_PRODUCT_RW_FLAG(type, name, value, doc) EMIT_CONSTRAINT(type, name)
+#define EMIT_CONSTRAINT_PD_PRODUCT_FLAG(type, name, doc) EMIT_CONSTRAINT(type, name)
+#define EMIT_CONSTRAINT_PD_DIAGNOSTIC_FLAG(type, name, doc) EMIT_CONSTRAINT(type, name)
#ifndef PRODUCT
-#define EMIT_CONSTRAINT_DEVELOPER_FLAG(type, name, value, doc) ); emit_constraint_##type(#name,&name
-#define EMIT_CONSTRAINT_PD_DEVELOPER_FLAG(type, name, doc) ); emit_constraint_##type(#name,&name
-#define EMIT_CONSTRAINT_NOTPRODUCT_FLAG(type, name, value, doc) ); emit_constraint_##type(#name,&name
+#define EMIT_CONSTRAINT_DEVELOPER_FLAG(type, name, value, doc) EMIT_CONSTRAINT(type, name)
+#define EMIT_CONSTRAINT_PD_DEVELOPER_FLAG(type, name, doc) EMIT_CONSTRAINT(type, name)
+#define EMIT_CONSTRAINT_NOTPRODUCT_FLAG(type, name, value, doc) EMIT_CONSTRAINT(type, name)
#else
-#define EMIT_CONSTRAINT_DEVELOPER_FLAG(type, name, value, doc) ); emit_constraint_no(#name,&name
-#define EMIT_CONSTRAINT_PD_DEVELOPER_FLAG(type, name, doc) ); emit_constraint_no(#name,&name
-#define EMIT_CONSTRAINT_NOTPRODUCT_FLAG(type, name, value, doc) ); emit_constraint_no(#name,&name
+#define EMIT_CONSTRAINT_DEVELOPER_FLAG(type, name, value, doc) EMIT_CONSTRAINT_NO
+#define EMIT_CONSTRAINT_PD_DEVELOPER_FLAG(type, name, doc) EMIT_CONSTRAINT_NO
+#define EMIT_CONSTRAINT_NOTPRODUCT_FLAG(type, name, value, doc) EMIT_CONSTRAINT_NO
#endif
#ifdef _LP64
-#define EMIT_CONSTRAINT_LP64_PRODUCT_FLAG(type, name, value, doc) ); emit_constraint_##type(#name,&name
+#define EMIT_CONSTRAINT_LP64_PRODUCT_FLAG(type, name, value, doc) EMIT_CONSTRAINT(type, name)
#else
-#define EMIT_CONSTRAINT_LP64_PRODUCT_FLAG(type, name, value, doc) ); emit_constraint_no(#name,&name
+#define EMIT_CONSTRAINT_LP64_PRODUCT_FLAG(type, name, value, doc) EMIT_CONSTRAINT_NO
#endif
+#define EMIT_CONSTRAINT_END );
// Generate func argument to pass into emit_constraint_xxx functions
#define EMIT_CONSTRAINT_CHECK(func, type) , func, JVMFlagConstraint::type
@@ -275,59 +274,26 @@
void JVMFlagConstraintList::init(void) {
_constraints = new (ResourceObj::C_HEAP, mtArguments) GrowableArray<JVMFlagConstraint*>(INITIAL_CONSTRAINTS_SIZE, true);
- emit_constraint_no(NULL VM_FLAGS(EMIT_CONSTRAINT_DEVELOPER_FLAG,
- EMIT_CONSTRAINT_PD_DEVELOPER_FLAG,
- EMIT_CONSTRAINT_PRODUCT_FLAG,
- EMIT_CONSTRAINT_PD_PRODUCT_FLAG,
- EMIT_CONSTRAINT_DIAGNOSTIC_FLAG,
- EMIT_CONSTRAINT_PD_DIAGNOSTIC_FLAG,
- EMIT_CONSTRAINT_EXPERIMENTAL_FLAG,
- EMIT_CONSTRAINT_NOTPRODUCT_FLAG,
- EMIT_CONSTRAINT_MANAGEABLE_FLAG,
- EMIT_CONSTRAINT_PRODUCT_RW_FLAG,
- EMIT_CONSTRAINT_LP64_PRODUCT_FLAG,
- IGNORE_RANGE,
- EMIT_CONSTRAINT_CHECK,
- IGNORE_WRITEABLE));
+ EMIT_CONSTRAINT_START
+
+ ALL_FLAGS(EMIT_CONSTRAINT_DEVELOPER_FLAG,
+ EMIT_CONSTRAINT_PD_DEVELOPER_FLAG,
+ EMIT_CONSTRAINT_PRODUCT_FLAG,
+ EMIT_CONSTRAINT_PD_PRODUCT_FLAG,
+ EMIT_CONSTRAINT_DIAGNOSTIC_FLAG,
+ EMIT_CONSTRAINT_PD_DIAGNOSTIC_FLAG,
+ EMIT_CONSTRAINT_EXPERIMENTAL_FLAG,
+ EMIT_CONSTRAINT_NOTPRODUCT_FLAG,
+ EMIT_CONSTRAINT_MANAGEABLE_FLAG,
+ EMIT_CONSTRAINT_PRODUCT_RW_FLAG,
+ EMIT_CONSTRAINT_LP64_PRODUCT_FLAG,
+ IGNORE_RANGE,
+ EMIT_CONSTRAINT_CHECK,
+ IGNORE_WRITEABLE)
EMIT_CONSTRAINTS_FOR_GLOBALS_EXT
- emit_constraint_no(NULL ARCH_FLAGS(EMIT_CONSTRAINT_DEVELOPER_FLAG,
- EMIT_CONSTRAINT_PRODUCT_FLAG,
- EMIT_CONSTRAINT_DIAGNOSTIC_FLAG,
- EMIT_CONSTRAINT_EXPERIMENTAL_FLAG,
- EMIT_CONSTRAINT_NOTPRODUCT_FLAG,
- IGNORE_RANGE,
- EMIT_CONSTRAINT_CHECK,
- IGNORE_WRITEABLE));
-
-
-#ifdef COMPILER1
- emit_constraint_no(NULL C1_FLAGS(EMIT_CONSTRAINT_DEVELOPER_FLAG,
- EMIT_CONSTRAINT_PD_DEVELOPER_FLAG,
- EMIT_CONSTRAINT_PRODUCT_FLAG,
- EMIT_CONSTRAINT_PD_PRODUCT_FLAG,
- EMIT_CONSTRAINT_DIAGNOSTIC_FLAG,
- EMIT_CONSTRAINT_PD_DIAGNOSTIC_FLAG,
- EMIT_CONSTRAINT_NOTPRODUCT_FLAG,
- IGNORE_RANGE,
- EMIT_CONSTRAINT_CHECK,
- IGNORE_WRITEABLE));
-#endif // COMPILER1
-
-#ifdef COMPILER2
- emit_constraint_no(NULL C2_FLAGS(EMIT_CONSTRAINT_DEVELOPER_FLAG,
- EMIT_CONSTRAINT_PD_DEVELOPER_FLAG,
- EMIT_CONSTRAINT_PRODUCT_FLAG,
- EMIT_CONSTRAINT_PD_PRODUCT_FLAG,
- EMIT_CONSTRAINT_DIAGNOSTIC_FLAG,
- EMIT_CONSTRAINT_PD_DIAGNOSTIC_FLAG,
- EMIT_CONSTRAINT_EXPERIMENTAL_FLAG,
- EMIT_CONSTRAINT_NOTPRODUCT_FLAG,
- IGNORE_RANGE,
- EMIT_CONSTRAINT_CHECK,
- IGNORE_WRITEABLE));
-#endif // COMPILER2
+ EMIT_CONSTRAINT_END
}
JVMFlagConstraint* JVMFlagConstraintList::find(const char* name) {
--- a/src/hotspot/share/runtime/flags/jvmFlagRangeList.cpp Fri May 17 13:21:44 2019 +0100
+++ b/src/hotspot/share/runtime/flags/jvmFlagRangeList.cpp Thu May 23 11:07:37 2019 +0100
@@ -32,7 +32,7 @@
#include "runtime/flags/jvmFlag.hpp"
#include "runtime/flags/jvmFlagConstraintList.hpp"
#include "runtime/flags/jvmFlagRangeList.hpp"
-#include "runtime/globals_extension.hpp"
+#include "runtime/globals.hpp"
#include "runtime/os.hpp"
#include "runtime/task.hpp"
#include "utilities/macros.hpp"
@@ -292,27 +292,31 @@
}
// Generate code to call emit_range_xxx function
-#define EMIT_RANGE_PRODUCT_FLAG(type, name, value, doc) ); emit_range_##type(#name,&name
-#define EMIT_RANGE_DIAGNOSTIC_FLAG(type, name, value, doc) ); emit_range_##type(#name,&name
-#define EMIT_RANGE_EXPERIMENTAL_FLAG(type, name, value, doc) ); emit_range_##type(#name,&name
-#define EMIT_RANGE_MANAGEABLE_FLAG(type, name, value, doc) ); emit_range_##type(#name,&name
-#define EMIT_RANGE_PRODUCT_RW_FLAG(type, name, value, doc) ); emit_range_##type(#name,&name
-#define EMIT_RANGE_PD_PRODUCT_FLAG(type, name, doc) ); emit_range_##type(#name,&name
-#define EMIT_RANGE_PD_DIAGNOSTIC_FLAG(type, name, doc) ); emit_range_##type(#name,&name
+#define EMIT_RANGE_START (void)(0
+#define EMIT_RANGE(type, name) ); emit_range_##type(#name, &name
+#define EMIT_RANGE_NO ); emit_range_no(0
+#define EMIT_RANGE_PRODUCT_FLAG(type, name, value, doc) EMIT_RANGE(type, name)
+#define EMIT_RANGE_DIAGNOSTIC_FLAG(type, name, value, doc) EMIT_RANGE(type, name)
+#define EMIT_RANGE_EXPERIMENTAL_FLAG(type, name, value, doc) EMIT_RANGE(type, name)
+#define EMIT_RANGE_MANAGEABLE_FLAG(type, name, value, doc) EMIT_RANGE(type, name)
+#define EMIT_RANGE_PRODUCT_RW_FLAG(type, name, value, doc) EMIT_RANGE(type, name)
+#define EMIT_RANGE_PD_PRODUCT_FLAG(type, name, doc) EMIT_RANGE(type, name)
+#define EMIT_RANGE_PD_DIAGNOSTIC_FLAG(type, name, doc) EMIT_RANGE(type, name)
#ifndef PRODUCT
-#define EMIT_RANGE_DEVELOPER_FLAG(type, name, value, doc) ); emit_range_##type(#name,&name
-#define EMIT_RANGE_PD_DEVELOPER_FLAG(type, name, doc) ); emit_range_##type(#name,&name
-#define EMIT_RANGE_NOTPRODUCT_FLAG(type, name, value, doc) ); emit_range_##type(#name,&name
+#define EMIT_RANGE_DEVELOPER_FLAG(type, name, value, doc) EMIT_RANGE(type, name)
+#define EMIT_RANGE_PD_DEVELOPER_FLAG(type, name, doc) EMIT_RANGE(type, name)
+#define EMIT_RANGE_NOTPRODUCT_FLAG(type, name, value, doc) EMIT_RANGE(type, name)
#else
-#define EMIT_RANGE_DEVELOPER_FLAG(type, name, value, doc) ); emit_range_no(#name,&name
-#define EMIT_RANGE_PD_DEVELOPER_FLAG(type, name, doc) ); emit_range_no(#name,&name
-#define EMIT_RANGE_NOTPRODUCT_FLAG(type, name, value, doc) ); emit_range_no(#name,&name
+#define EMIT_RANGE_DEVELOPER_FLAG(type, name, value, doc) EMIT_RANGE_NO
+#define EMIT_RANGE_PD_DEVELOPER_FLAG(type, name, doc) EMIT_RANGE_NO
+#define EMIT_RANGE_NOTPRODUCT_FLAG(type, name, value, doc) EMIT_RANGE_NO
#endif
#ifdef _LP64
-#define EMIT_RANGE_LP64_PRODUCT_FLAG(type, name, value, doc) ); emit_range_##type(#name,&name
+#define EMIT_RANGE_LP64_PRODUCT_FLAG(type, name, value, doc) EMIT_RANGE(type, name)
#else
-#define EMIT_RANGE_LP64_PRODUCT_FLAG(type, name, value, doc) ); emit_range_no(#name,&name
+#define EMIT_RANGE_LP64_PRODUCT_FLAG(type, name, value, doc) EMIT_RANGE_NO
#endif
+#define EMIT_RANGE_END );
// Generate func argument to pass into emit_range_xxx functions
#define EMIT_RANGE_CHECK(a, b) , a, b
@@ -325,72 +329,26 @@
_ranges = new (ResourceObj::C_HEAP, mtArguments) GrowableArray<JVMFlagRange*>(INITIAL_RANGES_SIZE, true);
- emit_range_no(NULL VM_FLAGS(EMIT_RANGE_DEVELOPER_FLAG,
- EMIT_RANGE_PD_DEVELOPER_FLAG,
- EMIT_RANGE_PRODUCT_FLAG,
- EMIT_RANGE_PD_PRODUCT_FLAG,
- EMIT_RANGE_DIAGNOSTIC_FLAG,
- EMIT_RANGE_PD_DIAGNOSTIC_FLAG,
- EMIT_RANGE_EXPERIMENTAL_FLAG,
- EMIT_RANGE_NOTPRODUCT_FLAG,
- EMIT_RANGE_MANAGEABLE_FLAG,
- EMIT_RANGE_PRODUCT_RW_FLAG,
- EMIT_RANGE_LP64_PRODUCT_FLAG,
- EMIT_RANGE_CHECK,
- IGNORE_CONSTRAINT,
- IGNORE_WRITEABLE));
+ EMIT_RANGE_START
+
+ ALL_FLAGS(EMIT_RANGE_DEVELOPER_FLAG,
+ EMIT_RANGE_PD_DEVELOPER_FLAG,
+ EMIT_RANGE_PRODUCT_FLAG,
+ EMIT_RANGE_PD_PRODUCT_FLAG,
+ EMIT_RANGE_DIAGNOSTIC_FLAG,
+ EMIT_RANGE_PD_DIAGNOSTIC_FLAG,
+ EMIT_RANGE_EXPERIMENTAL_FLAG,
+ EMIT_RANGE_NOTPRODUCT_FLAG,
+ EMIT_RANGE_MANAGEABLE_FLAG,
+ EMIT_RANGE_PRODUCT_RW_FLAG,
+ EMIT_RANGE_LP64_PRODUCT_FLAG,
+ EMIT_RANGE_CHECK,
+ IGNORE_CONSTRAINT,
+ IGNORE_WRITEABLE)
EMIT_RANGES_FOR_GLOBALS_EXT
- emit_range_no(NULL ARCH_FLAGS(EMIT_RANGE_DEVELOPER_FLAG,
- EMIT_RANGE_PRODUCT_FLAG,
- EMIT_RANGE_DIAGNOSTIC_FLAG,
- EMIT_RANGE_EXPERIMENTAL_FLAG,
- EMIT_RANGE_NOTPRODUCT_FLAG,
- EMIT_RANGE_CHECK,
- IGNORE_CONSTRAINT,
- IGNORE_WRITEABLE));
-
-#if INCLUDE_JVMCI
- emit_range_no(NULL JVMCI_FLAGS(EMIT_RANGE_DEVELOPER_FLAG,
- EMIT_RANGE_PD_DEVELOPER_FLAG,
- EMIT_RANGE_PRODUCT_FLAG,
- EMIT_RANGE_PD_PRODUCT_FLAG,
- EMIT_RANGE_DIAGNOSTIC_FLAG,
- EMIT_RANGE_PD_DIAGNOSTIC_FLAG,
- EMIT_RANGE_EXPERIMENTAL_FLAG,
- EMIT_RANGE_NOTPRODUCT_FLAG,
- EMIT_RANGE_CHECK,
- IGNORE_CONSTRAINT,
- IGNORE_WRITEABLE));
-#endif // INCLUDE_JVMCI
-
-#ifdef COMPILER1
- emit_range_no(NULL C1_FLAGS(EMIT_RANGE_DEVELOPER_FLAG,
- EMIT_RANGE_PD_DEVELOPER_FLAG,
- EMIT_RANGE_PRODUCT_FLAG,
- EMIT_RANGE_PD_PRODUCT_FLAG,
- EMIT_RANGE_DIAGNOSTIC_FLAG,
- EMIT_RANGE_PD_DIAGNOSTIC_FLAG,
- EMIT_RANGE_NOTPRODUCT_FLAG,
- EMIT_RANGE_CHECK,
- IGNORE_CONSTRAINT,
- IGNORE_WRITEABLE));
-#endif // COMPILER1
-
-#ifdef COMPILER2
- emit_range_no(NULL C2_FLAGS(EMIT_RANGE_DEVELOPER_FLAG,
- EMIT_RANGE_PD_DEVELOPER_FLAG,
- EMIT_RANGE_PRODUCT_FLAG,
- EMIT_RANGE_PD_PRODUCT_FLAG,
- EMIT_RANGE_DIAGNOSTIC_FLAG,
- EMIT_RANGE_PD_DIAGNOSTIC_FLAG,
- EMIT_RANGE_EXPERIMENTAL_FLAG,
- EMIT_RANGE_NOTPRODUCT_FLAG,
- EMIT_RANGE_CHECK,
- IGNORE_CONSTRAINT,
- IGNORE_WRITEABLE));
-#endif // COMPILER2
+ EMIT_RANGE_END
}
JVMFlagRange* JVMFlagRangeList::find(const char* name) {
--- a/src/hotspot/share/runtime/flags/jvmFlagWriteableList.cpp Fri May 17 13:21:44 2019 +0100
+++ b/src/hotspot/share/runtime/flags/jvmFlagWriteableList.cpp Thu May 23 11:07:37 2019 +0100
@@ -25,15 +25,6 @@
#include "precompiled.hpp"
#include "runtime/flags/jvmFlagWriteableList.hpp"
#include "runtime/os.hpp"
-#ifdef COMPILER1
-#include "c1/c1_globals.hpp"
-#endif // COMPILER1
-#ifdef COMPILER2
-#include "opto/c2_globals.hpp"
-#endif // COMPILER2
-#if INCLUDE_JVMCI
-#include "jvmci/jvmci_globals.hpp"
-#endif
bool JVMFlagWriteable::is_writeable(void) {
return _writeable;
@@ -93,20 +84,23 @@
}
// Generate code to call emit_writeable_xxx function
-#define EMIT_WRITEABLE_PRODUCT_FLAG(type, name, value, doc) ); emit_writeable_##type(#name
-#define EMIT_WRITEABLE_DIAGNOSTIC_FLAG(type, name, value, doc) ); emit_writeable_##type(#name
-#define EMIT_WRITEABLE_EXPERIMENTAL_FLAG(type, name, value, doc) ); emit_writeable_##type(#name
-#define EMIT_WRITEABLE_MANAGEABLE_FLAG(type, name, value, doc) ); emit_writeable_##type(#name
-#define EMIT_WRITEABLE_PRODUCT_RW_FLAG(type, name, value, doc) ); emit_writeable_##type(#name
-#define EMIT_WRITEABLE_PD_PRODUCT_FLAG(type, name, doc) ); emit_writeable_##type(#name
-#define EMIT_WRITEABLE_DEVELOPER_FLAG(type, name, value, doc) ); emit_writeable_##type(#name
-#define EMIT_WRITEABLE_PD_DEVELOPER_FLAG(type, name, doc) ); emit_writeable_##type(#name
-#define EMIT_WRITEABLE_PD_DIAGNOSTIC_FLAG(type, name, doc) ); emit_writeable_##type(#name
-#define EMIT_WRITEABLE_NOTPRODUCT_FLAG(type, name, value, doc) ); emit_writeable_##type(#name
-#define EMIT_WRITEABLE_LP64_PRODUCT_FLAG(type, name, value, doc) ); emit_writeable_##type(#name
+#define EMIT_WRITEABLE_START (void)(0
+#define EMIT_WRITEABLE(type, name) ); emit_writeable_##type(#name
+#define EMIT_WRITEABLE_PRODUCT_FLAG(type, name, value, doc) EMIT_WRITEABLE(type, name)
+#define EMIT_WRITEABLE_DIAGNOSTIC_FLAG(type, name, value, doc) EMIT_WRITEABLE(type, name)
+#define EMIT_WRITEABLE_EXPERIMENTAL_FLAG(type, name, value, doc) EMIT_WRITEABLE(type, name)
+#define EMIT_WRITEABLE_MANAGEABLE_FLAG(type, name, value, doc) EMIT_WRITEABLE(type, name)
+#define EMIT_WRITEABLE_PRODUCT_RW_FLAG(type, name, value, doc) EMIT_WRITEABLE(type, name)
+#define EMIT_WRITEABLE_PD_PRODUCT_FLAG(type, name, doc) EMIT_WRITEABLE(type, name)
+#define EMIT_WRITEABLE_DEVELOPER_FLAG(type, name, value, doc) EMIT_WRITEABLE(type, name)
+#define EMIT_WRITEABLE_PD_DEVELOPER_FLAG(type, name, doc) EMIT_WRITEABLE(type, name)
+#define EMIT_WRITEABLE_PD_DIAGNOSTIC_FLAG(type, name, doc) EMIT_WRITEABLE(type, name)
+#define EMIT_WRITEABLE_NOTPRODUCT_FLAG(type, name, value, doc) EMIT_WRITEABLE(type, name)
+#define EMIT_WRITEABLE_LP64_PRODUCT_FLAG(type, name, value, doc) EMIT_WRITEABLE(type, name)
+#define EMIT_WRITEABLE_END );
// Generate type argument to pass into emit_writeable_xxx functions
-#define EMIT_WRITEABLE(a) , JVMFlagWriteable::a
+#define EMIT_WRITEABLE_CHECK(a) , JVMFlagWriteable::a
#define INITIAL_WRITEABLES_SIZE 2
GrowableArray<JVMFlagWriteable*>* JVMFlagWriteableList::_controls = NULL;
@@ -115,72 +109,26 @@
_controls = new (ResourceObj::C_HEAP, mtArguments) GrowableArray<JVMFlagWriteable*>(INITIAL_WRITEABLES_SIZE, true);
- emit_writeable_no(NULL VM_FLAGS(EMIT_WRITEABLE_DEVELOPER_FLAG,
- EMIT_WRITEABLE_PD_DEVELOPER_FLAG,
- EMIT_WRITEABLE_PRODUCT_FLAG,
- EMIT_WRITEABLE_PD_PRODUCT_FLAG,
- EMIT_WRITEABLE_DIAGNOSTIC_FLAG,
- EMIT_WRITEABLE_PD_DIAGNOSTIC_FLAG,
- EMIT_WRITEABLE_EXPERIMENTAL_FLAG,
- EMIT_WRITEABLE_NOTPRODUCT_FLAG,
- EMIT_WRITEABLE_MANAGEABLE_FLAG,
- EMIT_WRITEABLE_PRODUCT_RW_FLAG,
- EMIT_WRITEABLE_LP64_PRODUCT_FLAG,
- IGNORE_RANGE,
- IGNORE_CONSTRAINT,
- EMIT_WRITEABLE));
+ EMIT_WRITEABLE_START
+
+ ALL_FLAGS(EMIT_WRITEABLE_DEVELOPER_FLAG,
+ EMIT_WRITEABLE_PD_DEVELOPER_FLAG,
+ EMIT_WRITEABLE_PRODUCT_FLAG,
+ EMIT_WRITEABLE_PD_PRODUCT_FLAG,
+ EMIT_WRITEABLE_DIAGNOSTIC_FLAG,
+ EMIT_WRITEABLE_PD_DIAGNOSTIC_FLAG,
+ EMIT_WRITEABLE_EXPERIMENTAL_FLAG,
+ EMIT_WRITEABLE_NOTPRODUCT_FLAG,
+ EMIT_WRITEABLE_MANAGEABLE_FLAG,
+ EMIT_WRITEABLE_PRODUCT_RW_FLAG,
+ EMIT_WRITEABLE_LP64_PRODUCT_FLAG,
+ IGNORE_RANGE,
+ IGNORE_CONSTRAINT,
+ EMIT_WRITEABLE_CHECK)
EMIT_WRITEABLES_FOR_GLOBALS_EXT
- emit_writeable_no(NULL ARCH_FLAGS(EMIT_WRITEABLE_DEVELOPER_FLAG,
- EMIT_WRITEABLE_PRODUCT_FLAG,
- EMIT_WRITEABLE_DIAGNOSTIC_FLAG,
- EMIT_WRITEABLE_EXPERIMENTAL_FLAG,
- EMIT_WRITEABLE_NOTPRODUCT_FLAG,
- IGNORE_RANGE,
- IGNORE_CONSTRAINT,
- EMIT_WRITEABLE));
-
-#if INCLUDE_JVMCI
- emit_writeable_no(NULL JVMCI_FLAGS(EMIT_WRITEABLE_DEVELOPER_FLAG,
- EMIT_WRITEABLE_PD_DEVELOPER_FLAG,
- EMIT_WRITEABLE_PRODUCT_FLAG,
- EMIT_WRITEABLE_PD_PRODUCT_FLAG,
- EMIT_WRITEABLE_DIAGNOSTIC_FLAG,
- EMIT_WRITEABLE_PD_DIAGNOSTIC_FLAG,
- EMIT_WRITEABLE_EXPERIMENTAL_FLAG,
- EMIT_WRITEABLE_NOTPRODUCT_FLAG,
- IGNORE_RANGE,
- IGNORE_CONSTRAINT,
- EMIT_WRITEABLE));
-#endif // INCLUDE_JVMCI
-
-#ifdef COMPILER1
- emit_writeable_no(NULL C1_FLAGS(EMIT_WRITEABLE_DEVELOPER_FLAG,
- EMIT_WRITEABLE_PD_DEVELOPER_FLAG,
- EMIT_WRITEABLE_PRODUCT_FLAG,
- EMIT_WRITEABLE_PD_PRODUCT_FLAG,
- EMIT_WRITEABLE_DIAGNOSTIC_FLAG,
- EMIT_WRITEABLE_PD_DIAGNOSTIC_FLAG,
- EMIT_WRITEABLE_NOTPRODUCT_FLAG,
- IGNORE_RANGE,
- IGNORE_CONSTRAINT,
- EMIT_WRITEABLE));
-#endif // COMPILER1
-
-#ifdef COMPILER2
- emit_writeable_no(NULL C2_FLAGS(EMIT_WRITEABLE_DEVELOPER_FLAG,
- EMIT_WRITEABLE_PD_DEVELOPER_FLAG,
- EMIT_WRITEABLE_PRODUCT_FLAG,
- EMIT_WRITEABLE_PD_PRODUCT_FLAG,
- EMIT_WRITEABLE_DIAGNOSTIC_FLAG,
- EMIT_WRITEABLE_PD_DIAGNOSTIC_FLAG,
- EMIT_WRITEABLE_EXPERIMENTAL_FLAG,
- EMIT_WRITEABLE_NOTPRODUCT_FLAG,
- IGNORE_RANGE,
- IGNORE_CONSTRAINT,
- EMIT_WRITEABLE));
-#endif // COMPILER2
+ EMIT_WRITEABLE_END
}
JVMFlagWriteable* JVMFlagWriteableList::find(const char* name) {
--- a/src/hotspot/share/runtime/globals.cpp Fri May 17 13:21:44 2019 +0100
+++ b/src/hotspot/share/runtime/globals.cpp Thu May 23 11:07:37 2019 +0100
@@ -30,6 +30,7 @@
#include "runtime/arguments.hpp"
#include "runtime/globals.hpp"
#include "runtime/globals_extension.hpp"
+#include "runtime/globals_shared.hpp"
#include "runtime/flags/jvmFlagConstraintList.hpp"
#include "runtime/flags/jvmFlagWriteableList.hpp"
#include "runtime/os.hpp"
@@ -38,49 +39,44 @@
#include "utilities/macros.hpp"
#include "utilities/ostream.hpp"
#include "utilities/stringUtils.hpp"
-#ifdef COMPILER1
-#include "c1/c1_globals.hpp"
-#endif
-#if INCLUDE_JVMCI
-#include "jvmci/jvmci_globals.hpp"
-#endif
-#ifdef COMPILER2
-#include "opto/c2_globals.hpp"
-#endif
-VM_FLAGS(MATERIALIZE_DEVELOPER_FLAG, \
- MATERIALIZE_PD_DEVELOPER_FLAG, \
- MATERIALIZE_PRODUCT_FLAG, \
- MATERIALIZE_PD_PRODUCT_FLAG, \
- MATERIALIZE_DIAGNOSTIC_FLAG, \
- MATERIALIZE_PD_DIAGNOSTIC_FLAG, \
- MATERIALIZE_EXPERIMENTAL_FLAG, \
- MATERIALIZE_NOTPRODUCT_FLAG, \
- MATERIALIZE_MANAGEABLE_FLAG, \
- MATERIALIZE_PRODUCT_RW_FLAG, \
- MATERIALIZE_LP64_PRODUCT_FLAG, \
- IGNORE_RANGE, \
- IGNORE_CONSTRAINT, \
- IGNORE_WRITEABLE)
+// Implementation macros
+#define MATERIALIZE_PRODUCT_FLAG(type, name, value, doc) type name = value;
+#define MATERIALIZE_PD_PRODUCT_FLAG(type, name, doc) type name = pd_##name;
+#define MATERIALIZE_DIAGNOSTIC_FLAG(type, name, value, doc) type name = value;
+#define MATERIALIZE_PD_DIAGNOSTIC_FLAG(type, name, doc) type name = pd_##name;
+#define MATERIALIZE_EXPERIMENTAL_FLAG(type, name, value, doc) type name = value;
+#define MATERIALIZE_MANAGEABLE_FLAG(type, name, value, doc) type name = value;
+#define MATERIALIZE_PRODUCT_RW_FLAG(type, name, value, doc) type name = value;
+#ifdef PRODUCT
+#define MATERIALIZE_DEVELOPER_FLAG(type, name, value, doc)
+#define MATERIALIZE_PD_DEVELOPER_FLAG(type, name, doc)
+#define MATERIALIZE_NOTPRODUCT_FLAG(type, name, value, doc)
+#else
+#define MATERIALIZE_DEVELOPER_FLAG(type, name, value, doc) type name = value;
+#define MATERIALIZE_PD_DEVELOPER_FLAG(type, name, doc) type name = pd_##name;
+#define MATERIALIZE_NOTPRODUCT_FLAG(type, name, value, doc) type name = value;
+#endif // PRODUCT
+#ifdef _LP64
+#define MATERIALIZE_LP64_PRODUCT_FLAG(type, name, value, doc) type name = value;
+#else
+#define MATERIALIZE_LP64_PRODUCT_FLAG(type, name, value, doc) /* flag is constant */
+#endif // _LP64
-RUNTIME_OS_FLAGS(MATERIALIZE_DEVELOPER_FLAG, \
- MATERIALIZE_PD_DEVELOPER_FLAG, \
- MATERIALIZE_PRODUCT_FLAG, \
- MATERIALIZE_PD_PRODUCT_FLAG, \
- MATERIALIZE_DIAGNOSTIC_FLAG, \
- MATERIALIZE_PD_DIAGNOSTIC_FLAG, \
- MATERIALIZE_NOTPRODUCT_FLAG, \
- IGNORE_RANGE, \
- IGNORE_CONSTRAINT, \
- IGNORE_WRITEABLE)
-ARCH_FLAGS(MATERIALIZE_DEVELOPER_FLAG, \
- MATERIALIZE_PRODUCT_FLAG, \
- MATERIALIZE_DIAGNOSTIC_FLAG, \
- MATERIALIZE_EXPERIMENTAL_FLAG, \
- MATERIALIZE_NOTPRODUCT_FLAG, \
- IGNORE_RANGE, \
- IGNORE_CONSTRAINT, \
- IGNORE_WRITEABLE)
+ALL_FLAGS(MATERIALIZE_DEVELOPER_FLAG, \
+ MATERIALIZE_PD_DEVELOPER_FLAG, \
+ MATERIALIZE_PRODUCT_FLAG, \
+ MATERIALIZE_PD_PRODUCT_FLAG, \
+ MATERIALIZE_DIAGNOSTIC_FLAG, \
+ MATERIALIZE_PD_DIAGNOSTIC_FLAG, \
+ MATERIALIZE_EXPERIMENTAL_FLAG, \
+ MATERIALIZE_NOTPRODUCT_FLAG, \
+ MATERIALIZE_MANAGEABLE_FLAG, \
+ MATERIALIZE_PRODUCT_RW_FLAG, \
+ MATERIALIZE_LP64_PRODUCT_FLAG, \
+ IGNORE_RANGE, \
+ IGNORE_CONSTRAINT, \
+ IGNORE_WRITEABLE)
MATERIALIZE_FLAGS_EXT
--- a/src/hotspot/share/runtime/globals.hpp Fri May 17 13:21:44 2019 +0100
+++ b/src/hotspot/share/runtime/globals.hpp Thu May 23 11:07:37 2019 +0100
@@ -25,115 +25,15 @@
#ifndef SHARE_RUNTIME_GLOBALS_HPP
#define SHARE_RUNTIME_GLOBALS_HPP
+#include "compiler/compiler_globals.hpp"
#include "gc/shared/gc_globals.hpp"
+#include "runtime/globals_shared.hpp"
#include "utilities/align.hpp"
#include "utilities/globalDefinitions.hpp"
#include "utilities/macros.hpp"
-
-#include <float.h> // for DBL_MAX
-
-// The larger HeapWordSize for 64bit requires larger heaps
-// for the same application running in 64bit. See bug 4967770.
-// The minimum alignment to a heap word size is done. Other
-// parts of the memory system may require additional alignment
-// and are responsible for those alignments.
-#ifdef _LP64
-#define ScaleForWordSize(x) align_down_((x) * 13 / 10, HeapWordSize)
-#else
-#define ScaleForWordSize(x) (x)
-#endif
-
-// use this for flags that are true per default in the tiered build
-// but false in non-tiered builds, and vice versa
-#ifdef TIERED
-#define trueInTiered true
-#define falseInTiered false
-#else
-#define trueInTiered false
-#define falseInTiered true
-#endif
-
-// Default and minimum StringTable and SymbolTable size values
-// Must be powers of 2
-const size_t defaultStringTableSize = NOT_LP64(1024) LP64_ONLY(65536);
-const size_t minimumStringTableSize = 128;
-const size_t defaultSymbolTableSize = 32768; // 2^15
-const size_t minimumSymbolTableSize = 1024;
-
#include CPU_HEADER(globals)
#include OS_HEADER(globals)
#include OS_CPU_HEADER(globals)
-#ifdef COMPILER1
-#include CPU_HEADER(c1_globals)
-#include OS_HEADER(c1_globals)
-#endif
-#ifdef COMPILER2
-#include CPU_HEADER(c2_globals)
-#include OS_HEADER(c2_globals)
-#endif
-
-#if !defined(COMPILER1) && !defined(COMPILER2) && !INCLUDE_JVMCI
-define_pd_global(bool, BackgroundCompilation, false);
-define_pd_global(bool, UseTLAB, false);
-define_pd_global(bool, CICompileOSR, false);
-define_pd_global(bool, UseTypeProfile, false);
-define_pd_global(bool, UseOnStackReplacement, false);
-define_pd_global(bool, InlineIntrinsics, false);
-define_pd_global(bool, PreferInterpreterNativeStubs, true);
-define_pd_global(bool, ProfileInterpreter, false);
-define_pd_global(bool, ProfileTraps, false);
-define_pd_global(bool, TieredCompilation, false);
-
-define_pd_global(intx, CompileThreshold, 0);
-
-define_pd_global(intx, OnStackReplacePercentage, 0);
-define_pd_global(bool, ResizeTLAB, false);
-define_pd_global(intx, FreqInlineSize, 0);
-define_pd_global(size_t, NewSizeThreadIncrease, 4*K);
-define_pd_global(bool, InlineClassNatives, true);
-define_pd_global(bool, InlineUnsafeOps, true);
-define_pd_global(uintx, InitialCodeCacheSize, 160*K);
-define_pd_global(uintx, ReservedCodeCacheSize, 32*M);
-define_pd_global(uintx, NonProfiledCodeHeapSize, 0);
-define_pd_global(uintx, ProfiledCodeHeapSize, 0);
-define_pd_global(uintx, NonNMethodCodeHeapSize, 32*M);
-
-define_pd_global(uintx, CodeCacheExpansionSize, 32*K);
-define_pd_global(uintx, CodeCacheMinBlockLength, 1);
-define_pd_global(uintx, CodeCacheMinimumUseSpace, 200*K);
-define_pd_global(size_t, MetaspaceSize, ScaleForWordSize(4*M));
-define_pd_global(bool, NeverActAsServerClassMachine, true);
-define_pd_global(uint64_t,MaxRAM, 1ULL*G);
-#define CI_COMPILER_COUNT 0
-#else
-
-#if COMPILER2_OR_JVMCI
-#define CI_COMPILER_COUNT 2
-#else
-#define CI_COMPILER_COUNT 1
-#endif // COMPILER2_OR_JVMCI
-
-#endif // no compilers
-
-// use this for flags that are true by default in the debug version but
-// false in the optimized version, and vice versa
-#ifdef ASSERT
-#define trueInDebug true
-#define falseInDebug false
-#else
-#define trueInDebug false
-#define falseInDebug true
-#endif
-
-// use this for flags that are true per default in the product build
-// but false in development builds, and vice versa
-#ifdef PRODUCT
-#define trueInProduct true
-#define falseInProduct false
-#else
-#define trueInProduct false
-#define falseInProduct true
-#endif
// develop flags are settable / visible only during development and are constant in the PRODUCT version
// product flags are always settable / visible
@@ -216,6 +116,12 @@
// (multiple times allowed)
//
+// Default and minimum StringTable and SymbolTable size values
+// Must be powers of 2
+const size_t defaultStringTableSize = NOT_LP64(1024) LP64_ONLY(65536);
+const size_t minimumStringTableSize = 128;
+const size_t defaultSymbolTableSize = 32768; // 2^15
+const size_t minimumSymbolTableSize = 1024;
#define RUNTIME_FLAGS(develop, \
develop_pd, \
@@ -2359,6 +2265,9 @@
"shared spaces, and dumps the shared spaces to a file to be " \
"used in future JVM runs") \
\
+ product(bool, DynamicDumpSharedSpaces, false, \
+ "Dynamic archive") \
+ \
product(bool, PrintSharedArchiveAndExit, false, \
"Print shared archive file contents") \
\
@@ -2476,6 +2385,9 @@
product(ccstr, SharedArchiveFile, NULL, \
"Override the default location of the CDS archive file") \
\
+ product(ccstr, ArchiveClassesAtExit, NULL, \
+ "The path and name of the dynamic archive file") \
+ \
product(ccstr, ExtraSharedClassListFile, NULL, \
"Extra classlist for building the CDS archive file") \
\
@@ -2554,57 +2466,6 @@
experimental(bool, UseFastUnorderedTimeStamps, false, \
"Use platform unstable time where supported for timestamps only")
-#define VM_FLAGS(develop, \
- develop_pd, \
- product, \
- product_pd, \
- diagnostic, \
- diagnostic_pd, \
- experimental, \
- notproduct, \
- manageable, \
- product_rw, \
- lp64_product, \
- range, \
- constraint, \
- writeable) \
- \
- RUNTIME_FLAGS( \
- develop, \
- develop_pd, \
- product, \
- product_pd, \
- diagnostic, \
- diagnostic_pd, \
- experimental, \
- notproduct, \
- manageable, \
- product_rw, \
- lp64_product, \
- range, \
- constraint, \
- writeable) \
- \
- GC_FLAGS( \
- develop, \
- develop_pd, \
- product, \
- product_pd, \
- diagnostic, \
- diagnostic_pd, \
- experimental, \
- notproduct, \
- manageable, \
- product_rw, \
- lp64_product, \
- range, \
- constraint, \
- writeable) \
-
-/*
- * Macros for factoring of globals
- */
-
// Interface macros
#define DECLARE_PRODUCT_FLAG(type, name, value, doc) extern "C" type name;
#define DECLARE_PD_PRODUCT_FLAG(type, name, doc) extern "C" type name;
@@ -2629,70 +2490,20 @@
#define DECLARE_LP64_PRODUCT_FLAG(type, name, value, doc) const type name = value;
#endif // _LP64
-// Implementation macros
-#define MATERIALIZE_PRODUCT_FLAG(type, name, value, doc) type name = value;
-#define MATERIALIZE_PD_PRODUCT_FLAG(type, name, doc) type name = pd_##name;
-#define MATERIALIZE_DIAGNOSTIC_FLAG(type, name, value, doc) type name = value;
-#define MATERIALIZE_PD_DIAGNOSTIC_FLAG(type, name, doc) type name = pd_##name;
-#define MATERIALIZE_EXPERIMENTAL_FLAG(type, name, value, doc) type name = value;
-#define MATERIALIZE_MANAGEABLE_FLAG(type, name, value, doc) type name = value;
-#define MATERIALIZE_PRODUCT_RW_FLAG(type, name, value, doc) type name = value;
-#ifdef PRODUCT
-#define MATERIALIZE_DEVELOPER_FLAG(type, name, value, doc)
-#define MATERIALIZE_PD_DEVELOPER_FLAG(type, name, doc)
-#define MATERIALIZE_NOTPRODUCT_FLAG(type, name, value, doc)
-#else
-#define MATERIALIZE_DEVELOPER_FLAG(type, name, value, doc) type name = value;
-#define MATERIALIZE_PD_DEVELOPER_FLAG(type, name, doc) type name = pd_##name;
-#define MATERIALIZE_NOTPRODUCT_FLAG(type, name, value, doc) type name = value;
-#endif // PRODUCT
-#ifdef _LP64
-#define MATERIALIZE_LP64_PRODUCT_FLAG(type, name, value, doc) type name = value;
-#else
-#define MATERIALIZE_LP64_PRODUCT_FLAG(type, name, value, doc) /* flag is constant */
-#endif // _LP64
-
-// Only materialize src code for range checking when required, ignore otherwise
-#define IGNORE_RANGE(a, b)
-// Only materialize src code for contraint checking when required, ignore otherwise
-#define IGNORE_CONSTRAINT(func,type)
-
-#define IGNORE_WRITEABLE(type)
-
-VM_FLAGS(DECLARE_DEVELOPER_FLAG, \
- DECLARE_PD_DEVELOPER_FLAG, \
- DECLARE_PRODUCT_FLAG, \
- DECLARE_PD_PRODUCT_FLAG, \
- DECLARE_DIAGNOSTIC_FLAG, \
- DECLARE_PD_DIAGNOSTIC_FLAG, \
- DECLARE_EXPERIMENTAL_FLAG, \
- DECLARE_NOTPRODUCT_FLAG, \
- DECLARE_MANAGEABLE_FLAG, \
- DECLARE_PRODUCT_RW_FLAG, \
- DECLARE_LP64_PRODUCT_FLAG, \
- IGNORE_RANGE, \
- IGNORE_CONSTRAINT, \
- IGNORE_WRITEABLE)
-
-RUNTIME_OS_FLAGS(DECLARE_DEVELOPER_FLAG, \
- DECLARE_PD_DEVELOPER_FLAG, \
- DECLARE_PRODUCT_FLAG, \
- DECLARE_PD_PRODUCT_FLAG, \
- DECLARE_DIAGNOSTIC_FLAG, \
- DECLARE_PD_DIAGNOSTIC_FLAG, \
- DECLARE_NOTPRODUCT_FLAG, \
- IGNORE_RANGE, \
- IGNORE_CONSTRAINT, \
- IGNORE_WRITEABLE)
-
-ARCH_FLAGS(DECLARE_DEVELOPER_FLAG, \
- DECLARE_PRODUCT_FLAG, \
- DECLARE_DIAGNOSTIC_FLAG, \
- DECLARE_EXPERIMENTAL_FLAG, \
- DECLARE_NOTPRODUCT_FLAG, \
- IGNORE_RANGE, \
- IGNORE_CONSTRAINT, \
- IGNORE_WRITEABLE)
+ALL_FLAGS(DECLARE_DEVELOPER_FLAG, \
+ DECLARE_PD_DEVELOPER_FLAG, \
+ DECLARE_PRODUCT_FLAG, \
+ DECLARE_PD_PRODUCT_FLAG, \
+ DECLARE_DIAGNOSTIC_FLAG, \
+ DECLARE_PD_DIAGNOSTIC_FLAG, \
+ DECLARE_EXPERIMENTAL_FLAG, \
+ DECLARE_NOTPRODUCT_FLAG, \
+ DECLARE_MANAGEABLE_FLAG, \
+ DECLARE_PRODUCT_RW_FLAG, \
+ DECLARE_LP64_PRODUCT_FLAG, \
+ IGNORE_RANGE, \
+ IGNORE_CONSTRAINT, \
+ IGNORE_WRITEABLE)
// Extensions
--- a/src/hotspot/share/runtime/globals_ext.hpp Fri May 17 13:21:44 2019 +0100
+++ b/src/hotspot/share/runtime/globals_ext.hpp Thu May 23 11:07:37 2019 +0100
@@ -29,11 +29,8 @@
// globals_extension.hpp extension
-// Additional JVMFlags enum values
-#define JVMFLAGS_EXT
-
-// Additional JVMFlagsWithType enum values
-#define JVMFLAGSWITHTYPE_EXT
+// Additional JVMFlagsEnum values
+#define JVMFLAGSENUM_EXT
// globals.cpp extension
--- a/src/hotspot/share/runtime/globals_extension.hpp Fri May 17 13:21:44 2019 +0100
+++ b/src/hotspot/share/runtime/globals_extension.hpp Thu May 23 11:07:37 2019 +0100
@@ -27,313 +27,124 @@
#include "runtime/globals.hpp"
#include "utilities/macros.hpp"
-#if INCLUDE_JVMCI
-#include "jvmci/jvmci_globals.hpp"
-#endif
-#ifdef COMPILER1
-#include "c1/c1_globals.hpp"
-#endif
-#ifdef COMPILER2
-#include "opto/c2_globals.hpp"
-#endif
// Construct enum of Flag_<cmdline-arg> constants.
-// Parenthesis left off in the following for the enum decl below.
-#define FLAG_MEMBER(flag) Flag_##flag
+#define FLAG_MEMBER_ENUM(name) Flag_##name##_enum
+#define FLAG_MEMBER_ENUM_(name) FLAG_MEMBER_ENUM(name),
-#define RUNTIME_PRODUCT_FLAG_MEMBER(type, name, value, doc) FLAG_MEMBER(name),
-#define RUNTIME_PD_PRODUCT_FLAG_MEMBER(type, name, doc) FLAG_MEMBER(name),
-#define RUNTIME_DIAGNOSTIC_FLAG_MEMBER(type, name, value, doc) FLAG_MEMBER(name),
-#define RUNTIME_PD_DIAGNOSTIC_FLAG_MEMBER(type, name, doc) FLAG_MEMBER(name),
-#define RUNTIME_EXPERIMENTAL_FLAG_MEMBER(type, name, value, doc) FLAG_MEMBER(name),
-#define RUNTIME_MANAGEABLE_FLAG_MEMBER(type, name, value, doc) FLAG_MEMBER(name),
-#define RUNTIME_PRODUCT_RW_FLAG_MEMBER(type, name, value, doc) FLAG_MEMBER(name),
-#define RUNTIME_DEVELOP_FLAG_MEMBER(type, name, value, doc) FLAG_MEMBER(name),
-#define RUNTIME_PD_DEVELOP_FLAG_MEMBER(type, name, doc) FLAG_MEMBER(name),
-#define RUNTIME_NOTPRODUCT_FLAG_MEMBER(type, name, value, doc) FLAG_MEMBER(name),
-
-#define JVMCI_PRODUCT_FLAG_MEMBER(type, name, value, doc) FLAG_MEMBER(name),
-#define JVMCI_PD_PRODUCT_FLAG_MEMBER(type, name, doc) FLAG_MEMBER(name),
-#define JVMCI_DEVELOP_FLAG_MEMBER(type, name, value, doc) FLAG_MEMBER(name),
-#define JVMCI_PD_DEVELOP_FLAG_MEMBER(type, name, doc) FLAG_MEMBER(name),
-#define JVMCI_DIAGNOSTIC_FLAG_MEMBER(type, name, value, doc) FLAG_MEMBER(name),
-#define JVMCI_PD_DIAGNOSTIC_FLAG_MEMBER(type, name, doc) FLAG_MEMBER(name),
-#define JVMCI_EXPERIMENTAL_FLAG_MEMBER(type, name, value, doc) FLAG_MEMBER(name),
-#define JVMCI_NOTPRODUCT_FLAG_MEMBER(type, name, value, doc) FLAG_MEMBER(name),
-
+#define FLAG_MEMBER_ENUM_PRODUCT(type, name, value, doc) FLAG_MEMBER_ENUM_(name)
+#define FLAG_MEMBER_ENUM_PD_PRODUCT(type, name, doc) FLAG_MEMBER_ENUM_(name)
+#define FLAG_MEMBER_ENUM_DIAGNOSTIC(type, name, value, doc) FLAG_MEMBER_ENUM_(name)
+#define FLAG_MEMBER_ENUM_PD_DIAGNOSTIC(type, name, doc) FLAG_MEMBER_ENUM_(name)
+#define FLAG_MEMBER_ENUM_EXPERIMENTAL(type, name, value, doc) FLAG_MEMBER_ENUM_(name)
+#define FLAG_MEMBER_ENUM_MANAGEABLE(type, name, value, doc) FLAG_MEMBER_ENUM_(name)
+#define FLAG_MEMBER_ENUM_PRODUCT_RW(type, name, value, doc) FLAG_MEMBER_ENUM_(name)
+#define FLAG_MEMBER_ENUM_DEVELOP(type, name, value, doc) FLAG_MEMBER_ENUM_(name)
+#define FLAG_MEMBER_ENUM_PD_DEVELOP(type, name, doc) FLAG_MEMBER_ENUM_(name)
+#define FLAG_MEMBER_ENUM_NOTPRODUCT(type, name, value, doc) FLAG_MEMBER_ENUM_(name)
#ifdef _LP64
-#define RUNTIME_LP64_PRODUCT_FLAG_MEMBER(type, name, value, doc) FLAG_MEMBER(name),
+#define FLAG_MEMBER_ENUM_LP64_PRODUCT(type, name, value, doc) FLAG_MEMBER_ENUM_(name)
#else
-#define RUNTIME_LP64_PRODUCT_FLAG_MEMBER(type, name, value, doc) /* flag is constant */
+#define FLAG_MEMBER_ENUM_LP64_PRODUCT(type, name, value, doc) /* flag is constant */
#endif // _LP64
-#define C1_PRODUCT_FLAG_MEMBER(type, name, value, doc) FLAG_MEMBER(name),
-#define C1_PD_PRODUCT_FLAG_MEMBER(type, name, doc) FLAG_MEMBER(name),
-#define C1_DIAGNOSTIC_FLAG_MEMBER(type, name, value, doc) FLAG_MEMBER(name),
-#define C1_PD_DIAGNOSTIC_FLAG_MEMBER(type, name, doc) FLAG_MEMBER(name),
-#define C1_DEVELOP_FLAG_MEMBER(type, name, value, doc) FLAG_MEMBER(name),
-#define C1_PD_DEVELOP_FLAG_MEMBER(type, name, doc) FLAG_MEMBER(name),
-#define C1_NOTPRODUCT_FLAG_MEMBER(type, name, value, doc) FLAG_MEMBER(name),
-
-#define C2_PRODUCT_FLAG_MEMBER(type, name, value, doc) FLAG_MEMBER(name),
-#define C2_PD_PRODUCT_FLAG_MEMBER(type, name, doc) FLAG_MEMBER(name),
-#define C2_DIAGNOSTIC_FLAG_MEMBER(type, name, value, doc) FLAG_MEMBER(name),
-#define C2_PD_DIAGNOSTIC_FLAG_MEMBER(type, name, doc) FLAG_MEMBER(name),
-#define C2_EXPERIMENTAL_FLAG_MEMBER(type, name, value, doc) FLAG_MEMBER(name),
-#define C2_DEVELOP_FLAG_MEMBER(type, name, value, doc) FLAG_MEMBER(name),
-#define C2_PD_DEVELOP_FLAG_MEMBER(type, name, doc) FLAG_MEMBER(name),
-#define C2_NOTPRODUCT_FLAG_MEMBER(type, name, value, doc) FLAG_MEMBER(name),
-
-#define ARCH_PRODUCT_FLAG_MEMBER(type, name, value, doc) FLAG_MEMBER(name),
-#define ARCH_DIAGNOSTIC_FLAG_MEMBER(type, name, value, doc) FLAG_MEMBER(name),
-#define ARCH_EXPERIMENTAL_FLAG_MEMBER(type, name, value, doc) FLAG_MEMBER(name),
-#define ARCH_DEVELOP_FLAG_MEMBER(type, name, value, doc) FLAG_MEMBER(name),
-#define ARCH_NOTPRODUCT_FLAG_MEMBER(type, name, value, doc) FLAG_MEMBER(name),
-
typedef enum {
- VM_FLAGS(RUNTIME_DEVELOP_FLAG_MEMBER, \
- RUNTIME_PD_DEVELOP_FLAG_MEMBER, \
- RUNTIME_PRODUCT_FLAG_MEMBER, \
- RUNTIME_PD_PRODUCT_FLAG_MEMBER, \
- RUNTIME_DIAGNOSTIC_FLAG_MEMBER, \
- RUNTIME_PD_DIAGNOSTIC_FLAG_MEMBER, \
- RUNTIME_EXPERIMENTAL_FLAG_MEMBER, \
- RUNTIME_NOTPRODUCT_FLAG_MEMBER, \
- RUNTIME_MANAGEABLE_FLAG_MEMBER, \
- RUNTIME_PRODUCT_RW_FLAG_MEMBER, \
- RUNTIME_LP64_PRODUCT_FLAG_MEMBER, \
- IGNORE_RANGE, \
- IGNORE_CONSTRAINT, \
- IGNORE_WRITEABLE)
-
- RUNTIME_OS_FLAGS(RUNTIME_DEVELOP_FLAG_MEMBER, \
- RUNTIME_PD_DEVELOP_FLAG_MEMBER, \
- RUNTIME_PRODUCT_FLAG_MEMBER, \
- RUNTIME_PD_PRODUCT_FLAG_MEMBER, \
- RUNTIME_DIAGNOSTIC_FLAG_MEMBER, \
- RUNTIME_PD_DIAGNOSTIC_FLAG_MEMBER, \
- RUNTIME_NOTPRODUCT_FLAG_MEMBER, \
- IGNORE_RANGE, \
- IGNORE_CONSTRAINT, \
- IGNORE_WRITEABLE)
-#if INCLUDE_JVMCI
- JVMCI_FLAGS(JVMCI_DEVELOP_FLAG_MEMBER, \
- JVMCI_PD_DEVELOP_FLAG_MEMBER, \
- JVMCI_PRODUCT_FLAG_MEMBER, \
- JVMCI_PD_PRODUCT_FLAG_MEMBER, \
- JVMCI_DIAGNOSTIC_FLAG_MEMBER, \
- JVMCI_PD_DIAGNOSTIC_FLAG_MEMBER, \
- JVMCI_EXPERIMENTAL_FLAG_MEMBER, \
- JVMCI_NOTPRODUCT_FLAG_MEMBER, \
- IGNORE_RANGE, \
- IGNORE_CONSTRAINT, \
- IGNORE_WRITEABLE)
-#endif // INCLUDE_JVMCI
-#ifdef COMPILER1
- C1_FLAGS(C1_DEVELOP_FLAG_MEMBER, \
- C1_PD_DEVELOP_FLAG_MEMBER, \
- C1_PRODUCT_FLAG_MEMBER, \
- C1_PD_PRODUCT_FLAG_MEMBER, \
- C1_DIAGNOSTIC_FLAG_MEMBER, \
- C1_PD_DIAGNOSTIC_FLAG_MEMBER, \
- C1_NOTPRODUCT_FLAG_MEMBER, \
- IGNORE_RANGE, \
- IGNORE_CONSTRAINT, \
- IGNORE_WRITEABLE)
-#endif
-#ifdef COMPILER2
- C2_FLAGS(C2_DEVELOP_FLAG_MEMBER, \
- C2_PD_DEVELOP_FLAG_MEMBER, \
- C2_PRODUCT_FLAG_MEMBER, \
- C2_PD_PRODUCT_FLAG_MEMBER, \
- C2_DIAGNOSTIC_FLAG_MEMBER, \
- C2_PD_DIAGNOSTIC_FLAG_MEMBER, \
- C2_EXPERIMENTAL_FLAG_MEMBER, \
- C2_NOTPRODUCT_FLAG_MEMBER, \
- IGNORE_RANGE, \
- IGNORE_CONSTRAINT, \
- IGNORE_WRITEABLE)
-#endif
- ARCH_FLAGS(ARCH_DEVELOP_FLAG_MEMBER, \
- ARCH_PRODUCT_FLAG_MEMBER, \
- ARCH_DIAGNOSTIC_FLAG_MEMBER, \
- ARCH_EXPERIMENTAL_FLAG_MEMBER, \
- ARCH_NOTPRODUCT_FLAG_MEMBER, \
- IGNORE_RANGE, \
- IGNORE_CONSTRAINT, \
+ ALL_FLAGS(FLAG_MEMBER_ENUM_DEVELOP,
+ FLAG_MEMBER_ENUM_PD_DEVELOP,
+ FLAG_MEMBER_ENUM_PRODUCT,
+ FLAG_MEMBER_ENUM_PD_PRODUCT,
+ FLAG_MEMBER_ENUM_DIAGNOSTIC,
+ FLAG_MEMBER_ENUM_PD_DIAGNOSTIC,
+ FLAG_MEMBER_ENUM_EXPERIMENTAL,
+ FLAG_MEMBER_ENUM_NOTPRODUCT,
+ FLAG_MEMBER_ENUM_MANAGEABLE,
+ FLAG_MEMBER_ENUM_PRODUCT_RW,
+ FLAG_MEMBER_ENUM_LP64_PRODUCT,
+ IGNORE_RANGE,
+ IGNORE_CONSTRAINT,
IGNORE_WRITEABLE)
- JVMFLAGS_EXT
- NUM_JVMFlags
-} JVMFlags;
-
-// Construct enum of Flag_<cmdline-arg>_<type> constants.
-
-#define FLAG_MEMBER_WITH_TYPE(flag,type) Flag_##flag##_##type
-
-#define RUNTIME_PRODUCT_FLAG_MEMBER_WITH_TYPE(type, name, value, doc) FLAG_MEMBER_WITH_TYPE(name,type),
-#define RUNTIME_PD_PRODUCT_FLAG_MEMBER_WITH_TYPE(type, name, doc) FLAG_MEMBER_WITH_TYPE(name,type),
-#define RUNTIME_DIAGNOSTIC_FLAG_MEMBER_WITH_TYPE(type, name, value, doc) FLAG_MEMBER_WITH_TYPE(name,type),
-#define RUNTIME_PD_DIAGNOSTIC_FLAG_MEMBER_WITH_TYPE(type, name, doc) FLAG_MEMBER_WITH_TYPE(name,type),
-#define RUNTIME_EXPERIMENTAL_FLAG_MEMBER_WITH_TYPE(type, name, value, doc) FLAG_MEMBER_WITH_TYPE(name,type),
-#define RUNTIME_MANAGEABLE_FLAG_MEMBER_WITH_TYPE(type, name, value, doc) FLAG_MEMBER_WITH_TYPE(name,type),
-#define RUNTIME_PRODUCT_RW_FLAG_MEMBER_WITH_TYPE(type, name, value, doc) FLAG_MEMBER_WITH_TYPE(name,type),
-#define RUNTIME_DEVELOP_FLAG_MEMBER_WITH_TYPE(type, name, value, doc) FLAG_MEMBER_WITH_TYPE(name,type),
-#define RUNTIME_PD_DEVELOP_FLAG_MEMBER_WITH_TYPE(type, name, doc) FLAG_MEMBER_WITH_TYPE(name,type),
-#define RUNTIME_NOTPRODUCT_FLAG_MEMBER_WITH_TYPE(type, name, value, doc) FLAG_MEMBER_WITH_TYPE(name,type),
-
-#define JVMCI_PRODUCT_FLAG_MEMBER_WITH_TYPE(type, name, value, doc) FLAG_MEMBER_WITH_TYPE(name,type),
-#define JVMCI_PD_PRODUCT_FLAG_MEMBER_WITH_TYPE(type, name, doc) FLAG_MEMBER_WITH_TYPE(name,type),
-#define JVMCI_DEVELOP_FLAG_MEMBER_WITH_TYPE(type, name, value, doc) FLAG_MEMBER_WITH_TYPE(name,type),
-#define JVMCI_PD_DEVELOP_FLAG_MEMBER_WITH_TYPE(type, name, doc) FLAG_MEMBER_WITH_TYPE(name,type),
-#define JVMCI_DIAGNOSTIC_FLAG_MEMBER_WITH_TYPE(type, name, value, doc) FLAG_MEMBER_WITH_TYPE(name,type),
-#define JVMCI_PD_DIAGNOSTIC_FLAG_MEMBER_WITH_TYPE(type, name, doc) FLAG_MEMBER_WITH_TYPE(name,type),
-#define JVMCI_EXPERIMENTAL_FLAG_MEMBER_WITH_TYPE(type, name, value, doc) FLAG_MEMBER_WITH_TYPE(name,type),
-#define JVMCI_NOTPRODUCT_FLAG_MEMBER_WITH_TYPE(type, name, value, doc) FLAG_MEMBER_WITH_TYPE(name,type),
-
-#define C1_PRODUCT_FLAG_MEMBER_WITH_TYPE(type, name, value, doc) FLAG_MEMBER_WITH_TYPE(name,type),
-#define C1_PD_PRODUCT_FLAG_MEMBER_WITH_TYPE(type, name, doc) FLAG_MEMBER_WITH_TYPE(name,type),
-#define C1_DIAGNOSTIC_FLAG_MEMBER_WITH_TYPE(type, name, value, doc) FLAG_MEMBER_WITH_TYPE(name,type),
-#define C1_PD_DIAGNOSTIC_FLAG_MEMBER_WITH_TYPE(type, name, doc) FLAG_MEMBER_WITH_TYPE(name,type),
-#define C1_DEVELOP_FLAG_MEMBER_WITH_TYPE(type, name, value, doc) FLAG_MEMBER_WITH_TYPE(name,type),
-#define C1_PD_DEVELOP_FLAG_MEMBER_WITH_TYPE(type, name, doc) FLAG_MEMBER_WITH_TYPE(name,type),
-#define C1_NOTPRODUCT_FLAG_MEMBER_WITH_TYPE(type, name, value, doc) FLAG_MEMBER_WITH_TYPE(name,type),
-
-#ifdef _LP64
-#define RUNTIME_LP64_PRODUCT_FLAG_MEMBER_WITH_TYPE(type, name, value, doc) FLAG_MEMBER_WITH_TYPE(name,type),
-#else
-#define RUNTIME_LP64_PRODUCT_FLAG_MEMBER_WITH_TYPE(type, name, value, doc) /* flag is constant */
-#endif // _LP64
-
-#define C2_PRODUCT_FLAG_MEMBER_WITH_TYPE(type, name, value, doc) FLAG_MEMBER_WITH_TYPE(name,type),
-#define C2_PD_PRODUCT_FLAG_MEMBER_WITH_TYPE(type, name, doc) FLAG_MEMBER_WITH_TYPE(name,type),
-#define C2_DIAGNOSTIC_FLAG_MEMBER_WITH_TYPE(type, name, value, doc) FLAG_MEMBER_WITH_TYPE(name,type),
-#define C2_PD_DIAGNOSTIC_FLAG_MEMBER_WITH_TYPE(type, name, doc) FLAG_MEMBER_WITH_TYPE(name,type),
-#define C2_EXPERIMENTAL_FLAG_MEMBER_WITH_TYPE(type, name, value, doc) FLAG_MEMBER_WITH_TYPE(name,type),
-#define C2_DEVELOP_FLAG_MEMBER_WITH_TYPE(type, name, value, doc) FLAG_MEMBER_WITH_TYPE(name,type),
-#define C2_PD_DEVELOP_FLAG_MEMBER_WITH_TYPE(type, name, doc) FLAG_MEMBER_WITH_TYPE(name,type),
-#define C2_NOTPRODUCT_FLAG_MEMBER_WITH_TYPE(type, name, value, doc) FLAG_MEMBER_WITH_TYPE(name,type),
-
-#define ARCH_PRODUCT_FLAG_MEMBER_WITH_TYPE(type, name, value, doc) FLAG_MEMBER_WITH_TYPE(name,type),
-#define ARCH_DIAGNOSTIC_FLAG_MEMBER_WITH_TYPE(type, name, value, doc) FLAG_MEMBER_WITH_TYPE(name,type),
-#define ARCH_EXPERIMENTAL_FLAG_MEMBER_WITH_TYPE(type, name, value, doc) FLAG_MEMBER_WITH_TYPE(name,type),
-#define ARCH_DEVELOP_FLAG_MEMBER_WITH_TYPE(type, name, value, doc) FLAG_MEMBER_WITH_TYPE(name,type),
-#define ARCH_NOTPRODUCT_FLAG_MEMBER_WITH_TYPE(type, name, value, doc) FLAG_MEMBER_WITH_TYPE(name,type),
-
-typedef enum {
- VM_FLAGS(RUNTIME_DEVELOP_FLAG_MEMBER_WITH_TYPE,
- RUNTIME_PD_DEVELOP_FLAG_MEMBER_WITH_TYPE,
- RUNTIME_PRODUCT_FLAG_MEMBER_WITH_TYPE,
- RUNTIME_PD_PRODUCT_FLAG_MEMBER_WITH_TYPE,
- RUNTIME_DIAGNOSTIC_FLAG_MEMBER_WITH_TYPE,
- RUNTIME_PD_DIAGNOSTIC_FLAG_MEMBER_WITH_TYPE,
- RUNTIME_EXPERIMENTAL_FLAG_MEMBER_WITH_TYPE,
- RUNTIME_NOTPRODUCT_FLAG_MEMBER_WITH_TYPE,
- RUNTIME_MANAGEABLE_FLAG_MEMBER_WITH_TYPE,
- RUNTIME_PRODUCT_RW_FLAG_MEMBER_WITH_TYPE,
- RUNTIME_LP64_PRODUCT_FLAG_MEMBER_WITH_TYPE,
- IGNORE_RANGE,
- IGNORE_CONSTRAINT,
- IGNORE_WRITEABLE)
-
- RUNTIME_OS_FLAGS(RUNTIME_DEVELOP_FLAG_MEMBER_WITH_TYPE,
- RUNTIME_PD_DEVELOP_FLAG_MEMBER_WITH_TYPE,
- RUNTIME_PRODUCT_FLAG_MEMBER_WITH_TYPE,
- RUNTIME_PD_PRODUCT_FLAG_MEMBER_WITH_TYPE,
- RUNTIME_DIAGNOSTIC_FLAG_MEMBER_WITH_TYPE,
- RUNTIME_PD_DIAGNOSTIC_FLAG_MEMBER_WITH_TYPE,
- RUNTIME_NOTPRODUCT_FLAG_MEMBER_WITH_TYPE,
- IGNORE_RANGE,
- IGNORE_CONSTRAINT,
- IGNORE_WRITEABLE)
-#if INCLUDE_JVMCI
- JVMCI_FLAGS(JVMCI_DEVELOP_FLAG_MEMBER_WITH_TYPE,
- JVMCI_PD_DEVELOP_FLAG_MEMBER_WITH_TYPE,
- JVMCI_PRODUCT_FLAG_MEMBER_WITH_TYPE,
- JVMCI_PD_PRODUCT_FLAG_MEMBER_WITH_TYPE,
- JVMCI_DIAGNOSTIC_FLAG_MEMBER_WITH_TYPE,
- JVMCI_PD_DIAGNOSTIC_FLAG_MEMBER_WITH_TYPE,
- JVMCI_EXPERIMENTAL_FLAG_MEMBER_WITH_TYPE,
- JVMCI_NOTPRODUCT_FLAG_MEMBER_WITH_TYPE,
- IGNORE_RANGE,
- IGNORE_CONSTRAINT,
- IGNORE_WRITEABLE)
-#endif // INCLUDE_JVMCI
-#ifdef COMPILER1
- C1_FLAGS(C1_DEVELOP_FLAG_MEMBER_WITH_TYPE,
- C1_PD_DEVELOP_FLAG_MEMBER_WITH_TYPE,
- C1_PRODUCT_FLAG_MEMBER_WITH_TYPE,
- C1_PD_PRODUCT_FLAG_MEMBER_WITH_TYPE,
- C1_DIAGNOSTIC_FLAG_MEMBER_WITH_TYPE,
- C1_PD_DIAGNOSTIC_FLAG_MEMBER_WITH_TYPE,
- C1_NOTPRODUCT_FLAG_MEMBER_WITH_TYPE,
- IGNORE_RANGE,
- IGNORE_CONSTRAINT,
- IGNORE_WRITEABLE)
-#endif
-#ifdef COMPILER2
- C2_FLAGS(C2_DEVELOP_FLAG_MEMBER_WITH_TYPE,
- C2_PD_DEVELOP_FLAG_MEMBER_WITH_TYPE,
- C2_PRODUCT_FLAG_MEMBER_WITH_TYPE,
- C2_PD_PRODUCT_FLAG_MEMBER_WITH_TYPE,
- C2_DIAGNOSTIC_FLAG_MEMBER_WITH_TYPE,
- C2_PD_DIAGNOSTIC_FLAG_MEMBER_WITH_TYPE,
- C2_EXPERIMENTAL_FLAG_MEMBER_WITH_TYPE,
- C2_NOTPRODUCT_FLAG_MEMBER_WITH_TYPE,
- IGNORE_RANGE,
- IGNORE_CONSTRAINT,
- IGNORE_WRITEABLE)
-#endif
- ARCH_FLAGS(ARCH_DEVELOP_FLAG_MEMBER_WITH_TYPE,
- ARCH_PRODUCT_FLAG_MEMBER_WITH_TYPE,
- ARCH_DIAGNOSTIC_FLAG_MEMBER_WITH_TYPE,
- ARCH_EXPERIMENTAL_FLAG_MEMBER_WITH_TYPE,
- ARCH_NOTPRODUCT_FLAG_MEMBER_WITH_TYPE,
- IGNORE_RANGE,
- IGNORE_CONSTRAINT,
- IGNORE_WRITEABLE)
- JVMFLAGSWITHTYPE_EXT
- NUM_JVMFlagsWithType
-} JVMFlagsWithType;
-
-#define FLAG_IS_DEFAULT(name) (JVMFlagEx::is_default(FLAG_MEMBER(name)))
-#define FLAG_IS_ERGO(name) (JVMFlagEx::is_ergo(FLAG_MEMBER(name)))
-#define FLAG_IS_CMDLINE(name) (JVMFlagEx::is_cmdline(FLAG_MEMBER(name)))
-
-#define FLAG_SET_DEFAULT(name, value) ((name) = (value))
-
-#define FLAG_SET_CMDLINE(type, name, value) (JVMFlagEx::setOnCmdLine(FLAG_MEMBER_WITH_TYPE(name, type)), \
- JVMFlagEx::type##AtPut(FLAG_MEMBER_WITH_TYPE(name, type), (type)(value), JVMFlag::COMMAND_LINE))
-#define FLAG_SET_ERGO(type, name, value) (JVMFlagEx::type##AtPut(FLAG_MEMBER_WITH_TYPE(name, type), (type)(value), JVMFlag::ERGONOMIC))
-#define FLAG_SET_MGMT(type, name, value) (JVMFlagEx::type##AtPut(FLAG_MEMBER_WITH_TYPE(name, type), (type)(value), JVMFlag::MANAGEMENT))
-
-#define FLAG_SET_ERGO_IF_DEFAULT(type, name, value) \
- do { \
- if (FLAG_IS_DEFAULT(name)) { \
- FLAG_SET_ERGO(type, name, value); \
- } \
- } while (0)
+ JVMFLAGSENUM_EXT
+ NUM_JVMFlagsEnum
+} JVMFlagsEnum;
// Can't put the following in JVMFlags because
// of a circular dependency on the enum definition.
class JVMFlagEx : JVMFlag {
public:
- static JVMFlag::Error boolAtPut(JVMFlagsWithType flag, bool value, JVMFlag::Flags origin);
- static JVMFlag::Error intAtPut(JVMFlagsWithType flag, int value, JVMFlag::Flags origin);
- static JVMFlag::Error uintAtPut(JVMFlagsWithType flag, uint value, JVMFlag::Flags origin);
- static JVMFlag::Error intxAtPut(JVMFlagsWithType flag, intx value, JVMFlag::Flags origin);
- static JVMFlag::Error uintxAtPut(JVMFlagsWithType flag, uintx value, JVMFlag::Flags origin);
- static JVMFlag::Error uint64_tAtPut(JVMFlagsWithType flag, uint64_t value, JVMFlag::Flags origin);
- static JVMFlag::Error size_tAtPut(JVMFlagsWithType flag, size_t value, JVMFlag::Flags origin);
- static JVMFlag::Error doubleAtPut(JVMFlagsWithType flag, double value, JVMFlag::Flags origin);
+ static JVMFlag::Error boolAtPut(JVMFlagsEnum flag, bool value, JVMFlag::Flags origin);
+ static JVMFlag::Error intAtPut(JVMFlagsEnum flag, int value, JVMFlag::Flags origin);
+ static JVMFlag::Error uintAtPut(JVMFlagsEnum flag, uint value, JVMFlag::Flags origin);
+ static JVMFlag::Error intxAtPut(JVMFlagsEnum flag, intx value, JVMFlag::Flags origin);
+ static JVMFlag::Error uintxAtPut(JVMFlagsEnum flag, uintx value, JVMFlag::Flags origin);
+ static JVMFlag::Error uint64_tAtPut(JVMFlagsEnum flag, uint64_t value, JVMFlag::Flags origin);
+ static JVMFlag::Error size_tAtPut(JVMFlagsEnum flag, size_t value, JVMFlag::Flags origin);
+ static JVMFlag::Error doubleAtPut(JVMFlagsEnum flag, double value, JVMFlag::Flags origin);
// Contract: Flag will make private copy of the incoming value
- static JVMFlag::Error ccstrAtPut(JVMFlagsWithType flag, ccstr value, JVMFlag::Flags origin);
+ static JVMFlag::Error ccstrAtPut(JVMFlagsEnum flag, ccstr value, JVMFlag::Flags origin);
+ static JVMFlag::Error ccstrlistAtPut(JVMFlagsEnum flag, ccstr value, JVMFlag::Flags origin) {
+ return ccstrAtPut(flag, value, origin);
+ }
- static bool is_default(JVMFlags flag);
- static bool is_ergo(JVMFlags flag);
- static bool is_cmdline(JVMFlags flag);
+ static bool is_default(JVMFlagsEnum flag);
+ static bool is_ergo(JVMFlagsEnum flag);
+ static bool is_cmdline(JVMFlagsEnum flag);
- static void setOnCmdLine(JVMFlagsWithType flag);
+ static void setOnCmdLine(JVMFlagsEnum flag);
};
+// Construct set functions for all flags
+
+#define FLAG_MEMBER_SET(name) Flag_##name##_set
+#define FLAG_MEMBER_SET_(type, name) inline JVMFlag::Error FLAG_MEMBER_SET(name)(type value, JVMFlag::Flags origin) { return JVMFlagEx::type##AtPut(FLAG_MEMBER_ENUM(name), value, origin); }
+
+#define FLAG_MEMBER_SET_PRODUCT(type, name, value, doc) FLAG_MEMBER_SET_(type, name)
+#define FLAG_MEMBER_SET_PD_PRODUCT(type, name, doc) FLAG_MEMBER_SET_(type, name)
+#define FLAG_MEMBER_SET_DIAGNOSTIC(type, name, value, doc) FLAG_MEMBER_SET_(type, name)
+#define FLAG_MEMBER_SET_PD_DIAGNOSTIC(type, name, doc) FLAG_MEMBER_SET_(type, name)
+#define FLAG_MEMBER_SET_EXPERIMENTAL(type, name, value, doc) FLAG_MEMBER_SET_(type, name)
+#define FLAG_MEMBER_SET_MANAGEABLE(type, name, value, doc) FLAG_MEMBER_SET_(type, name)
+#define FLAG_MEMBER_SET_PRODUCT_RW(type, name, value, doc) FLAG_MEMBER_SET_(type, name)
+#define FLAG_MEMBER_SET_DEVELOP(type, name, value, doc) FLAG_MEMBER_SET_(type, name)
+#define FLAG_MEMBER_SET_PD_DEVELOP(type, name, doc) FLAG_MEMBER_SET_(type, name)
+#define FLAG_MEMBER_SET_NOTPRODUCT(type, name, value, doc) FLAG_MEMBER_SET_(type, name)
+#ifdef _LP64
+#define FLAG_MEMBER_SET_LP64_PRODUCT(type, name, value, doc) FLAG_MEMBER_SET_(type, name)
+#else
+#define FLAG_MEMBER_SET_LP64_PRODUCT(type, name, value, doc) /* flag is constant */
+#endif // _LP64
+
+ALL_FLAGS(FLAG_MEMBER_SET_DEVELOP,
+ FLAG_MEMBER_SET_PD_DEVELOP,
+ FLAG_MEMBER_SET_PRODUCT,
+ FLAG_MEMBER_SET_PD_PRODUCT,
+ FLAG_MEMBER_SET_DIAGNOSTIC,
+ FLAG_MEMBER_SET_PD_DIAGNOSTIC,
+ FLAG_MEMBER_SET_EXPERIMENTAL,
+ FLAG_MEMBER_SET_NOTPRODUCT,
+ FLAG_MEMBER_SET_MANAGEABLE,
+ FLAG_MEMBER_SET_PRODUCT_RW,
+ FLAG_MEMBER_SET_LP64_PRODUCT,
+ IGNORE_RANGE,
+ IGNORE_CONSTRAINT,
+ IGNORE_WRITEABLE)
+
+#define FLAG_IS_DEFAULT(name) (JVMFlagEx::is_default(FLAG_MEMBER_ENUM(name)))
+#define FLAG_IS_ERGO(name) (JVMFlagEx::is_ergo(FLAG_MEMBER_ENUM(name)))
+#define FLAG_IS_CMDLINE(name) (JVMFlagEx::is_cmdline(FLAG_MEMBER_ENUM(name)))
+
+#define FLAG_SET_DEFAULT(name, value) ((name) = (value))
+
+#define FLAG_SET_CMDLINE(name, value) (JVMFlagEx::setOnCmdLine(FLAG_MEMBER_ENUM(name)), \
+ FLAG_MEMBER_SET(name)((value), JVMFlag::COMMAND_LINE))
+#define FLAG_SET_ERGO(name, value) (FLAG_MEMBER_SET(name)((value), JVMFlag::ERGONOMIC))
+#define FLAG_SET_MGMT(name, value) (FLAG_MEMBER_SET(name)((value), JVMFlag::MANAGEMENT))
+
+#define FLAG_SET_ERGO_IF_DEFAULT(name, value) \
+ do { \
+ if (FLAG_IS_DEFAULT(name)) { \
+ FLAG_SET_ERGO(name, value); \
+ } \
+ } while (0)
+
#endif // SHARE_RUNTIME_GLOBALS_EXTENSION_HPP
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/hotspot/share/runtime/globals_shared.hpp Thu May 23 11:07:37 2019 +0100
@@ -0,0 +1,223 @@
+/*
+ * 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
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#ifndef SHARE_RUNTIME_GLOBALS_SHARED_HPP
+#define SHARE_RUNTIME_GLOBALS_SHARED_HPP
+
+#include "utilities/align.hpp"
+#include "utilities/globalDefinitions.hpp"
+#include "utilities/macros.hpp"
+
+#include <float.h> // for DBL_MAX
+
+// The larger HeapWordSize for 64bit requires larger heaps
+// for the same application running in 64bit. See bug 4967770.
+// The minimum alignment to a heap word size is done. Other
+// parts of the memory system may require additional alignment
+// and are responsible for those alignments.
+#ifdef _LP64
+#define ScaleForWordSize(x) align_down_((x) * 13 / 10, HeapWordSize)
+#else
+#define ScaleForWordSize(x) (x)
+#endif
+
+// use this for flags that are true per default in the tiered build
+// but false in non-tiered builds, and vice versa
+#ifdef TIERED
+#define trueInTiered true
+#define falseInTiered false
+#else
+#define trueInTiered false
+#define falseInTiered true
+#endif
+
+// use this for flags that are true by default in the debug version but
+// false in the optimized version, and vice versa
+#ifdef ASSERT
+#define trueInDebug true
+#define falseInDebug false
+#else
+#define trueInDebug false
+#define falseInDebug true
+#endif
+
+// use this for flags that are true per default in the product build
+// but false in development builds, and vice versa
+#ifdef PRODUCT
+#define trueInProduct true
+#define falseInProduct false
+#else
+#define trueInProduct false
+#define falseInProduct true
+#endif
+
+// Only materialize src code for range checking when required, ignore otherwise
+#define IGNORE_RANGE(a, b)
+// Only materialize src code for contraint checking when required, ignore otherwise
+#define IGNORE_CONSTRAINT(func,type)
+
+#define IGNORE_WRITEABLE(type)
+
+#define VM_FLAGS( \
+ develop, \
+ develop_pd, \
+ product, \
+ product_pd, \
+ diagnostic, \
+ diagnostic_pd, \
+ experimental, \
+ notproduct, \
+ manageable, \
+ product_rw, \
+ lp64_product, \
+ range, \
+ constraint, \
+ writeable) \
+ \
+ RUNTIME_FLAGS( \
+ develop, \
+ develop_pd, \
+ product, \
+ product_pd, \
+ diagnostic, \
+ diagnostic_pd, \
+ experimental, \
+ notproduct, \
+ manageable, \
+ product_rw, \
+ lp64_product, \
+ range, \
+ constraint, \
+ writeable) \
+ \
+ GC_FLAGS( \
+ develop, \
+ develop_pd, \
+ product, \
+ product_pd, \
+ diagnostic, \
+ diagnostic_pd, \
+ experimental, \
+ notproduct, \
+ manageable, \
+ product_rw, \
+ lp64_product, \
+ range, \
+ constraint, \
+ writeable) \
+
+
+#define ALL_FLAGS( \
+ develop, \
+ develop_pd, \
+ product, \
+ product_pd, \
+ diagnostic, \
+ diagnostic_pd, \
+ experimental, \
+ notproduct, \
+ manageable, \
+ product_rw, \
+ lp64_product, \
+ range, \
+ constraint, \
+ writeable) \
+ \
+ VM_FLAGS( \
+ develop, \
+ develop_pd, \
+ product, \
+ product_pd, \
+ diagnostic, \
+ diagnostic_pd, \
+ experimental, \
+ notproduct, \
+ manageable, \
+ product_rw, \
+ lp64_product, \
+ range, \
+ constraint, \
+ writeable) \
+ \
+ RUNTIME_OS_FLAGS( \
+ develop, \
+ develop_pd, \
+ product, \
+ product_pd, \
+ diagnostic, \
+ diagnostic_pd, \
+ notproduct, \
+ range, \
+ constraint, \
+ writeable) \
+ \
+ JVMCI_ONLY(JVMCI_FLAGS( \
+ develop, \
+ develop_pd, \
+ product, \
+ product_pd, \
+ diagnostic, \
+ diagnostic_pd, \
+ experimental, \
+ notproduct, \
+ range, \
+ constraint, \
+ writeable)) \
+ \
+ COMPILER1_PRESENT(C1_FLAGS( \
+ develop, \
+ develop_pd, \
+ product, \
+ product_pd, \
+ diagnostic, \
+ diagnostic_pd, \
+ notproduct, \
+ range, \
+ constraint, \
+ writeable)) \
+ \
+ COMPILER2_PRESENT(C2_FLAGS( \
+ develop, \
+ develop_pd, \
+ product, \
+ product_pd, \
+ diagnostic, \
+ diagnostic_pd, \
+ experimental, \
+ notproduct, \
+ range, \
+ constraint, \
+ writeable)) \
+ \
+ ARCH_FLAGS( \
+ develop, \
+ product, \
+ diagnostic, \
+ experimental, \
+ notproduct, \
+ range, \
+ constraint, \
+ writeable)
+
+#endif // SHARE_RUNTIME_GLOBALS_SHARED_HPP
--- a/src/hotspot/share/runtime/java.cpp Fri May 17 13:21:44 2019 +0100
+++ b/src/hotspot/share/runtime/java.cpp Thu May 23 11:07:37 2019 +0100
@@ -43,6 +43,7 @@
#include "logging/logStream.hpp"
#include "memory/oopFactory.hpp"
#include "memory/resourceArea.hpp"
+#include "memory/dynamicArchive.hpp"
#include "memory/universe.hpp"
#include "oops/constantPool.hpp"
#include "oops/generateOopMap.hpp"
@@ -498,6 +499,12 @@
// Note: we don't wait until it actually dies.
os::terminate_signal_thread();
+#if INCLUDE_CDS
+ if (DynamicDumpSharedSpaces) {
+ DynamicArchive::dump();
+ }
+#endif
+
print_statistics();
Universe::heap()->print_tracing_info();
--- a/src/hotspot/share/runtime/mutexLocker.cpp Fri May 17 13:21:44 2019 +0100
+++ b/src/hotspot/share/runtime/mutexLocker.cpp Thu May 23 11:07:37 2019 +0100
@@ -153,9 +153,12 @@
#if INCLUDE_NMT
Mutex* NMTQuery_lock = NULL;
#endif
-#if INCLUDE_CDS && INCLUDE_JVMTI
+#if INCLUDE_CDS
+#if INCLUDE_JVMTI
Mutex* CDSClassFileStream_lock = NULL;
#endif
+Mutex* DumpTimeTable_lock = NULL;
+#endif // INCLUDE_CDS
#if INCLUDE_JVMCI
Monitor* JVMCI_lock = NULL;
@@ -351,7 +354,8 @@
#if INCLUDE_NMT
def(NMTQuery_lock , PaddedMutex , max_nonleaf, false, Monitor::_safepoint_check_always);
#endif
-#if INCLUDE_CDS && INCLUDE_JVMTI
+#if INCLUDE_CDS
+#if INCLUDE_JVMTI
def(CDSClassFileStream_lock , PaddedMutex , max_nonleaf, false, Monitor::_safepoint_check_always);
#endif
@@ -360,6 +364,8 @@
def(JVMCIGlobalAlloc_lock , PaddedMutex , nonleaf, true, Monitor::_safepoint_check_never);
def(JVMCIGlobalActive_lock , PaddedMutex , nonleaf-1, true, Monitor::_safepoint_check_never);
#endif
+ def(DumpTimeTable_lock , PaddedMutex , leaf, true, Monitor::_safepoint_check_never);
+#endif // INCLUDE_CDS
}
GCMutexLocker::GCMutexLocker(Monitor * mutex) {
--- a/src/hotspot/share/runtime/mutexLocker.hpp Fri May 17 13:21:44 2019 +0100
+++ b/src/hotspot/share/runtime/mutexLocker.hpp Thu May 23 11:07:37 2019 +0100
@@ -132,9 +132,12 @@
#if INCLUDE_NMT
extern Mutex* NMTQuery_lock; // serialize NMT Dcmd queries
#endif
-#if INCLUDE_CDS && INCLUDE_JVMTI
+#if INCLUDE_CDS
+#if INCLUDE_JVMTI
extern Mutex* CDSClassFileStream_lock; // FileMapInfo::open_stream_for_jvmti
#endif
+extern Mutex* DumpTimeTable_lock; // SystemDictionaryShared::find_or_allocate_info_for
+#endif // INCLUDE_CDS
#if INCLUDE_JFR
extern Mutex* JfrStacktrace_lock; // used to guard access to the JFR stacktrace table
extern Monitor* JfrMsg_lock; // protects JFR messaging
--- a/src/hotspot/share/runtime/safepoint.cpp Fri May 17 13:21:44 2019 +0100
+++ b/src/hotspot/share/runtime/safepoint.cpp Thu May 23 11:07:37 2019 +0100
@@ -24,6 +24,7 @@
#include "precompiled.hpp"
#include "classfile/classLoaderDataGraph.inline.hpp"
+#include "classfile/dictionary.hpp"
#include "classfile/stringTable.hpp"
#include "classfile/symbolTable.hpp"
#include "classfile/systemDictionary.hpp"
@@ -66,9 +67,6 @@
#include "services/runtimeService.hpp"
#include "utilities/events.hpp"
#include "utilities/macros.hpp"
-#ifdef COMPILER1
-#include "c1/c1_globals.hpp"
-#endif
static void post_safepoint_begin_event(EventSafepointBegin& event,
uint64_t safepoint_id,
@@ -516,6 +514,8 @@
if (ObjectSynchronizer::is_cleanup_needed()) return true;
// Need a safepoint if some inline cache buffers is non-empty
if (!InlineCacheBuffer::is_empty()) return true;
+ if (StringTable::needs_rehashing()) return true;
+ if (SymbolTable::needs_rehashing()) return true;
return false;
}
@@ -608,23 +608,27 @@
}
if (_subtasks.try_claim_task(SafepointSynchronize::SAFEPOINT_CLEANUP_CLD_PURGE)) {
- // CMS delays purging the CLDG until the beginning of the next safepoint and to
- // make sure concurrent sweep is done
- const char* name = "purging class loader data graph";
- EventSafepointCleanupTask event;
- TraceTime timer(name, TRACETIME_LOG(Info, safepoint, cleanup));
- ClassLoaderDataGraph::purge_if_needed();
+ if (ClassLoaderDataGraph::should_purge_and_reset()) {
+ // CMS delays purging the CLDG until the beginning of the next safepoint and to
+ // make sure concurrent sweep is done
+ const char* name = "purging class loader data graph";
+ EventSafepointCleanupTask event;
+ TraceTime timer(name, TRACETIME_LOG(Info, safepoint, cleanup));
+ ClassLoaderDataGraph::purge();
- post_safepoint_cleanup_task_event(event, safepoint_id, name);
+ post_safepoint_cleanup_task_event(event, safepoint_id, name);
+ }
}
if (_subtasks.try_claim_task(SafepointSynchronize::SAFEPOINT_CLEANUP_SYSTEM_DICTIONARY_RESIZE)) {
- const char* name = "resizing system dictionaries";
- EventSafepointCleanupTask event;
- TraceTime timer(name, TRACETIME_LOG(Info, safepoint, cleanup));
- ClassLoaderDataGraph::resize_if_needed();
+ if (Dictionary::does_any_dictionary_needs_resizing()) {
+ const char* name = "resizing system dictionaries";
+ EventSafepointCleanupTask event;
+ TraceTime timer(name, TRACETIME_LOG(Info, safepoint, cleanup));
+ ClassLoaderDataGraph::resize_dictionaries();
- post_safepoint_cleanup_task_event(event, safepoint_id, name);
+ post_safepoint_cleanup_task_event(event, safepoint_id, name);
+ }
}
_subtasks.all_tasks_completed(_num_workers);
--- a/src/hotspot/share/runtime/stackValue.cpp Fri May 17 13:21:44 2019 +0100
+++ b/src/hotspot/share/runtime/stackValue.cpp Thu May 23 11:07:37 2019 +0100
@@ -32,6 +32,9 @@
#if INCLUDE_ZGC
#include "gc/z/zBarrier.inline.hpp"
#endif
+#if INCLUDE_SHENANDOAHGC
+#include "gc/shenandoah/shenandoahBarrierSet.hpp"
+#endif
StackValue* StackValue::create_stack_value(const frame* fr, const RegisterMap* reg_map, ScopeValue* sv) {
if (sv->is_location()) {
@@ -106,8 +109,15 @@
} else {
value.noop = *(narrowOop*) value_addr;
}
- // Decode narrowoop and wrap a handle around the oop
- Handle h(Thread::current(), CompressedOops::decode(value.noop));
+ // Decode narrowoop
+ oop val = CompressedOops::decode(value.noop);
+ // Deoptimization must make sure all oops have passed load barriers
+#if INCLUDE_SHENANDOAHGC
+ if (UseShenandoahGC) {
+ val = ShenandoahBarrierSet::barrier_set()->load_reference_barrier(val);
+ }
+#endif
+ Handle h(Thread::current(), val); // Wrap a handle around the oop
return new StackValue(h);
}
#endif
@@ -122,13 +132,17 @@
val = (oop)NULL;
}
#endif
+ // Deoptimization must make sure all oops have passed load barriers
#if INCLUDE_ZGC
- // Deoptimization must make sure all oop have passed load barrier
if (UseZGC) {
val = ZBarrier::load_barrier_on_oop_field_preloaded((oop*)value_addr, val);
}
#endif
-
+#if INCLUDE_SHENANDOAHGC
+ if (UseShenandoahGC) {
+ val = ShenandoahBarrierSet::barrier_set()->load_reference_barrier(val);
+ }
+#endif
Handle h(Thread::current(), val); // Wrap a handle around the oop
return new StackValue(h);
}
--- a/src/hotspot/share/runtime/stubCodeGenerator.cpp Fri May 17 13:21:44 2019 +0100
+++ b/src/hotspot/share/runtime/stubCodeGenerator.cpp Thu May 23 11:07:37 2019 +0100
@@ -60,7 +60,7 @@
st->print("%s", group());
st->print("::");
st->print("%s", name());
- st->print(" [" INTPTR_FORMAT ", " INTPTR_FORMAT "[ (%d bytes)", p2i(begin()), p2i(end()), size_in_bytes());
+ st->print(" [" INTPTR_FORMAT ", " INTPTR_FORMAT "] (%d bytes)", p2i(begin()), p2i(end()), size_in_bytes());
}
void StubCodeDesc::print() const { print_on(tty); }
@@ -98,9 +98,12 @@
// of this stub.
offset = cdesc->begin() - outer_cbuf->insts()->start();
#endif
- cdesc->print();
+ ttyLocker ttyl;
+ tty->print_cr("- - - [BEGIN] - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
+ cdesc->print_on(tty);
tty->cr();
- Disassembler::decode(cdesc->begin(), cdesc->end(), NULL, cs, offset);
+ Disassembler::decode(cdesc->begin(), cdesc->end(), tty, cs /*, offset */);
+ tty->print_cr("- - - [END] - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
tty->cr();
}
}
--- a/src/hotspot/share/runtime/thread.cpp Fri May 17 13:21:44 2019 +0100
+++ b/src/hotspot/share/runtime/thread.cpp Thu May 23 11:07:37 2019 +0100
@@ -1613,7 +1613,6 @@
set_deopt_compiled_method(NULL);
clear_must_deopt_id();
set_monitor_chunks(NULL);
- set_next(NULL);
_on_thread_list = false;
set_thread_state(_thread_new);
_terminated = _not_terminated;
@@ -3457,7 +3456,6 @@
// would like. We are actively migrating Threads_lock uses to other
// mechanisms in order to reduce Threads_lock contention.
-JavaThread* Threads::_thread_list = NULL;
int Threads::_number_of_threads = 0;
int Threads::_number_of_non_daemon_threads = 0;
int Threads::_return_code = 0;
@@ -3764,7 +3762,6 @@
}
// Initialize Threads state
- _thread_list = NULL;
_number_of_threads = 0;
_number_of_non_daemon_threads = 0;
@@ -3964,10 +3961,8 @@
SystemDictionary::compute_java_loaders(CHECK_JNI_ERR);
#if INCLUDE_CDS
- if (DumpSharedSpaces) {
- // capture the module path info from the ModuleEntryTable
- ClassLoader::initialize_module_path(THREAD);
- }
+ // capture the module path info from the ModuleEntryTable
+ ClassLoader::initialize_module_path(THREAD);
#endif
#if INCLUDE_JVMCI
@@ -4169,7 +4164,7 @@
for (agent = Arguments::agents(); agent != NULL; agent = agent->next()) {
// CDS dumping does not support native JVMTI agent.
// CDS dumping supports Java agent if the AllowArchivingWithJavaAgent diagnostic option is specified.
- if (DumpSharedSpaces) {
+ if (DumpSharedSpaces || DynamicDumpSharedSpaces) {
if(!agent->is_instrument_lib()) {
vm_exit_during_cds_dumping("CDS dumping does not support native JVMTI agent, name", agent->name());
} else if (!AllowArchivingWithJavaAgent) {
@@ -4425,9 +4420,6 @@
BarrierSet::barrier_set()->on_thread_attach(p);
- p->set_next(_thread_list);
- _thread_list = p;
-
// Once a JavaThread is added to the Threads list, smr_delete() has
// to be used to delete it. Otherwise we can just delete it directly.
p->set_on_thread_list();
@@ -4465,20 +4457,6 @@
// Maintain fast thread list
ThreadsSMRSupport::remove_thread(p);
- JavaThread* current = _thread_list;
- JavaThread* prev = NULL;
-
- while (current != p) {
- prev = current;
- current = current->next();
- }
-
- if (prev) {
- prev->set_next(current->next());
- } else {
- _thread_list = p->next();
- }
-
_number_of_threads--;
if (!is_daemon) {
_number_of_non_daemon_threads--;
--- a/src/hotspot/share/runtime/thread.hpp Fri May 17 13:21:44 2019 +0100
+++ b/src/hotspot/share/runtime/thread.hpp Thu May 23 11:07:37 2019 +0100
@@ -983,7 +983,6 @@
friend class JVMCIVMStructs;
friend class WhiteBox;
private:
- JavaThread* _next; // The next thread in the Threads list
bool _on_thread_list; // Is set when this JavaThread is added to the Threads list
oop _threadObj; // The Java level thread object
@@ -1247,10 +1246,6 @@
virtual bool is_Java_thread() const { return true; }
virtual bool can_call_java() const { return true; }
- // Thread chain operations
- JavaThread* next() const { return _next; }
- void set_next(JavaThread* p) { _next = p; }
-
// Thread oop. threadObj() can be NULL for initial JavaThread
// (or for threads attached via JNI)
oop threadObj() const { return _threadObj; }
@@ -2213,7 +2208,6 @@
class Threads: AllStatic {
friend class VMStructs;
private:
- static JavaThread* _thread_list;
static int _number_of_threads;
static int _number_of_non_daemon_threads;
static int _return_code;
--- a/src/hotspot/share/runtime/threadSMR.hpp Fri May 17 13:21:44 2019 +0100
+++ b/src/hotspot/share/runtime/threadSMR.hpp Thu May 23 11:07:37 2019 +0100
@@ -86,6 +86,7 @@
// SMR Support for the Threads class.
//
class ThreadsSMRSupport : AllStatic {
+ friend class VMStructs;
friend class SafeThreadsListPtr; // for _nested_thread_list_max, delete_notify(), release_stable_list_wake_up() access
// The coordination between ThreadsSMRSupport::release_stable_list() and
@@ -158,6 +159,7 @@
// A fast list of JavaThreads.
//
class ThreadsList : public CHeapObj<mtThread> {
+ friend class VMStructs;
friend class SafeThreadsListPtr; // for {dec,inc}_nested_handle_cnt() access
friend class ThreadsSMRSupport; // for _nested_handle_cnt, {add,remove}_thread(), {,set_}next_list() access
--- a/src/hotspot/share/runtime/tieredThresholdPolicy.cpp Fri May 17 13:21:44 2019 +0100
+++ b/src/hotspot/share/runtime/tieredThresholdPolicy.cpp Thu May 23 11:07:37 2019 +0100
@@ -238,7 +238,7 @@
// Lower the compiler count such that all buffers fit into the code cache
count = MAX2(max_count, c1_only ? 1 : 2);
}
- FLAG_SET_ERGO(intx, CICompilerCount, count);
+ FLAG_SET_ERGO(CICompilerCount, count);
}
#else
// On 32-bit systems, the number of compiler threads is limited to 3.
@@ -250,7 +250,7 @@
/// available to the VM and thus cause the VM to crash.
if (FLAG_IS_DEFAULT(CICompilerCount)) {
count = 3;
- FLAG_SET_ERGO(intx, CICompilerCount, count);
+ FLAG_SET_ERGO(CICompilerCount, count);
}
#endif
--- a/src/hotspot/share/runtime/vmStructs.cpp Fri May 17 13:21:44 2019 +0100
+++ b/src/hotspot/share/runtime/vmStructs.cpp Thu May 23 11:07:37 2019 +0100
@@ -94,6 +94,7 @@
#include "runtime/sharedRuntime.hpp"
#include "runtime/stubRoutines.hpp"
#include "runtime/thread.inline.hpp"
+#include "runtime/threadSMR.hpp"
#include "runtime/vframeArray.hpp"
#include "runtime/vmStructs.hpp"
#include "utilities/globalDefinitions.hpp"
@@ -740,10 +741,13 @@
/* Threads (NOTE: incomplete) */ \
/******************************/ \
\
- static_field(Threads, _thread_list, JavaThread*) \
- static_field(Threads, _number_of_threads, int) \
- static_field(Threads, _number_of_non_daemon_threads, int) \
- static_field(Threads, _return_code, int) \
+ static_field(Threads, _number_of_threads, int) \
+ static_field(Threads, _number_of_non_daemon_threads, int) \
+ static_field(Threads, _return_code, int) \
+ \
+ static_ptr_volatile_field(ThreadsSMRSupport, _java_thread_list, ThreadsList*) \
+ nonstatic_field(ThreadsList, _length, const uint) \
+ nonstatic_field(ThreadsList, _threads, JavaThread *const *const) \
\
nonstatic_field(ThreadShadow, _pending_exception, oop) \
nonstatic_field(ThreadShadow, _exception_file, const char*) \
@@ -757,7 +761,6 @@
nonstatic_field(Thread, _current_waiting_monitor, ObjectMonitor*) \
nonstatic_field(NamedThread, _name, char*) \
nonstatic_field(NamedThread, _processed_thread, JavaThread*) \
- nonstatic_field(JavaThread, _next, JavaThread*) \
nonstatic_field(JavaThread, _threadObj, oop) \
nonstatic_field(JavaThread, _anchor, JavaFrameAnchor) \
nonstatic_field(JavaThread, _vm_result, oop) \
@@ -1371,6 +1374,9 @@
declare_toplevel_type(OSThread) \
declare_toplevel_type(JavaFrameAnchor) \
\
+ declare_toplevel_type(ThreadsSMRSupport) \
+ declare_toplevel_type(ThreadsList) \
+ \
/***************/ \
/* Interpreter */ \
/***************/ \
@@ -1964,6 +1970,7 @@
declare_toplevel_type(intptr_t*) \
declare_unsigned_integer_type(InvocationCounter) /* FIXME: wrong type (not integer) */ \
declare_toplevel_type(JavaThread*) \
+ declare_toplevel_type(JavaThread *const *const) \
declare_toplevel_type(java_lang_Class) \
declare_integer_type(JavaThread::AsyncRequests) \
declare_integer_type(JavaThread::TerminatedTypes) \
--- a/src/hotspot/share/utilities/events.cpp Fri May 17 13:21:44 2019 +0100
+++ b/src/hotspot/share/utilities/events.cpp Thu May 23 11:07:37 2019 +0100
@@ -108,7 +108,8 @@
int index = compute_log_index();
_records[index].thread = thread;
_records[index].timestamp = timestamp;
- stringStream st = _records[index].data.stream();
+ stringStream st(_records[index].data.buffer(),
+ _records[index].data.size());
st.print("Unloading class " INTPTR_FORMAT " ", p2i(ik));
ik->name()->print_value_on(&st);
}
@@ -121,7 +122,8 @@
int index = compute_log_index();
_records[index].thread = thread;
_records[index].timestamp = timestamp;
- stringStream st = _records[index].data.stream();
+ stringStream st(_records[index].data.buffer(),
+ _records[index].data.size());
st.print("Exception <");
h_exception->print_value_on(&st);
st.print("%s%s> (" INTPTR_FORMAT ") \n"
--- a/src/hotspot/share/utilities/events.hpp Fri May 17 13:21:44 2019 +0100
+++ b/src/hotspot/share/utilities/events.hpp Thu May 23 11:07:37 2019 +0100
@@ -137,11 +137,6 @@
// A simple wrapper class for fixed size text messages.
template <size_t bufsz>
class FormatStringLogMessage : public FormatBuffer<bufsz> {
- public:
- // Wrap this buffer in a stringStream.
- stringStream stream() {
- return stringStream(this->_buf, this->size());
- }
};
typedef FormatStringLogMessage<256> StringLogMessage;
typedef FormatStringLogMessage<512> ExtendedStringLogMessage;
--- a/src/hotspot/share/utilities/exceptions.cpp Fri May 17 13:21:44 2019 +0100
+++ b/src/hotspot/share/utilities/exceptions.cpp Thu May 23 11:07:37 2019 +0100
@@ -526,17 +526,17 @@
}
// for logging exceptions
-void Exceptions::log_exception(Handle exception, stringStream tempst) {
+void Exceptions::log_exception(Handle exception, const char* message) {
ResourceMark rm;
- Symbol* message = java_lang_Throwable::detail_message(exception());
- if (message != NULL) {
+ Symbol* detail_message = java_lang_Throwable::detail_message(exception());
+ if (detail_message != NULL) {
log_info(exceptions)("Exception <%s: %s>\n thrown in %s",
exception->print_value_string(),
- message->as_C_string(),
- tempst.as_string());
+ detail_message->as_C_string(),
+ message);
} else {
log_info(exceptions)("Exception <%s>\n thrown in %s",
exception->print_value_string(),
- tempst.as_string());
+ message);
}
}
--- a/src/hotspot/share/utilities/exceptions.hpp Fri May 17 13:21:44 2019 +0100
+++ b/src/hotspot/share/utilities/exceptions.hpp Thu May 23 11:07:37 2019 +0100
@@ -186,7 +186,7 @@
static void debug_check_abort(const char *value_string, const char* message = NULL);
// for logging exceptions
- static void log_exception(Handle exception, stringStream tempst);
+ static void log_exception(Handle exception, const char* message);
};
--- a/src/hotspot/share/utilities/globalDefinitions.hpp Fri May 17 13:21:44 2019 +0100
+++ b/src/hotspot/share/utilities/globalDefinitions.hpp Thu May 23 11:07:37 2019 +0100
@@ -43,6 +43,26 @@
#define ATTRIBUTE_ALIGNED(x)
#endif
+// These are #defines to selectively turn on/off the Print(Opto)Assembly
+// capabilities. Choices should be led by a tradeoff between
+// code size and improved supportability.
+// if PRINT_ASSEMBLY then PRINT_ABSTRACT_ASSEMBLY must be true as well
+// to have a fallback in case hsdis is not available.
+#if defined(PRODUCT)
+ #define SUPPORT_ABSTRACT_ASSEMBLY
+ #define SUPPORT_ASSEMBLY
+ #undef SUPPORT_OPTO_ASSEMBLY // Can't activate. In PRODUCT, many dump methods are missing.
+ #undef SUPPORT_DATA_STRUCTS // Of limited use. In PRODUCT, many print methods are empty.
+#else
+ #define SUPPORT_ABSTRACT_ASSEMBLY
+ #define SUPPORT_ASSEMBLY
+ #define SUPPORT_OPTO_ASSEMBLY
+ #define SUPPORT_DATA_STRUCTS
+#endif
+#if defined(SUPPORT_ASSEMBLY) && !defined(SUPPORT_ABSTRACT_ASSEMBLY)
+ #define SUPPORT_ABSTRACT_ASSEMBLY
+#endif
+
// This file holds all globally used constants & types, class (forward)
// declarations and a few frequently used utility functions.
--- a/src/hotspot/share/utilities/ostream.cpp Fri May 17 13:21:44 2019 +0100
+++ b/src/hotspot/share/utilities/ostream.cpp Thu May 23 11:07:37 2019 +0100
@@ -309,10 +309,9 @@
stringStream::stringStream(size_t initial_size) : outputStream() {
buffer_length = initial_size;
- buffer = NEW_RESOURCE_ARRAY(char, buffer_length);
+ buffer = NEW_C_HEAP_ARRAY(char, buffer_length, mtInternal);
buffer_pos = 0;
buffer_fixed = false;
- DEBUG_ONLY(rm = Thread::current()->current_resource_mark();)
}
// useful for output to fixed chunks of memory, such as performance counters
@@ -337,15 +336,7 @@
if (end < buffer_length * 2) {
end = buffer_length * 2;
}
- char* oldbuf = buffer;
- assert(rm == NULL || Thread::current()->current_resource_mark() == rm,
- "StringStream is re-allocated with a different ResourceMark. Current: "
- PTR_FORMAT " original: " PTR_FORMAT,
- p2i(Thread::current()->current_resource_mark()), p2i(rm));
- buffer = NEW_RESOURCE_ARRAY(char, end);
- if (buffer_pos > 0) {
- memcpy(buffer, oldbuf, buffer_pos);
- }
+ buffer = REALLOC_C_HEAP_ARRAY(char, buffer, end, mtInternal);
buffer_length = end;
}
}
@@ -370,7 +361,11 @@
return copy;
}
-stringStream::~stringStream() {}
+stringStream::~stringStream() {
+ if (buffer_fixed == false && buffer != NULL) {
+ FREE_C_HEAP_ARRAY(char, buffer);
+ }
+}
xmlStream* xtty;
outputStream* tty;
--- a/src/hotspot/share/utilities/ostream.hpp Fri May 17 13:21:44 2019 +0100
+++ b/src/hotspot/share/utilities/ostream.hpp Thu May 23 11:07:37 2019 +0100
@@ -42,6 +42,10 @@
// This allows for redirection via -XX:+DisplayVMOutputToStdout and
// -XX:+DisplayVMOutputToStderr
class outputStream : public ResourceObj {
+ private:
+ outputStream(const outputStream&);
+ outputStream& operator=(const outputStream&);
+
protected:
int _indentation; // current indentation
int _width; // width of the page
@@ -186,19 +190,25 @@
}
};
-// for writing to strings; buffer will expand automatically
+// for writing to strings; buffer will expand automatically.
+// Buffer will always be zero-terminated.
class stringStream : public outputStream {
protected:
char* buffer;
size_t buffer_pos;
size_t buffer_length;
bool buffer_fixed;
- DEBUG_ONLY(ResourceMark* rm;)
public:
+ // Create a stringStream using an internal buffer of initially initial_bufsize size;
+ // will be enlarged on demand. There is no maximum cap.
stringStream(size_t initial_bufsize = 256);
+ // Creates a stringStream using a caller-provided buffer. Will truncate silently if
+ // it overflows.
stringStream(char* fixed_buffer, size_t fixed_buffer_size);
~stringStream();
virtual void write(const char* c, size_t len);
+ // Return number of characters written into buffer, excluding terminating zero and
+ // subject to truncation in static buffer mode.
size_t size() { return buffer_pos; }
const char* base() { return buffer; }
void reset() { buffer_pos = 0; _precount = 0; _position = 0; }
--- a/src/java.base/share/classes/java/io/BufferedInputStream.java Fri May 17 13:21:44 2019 +0100
+++ b/src/java.base/share/classes/java/io/BufferedInputStream.java Thu May 23 11:07:37 2019 +0100
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1994, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1994, 2019, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -26,6 +26,7 @@
package java.io;
import jdk.internal.misc.Unsafe;
+import jdk.internal.util.ArraysSupport;
/**
* A <code>BufferedInputStream</code> adds
@@ -54,14 +55,6 @@
private static int DEFAULT_BUFFER_SIZE = 8192;
/**
- * The maximum size of array to allocate.
- * Some VMs reserve some header words in an array.
- * Attempts to allocate larger arrays may result in
- * OutOfMemoryError: Requested array size exceeds VM limit
- */
- private static int MAX_BUFFER_SIZE = Integer.MAX_VALUE - 8;
-
- /**
* As this class is used early during bootstrap, it's motivated to use
* Unsafe.compareAndSetObject instead of AtomicReferenceFieldUpdater
* (or VarHandles) to reduce dependencies and improve startup time.
@@ -220,7 +213,7 @@
byte[] buffer = getBufIfOpen();
if (markpos < 0)
pos = 0; /* no mark: throw away the buffer */
- else if (pos >= buffer.length) /* no room left in buffer */
+ else if (pos >= buffer.length) { /* no room left in buffer */
if (markpos > 0) { /* can throw away early part of the buffer */
int sz = pos - markpos;
System.arraycopy(buffer, markpos, buffer, 0, sz);
@@ -229,11 +222,10 @@
} else if (buffer.length >= marklimit) {
markpos = -1; /* buffer got too big, invalidate mark */
pos = 0; /* drop buffer contents */
- } else if (buffer.length >= MAX_BUFFER_SIZE) {
- throw new OutOfMemoryError("Required array size too large");
} else { /* grow buffer */
- int nsz = (pos <= MAX_BUFFER_SIZE - pos) ?
- pos * 2 : MAX_BUFFER_SIZE;
+ int nsz = ArraysSupport.newLength(pos,
+ 1, /* minimum growth */
+ pos /* preferred growth */);
if (nsz > marklimit)
nsz = marklimit;
byte[] nbuf = new byte[nsz];
@@ -248,6 +240,7 @@
}
buffer = nbuf;
}
+ }
count = pos;
int n = getInIfOpen().read(buffer, pos, buffer.length - pos);
if (n > 0)
--- a/src/java.base/share/classes/java/io/ByteArrayOutputStream.java Fri May 17 13:21:44 2019 +0100
+++ b/src/java.base/share/classes/java/io/ByteArrayOutputStream.java Thu May 23 11:07:37 2019 +0100
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1994, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1994, 2019, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -29,6 +29,8 @@
import java.util.Arrays;
import java.util.Objects;
+import jdk.internal.util.ArraysSupport;
+
/**
* This class implements an output stream in which the data is
* written into a byte array. The buffer automatically grows as data
@@ -84,48 +86,20 @@
* at least the number of elements specified by the minimum
* capacity argument.
*
- * @param minCapacity the desired minimum capacity
- * @throws OutOfMemoryError if {@code minCapacity < 0}. This is
- * interpreted as a request for the unsatisfiably large capacity
+ * @param minCapacity the desired minimum capacity.
+ * @throws OutOfMemoryError if {@code minCapacity < 0} and
+ * {@code minCapacity - buf.length > 0}. This is interpreted as a
+ * request for the unsatisfiably large capacity.
* {@code (long) Integer.MAX_VALUE + (minCapacity - Integer.MAX_VALUE)}.
*/
private void ensureCapacity(int minCapacity) {
// overflow-conscious code
- if (minCapacity - buf.length > 0)
- grow(minCapacity);
- }
-
- /**
- * The maximum size of array to allocate.
- * Some VMs reserve some header words in an array.
- * Attempts to allocate larger arrays may result in
- * OutOfMemoryError: Requested array size exceeds VM limit
- */
- private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;
-
- /**
- * Increases the capacity to ensure that it can hold at least the
- * number of elements specified by the minimum capacity argument.
- *
- * @param minCapacity the desired minimum capacity
- */
- private void grow(int minCapacity) {
- // overflow-conscious code
int oldCapacity = buf.length;
- int newCapacity = oldCapacity << 1;
- if (newCapacity - minCapacity < 0)
- newCapacity = minCapacity;
- if (newCapacity - MAX_ARRAY_SIZE > 0)
- newCapacity = hugeCapacity(minCapacity);
- buf = Arrays.copyOf(buf, newCapacity);
- }
-
- private static int hugeCapacity(int minCapacity) {
- if (minCapacity < 0) // overflow
- throw new OutOfMemoryError();
- return (minCapacity > MAX_ARRAY_SIZE) ?
- Integer.MAX_VALUE :
- MAX_ARRAY_SIZE;
+ int minGrowth = minCapacity - oldCapacity;
+ if (minGrowth > 0) {
+ buf = Arrays.copyOf(buf, ArraysSupport.newLength(oldCapacity,
+ minGrowth, oldCapacity /* preferred growth */));
+ }
}
/**
--- a/src/java.base/share/classes/java/io/ObjectInputFilter.java Fri May 17 13:21:44 2019 +0100
+++ b/src/java.base/share/classes/java/io/ObjectInputFilter.java Thu May 23 11:07:37 2019 +0100
@@ -283,7 +283,7 @@
/**
* Current configured filter.
*/
- private static ObjectInputFilter serialFilter = configuredFilter;
+ private static volatile ObjectInputFilter serialFilter = configuredFilter;
/**
* Returns the system-wide serialization filter or {@code null} if not configured.
@@ -291,9 +291,7 @@
* @return the system-wide serialization filter or {@code null} if not configured
*/
public static ObjectInputFilter getSerialFilter() {
- synchronized (serialFilterLock) {
- return serialFilter;
- }
+ return serialFilter;
}
/**
--- a/src/java.base/share/classes/java/lang/Byte.java Fri May 17 13:21:44 2019 +0100
+++ b/src/java.base/share/classes/java/lang/Byte.java Thu May 23 11:07:37 2019 +0100
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1996, 2013, 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
@@ -356,7 +356,7 @@
/**
* Returns the value of this {@code Byte} as a {@code short} after
* a widening primitive conversion.
- * @jls 5.1.2 Widening Primitive Conversions
+ * @jls 5.1.2 Widening Primitive Conversion
*/
public short shortValue() {
return (short)value;
@@ -365,7 +365,7 @@
/**
* Returns the value of this {@code Byte} as an {@code int} after
* a widening primitive conversion.
- * @jls 5.1.2 Widening Primitive Conversions
+ * @jls 5.1.2 Widening Primitive Conversion
*/
public int intValue() {
return (int)value;
@@ -374,7 +374,7 @@
/**
* Returns the value of this {@code Byte} as a {@code long} after
* a widening primitive conversion.
- * @jls 5.1.2 Widening Primitive Conversions
+ * @jls 5.1.2 Widening Primitive Conversion
*/
public long longValue() {
return (long)value;
@@ -383,7 +383,7 @@
/**
* Returns the value of this {@code Byte} as a {@code float} after
* a widening primitive conversion.
- * @jls 5.1.2 Widening Primitive Conversions
+ * @jls 5.1.2 Widening Primitive Conversion
*/
public float floatValue() {
return (float)value;
@@ -392,7 +392,7 @@
/**
* Returns the value of this {@code Byte} as a {@code double}
* after a widening primitive conversion.
- * @jls 5.1.2 Widening Primitive Conversions
+ * @jls 5.1.2 Widening Primitive Conversion
*/
public double doubleValue() {
return (double)value;
--- a/src/java.base/share/classes/java/lang/Class.java Fri May 17 13:21:44 2019 +0100
+++ b/src/java.base/share/classes/java/lang/Class.java Thu May 23 11:07:37 2019 +0100
@@ -999,7 +999,7 @@
*
* @since 9
* @spec JPMS
- * @jls 6.7 Fully Qualified Names
+ * @jls 6.7 Fully Qualified Names
*/
public String getPackageName() {
String pn = this.packageName;
@@ -3910,7 +3910,8 @@
* SecurityManager#checkPackageAccess s.checkPackageAccess()}
* denies access to the package of the returned class
* @since 11
- * @jvms 4.7.28 and 4.7.29 NestHost and NestMembers attributes
+ * @jvms 4.7.28 The {@code NestHost} Attribute
+ * @jvms 4.7.29 The {@code NestMembers} Attribute
* @jvms 5.4.4 Access Control
*/
@CallerSensitive
--- a/src/java.base/share/classes/java/lang/ClassLoader.java Fri May 17 13:21:44 2019 +0100
+++ b/src/java.base/share/classes/java/lang/ClassLoader.java Thu May 23 11:07:37 2019 +0100
@@ -222,7 +222,7 @@
* or a fully qualified name as defined by
* <cite>The Java™ Language Specification</cite>.
*
- * @jls 6.7 Fully Qualified Names
+ * @jls 6.7 Fully Qualified Names
* @jls 13.1 The Form of a Binary
* @see #resolveClass(Class)
* @since 1.0
@@ -2194,7 +2194,7 @@
* @revised 9
* @spec JPMS
*
- * @jvms 5.3 Run-time package
+ * @jvms 5.3 Creation and Loading
* @see <a href="{@docRoot}/../specs/jar/jar.html#package-sealing">
* The JAR File Specification: Package Sealing</a>
*/
@@ -2228,7 +2228,7 @@
* @throws NullPointerException
* if {@code name} is {@code null}.
*
- * @jvms 5.3 Run-time package
+ * @jvms 5.3 Creation and Loading
*
* @since 9
* @spec JPMS
@@ -2255,7 +2255,7 @@
* this class loader; or an zero length array if no package has been
* defined by this class loader.
*
- * @jvms 5.3 Run-time package
+ * @jvms 5.3 Creation and Loading
*
* @since 9
* @spec JPMS
--- a/src/java.base/share/classes/java/lang/Double.java Fri May 17 13:21:44 2019 +0100
+++ b/src/java.base/share/classes/java/lang/Double.java Thu May 23 11:07:37 2019 +0100
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1994, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1994, 2019, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -673,7 +673,7 @@
*
* @return the {@code double} value represented by this object
* converted to type {@code byte}
- * @jls 5.1.3 Narrowing Primitive Conversions
+ * @jls 5.1.3 Narrowing Primitive Conversion
* @since 1.1
*/
public byte byteValue() {
@@ -686,7 +686,7 @@
*
* @return the {@code double} value represented by this object
* converted to type {@code short}
- * @jls 5.1.3 Narrowing Primitive Conversions
+ * @jls 5.1.3 Narrowing Primitive Conversion
* @since 1.1
*/
public short shortValue() {
@@ -696,7 +696,7 @@
/**
* Returns the value of this {@code Double} as an {@code int}
* after a narrowing primitive conversion.
- * @jls 5.1.3 Narrowing Primitive Conversions
+ * @jls 5.1.3 Narrowing Primitive Conversion
*
* @return the {@code double} value represented by this object
* converted to type {@code int}
@@ -711,7 +711,7 @@
*
* @return the {@code double} value represented by this object
* converted to type {@code long}
- * @jls 5.1.3 Narrowing Primitive Conversions
+ * @jls 5.1.3 Narrowing Primitive Conversion
*/
public long longValue() {
return (long)value;
@@ -723,7 +723,7 @@
*
* @return the {@code double} value represented by this object
* converted to type {@code float}
- * @jls 5.1.3 Narrowing Primitive Conversions
+ * @jls 5.1.3 Narrowing Primitive Conversion
* @since 1.0
*/
public float floatValue() {
--- a/src/java.base/share/classes/java/lang/Float.java Fri May 17 13:21:44 2019 +0100
+++ b/src/java.base/share/classes/java/lang/Float.java Thu May 23 11:07:37 2019 +0100
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1994, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1994, 2019, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -602,7 +602,7 @@
*
* @return the {@code float} value represented by this object
* converted to type {@code byte}
- * @jls 5.1.3 Narrowing Primitive Conversions
+ * @jls 5.1.3 Narrowing Primitive Conversion
*/
public byte byteValue() {
return (byte)value;
@@ -614,7 +614,7 @@
*
* @return the {@code float} value represented by this object
* converted to type {@code short}
- * @jls 5.1.3 Narrowing Primitive Conversions
+ * @jls 5.1.3 Narrowing Primitive Conversion
* @since 1.1
*/
public short shortValue() {
@@ -627,7 +627,7 @@
*
* @return the {@code float} value represented by this object
* converted to type {@code int}
- * @jls 5.1.3 Narrowing Primitive Conversions
+ * @jls 5.1.3 Narrowing Primitive Conversion
*/
public int intValue() {
return (int)value;
@@ -639,7 +639,7 @@
*
* @return the {@code float} value represented by this object
* converted to type {@code long}
- * @jls 5.1.3 Narrowing Primitive Conversions
+ * @jls 5.1.3 Narrowing Primitive Conversion
*/
public long longValue() {
return (long)value;
@@ -661,7 +661,7 @@
*
* @return the {@code float} value represented by this
* object converted to type {@code double}
- * @jls 5.1.2 Widening Primitive Conversions
+ * @jls 5.1.2 Widening Primitive Conversion
*/
public double doubleValue() {
return (double)value;
--- a/src/java.base/share/classes/java/lang/FunctionalInterface.java Fri May 17 13:21:44 2019 +0100
+++ b/src/java.base/share/classes/java/lang/FunctionalInterface.java Thu May 23 11:07:37 2019 +0100
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 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
@@ -57,7 +57,7 @@
* regardless of whether or not a {@code FunctionalInterface}
* annotation is present on the interface declaration.
*
- * @jls 4.3.2. The Class Object
+ * @jls 4.3.2 The Class Object
* @jls 9.8 Functional Interfaces
* @jls 9.4.3 Interface Method Body
* @jls 9.6.4.9 @FunctionalInterface
--- a/src/java.base/share/classes/java/lang/Integer.java Fri May 17 13:21:44 2019 +0100
+++ b/src/java.base/share/classes/java/lang/Integer.java Thu May 23 11:07:37 2019 +0100
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1994, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1994, 2019, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -1120,7 +1120,7 @@
/**
* Returns the value of this {@code Integer} as a {@code byte}
* after a narrowing primitive conversion.
- * @jls 5.1.3 Narrowing Primitive Conversions
+ * @jls 5.1.3 Narrowing Primitive Conversion
*/
public byte byteValue() {
return (byte)value;
@@ -1129,7 +1129,7 @@
/**
* Returns the value of this {@code Integer} as a {@code short}
* after a narrowing primitive conversion.
- * @jls 5.1.3 Narrowing Primitive Conversions
+ * @jls 5.1.3 Narrowing Primitive Conversion
*/
public short shortValue() {
return (short)value;
@@ -1147,7 +1147,7 @@
/**
* Returns the value of this {@code Integer} as a {@code long}
* after a widening primitive conversion.
- * @jls 5.1.2 Widening Primitive Conversions
+ * @jls 5.1.2 Widening Primitive Conversion
* @see Integer#toUnsignedLong(int)
*/
public long longValue() {
@@ -1157,7 +1157,7 @@
/**
* Returns the value of this {@code Integer} as a {@code float}
* after a widening primitive conversion.
- * @jls 5.1.2 Widening Primitive Conversions
+ * @jls 5.1.2 Widening Primitive Conversion
*/
public float floatValue() {
return (float)value;
@@ -1166,7 +1166,7 @@
/**
* Returns the value of this {@code Integer} as a {@code double}
* after a widening primitive conversion.
- * @jls 5.1.2 Widening Primitive Conversions
+ * @jls 5.1.2 Widening Primitive Conversion
*/
public double doubleValue() {
return (double)value;
--- a/src/java.base/share/classes/java/lang/Long.java Fri May 17 13:21:44 2019 +0100
+++ b/src/java.base/share/classes/java/lang/Long.java Thu May 23 11:07:37 2019 +0100
@@ -1339,7 +1339,7 @@
/**
* Returns the value of this {@code Long} as a {@code byte} after
* a narrowing primitive conversion.
- * @jls 5.1.3 Narrowing Primitive Conversions
+ * @jls 5.1.3 Narrowing Primitive Conversion
*/
public byte byteValue() {
return (byte)value;
@@ -1348,7 +1348,7 @@
/**
* Returns the value of this {@code Long} as a {@code short} after
* a narrowing primitive conversion.
- * @jls 5.1.3 Narrowing Primitive Conversions
+ * @jls 5.1.3 Narrowing Primitive Conversion
*/
public short shortValue() {
return (short)value;
@@ -1357,7 +1357,7 @@
/**
* Returns the value of this {@code Long} as an {@code int} after
* a narrowing primitive conversion.
- * @jls 5.1.3 Narrowing Primitive Conversions
+ * @jls 5.1.3 Narrowing Primitive Conversion
*/
public int intValue() {
return (int)value;
@@ -1375,7 +1375,7 @@
/**
* Returns the value of this {@code Long} as a {@code float} after
* a widening primitive conversion.
- * @jls 5.1.2 Widening Primitive Conversions
+ * @jls 5.1.2 Widening Primitive Conversion
*/
public float floatValue() {
return (float)value;
@@ -1384,7 +1384,7 @@
/**
* Returns the value of this {@code Long} as a {@code double}
* after a widening primitive conversion.
- * @jls 5.1.2 Widening Primitive Conversions
+ * @jls 5.1.2 Widening Primitive Conversion
*/
public double doubleValue() {
return (double)value;
--- a/src/java.base/share/classes/java/lang/Number.java Fri May 17 13:21:44 2019 +0100
+++ b/src/java.base/share/classes/java/lang/Number.java Thu May 23 11:07:37 2019 +0100
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1994, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1994, 2019, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -48,12 +48,17 @@
*
* @author Lee Boynton
* @author Arthur van Hoff
- * @jls 5.1.2 Widening Primitive Conversions
- * @jls 5.1.3 Narrowing Primitive Conversions
+ * @jls 5.1.2 Widening Primitive Conversion
+ * @jls 5.1.3 Narrowing Primitive Conversion
* @since 1.0
*/
public abstract class Number implements java.io.Serializable {
/**
+ * Constructor for subclasses to call.
+ */
+ public Number() {super();}
+
+ /**
* Returns the value of the specified number as an {@code int}.
*
* @return the numeric value represented by this object after conversion
--- a/src/java.base/share/classes/java/lang/Package.java Fri May 17 13:21:44 2019 +0100
+++ b/src/java.base/share/classes/java/lang/Package.java Thu May 23 11:07:37 2019 +0100
@@ -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
@@ -108,7 +108,7 @@
* <em>named modules</em>. Instead those packages are automatically defined
* and have no specification and implementation versioning information.
*
- * @jvms 5.3 Run-time package
+ * @jvms 5.3 Creation and Loading
* @see <a href="{@docRoot}/../specs/jar/jar.html#package-sealing">
* The JAR File Specification: Package Sealing</a>
* @see ClassLoader#definePackage(String, String, String, String, String, String, String, URL)
--- a/src/java.base/share/classes/java/lang/Short.java Fri May 17 13:21:44 2019 +0100
+++ b/src/java.base/share/classes/java/lang/Short.java Thu May 23 11:07:37 2019 +0100
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1996, 2013, 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
@@ -352,7 +352,7 @@
/**
* Returns the value of this {@code Short} as a {@code byte} after
* a narrowing primitive conversion.
- * @jls 5.1.3 Narrowing Primitive Conversions
+ * @jls 5.1.3 Narrowing Primitive Conversion
*/
public byte byteValue() {
return (byte)value;
@@ -370,7 +370,7 @@
/**
* Returns the value of this {@code Short} as an {@code int} after
* a widening primitive conversion.
- * @jls 5.1.2 Widening Primitive Conversions
+ * @jls 5.1.2 Widening Primitive Conversion
*/
public int intValue() {
return (int)value;
@@ -379,7 +379,7 @@
/**
* Returns the value of this {@code Short} as a {@code long} after
* a widening primitive conversion.
- * @jls 5.1.2 Widening Primitive Conversions
+ * @jls 5.1.2 Widening Primitive Conversion
*/
public long longValue() {
return (long)value;
@@ -388,7 +388,7 @@
/**
* Returns the value of this {@code Short} as a {@code float}
* after a widening primitive conversion.
- * @jls 5.1.2 Widening Primitive Conversions
+ * @jls 5.1.2 Widening Primitive Conversion
*/
public float floatValue() {
return (float)value;
@@ -397,7 +397,7 @@
/**
* Returns the value of this {@code Short} as a {@code double}
* after a widening primitive conversion.
- * @jls 5.1.2 Widening Primitive Conversions
+ * @jls 5.1.2 Widening Primitive Conversion
*/
public double doubleValue() {
return (double)value;
--- a/src/java.base/share/classes/java/lang/StringLatin1.java Fri May 17 13:21:44 2019 +0100
+++ b/src/java.base/share/classes/java/lang/StringLatin1.java Thu May 23 11:07:37 2019 +0100
@@ -35,6 +35,7 @@
import java.util.stream.Stream;
import java.util.stream.StreamSupport;
import jdk.internal.HotSpotIntrinsicCandidate;
+import jdk.internal.util.ArraysSupport;
import static java.lang.String.LATIN1;
import static java.lang.String.UTF16;
@@ -42,14 +43,6 @@
final class StringLatin1 {
- /**
- * The maximum size of array to allocate (unless necessary).
- * Some VMs reserve some header words in an array.
- * Attempts to allocate larger arrays may result in
- * OutOfMemoryError: Requested array size exceeds VM limit
- */
- private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;
-
public static char charAt(byte[] value, int index) {
if (index < 0 || index >= value.length) {
throw new StringIndexOutOfBoundsException(index);
@@ -353,15 +346,7 @@
i += targLen;
while ((j = indexOf(value, valLen, targ, targLen, i)) > 0) {
if (++p == pos.length) {
- int cap = p + (p >> 1);
- // overflow-conscious code
- if (cap - MAX_ARRAY_SIZE > 0) {
- if (p == MAX_ARRAY_SIZE) {
- throw new OutOfMemoryError();
- }
- cap = MAX_ARRAY_SIZE;
- }
- pos = Arrays.copyOf(pos, cap);
+ pos = Arrays.copyOf(pos, ArraysSupport.newLength(p, 1, p >> 1));
}
pos[p] = j;
i = j + targLen;
--- a/src/java.base/share/classes/java/lang/StringUTF16.java Fri May 17 13:21:44 2019 +0100
+++ b/src/java.base/share/classes/java/lang/StringUTF16.java Thu May 23 11:07:37 2019 +0100
@@ -33,6 +33,7 @@
import java.util.stream.Stream;
import java.util.stream.StreamSupport;
import jdk.internal.HotSpotIntrinsicCandidate;
+import jdk.internal.util.ArraysSupport;
import jdk.internal.vm.annotation.ForceInline;
import jdk.internal.vm.annotation.DontInline;
@@ -649,15 +650,7 @@
: indexOf(value, valLen, targ, targLen, i))) > 0)
{
if (++p == pos.length) {
- int cap = p + (p >> 1);
- // overflow-conscious code
- if (cap - MAX_ARRAY_SIZE > 0) {
- if (p == MAX_ARRAY_SIZE) {
- throw new OutOfMemoryError();
- }
- cap = MAX_ARRAY_SIZE;
- }
- pos = Arrays.copyOf(pos, cap);
+ pos = Arrays.copyOf(pos, ArraysSupport.newLength(p, 1, p >> 1));
}
pos[p] = j;
i = j + targLen;
@@ -1554,15 +1547,6 @@
static final int MAX_LENGTH = Integer.MAX_VALUE >> 1;
-
- /**
- * The maximum size of array to allocate (unless necessary).
- * Some VMs reserve some header words in an array.
- * Attempts to allocate larger arrays may result in
- * OutOfMemoryError: Requested array size exceeds VM limit
- */
- private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;
-
// Used by trusted callers. Assumes all necessary bounds checks have
// been done by the caller.
--- a/src/java.base/share/classes/java/lang/SuppressWarnings.java Fri May 17 13:21:44 2019 +0100
+++ b/src/java.base/share/classes/java/lang/SuppressWarnings.java Thu May 23 11:07:37 2019 +0100
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2004, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2004, 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
@@ -49,7 +49,7 @@
* @jls 4.8 Raw Types
* @jls 4.12.2 Variables of Reference Type
* @jls 5.1.9 Unchecked Conversion
- * @jls 5.5.2 Checked Casts and Unchecked Casts
+ * @jls 5.5 Casting Contexts
* @jls 9.6.4.5 @SuppressWarnings
*/
@Target({TYPE, FIELD, METHOD, PARAMETER, CONSTRUCTOR, LOCAL_VARIABLE, MODULE})
--- a/src/java.base/share/classes/java/lang/constant/Constable.java Fri May 17 13:21:44 2019 +0100
+++ b/src/java.base/share/classes/java/lang/constant/Constable.java Thu May 23 11:07:37 2019 +0100
@@ -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
@@ -59,7 +59,7 @@
* method handles, but not necessarily those produced by method handle
* combinators.)
* @jvms 4.4 The Constant Pool
- * @jvms 4.4.10 The CONSTANT_InvokeDynamic_info Structure
+ * @jvms 4.4.10 The {@code CONSTANT_Dynamic_info} and {@code CONSTANT_InvokeDynamic_info} Structures
*
* @since 12
*/
--- a/src/java.base/share/classes/java/lang/constant/ConstantDesc.java Fri May 17 13:21:44 2019 +0100
+++ b/src/java.base/share/classes/java/lang/constant/ConstantDesc.java Thu May 23 11:07:37 2019 +0100
@@ -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
@@ -97,6 +97,11 @@
* @throws ReflectiveOperationException if a class, method, or field
* could not be reflectively resolved in the course of resolution
* @throws LinkageError if a linkage error occurs
+ *
+ * @apiNote {@linkplain MethodTypeDesc} can represent method type descriptors
+ * that are not representable by {@linkplain MethodType}, such as methods with
+ * more than 255 parameter slots, so attempts to resolve these may result in errors.
+ *
* @jvms 5.4.3 Resolution
* @jvms 5.4.4 Access Control
*/
--- a/src/java.base/share/classes/java/lang/constant/MethodHandleDesc.java Fri May 17 13:21:44 2019 +0100
+++ b/src/java.base/share/classes/java/lang/constant/MethodHandleDesc.java Thu May 23 11:07:37 2019 +0100
@@ -70,6 +70,8 @@
* for a field or constructor
* @return the {@linkplain MethodHandleDesc}
* @throws NullPointerException if any of the non-ignored arguments are null
+ * @throws IllegalArgumentException if the descriptor string is not a valid
+ * method or field descriptor
* @jvms 4.4.8 The CONSTANT_MethodHandle_info Structure
* @jvms 4.2.2 Unqualified Names
* @jvms 4.3.2 Field Descriptors
--- a/src/java.base/share/classes/java/lang/constant/MethodTypeDesc.java Fri May 17 13:21:44 2019 +0100
+++ b/src/java.base/share/classes/java/lang/constant/MethodTypeDesc.java Thu May 23 11:07:37 2019 +0100
@@ -65,7 +65,9 @@
* @param returnDesc a {@linkplain ClassDesc} describing the return type
* @param paramDescs {@linkplain ClassDesc}s describing the argument types
* @return a {@linkplain MethodTypeDesc} describing the desired method type
- * @throws NullPointerException if any argument is {@code null}
+ * @throws NullPointerException if any argument or its contents are {@code null}
+ * @throws IllegalArgumentException if any element of {@code paramDescs} is a
+ * {@link ClassDesc} for {@code void}
*/
static MethodTypeDesc of(ClassDesc returnDesc, ClassDesc... paramDescs) {
return new MethodTypeDescImpl(returnDesc, paramDescs);
@@ -141,8 +143,8 @@
* @param end the index after the last parameter to remove
* @return a {@linkplain MethodTypeDesc} describing the desired method type
* @throws IndexOutOfBoundsException if {@code start} is outside the half-open
- * range {[0, parameterCount)}, or {@code end} is outside the closed range
- * {@code [0, parameterCount]}
+ * range {@code [0, parameterCount)}, or {@code end} is outside the closed range
+ * {@code [0, parameterCount]}, or if {@code start > end}
*/
MethodTypeDesc dropParameterTypes(int start, int end);
@@ -154,9 +156,11 @@
* @param paramTypes {@link ClassDesc}s describing the new parameter types
* to insert
* @return a {@linkplain MethodTypeDesc} describing the desired method type
- * @throws NullPointerException if any argument is {@code null}
+ * @throws NullPointerException if any argument or its contents are {@code null}
* @throws IndexOutOfBoundsException if {@code pos} is outside the closed
* range {[0, parameterCount]}
+ * @throws IllegalArgumentException if any element of {@code paramTypes}
+ * is a {@link ClassDesc} for {@code void}
*/
MethodTypeDesc insertParameterTypes(int pos, ClassDesc... paramTypes);
--- a/src/java.base/share/classes/java/lang/constant/MethodTypeDescImpl.java Fri May 17 13:21:44 2019 +0100
+++ b/src/java.base/share/classes/java/lang/constant/MethodTypeDescImpl.java Thu May 23 11:07:37 2019 +0100
@@ -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
@@ -111,10 +111,8 @@
@Override
public MethodTypeDesc dropParameterTypes(int start, int end) {
- if (start < 0 || start >= argTypes.length || end < 0 || end > argTypes.length)
+ if (start < 0 || start >= argTypes.length || end < 0 || end > argTypes.length || start > end)
throw new IndexOutOfBoundsException();
- else if (start > end)
- throw new IllegalArgumentException(String.format("Range (%d, %d) not valid for size %d", start, end, argTypes.length));
ClassDesc[] newArgs = new ClassDesc[argTypes.length - (end - start)];
System.arraycopy(argTypes, 0, newArgs, 0, start);
System.arraycopy(argTypes, end, newArgs, start, argTypes.length - end);
--- a/src/java.base/share/classes/java/lang/reflect/Method.java Fri May 17 13:21:44 2019 +0100
+++ b/src/java.base/share/classes/java/lang/reflect/Method.java Thu May 23 11:07:37 2019 +0100
@@ -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
@@ -403,7 +403,7 @@
* @return a string describing this {@code Method}
*
* @jls 8.4.3 Method Modifiers
- * @jls 9.4 Method Declarations
+ * @jls 9.4 Method Declarations
* @jls 9.6.1 Annotation Type Elements
*/
public String toString() {
@@ -474,7 +474,7 @@
* @since 1.5
*
* @jls 8.4.3 Method Modifiers
- * @jls 9.4 Method Declarations
+ * @jls 9.4 Method Declarations
* @jls 9.6.1 Annotation Type Elements
*/
@Override
--- a/src/java.base/share/classes/java/lang/reflect/Modifier.java Fri May 17 13:21:44 2019 +0100
+++ b/src/java.base/share/classes/java/lang/reflect/Modifier.java Thu May 23 11:07:37 2019 +0100
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1996, 2013, 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
@@ -394,7 +394,7 @@
/**
* The Java source modifiers that can be applied to a field.
- * @jls 8.3.1 Field Modifiers
+ * @jls 8.3.1 Field Modifiers
*/
private static final int FIELD_MODIFIERS =
Modifier.PUBLIC | Modifier.PROTECTED | Modifier.PRIVATE |
--- a/src/java.base/share/classes/java/net/Inet6AddressImpl.java Fri May 17 13:21:44 2019 +0100
+++ b/src/java.base/share/classes/java/net/Inet6AddressImpl.java Thu May 23 11:07:37 2019 +0100
@@ -32,9 +32,13 @@
* Package private implementation of InetAddressImpl for dual
* IPv4/IPv6 stack.
* <p>
- * If InetAddress.preferIPv6Address is true then anyLocalAddress(),
- * loopbackAddress(), and localHost() will return IPv6 addresses,
- * otherwise IPv4 addresses.
+ * If InetAddress.preferIPv6Address is true then anyLocalAddress()
+ * and localHost() will return IPv6 addresses, otherwise IPv4 addresses.
+ *
+ * loopbackAddress() will return the first valid loopback address in
+ * [IPv6 loopback, IPv4 loopback] if InetAddress.preferIPv6Address is true,
+ * else [IPv4 loopback, IPv6 loopback].
+ * If neither are valid it will fallback to the first address tried.
*
* @since 1.4
*/
@@ -103,15 +107,31 @@
public synchronized InetAddress loopbackAddress() {
if (loopbackAddress == null) {
- if (InetAddress.preferIPv6Address == PREFER_IPV6_VALUE ||
- InetAddress.preferIPv6Address == PREFER_SYSTEM_VALUE) {
- byte[] loopback =
- {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01};
- loopbackAddress = new Inet6Address("localhost", loopback);
- } else {
- loopbackAddress = (new Inet4AddressImpl()).loopbackAddress();
- }
+ boolean preferIPv6Address =
+ InetAddress.preferIPv6Address == PREFER_IPV6_VALUE ||
+ InetAddress.preferIPv6Address == PREFER_SYSTEM_VALUE;
+ InetAddress loopback4 = (new Inet4AddressImpl()).loopbackAddress();
+ InetAddress loopback6 = new Inet6Address("localhost",
+ new byte[] {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01});
+ // Order the candidate addresses by preference.
+ InetAddress[] addresses = preferIPv6Address
+ ? new InetAddress[] {loopback6, loopback4}
+ : new InetAddress[] {loopback4, loopback6};
+ // In case of failure, default to the preferred address.
+ loopbackAddress = addresses[0];
+ // Pick the first candidate address that actually exists.
+ for (InetAddress address : addresses) {
+ try {
+ if (NetworkInterface.getByInetAddress(address) == null) {
+ continue;
+ }
+ } catch (SocketException e) {
+ continue;
+ }
+ loopbackAddress = address;
+ break;
+ }
}
return loopbackAddress;
}
--- a/src/java.base/share/classes/java/nio/file/Files.java Fri May 17 13:21:44 2019 +0100
+++ b/src/java.base/share/classes/java/nio/file/Files.java Thu May 23 11:07:37 2019 +0100
@@ -77,6 +77,7 @@
import java.util.stream.Stream;
import java.util.stream.StreamSupport;
+import jdk.internal.util.ArraysSupport;
import sun.nio.ch.FileChannelImpl;
import sun.nio.fs.AbstractFileSystemProvider;
@@ -3196,14 +3197,6 @@
}
}
- /**
- * The maximum size of array to allocate.
- * Some VMs reserve some header words in an array.
- * Attempts to allocate larger arrays may result in
- * OutOfMemoryError: Requested array size exceeds VM limit
- */
- private static final int MAX_BUFFER_SIZE = Integer.MAX_VALUE - 8;
-
private static final jdk.internal.access.JavaLangAccess JLA =
jdk.internal.access.SharedSecrets.getJavaLangAccess();
@@ -3240,13 +3233,10 @@
break;
// one more byte was read; need to allocate a larger buffer
- if (capacity <= MAX_BUFFER_SIZE - capacity) {
- capacity = Math.max(capacity << 1, BUFFER_SIZE);
- } else {
- if (capacity == MAX_BUFFER_SIZE)
- throw new OutOfMemoryError("Required array size too large");
- capacity = MAX_BUFFER_SIZE;
- }
+ capacity = Math.max(ArraysSupport.newLength(capacity,
+ 1, /* minimum growth */
+ capacity /* preferred growth */),
+ BUFFER_SIZE);
buf = Arrays.copyOf(buf, capacity);
buf[nread++] = (byte)n;
}
@@ -3283,7 +3273,7 @@
if (sbc instanceof FileChannelImpl)
((FileChannelImpl) sbc).setUninterruptible();
long size = sbc.size();
- if (size > (long) MAX_BUFFER_SIZE)
+ if (size > (long) Integer.MAX_VALUE)
throw new OutOfMemoryError("Required array size too large");
return read(in, (int)size);
}
--- a/src/java.base/share/classes/java/util/AbstractCollection.java Fri May 17 13:21:44 2019 +0100
+++ b/src/java.base/share/classes/java/util/AbstractCollection.java Thu May 23 11:07:37 2019 +0100
@@ -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
@@ -25,6 +25,8 @@
package java.util;
+import jdk.internal.util.ArraysSupport;
+
/**
* This class provides a skeletal implementation of the {@code Collection}
* interface, to minimize the effort required to implement this interface. <p>
@@ -204,14 +206,6 @@
}
/**
- * The maximum size of array to allocate.
- * Some VMs reserve some header words in an array.
- * Attempts to allocate larger arrays may result in
- * OutOfMemoryError: Requested array size exceeds VM limit
- */
- private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;
-
- /**
* Reallocates the array being used within toArray when the iterator
* returned more elements than expected, and finishes filling it from
* the iterator.
@@ -223,29 +217,19 @@
*/
@SuppressWarnings("unchecked")
private static <T> T[] finishToArray(T[] r, Iterator<?> it) {
- int i = r.length;
+ int len = r.length;
+ int i = len;
while (it.hasNext()) {
- int cap = r.length;
- if (i == cap) {
- int newCap = cap + (cap >> 1) + 1;
- // overflow-conscious code
- if (newCap - MAX_ARRAY_SIZE > 0)
- newCap = hugeCapacity(cap + 1);
- r = Arrays.copyOf(r, newCap);
+ if (i == len) {
+ len = ArraysSupport.newLength(len,
+ 1, /* minimum growth */
+ (len >> 1) + 1 /* preferred growth */);
+ r = Arrays.copyOf(r, len);
}
r[i++] = (T)it.next();
}
// trim if overallocated
- return (i == r.length) ? r : Arrays.copyOf(r, i);
- }
-
- private static int hugeCapacity(int minCapacity) {
- if (minCapacity < 0) // overflow
- throw new OutOfMemoryError
- ("Required array size too large");
- return (minCapacity > MAX_ARRAY_SIZE) ?
- Integer.MAX_VALUE :
- MAX_ARRAY_SIZE;
+ return (i == len) ? r : Arrays.copyOf(r, i);
}
// Modification Operations
--- a/src/java.base/share/classes/java/util/ArrayList.java Fri May 17 13:21:44 2019 +0100
+++ b/src/java.base/share/classes/java/util/ArrayList.java Thu May 23 11:07:37 2019 +0100
@@ -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
@@ -29,6 +29,7 @@
import java.util.function.Predicate;
import java.util.function.UnaryOperator;
import jdk.internal.access.SharedSecrets;
+import jdk.internal.util.ArraysSupport;
/**
* Resizable-array implementation of the {@code List} interface. Implements
@@ -219,14 +220,6 @@
}
/**
- * The maximum size of array to allocate (unless necessary).
- * Some VMs reserve some header words in an array.
- * Attempts to allocate larger arrays may result in
- * OutOfMemoryError: Requested array size exceeds VM limit
- */
- private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;
-
- /**
* Increases the capacity to ensure that it can hold at least the
* number of elements specified by the minimum capacity argument.
*
@@ -234,8 +227,15 @@
* @throws OutOfMemoryError if minCapacity is less than zero
*/
private Object[] grow(int minCapacity) {
- return elementData = Arrays.copyOf(elementData,
- newCapacity(minCapacity));
+ int oldCapacity = elementData.length;
+ if (oldCapacity > 0 || elementData != DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
+ int newCapacity = ArraysSupport.newLength(oldCapacity,
+ minCapacity - oldCapacity, /* minimum growth */
+ oldCapacity >> 1 /* preferred growth */);
+ return elementData = Arrays.copyOf(elementData, newCapacity);
+ } else {
+ return elementData = new Object[Math.max(DEFAULT_CAPACITY, minCapacity)];
+ }
}
private Object[] grow() {
@@ -243,39 +243,6 @@
}
/**
- * Returns a capacity at least as large as the given minimum capacity.
- * Returns the current capacity increased by 50% if that suffices.
- * Will not return a capacity greater than MAX_ARRAY_SIZE unless
- * the given minimum capacity is greater than MAX_ARRAY_SIZE.
- *
- * @param minCapacity the desired minimum capacity
- * @throws OutOfMemoryError if minCapacity is less than zero
- */
- private int newCapacity(int minCapacity) {
- // overflow-conscious code
- int oldCapacity = elementData.length;
- int newCapacity = oldCapacity + (oldCapacity >> 1);
- if (newCapacity - minCapacity <= 0) {
- if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA)
- return Math.max(DEFAULT_CAPACITY, minCapacity);
- if (minCapacity < 0) // overflow
- throw new OutOfMemoryError();
- return minCapacity;
- }
- return (newCapacity - MAX_ARRAY_SIZE <= 0)
- ? newCapacity
- : hugeCapacity(minCapacity);
- }
-
- private static int hugeCapacity(int minCapacity) {
- if (minCapacity < 0) // overflow
- throw new OutOfMemoryError();
- return (minCapacity > MAX_ARRAY_SIZE)
- ? Integer.MAX_VALUE
- : MAX_ARRAY_SIZE;
- }
-
- /**
* Returns the number of elements in this list.
*
* @return the number of elements in this list
--- a/src/java.base/share/classes/java/util/PriorityQueue.java Fri May 17 13:21:44 2019 +0100
+++ b/src/java.base/share/classes/java/util/PriorityQueue.java Thu May 23 11:07:37 2019 +0100
@@ -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
@@ -28,6 +28,7 @@
import java.util.function.Consumer;
import java.util.function.Predicate;
import jdk.internal.access.SharedSecrets;
+import jdk.internal.util.ArraysSupport;
/**
* An unbounded priority {@linkplain Queue queue} based on a priority heap.
@@ -282,14 +283,6 @@
}
/**
- * The maximum size of array to allocate.
- * Some VMs reserve some header words in an array.
- * Attempts to allocate larger arrays may result in
- * OutOfMemoryError: Requested array size exceeds VM limit
- */
- private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;
-
- /**
* Increases the capacity of the array.
*
* @param minCapacity the desired minimum capacity
@@ -297,23 +290,13 @@
private void grow(int minCapacity) {
int oldCapacity = queue.length;
// Double size if small; else grow by 50%
- int newCapacity = oldCapacity + ((oldCapacity < 64) ?
- (oldCapacity + 2) :
- (oldCapacity >> 1));
- // overflow-conscious code
- if (newCapacity - MAX_ARRAY_SIZE > 0)
- newCapacity = hugeCapacity(minCapacity);
+ int newCapacity = ArraysSupport.newLength(oldCapacity,
+ minCapacity - oldCapacity, /* minimum growth */
+ oldCapacity < 64 ? oldCapacity + 2 : oldCapacity >> 1
+ /* preferred growth */);
queue = Arrays.copyOf(queue, newCapacity);
}
- private static int hugeCapacity(int minCapacity) {
- if (minCapacity < 0) // overflow
- throw new OutOfMemoryError();
- return (minCapacity > MAX_ARRAY_SIZE) ?
- Integer.MAX_VALUE :
- MAX_ARRAY_SIZE;
- }
-
/**
* Inserts the specified element into this priority queue.
*
--- a/src/java.base/share/classes/java/util/Vector.java Fri May 17 13:21:44 2019 +0100
+++ b/src/java.base/share/classes/java/util/Vector.java Thu May 23 11:07:37 2019 +0100
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1994, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1994, 2019, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -32,6 +32,8 @@
import java.util.function.Predicate;
import java.util.function.UnaryOperator;
+import jdk.internal.util.ArraysSupport;
+
/**
* The {@code Vector} class implements a growable array of
* objects. Like an array, it contains components that can be
@@ -242,14 +244,6 @@
}
/**
- * The maximum size of array to allocate (unless necessary).
- * Some VMs reserve some header words in an array.
- * Attempts to allocate larger arrays may result in
- * OutOfMemoryError: Requested array size exceeds VM limit
- */
- private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;
-
- /**
* Increases the capacity to ensure that it can hold at least the
* number of elements specified by the minimum capacity argument.
*
@@ -257,8 +251,12 @@
* @throws OutOfMemoryError if minCapacity is less than zero
*/
private Object[] grow(int minCapacity) {
- return elementData = Arrays.copyOf(elementData,
- newCapacity(minCapacity));
+ int oldCapacity = elementData.length;
+ int newCapacity = ArraysSupport.newLength(oldCapacity,
+ minCapacity - oldCapacity, /* minimum growth */
+ capacityIncrement > 0 ? capacityIncrement : oldCapacity
+ /* preferred growth */);
+ return elementData = Arrays.copyOf(elementData, newCapacity);
}
private Object[] grow() {
@@ -266,37 +264,6 @@
}
/**
- * Returns a capacity at least as large as the given minimum capacity.
- * Will not return a capacity greater than MAX_ARRAY_SIZE unless
- * the given minimum capacity is greater than MAX_ARRAY_SIZE.
- *
- * @param minCapacity the desired minimum capacity
- * @throws OutOfMemoryError if minCapacity is less than zero
- */
- private int newCapacity(int minCapacity) {
- // overflow-conscious code
- int oldCapacity = elementData.length;
- int newCapacity = oldCapacity + ((capacityIncrement > 0) ?
- capacityIncrement : oldCapacity);
- if (newCapacity - minCapacity <= 0) {
- if (minCapacity < 0) // overflow
- throw new OutOfMemoryError();
- return minCapacity;
- }
- return (newCapacity - MAX_ARRAY_SIZE <= 0)
- ? newCapacity
- : hugeCapacity(minCapacity);
- }
-
- private static int hugeCapacity(int minCapacity) {
- if (minCapacity < 0) // overflow
- throw new OutOfMemoryError();
- return (minCapacity > MAX_ARRAY_SIZE) ?
- Integer.MAX_VALUE :
- MAX_ARRAY_SIZE;
- }
-
- /**
* Sets the size of this vector. If the new size is greater than the
* current size, new {@code null} items are added to the end of
* the vector. If the new size is less than the current size, all
--- a/src/java.base/share/classes/java/util/regex/Pattern.java Fri May 17 13:21:44 2019 +0100
+++ b/src/java.base/share/classes/java/util/regex/Pattern.java Thu May 23 11:07:37 2019 +0100
@@ -43,6 +43,7 @@
import java.util.stream.Stream;
import java.util.stream.StreamSupport;
+import jdk.internal.util.ArraysSupport;
/**
* A compiled representation of a regular expression.
@@ -2315,13 +2316,15 @@
}
}
- private void append(int ch, int len) {
- if (len >= buffer.length) {
- int[] tmp = new int[len+len];
- System.arraycopy(buffer, 0, tmp, 0, len);
- buffer = tmp;
- }
- buffer[len] = ch;
+ private void append(int ch, int index) {
+ int len = buffer.length;
+ if (index - len >= 0) {
+ len = ArraysSupport.newLength(len,
+ 1 + index - len, /* minimum growth */
+ len /* preferred growth */);
+ buffer = Arrays.copyOf(buffer, len);
+ }
+ buffer[index] = ch;
}
/**
--- a/src/java.base/share/classes/javax/crypto/JceSecurity.java.template Fri May 17 13:21:44 2019 +0100
+++ b/src/java.base/share/classes/javax/crypto/JceSecurity.java.template Thu May 23 11:07:37 2019 +0100
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997, 2016, 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
@@ -50,6 +50,7 @@
package javax.crypto;
import java.util.*;
+import java.util.concurrent.ConcurrentHashMap;
import java.io.*;
import java.net.URL;
import java.nio.file.*;
@@ -84,11 +85,11 @@
private static CryptoPermissions defaultPolicy = null;
private static CryptoPermissions exemptPolicy = null;
- // Map<Provider,?> of the providers we already have verified
- // value == PROVIDER_VERIFIED is successfully verified
- // value is failure cause Exception in error case
- private static final Map<Provider, Object> verificationResults =
- new IdentityHashMap<>();
+ // Map of the providers we already have verified.
+ // If verified ok, value == PROVIDER_VERIFIED, otherwise
+ // the cause of verification failure is stored as value.
+ private static final Map<IdentityWrapper, Object>
+ verificationResults = new ConcurrentHashMap<>();
// Map<Provider,?> of the providers currently being verified
private static final Map<Provider, Object> verifyingProviders =
@@ -199,31 +200,39 @@
* JCE trusted CA.
* Return null if ok, failure Exception if verification failed.
*/
- static synchronized Exception getVerificationResult(Provider p) {
- Object o = verificationResults.get(p);
- if (o == PROVIDER_VERIFIED) {
- return null;
- } else if (o != null) {
- return (Exception)o;
- }
- if (verifyingProviders.get(p) != null) {
- // this method is static synchronized, must be recursion
- // return failure now but do not save the result
- return new NoSuchProviderException("Recursion during verification");
+ static Exception getVerificationResult(Provider p) {
+ IdentityWrapper pKey = new IdentityWrapper(p);
+ Object o = verificationResults.get(pKey);
+ // no mapping found
+ if (o == null) {
+ synchronized (JceSecurity.class) {
+ // check cache again in case the result is now available
+ o = verificationResults.get(pKey);
+ if (o == null) {
+ if (verifyingProviders.get(p) != null) {
+ // recursion; return failure now
+ return new NoSuchProviderException
+ ("Recursion during verification");
+ }
+ try {
+ verifyingProviders.put(p, Boolean.FALSE);
+ URL providerURL = getCodeBase(p.getClass());
+ verifyProvider(providerURL, p);
+ o = PROVIDER_VERIFIED;
+ } catch (Exception e) {
+ o = e;
+ } finally {
+ verifyingProviders.remove(p);
+ }
+ verificationResults.put(pKey, o);
+ if (debug != null) {
+ debug.println("Provider " + p.getName() +
+ " verification result: " + o);
+ }
+ }
+ }
}
- try {
- verifyingProviders.put(p, Boolean.FALSE);
- URL providerURL = getCodeBase(p.getClass());
- verifyProvider(providerURL, p);
- // Verified ok, cache result
- verificationResults.put(p, PROVIDER_VERIFIED);
- return null;
- } catch (Exception e) {
- verificationResults.put(p, e);
- return e;
- } finally {
- verifyingProviders.remove(p);
- }
+ return (o == PROVIDER_VERIFIED? null : (Exception) o);
}
// return whether this provider is properly signed and can be used by JCE
@@ -391,4 +400,29 @@
static boolean isRestricted() {
return isRestricted;
}
+
+ private static final class IdentityWrapper {
+
+ final Provider obj;
+
+ IdentityWrapper(Provider obj) {
+ this.obj = obj;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (!(o instanceof IdentityWrapper)) {
+ return false;
+ }
+ return this.obj == ((IdentityWrapper)o).obj;
+ }
+
+ @Override
+ public int hashCode() {
+ return System.identityHashCode(obj);
+ }
+ }
}
--- a/src/java.base/share/classes/jdk/internal/util/ArraysSupport.java Fri May 17 13:21:44 2019 +0100
+++ b/src/java.base/share/classes/jdk/internal/util/ArraysSupport.java Thu May 23 11:07:37 2019 +0100
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015, 2017, 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
@@ -28,7 +28,9 @@
import jdk.internal.misc.Unsafe;
/**
- * Utility methods to find a mismatch between two primitive arrays.
+ * Utility methods to work with arrays. This includes a set of methods
+ * to find a mismatch between two primitive arrays. Also included is
+ * a method to calculate the new length of an array to be reallocated.
*
* <p>Array equality and lexicographical comparison can be built on top of
* array mismatch functionality.
@@ -571,4 +573,54 @@
return -1;
}
+
+ /**
+ * The maximum length of array to allocate (unless necessary).
+ * Some VMs reserve some header words in an array.
+ * Attempts to allocate larger arrays may result in
+ * {@code OutOfMemoryError: Requested array size exceeds VM limit}
+ */
+ public static final int MAX_ARRAY_LENGTH = Integer.MAX_VALUE - 8;
+
+ /**
+ * Calculates a new array length given an array's current length, a preferred
+ * growth value, and a minimum growth value. If the preferred growth value
+ * is less than the minimum growth value, the minimum growth value is used in
+ * its place. If the sum of the current length and the preferred growth
+ * value does not exceed {@link #MAX_ARRAY_LENGTH}, that sum is returned.
+ * If the sum of the current length and the minimum growth value does not
+ * exceed {@code MAX_ARRAY_LENGTH}, then {@code MAX_ARRAY_LENGTH} is returned.
+ * If the sum does not overflow an int, then {@code Integer.MAX_VALUE} is
+ * returned. Otherwise, {@code OutOfMemoryError} is thrown.
+ *
+ * @param oldLength current length of the array (must be non negative)
+ * @param minGrowth minimum required growth of the array length (must be
+ * positive)
+ * @param prefGrowth preferred growth of the array length (ignored, if less
+ * then {@code minGrowth})
+ * @return the new length of the array
+ * @throws OutOfMemoryError if increasing {@code oldLength} by
+ * {@code minGrowth} overflows.
+ */
+ public static int newLength(int oldLength, int minGrowth, int prefGrowth) {
+ // assert oldLength >= 0
+ // assert minGrowth > 0
+
+ int newLength = Math.max(minGrowth, prefGrowth) + oldLength;
+ if (newLength - MAX_ARRAY_LENGTH <= 0) {
+ return newLength;
+ }
+ return hugeLength(oldLength, minGrowth);
+ }
+
+ private static int hugeLength(int oldLength, int minGrowth) {
+ int minLength = oldLength + minGrowth;
+ if (minLength < 0) { // overflow
+ throw new OutOfMemoryError("Required array length too large");
+ }
+ if (minLength <= MAX_ARRAY_LENGTH) {
+ return MAX_ARRAY_LENGTH;
+ }
+ return Integer.MAX_VALUE;
+ }
}
--- a/src/java.base/share/classes/module-info.java Fri May 17 13:21:44 2019 +0100
+++ b/src/java.base/share/classes/module-info.java Thu May 23 11:07:37 2019 +0100
@@ -36,11 +36,11 @@
* {@link java.nio.file.FileSystems#newFileSystem
* FileSystems.newFileSystem(URI.create("jrt:/"))}.
* </dd>
- * <dt class="simpleTagLabel" style="font-family:'DejaVu Sans', Arial, Helvetica, sans serif">Tool Guides:</dt>
- * <dd style="font-family:'DejaVu Sans', Arial, Helvetica, sans serif"> {@extLink java_tool_reference java launcher},
- * {@extLink keytool_tool_reference keytool}</dd>
* </dl>
*
+ * @toolGuide java java launcher
+ * @toolGuide keytool
+ *
* @provides java.nio.file.spi.FileSystemProvider
*
* @uses java.lang.System.LoggerFinder
--- a/src/java.base/share/classes/sun/launcher/resources/launcher.properties Fri May 17 13:21:44 2019 +0100
+++ b/src/java.base/share/classes/sun/launcher/resources/launcher.properties Thu May 23 11:07:37 2019 +0100
@@ -132,10 +132,15 @@
\ -Xdebug provided for backward compatibility\n\
\ -Xdiag show additional diagnostic messages\n\
\ -Xfuture enable strictest checks, anticipating future default\n\
+\ This option is deprecated and may be removed in a\n\
+\ future release.\n\
\ -Xint interpreted mode execution only\n\
\ -Xinternalversion\n\
\ displays more detailed JVM version information than the\n\
\ -version option\n\
+\ -Xlog:<opts> Configure or enable logging with the Java Virtual\n\
+\ Machine (JVM) unified logging framework. Use -Xlog:help\n\
+\ for details.\n\
\ -Xloggc:<file> log GC status to a file with time stamps\n\
\ -Xmixed mixed mode execution (default)\n\
\ -Xmn<size> sets the initial and maximum size (in bytes) of the heap\n\
--- a/src/java.base/share/classes/sun/security/util/SecurityProperties.java Fri May 17 13:21:44 2019 +0100
+++ b/src/java.base/share/classes/sun/security/util/SecurityProperties.java Thu May 23 11:07:37 2019 +0100
@@ -43,15 +43,20 @@
* @return the value of the system or security property
*/
public static String privilegedGetOverridable(String propName) {
- return AccessController.doPrivileged((PrivilegedAction<String>)
- () -> {
- String val = System.getProperty(propName);
- if (val == null) {
- return Security.getProperty(propName);
- } else {
- return val;
- }
- });
+ if (System.getSecurityManager() == null) {
+ return getOverridableProperty(propName);
+ } else {
+ return AccessController.doPrivileged((PrivilegedAction<String>) () -> getOverridableProperty(propName));
+ }
+ }
+
+ private static String getOverridableProperty(String propName) {
+ String val = System.getProperty(propName);
+ if (val == null) {
+ return Security.getProperty(propName);
+ } else {
+ return val;
+ }
}
/**
--- a/src/java.base/share/classes/sun/util/locale/provider/CalendarNameProviderImpl.java Fri May 17 13:21:44 2019 +0100
+++ b/src/java.base/share/classes/sun/util/locale/provider/CalendarNameProviderImpl.java Thu May 23 11:07:37 2019 +0100
@@ -257,11 +257,13 @@
return langtags;
}
+ // Check if each string is unique, except null or empty strings,
+ // as these strings are used for keys in the name-to-value map.
private boolean hasDuplicates(String[] strings) {
int len = strings.length;
for (int i = 0; i < len - 1; i++) {
String a = strings[i];
- if (a != null) {
+ if (a != null && !a.isEmpty()) {
for (int j = i + 1; j < len; j++) {
if (a.equals(strings[j])) {
return true;
--- a/src/java.base/share/man/java.1 Fri May 17 13:21:44 2019 +0100
+++ b/src/java.base/share/man/java.1 Thu May 23 11:07:37 2019 +0100
@@ -716,6 +716,8 @@
\-Xfuture
.RS 4
Enables strict class\-file format checks that enforce close conformance to the class\-file format specification\&. Developers are encouraged to use this flag when developing new code because the stricter checks will become the default in future releases\&.
+.sp
+This option is deprecated and may be removed in a future release.
.RE
.PP
\-Xint
--- a/src/java.base/share/native/libjli/emessages.h Fri May 17 13:21:44 2019 +0100
+++ b/src/java.base/share/native/libjli/emessages.h Thu May 23 11:07:37 2019 +0100
@@ -38,6 +38,7 @@
#define ARG_INFO_ENVVAR "NOTE: Picked up %s: %s"
#define ARG_WARN "Warning: %s option is no longer supported."
+#define ARG_DEPRECATED "Warning: %s option is deprecated and may be removed in a future release."
#define ARG_ERROR1 "Error: %s requires class path specification"
#define ARG_ERROR2 "Error: %s requires jar file specification"
--- a/src/java.base/share/native/libjli/java.c Fri May 17 13:21:44 2019 +0100
+++ b/src/java.base/share/native/libjli/java.c Thu May 23 11:07:37 2019 +0100
@@ -1430,6 +1430,7 @@
} else if (JLI_StrCmp(arg, "-noclassgc") == 0) {
AddOption("-Xnoclassgc", NULL);
} else if (JLI_StrCmp(arg, "-Xfuture") == 0) {
+ JLI_ReportErrorMessage(ARG_DEPRECATED, "-Xfuture");
AddOption("-Xverify:all", NULL);
} else if (JLI_StrCmp(arg, "-verify") == 0) {
AddOption("-Xverify:all", NULL);
--- a/src/java.base/unix/native/libjava/canonicalize_md.c Fri May 17 13:21:44 2019 +0100
+++ b/src/java.base/unix/native/libjava/canonicalize_md.c Thu May 23 11:07:37 2019 +0100
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1994, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1994, 2019, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -211,11 +211,10 @@
char *p, *end, *r = NULL;
char path[PATH_MAX + 1];
- strncpy(path, original, sizeof(path));
- if (path[PATH_MAX] != '\0') {
- errno = ENAMETOOLONG;
- return -1;
- }
+ // strlen(original) <= PATH_MAX, see above
+ strncpy(path, original, PATH_MAX);
+ // append null for == case
+ path[PATH_MAX] = '\0';
end = path + strlen(path);
for (p = end; p > path;) {
--- a/src/java.compiler/share/classes/javax/lang/model/AnnotatedConstruct.java Fri May 17 13:21:44 2019 +0100
+++ b/src/java.compiler/share/classes/javax/lang/model/AnnotatedConstruct.java Thu May 23 11:07:37 2019 +0100
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2013, 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 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
@@ -114,7 +114,7 @@
*
* @since 1.8
* @jls 9.6 Annotation Types
- * @jls 9.6.3.3 @Inherited
+ * @jls 9.6.4.3 {@code @Inherited}
*/
public interface AnnotatedConstruct {
/**
--- a/src/java.compiler/share/classes/javax/lang/model/element/Element.java Fri May 17 13:21:44 2019 +0100
+++ b/src/java.compiler/share/classes/javax/lang/model/element/Element.java Thu May 23 11:07:37 2019 +0100
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2005, 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2005, 2019, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -196,7 +196,7 @@
* @see ModuleElement#getEnclosedElements
* @see Elements#getAllMembers
* @jls 8.8.9 Default Constructor
- * @jls 8.9 Enums
+ * @jls 8.9 Enum Types
* @revised 9
* @spec JPMS
*/
--- a/src/java.compiler/share/classes/javax/lang/model/element/NestingKind.java Fri May 17 13:21:44 2019 +0100
+++ b/src/java.compiler/share/classes/javax/lang/model/element/NestingKind.java Thu May 23 11:07:37 2019 +0100
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2005, 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2005, 2019, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -111,7 +111,7 @@
* More specifically, an <i>inner</i> type element is any nested type element that
* is not {@linkplain Modifier#STATIC static}.
* @return whether or not the constant is nested
- * @jls 14.3 Inner Classes and Enclosing Instances
+ * @jls 14.3 Local Class Declarations
*/
public boolean isNested() {
return this != TOP_LEVEL;
--- a/src/java.compiler/share/classes/javax/lang/model/util/ElementScanner6.java Fri May 17 13:21:44 2019 +0100
+++ b/src/java.compiler/share/classes/javax/lang/model/util/ElementScanner6.java Thu May 23 11:07:37 2019 +0100
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2005, 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2005, 2019, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -180,6 +180,10 @@
* {@inheritDoc}
*
* @implSpec This implementation scans the enclosed elements.
+ * Note that type parameters are <em>not</em> scanned by this
+ * implementation since type parameters are not considered to be
+ * {@linkplain TypeElement#getEnclosedElements enclosed elements
+ * of a type}.
*
* @param e {@inheritDoc}
* @param p {@inheritDoc}
@@ -211,6 +215,8 @@
* {@inheritDoc}
*
* @implSpec This implementation scans the parameters.
+ * Note that type parameters are <em>not</em> scanned by this
+ * implementation.
*
* @param e {@inheritDoc}
* @param p {@inheritDoc}
--- a/src/java.compiler/share/classes/javax/lang/model/util/Types.java Fri May 17 13:21:44 2019 +0100
+++ b/src/java.compiler/share/classes/javax/lang/model/util/Types.java Thu May 23 11:07:37 2019 +0100
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2005, 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2005, 2019, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -104,7 +104,7 @@
* @return {@code true} if and only if the first type is assignable
* to the second
* @throws IllegalArgumentException if given a type for an executable, package, or module
- * @jls 5.2 Assignment Conversion
+ * @jls 5.2 Assignment Contexts
*/
boolean isAssignable(TypeMirror t1, TypeMirror t2);
@@ -115,7 +115,7 @@
* @param t2 the second type
* @return {@code true} if and only if the first type contains the second
* @throws IllegalArgumentException if given a type for an executable, package, or module
- * @jls 4.5.1.1 Type Argument Containment and Equivalence
+ * @jls 4.5.1 Type Arguments of Parameterized Types
*/
boolean contains(TypeMirror t1, TypeMirror t2);
--- a/src/java.instrument/share/classes/java/lang/instrument/Instrumentation.java Fri May 17 13:21:44 2019 +0100
+++ b/src/java.instrument/share/classes/java/lang/instrument/Instrumentation.java Thu May 23 11:07:37 2019 +0100
@@ -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
@@ -65,6 +65,9 @@
* <p>
* Once an agent acquires an <code>Instrumentation</code> instance,
* the agent may call methods on the instance at any time.
+ * <p>
+ * @apiNote This interface is not intended to be implemented outside of
+ * the java.instrument module.
*
* @since 1.5
*/
--- a/src/java.rmi/share/classes/module-info.java Fri May 17 13:21:44 2019 +0100
+++ b/src/java.rmi/share/classes/module-info.java Thu May 23 11:07:37 2019 +0100
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2014, 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2014, 2019, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -31,12 +31,8 @@
* object registry, and the <em>{@index rmid rmid tool}</em> tool to start
* the activation system daemon.
*
- * <dl style="font-family:'DejaVu Sans', Arial, Helvetica, sans serif">
- * <dt class="simpleTagLabel">Tool Guides:</dt>
- * <dd> {@extLink rmiregistry_tool_reference rmiregistry},
- * {@extLink rmid_tool_reference rmid}
- * </dd>
- * </dl>
+ * @toolGuide rmiregistry
+ * @toolGuide rmid
*
* @uses java.rmi.server.RMIClassLoaderSpi
*
--- a/src/java.scripting/share/classes/module-info.java Fri May 17 13:21:44 2019 +0100
+++ b/src/java.scripting/share/classes/module-info.java Thu May 23 11:07:37 2019 +0100
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2014, 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2014, 2019, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -31,10 +31,7 @@
* that supports executing JavaScript and other languages if its corresponding
* script engine is installed.
*
- * <dl style="font-family:'DejaVu Sans', Arial, Helvetica, sans serif">
- * <dt class="simpleTagLabel">Tool Guides:
- * <dd> {@extLink jrunscript_tool_reference jrunscript}</dd>
- * </dl>
+ * @toolGuide jrunscript
*
* @uses javax.script.ScriptEngineFactory
*
--- a/src/java.xml/share/classes/javax/xml/parsers/DocumentBuilderFactory.java Fri May 17 13:21:44 2019 +0100
+++ b/src/java.xml/share/classes/javax/xml/parsers/DocumentBuilderFactory.java Thu May 23 11:07:37 2019 +0100
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2000, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2000, 2019, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -39,7 +39,8 @@
*/
public abstract class DocumentBuilderFactory {
-
+ private static final String DEFAULT_IMPL =
+ "com.sun.org.apache.xerces.internal.jaxp.DocumentBuilderFactoryImpl";
private boolean validating = false;
private boolean namespaceAware = false;
private boolean whitespace = false;
@@ -55,6 +56,76 @@
}
/**
+ * Creates a new NamespaceAware instance of the {@code DocumentBuilderFactory}
+ * builtin system-default implementation. Parsers produced by the factory
+ * instance provides support for XML namespaces by default.
+ *
+ * @implSpec
+ * In addition to creating a factory instance using the same process as
+ * {@link #newDefaultInstance()}, this method must set NamespaceAware to true.
+ *
+ * @return a new instance of the {@code DocumentBuilderFactory} builtin
+ * system-default implementation.
+ *
+ * @since 13
+ */
+ public static DocumentBuilderFactory newDefaultNSInstance() {
+ return makeNSAware(new DocumentBuilderFactoryImpl());
+ }
+
+ /**
+ * Creates a new NamespaceAware instance of a {@code DocumentBuilderFactory}.
+ * Parsers produced by the factory instance provides support for XML namespaces
+ * by default.
+ *
+ * @implSpec
+ * In addition to creating a factory instance using the same process as
+ * {@link #newInstance()}, this method must set NamespaceAware to true.
+ *
+ * @return a new instance of a {@code DocumentBuilderFactory}
+ *
+ * @throws FactoryConfigurationError in case of {@linkplain
+ * java.util.ServiceConfigurationError service configuration error}
+ * or if the implementation is not available or cannot be instantiated.
+ *
+ * @since 13
+ */
+ public static DocumentBuilderFactory newNSInstance() {
+ return makeNSAware(FactoryFinder.find(DocumentBuilderFactory.class, DEFAULT_IMPL));
+ }
+
+ /**
+ * Creates a new NamespaceAware instance of a {@code DocumentBuilderFactory}
+ * from the class name. Parsers produced by the factory instance provides
+ * support for XML namespaces by default.
+ *
+ * @implSpec
+ * In addition to creating a factory instance using the same process as
+ * {@link #newInstance(java.lang.String, java.lang.ClassLoader)}, this method
+ * must set NamespaceAware to true.
+ *
+ * @param factoryClassName a fully qualified factory class name that provides
+ * implementation of
+ * {@code javax.xml.parsers.DocumentBuilderFactory}.
+ *
+ * @param classLoader the {@code ClassLoader} used to load the factory class.
+ * If it is {@code null}, the current {@code Thread}'s
+ * context classLoader is used to load the factory class.
+ *
+ * @return a new instance of a {@code DocumentBuilderFactory}
+ *
+ * @throws FactoryConfigurationError if {@code factoryClassName} is {@code null}, or
+ * the factory class cannot be loaded, instantiated.
+ *
+ * @since 13
+ */
+ public static DocumentBuilderFactory newNSInstance(String factoryClassName,
+ ClassLoader classLoader) {
+ return makeNSAware(FactoryFinder.newInstance(
+ DocumentBuilderFactory.class, factoryClassName, classLoader, false));
+ }
+
+ /**
* Creates a new instance of the {@code DocumentBuilderFactory} builtin
* system-default implementation.
*
@@ -141,7 +212,7 @@
/* The default property name according to the JAXP spec */
DocumentBuilderFactory.class, // "javax.xml.parsers.DocumentBuilderFactory"
/* The fallback implementation class name */
- "com.sun.org.apache.xerces.internal.jaxp.DocumentBuilderFactoryImpl");
+ DEFAULT_IMPL);
}
/**
@@ -185,6 +256,11 @@
factoryClassName, classLoader, false);
}
+ private static DocumentBuilderFactory makeNSAware(DocumentBuilderFactory dbf) {
+ dbf.setNamespaceAware(true);
+ return dbf;
+ }
+
/**
* Creates a new instance of a {@link javax.xml.parsers.DocumentBuilder}
* using the currently configured parameters.
--- a/src/java.xml/share/classes/javax/xml/parsers/SAXParserFactory.java Fri May 17 13:21:44 2019 +0100
+++ b/src/java.xml/share/classes/javax/xml/parsers/SAXParserFactory.java Thu May 23 11:07:37 2019 +0100
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2000, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2000, 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
@@ -41,6 +41,8 @@
* @since 1.4
*/
public abstract class SAXParserFactory {
+ private static final String DEFAULT_IMPL =
+ "com.sun.org.apache.xerces.internal.jaxp.SAXParserFactoryImpl";
/**
* Should Parsers be validating?
@@ -60,6 +62,76 @@
}
/**
+ * Creates a new NamespaceAware instance of the {@code SAXParserFactory}
+ * builtin system-default implementation. Parsers produced by the factory
+ * instance provides support for XML namespaces by default.
+ *
+ * @implSpec
+ * In addition to creating a factory instance using the same process as
+ * {@link #newDefaultInstance()}, this method must set NamespaceAware to true.
+ *
+ * @return a new instance of the {@code SAXParserFactory} builtin
+ * system-default implementation.
+ *
+ * @since 13
+ */
+ public static SAXParserFactory newDefaultNSInstance() {
+ return makeNSAware(new SAXParserFactoryImpl());
+ }
+
+ /**
+ * Creates a new NamespaceAware instance of a {@code SAXParserFactory}.
+ * Parsers produced by the factory instance provides support for XML
+ * namespaces by default.
+ *
+ * @implSpec
+ * In addition to creating a factory instance using the same process as
+ * {@link #newInstance()}, this method must set NamespaceAware to true.
+ *
+ * @return a new instance of the {@code SAXParserFactory}
+ *
+ * @throws FactoryConfigurationError in case of {@linkplain
+ * java.util.ServiceConfigurationError service configuration error}
+ * or if the implementation is not available or cannot be instantiated.
+ *
+ * @since 13
+ */
+ public static SAXParserFactory newNSInstance() {
+ return makeNSAware(FactoryFinder.find(SAXParserFactory.class, DEFAULT_IMPL));
+ }
+
+ /**
+ * Creates a new NamespaceAware instance of a {@code SAXParserFactory} from
+ * the class name. Parsers produced by the factory instance provides
+ * support for XML namespaces by default.
+ *
+ * @implSpec
+ * In addition to creating a factory instance using the same process as
+ * {@link #newInstance(java.lang.String, java.lang.ClassLoader)}, this method
+ * must set NamespaceAware to true.
+ *
+ * @param factoryClassName a fully qualified factory class name that provides
+ * implementation of
+ * {@code javax.xml.parsers.SAXParserFactory}.
+ *
+ * @param classLoader the {@code ClassLoader} used to load the factory class.
+ * If it is {@code null}, the current {@code Thread}'s
+ * context classLoader is used to load the factory class.
+ *
+ * @return a new instance of the {@code SAXParserFactory}
+ *
+ * @throws FactoryConfigurationError if {@code factoryClassName} is {@code null}, or
+ * the factory class cannot be loaded, instantiated.
+ *
+ * @since 13
+ */
+ public static SAXParserFactory newNSInstance(String factoryClassName,
+ ClassLoader classLoader) {
+ return makeNSAware(FactoryFinder.newInstance(
+ SAXParserFactory.class, factoryClassName, classLoader, false));
+ }
+
+ /**
* Creates a new instance of the {@code SAXParserFactory} builtin
* system-default implementation.
*
@@ -148,7 +220,7 @@
/* The default property name according to the JAXP spec */
SAXParserFactory.class,
/* The fallback implementation class name */
- "com.sun.org.apache.xerces.internal.jaxp.SAXParserFactoryImpl");
+ DEFAULT_IMPL);
}
/**
@@ -192,6 +264,11 @@
factoryClassName, classLoader, false);
}
+ private static SAXParserFactory makeNSAware(SAXParserFactory spf) {
+ spf.setNamespaceAware(true);
+ return spf;
+ }
+
/**
* Creates a new instance of a SAXParser using the currently
* configured factory parameters.
--- a/src/jdk.compiler/share/classes/com/sun/source/tree/BinaryTree.java Fri May 17 13:21:44 2019 +0100
+++ b/src/jdk.compiler/share/classes/com/sun/source/tree/BinaryTree.java Thu May 23 11:07:37 2019 +0100
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2005, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2005, 2019, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -40,8 +40,8 @@
* @jls 15.20 Relational Operators
* @jls 15.21 Equality Operators
* @jls 15.22 Bitwise and Logical Operators
- * @jls 15.23 Conditional-And Operator &&
- * @jls 15.24 Conditional-Or Operator ||
+ * @jls 15.23 Conditional-And Operator {@code &&}
+ * @jls 15.24 Conditional-Or Operator {@code ||}
*
* @author Peter von der Ahé
* @author Jonathan Gibbons
--- a/src/jdk.compiler/share/classes/com/sun/source/tree/ModifiersTree.java Fri May 17 13:21:44 2019 +0100
+++ b/src/jdk.compiler/share/classes/com/sun/source/tree/ModifiersTree.java Thu May 23 11:07:37 2019 +0100
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2005, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2005, 2019, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -45,7 +45,7 @@
* @jls 8.5.1 Static Member Type Declarations
* @jls 8.8.3 Constructor Modifiers
* @jls 9.1.1 Interface Modifiers
- * @jls 9.7 Annotations
+ * @jls 9.7 Annotations
*
* @author Peter von der Ahé
* @author Jonathan Gibbons
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Types.java Fri May 17 13:21:44 2019 +0100
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Types.java Thu May 23 11:07:37 2019 +0100
@@ -2733,7 +2733,7 @@
* signature</em> of the other. This is <b>not</b> an equivalence
* relation.
*
- * @jls section 8.4.2.
+ * @jls 8.4.2 Method Signature
* @see #overrideEquivalent(Type t, Type s)
* @param t first signature (possibly raw).
* @param s second signature (could be subjected to erasure).
@@ -2752,7 +2752,7 @@
* equivalence</em>. This is the natural extension of
* isSubSignature to an equivalence relation.
*
- * @jls section 8.4.2.
+ * @jls 8.4.2 Method Signature
* @see #isSubSignature(Type t, Type s)
* @param t a signature (possible raw, could be subjected to
* erasure).
@@ -4214,7 +4214,7 @@
/**
* Return-Type-Substitutable.
- * @jls section 8.4.5
+ * @jls 8.4.5 Method Result
*/
public boolean returnTypeSubstitutable(Type r1, Type r2) {
if (hasSameArgs(r1, r2))
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Attr.java Fri May 17 13:21:44 2019 +0100
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Attr.java Thu May 23 11:07:37 2019 +0100
@@ -4222,7 +4222,7 @@
* @param tree The tree making up the variable reference.
* @param env The current environment.
* @param v The variable's symbol.
- * @jls section 8.9 Enums
+ * @jls 8.9 Enum Types
*/
private void checkEnumInitializer(JCTree tree, Env<AttrContext> env, VarSymbol v) {
// JLS:
--- a/src/jdk.compiler/share/classes/module-info.java Fri May 17 13:21:44 2019 +0100
+++ b/src/jdk.compiler/share/classes/module-info.java Thu May 23 11:07:37 2019 +0100
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2014, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2014, 2019, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -55,10 +55,7 @@
* {@code jdk.zipfs} module, must be available if the compiler is to be able
* to read JAR files.
*
- * <dl style="font-family:'DejaVu Sans', Arial, Helvetica, sans serif">
- * <dt class="simpleTagLabel">Tool Guides:
- * <dd>{@extLink javac_tool_reference javac}
- * </dl>
+ * @toolGuide javac
*
* @provides java.util.spi.ToolProvider
* @provides com.sun.tools.javac.platform.PlatformProvider
--- a/src/jdk.hotspot.agent/share/classes/module-info.java Fri May 17 13:21:44 2019 +0100
+++ b/src/jdk.hotspot.agent/share/classes/module-info.java Thu May 23 11:07:37 2019 +0100
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2014, 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2014, 2019, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -30,10 +30,7 @@
* attach to a running Java Virtual Machine (JVM) or launch a postmortem
* debugger to analyze the content of a core-dump from a crashed JVM.
*
- * <dl style="font-family:'DejaVu Sans', Arial, Helvetica, sans serif">
- * <dt class="simpleTagLabel">Tool Guides:</dt>
- * <dd> {@extLink jhsdb_tool_reference jhsdb}</dd>
- * </dl>
+ * @toolGuide jhsdb
*
* @moduleGraph
* @since 9
--- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/CommandProcessor.java Fri May 17 13:21:44 2019 +0100
+++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/CommandProcessor.java Thu May 23 11:07:37 2019 +0100
@@ -536,7 +536,8 @@
// Not an address
boolean all = name.equals("-a");
Threads threads = VM.getVM().getThreads();
- for (JavaThread thread = threads.first(); thread != null; thread = thread.next()) {
+ for (int i = 0; i < threads.getNumberOfThreads(); i++) {
+ JavaThread thread = threads.getJavaThreadAt(i);
ByteArrayOutputStream bos = new ByteArrayOutputStream();
thread.printThreadIDOn(new PrintStream(bos));
if (all || bos.toString().equals(name)) {
@@ -898,7 +899,8 @@
String name = t.nextToken();
boolean all = name.equals("-a");
Threads threads = VM.getVM().getThreads();
- for (JavaThread thread = threads.first(); thread != null; thread = thread.next()) {
+ for (int i = 0; i < threads.getNumberOfThreads(); i++) {
+ JavaThread thread = threads.getJavaThreadAt(i);
ByteArrayOutputStream bos = new ByteArrayOutputStream();
thread.printThreadIDOn(new PrintStream(bos));
if (all || bos.toString().equals(name)) {
@@ -927,7 +929,8 @@
String name = t.nextToken();
boolean all = name.equals("-a");
Threads threads = VM.getVM().getThreads();
- for (JavaThread thread = threads.first(); thread != null; thread = thread.next()) {
+ for (int i = 0; i < threads.getNumberOfThreads(); i++) {
+ JavaThread thread = threads.getJavaThreadAt(i);
ByteArrayOutputStream bos = new ByteArrayOutputStream();
thread.printThreadIDOn(new PrintStream(bos));
if (all || bos.toString().equals(name)) {
@@ -954,7 +957,8 @@
String name = t.nextToken();
boolean all = name.equals("-a");
Threads threads = VM.getVM().getThreads();
- for (JavaThread thread = threads.first(); thread != null; thread = thread.next()) {
+ for (int i = 0; i < threads.getNumberOfThreads(); i++) {
+ JavaThread thread = threads.getJavaThreadAt(i);
ByteArrayOutputStream bos = new ByteArrayOutputStream();
thread.printThreadIDOn(new PrintStream(bos));
if (all || bos.toString().equals(name)) {
@@ -1437,7 +1441,8 @@
final long stride = VM.getVM().getAddressSize();
if (type.equals("threads")) {
Threads threads = VM.getVM().getThreads();
- for (JavaThread thread = threads.first(); thread != null; thread = thread.next()) {
+ for (int i = 0; i < threads.getNumberOfThreads(); i++) {
+ JavaThread thread = threads.getJavaThreadAt(i);
Address base = thread.getStackBase();
Address end = thread.getLastJavaSP();
if (end == null) continue;
@@ -1561,7 +1566,8 @@
String name = t.nextToken();
Threads threads = VM.getVM().getThreads();
boolean all = name.equals("-a");
- for (JavaThread thread = threads.first(); thread != null; thread = thread.next()) {
+ for (int i = 0; i < threads.getNumberOfThreads(); i++) {
+ JavaThread thread = threads.getJavaThreadAt(i);
ByteArrayOutputStream bos = new ByteArrayOutputStream();
thread.printThreadIDOn(new PrintStream(bos));
if (all || bos.toString().equals(name)) {
@@ -1590,7 +1596,8 @@
String name = t.nextToken();
Threads threads = VM.getVM().getThreads();
boolean all = name.equals("-a");
- for (JavaThread thread = threads.first(); thread != null; thread = thread.next()) {
+ for (int i = 0; i < threads.getNumberOfThreads(); i++) {
+ JavaThread thread = threads.getJavaThreadAt(i);
ByteArrayOutputStream bos = new ByteArrayOutputStream();
thread.printThreadIDOn(new PrintStream(bos));
if (all || bos.toString().equals(name)) {
@@ -1613,7 +1620,8 @@
usage();
} else {
Threads threads = VM.getVM().getThreads();
- for (JavaThread thread = threads.first(); thread != null; thread = thread.next()) {
+ for (int i = 0; i < threads.getNumberOfThreads(); i++) {
+ JavaThread thread = threads.getJavaThreadAt(i);
thread.printThreadIDOn(out);
out.println(" " + thread.getThreadName());
thread.printInfoOn(out);
@@ -1631,7 +1639,8 @@
ArrayList nmethods = new ArrayList();
Threads threads = VM.getVM().getThreads();
HTMLGenerator gen = new HTMLGenerator(false);
- for (JavaThread thread = threads.first(); thread != null; thread = thread.next()) {
+ for (int i = 0; i < threads.getNumberOfThreads(); i++) {
+ JavaThread thread = threads.getJavaThreadAt(i);
try {
for (JavaVFrame vf = thread.getLastJavaVFrameDbg(); vf != null; vf = vf.javaSender()) {
if (vf instanceof CompiledVFrame) {
--- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/bsd/BsdDebuggerLocal.java Fri May 17 13:21:44 2019 +0100
+++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/bsd/BsdDebuggerLocal.java Thu May 23 11:07:37 2019 +0100
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2002, 2017, 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
@@ -619,10 +619,10 @@
Threads threads = VM.getVM().getThreads();
int len = threads.getNumberOfThreads();
long[] result = new long[len * 3]; // triple
- JavaThread t = threads.first();
long beg, end;
int i = 0;
- while (t != null) {
+ for (int k = 0; k < threads.getNumberOfThreads(); k++) {
+ JavaThread t = threads.getJavaThreadAt(k);
end = t.getStackBaseValue();
beg = end - t.getStackSize();
BsdThread bsdt = (BsdThread)t.getThreadProxy();
@@ -631,7 +631,6 @@
result[i] = uid;
result[i + 1] = beg;
result[i + 2] = end;
- t = t.next();
i += 3;
}
return result;
--- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/ObjectHeap.java Fri May 17 13:21:44 2019 +0100
+++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/ObjectHeap.java Thu May 23 11:07:37 2019 +0100
@@ -357,7 +357,9 @@
// end.
if (VM.getVM().getUseTLAB()) {
- for (JavaThread thread = VM.getVM().getThreads().first(); thread != null; thread = thread.next()) {
+ Threads threads = VM.getVM().getThreads();
+ for (int i = 0; i < threads.getNumberOfThreads(); i++) {
+ JavaThread thread = threads.getJavaThreadAt(i);
ThreadLocalAllocBuffer tlab = thread.tlab();
if (tlab.start() != null) {
if ((tlab.top() == null) || (tlab.end() == null)) {
--- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/DeadlockDetector.java Fri May 17 13:21:44 2019 +0100
+++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/DeadlockDetector.java Thu May 23 11:07:37 2019 +0100
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2004, 2006, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2004, 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
@@ -146,7 +146,9 @@
private static void createThreadTable() {
threadTable = new HashMap();
- for (JavaThread cur = threads.first(); cur != null; cur = cur.next()) {
+ Threads threads = VM.getVM().getThreads();
+ for (int i = 0; i < threads.getNumberOfThreads(); i++) {
+ JavaThread cur = threads.getJavaThreadAt(i);
// initialize dfn for each thread to -1
threadTable.put(cur, new Integer(-1));
}
--- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/JavaThread.java Fri May 17 13:21:44 2019 +0100
+++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/JavaThread.java Thu May 23 11:07:37 2019 +0100
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2000, 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2000, 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
@@ -41,7 +41,6 @@
public class JavaThread extends Thread {
private static final boolean DEBUG = System.getProperty("sun.jvm.hotspot.runtime.JavaThread.DEBUG") != null;
- private static AddressField nextField;
private static sun.jvm.hotspot.types.OopField threadObjField;
private static AddressField anchorField;
private static AddressField lastJavaSPField;
@@ -84,7 +83,6 @@
Type type = db.lookupType("JavaThread");
Type anchorType = db.lookupType("JavaFrameAnchor");
- nextField = type.getAddressField("_next");
threadObjField = type.getOopField("_threadObj");
anchorField = type.getAddressField("_anchor");
lastJavaSPField = anchorType.getAddressField("_last_Java_sp");
@@ -120,15 +118,6 @@
this.access = access;
}
- public JavaThread next() {
- Address threadAddr = nextField.getValue(addr);
- if (threadAddr == null) {
- return null;
- }
-
- return VM.getVM().getThreads().createJavaThreadWrapper(threadAddr);
- }
-
/** NOTE: for convenience, this differs in definition from the underlying VM.
Only "pure" JavaThreads return true; CompilerThreads, the CodeCacheSweeperThread,
JVMDIDebuggerThreads return false.
--- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/Threads.java Fri May 17 13:21:44 2019 +0100
+++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/Threads.java Thu May 23 11:07:37 2019 +0100
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2000, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2000, 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,12 +42,41 @@
import sun.jvm.hotspot.runtime.bsd_amd64.BsdAMD64JavaThreadPDAccess;
import sun.jvm.hotspot.utilities.*;
+class ThreadsList extends VMObject {
+ private static AddressField threadsField;
+ private static CIntegerField lengthField;
+
+ static {
+ VM.registerVMInitializedObserver((o, d) -> initialize(VM.getVM().getTypeDataBase()));
+ }
+
+ private static synchronized void initialize(TypeDataBase db) {
+ Type type = db.lookupType("ThreadsList");
+ lengthField = type.getCIntegerField("_length");
+ threadsField = type.getAddressField("_threads");
+ }
+
+ public Address getJavaThreadAddressAt(int i) {
+ Address threadAddr = threadsField.getValue(addr);
+ Address at = threadAddr.getAddressAt(VM.getVM().getAddressSize() * i);
+ return at;
+ }
+
+ public long length() {
+ return lengthField.getValue(addr);
+ }
+
+ public ThreadsList(Address addr) {
+ super(addr);
+ }
+}
+
public class Threads {
private static JavaThreadFactory threadFactory;
private static AddressField threadListField;
- private static CIntegerField numOfThreadsField;
private static VirtualConstructor virtualConstructor;
private static JavaThreadPDAccess access;
+ private static ThreadsList _list;
static {
VM.registerVMInitializedObserver(new Observer() {
@@ -58,10 +87,8 @@
}
private static synchronized void initialize(TypeDataBase db) {
- Type type = db.lookupType("Threads");
-
- threadListField = type.getAddressField("_thread_list");
- numOfThreadsField = type.getCIntegerField("_number_of_threads");
+ Type type = db.lookupType("ThreadsSMRSupport");
+ threadListField = type.getAddressField("_java_thread_list");
// Instantiate appropriate platform-specific JavaThreadFactory
String os = VM.getVM().getOS();
@@ -134,6 +161,7 @@
}
public Threads() {
+ _list = VMObjectFactory.newObject(ThreadsList.class, threadListField.getValue());
}
/** NOTE: this returns objects of type JavaThread, CompilerThread,
@@ -147,17 +175,15 @@
false for the three subclasses. FIXME: should reconsider the
inheritance hierarchy; see {@link
sun.jvm.hotspot.runtime.JavaThread#isJavaThread}. */
- public JavaThread first() {
- Address threadAddr = threadListField.getValue();
- if (threadAddr == null) {
- return null;
+ public JavaThread getJavaThreadAt(int i) {
+ if (i < _list.length()) {
+ return createJavaThreadWrapper(_list.getJavaThreadAddressAt(i));
}
-
- return createJavaThreadWrapper(threadAddr);
+ return null;
}
public int getNumberOfThreads() {
- return (int) numOfThreadsField.getValue();
+ return (int) _list.length();
}
/** Routine for instantiating appropriately-typed wrapper for a
@@ -177,7 +203,9 @@
/** Memory operations */
public void oopsDo(AddressVisitor oopVisitor) {
// FIXME: add more of VM functionality
- for (JavaThread thread = first(); thread != null; thread = thread.next()) {
+ Threads threads = VM.getVM().getThreads();
+ for (int i = 0; i < threads.getNumberOfThreads(); i++) {
+ JavaThread thread = threads.getJavaThreadAt(i);
thread.oopsDo(oopVisitor);
}
}
@@ -185,15 +213,17 @@
// refer to Threads::owning_thread_from_monitor_owner
public JavaThread owningThreadFromMonitor(Address o) {
if (o == null) return null;
- for (JavaThread thread = first(); thread != null; thread = thread.next()) {
+ for (int i = 0; i < getNumberOfThreads(); i++) {
+ JavaThread thread = getJavaThreadAt(i);
if (o.equals(thread.threadObjectAddress())) {
return thread;
}
}
- for (JavaThread thread = first(); thread != null; thread = thread.next()) {
- if (thread.isLockOwned(o))
- return thread;
+ for (int i = 0; i < getNumberOfThreads(); i++) {
+ JavaThread thread = getJavaThreadAt(i);
+ if (thread.isLockOwned(o))
+ return thread;
}
return null;
}
@@ -206,7 +236,8 @@
// Get list of Java threads that are waiting to enter the specified monitor.
public List getPendingThreads(ObjectMonitor monitor) {
List pendingThreads = new ArrayList();
- for (JavaThread thread = first(); thread != null; thread = thread.next()) {
+ for (int i = 0; i < getNumberOfThreads(); i++) {
+ JavaThread thread = getJavaThreadAt(i);
if (thread.isCompilerThread() || thread.isCodeCacheSweeperThread()) {
continue;
}
@@ -221,7 +252,8 @@
// Get list of Java threads that have called Object.wait on the specified monitor.
public List getWaitingThreads(ObjectMonitor monitor) {
List pendingThreads = new ArrayList();
- for (JavaThread thread = first(); thread != null; thread = thread.next()) {
+ for (int i = 0; i < getNumberOfThreads(); i++) {
+ JavaThread thread = getJavaThreadAt(i);
ObjectMonitor waiting = thread.getCurrentWaitingMonitor();
if (monitor.equals(waiting)) {
pendingThreads.add(thread);
--- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/tools/PStack.java Fri May 17 13:21:44 2019 +0100
+++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/tools/PStack.java Thu May 23 11:07:37 2019 +0100
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2003, 2017, 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
@@ -201,7 +201,8 @@
jframeCache = new HashMap();
proxyToThread = new HashMap();
Threads threads = VM.getVM().getThreads();
- for (JavaThread cur = threads.first(); cur != null; cur = cur.next()) {
+ for (int i = 0; i < threads.getNumberOfThreads(); i++) {
+ JavaThread cur = threads.getJavaThreadAt(i);
List tmp = new ArrayList(10);
try {
for (JavaVFrame vf = cur.getLastJavaVFrameDbg(); vf != null; vf = vf.javaSender()) {
--- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/tools/StackTrace.java Fri May 17 13:21:44 2019 +0100
+++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/tools/StackTrace.java Thu May 23 11:07:37 2019 +0100
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2002, 2017, 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
@@ -71,8 +71,8 @@
concLocksPrinter = new ConcurrentLocksPrinter();
}
Threads threads = VM.getVM().getThreads();
- int i = 1;
- for (JavaThread cur = threads.first(); cur != null; cur = cur.next(), i++) {
+ for (int i = 0; i < threads.getNumberOfThreads(); i++) {
+ JavaThread cur = threads.getJavaThreadAt(i);
if (cur.isJavaThread()) {
cur.printThreadInfoOn(tty);
try {
--- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/ui/JavaThreadsPanel.java Fri May 17 13:21:44 2019 +0100
+++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/ui/JavaThreadsPanel.java Thu May 23 11:07:37 2019 +0100
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2000, 2004, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2000, 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
@@ -459,12 +459,13 @@
}
private void cache() {
- Threads threads = VM.getVM().getThreads();
- for (JavaThread t = threads.first(); t != null; t = t.next()) {
- if (t.isJavaThread()) {
- cachedThreads.add(new CachedThread(t));
- }
+ Threads threads = VM.getVM().getThreads();
+ for (int i = 0; i < threads.getNumberOfThreads(); i++) {
+ JavaThread t = threads.getJavaThreadAt(i);
+ if (t.isJavaThread()) {
+ cachedThreads.add(new CachedThread(t));
}
+ }
}
private void decache() {
--- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/utilities/AbstractHeapGraphWriter.java Fri May 17 13:21:44 2019 +0100
+++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/utilities/AbstractHeapGraphWriter.java Thu May 23 11:07:37 2019 +0100
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2004, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2004, 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,15 +129,12 @@
protected void writeJavaThreads() throws IOException {
Threads threads = VM.getVM().getThreads();
- JavaThread jt = threads.first();
- int index = 1;
- while (jt != null) {
+ for (int i = 0; i < threads.getNumberOfThreads(); i++) {
+ JavaThread jt = threads.getJavaThreadAt(i);
if (jt.getThreadObj() != null) {
// Note that the thread serial number range is 1-to-N
- writeJavaThread(jt, index);
- index++;
+ writeJavaThread(jt, i + 1);
}
- jt = jt.next();
}
}
--- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/utilities/HeapHprofBinWriter.java Fri May 17 13:21:44 2019 +0100
+++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/utilities/HeapHprofBinWriter.java Thu May 23 11:07:37 2019 +0100
@@ -708,8 +708,8 @@
int frameSerialNum = 0;
int numThreads = 0;
Threads threads = VM.getVM().getThreads();
-
- for (JavaThread thread = threads.first(); thread != null; thread = thread.next()) {
+ for (int i = 0; i < threads.getNumberOfThreads(); i++) {
+ JavaThread thread = threads.getJavaThreadAt(i);
Oop threadObj = thread.getThreadObj();
if (threadObj != null && !thread.isExiting() && !thread.isHiddenFromExternalView()) {
--- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/utilities/PointerFinder.java Fri May 17 13:21:44 2019 +0100
+++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/utilities/PointerFinder.java Thu May 23 11:07:37 2019 +0100
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2000, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2000, 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,7 +56,9 @@
if (VM.getVM().getUseTLAB()) {
// Try to find thread containing it
- for (JavaThread t = VM.getVM().getThreads().first(); t != null; t = t.next()) {
+ Threads threads = VM.getVM().getThreads();
+ for (int i = 0; i < threads.getNumberOfThreads(); i++) {
+ JavaThread t = threads.getJavaThreadAt(i);
ThreadLocalAllocBuffer tlab = t.tlab();
if (tlab.contains(a)) {
loc.inTLAB = true;
@@ -125,7 +127,9 @@
return loc;
}
// Look in thread-local handles
- for (JavaThread t = VM.getVM().getThreads().first(); t != null; t = t.next()) {
+ Threads threads = VM.getVM().getThreads();
+ for (int i = 0; i < threads.getNumberOfThreads(); i++) {
+ JavaThread t = threads.getJavaThreadAt(i);
JNIHandleBlock handleBlock = t.activeHandles();
if (handleBlock != null) {
handleBlock = handleBlock.blockContainingHandle(a);
--- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/utilities/ReversePtrsAnalysis.java Fri May 17 13:21:44 2019 +0100
+++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/utilities/ReversePtrsAnalysis.java Thu May 23 11:07:37 2019 +0100
@@ -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
@@ -92,9 +92,9 @@
heap = vm.getObjectHeap();
// Do each thread's roots
- for (JavaThread thread = VM.getVM().getThreads().first();
- thread != null;
- thread = thread.next()) {
+ Threads threads = VM.getVM().getThreads();
+ for (int i = 0; i < threads.getNumberOfThreads(); i++) {
+ JavaThread thread = threads.getJavaThreadAt(i);
ByteArrayOutputStream bos = new ByteArrayOutputStream();
thread.printThreadIDOn(new PrintStream(bos));
String threadDesc =
--- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/utilities/soql/JSJavaVM.java Fri May 17 13:21:44 2019 +0100
+++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/utilities/soql/JSJavaVM.java Thu May 23 11:07:37 2019 +0100
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2004, 2007, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2004, 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
@@ -189,12 +189,12 @@
private synchronized JSList getThreads() {
if (threadsCache == null) {
- List threads = new ArrayList(0);
- threadsCache = factory.newJSList(threads);
- JavaThread jthread = vm.getThreads().first();
- while (jthread != null) {
- threads.add(jthread);
- jthread = jthread.next();
+ List threadsList = new ArrayList(0);
+ threadsCache = factory.newJSList(threadsList);
+ Threads threads = VM.getVM().getThreads();
+ for (int i = 0; i < threads.getNumberOfThreads(); i++) {
+ JavaThread thread = threads.getJavaThreadAt(i);
+ threadsList.add(thread);
}
}
return threadsCache;
--- a/src/jdk.jartool/share/classes/module-info.java Fri May 17 13:21:44 2019 +0100
+++ b/src/jdk.jartool/share/classes/module-info.java Thu May 23 11:07:37 2019 +0100
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2014, 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2014, 2019, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -36,11 +36,8 @@
* or the {@linkplain java.util.ServiceLoader service loader} with the name
* {@code "jar"}.
*
- * <dl style="font-family:'DejaVu Sans', Arial, Helvetica, sans serif">
- * <dt class="simpleTagLabel">Tool Guides:
- * <dd>{@extLink jar_tool_reference jar},
- * {@extLink jarsigner_tool_reference jarsigner}
- * </dl>
+ * @toolGuide jar
+ * @toolGuide jarsigner
*
* @moduleGraph
* @since 9
--- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/AnnotationTypeWriterImpl.java Fri May 17 13:21:44 2019 +0100
+++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/AnnotationTypeWriterImpl.java Thu May 23 11:07:37 2019 +0100
@@ -43,6 +43,7 @@
import jdk.javadoc.internal.doclets.toolkit.Content;
import jdk.javadoc.internal.doclets.toolkit.util.CommentHelper;
import jdk.javadoc.internal.doclets.toolkit.util.DocFileIOException;
+import jdk.javadoc.internal.doclets.toolkit.util.DocPath;
/**
* Generate the Class Information Page.
@@ -154,9 +155,9 @@
public void printDocument(Content contentTree) throws DocFileIOException {
String description = getDescription("declaration", annotationType);
PackageElement pkg = utils.containingPackage(this.annotationType);
- Content stylesheetContent = getLocalStylesheetContent(pkg);
+ List<DocPath> localStylesheets = getLocalStylesheets(pkg);
printHtmlDocument(configuration.metakeywords.getMetaKeywords(annotationType),
- description, stylesheetContent, contentTree);
+ description, localStylesheets, contentTree);
}
/**
--- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/ClassWriterImpl.java Fri May 17 13:21:44 2019 +0100
+++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/ClassWriterImpl.java Thu May 23 11:07:37 2019 +0100
@@ -55,6 +55,7 @@
import jdk.javadoc.internal.doclets.toolkit.util.ClassTree;
import jdk.javadoc.internal.doclets.toolkit.util.CommentHelper;
import jdk.javadoc.internal.doclets.toolkit.util.DocFileIOException;
+import jdk.javadoc.internal.doclets.toolkit.util.DocPath;
import jdk.javadoc.internal.doclets.toolkit.util.DocletConstants;
/**
@@ -185,9 +186,9 @@
public void printDocument(Content contentTree) throws DocFileIOException {
String description = getDescription("declaration", typeElement);
PackageElement pkg = utils.containingPackage(typeElement);
- Content stylesheetContent = getLocalStylesheetContent(pkg);
+ List<DocPath> localStylesheets = getLocalStylesheets(pkg);
printHtmlDocument(configuration.metakeywords.getMetaKeywords(typeElement),
- description, stylesheetContent, contentTree);
+ description, localStylesheets, contentTree);
}
/**
--- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/DocFilesHandlerImpl.java Fri May 17 13:21:44 2019 +0100
+++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/DocFilesHandlerImpl.java Thu May 23 11:07:37 2019 +0100
@@ -206,7 +206,7 @@
footer.add(navBar.getContent(false));
docletWriter.addBottom(footer);
htmlContent.add(footer);
- docletWriter.printHtmlDocument(Collections.emptyList(), null, localTagsContent, htmlContent);
+ docletWriter.printHtmlDocument(Collections.emptyList(), null, localTagsContent, Collections.emptyList(), htmlContent);
}
--- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/HtmlConfiguration.java Fri May 17 13:21:44 2019 +0100
+++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/HtmlConfiguration.java Thu May 23 11:07:37 2019 +0100
@@ -452,13 +452,17 @@
return null;
}
- public DocFile getMainStylesheet() {
- return stylesheetfile.isEmpty() ? null : DocFile.createFileForInput(this, stylesheetfile);
+ public DocPath getMainStylesheet() {
+ if(!stylesheetfile.isEmpty()){
+ DocFile docFile = DocFile.createFileForInput(this, stylesheetfile);
+ return DocPath.create(docFile.getName());
+ }
+ return null;
}
- public List<DocFile> getAdditionalStylesheets() {
+ public List<DocPath> getAdditionalStylesheets() {
return additionalStylesheets.stream()
- .map(ssf -> DocFile.createFileForInput(this, ssf))
+ .map(ssf -> DocFile.createFileForInput(this, ssf)).map(file -> DocPath.create(file.getName()))
.collect(Collectors.toList());
}
--- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/HtmlDocletWriter.java Fri May 17 13:21:44 2019 +0100
+++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/HtmlDocletWriter.java Thu May 23 11:07:37 2019 +0100
@@ -26,6 +26,7 @@
package jdk.javadoc.internal.doclets.formats.html;
import java.util.ArrayList;
+import java.util.Collections;
import java.util.LinkedList;
import java.util.List;
import java.util.ListIterator;
@@ -399,7 +400,26 @@
String description,
Content body)
throws DocFileIOException {
- printHtmlDocument(metakeywords, description, new ContentBuilder(), body);
+ printHtmlDocument(metakeywords, description, new ContentBuilder(), Collections.emptyList(), body);
+ }
+
+ /**
+ * Generates the HTML document tree and prints it out.
+ *
+ * @param metakeywords Array of String keywords for META tag. Each element
+ * of the array is assigned to a separate META tag.
+ * Pass in null for no array
+ * @param description the content for the description META tag.
+ * @param localStylesheets local stylesheets to be included in the HEAD element
+ * @param body the body htmltree to be included in the document
+ * @throws DocFileIOException if there is a problem writing the file
+ */
+ public void printHtmlDocument(List<String> metakeywords,
+ String description,
+ List<DocPath> localStylesheets,
+ Content body)
+ throws DocFileIOException {
+ printHtmlDocument(metakeywords, description, new ContentBuilder(), localStylesheets, body);
}
/**
@@ -410,15 +430,19 @@
* Pass in null for no array
* @param description the content for the description META tag.
* @param extraHeadContent any additional content to be included in the HEAD element
+ * @param localStylesheets local stylesheets to be included in the HEAD element
* @param body the body htmltree to be included in the document
* @throws DocFileIOException if there is a problem writing the file
*/
public void printHtmlDocument(List<String> metakeywords,
String description,
Content extraHeadContent,
+ List<DocPath> localStylesheets,
Content body)
throws DocFileIOException {
Content htmlComment = contents.newPage;
+ List<DocPath> additionalStylesheets = configuration.getAdditionalStylesheets();
+ additionalStylesheets.addAll(localStylesheets);
Head head = new Head(path, configuration.docletVersion)
.setTimestamp(!configuration.notimestamp)
.setDescription(description)
@@ -426,7 +450,7 @@
.setTitle(winTitle)
.setCharset(configuration.charset)
.addKeywords(metakeywords)
- .setStylesheets(configuration.getMainStylesheet(), configuration.getAdditionalStylesheets())
+ .setStylesheets(configuration.getMainStylesheet(), additionalStylesheets)
.setIndex(configuration.createindex, mainBodyScript)
.addContent(extraHeadContent);
@@ -2188,8 +2212,42 @@
return mainBodyScript;
}
- Content getLocalStylesheetContent(Element element) throws DocFileIOException {
- Content stylesheetContent = new ContentBuilder();
+ /**
+ * Returns the path of module/package specific stylesheets for the element.
+ * @param element module/Package element
+ * @return list of path of module/package specific stylesheets
+ * @throws DocFileIOException
+ */
+ List<DocPath> getLocalStylesheets(Element element) throws DocFileIOException {
+ List<DocPath> stylesheets = new ArrayList<>();
+ DocPath basePath = null;
+ if (element instanceof PackageElement) {
+ stylesheets.addAll(getModuleStylesheets((PackageElement)element));
+ basePath = docPaths.forPackage((PackageElement)element);
+ } else if (element instanceof ModuleElement) {
+ basePath = DocPaths.forModule((ModuleElement)element);
+ }
+ for (DocPath stylesheet : getStylesheets(element)) {
+ stylesheets.add(basePath.resolve(stylesheet.getPath()));
+ }
+ return stylesheets;
+ }
+
+ private List<DocPath> getModuleStylesheets(PackageElement pkgElement) throws
+ DocFileIOException {
+ List<DocPath> moduleStylesheets = new ArrayList<>();
+ ModuleElement moduleElement = utils.containingModule(pkgElement);
+ if (moduleElement != null && !moduleElement.isUnnamed()) {
+ List<DocPath> localStylesheets = getStylesheets(moduleElement);
+ DocPath basePath = DocPaths.forModule(moduleElement);
+ for (DocPath stylesheet : localStylesheets) {
+ moduleStylesheets.add(basePath.resolve(stylesheet));
+ }
+ }
+ return moduleStylesheets;
+ }
+
+ private List<DocPath> getStylesheets(Element element) throws DocFileIOException {
List<DocPath> localStylesheets = configuration.localStylesheetMap.get(element);
if (localStylesheets == null) {
DocFilesHandlerImpl docFilesHandler = (DocFilesHandlerImpl)configuration
@@ -2197,11 +2255,7 @@
localStylesheets = docFilesHandler.getStylesheets();
configuration.localStylesheetMap.put(element, localStylesheets);
}
- for (DocPath stylesheet : localStylesheets) {
- stylesheetContent.add(HtmlTree.LINK("stylesheet",
- "text/css", stylesheet.getPath(), "Style"));
- }
- return stylesheetContent;
+ return localStylesheets;
}
}
--- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/ModuleWriterImpl.java Fri May 17 13:21:44 2019 +0100
+++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/ModuleWriterImpl.java Thu May 23 11:07:37 2019 +0100
@@ -902,8 +902,7 @@
@Override
public void printDocument(Content contentTree) throws DocFileIOException {
printHtmlDocument(configuration.metakeywords.getMetaKeywordsForModule(mdle),
- getDescription("declaration", mdle),
- contentTree);
+ getDescription("declaration", mdle), getLocalStylesheets(mdle), contentTree);
}
/**
--- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/PackageWriterImpl.java Fri May 17 13:21:44 2019 +0100
+++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/PackageWriterImpl.java Thu May 23 11:07:37 2019 +0100
@@ -47,6 +47,7 @@
import jdk.javadoc.internal.doclets.toolkit.PackageSummaryWriter;
import jdk.javadoc.internal.doclets.toolkit.util.CommentHelper;
import jdk.javadoc.internal.doclets.toolkit.util.DocFileIOException;
+import jdk.javadoc.internal.doclets.toolkit.util.DocPath;
import jdk.javadoc.internal.doclets.toolkit.util.DocPaths;
/**
@@ -317,9 +318,9 @@
@Override
public void printDocument(Content contentTree) throws DocFileIOException {
String description = getDescription("declaration", packageElement);
- Content stylesheetContent = getLocalStylesheetContent(packageElement);
+ List<DocPath> localStylesheets = getLocalStylesheets(packageElement);
printHtmlDocument(configuration.metakeywords.getMetaKeywords(packageElement),
- description, stylesheetContent, contentTree);
+ description, localStylesheets, contentTree);
}
/**
--- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/markup/Head.java Fri May 17 13:21:44 2019 +0100
+++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/markup/Head.java Thu May 23 11:07:37 2019 +0100
@@ -59,8 +59,8 @@
private String description;
private String generator;
private boolean showTimestamp;
- private DocFile mainStylesheetFile;
- private List<DocFile> additionalStylesheetFiles = Collections.emptyList();
+ private DocPath mainStylesheet;
+ private List<DocPath> additionalStylesheets = Collections.emptyList();
private boolean index;
private Script mainBodyScript;
private final List<Script> scripts;
@@ -157,14 +157,16 @@
/**
* Sets the main and any additional stylesheets to be listed in the HEAD element.
+ * The paths for the stylesheets must be relative to the root of the generated
+ * documentation hierarchy.
*
* @param main the main stylesheet, or null to use the default
* @param additional a list of any additional stylesheets to be included
* @return this object
*/
- public Head setStylesheets(DocFile main, List<DocFile> additional) {
- this.mainStylesheetFile = main;
- this.additionalStylesheetFiles = additional;
+ public Head setStylesheets(DocPath main, List<DocPath> additional) {
+ this.mainStylesheet = main;
+ this.additionalStylesheets = additional;
return this;
}
@@ -286,16 +288,13 @@
}
private void addStylesheets(HtmlTree tree) {
- DocPath mainStylesheet;
- if (mainStylesheetFile == null) {
+ if (mainStylesheet == null) {
mainStylesheet = DocPaths.STYLESHEET;
- } else {
- mainStylesheet = DocPath.create(mainStylesheetFile.getName());
}
addStylesheet(tree, mainStylesheet);
- for (DocFile file : additionalStylesheetFiles) {
- addStylesheet(tree, DocPath.create(file.getName()));
+ for (DocPath path : additionalStylesheets) {
+ addStylesheet(tree, path);
}
if (index) {
--- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/builders/ModuleSummaryBuilder.java Fri May 17 13:21:44 2019 +0100
+++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/builders/ModuleSummaryBuilder.java Thu May 23 11:07:37 2019 +0100
@@ -28,6 +28,7 @@
import javax.lang.model.element.ModuleElement;
import jdk.javadoc.internal.doclets.toolkit.Content;
+import jdk.javadoc.internal.doclets.toolkit.DocFilesHandler;
import jdk.javadoc.internal.doclets.toolkit.DocletException;
import jdk.javadoc.internal.doclets.toolkit.ModuleSummaryWriter;
@@ -116,9 +117,8 @@
moduleWriter.addModuleFooter(contentTree);
moduleWriter.printDocument(contentTree);
- // uncomment to support doc-files in modules
- // DocFilesHandler docFilesHandler = configuration.getWriterFactory().getDocFilesWriter(mdle);
- // docFilesHandler.copyDocFiles();
+ DocFilesHandler docFilesHandler = configuration.getWriterFactory().getDocFilesHandler(mdle);
+ docFilesHandler.copyDocFiles();
}
/**
--- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/resources/doclets.properties Fri May 17 13:21:44 2019 +0100
+++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/resources/doclets.properties Thu May 23 11:07:37 2019 +0100
@@ -160,13 +160,13 @@
doclet.Properties_Inherited_From_Interface=Properties inherited from interface
doclet.Properties_Declared_In_Class=Properties declared in class
doclet.Properties_Declared_In_Interface=Properties declared in interface
-doclet.Annotation_Type_Member_Detail=Element Detail
-doclet.Enum_Constant_Detail=Enum Constant Detail
+doclet.Annotation_Type_Member_Detail=Element Details
+doclet.Enum_Constant_Detail=Enum Constant Details
doclet.Constants_Summary=Constant Field Values
-doclet.Field_Detail=Field Detail
-doclet.Property_Detail=Property Detail
-doclet.Method_Detail=Method Detail
-doclet.Constructor_Detail=Constructor Detail
+doclet.Field_Detail=Field Details
+doclet.Property_Detail=Property Details
+doclet.Method_Detail=Method Details
+doclet.Constructor_Detail=Constructor Details
doclet.Deprecated=Deprecated.
doclet.DeprecatedForRemoval=Deprecated, for removal: This API element is subject to removal in a future version.
doclet.Groupname_already_used=In -group option, groupname already used: {0}
--- a/src/jdk.javadoc/share/classes/module-info.java Fri May 17 13:21:44 2019 +0100
+++ b/src/jdk.javadoc/share/classes/module-info.java Thu May 23 11:07:37 2019 +0100
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2014, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2014, 2019, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -42,10 +42,7 @@
* or the {@linkplain java.util.ServiceLoader service loader} with the name
* {@code "javadoc"}.
*
- * <dl style="font-family:'DejaVu Sans', Arial, Helvetica, sans serif">
- * <dt class="simpleTagLabel">Tool Guides:
- * <dd>{@extLink javadoc_tool_reference javadoc}
- * </dl>
+ * @toolGuide javadoc
*
* @provides java.util.spi.ToolProvider
* @provides javax.tools.DocumentationTool
--- a/src/jdk.jcmd/share/classes/module-info.java Fri May 17 13:21:44 2019 +0100
+++ b/src/jdk.jcmd/share/classes/module-info.java Thu May 23 11:07:37 2019 +0100
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2014, 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2014, 2019, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -28,16 +28,12 @@
* such as the <em>{@index jcmd jcmd tool}</em>, <em>{@index jps jps tool}</em>,
* <em>{@index jstat jstat tool}</em> tools.
*
- * <dl style="font-family:'DejaVu Sans', Arial, Helvetica, sans serif">
- * <dt class="simpleTagLabel">Tool Guides:
- * <dd>
- * {@extLink jcmd_tool_reference jcmd},
- * {@extLink jinfo_tool_reference jinfo},
- * {@extLink jmap_tool_reference jmap},
- * {@extLink jps_tool_reference jps},
- * {@extLink jstack_tool_reference jstack},
- * {@extLink jstat_tool_reference jstat}
- * </dl>
+ * @toolGuide jcmd
+ * @toolGuide jinfo
+ * @toolGuide jmap
+ * @toolGuide jps
+ * @toolGuide jstack
+ * @toolGuide jstat
*
* @moduleGraph
* @since 9
--- a/src/jdk.jconsole/share/classes/module-info.java Fri May 17 13:21:44 2019 +0100
+++ b/src/jdk.jconsole/share/classes/module-info.java Thu May 23 11:07:37 2019 +0100
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2014, 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2014, 2019, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -28,11 +28,12 @@
* for monitoring and managing a running application.
*
* <dl style="font-family:'DejaVu Sans', Arial, Helvetica, sans serif">
- * <dt class="simpleTagLabel">Tool Guides:
- * <dd>{@extLink jconsole_tool_reference jconsole},
- * {@extLink using_jconsole Using JConsole}
+ * <dt class="simpleTagLabel">See Also:
+ * <dd>{@extLink using_jconsole Using JConsole}
* </dl>
*
+ * @toolGuide jconsole
+ *
* @uses com.sun.tools.jconsole.JConsolePlugin
*
* @moduleGraph
--- a/src/jdk.jdeps/share/classes/module-info.java Fri May 17 13:21:44 2019 +0100
+++ b/src/jdk.jdeps/share/classes/module-info.java Thu May 23 11:07:37 2019 +0100
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015, 2017, 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
@@ -44,12 +44,9 @@
* <em>jdeprscan</em> only exists as a command line tool, and does not provide
* any direct API.
*
- * <dl style="font-family:'DejaVu Sans', Arial, Helvetica, sans serif">
- * <dt class="simpleTagLabel">Tool Guides:
- * <dd>{@extLink javap_tool_reference javap},
- * {@extLink jdeprscan_tool_reference jdeprscan},
- * {@extLink jdeps_tool_reference jdeps}
- * </dl>
+ * @toolGuide javap
+ * @toolGuide jdeprscan
+ * @toolGuide jdeps
*
* @provides java.util.spi.ToolProvider
*
--- a/src/jdk.jdi/share/classes/module-info.java Fri May 17 13:21:44 2019 +0100
+++ b/src/jdk.jdi/share/classes/module-info.java Thu May 23 11:07:37 2019 +0100
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2014, 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2014, 2019, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -104,10 +104,7 @@
* </blockquote>
*
*
- * <dl style="font-family:'DejaVu Sans', Arial, Helvetica, sans serif">
- * <dt class="simpleTagLabel">Tool Guides:
- * <dd>{@extLink jdb_tool_reference jdb}
- * </dl>
+ * @toolGuide jdb
*
* @provides com.sun.jdi.connect.Connector
*
--- a/src/jdk.jdwp.agent/share/native/libdt_socket/socketTransport.c Fri May 17 13:21:44 2019 +0100
+++ b/src/jdk.jdwp.agent/share/native/libdt_socket/socketTransport.c Thu May 23 11:07:37 2019 +0100
@@ -394,6 +394,7 @@
parseAllowedMask(const char *buffer, int isIPv4, struct in6_addr *result) {
int prefixLen = 0;
int maxValue = isIPv4 ? 32 : 128;
+ int i;
do {
if (*buffer < '0' || *buffer > '9') {
@@ -419,7 +420,7 @@
memset(result, 0, sizeof(*result));
// prefixLen <= 128, so we won't go over result's size
- for (int i = 0; prefixLen > 0; i++, prefixLen -= 8) {
+ for (i = 0; prefixLen > 0; i++, prefixLen -= 8) {
if (prefixLen >= 8) {
// set the whole byte
result->s6_addr[i] = 0xFF;
@@ -471,6 +472,7 @@
"invalid IP address in allow option");
}
if (mask != NULL) {
+ size_t i;
if (parseAllowedMask(mask, isIPv4, &(_peers[_peers_cnt].netmask)) != JDWPTRANSPORT_ERROR_NONE) {
_peers_cnt = 0;
fprintf(stderr, "Error in allow option: '%s'\n", mask);
@@ -478,7 +480,7 @@
"invalid netmask in allow option");
}
// for safety update subnet to satisfy the mask
- for (size_t i = 0; i < sizeof(_peers[_peers_cnt].subnet); i++) {
+ for (i = 0; i < sizeof(_peers[_peers_cnt].subnet); i++) {
_peers[_peers_cnt].subnet.s6_addr[i] &= _peers[_peers_cnt].netmask.s6_addr[i];
}
} else {
@@ -521,7 +523,8 @@
static int
isAddressInSubnet(const struct in6_addr *address, const struct in6_addr *subnet, const struct in6_addr *mask) {
- for (size_t i = 0; i < sizeof(struct in6_addr); i++) {
+ size_t i;
+ for (i = 0; i < sizeof(struct in6_addr); i++) {
if ((address->s6_addr[i] & mask->s6_addr[i]) != subnet->s6_addr[i]) {
return 0;
}
@@ -533,6 +536,7 @@
isPeerAllowed(struct sockaddr_storage *peer) {
struct in6_addr tmp;
struct in6_addr *addr6;
+ int i;
// _peers contains IPv6 subnet and mask (IPv4 is converted to mapped IPv6)
if (peer->ss_family == AF_INET) {
convertIPv4ToIPv6((struct sockaddr *)peer, &tmp);
@@ -541,7 +545,7 @@
addr6 = &(((struct sockaddr_in6 *)peer)->sin6_addr);
}
- for (int i = 0; i < _peers_cnt; ++i) {
+ for (i = 0; i < _peers_cnt; ++i) {
if (isAddressInSubnet(addr6, &(_peers[i].subnet), &(_peers[i].netmask))) {
return 1;
}
@@ -635,8 +639,10 @@
char** actualAddress)
{
int err;
+ int pass;
struct addrinfo *addrInfo = NULL;
struct addrinfo *listenAddr = NULL;
+ struct addrinfo *ai = NULL;
/* no address provided */
if ((address == NULL) || (address[0] == '\0')) {
@@ -649,8 +655,8 @@
}
/* 1st pass - preferredAddressFamily (by default IPv4), 2nd pass - the rest */
- for (int pass = 0; pass < 2 && listenAddr == NULL; pass++) {
- for (struct addrinfo *ai = addrInfo; ai != NULL; ai = ai->ai_next) {
+ for (pass = 0; pass < 2 && listenAddr == NULL; pass++) {
+ for (ai = addrInfo; ai != NULL; ai = ai->ai_next) {
if ((pass == 0 && ai->ai_family == preferredAddressFamily) ||
(pass == 1 && ai->ai_family != preferredAddressFamily))
{
@@ -860,7 +866,9 @@
jlong handshakeTimeout)
{
int err;
+ int pass;
struct addrinfo *addrInfo = NULL;
+ struct addrinfo *ai;
if (addressString == NULL || addressString[0] == '\0') {
RETURN_ERROR(JDWPTRANSPORT_ERROR_ILLEGAL_ARGUMENT, "address is missing");
@@ -872,8 +880,8 @@
}
/* 1st pass - preferredAddressFamily (by default IPv4), 2nd pass - the rest */
- for (int pass = 0; pass < 2 && socketFD < 0; pass++) {
- for (struct addrinfo *ai = addrInfo; ai != NULL; ai = ai->ai_next) {
+ for (pass = 0; pass < 2 && socketFD < 0; pass++) {
+ for (ai = addrInfo; ai != NULL; ai = ai->ai_next) {
if ((pass == 0 && ai->ai_family == preferredAddressFamily) ||
(pass == 1 && ai->ai_family != preferredAddressFamily))
{
--- a/src/jdk.jfr/share/classes/module-info.java Fri May 17 13:21:44 2019 +0100
+++ b/src/jdk.jfr/share/classes/module-info.java Thu May 23 11:07:37 2019 +0100
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2014, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2014, 2019, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -27,11 +27,6 @@
* Defines the API for JDK Flight Recorder.
* <p>
*
- * <dl style="font-family:'DejaVu Sans', Arial, Helvetica, sans serif">
- * <dt class="simpleTagLabel">Tool Guides:
- * <dd>{@extLink jfr_tool_reference jfr}
- * </dl>
- *
* @moduleGraph
* @since 9
*/
--- a/src/jdk.jfr/share/conf/jfr/default.jfc Fri May 17 13:21:44 2019 +0100
+++ b/src/jdk.jfr/share/conf/jfr/default.jfc Thu May 23 11:07:37 2019 +0100
@@ -445,6 +445,15 @@
<setting name="enabled" control="gc-enabled-all">false</setting>
</event>
+ <event name="jdk.ShenandoahHeapRegionInformation">
+ <setting name="enabled" control="gc-enabled-all">false</setting>
+ <setting name="period">everyChunk</setting>
+ </event>
+
+ <event name="jdk.ShenandoahHeapRegionStateChange">
+ <setting name="enabled" control="gc-enabled-all">false</setting>
+ </event>
+
<event name="jdk.OldObjectSample">
<setting name="enabled" control="memory-leak-detection-enabled">true</setting>
<setting name="stackTrace" control="memory-leak-detection-stack-trace">false</setting>
--- a/src/jdk.jfr/share/conf/jfr/profile.jfc Fri May 17 13:21:44 2019 +0100
+++ b/src/jdk.jfr/share/conf/jfr/profile.jfc Thu May 23 11:07:37 2019 +0100
@@ -445,6 +445,15 @@
<setting name="enabled" control="gc-enabled-all">false</setting>
</event>
+ <event name="jdk.ShenandoahHeapRegionInformation">
+ <setting name="enabled" control="gc-enabled-all">false</setting>
+ <setting name="period">everyChunk</setting>
+ </event>
+
+ <event name="jdk.ShenandoahHeapRegionStateChange">
+ <setting name="enabled" control="gc-enabled-all">false</setting>
+ </event>
+
<event name="jdk.OldObjectSample">
<setting name="enabled" control="memory-leak-detection-enabled">true</setting>
<setting name="stackTrace" control="memory-leak-detection-stack-trace">true</setting>
--- a/src/jdk.jlink/share/classes/module-info.java Fri May 17 13:21:44 2019 +0100
+++ b/src/jdk.jlink/share/classes/module-info.java Thu May 23 11:07:37 2019 +0100
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 2019, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -30,8 +30,7 @@
* the JDK implementation-specific container file for classes and resources.
*
* <p> This module provides the equivalent of command-line access to the
- * <em>{@extLink jlink_tool_reference jlink}</em> and
- * <em>{@extLink jmod_tool_reference jmod}</em> tools via the
+ * <em>jlink</em> and <em>jmod</em> tools via the
* {@link java.util.spi.ToolProvider ToolProvider} SPI.
* Instances of the tools can be obtained by calling
* {@link java.util.spi.ToolProvider#findFirst ToolProvider.findFirst}
@@ -41,11 +40,8 @@
* <p> <em>jimage</em> only exists
* as a command-line tool, and does not provide any direct API.
*
- * <dl style="font-family:'DejaVu Sans', Arial, Helvetica, sans serif">
- * <dt class="simpleTagLabel">Tool Guides:
- * <dd>{@extLink jlink_tool_reference jlink},
- * {@extLink jmod_tool_reference jmod}
- * </dl>
+ * @toolGuide jlink
+ * @toolGuide jmod
*
* @provides java.util.spi.ToolProvider
*
--- a/src/jdk.jshell/share/classes/jdk/jshell/ExpressionSnippet.java Fri May 17 13:21:44 2019 +0100
+++ b/src/jdk.jshell/share/classes/jdk/jshell/ExpressionSnippet.java Thu May 23 11:07:37 2019 +0100
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 2019, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -36,7 +36,7 @@
* and thus is thread-safe.
*
* @since 9
- * @jls 15: Expression.
+ * @jls 15 Expressions
*/
public class ExpressionSnippet extends Snippet {
--- a/src/jdk.jshell/share/classes/jdk/jshell/ImportSnippet.java Fri May 17 13:21:44 2019 +0100
+++ b/src/jdk.jshell/share/classes/jdk/jshell/ImportSnippet.java Thu May 23 11:07:37 2019 +0100
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 2019, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -36,7 +36,7 @@
* and thus is thread-safe.
*
* @since 9
- * @jls 8.3: importDeclaration.
+ * @jls 7.5 Import Declarations
*/
public class ImportSnippet extends PersistentSnippet {
--- a/src/jdk.jshell/share/classes/jdk/jshell/MethodSnippet.java Fri May 17 13:21:44 2019 +0100
+++ b/src/jdk.jshell/share/classes/jdk/jshell/MethodSnippet.java Thu May 23 11:07:37 2019 +0100
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 2019, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -37,7 +37,7 @@
* and thus is thread-safe.
*
* @since 9
- * @jls 8.4: MethodDeclaration.
+ * @jls 8.4 Method Declarations
*/
public class MethodSnippet extends DeclarationSnippet {
--- a/src/jdk.jshell/share/classes/jdk/jshell/Snippet.java Fri May 17 13:21:44 2019 +0100
+++ b/src/jdk.jshell/share/classes/jdk/jshell/Snippet.java Thu May 23 11:07:37 2019 +0100
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015, 2017, 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
@@ -73,7 +73,7 @@
* ({@link jdk.jshell.Snippet.SubKind#SINGLE_STATIC_IMPORT_SUBKIND}) --
* use {@link jdk.jshell.Snippet#subKind()} to distinguish.
*
- * @jls 8.3: importDeclaration.
+ * @jls 7.5 Import Declarations
* <P>
* An import declaration is {@linkplain Kind#isPersistent() persistent}.
*/
@@ -91,7 +91,7 @@
* annotation interfaces -- see {@link jdk.jshell.Snippet.SubKind} to
* differentiate.
*
- * @jls 7.6: TypeDeclaration.
+ * @jls 7.6 Top Level Type Declarations
* <P>
* A type declaration is {@linkplain Kind#isPersistent() persistent}.
*/
@@ -101,7 +101,7 @@
* A method declaration.
* The snippet is an instance of {@link jdk.jshell.MethodSnippet}.
*
- * @jls 8.4: MethodDeclaration.
+ * @jls 8.4 Method Declarations
* <P>
* A method declaration is {@linkplain Kind#isPersistent() persistent}.
*/
@@ -116,7 +116,7 @@
* variable representing an expression -- see
* {@link jdk.jshell.Snippet.SubKind}to differentiate.
*
- * @jls 8.3: FieldDeclaration.
+ * @jls 8.3 Field Declarations
* <P>
* A variable declaration is {@linkplain Kind#isPersistent() persistent}.
*/
@@ -133,7 +133,7 @@
* All other expression forms (operators, method calls, ...) generate a
* scratch variable and so are instead of the VAR Kind.
*
- * @jls 15: Expression.
+ * @jls 15 Expressions
*/
EXPRESSION(false),
@@ -141,7 +141,7 @@
* A statement.
* The snippet is an instance of {@link jdk.jshell.StatementSnippet}.
*
- * @jls 14.5: Statement.
+ * @jls 14.5 Statements
*/
STATEMENT(false),
@@ -185,99 +185,97 @@
/**
* Single-Type-Import Declaration.
* An import declaration of a single type.
- * @jls 7.5.1 SingleTypeImportDeclaration.
+ * @jls 7.5.1 Single-Type-Import Declarations
*/
SINGLE_TYPE_IMPORT_SUBKIND(Kind.IMPORT),
/**
* Type-Import-on-Demand Declaration.
* A non-static "star" import.
- * @jls 7.5.2. TypeImportOnDemandDeclaration.
+ * @jls 7.5.2 Type-Import-on-Demand Declarations
*/
TYPE_IMPORT_ON_DEMAND_SUBKIND(Kind.IMPORT),
/**
* Single-Static-Import Declaration.
* An import of a static member.
- * @jls 7.5.3 Single-Static-Import.
+ * @jls 7.5.3 Single-Static-Import Declarations
*/
SINGLE_STATIC_IMPORT_SUBKIND(Kind.IMPORT),
/**
* Static-Import-on-Demand Declaration.
* A static "star" import of all static members of a named type.
- * @jls 7.5.4. Static-Import-on-Demand Static "star" import.
+ * @jls 7.5.4 Static-Import-on-Demand Declarations
*/
STATIC_IMPORT_ON_DEMAND_SUBKIND(Kind.IMPORT),
/**
* A class declaration.
* A {@code SubKind} of {@link Kind#TYPE_DECL}.
- * @jls 8.1. NormalClassDeclaration.
+ * @jls 8.1 Class Declarations
*/
CLASS_SUBKIND(Kind.TYPE_DECL),
/**
* An interface declaration.
* A {@code SubKind} of {@link Kind#TYPE_DECL}.
- * @jls 9.1. NormalInterfaceDeclaration.
+ * @jls 9.1 Interface Declarations
*/
INTERFACE_SUBKIND(Kind.TYPE_DECL),
/**
* An enum declaration.
* A {@code SubKind} of {@link Kind#TYPE_DECL}.
- * @jls 8.9. EnumDeclaration.
+ * @jls 8.9 Enum Types
*/
ENUM_SUBKIND(Kind.TYPE_DECL),
/**
* An annotation interface declaration. A {@code SubKind} of
* {@link Kind#TYPE_DECL}.
- * @jls 9.6. AnnotationTypeDeclaration.
+ * @jls 9.6 Annotation Types
*/
ANNOTATION_TYPE_SUBKIND(Kind.TYPE_DECL),
/**
* A method. The only {@code SubKind} for {@link Kind#METHOD}.
- * @jls 8.4. MethodDeclaration.
+ * @jls 8.4 Method Declarations
*/
METHOD_SUBKIND(Kind.METHOD),
/**
* A variable declaration without initializer.
* A {@code SubKind} of {@link Kind#VAR}.
- * @jls 8.3. VariableDeclarator without VariableInitializer in
- * FieldDeclaration.
+ * @jls 8.3 Field Declarations
*/
VAR_DECLARATION_SUBKIND(Kind.VAR, true, true),
/**
* A variable declaration with an initializer expression. A
* {@code SubKind} of {@link Kind#VAR}.
- * @jls 8.3. VariableDeclarator with VariableInitializer in
- * FieldDeclaration.
+ * @jls 8.3 Field Declarations
*/
VAR_DECLARATION_WITH_INITIALIZER_SUBKIND(Kind.VAR, true, true),
/**
* An expression whose value has been stored in a temporary variable. A
* {@code SubKind} of {@link Kind#VAR}.
- * @jls 15. Primary.
+ * @jls 15 Expressions
*/
TEMP_VAR_EXPRESSION_SUBKIND(Kind.VAR, true, true),
/**
* A simple variable reference expression. A {@code SubKind} of
* {@link Kind#EXPRESSION}.
- * @jls 15.11. Field Access as 3.8. Identifier.
+ * @jls 15.11 Field Access Expressions
*/
VAR_VALUE_SUBKIND(Kind.EXPRESSION, true, true),
/**
* An assignment expression. A {@code SubKind} of
* {@link Kind#EXPRESSION}.
- * @jls 15.26. Assignment.
+ * @jls 15.26 Assignment Operators
*/
ASSIGNMENT_SUBKIND(Kind.EXPRESSION, true, true),
@@ -289,7 +287,7 @@
/**
* A statement. The only {@code SubKind} for {@link Kind#STATEMENT}.
- * @jls 14.5. Statement.
+ * @jls 14.5 Statements
*/
STATEMENT_SUBKIND(Kind.STATEMENT, true, false),
--- a/src/jdk.jshell/share/classes/jdk/jshell/StatementSnippet.java Fri May 17 13:21:44 2019 +0100
+++ b/src/jdk.jshell/share/classes/jdk/jshell/StatementSnippet.java Thu May 23 11:07:37 2019 +0100
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 2019, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -36,7 +36,7 @@
* and thus is thread-safe.
*
* @since 9
- * @jls 14.5: Statement.
+ * @jls 14.5 Statements
*/
public class StatementSnippet extends Snippet {
--- a/src/jdk.jshell/share/classes/jdk/jshell/VarSnippet.java Fri May 17 13:21:44 2019 +0100
+++ b/src/jdk.jshell/share/classes/jdk/jshell/VarSnippet.java Thu May 23 11:07:37 2019 +0100
@@ -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
@@ -39,7 +39,7 @@
* and thus is thread-safe.
*
* @since 9
- * @jls 8.3: FieldDeclaration.
+ * @jls 8.3 Field Declarations
*/
public class VarSnippet extends DeclarationSnippet {
--- a/src/jdk.jshell/share/classes/module-info.java Fri May 17 13:21:44 2019 +0100
+++ b/src/jdk.jshell/share/classes/module-info.java Thu May 23 11:07:37 2019 +0100
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015, 2017, 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,9 +24,11 @@
*/
/**
- * This module provides support for
- * Java Programming Language 'snippet' evaluating tools, such as
- * Read-Eval-Print Loops (REPLs), including the <em>{@index jshell jshell tool}</em> tool.
+ * Provides the <em>{@index jshell jshell tool}</em> tool for evaluating
+ * snippets of Java code, and defines a JDK-specific API for modeling and
+ * executing snippets.
+ * The JShell API supports Java Programming Language 'snippet' evaluating
+ * tools, such as Read-Eval-Print Loops (REPLs).
* Separate packages support building tools, configuring the execution of tools,
* and programmatically launching the existing Java shell tool.
* <p>
@@ -52,10 +54,7 @@
* definitions.
* </p>
*
- * <dl style="font-family:'DejaVu Sans', Arial, Helvetica, sans serif">
- * <dt class="simpleTagLabel">Tool Guides:
- * <dd>{@extLink jshell_tool_reference jshell}
- * </dl>
+ * @toolGuide jshell
*
* @provides javax.tools.Tool
* @provides jdk.jshell.spi.ExecutionControlProvider
--- a/src/jdk.jstatd/share/classes/module-info.java Fri May 17 13:21:44 2019 +0100
+++ b/src/jdk.jstatd/share/classes/module-info.java Thu May 23 11:07:37 2019 +0100
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015, 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 2019, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -27,10 +27,7 @@
* Defines the <em>{@index jstatd jstatd tool}</em> tool for starting a daemon
* for the jstat tool to monitor JVM statistics remotely.
*
- * <dl style="font-family:'DejaVu Sans', Arial, Helvetica, sans serif">
- * <dt class="simpleTagLabel">Tool Guides:
- * <dd>{@extLink jstatd_tool_reference jstatd}
- * </dl>
+ * @toolGuide jstatd
*
* @moduleGraph
* @since 9
--- a/src/jdk.localedata/share/classes/sun/text/resources/ext/FormatData_ar.java Fri May 17 13:21:44 2019 +0100
+++ b/src/jdk.localedata/share/classes/sun/text/resources/ext/FormatData_ar.java Thu May 23 11:07:37 2019 +0100
@@ -212,6 +212,7 @@
"\u062a\u064a\u0634\u0648",
"\u0634\u0648\u0648\u0627",
"\u0647\u064a\u0633\u064a",
+ "\u0631\u064a\u0648\u0627",
}
},
{ "japanese.short.Eras",
@@ -221,6 +222,7 @@
"\u062a\u064a\u0634\u0648",
"\u0634\u0648\u0648\u0627",
"\u0647\u064a\u0633\u064a",
+ "\u0631\u064a\u0648\u0627",
}
},
{ "buddhist.Eras",
--- a/src/jdk.localedata/share/classes/sun/text/resources/ext/FormatData_es_PE.java Fri May 17 13:21:44 2019 +0100
+++ b/src/jdk.localedata/share/classes/sun/text/resources/ext/FormatData_es_PE.java Thu May 23 11:07:37 2019 +0100
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997, 2013, 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
@@ -63,6 +63,21 @@
"hh:mm a", // short time pattern
}
},
+ { "NumberElements",
+ new String[] {
+ ".", // decimal separator
+ ",", // group (thousands) separator
+ ";", // list separator
+ "%", // percent sign
+ "0", // native 0 digit
+ "#", // pattern digit
+ "-", // minus sign
+ "E", // exponential
+ "\u2030", // per mille
+ "\u221e", // infinity
+ "\ufffd" // NaN
+ }
+ },
{ "DatePatterns",
new String[] {
"EEEE d' de 'MMMM' de 'yyyy", // full date pattern
--- a/src/jdk.localedata/share/classes/sun/text/resources/ext/FormatData_ko.java Fri May 17 13:21:44 2019 +0100
+++ b/src/jdk.localedata/share/classes/sun/text/resources/ext/FormatData_ko.java Thu May 23 11:07:37 2019 +0100
@@ -192,6 +192,7 @@
"\ub2e4\uc774\uc1fc",
"\uc1fc\uc640",
"\ud5e4\uc774\uc138\uc774",
+ "\ub808\uc774\uc640",
}
},
{ "AmPmMarkers",
--- a/src/jdk.localedata/share/classes/sun/text/resources/ext/FormatData_th.java Fri May 17 13:21:44 2019 +0100
+++ b/src/jdk.localedata/share/classes/sun/text/resources/ext/FormatData_th.java Thu May 23 11:07:37 2019 +0100
@@ -245,6 +245,7 @@
"\u0e17\u0e30\u0e2d\u0e34\u0e42\u0e0a",
"\u0e42\u0e0a\u0e27\u0e30",
"\u0e40\u0e2e\u0e40\u0e0b",
+ "\u0e40\u0e23\u0e27\u0e30",
}
},
{ "japanese.short.Eras",
@@ -254,6 +255,7 @@
"\u0e17",
"\u0e0a",
"\u0e2e",
+ "R",
}
},
{ "buddhist.TimePatterns",
--- a/src/jdk.localedata/share/classes/sun/text/resources/ext/FormatData_zh.java Fri May 17 13:21:44 2019 +0100
+++ b/src/jdk.localedata/share/classes/sun/text/resources/ext/FormatData_zh.java Thu May 23 11:07:37 2019 +0100
@@ -282,6 +282,7 @@
"\u5927\u6b63",
"\u662d\u548c",
"\u5e73\u6210",
+ "\u4ee4\u548c",
}
},
{ "TimePatterns",
--- a/src/jdk.localedata/share/classes/sun/text/resources/ext/JavaTimeSupplementary_ar.java Fri May 17 13:21:44 2019 +0100
+++ b/src/jdk.localedata/share/classes/sun/text/resources/ext/JavaTimeSupplementary_ar.java Thu May 23 11:07:37 2019 +0100
@@ -157,6 +157,7 @@
"\u062a\u064a\u0634\u0648",
"\u0634\u0648\u0648\u0627",
"\u0647\u064a\u0633\u064a",
+ "\u0631\u064a\u0648\u0627",
};
final String[] sharedShortEras = {
--- a/src/jdk.localedata/share/classes/sun/text/resources/ext/JavaTimeSupplementary_hi_IN.java Fri May 17 13:21:44 2019 +0100
+++ b/src/jdk.localedata/share/classes/sun/text/resources/ext/JavaTimeSupplementary_hi_IN.java Thu May 23 11:07:37 2019 +0100
@@ -241,6 +241,7 @@
"\u0924\u093e\u0908\u0936\u094b",
"\u0936\u094b\u0935\u093e",
"\u0939\u0947\u0908\u0938\u0947\u0908",
+ "\u0930\u0947\u0907\u0935\u093e",
}
},
{ "java.time.japanese.short.Eras",
@@ -250,6 +251,7 @@
"\u0924\u093e\u0908\u0936\u094b",
"\u0936\u094b\u0935\u093e",
"\u0939\u0947\u0908\u0938\u0947\u0908",
+ "\u0930\u0947\u0907\u0935\u093e",
}
},
{ "java.time.long.Eras",
--- a/src/jdk.localedata/share/classes/sun/text/resources/ext/JavaTimeSupplementary_hr.java Fri May 17 13:21:44 2019 +0100
+++ b/src/jdk.localedata/share/classes/sun/text/resources/ext/JavaTimeSupplementary_hr.java Thu May 23 11:07:37 2019 +0100
@@ -231,6 +231,7 @@
"Taish\u014d",
"Sh\u014dwa",
"Heisei",
+ "Reiwa",
}
},
{ "java.time.japanese.short.Eras",
@@ -240,6 +241,7 @@
"Taish\u014d",
"Sh\u014dwa",
"Heisei",
+ "Reiwa",
}
},
{ "java.time.long.Eras",
--- a/src/jdk.localedata/share/classes/sun/text/resources/ext/JavaTimeSupplementary_in.java Fri May 17 13:21:44 2019 +0100
+++ b/src/jdk.localedata/share/classes/sun/text/resources/ext/JavaTimeSupplementary_in.java Thu May 23 11:07:37 2019 +0100
@@ -148,6 +148,7 @@
"Taish\u014d",
"Sh\u014dwa",
"Heisei",
+ "Reiwa",
};
final String[] sharedEras = {
--- a/src/jdk.localedata/share/classes/sun/text/resources/ext/JavaTimeSupplementary_ko.java Fri May 17 13:21:44 2019 +0100
+++ b/src/jdk.localedata/share/classes/sun/text/resources/ext/JavaTimeSupplementary_ko.java Thu May 23 11:07:37 2019 +0100
@@ -143,6 +143,7 @@
"\ub2e4\uc774\uc1fc",
"\uc1fc\uc640",
"\ud5e4\uc774\uc138\uc774",
+ "\ub808\uc774\uc640",
};
final String[] sharedJavaTimeShortEras2 = {
--- a/src/jdk.localedata/share/classes/sun/text/resources/ext/JavaTimeSupplementary_lt.java Fri May 17 13:21:44 2019 +0100
+++ b/src/jdk.localedata/share/classes/sun/text/resources/ext/JavaTimeSupplementary_lt.java Thu May 23 11:07:37 2019 +0100
@@ -223,6 +223,7 @@
"Tai\u0161o",
"\u0160ova",
"Heisei",
+ "Reiwa",
}
},
{ "java.time.japanese.short.Eras",
@@ -232,6 +233,7 @@
"Tai\u0161o",
"\u0160ova",
"Heisei",
+ "Reiwa",
}
},
{ "java.time.long.Eras",
--- a/src/jdk.localedata/share/classes/sun/text/resources/ext/JavaTimeSupplementary_nl.java Fri May 17 13:21:44 2019 +0100
+++ b/src/jdk.localedata/share/classes/sun/text/resources/ext/JavaTimeSupplementary_nl.java Thu May 23 11:07:37 2019 +0100
@@ -265,6 +265,7 @@
"Taish\u014d",
"Sh\u014dwa",
"Heisei",
+ "Reiwa",
}
},
{ "java.time.japanese.short.Eras",
@@ -274,6 +275,7 @@
"Taish\u014d",
"Sh\u014dwa",
"Heisei",
+ "Reiwa",
}
},
{ "java.time.long.Eras",
--- a/src/jdk.localedata/share/classes/sun/text/resources/ext/JavaTimeSupplementary_no.java Fri May 17 13:21:44 2019 +0100
+++ b/src/jdk.localedata/share/classes/sun/text/resources/ext/JavaTimeSupplementary_no.java Thu May 23 11:07:37 2019 +0100
@@ -283,6 +283,7 @@
"Taish\u014d",
"Sh\u014dwa",
"Heisei",
+ "Reiwa",
}
},
{ "java.time.japanese.short.Eras",
@@ -292,6 +293,7 @@
"T",
"S",
"H",
+ "R",
}
},
{ "java.time.long.Eras",
--- a/src/jdk.localedata/share/classes/sun/text/resources/ext/JavaTimeSupplementary_ru.java Fri May 17 13:21:44 2019 +0100
+++ b/src/jdk.localedata/share/classes/sun/text/resources/ext/JavaTimeSupplementary_ru.java Thu May 23 11:07:37 2019 +0100
@@ -237,6 +237,7 @@
"\u042d\u043f\u043e\u0445\u0430 \u0422\u0430\u0439\u0441\u044c\u043e",
"\u0421\u044c\u043e\u0432\u0430",
"\u042d\u043f\u043e\u0445\u0430 \u0425\u044d\u0439\u0441\u044d\u0439",
+ "\u0420\u044d\u0439\u0432\u0430",
}
},
{ "java.time.japanese.short.Eras",
@@ -246,6 +247,7 @@
"\u042d\u043f\u043e\u0445\u0430 \u0422\u0430\u0439\u0441\u044c\u043e",
"\u0421\u044c\u043e\u0432\u0430",
"\u042d\u043f\u043e\u0445\u0430 \u0425\u044d\u0439\u0441\u044d\u0439",
+ "\u0420\u044d\u0439\u0432\u0430",
}
},
{ "java.time.long.Eras",
--- a/src/jdk.localedata/share/classes/sun/text/resources/ext/JavaTimeSupplementary_sr.java Fri May 17 13:21:44 2019 +0100
+++ b/src/jdk.localedata/share/classes/sun/text/resources/ext/JavaTimeSupplementary_sr.java Thu May 23 11:07:37 2019 +0100
@@ -280,6 +280,7 @@
"\u0422\u0430\u0438\u0448\u043e",
"\u0428\u043e\u0432\u0430",
"\u0425\u0430\u0438\u0441\u0435\u0438",
+ "\u0420\u0435\u0438\u0432\u0430",
}
},
{ "java.time.japanese.short.Eras",
@@ -289,6 +290,7 @@
"\u0422\u0430\u0438\u0448\u043e",
"\u0428\u043e\u0432\u0430",
"\u0425\u0430\u0438\u0441\u0435\u0438",
+ "\u0420\u0435\u0438\u0432\u0430",
}
},
{ "java.time.long.Eras",
--- a/src/jdk.localedata/share/classes/sun/text/resources/ext/JavaTimeSupplementary_sr_Latn.java Fri May 17 13:21:44 2019 +0100
+++ b/src/jdk.localedata/share/classes/sun/text/resources/ext/JavaTimeSupplementary_sr_Latn.java Thu May 23 11:07:37 2019 +0100
@@ -225,6 +225,7 @@
"Tai\u0161o",
"\u0160ova",
"Haisei",
+ "Reiva",
}
},
{ "java.time.japanese.short.Eras",
@@ -234,6 +235,7 @@
"Tai\u0161o",
"\u0160ova",
"Haisei",
+ "Reiva",
}
},
{ "java.time.long.Eras",
--- a/src/jdk.localedata/share/classes/sun/text/resources/ext/JavaTimeSupplementary_sv.java Fri May 17 13:21:44 2019 +0100
+++ b/src/jdk.localedata/share/classes/sun/text/resources/ext/JavaTimeSupplementary_sv.java Thu May 23 11:07:37 2019 +0100
@@ -249,6 +249,7 @@
"Taish\u014d",
"Sh\u014dwa",
"Heisei",
+ "Reiwa",
}
},
{ "java.time.japanese.short.Eras",
@@ -258,6 +259,7 @@
"Taish\u014d",
"Sh\u014dwa",
"Heisei",
+ "Reiwa",
}
},
{ "java.time.long.Eras",
--- a/src/jdk.localedata/share/classes/sun/text/resources/ext/JavaTimeSupplementary_th.java Fri May 17 13:21:44 2019 +0100
+++ b/src/jdk.localedata/share/classes/sun/text/resources/ext/JavaTimeSupplementary_th.java Thu May 23 11:07:37 2019 +0100
@@ -137,6 +137,7 @@
"\u0e17\u0e30\u0e2d\u0e34\u0e42\u0e0a",
"\u0e42\u0e0a\u0e27\u0e30",
"\u0e40\u0e2e\u0e40\u0e0b",
+ "\u0e40\u0e23\u0e27\u0e30",
};
final String[] sharedShortEras = {
--- a/src/jdk.localedata/share/classes/sun/text/resources/ext/JavaTimeSupplementary_zh.java Fri May 17 13:21:44 2019 +0100
+++ b/src/jdk.localedata/share/classes/sun/text/resources/ext/JavaTimeSupplementary_zh.java Thu May 23 11:07:37 2019 +0100
@@ -176,6 +176,7 @@
"\u5927\u6b63",
"\u662d\u548c",
"\u5e73\u6210",
+ "\u4ee4\u548c",
};
final String[] sharedJavaTimeShortEras2 = {
--- a/src/jdk.localedata/share/classes/sun/text/resources/ext/JavaTimeSupplementary_zh_TW.java Fri May 17 13:21:44 2019 +0100
+++ b/src/jdk.localedata/share/classes/sun/text/resources/ext/JavaTimeSupplementary_zh_TW.java Thu May 23 11:07:37 2019 +0100
@@ -135,6 +135,7 @@
"\u5927\u6b63",
"\u662d\u548c",
"\u5e73\u6210",
+ "\u4ee4\u548c",
};
final String[] sharedJavaTimeShortEras2 = {
--- a/src/jdk.pack/share/classes/module-info.java Fri May 17 13:21:44 2019 +0100
+++ b/src/jdk.pack/share/classes/module-info.java Thu May 23 11:07:37 2019 +0100
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2014, 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2014, 2019, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -29,11 +29,8 @@
* <em>{@index pack200 pack200 tool}</em> and
* <em>{@index unpack200 unpack200 tool}</em> tools.
*
- * <dl style="font-family:'DejaVu Sans', Arial, Helvetica, sans serif">
- * <dt class="simpleTagLabel">Tool Guides:
- * <dd>{@extLink pack200_tool_reference pack200},
- * {@extLink unpack200_tool_reference unpack200}
- * </dl>
+ * @toolGuide pack200
+ * @toolGuide unpack200
*
* @moduleGraph
* @deprecated This module is deprecated, and is planned for removal in a
--- a/src/jdk.rmic/share/classes/module-info.java Fri May 17 13:21:44 2019 +0100
+++ b/src/jdk.rmic/share/classes/module-info.java Thu May 23 11:07:37 2019 +0100
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2014, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2014, 2019, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -27,10 +27,7 @@
* Defines the <em>{@index rmic rmic}</em> compiler for generating stubs and
* skeletons using the Java Remote Method Protocol (JRMP) for remote objects.
*
- * <dl style="font-family:'DejaVu Sans', Arial, Helvetica, sans serif">
- * <dt class="simpleTagLabel">Tool Guides:
- * <dd>{@extLink rmic_tool_reference rmic}
- * </dl>
+ * @toolGuide rmic
*
* @moduleGraph
* @since 9
--- a/src/jdk.scripting.nashorn.shell/share/classes/module-info.java Fri May 17 13:21:44 2019 +0100
+++ b/src/jdk.scripting.nashorn.shell/share/classes/module-info.java Thu May 23 11:07:37 2019 +0100
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2014, 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2014, 2019, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -29,10 +29,7 @@
* <p>This module includes the command line tool <em>{@index jjs jjs tool}</em>
* to invoke the Nashorn engine.
*
- * <dl style="font-family:'DejaVu Sans', Arial, Helvetica, sans serif">
- * <dt class="simpleTagLabel">Tool Guides:
- * <dd>{@extLink jjs_tool_reference jjs}
- * </dl>
+ * @toolGuide jjs
*
* @moduleGraph
* @since 9
--- a/src/jdk.zipfs/share/classes/jdk/nio/zipfs/ZipFileSystem.java Fri May 17 13:21:44 2019 +0100
+++ b/src/jdk.zipfs/share/classes/jdk/nio/zipfs/ZipFileSystem.java Thu May 23 11:07:37 2019 +0100
@@ -1934,7 +1934,7 @@
this.pos = pos;
}
- // constructor for cenInit() (1) remove trailing '/' (2) pad leading '/'
+ // constructor for initCEN() (1) remove trailing '/' (2) pad leading '/'
IndexNode(byte[] cen, int pos, int nlen) {
int noff = pos + CENHDR;
if (cen[noff + nlen - 1] == '/') {
@@ -1948,10 +1948,51 @@
System.arraycopy(cen, noff, name, 1, nlen);
name[0] = '/';
}
- name(name);
+ name(normalize(name));
this.pos = pos;
}
+ // Normalize the IndexNode.name field.
+ private byte[] normalize(byte[] path) {
+ int len = path.length;
+ if (len == 0)
+ return path;
+ byte prevC = 0;
+ for (int pathPos = 0; pathPos < len; pathPos++) {
+ byte c = path[pathPos];
+ if (c == '/' && prevC == '/')
+ return normalize(path, pathPos - 1);
+ prevC = c;
+ }
+ if (len > 1 && prevC == '/') {
+ return Arrays.copyOf(path, len - 1);
+ }
+ return path;
+ }
+
+ private byte[] normalize(byte[] path, int off) {
+ // As we know we have at least one / to trim, we can reduce
+ // the size of the resulting array
+ byte[] to = new byte[path.length - 1];
+ int pathPos = 0;
+ while (pathPos < off) {
+ to[pathPos] = path[pathPos];
+ pathPos++;
+ }
+ int toPos = pathPos;
+ byte prevC = 0;
+ while (pathPos < path.length) {
+ byte c = path[pathPos++];
+ if (c == '/' && prevC == '/')
+ continue;
+ to[toPos++] = c;
+ prevC = c;
+ }
+ if (toPos > 1 && to[toPos - 1] == '/')
+ toPos--;
+ return (toPos == to.length) ? to : Arrays.copyOf(to, toPos);
+ }
+
private static final ThreadLocal<IndexNode> cachedKey = new ThreadLocal<>();
final static IndexNode keyOf(byte[] name) { // get a lookup key;
--- a/test/fmw/gtest/src/gtest.cc Fri May 17 13:21:44 2019 +0100
+++ b/test/fmw/gtest/src/gtest.cc Thu May 23 11:07:37 2019 +0100
@@ -34,6 +34,7 @@
#include "gtest/internal/custom/gtest.h"
#include "gtest/gtest-spi.h"
+#include <assert.h>
#include <ctype.h>
#include <math.h>
#include <stdarg.h>
@@ -4388,7 +4389,8 @@
// errors are ignored as there's nothing better we can do and we
// don't want to fail the test because of this.
FILE* pfile = posix::FOpen(premature_exit_filepath, "w");
- fwrite("0", 1, 1, pfile);
+ size_t cnt= fwrite("0", 1, 1, pfile);
+ assert(cnt == (size_t)1);
fclose(pfile);
}
}
--- a/test/hotspot/gtest/gc/shared/test_collectorPolicy.cpp Fri May 17 13:21:44 2019 +0100
+++ b/test/hotspot/gtest/gc/shared/test_collectorPolicy.cpp Thu May 23 11:07:37 2019 +0100
@@ -66,10 +66,10 @@
FLAG_GUARD(OldSize);
MinHeapSize = 40 * M;
- FLAG_SET_ERGO(size_t, InitialHeapSize, 100 * M);
- FLAG_SET_ERGO(size_t, OldSize, 4 * M);
- FLAG_SET_ERGO(size_t, NewSize, 1 * M);
- FLAG_SET_ERGO(size_t, MaxNewSize, 80 * M);
+ FLAG_SET_ERGO(InitialHeapSize, 100 * M);
+ FLAG_SET_ERGO(OldSize, 4 * M);
+ FLAG_SET_ERGO(NewSize, 1 * M);
+ FLAG_SET_ERGO(MaxNewSize, 80 * M);
ASSERT_NO_FATAL_FAILURE(setter1->execute());
@@ -88,7 +88,7 @@
public:
SetNewSizeErgo(size_t param) : UnaryExecutor(param) { }
void execute() {
- FLAG_SET_ERGO(size_t, NewSize, param);
+ FLAG_SET_ERGO(NewSize, param);
}
};
@@ -129,7 +129,7 @@
public:
SetNewSizeCmd(size_t param) : UnaryExecutor(param) { }
void execute() {
- FLAG_SET_CMDLINE(size_t, NewSize, param);
+ FLAG_SET_CMDLINE(NewSize, param);
}
};
@@ -148,7 +148,7 @@
public:
SetOldSizeCmd(size_t param) : UnaryExecutor(param) { }
void execute() {
- FLAG_SET_CMDLINE(size_t, OldSize, param);
+ FLAG_SET_CMDLINE(OldSize, param);
}
};
@@ -159,7 +159,7 @@
size_t heap_alignment = GCArguments::compute_heap_alignment();
size_t new_size_value = align_up(MaxHeapSize, heap_alignment)
- param1 + param2;
- FLAG_SET_CMDLINE(size_t, MaxNewSize, new_size_value);
+ FLAG_SET_CMDLINE(MaxNewSize, new_size_value);
}
};
--- a/test/hotspot/gtest/runtime/test_os_windows.cpp Fri May 17 13:21:44 2019 +0100
+++ b/test/hotspot/gtest/runtime/test_os_windows.cpp Thu May 23 11:07:37 2019 +0100
@@ -59,8 +59,8 @@
// set globals to make sure we hit the correct code path
FLAG_GUARD(UseLargePagesIndividualAllocation);
FLAG_GUARD(UseNUMAInterleaving);
- FLAG_SET_CMDLINE(bool, UseLargePagesIndividualAllocation, false);
- FLAG_SET_CMDLINE(bool, UseNUMAInterleaving, false);
+ FLAG_SET_CMDLINE(UseLargePagesIndividualAllocation, false);
+ FLAG_SET_CMDLINE(UseNUMAInterleaving, false);
const size_t large_allocation_size = os::large_page_size() * 4;
char* result = os::reserve_memory_special(large_allocation_size, os::large_page_size(), NULL, false);
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/gtest/utilities/test_ostream.cpp Thu May 23 11:07:37 2019 +0100
@@ -0,0 +1,69 @@
+/*
+ * 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.
+ *
+ */
+
+#include "precompiled.hpp"
+#include "memory/resourceArea.hpp"
+#include "runtime/os.hpp"
+#include "utilities/globalDefinitions.hpp"
+#include "utilities/ostream.hpp"
+
+#include "unittest.hpp"
+
+static size_t print_lorem(outputStream* st, bool short_len) {
+ // Create a ResourceMark just to make sure the stream does not use ResourceArea
+ ResourceMark rm;
+ static const char* const lorem = "Lorem ipsum dolor sit amet, consectetur adipiscing elit, "
+ "sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Lacinia at quis "
+ "risus sed vulputate odio ut enim blandit. Amet risus nullam eget felis eget. Viverra "
+ "orci sagittis eu volutpat odio facilisis mauris sit. Erat velit scelerisque in dictum non.";
+ static const size_t len_lorem = strlen(lorem);
+ size_t len;
+ if (short_len) {
+ len = os::random() % 10;
+ } else {
+ len = MAX2(1, (int)(os::random() % len_lorem));
+ }
+ st->write(lorem, len);
+ return len;
+}
+
+static void do_test_stringStream_dynamic_realloc(bool short_len) {
+ stringStream ss(2); // small buffer to force lots of reallocations.
+ size_t written = 0;
+ for (int i = 0; i < 1000; i ++) {
+ written += print_lorem(&ss, short_len);
+ ASSERT_EQ(ss.size(), written);
+ // Internal buffer should always be zero-terminated.
+ ASSERT_EQ(ss.base()[ss.size()], '\0');
+ }
+}
+
+TEST_VM(ostream, stringStream_dynamic_realloc_1) {
+ do_test_stringStream_dynamic_realloc(false);
+}
+
+TEST_VM(ostream, stringStream_dynamic_realloc_2) {
+ do_test_stringStream_dynamic_realloc(true);
+}
--- a/test/hotspot/jtreg/ProblemList-graal.txt Fri May 17 13:21:44 2019 +0100
+++ b/test/hotspot/jtreg/ProblemList-graal.txt Thu May 23 11:07:37 2019 +0100
@@ -226,14 +226,6 @@
runtime/exceptionMsgs/AbstractMethodError/AbstractMethodErrorTest.java 8222582 generic-all
-vmTestbase/nsk/jdi/ObjectReference/referringObjects/referringObjects002/referringObjects002.java 8220032 generic-all
-vmTestbase/nsk/jdi/VirtualMachine/instanceCounts/instancecounts003/instancecounts003.java 8220032 generic-all
-
-vmTestbase/nsk/jdi/ClassLoaderReference/definedClasses/definedclasses003/TestDescription.java 8222422 generic-all
-vmTestbase/nsk/jdi/ClassLoaderReference/definedClasses/definedclasses005/TestDescription.java 8222422 generic-all
-
-runtime/exceptionMsgs/ArrayIndexOutOfBoundsException/ArrayIndexOutOfBoundsExceptionTest.java 8222292 generic-all
-
serviceability/dcmd/compiler/CodelistTest.java 8220449 generic-all
# Graal unit tests
--- a/test/hotspot/jtreg/ProblemList.txt Fri May 17 13:21:44 2019 +0100
+++ b/test/hotspot/jtreg/ProblemList.txt Thu May 23 11:07:37 2019 +0100
@@ -79,7 +79,6 @@
# :hotspot_runtime
runtime/SharedArchiveFile/SASymbolTableTest.java 8193639 solaris-all
-containers/docker/TestCPUSets.java 8220672 generic-all
runtime/jni/terminatedThread/TestTerminatedThread.java 8219652 aix-ppc64
#############################################################################
@@ -114,7 +113,6 @@
serviceability/sa/DeadlockDetectionTest.java 8193639,8211767 solaris-all,linux-ppc64le,linux-ppc64
serviceability/sa/JhsdbThreadInfoTest.java 8193639,8211767 solaris-all,linux-ppc64le,linux-ppc64
serviceability/sa/jmap-hprof/JMapHProfLargeHeapTest.java 8193639 solaris-all
-serviceability/sa/sadebugd/SADebugDTest.java 8163805 generic-all
serviceability/sa/TestClassDump.java 8193639 solaris-all
serviceability/sa/TestClhsdbJstackLock.java 8193639,8211767 solaris-all,linux-ppc64le,linux-ppc64
serviceability/sa/TestCpoolForInvokeDynamic.java 8193639,8211767 solaris-all,linux-ppc64le,linux-ppc64
@@ -134,6 +132,7 @@
serviceability/sa/TestUniverse.java#id0 8193639,8211767 solaris-all,linux-ppc64le,linux-ppc64
serviceability/jvmti/HeapMonitor/MyPackage/HeapMonitorStatIntervalTest.java 8214032 generic-all
+serviceability/jvmti/HeapMonitor/MyPackage/HeapMonitorStatArrayCorrectnessTest.java 8224150 generic-all
#############################################################################
--- a/test/hotspot/jtreg/TEST.groups Fri May 17 13:21:44 2019 +0100
+++ b/test/hotspot/jtreg/TEST.groups Thu May 23 11:07:37 2019 +0100
@@ -314,6 +314,23 @@
hotspot_appcds = \
runtime/appcds/
+hotspot_appcds_dynamic = \
+ runtime/appcds/ \
+ -runtime/appcds/cacheObject \
+ -runtime/appcds/customLoader \
+ -runtime/appcds/dynamicArchive \
+ -runtime/appcds/javaldr/ArrayTest.java \
+ -runtime/appcds/javaldr/GCSharedStringsDuringDump.java \
+ -runtime/appcds/javaldr/HumongousDuringDump.java \
+ -runtime/appcds/sharedStrings \
+ -runtime/appcds/DumpClassList.java \
+ -runtime/appcds/ExtraSymbols.java \
+ -runtime/appcds/LongClassListPath.java \
+ -runtime/appcds/LotsOfClasses.java \
+ -runtime/appcds/SharedArchiveConsistency.java \
+ -runtime/appcds/UnusedCPDuringDump.java \
+ -runtime/appcds/VerifierTest_1B.java
+
# A subset of AppCDS tests to be run in tier1
tier1_runtime_appcds = \
runtime/appcds/HelloTest.java \
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/compiler/arraycopy/TestArrayCopyWithBadOffset.java Thu May 23 11:07:37 2019 +0100
@@ -0,0 +1,71 @@
+/*
+ * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @bug 8224539
+ * @summary Test arraycopy optimizations with bad src/dst array offsets.
+ * @run main/othervm -Xbatch -XX:+AlwaysIncrementalInline
+ * compiler.arraycopy.TestArrayCopyWithBadOffset
+ */
+
+package compiler.arraycopy;
+
+public class TestArrayCopyWithBadOffset {
+
+ public static byte[] getSrc() {
+ return new byte[5];
+ }
+
+ // Test bad src offset
+ public static void test1(byte[] dst) {
+ byte[] src = getSrc();
+ try {
+ System.arraycopy(src, Integer.MAX_VALUE-1, dst, 0, src.length);
+ } catch (Exception e) {
+ // Expected
+ }
+ }
+
+ public static byte[] getDst() {
+ return new byte[5];
+ }
+
+ // Test bad dst offset
+ public static void test2(byte[] src) {
+ byte[] dst = getDst();
+ try {
+ System.arraycopy(src, 0, dst, Integer.MAX_VALUE-1, dst.length);
+ } catch (Exception e) {
+ // Expected
+ }
+ }
+
+ public static void main(String[] args) {
+ byte[] array = new byte[5];
+ for (int i = 0; i < 10_000; ++i) {
+ test1(array);
+ test2(array);
+ }
+ }
+}
--- a/test/hotspot/jtreg/compiler/graalunit/README.md Fri May 17 13:21:44 2019 +0100
+++ b/test/hotspot/jtreg/compiler/graalunit/README.md Thu May 23 11:07:37 2019 +0100
@@ -21,14 +21,23 @@
https://lafo.ssw.uni-linz.ac.at/pub/graal-external-deps/hamcrest-core-1.3.jar
java-allocation-instrumenter.jar:
- https://lafo.ssw.uni-linz.ac.at/pub/java-allocation-instrumenter/java-allocation-instrumenter-8f0db117e64e.jar
+ https://lafo.ssw.uni-linz.ac.at/pub/java-allocation-instrumenter/java-allocation-instrumenter.jar
Before running the tests you need to download these jars from above locations in build/<platform>/images/test/hotspot/jtreg/graal/
-directory. Then you can pass it to jtreg as java option by using "-vmoptions:-Dgraalunit.libs=" or as environment variable
-by using "-e:TEST_IMAGE_GRAAL_DIR=..."
+directory. You can use 'downloadLibs.sh' script which will try to download all these libs using wget.
+
+
+Then you can run Graal unit test(s) using 'make run-test':
+
+> make run-test TEST="compiler/graalunit/ApiTest.java" TEST_VM_OPTS="-server -XX:+UnlockExperimentalVMOptions -XX:+EnableJVMCI"
+
+
+If you want to use jtreg directly you need to say jtreg where to find external jars.
+You can do it by passing additional option "-vmoptions:-Dgraalunit.libs=" or setting environment variable by using "-e:TEST_IMAGE_GRAAL_DIR=..."
Example:
-> jtreg -vt -jdk:<TESTED_JDK> -vmoptions:"-Dgraalunit.libs=build/<platform>/images/test/hotspot/jtreg/graal"
+> jtreg -vt -jdk:<TESTED_JDK> -vmoptions:"-server -XX:+UnlockExperimentalVMOptions -XX:+EnableJVMCI"
+ -vmoptions:"-Dgraalunit.libs=build/<platform>/images/test/hotspot/jtreg/graal"
compiler/graalunit/UtilTest.java
To run Graal unit tests in Graal as JIT mode pass additional -vmoptions to jtreg:
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/compiler/graalunit/downloadLibs.sh Thu May 23 11:07:37 2019 +0100
@@ -0,0 +1,45 @@
+#!/bin/bash
+#
+# Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
+# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+#
+# This code is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License version 2 only, as
+# published by the Free Software Foundation.
+#
+# This code is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+# version 2 for more details (a copy is included in the LICENSE file that
+# accompanied this code).
+#
+# You should have received a copy of the GNU General Public License version
+# 2 along with this work; if not, write to the Free Software Foundation,
+# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+#
+# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+# or visit www.oracle.com if you need additional information or have any
+# questions.
+#
+
+if [ -z "$1" ]; then
+ echo use:
+ echo '$0 <libs dir to download in>'
+ echo
+ exit 0
+fi
+
+LIBS_DIR=$1
+mkdir -p ${LIBS_DIR}
+
+LIBS="https://lafo.ssw.uni-linz.ac.at/pub/graal-external-deps/asm-5.0.4.jar"
+LIBS="$LIBS https://lafo.ssw.uni-linz.ac.at/pub/graal-external-deps/asm-tree-5.0.4.jar"
+LIBS="$LIBS https://lafo.ssw.uni-linz.ac.at/pub/graal-external-deps/junit-4.12.jar"
+LIBS="$LIBS https://lafo.ssw.uni-linz.ac.at/pub/graal-external-deps/hamcrest-core-1.3.jar"
+LIBS="$LIBS https://lafo.ssw.uni-linz.ac.at/pub/java-allocation-instrumenter/java-allocation-instrumenter.jar"
+
+for l in ${LIBS} ;
+do
+ echo "Download $l"
+ wget -P ${LIBS_DIR} $l
+done
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/compiler/intrinsics/Test8215792.java Thu May 23 11:07:37 2019 +0100
@@ -0,0 +1,62 @@
+/*
+ * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2019, Arm Limited. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @bug 8215792
+ * @summary Fix a bug in AArch64 string intrinsics
+ *
+ * @run main/othervm compiler.intrinsics.Test8215792
+ * @run main/othervm -XX:-CompactStrings compiler.intrinsics.Test8215792
+ */
+
+package compiler.intrinsics;
+
+public class Test8215792 {
+
+ private static final int ITERATIONS = 10000;
+ private static final String pattern = "01234567890123456789";
+
+ public static void main(String[] args) {
+
+ // Repeat many times to trigger compilation
+ for (int iter = 0; iter < ITERATIONS; iter++) {
+ StringBuilder str1 = new StringBuilder("ABCDEFGHIJKLMNOPQRSTUVWXYZ01234567890123456789");
+ StringBuilder str2 = new StringBuilder("\u4f60\u598dCDEFGHIJKLMNOPQRSTUVWXYZ01234567890123456789");
+
+ for (int i = 0; i < 20; i++) {
+ // Remove one character from the tail
+ str1.setLength(str1.length() - 1);
+ str2.setLength(str2.length() - 1);
+ // Pattern string should not be found after characters removed from the tail
+ if (str1.indexOf(pattern) != -1 || str2.indexOf(pattern) != -1) {
+ System.out.println("FAILED");
+ System.exit(1);
+ }
+ }
+ }
+ System.out.println("PASSED");
+ }
+}
+
--- a/test/hotspot/jtreg/compiler/intrinsics/sha/cli/SHAOptionsBase.java Fri May 17 13:21:44 2019 +0100
+++ b/test/hotspot/jtreg/compiler/intrinsics/sha/cli/SHAOptionsBase.java Thu May 23 11:07:37 2019 +0100
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2014, 2019, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -74,23 +74,17 @@
* instructions required by the option are not supported.
*/
public static String getWarningForUnsupportedCPU(String optionName) {
- if (Platform.isAArch64() || Platform.isS390x() || Platform.isSparc()
- || Platform.isX64() || Platform.isX86() || Platform.isPPC()) {
- switch (optionName) {
- case SHAOptionsBase.USE_SHA_OPTION:
- return SHAOptionsBase.SHA_INSTRUCTIONS_ARE_NOT_AVAILABLE;
- case SHAOptionsBase.USE_SHA1_INTRINSICS_OPTION:
- return SHAOptionsBase.SHA1_INTRINSICS_ARE_NOT_AVAILABLE;
- case SHAOptionsBase.USE_SHA256_INTRINSICS_OPTION:
- return SHAOptionsBase.SHA256_INTRINSICS_ARE_NOT_AVAILABLE;
- case SHAOptionsBase.USE_SHA512_INTRINSICS_OPTION:
- return SHAOptionsBase.SHA512_INTRINSICS_ARE_NOT_AVAILABLE;
- default:
- throw new Error("Unexpected option " + optionName);
- }
- } else {
- throw new Error("Support for CPUs different from AARCH64, S390x,"
- + " SPARC, X86, and PPC is not implemented");
+ switch (optionName) {
+ case SHAOptionsBase.USE_SHA_OPTION:
+ return SHAOptionsBase.SHA_INSTRUCTIONS_ARE_NOT_AVAILABLE;
+ case SHAOptionsBase.USE_SHA1_INTRINSICS_OPTION:
+ return SHAOptionsBase.SHA1_INTRINSICS_ARE_NOT_AVAILABLE;
+ case SHAOptionsBase.USE_SHA256_INTRINSICS_OPTION:
+ return SHAOptionsBase.SHA256_INTRINSICS_ARE_NOT_AVAILABLE;
+ case SHAOptionsBase.USE_SHA512_INTRINSICS_OPTION:
+ return SHAOptionsBase.SHA512_INTRINSICS_ARE_NOT_AVAILABLE;
+ default:
+ throw new Error("Unexpected option " + optionName);
}
}
--- a/test/hotspot/jtreg/compiler/intrinsics/sha/cli/testcases/GenericTestCaseForOtherCPU.java Fri May 17 13:21:44 2019 +0100
+++ b/test/hotspot/jtreg/compiler/intrinsics/sha/cli/testcases/GenericTestCaseForOtherCPU.java Thu May 23 11:07:37 2019 +0100
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2014, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2014, 2019, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -32,12 +32,12 @@
/**
* Generic test case for SHA-related options targeted to any CPU except
- * AArch64, S390x, SPARC and X86.
+ * AArch64, PPC, S390x, SPARC and X86.
*/
public class GenericTestCaseForOtherCPU extends
SHAOptionsBase.TestCase {
public GenericTestCaseForOtherCPU(String optionName) {
- // Execute the test case on any CPU except AArch64, S390x, SPARC and X86.
+ // Execute the test case on any CPU except AArch64, PPC, S390x, SPARC and X86.
super(optionName, new NotPredicate(
new OrPredicate(Platform::isAArch64,
new OrPredicate(Platform::isS390x,
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/compiler/intrinsics/string/TestStringCompareToDifferentLength.java Thu May 23 11:07:37 2019 +0100
@@ -0,0 +1,101 @@
+/*
+ * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2019, BELLSOFT. 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
+ * @requires os.arch=="aarch64"
+ * @summary String::compareTo implementation uses different algorithms for
+ * different string length. This test creates string with specified
+ * size and longer string, which is same at beginning.
+ * Expecting length delta to be returned. Test class takes 2
+ * parameters: <string length>, <maximum string length delta>
+ * Input parameters for this test are set according to Aarch64
+ * String::compareTo intrinsic implementation specifics. Aarch64
+ * implementation has 1, 4, 8 -characters loops for length < 72 and
+ * 16, 32, 64 -characters loops for length >= 72. Code is also affected
+ * by SoftwarePrefetchHintDistance vm flag value.
+ * @run main/othervm -XX:SoftwarePrefetchHintDistance=192 compiler.intrinsics.string.TestStringCompareToDifferentLength 4 2 5 10 13 17 20 25 71 72 73 88 90 192 193 208 209
+ * @run main/othervm -XX:SoftwarePrefetchHintDistance=16 compiler.intrinsics.string.TestStringCompareToDifferentLength 4 2 5 10 13 17 20 25 71 72 73 88 90
+ * @run main/othervm -XX:SoftwarePrefetchHintDistance=-1 compiler.intrinsics.string.TestStringCompareToDifferentLength 4 2 5 10 13 17 20 25 71 72 73 88 90
+ */
+
+package compiler.intrinsics.string;
+
+public class TestStringCompareToDifferentLength {
+ private final int size;
+
+ public static void main(String args[]) {
+ if (args.length > 1) {
+ int maxLengthDelta = Integer.parseInt(args[0]);
+ for (int i = 1; i < args.length; i++) {
+ int size = Integer.parseInt(args[i]);
+ TestStringCompareToDifferentLength test
+ = new TestStringCompareToDifferentLength(size);
+ for (int delta = 1; delta <= maxLengthDelta; delta++) {
+ test.testCompareTo(delta);
+ }
+ }
+ } else {
+ System.out.println("Usage: $testClass $maxLengthDelta $testLength [$testLength2 [$testLength3 [...]]]");
+ }
+ }
+
+ private TestStringCompareToDifferentLength(int size) {
+ this.size = size;
+ }
+
+ private void testCompareTo(int delta) {
+ char strsrc[] = new char[size + delta];
+ // generate ASCII string
+ for (int i = 0; i < size + delta; i++) {
+ strsrc[i] = (char) ('a' + (i % 26));
+ }
+
+ String longLatin1 = new String(strsrc);
+ String shortLatin1 = longLatin1.substring(0, size);
+
+ String longUTF16LastChar = longLatin1.substring(0, longLatin1.length() - 1) + '\uBEEF';
+ String longUTF16FirstChar = '\uBEEF' + longLatin1.substring(1, longLatin1.length());
+ String shortUTF16FirstChar = longUTF16FirstChar.substring(0, size);
+
+ for (int i = 0; i < 10000; i++) {
+ checkCase(longLatin1, shortLatin1, delta, "LL"); // Latin1-Latin1.
+ checkCase(longUTF16LastChar, shortLatin1, delta, "UL"); // Latin1-UTF-16 case.
+ checkCase(longUTF16FirstChar, shortUTF16FirstChar, delta, "UU"); // UTF-16-UTF-16 case
+ }
+ }
+
+ private void checkCase(String str2, String str1, int expected, String caseName) {
+ int result = str2.compareTo(str1);
+ int reversedResult = str1.compareTo(str2);
+ if (expected != result || result != -reversedResult) {
+ throw new AssertionError(String.format("%s CASE FAILED: size = %d, "
+ + "expected = %d, but got result = %d, "
+ + "reversedResult = %d for string1 = '%s', string2 = '%s'",
+ caseName, size, expected, result,
+ reversedResult, str1, str2));
+ }
+ }
+}
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/compiler/intrinsics/string/TestStringCompareToSameLength.java Thu May 23 11:07:37 2019 +0100
@@ -0,0 +1,142 @@
+/*
+ * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2019, BELLSOFT. 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
+ * @requires os.arch=="aarch64"
+ * @summary String::compareTo implementation uses different algorithms for
+ * different string length. This test creates various strings of
+ * specified size, which are different at all possible index values and
+ * compares them. Expecting separately calculated result to be returned.
+ * String size is specified via commandline. Various size values can
+ * be specified during intrinsic development in order to test cases
+ * specific for new or modified intrinsic implementation. Aarch64
+ * implementation has 1, 4, 8 -characters loops for length < 72 and
+ * 16, 32, 64 -characters loops for string length >= 72. Code is also
+ * affected by SoftwarePrefetchHintDistance flag value.
+ * Test class can also accept "-fullmode" parameter
+ * with maxLength paramter after it. Then it will iterate through all
+ * string length values up to maxLength parameter (inclusive). It takes
+ * a lot of time but is useful for development.
+ * @run main/othervm -XX:SoftwarePrefetchHintDistance=192 compiler.intrinsics.string.TestStringCompareToSameLength 2 5 10 13 17 20 25 71 72 73 88 90 192 193 208 209
+ * @run main/othervm -XX:SoftwarePrefetchHintDistance=16 compiler.intrinsics.string.TestStringCompareToSameLength 2 5 10 13 17 20 25 71 72 73 88 90
+ * @run main/othervm -XX:SoftwarePrefetchHintDistance=-1 compiler.intrinsics.string.TestStringCompareToSameLength 2 5 10 13 17 20 25 71 72 73 88 90
+ */
+
+package compiler.intrinsics.string;
+
+public class TestStringCompareToSameLength {
+ private final int size;
+
+ public static void main(String args[]) {
+ if (args.length == 0) {
+ throw new IllegalArgumentException("Usage: $testClass $testLength1"
+ + " [$testLength2 [...]] | -fullmode $maxLength");
+ }
+ if (args.length == 2 && "-fullmode".equals(args[0])) {
+ int maxLength = Integer.parseInt(args[1]);
+ for (int length = 1; length <= maxLength; length++) {
+ TestStringCompareToSameLength test = new TestStringCompareToSameLength(length);
+ for (int mismatchIdx = 0; mismatchIdx <= length; mismatchIdx++) {
+ test.testCompareTo(mismatchIdx);
+ }
+ }
+ } else {
+ for (String arg : args) {
+ int size = Integer.parseInt(arg);
+ TestStringCompareToSameLength test = new TestStringCompareToSameLength(size);
+ for (int mismatchIdx = 0; mismatchIdx <= size; mismatchIdx++) {
+ test.testCompareTo(mismatchIdx);
+ }
+ }
+ }
+ }
+
+ private TestStringCompareToSameLength(int size) {
+ this.size = size;
+ }
+
+ private void testCompareTo(int mismatchIdx) {
+ // Create Latin1 strings: latin1, latin2, which are different at index.
+ // Case of index == size is a case of equal strings
+ char latinSrc[] = new char[size];
+ // generate ASCII string
+ for (int i = 0; i < size; i++) {
+ latinSrc[i] = (char) ('a' + (i % 26));
+ }
+ String latinStr1 = new String(latinSrc);
+ if (mismatchIdx != size) latinSrc[mismatchIdx] = (char) ('a' - 1);
+ String latinStr2 = new String(latinSrc);
+
+ // Create 3 utf strings: utfStr1, utfStr2: same as latinStr1, but has UTF-16 character
+ // utfStr1 and utfStr2 are different at requested index and character value is greater
+ // than same index character in latinStr1.
+ // utfStr3 is different at requested index and character value is less than same
+ // index character in latinStr1. Will be a Latin1-encoded string in case difference
+ // is requested at last character. This case not applicable and is skipped below.
+ char cArray[] = latinStr1.toCharArray();
+ cArray[cArray.length - 1] = '\uBEEF'; // at least last character is UTF-16
+ if (mismatchIdx != size) cArray[mismatchIdx] = '\u1234';
+ String utfStr1 = new String(cArray);
+ if (mismatchIdx != size) cArray[mismatchIdx] = '\u5678';
+ String utfStr2 = new String(cArray);
+ if (mismatchIdx != size) cArray[mismatchIdx] = (char) ('a' - 2); // less than Latin1 index position
+ // utfStr3 will be Latin1 if last character differ. Will skip this case
+ String utfStr3 = new String(cArray);
+
+ for (int i = 0; i < 10000; i++) {
+ checkCase(mismatchIdx, latinStr1, latinStr2, "LL"); // compare Latin1 with Latin1
+
+ checkCase(mismatchIdx, utfStr1, utfStr2, "UU"); // compare UTF-16 vs UTF-16
+
+ if (size != mismatchIdx) { // UTF-16 and Latin1 strings can't be equal. Then skip this case
+ // compare UTF16 string, which is expected to be > than Latin1
+ checkCase(mismatchIdx, latinStr1, utfStr1, "U(large)L");
+ if (mismatchIdx != size - 1) {
+ // compare UTF16 string, which is expected to be < than Latin1
+ checkCase(mismatchIdx, latinStr1, utfStr3, "U(small)L");
+ }
+ }
+ }
+ }
+
+ private void checkCase(int mismatchIdx, String str1, String str2, String caseName) {
+ int expected;
+ if (mismatchIdx != size) {
+ expected = str1.charAt(mismatchIdx) - str2.charAt(mismatchIdx);
+ } else {
+ expected = str1.length() - str2.length();
+ }
+ int result = str1.compareTo(str2);
+ int reversedResult = str2.compareTo(str1);
+ if (expected != result || result != -reversedResult) {
+ throw new AssertionError(String.format("%s CASE FAILED: size = %d, "
+ + "mismatchIdx = %d, expected = %d, but got result = %d, "
+ + "reversedResult = %d for string1 = '%s', string2 = '%s'",
+ caseName, size, mismatchIdx, expected, result,
+ reversedResult, str1, str2));
+ }
+ }
+}
+
--- a/test/hotspot/jtreg/containers/docker/TestCPUSets.java Fri May 17 13:21:44 2019 +0100
+++ b/test/hotspot/jtreg/containers/docker/TestCPUSets.java Thu May 23 11:07:37 2019 +0100
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2017, 2019, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -44,7 +44,7 @@
import jdk.test.lib.Platform;
import jdk.test.lib.Utils;
import jdk.test.lib.process.OutputAnalyzer;
-
+import jtreg.SkippedException;
public class TestCPUSets {
private static final String imageName = Common.imageName("cpusets");
@@ -54,6 +54,7 @@
return;
}
+
Common.prepareWhiteBox();
DockerTestUtils.buildJdkDockerImage(imageName, "Dockerfile-BasicTest", "jdk-docker");
@@ -72,22 +73,48 @@
String cpuSetStr = CPUSetsReader.readFromProcStatus(setType);
if (cpuSetStr == null) {
- System.out.printf("The %s test is skipped %n", setType);
- } else {
- List<Integer> cpuSet = CPUSetsReader.parseCpuSet(cpuSetStr);
+ String msg = String.format("The %s test is skipped: cpuSetStr is null %n", setType);
+ throw new SkippedException(msg);
+ }
+
+ List<Integer> cpuSet = CPUSetsReader.parseCpuSet(cpuSetStr);
+ int availableProcessors = Runtime.getRuntime().availableProcessors();
+
+ // print diagnostic info
+ printSet(setType, cpuSet);
+ log("getNumCpus(): " + CPUSetsReader.getNumCpus());
+ log("Runtime.getRuntime().availableProcessors(): " + availableProcessors);
+
+ int maxSetSize = Math.min(cpuSet.size(), availableProcessors);
+ log("maxSetSize = " + maxSetSize);
- // Test subset of one, full subset, and half of the subset
- testCpuSet(CPUSetsReader.listToString(cpuSet, 1));
- if (cpuSet.size() > 1) {
- testCpuSet(CPUSetsReader.listToString(cpuSet));
- }
- if (cpuSet.size() > 2) {
- testCpuSet(CPUSetsReader.listToString(cpuSet, cpuSet.size()/2 ));
- }
+ // Test subset of one, full set, and half of the set
+ testCpuSet(CPUSetsReader.listToString(cpuSet, 1));
+ if (maxSetSize >= 2) {
+ String cpuSetParam = CPUSetsReader.listToString(cpuSet, maxSetSize);
+ log("Testing with cpuSetParam = " + cpuSetParam);
+ testCpuSet(cpuSetParam);
+ }
+ if (maxSetSize >= 4) {
+ String cpuSetParam = CPUSetsReader.listToString(cpuSet, maxSetSize/2);
+ log("Testing with cpuSetParam = " + cpuSetParam);
+ testCpuSet(cpuSetParam);
}
}
+ private static void printSet(String setType, List<Integer> set) {
+ System.out.print("printSet(): " + setType + ": ");
+ set.forEach( i -> System.out.print(i + ", "));
+ System.out.println("");
+ }
+
+
+ private static void log(String msg) {
+ System.out.println(msg);
+ }
+
+
private static DockerRunOptions commonOpts() {
DockerRunOptions opts = new DockerRunOptions(imageName, "/jdk/bin/java",
"PrintContainerInfo");
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/gc/z/TestHighUsage.java Thu May 23 11:07:37 2019 +0100
@@ -0,0 +1,102 @@
+/*
+ * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package gc.z;
+
+/*
+ * @test TestHighUsage
+ * @requires vm.gc.Z & !vm.graal.enabled
+ * @summary Test ZGC "High Usage" rule
+ * @library /test/lib
+ * @run main/othervm gc.z.TestHighUsage
+ */
+
+import java.util.LinkedList;
+import jdk.test.lib.process.ProcessTools;
+
+public class TestHighUsage {
+ static class Test {
+ private static final int K = 1024;
+ private static final int M = K * K;
+ private static final long startAt = 16 * M;
+ private static final long spikeAt = 4 * M;
+ private static volatile LinkedList<byte[]> keepAlive;
+ private static volatile Object dummy;
+
+ public static void main(String[] args) throws Exception {
+ System.out.println("Allocating live-set");
+
+ // Allocate live-set
+ keepAlive = new LinkedList<>();
+ while (Runtime.getRuntime().freeMemory() > startAt) {
+ while (Runtime.getRuntime().freeMemory() > startAt) {
+ keepAlive.add(new byte[128 * K]);
+ }
+
+ // Compact live-set and let allocation rate settle down
+ System.gc();
+ Thread.sleep(2000);
+ }
+
+ System.out.println("Allocating garbage slowly");
+
+ // Allocate garbage slowly, such that the sampled allocation rate on
+ // average becomes zero MB/s for the last 1 second windows. If free
+ // memory goes below the spike limit we induce an allocation spike.
+ // The expected behavior is that the "High Usage" rule kicks in before
+ // the spike happens, avoiding an "Allocation Stall".
+ for (int i = 0; i < 300; i++) {
+ final long free = Runtime.getRuntime().freeMemory();
+ System.out.println("Free: " + (free / M) + "M");
+
+ if (free > spikeAt) {
+ // Low allocation rate
+ dummy = new byte[128 * K];
+ } else {
+ // High allocation rate
+ dummy = new byte[8 * M];
+ }
+
+ Thread.sleep(250);
+ }
+
+ System.out.println("Done");
+ }
+ }
+
+ public static void main(String[] args) throws Exception {
+ ProcessTools.executeTestJvm(new String[]{ "-XX:+UnlockExperimentalVMOptions",
+ "-XX:+UseZGC",
+ "-XX:+UnlockDiagnosticVMOptions",
+ "-XX:-ZProactive",
+ "-Xms128M",
+ "-Xmx128M",
+ "-XX:ParallelGCThreads=1",
+ "-XX:ConcGCThreads=1",
+ "-Xlog:gc",
+ Test.class.getName() })
+ .shouldNotContain("Allocation Stall")
+ .shouldContain("High Usage")
+ .shouldHaveExitValue(0);
+ }
+}
--- a/test/hotspot/jtreg/runtime/ErrorHandling/ErrorHandler.java Fri May 17 13:21:44 2019 +0100
+++ b/test/hotspot/jtreg/runtime/ErrorHandling/ErrorHandler.java Thu May 23 11:07:37 2019 +0100
@@ -66,7 +66,7 @@
String[] patterns = {
"(SIGILL|SIGSEGV|EXCEPTION_ACCESS_VIOLATION).* at pc=",
- "(SIGBUS|SIGSEGV|SIGILL|EXCEPTION_ACCESS_VIOLATION).* at pc="
+ // -XX:ErrorHandlerTest=13 is too unreliable. It sometimes fails to crash in the expected way.
// -XX:ErrorHandlerTest=14 is tested by SafeFetchInErrorHandlingTest.java
// -XX:ErrorHandlerTest=15 is tested by SecondaryErrorTest.java
// -XX:ErrorHandlerTest=16 is tested by ThreadsListHandleInErrorHandlingTest.java
--- a/test/hotspot/jtreg/runtime/appcds/AppendClasspath.java Fri May 17 13:21:44 2019 +0100
+++ b/test/hotspot/jtreg/runtime/appcds/AppendClasspath.java Thu May 23 11:07:37 2019 +0100
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2014, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2014, 2019, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -58,23 +58,26 @@
// FAIL: 2) runtime with classpath different from the one used in dump time
// (runtime has an extra jar file prepended to the class path)
TestCommon.run(
+ "-Xlog:cds",
"-cp", appJar2 + File.pathSeparator + appJar,
"HelloMore")
- .assertAbnormalExit(errorMessage1, errorMessage2);
+ .assertAbnormalExit(errorMessage1, errorMessage2);
// FAIL: 3) runtime with classpath part of the one used in dump time
TestCommon.testDump(appJar + File.pathSeparator + appJar2,
TestCommon.list("Hello"));
TestCommon.run(
+ "-Xlog:cds",
"-cp", appJar2,
"Hello")
- .assertAbnormalExit(errorMessage1, errorMessage2);
+ .assertAbnormalExit(errorMessage1, errorMessage2);
// FAIL: 4) runtime with same set of jar files in the classpath but
// with different order
TestCommon.run(
+ "-Xlog:cds",
"-cp", appJar2 + File.pathSeparator + appJar,
"HelloMore")
- .assertAbnormalExit(errorMessage1, errorMessage2);
+ .assertAbnormalExit(errorMessage1, errorMessage2);
}
}
--- a/test/hotspot/jtreg/runtime/appcds/BootClassPathMismatch.java Fri May 17 13:21:44 2019 +0100
+++ b/test/hotspot/jtreg/runtime/appcds/BootClassPathMismatch.java Thu May 23 11:07:37 2019 +0100
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2014, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2014, 2019, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -55,7 +55,11 @@
test.testBootClassPathMismatch();
test.testBootClassPathMismatchWithAppClass();
test.testBootClassPathMismatchWithBadPath();
- test.testBootClassPathMatchWithAppend();
+ if (!TestCommon.isDynamicArchive()) {
+ // this test is not applicable to dynamic archive since
+ // there is no class to be archived in the top archive
+ test.testBootClassPathMatchWithAppend();
+ }
test.testBootClassPathMatch();
}
@@ -77,11 +81,13 @@
TestCommon.dump(appJar, appClasses, "-Xbootclasspath/a:" + appJar);
TestCommon.run(
+ "-Xlog:cds",
"-cp", appJar, "-Xbootclasspath/a:" + otherJar, "Hello")
.assertAbnormalExit(mismatchMessage);
TestCommon.dump(appJar, appClasses, "-Xbootclasspath/a:" + otherJar);
TestCommon.run(
+ "-Xlog:cds",
"-cp", appJar, "-Xbootclasspath/a:" + appJar, "Hello")
.assertAbnormalExit(mismatchMessage);
}
@@ -100,6 +106,7 @@
TestCommon.dump(appJar, appClasses, "-Xbootclasspath/a:" + appJar);
TestCommon.run(
+ "-Xlog:cds",
"-cp", appJar, "-Xbootclasspath/a:" + otherJar, "Hello")
.assertAbnormalExit(mismatchMessage);
}
@@ -148,6 +155,7 @@
String appClasses[] = {"Hello"};
TestCommon.dump(appJar, appClasses);
TestCommon.run(
+ "-Xlog:cds",
"-cp", appJar, "-Xbootclasspath/a:" + appJar, "Hello")
.assertAbnormalExit(mismatchMessage);
}
--- a/test/hotspot/jtreg/runtime/appcds/CDSandJFR.java Fri May 17 13:21:44 2019 +0100
+++ b/test/hotspot/jtreg/runtime/appcds/CDSandJFR.java Thu May 23 11:07:37 2019 +0100
@@ -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
@@ -30,7 +30,7 @@
* @modules jdk.jfr
* @build Hello GetFlightRecorder
* @run driver ClassFileInstaller -jar CDSandJFR.jar Hello GetFlightRecorder GetFlightRecorder$TestEvent GetFlightRecorder$SimpleEvent
- * @run driver/timeout=500 CDSandJFR
+ * @run main/othervm/timeout=500 CDSandJFR
*/
import jdk.test.lib.BuildHelper;
--- a/test/hotspot/jtreg/runtime/appcds/CaseSensitiveClassPath.java Fri May 17 13:21:44 2019 +0100
+++ b/test/hotspot/jtreg/runtime/appcds/CaseSensitiveClassPath.java Thu May 23 11:07:37 2019 +0100
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2016, 2019, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -78,8 +78,7 @@
}
boolean isSameFile = Files.isSameFile(jarPath, jarPathUpper);
- TestCommon.run("-cp", appJarUpper, "Hello", "-Xlog:class+path=info",
- "-Xlog:cds")
+ TestCommon.run("-Xlog:class+path=info,cds", "-cp", appJarUpper, "Hello")
.ifNoMappingFailure(output -> {
if (isSameFile) {
output.shouldContain("Hello World");
--- a/test/hotspot/jtreg/runtime/appcds/CommandLineFlagCombo.java Fri May 17 13:21:44 2019 +0100
+++ b/test/hotspot/jtreg/runtime/appcds/CommandLineFlagCombo.java Thu May 23 11:07:37 2019 +0100
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2014, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2014, 2019, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -72,10 +72,22 @@
continue;
OutputAnalyzer dumpOutput = TestCommon.dump(appJar, classList, testEntry);
- TestCommon.checkDump(dumpOutput, "Loading classes to share");
+ if (!TestCommon.isDynamicArchive()) {
+ TestCommon.checkDump(dumpOutput, "Loading classes to share");
+ } else {
+ if (testEntry.contains("ObjectAlignmentInBytes")) {
+ dumpOutput.shouldHaveExitValue(1)
+ .shouldMatch("The shared archive file's ObjectAlignmentInBytes of .* does not equal the current ObjectAlignmentInBytes of");
+ } else {
+ TestCommon.checkDump(dumpOutput, "Loading classes to share");
+ }
+ }
- OutputAnalyzer execOutput = TestCommon.exec(appJar, testEntry, "Hello");
- TestCommon.checkExec(execOutput, "Hello World");
+ if ((TestCommon.isDynamicArchive() && !testEntry.contains("ObjectAlignmentInBytes")) ||
+ !TestCommon.isDynamicArchive()) {
+ OutputAnalyzer execOutput = TestCommon.exec(appJar, testEntry, "Hello");
+ TestCommon.checkExec(execOutput, "Hello World");
+ }
}
for (int i=0; i<2; i++) {
--- a/test/hotspot/jtreg/runtime/appcds/CommandLineFlagComboNegative.java Fri May 17 13:21:44 2019 +0100
+++ b/test/hotspot/jtreg/runtime/appcds/CommandLineFlagComboNegative.java Thu May 23 11:07:37 2019 +0100
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2014, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2014, 2019, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -65,8 +65,10 @@
if (Platform.is64bit()) {
testTable.add( new TestVector("-XX:ObjectAlignmentInBytes=8", "-XX:ObjectAlignmentInBytes=16",
"An error has occurred while processing the shared archive file", 1) );
- testTable.add( new TestVector("-XX:ObjectAlignmentInBytes=64", "-XX:ObjectAlignmentInBytes=32",
- "An error has occurred while processing the shared archive file", 1) );
+ if (!TestCommon.isDynamicArchive()) {
+ testTable.add( new TestVector("-XX:ObjectAlignmentInBytes=64", "-XX:ObjectAlignmentInBytes=32",
+ "An error has occurred while processing the shared archive file", 1) );
+ }
testTable.add( new TestVector("-XX:+UseCompressedOops", "-XX:-UseCompressedOops",
"Class data sharing is inconsistent with other specified options", 1) );
testTable.add( new TestVector("-XX:+UseCompressedClassPointers", "-XX:-UseCompressedClassPointers",
--- a/test/hotspot/jtreg/runtime/appcds/DirClasspathTest.java Fri May 17 13:21:44 2019 +0100
+++ b/test/hotspot/jtreg/runtime/appcds/DirClasspathTest.java Thu May 23 11:07:37 2019 +0100
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2017, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2017, 2019, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -27,7 +27,9 @@
* @summary Handling of directories in -cp is based on the classlist
* @requires vm.cds
* @library /test/lib
+ * @modules jdk.jartool/sun.tools.jar
* @compile test-classes/Hello.java
+ * @compile test-classes/Super.java
* @run driver DirClasspathTest
*/
@@ -42,11 +44,19 @@
public class DirClasspathTest {
private static final int MAX_PATH = 260;
+ // We add helloJar into the classpath to be compatible with TestCommon.DYNAMIC_DUMP
+ static OutputAnalyzer doDump(String path, String classList[],
+ String... suffix) throws Exception {
+ String helloJar = JarBuilder.getOrCreateHelloJar();
+ return TestCommon.dump(helloJar + File.pathSeparator + path, classList, suffix);
+ }
+
public static void main(String[] args) throws Exception {
File dir = new File(System.getProperty("user.dir"));
File emptydir = new File(dir, "emptydir");
emptydir.mkdir();
+
/////////////////////////////////////////////////////////////////
// The classlist only contains boot class in following test cases
/////////////////////////////////////////////////////////////////
@@ -54,7 +64,7 @@
// Empty dir in -cp: should be OK
OutputAnalyzer output;
- output = TestCommon.dump(emptydir.getPath(), bootClassList, "-Xlog:class+path=info");
+ output = doDump(emptydir.getPath(), bootClassList, "-Xlog:class+path=info");
TestCommon.checkDump(output);
// Long path to empty dir in -cp: should be OK
@@ -71,17 +81,17 @@
longDir.mkdir();
File subDir = new File(longDir, "subdir");
subDir.mkdir();
- output = TestCommon.dump(subDir.getPath(), bootClassList, "-Xlog:class+path=info");
+ output = doDump(subDir.getPath(), bootClassList, "-Xlog:class+path=info");
TestCommon.checkDump(output);
// Non-empty dir in -cp: should be OK
// <dir> is not empty because it has at least one subdirectory, i.e., <emptydir>
- output = TestCommon.dump(dir.getPath(), bootClassList, "-Xlog:class+path=info");
+ output = doDump(dir.getPath(), bootClassList, "-Xlog:class+path=info");
TestCommon.checkDump(output);
// Long path to non-empty dir in -cp: should be OK
// <dir> is not empty because it has at least one subdirectory, i.e., <emptydir>
- output = TestCommon.dump(longDir.getPath(), bootClassList, "-Xlog:class+path=info");
+ output = doDump(longDir.getPath(), bootClassList, "-Xlog:class+path=info");
TestCommon.checkDump(output);
/////////////////////////////////////////////////////////////////
@@ -90,27 +100,27 @@
String appClassList[] = {"java/lang/Object", "com/sun/tools/javac/Main"};
// Non-empty dir in -cp: should be OK (as long as no classes were loaded from there)
- output = TestCommon.dump(dir.getPath(), appClassList, "-Xlog:class+path=info");
+ output = doDump(dir.getPath(), appClassList, "-Xlog:class+path=info");
TestCommon.checkDump(output);
// Long path to non-empty dir in -cp: should be OK (as long as no classes were loaded from there)
- output = TestCommon.dump(longDir.getPath(), appClassList, "-Xlog:class+path=info");
+ output = doDump(longDir.getPath(), appClassList, "-Xlog:class+path=info");
TestCommon.checkDump(output);
/////////////////////////////////////////////////////////////////
// Loading an app class from a directory
/////////////////////////////////////////////////////////////////
- String appClassList2[] = {"Hello", "java/lang/Object", "com/sun/tools/javac/Main"};
+ String appClassList2[] = {"Super", "java/lang/Object", "com/sun/tools/javac/Main"};
// Non-empty dir in -cp: should report error if a class is loaded from it
- output = TestCommon.dump(classDir.toString(), appClassList2, "-Xlog:class+path=info");
+ output = doDump(classDir.toString(), appClassList2, "-Xlog:class+path=info,class+load=trace");
output.shouldNotHaveExitValue(0);
output.shouldContain("Cannot have non-empty directory in paths");
// Long path to non-empty dir in -cp: should report error if a class is loaded from it
- File srcClass = new File(classDir.toFile(), "Hello.class");
- File destClass = new File(longDir, "Hello.class");
+ File srcClass = new File(classDir.toFile(), "Super.class");
+ File destClass = new File(longDir, "Super.class");
Files.copy(srcClass.toPath(), destClass.toPath());
- output = TestCommon.dump(longDir.getPath(), appClassList2, "-Xlog:class+path=info");
+ output = doDump(longDir.getPath(), appClassList2, "-Xlog:class+path=info");
output.shouldNotHaveExitValue(0);
output.shouldContain("Cannot have non-empty directory in paths");
}
--- a/test/hotspot/jtreg/runtime/appcds/JvmtiAddPath.java Fri May 17 13:21:44 2019 +0100
+++ b/test/hotspot/jtreg/runtime/appcds/JvmtiAddPath.java Thu May 23 11:07:37 2019 +0100
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2014, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2014, 2019, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -84,7 +84,9 @@
run(check_appcds_enabled, appJar, "-Xlog:class+load", "JvmtiApp", "noadd"); // appcds should be enabled
System.out.println("Test case 2: add to boot classpath only - should find Hello.class in boot loader");
- run(check_appcds_disabled, appJar, "-Xlog:class+load", "JvmtiApp", "bootonly", addbootJar); // appcds should be disabled
+ String[] toCheck = (TestCommon.isDynamicArchive()) ? check_appcds_enabled
+ : check_appcds_disabled;
+ run(toCheck, appJar, "-Xlog:class+load", "JvmtiApp", "bootonly", addbootJar); // appcds should be disabled
System.out.println("Test case 3: add to app classpath only - should find Hello.class in app loader");
run(appJar, "JvmtiApp", "apponly", addappJar);
@@ -97,7 +99,11 @@
System.out.println("Test case 6: add to app using AppCDS, but add to boot using JVMTI - should find Hello.class in boot loader");
TestCommon.testDump(twoAppJars, TestCommon.list("JvmtiApp", "ExtraClass", "Hello"), use_whitebox_jar);
- run(twoAppJars, "JvmtiApp", "bootonly", addappJar);
+ if (!TestCommon.isDynamicArchive()) {
+ // skip for dynamic archive, the Hello class will be loaded from
+ // the dynamic archive
+ run(twoAppJars, "JvmtiApp", "bootonly", addappJar);
+ }
System.out.println("Test case 7: add to app using AppCDS, no JVMTI calls - should find Hello.class in app loader");
run(twoAppJars, "JvmtiApp", "noadd-appcds");
--- a/test/hotspot/jtreg/runtime/appcds/LotsOfClasses.java Fri May 17 13:21:44 2019 +0100
+++ b/test/hotspot/jtreg/runtime/appcds/LotsOfClasses.java Thu May 23 11:07:37 2019 +0100
@@ -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
@@ -22,15 +22,7 @@
*
*/
-import java.net.URI;
-import java.nio.file.DirectoryStream;
-import java.nio.file.Files;
-import java.nio.file.FileSystem;
-import java.nio.file.FileSystems;
-import java.nio.file.Path;
import java.util.ArrayList;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
import jdk.test.lib.cds.CDSTestUtils;
import jdk.test.lib.cds.CDSOptions;
@@ -41,16 +33,15 @@
* @summary Try to archive lots of classes by searching for classes from the jrt:/ file system. With JDK 12
* this will produce an archive with over 30,000 classes.
* @requires vm.cds
- * @library /test/lib
+ * @library /test/lib /test/hotspot/jtreg/runtime/appcds
* @run driver/timeout=500 LotsOfClasses
*/
public class LotsOfClasses {
- static Pattern pattern;
public static void main(String[] args) throws Throwable {
ArrayList<String> list = new ArrayList<>();
- findAllClasses(list);
+ TestCommon.findAllClasses(list);
CDSOptions opts = new CDSOptions();
opts.setClassList(list);
@@ -64,28 +55,4 @@
OutputAnalyzer out = CDSTestUtils.createArchive(opts);
CDSTestUtils.checkDump(out);
}
-
- static void findAllClasses(ArrayList<String> list) throws Throwable {
- // Find all the classes in the jrt file system
- pattern = Pattern.compile("/modules/[a-z.]*[a-z]+/([^-]*)[.]class");
- FileSystem fs = FileSystems.getFileSystem(URI.create("jrt:/"));
- Path base = fs.getPath("/modules/");
- find(base, list);
- }
-
- static void find(Path p, ArrayList<String> list) throws Throwable {
- try (DirectoryStream<Path> stream = Files.newDirectoryStream(p)) {
- for (Path entry: stream) {
- Matcher matcher = pattern.matcher(entry.toString());
- if (matcher.find()) {
- String className = matcher.group(1);
- list.add(className);
- //System.out.println(className);
- }
- try {
- find(entry, list);
- } catch (Throwable t) {}
- }
- }
- }
}
--- a/test/hotspot/jtreg/runtime/appcds/PackageSealing.java Fri May 17 13:21:44 2019 +0100
+++ b/test/hotspot/jtreg/runtime/appcds/PackageSealing.java Thu May 23 11:07:37 2019 +0100
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2014, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2014, 2019, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -27,14 +27,15 @@
* @summary AppCDS handling of package.
* @requires vm.cds
* @library /test/lib
- * @modules java.base/jdk.internal.misc
- * java.management
+ * @modules jdk.jartool/sun.tools.jar
* @compile test-classes/C1.java
* @compile test-classes/C2.java
* @compile test-classes/PackageSealingTest.java
+ * @compile test-classes/Hello.java
* @run driver PackageSealing
*/
+import java.io.File;
import jdk.test.lib.process.OutputAnalyzer;
public class PackageSealing {
@@ -44,16 +45,19 @@
ClassFileInstaller.Manifest.fromSourceFile("test-classes/package_seal.mf"),
"PackageSealingTest", "sealed/pkg/C1", "pkg/C2");
+ String helloJar = JarBuilder.getOrCreateHelloJar();
+ String jars = helloJar + File.pathSeparator + appJar;
+
// test shared package from -cp path
- TestCommon.testDump(appJar, TestCommon.list(classList));
+ TestCommon.testDump(jars, TestCommon.list(classList));
OutputAnalyzer output;
- output = TestCommon.exec(appJar, "PackageSealingTest");
+ output = TestCommon.exec(jars, "PackageSealingTest");
TestCommon.checkExec(output, "OK");
// test shared package from -Xbootclasspath/a
- TestCommon.dump(appJar, TestCommon.list(classList),
+ TestCommon.dump(helloJar, TestCommon.list(classList),
"-Xbootclasspath/a:" + appJar);
- output = TestCommon.exec(appJar, "-Xbootclasspath/a:" + appJar, "PackageSealingTest");
+ output = TestCommon.exec(helloJar, "-Xbootclasspath/a:" + appJar, "PackageSealingTest");
TestCommon.checkExec(output, "OK");
}
}
--- a/test/hotspot/jtreg/runtime/appcds/ProhibitedPackage.java Fri May 17 13:21:44 2019 +0100
+++ b/test/hotspot/jtreg/runtime/appcds/ProhibitedPackage.java Thu May 23 11:07:37 2019 +0100
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2014, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2014, 2019, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -27,9 +27,7 @@
* @summary AppCDS handling of prohibited package.
* @requires vm.cds
* @library /test/lib
- * @modules java.base/jdk.internal.misc
- * java.management
- * jdk.jartool/sun.tools.jar
+ * @modules jdk.jartool/sun.tools.jar
* @compile test-classes/ProhibitedHelper.java test-classes/Prohibited.jasm
* @run driver ProhibitedPackage
*/
@@ -46,7 +44,8 @@
String appJar = TestCommon.getTestJar("prohibited_pkg.jar");
// Test support for customer loaders
- if (Platform.areCustomLoadersSupportedForCDS()) {
+ if (Platform.areCustomLoadersSupportedForCDS() &&
+ !TestCommon.isDynamicArchive()) {
String classlist[] = new String[] {
"java/lang/Object id: 1",
"java/lang/Prohibited id: 2 super: 1 source: " + appJar
--- a/test/hotspot/jtreg/runtime/appcds/SharedArchiveConsistency.java Fri May 17 13:21:44 2019 +0100
+++ b/test/hotspot/jtreg/runtime/appcds/SharedArchiveConsistency.java Thu May 23 11:07:37 2019 +0100
@@ -71,7 +71,18 @@
public static File jsa; // will be updated during test
public static File orgJsaFile; // kept the original file not touched.
- public static String[] shared_region_name = {"MiscCode", "ReadWrite", "ReadOnly", "MiscData"};
+ // The following should be consistent with the enum in the C++ MetaspaceShared class
+ public static String[] shared_region_name = {
+ "mc", // MiscCode
+ "rw", // ReadWrite
+ "ro", // ReadOnly
+ "md", // MiscData
+ "first_closed_archive",
+ "last_closed_archive",
+ "first_open_archive",
+ "last_open_archive"
+ };
+
public static int num_regions = shared_region_name.length;
public static String[] matchMessages = {
"Unable to use shared archive",
@@ -102,10 +113,11 @@
return file_header_size;
}
// this is not real header size, it is struct size
+ int int_size = wb.getOffsetForName("int_size");
file_header_size = wb.getOffsetForName("file_header_size");
int offset_path_misc_info = wb.getOffsetForName("FileMapHeader::_paths_misc_info_size") -
offset_magic;
- int path_misc_info_size = (int)readInt(fc, offset_path_misc_info, size_t_size);
+ int path_misc_info_size = (int)readInt(fc, offset_path_misc_info, int_size);
file_header_size += path_misc_info_size; //readInt(fc, offset_path_misc_info, size_t_size);
System.out.println("offset_path_misc_info = " + offset_path_misc_info);
System.out.println("path_misc_info_size = " + path_misc_info_size);
@@ -157,25 +169,26 @@
public static void modifyJsaContentRandomly() throws Exception {
FileChannel fc = getFileChannel();
- // corrupt random area in the data areas (MiscCode, ReadWrite, ReadOnly, MiscData)
+ // corrupt random area in the data areas
long[] used = new long[num_regions]; // record used bytes
long start0, start, end, off;
int used_offset, path_info_size;
int bufSize;
- System.out.printf("%-12s%-12s%-12s%-12s%-12s\n", "Space Name", "Offset", "Used bytes", "Reg Start", "Random Offset");
+ System.out.printf("%-24s%12s%12s%16s\n", "Space Name", "Used bytes", "Reg Start", "Random Offset");
start0 = getFileHeaderSize(fc);
for (int i = 0; i < num_regions; i++) {
- used_offset = sp_offset + CDSFileMapRegion_size * i + sp_used_offset;
- // read 'used'
- used[i] = readInt(fc, used_offset, size_t_size);
+ used[i] = get_region_used_size_aligned(fc, i);
start = start0;
for (int j = 0; j < i; j++) {
start += align_up_page(used[j]);
}
end = start + used[i];
+ if (start == end) {
+ continue; // Ignore empty regions
+ }
off = getRandomBetween(start, end);
- System.out.printf("%-12s%-12d%-12d%-12d%-12d\n", shared_region_name[i], used_offset, used[i], start, off);
+ System.out.printf("%-24s%12d%12d%16d\n", shared_region_name[i], used[i], start, off);
if (end - off < 1024) {
bufSize = (int)(end - off + 1);
} else {
@@ -189,34 +202,50 @@
}
}
- public static void modifyJsaContent() throws Exception {
+ static long get_region_used_size_aligned(FileChannel fc, int region) throws Exception {
+ long n = sp_offset + CDSFileMapRegion_size * region + sp_used_offset;
+ long alignment = WhiteBox.getWhiteBox().metaspaceReserveAlignment();
+ long used = readInt(fc, n, size_t_size);
+ used = (used + alignment - 1) & ~(alignment - 1);
+ return used;
+ }
+
+ public static boolean modifyJsaContent(int region) throws Exception {
FileChannel fc = getFileChannel();
byte[] buf = new byte[4096];
ByteBuffer bbuf = ByteBuffer.wrap(buf);
long total = 0L;
- long used_offset = 0L;
long[] used = new long[num_regions];
- System.out.printf("%-12s%-12s\n", "Space name", "Used bytes");
+ System.out.printf("%-24s%12s\n", "Space name", "Used bytes");
for (int i = 0; i < num_regions; i++) {
- used_offset = sp_offset + CDSFileMapRegion_size* i + sp_used_offset;
- // read 'used'
- used[i] = readInt(fc, used_offset, size_t_size);
- System.out.printf("%-12s%-12d\n", shared_region_name[i], used[i]);
+ used[i] = get_region_used_size_aligned(fc, i);
+ System.out.printf("%-24s%12d\n", shared_region_name[i], used[i]);
total += used[i];
}
- System.out.printf("%-12s%-12d\n", "Total: ", total);
- long corrupt_used_offset = getFileHeaderSize(fc);
- System.out.println("Corrupt RO section, offset = " + corrupt_used_offset);
- while (used_offset < used[0]) {
- writeData(fc, corrupt_used_offset, bbuf);
+ System.out.printf("%-24s%12d\n", "Total: ", total);
+ long header_size = getFileHeaderSize(fc);
+ long region_start_offset = header_size;
+ for (int i=0; i<region; i++) {
+ region_start_offset += used[i];
+ }
+ if (used[region] == 0) {
+ System.out.println("Region " + shared_region_name[region] + " is empty. Nothing to corrupt.");
+ return false;
+ }
+ System.out.println("Corrupt " + shared_region_name[region] + " section, start = " + region_start_offset
+ + " (header_size + 0x" + Long.toHexString(region_start_offset-header_size) + ")");
+ long bytes_written = 0L;
+ while (bytes_written < used[region]) {
+ writeData(fc, region_start_offset + bytes_written, bbuf);
bbuf.clear();
- used_offset += 4096;
+ bytes_written += 4096;
}
fc.force(true);
if (fc.isOpen()) {
fc.close();
}
+ return true;
}
public static void modifyJsaHeader() throws Exception {
@@ -299,11 +328,11 @@
// read the jsa file
// 1) run normal
// 2) modify header
- // 3) keep header correct but modify content
+ // 3) keep header correct but modify content in each region specified by shared_region_name[]
// 4) update both header and content, test
// 5) delete bytes in data begining
// 6) insert bytes in data begining
- // 7) randomly corrupt data in four areas: RO, RW. MISC DATA, MISC CODE
+ // 7) randomly corrupt data in each region specified by shared_region_name[]
public static void main(String... args) throws Exception {
// must call to get offset info first!!!
getFileOffsetInfo();
@@ -352,18 +381,23 @@
output.shouldContain("The shared archive file has the wrong version");
output.shouldNotContain("Checksum verification failed");
+ File newJsaFile = null;
// modify content
System.out.println("\n3. Corrupt Content, should fail\n");
-
- copyFile(orgJsaFile, jsa);
- modifyJsaContent();
- testAndCheck(verifyExecArgs);
+ for (int i=0; i<num_regions; i++) {
+ newJsaFile = new File(TestCommon.getNewArchiveName(shared_region_name[i]));
+ copyFile(orgJsaFile, newJsaFile);
+ if (modifyJsaContent(i)) {
+ testAndCheck(execArgs);
+ }
+ }
// modify both header and content, test should fail
System.out.println("\n4. Corrupt Header and Content, should fail\n");
- copyFile(orgJsaFile, jsa);
+ newJsaFile = new File(TestCommon.getNewArchiveName("header-and-content"));
+ copyFile(orgJsaFile, newJsaFile);
modifyJsaHeader();
- modifyJsaContent(); // this will not be reached since failed on header change first
+ modifyJsaContent(0); // this will not be reached since failed on header change first
output = TestCommon.execCommon(execArgs);
output.shouldContain("The shared archive file has the wrong version");
output.shouldNotContain("Checksum verification failed");
@@ -379,7 +413,8 @@
testAndCheck(verifyExecArgs);
System.out.println("\n7. modify Content in random areas, should fail\n");
- copyFile(orgJsaFile, jsa);
+ newJsaFile = new File(TestCommon.getNewArchiveName("random-areas"));
+ copyFile(orgJsaFile, newJsaFile);
modifyJsaContentRandomly();
testAndCheck(verifyExecArgs);
}
--- a/test/hotspot/jtreg/runtime/appcds/TestCommon.java Fri May 17 13:21:44 2019 +0100
+++ b/test/hotspot/jtreg/runtime/appcds/TestCommon.java Thu May 23 11:07:37 2019 +0100
@@ -32,10 +32,28 @@
import jdk.test.lib.process.ProcessTools;
import jdk.test.lib.process.OutputAnalyzer;
import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.InputStream;
+import java.net.URI;
+import java.nio.file.DirectoryStream;
+import java.nio.file.Files;
+import java.nio.file.FileSystem;
+import java.nio.file.FileSystems;
+import java.nio.file.Path;
import java.text.SimpleDateFormat;
import java.util.Arrays;
import java.util.ArrayList;
import java.util.Date;
+import java.util.Enumeration;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipFile;
+import java.util.zip.ZipOutputStream;
+import jtreg.SkippedException;
+import cdsutils.DynamicDumpHelper;
+
/**
* This is a test utility class for common AppCDS test functionality.
@@ -51,7 +69,7 @@
*/
public class TestCommon extends CDSTestUtils {
private static final String JSA_FILE_PREFIX = System.getProperty("user.dir") +
- File.separator + "appcds-";
+ File.separator;
private static final SimpleDateFormat timeStampFormat =
new SimpleDateFormat("HH'h'mm'm'ss's'SSS");
@@ -64,8 +82,7 @@
// Call this method to start new archive with new unique name
public static void startNewArchiveName() {
deletePriorArchives();
- currentArchiveName = JSA_FILE_PREFIX +
- timeStampFormat.format(new Date()) + ".jsa";
+ currentArchiveName = getNewArchiveName();
}
// Call this method to get current archive name
@@ -73,6 +90,18 @@
return currentArchiveName;
}
+ public static String getNewArchiveName() {
+ return getNewArchiveName(null);
+ }
+
+ public static String getNewArchiveName(String stem) {
+ if (stem == null) {
+ stem = "appcds";
+ }
+ return JSA_FILE_PREFIX + stem + "-" +
+ timeStampFormat.format(new Date()) + ".jsa";
+ }
+
// Attempt to clean old archives to preserve space
// Archives are large artifacts (20Mb or more), and much larger than
// most other artifacts created in jtreg testing.
@@ -92,7 +121,6 @@
}
}
-
// Create AppCDS archive using most common args - convenience method
// Legacy name preserved for compatibility
public static OutputAnalyzer dump(String appJar, String classList[],
@@ -110,10 +138,12 @@
return createArchive(opts);
}
+ // Simulate -Xshare:dump with -XX:ArchiveClassesAtExit. See comments around patchJarForDynamicDump()
+ private static final Class tmp = DynamicDumpHelper.class;
+
// Create AppCDS archive using appcds options
public static OutputAnalyzer createArchive(AppCDSOptions opts)
throws Exception {
-
ArrayList<String> cmd = new ArrayList<String>();
startNewArchiveName();
@@ -122,23 +152,73 @@
if (opts.appJar != null) {
cmd.add("-cp");
cmd.add(opts.appJar);
+ File jf = new File(opts.appJar);
+ if (DYNAMIC_DUMP && !jf.isDirectory()) {
+ patchJarForDynamicDump(opts.appJar);
+ }
} else {
cmd.add("-Djava.class.path=");
}
- cmd.add("-Xshare:dump");
-
- if (opts.archiveName == null)
+ if (opts.archiveName == null) {
opts.archiveName = getCurrentArchiveName();
-
- cmd.add("-XX:SharedArchiveFile=" + opts.archiveName);
-
- if (opts.classList != null) {
- File classListFile = makeClassList(opts.classList);
- cmd.add("-XX:ExtraSharedClassListFile=" + classListFile.getPath());
}
- for (String s : opts.suffix) cmd.add(s);
+ if (DYNAMIC_DUMP) {
+ cmd.add("-Xshare:on");
+ cmd.add("-XX:ArchiveClassesAtExit=" + opts.archiveName);
+
+ cmd.add("-Xlog:cds");
+ cmd.add("-Xlog:cds+dynamic");
+ boolean mainModuleSpecified = false;
+ boolean patchModuleSpecified = false;
+ for (String s : opts.suffix) {
+ if (s.length() == 0) {
+ continue;
+ }
+ if (s.equals("-m")) {
+ mainModuleSpecified = true;
+ }
+ if (s.startsWith("--patch-module=")) {
+ patchModuleSpecified = true;
+ }
+ cmd.add(s);
+ }
+
+ if (opts.appJar != null) {
+ // classlist is supported only when we have a Jar file to patch (to insert
+ // cdsutils.DynamicDumpHelper)
+ if (opts.classList == null) {
+ throw new RuntimeException("test.dynamic.dump requires classList file");
+ }
+
+ if (!mainModuleSpecified && !patchModuleSpecified) {
+ cmd.add("cdsutils.DynamicDumpHelper");
+ File classListFile = makeClassList(opts.classList);
+ cmd.add(classListFile.getPath());
+ }
+ } else {
+ if (!mainModuleSpecified && !patchModuleSpecified) {
+ // If you have an empty classpath, you cannot specify a classlist!
+ if (opts.classList != null && opts.classList.length > 0) {
+ throw new RuntimeException("test.dynamic.dump not supported empty classpath with non-empty classlist");
+ }
+ cmd.add("-version");
+ }
+ }
+ } else {
+ // static dump
+ cmd.add("-Xshare:dump");
+ cmd.add("-XX:SharedArchiveFile=" + opts.archiveName);
+
+ if (opts.classList != null) {
+ File classListFile = makeClassList(opts.classList);
+ cmd.add("-XX:ExtraSharedClassListFile=" + classListFile.getPath());
+ }
+ for (String s : opts.suffix) {
+ cmd.add(s);
+ }
+ }
String[] cmdLine = cmd.toArray(new String[cmd.size()]);
ProcessBuilder pb = ProcessTools.createJavaProcessBuilder(true, cmdLine);
@@ -154,6 +234,93 @@
// Some AppCDS tests are not compatible with this mode. See the group
// hotspot_appcds_with_jfr in ../../TEST.ROOT for details.
private static final boolean RUN_WITH_JFR = Boolean.getBoolean("test.cds.run.with.jfr");
+ // This method simulates -Xshare:dump with -XX:ArchiveClassesAtExit. This way, we
+ // can re-use many tests (outside of the ./dynamicArchive directory) for testing
+ // general features of JDK-8215311 (JEP 350: Dynamic CDS Archives).
+ //
+ // We insert the cdsutils/DynamicDumpHelper.class into the first Jar file in
+ // the classpath. We use this class to load all the classes specified in the classlist.
+ //
+ // There's no need to change the run-time command-line: in this special mode, two
+ // archives are involved. The command-line specifies only the top archive. However,
+ // the location of the base archive is recorded in the top archive, so it can be
+ // determined by the JVM at runtime start-up.
+ //
+ // To run in this special mode, specify the following in your jtreg command-line
+ // -Dtest.dynamic.cds.archive=true
+ //
+ // Note that some tests are not compatible with this special mode, including
+ // + Tests in ./dynamicArchive: these tests are specifically written for
+ // dynamic archive, and do not use TestCommon.createArchive(), which works
+ // together with patchJarForDynamicDump().
+ // + Tests related to cached objects and shared strings: dynamic dumping
+ // does not support these.
+ // + Custom loader tests: DynamicDumpHelper doesn't support the required
+ // classlist syntax. (FIXME).
+ // + Extra symbols and extra strings.
+ // See the hotspot_appcds_dynamic in ../../TEST.ROOT for details.
+ //
+ // To run all tests that are compatible with this mode:
+ // cd test/hotspot/jtreg
+ // jtreg -Dtest.dynamic.cds.archive=true :hotspot_appcds_dynamic
+ //
+ private static void patchJarForDynamicDump(String cp) throws Exception {
+ System.out.println("patchJarForDynamicDump: classpath = " + cp);
+ String firstJar = cp;
+ int n = firstJar.indexOf(File.pathSeparator);
+ if (n > 0) {
+ firstJar = firstJar.substring(0, n);
+ }
+ String classDir = System.getProperty("test.classes");
+ String expected1 = classDir + File.separator;
+ String expected2 = System.getProperty("user.dir") + File.separator;
+
+ if (!firstJar.startsWith(expected1) && !firstJar.startsWith(expected2)) {
+ throw new RuntimeException("FIXME: jar file not at a supported location ('"
+ + expected1 + "', or '" + expected2 + "'): " + firstJar);
+ }
+
+ String replaceJar = firstJar + ".tmp";
+ String patchClass = "cdsutils/DynamicDumpHelper.class";
+ ZipFile zipFile = new ZipFile(firstJar);
+ byte[] buf = new byte[1024];
+ int len;
+ if (zipFile.getEntry(patchClass) == null) {
+ FileOutputStream fout = new FileOutputStream(replaceJar);
+ final ZipOutputStream zos = new ZipOutputStream(fout);
+
+ zos.putNextEntry(new ZipEntry(patchClass));
+ InputStream is = new FileInputStream(classDir + File.separator + patchClass);
+ while ((len = (is.read(buf))) > 0) {
+ zos.write(buf, 0, len);
+ }
+ zos.closeEntry();
+ is.close();
+
+ for (Enumeration e = zipFile.entries(); e.hasMoreElements(); ) {
+ ZipEntry entryIn = (ZipEntry) e.nextElement();
+ zos.putNextEntry(entryIn);
+ is = zipFile.getInputStream(entryIn);
+ while ((len = is.read(buf)) > 0) {
+ zos.write(buf, 0, len);
+ }
+ zos.closeEntry();
+ is.close();
+ }
+
+ zos.close();
+ fout.close();
+ zipFile.close();
+
+ File oldFile = new File(firstJar);
+ File newFile = new File(replaceJar);
+ oldFile.delete();
+ newFile.renameTo(oldFile);
+ System.out.println("firstJar = " + firstJar + " Modified");
+ } else {
+ System.out.println("firstJar = " + firstJar);
+ }
+ }
// Execute JVM using AppCDS archive with specified AppCDSOptions
public static OutputAnalyzer runWithArchive(AppCDSOptions opts)
@@ -260,12 +427,18 @@
return runWithArchive(opts);
}
-
// A common operation: dump, then check results
public static OutputAnalyzer testDump(String appJar, String classList[],
String... suffix) throws Exception {
OutputAnalyzer output = dump(appJar, classList, suffix);
- output.shouldContain("Loading classes to share");
+ if (DYNAMIC_DUMP) {
+ if (isUnableToMap(output)) {
+ throw new SkippedException(UnableToMapMsg);
+ }
+ output.shouldContain("Written dynamic archive");
+ } else {
+ output.shouldContain("Loading classes to share");
+ }
output.shouldHaveExitValue(0);
return output;
}
@@ -301,7 +474,6 @@
return output;
}
-
// Convenience concatenation utils
public static String[] list(String ...args) {
return args;
@@ -336,6 +508,15 @@
return list.toArray(new String[list.size()]);
}
+ public static String[] concat(String prefix, String[] extra) {
+ ArrayList<String> list = new ArrayList<String>();
+ list.add(prefix);
+ for (String s : extra) {
+ list.add(s);
+ }
+
+ return list.toArray(new String[list.size()]);
+ }
// ===================== Concatenate paths
public static String concatPaths(String... paths) {
@@ -384,4 +565,29 @@
}
return true;
}
+
+ static Pattern pattern;
+
+ static void findAllClasses(ArrayList<String> list) throws Throwable {
+ // Find all the classes in the jrt file system
+ pattern = Pattern.compile("/modules/[a-z.]*[a-z]+/([^-]*)[.]class");
+ FileSystem fs = FileSystems.getFileSystem(URI.create("jrt:/"));
+ Path base = fs.getPath("/modules/");
+ findAllClassesAtPath(base, list);
+ }
+
+ private static void findAllClassesAtPath(Path p, ArrayList<String> list) throws Throwable {
+ try (DirectoryStream<Path> stream = Files.newDirectoryStream(p)) {
+ for (Path entry: stream) {
+ Matcher matcher = pattern.matcher(entry.toString());
+ if (matcher.find()) {
+ String className = matcher.group(1);
+ list.add(className);
+ }
+ try {
+ findAllClassesAtPath(entry, list);
+ } catch (Throwable t) {}
+ }
+ }
+ }
}
--- a/test/hotspot/jtreg/runtime/appcds/TraceLongClasspath.java Fri May 17 13:21:44 2019 +0100
+++ b/test/hotspot/jtreg/runtime/appcds/TraceLongClasspath.java Thu May 23 11:07:37 2019 +0100
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2014, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2014, 2019, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -31,6 +31,7 @@
* java.management
* jdk.jartool/sun.tools.jar
* @compile test-classes/Hello.java
+ * @compile test-classes/Super.java
* @run driver TraceLongClasspath
*/
@@ -43,8 +44,10 @@
public static void main(String[] args) throws Exception {
String appJar = JarBuilder.getOrCreateHelloJar();
+ String dummyJar = JarBuilder.build("dummy", "Super");
String longClassPath =
+ dummyJar + ps +
"/scratch/xxxx/yyyy/ZZZZZZ/aaaaaaaaaa/xx/abc/abc/modules/user-patch.jar" + ps +
"/scratch/xxxx/yyyy/ZZZZZZ/aaaaaaaaaa/xx/abc/abc/modules/abc-startup.jar" + ps +
"/scratch/xxxx/yyyy/ZZZZZZ/aaaaaaaaaa/xx/foobar_common/modules/features/com.foobar.db.jdbc7-dms.jar" + ps +
@@ -91,15 +94,15 @@
// Then try to execute the archive with a different classpath and with -XX:+TraceClassPaths.
// The diagnosis "expecting" app classpath trace should show the entire classpath.
TestCommon.run(
- "-XX:+TraceClassPaths",
+ "-XX:+TraceClassPaths", "-Xlog:cds",
"-cp", appJar,
"Hello")
- .assertAbnormalExit(output -> {
- output.shouldContain("Unable to use shared archive");
- output.shouldContain("shared class paths mismatch");
- // the "expecting" app classpath from -XX:+TraceClassPaths should not
- // be truncated
- output.shouldContain(myCP);
- });
+ .assertAbnormalExit(output -> {
+ output.shouldContain("Unable to use shared archive");
+ output.shouldContain("shared class paths mismatch");
+ // the "expecting" app classpath from -XX:+TraceClassPaths should not
+ // be truncated
+ output.shouldContain(myCP);
+ });
}
}
--- a/test/hotspot/jtreg/runtime/appcds/WrongClasspath.java Fri May 17 13:21:44 2019 +0100
+++ b/test/hotspot/jtreg/runtime/appcds/WrongClasspath.java Thu May 23 11:07:37 2019 +0100
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2014, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2014, 2019, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -47,8 +47,9 @@
// Then try to execute the archive without -classpath -- it should fail
TestCommon.run(
/* "-cp", appJar, */ // <- uncomment this and the execution should succeed
+ "-Xlog:cds",
"Hello")
- .assertAbnormalExit("Unable to use shared archive",
- "shared class paths mismatch");
+ .assertAbnormalExit("Unable to use shared archive",
+ "shared class paths mismatch");
}
}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/runtime/appcds/cdsutils/DynamicDumpHelper.java Thu May 23 11:07:37 2019 +0100
@@ -0,0 +1,61 @@
+/*
+ * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+package cdsutils;
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileReader;
+
+/**
+ * This class is used to simulate -Xshare:dump with -XX:ArchiveClassesAtExit.
+ * It loads all classes specified in a classlist file. See patchJarForDynamicDump()
+ * in ../TestCommon.java for details.
+ */
+public class DynamicDumpHelper {
+ public static void main(String args[]) throws Throwable {
+ File file = new File(args[0]);
+
+ System.out.println("Loading classes to share...");
+ try (BufferedReader br = new BufferedReader(new FileReader(file))) {
+ String line;
+ while ((line = br.readLine()) != null) {
+ //System.out.println("Loading class: " + line);
+ line = line.replace('/', '.');
+ try {
+ Class.forName(line);
+ } catch (java.lang.ClassNotFoundException ex) {
+ try {
+ Class.forName(line, true, null);
+ } catch (java.lang.ClassNotFoundException cnfe) {
+ System.out.println("Preload Warning: Cannot find " + line.replace('.', '/'));
+ }
+ } catch (Throwable t) {
+ System.out.println("Error: failed to load \"" + line + "\": " + t);
+ }
+ }
+ }
+ System.out.println("Loading classes to share: done.");
+ }
+}
--- a/test/hotspot/jtreg/runtime/appcds/customLoader/ClassListFormatA.java Fri May 17 13:21:44 2019 +0100
+++ b/test/hotspot/jtreg/runtime/appcds/customLoader/ClassListFormatA.java Thu May 23 11:07:37 2019 +0100
@@ -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
@@ -32,7 +32,7 @@
* @modules java.base/jdk.internal.misc
* java.management
* jdk.jartool/sun.tools.jar
- * @compile test-classes/Hello.java test-classes/CustomLoadee.java test-classes/CustomLoadee2.java
+ * @compile ../test-classes/Hello.java test-classes/CustomLoadee.java test-classes/CustomLoadee2.java
* test-classes/CustomInterface2_ia.java test-classes/CustomInterface2_ib.java
* @run driver ClassListFormatA
*/
@@ -133,4 +133,3 @@
"input line too long (must be no longer than " + _max_allowed_line + " chars");
}
}
-
--- a/test/hotspot/jtreg/runtime/appcds/customLoader/ClassListFormatB.java Fri May 17 13:21:44 2019 +0100
+++ b/test/hotspot/jtreg/runtime/appcds/customLoader/ClassListFormatB.java Thu May 23 11:07:37 2019 +0100
@@ -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
@@ -32,7 +32,7 @@
* @modules java.base/jdk.internal.misc
* java.management
* jdk.jartool/sun.tools.jar
- * @compile test-classes/Hello.java test-classes/CustomLoadee.java test-classes/CustomLoadee2.java
+ * @compile ../test-classes/Hello.java test-classes/CustomLoadee.java test-classes/CustomLoadee2.java
* test-classes/CustomInterface2_ia.java test-classes/CustomInterface2_ib.java
* @run driver ClassListFormatB
*/
@@ -69,4 +69,3 @@
"If source location is specified, id must be also specified");
}
}
-
--- a/test/hotspot/jtreg/runtime/appcds/customLoader/ClassListFormatBase.java Fri May 17 13:21:44 2019 +0100
+++ b/test/hotspot/jtreg/runtime/appcds/customLoader/ClassListFormatBase.java Thu May 23 11:07:37 2019 +0100
@@ -79,4 +79,3 @@
return TestCommon.list(args);
}
}
-
--- a/test/hotspot/jtreg/runtime/appcds/customLoader/ClassListFormatC.java Fri May 17 13:21:44 2019 +0100
+++ b/test/hotspot/jtreg/runtime/appcds/customLoader/ClassListFormatC.java Thu May 23 11:07:37 2019 +0100
@@ -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
@@ -32,7 +32,7 @@
* @modules java.base/jdk.internal.misc
* java.management
* jdk.jartool/sun.tools.jar
- * @compile test-classes/Hello.java test-classes/CustomLoadee.java test-classes/CustomLoadee2.java
+ * @compile ../test-classes/Hello.java test-classes/CustomLoadee.java test-classes/CustomLoadee2.java
* test-classes/CustomInterface2_ia.java test-classes/CustomInterface2_ib.java
* @run driver ClassListFormatC
*/
@@ -71,4 +71,3 @@
"If source location is not specified, interface(s) must not be specified");
}
}
-
--- a/test/hotspot/jtreg/runtime/appcds/customLoader/ClassListFormatD.java Fri May 17 13:21:44 2019 +0100
+++ b/test/hotspot/jtreg/runtime/appcds/customLoader/ClassListFormatD.java Thu May 23 11:07:37 2019 +0100
@@ -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
@@ -32,7 +32,7 @@
* @modules java.base/jdk.internal.misc
* java.management
* jdk.jartool/sun.tools.jar
- * @compile test-classes/Hello.java test-classes/CustomLoadee.java test-classes/CustomLoadee2.java
+ * @compile ../test-classes/Hello.java test-classes/CustomLoadee.java test-classes/CustomLoadee2.java
* test-classes/CustomInterface2_ia.java test-classes/CustomInterface2_ib.java
* @run driver ClassListFormatD
*/
@@ -80,4 +80,3 @@
"Interface id 2 is not yet loaded");
}
}
-
--- a/test/hotspot/jtreg/runtime/appcds/customLoader/ClassListFormatE.java Fri May 17 13:21:44 2019 +0100
+++ b/test/hotspot/jtreg/runtime/appcds/customLoader/ClassListFormatE.java Thu May 23 11:07:37 2019 +0100
@@ -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
@@ -32,7 +32,7 @@
* @modules java.base/jdk.internal.misc
* java.management
* jdk.jartool/sun.tools.jar
- * @compile test-classes/Hello.java test-classes/CustomLoadee.java test-classes/CustomLoadee2.java
+ * @compile ../test-classes/Hello.java test-classes/CustomLoadee.java test-classes/CustomLoadee2.java
* test-classes/CustomInterface2_ia.java test-classes/CustomInterface2_ib.java
* @run driver ClassListFormatE
*/
@@ -106,4 +106,3 @@
"The specified super class CustomLoadee (id 4) does not match actual super class java.lang.Object");
}
}
-
--- a/test/hotspot/jtreg/runtime/appcds/customLoader/HelloCustom.java Fri May 17 13:21:44 2019 +0100
+++ b/test/hotspot/jtreg/runtime/appcds/customLoader/HelloCustom.java Thu May 23 11:07:37 2019 +0100
@@ -27,10 +27,12 @@
* @summary Hello World test for AppCDS custom loader support
* @requires vm.cds
* @requires vm.cds.custom.loaders
- * @library /test/lib /test/hotspot/jtreg/runtime/appcds
- * @compile test-classes/Hello.java test-classes/CustomLoadee.java
- * @build sun.hotspot.WhiteBox
- * @run driver ClassFileInstaller -jar hello.jar Hello
+ * @library /test/lib /test/hotspot/jtreg/runtime/appcds /runtime/testlibrary
+ * @modules java.base/jdk.internal.misc
+ * java.management
+ * @compile test-classes/HelloUnload.java test-classes/CustomLoadee.java
+ * @build sun.hotspot.WhiteBox ClassUnloadCommon
+ * @run driver ClassFileInstaller -jar hello.jar HelloUnload ClassUnloadCommon ClassUnloadCommon$1 ClassUnloadCommon$TestFailure
* @run driver ClassFileInstaller -jar hello_custom.jar CustomLoadee
* @run driver ClassFileInstaller -jar WhiteBox.jar sun.hotspot.WhiteBox
* @run driver HelloCustom
@@ -52,7 +54,7 @@
// Dump the archive
String classlist[] = new String[] {
- "Hello",
+ "HelloUnload",
"java/lang/Object id: 1",
"CustomLoadee id: 2 super: 1 source: " + customJarPath
};
@@ -68,8 +70,7 @@
use_whitebox_jar,
"-XX:+UnlockDiagnosticVMOptions",
"-XX:+WhiteBoxAPI",
- "Hello", customJarPath));
+ "HelloUnload", customJarPath, "true", "true"));
TestCommon.checkExec(output);
}
}
-
--- a/test/hotspot/jtreg/runtime/appcds/customLoader/HelloCustom_JFR.java Fri May 17 13:21:44 2019 +0100
+++ b/test/hotspot/jtreg/runtime/appcds/customLoader/HelloCustom_JFR.java Thu May 23 11:07:37 2019 +0100
@@ -30,10 +30,10 @@
* @requires vm.hasJFR
* @requires vm.cds
* @requires vm.cds.custom.loaders
- * @library /test/lib /test/hotspot/jtreg/runtime/appcds
- * @compile test-classes/Hello.java test-classes/CustomLoadee.java
- * @build sun.hotspot.WhiteBox
- * @run driver ClassFileInstaller -jar hello.jar Hello
+ * @library /test/lib /test/hotspot/jtreg/runtime/appcds /runtime/testlibrary
+ * @compile test-classes/HelloUnload.java test-classes/CustomLoadee.java
+ * @build sun.hotspot.WhiteBox ClassUnloadCommon
+ * @run driver ClassFileInstaller -jar hello.jar HelloUnload ClassUnloadCommon ClassUnloadCommon$1 ClassUnloadCommon$TestFailure
* @run driver ClassFileInstaller -jar hello_custom.jar CustomLoadee
* @run driver ClassFileInstaller -jar WhiteBox.jar sun.hotspot.WhiteBox
* @run driver HelloCustom_JFR
@@ -47,4 +47,3 @@
HelloCustom.run("-XX:StartFlightRecording=dumponexit=true", "-Xlog:cds+jvmti=debug");
}
}
-
--- a/test/hotspot/jtreg/runtime/appcds/customLoader/ProhibitedPackageNamesTest.java Fri May 17 13:21:44 2019 +0100
+++ b/test/hotspot/jtreg/runtime/appcds/customLoader/ProhibitedPackageNamesTest.java Thu May 23 11:07:37 2019 +0100
@@ -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
@@ -31,7 +31,7 @@
* @modules java.base/jdk.internal.misc
* java.management
* jdk.jartool/sun.tools.jar
- * @compile ClassListFormatBase.java test-classes/Hello.java test-classes/InProhibitedPkg.java
+ * @compile ClassListFormatBase.java ../test-classes/Hello.java test-classes/InProhibitedPkg.java
* @run driver ProhibitedPackageNamesTest
*/
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/runtime/appcds/customLoader/test-classes/HelloUnload.java Thu May 23 11:07:37 2019 +0100
@@ -0,0 +1,106 @@
+/*
+ * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+import java.io.File;
+import java.net.URL;
+import java.net.URLClassLoader;
+import sun.hotspot.WhiteBox;
+
+public class HelloUnload {
+ private static String className = "CustomLoadee";
+
+ public static void main(String args[]) throws Exception {
+ if (args.length != 3) {
+ throw new RuntimeException("Unexpected number of arguments: expected 3, actual " + args.length);
+ }
+
+ String path = args[0];
+ URL url = new File(path).toURI().toURL();
+ URL[] urls = new URL[] {url};
+ System.out.println(path);
+ System.out.println(url);
+
+ // unload the custom class loader
+ boolean doUnload = false;
+ if (args[1].equals("true")) {
+ doUnload = true;
+ } else if (args[1].equals("false")) {
+ doUnload = false;
+ } else {
+ throw new RuntimeException("args[1] can only be either \"true\" or \"false\", actual " + args[1]);
+ }
+
+ // should the CustomLoadee class be in the shared archive
+ boolean inArchive = false;
+ if (args[2].equals("true")) {
+ inArchive = true;
+ } else if (args[2].equals("false")) {
+ inArchive = false;
+ } else {
+ throw new RuntimeException("args[2] can only be either \"true\" or \"false\", actual " + args[1]);
+ }
+
+ URLClassLoader urlClassLoader =
+ new URLClassLoader("HelloClassLoader", urls, null);
+ Class c = Class.forName(className, true, urlClassLoader);
+ System.out.println(c);
+ System.out.println(c.getClassLoader());
+ Object o = c.newInstance();
+
+ // [1] Check that CustomLoadee is defined by the correct loader
+ if (c.getClassLoader() != urlClassLoader) {
+ throw new RuntimeException("c.getClassLoader() == " + c.getClassLoader() +
+ ", expected == " + urlClassLoader);
+ }
+
+ // [2] Check that CustomLoadee is loaded from shared archive.
+ WhiteBox wb = WhiteBox.getWhiteBox();
+ if(wb.isSharedClass(HelloUnload.class)) {
+ if (inArchive && !wb.isSharedClass(c)) {
+ throw new RuntimeException("wb.isSharedClass(c) should be true");
+ }
+ }
+
+ ClassUnloadCommon.failIf(!wb.isClassAlive(className), "should be live here");
+
+ if (doUnload) {
+ String loaderName = urlClassLoader.getName();
+ int loadedRefcount = wb.getSymbolRefcount(loaderName);
+ System.out.println("Refcount of symbol " + loaderName + " is " + loadedRefcount);
+
+ urlClassLoader = null; c = null; o = null;
+ ClassUnloadCommon.triggerUnloading();
+ System.out.println("Is CustomLoadee alive? " + wb.isClassAlive(className));
+ ClassUnloadCommon.failIf(wb.isClassAlive(className), "should have been unloaded");
+
+ int unloadedRefcount = wb.getSymbolRefcount(loaderName);
+ System.out.println("Refcount of symbol " + loaderName + " is " + unloadedRefcount);
+
+ // refcount of a permanent symbol will not be decremented
+ if (loadedRefcount != 65535) {
+ ClassUnloadCommon.failIf(unloadedRefcount != (loadedRefcount - 1), "Refcount must be decremented");
+ }
+ }
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/runtime/appcds/dynamicArchive/AppendClasspath.java Thu May 23 11:07:37 2019 +0100
@@ -0,0 +1,92 @@
+/*
+ * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+/*
+ * @test
+ * @summary At run time, it is OK to append new elements to the classpath that was used at dump time.
+ * @requires vm.cds
+ * @library /test/lib /test/hotspot/jtreg/runtime/appcds
+ * @modules java.base/jdk.internal.misc
+ * java.management
+ * jdk.jartool/sun.tools.jar
+ * @compile ../test-classes/Hello.java
+ * @compile ../test-classes/HelloMore.java
+ * @run driver AppendClasspath
+ */
+
+import java.io.File;
+
+public class AppendClasspath extends DynamicArchiveTestBase {
+
+ public static void main(String[] args) throws Exception {
+ runTest(AppendClasspath::testDefaultBase);
+ }
+
+ static void testDefaultBase() throws Exception {
+ String topArchiveName = getNewArchiveName("top");
+ doTest(topArchiveName);
+ }
+
+ private static void doTest(String topArchiveName) throws Exception {
+ String appJar = JarBuilder.getOrCreateHelloJar();
+ String appJar2 = JarBuilder.build("AppendClasspath_HelloMore", "HelloMore");
+
+ // Dump an archive with a specified JAR file in -classpath
+ dump(topArchiveName,
+ "-Xlog:cds",
+ "-Xlog:cds+dynamic=debug",
+ "-cp", appJar, "Hello")
+ .assertNormalExit(output -> {
+ output.shouldContain("Buffer-space to target-space delta")
+ .shouldContain("Written dynamic archive 0x");
+ });
+
+ // runtime with classpath containing the one used in dump time,
+ // i.e. the dump time classpath is a prefix of the runtime classpath.
+ run(topArchiveName,
+ "-Xlog:class+load",
+ "-Xlog:cds+dynamic=debug,cds=debug",
+ "-cp", appJar + File.pathSeparator + appJar2,
+ "HelloMore")
+ .assertNormalExit(output -> {
+ output.shouldContain("Hello source: shared objects file")
+ .shouldContain("Hello World ... More")
+ .shouldHaveExitValue(0);
+ });
+
+ // reverse the order of the 2 jar files so that the dump time classpath
+ // is no longer a prefix of the runtime classpath. The Hello class
+ // should be loaded from the jar file.
+ run(topArchiveName,
+ "-Xlog:class+load",
+ "-Xlog:cds+dynamic=debug,cds=debug",
+ "-cp", appJar2 + File.pathSeparator + appJar,
+ "HelloMore")
+ .assertAbnormalExit(output -> {
+ output.shouldContain("shared class paths mismatch")
+ .shouldHaveExitValue(1);
+ });
+
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/runtime/appcds/dynamicArchive/ArchiveConsistency.java Thu May 23 11:07:37 2019 +0100
@@ -0,0 +1,167 @@
+/*
+ * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+/*
+ * @test
+ * @summary Corrupt the header CRC fields of the top archive. VM should exit with an error.
+ * @requires vm.cds
+ * @library /test/lib /test/hotspot/jtreg/runtime/appcds /test/hotspot/jtreg/runtime/appcds/test-classes
+ * @build Hello sun.hotspot.WhiteBox
+ * @run driver ClassFileInstaller -jar hello.jar Hello
+ * @run driver ClassFileInstaller sun.hotspot.WhiteBox
+ * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI ArchiveConsistency
+ */
+
+import java.io.File;
+import java.io.IOException;
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+import java.nio.channels.FileChannel;
+import java.nio.file.StandardOpenOption;
+import static java.nio.file.StandardOpenOption.READ;
+import static java.nio.file.StandardOpenOption.WRITE;
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+import sun.hotspot.WhiteBox;
+
+public class ArchiveConsistency extends DynamicArchiveTestBase {
+ public static WhiteBox wb;
+ public static int int_size; // size of int
+ public static String[] shared_region_name = {"MiscCode", "ReadWrite", "ReadOnly", "MiscData"};
+ public static int num_regions = shared_region_name.length;
+
+ public static void main(String[] args) throws Exception {
+ runTest(ArchiveConsistency::testCustomBase);
+ }
+
+ // Test with custom base archive + top archive
+ static void testCustomBase() throws Exception {
+ String topArchiveName = getNewArchiveName("top2");
+ String baseArchiveName = getNewArchiveName("base");
+ dumpBaseArchive(baseArchiveName);
+ doTest(baseArchiveName, topArchiveName);
+ }
+
+ public static void setReadWritePermission(File file) throws Exception {
+ if (!file.canRead()) {
+ if (!file.setReadable(true)) {
+ throw new IOException("Cannot modify file " + file + " as readable");
+ }
+ }
+ if (!file.canWrite()) {
+ if (!file.setWritable(true)) {
+ throw new IOException("Cannot modify file " + file + " as writable");
+ }
+ }
+ }
+
+ public static long readInt(FileChannel fc, long offset, int nbytes) throws Exception {
+ ByteBuffer bb = ByteBuffer.allocate(nbytes);
+ bb.order(ByteOrder.nativeOrder());
+ fc.position(offset);
+ fc.read(bb);
+ return (nbytes > 4 ? bb.getLong(0) : bb.getInt(0));
+ }
+
+ public static long align_up_page(long l) throws Exception {
+ // wb is obtained in getFileOffsetInfo() which is called first in main() else we should call
+ // WhiteBox.getWhiteBox() here first.
+ int pageSize = wb.getVMPageSize();
+ return (l + pageSize -1) & (~ (pageSize - 1));
+ }
+
+ public static void writeData(FileChannel fc, long offset, ByteBuffer bb) throws Exception {
+ fc.position(offset);
+ fc.write(bb);
+ fc.force(true);
+ }
+
+ public static FileChannel getFileChannel(File jsa) throws Exception {
+ List<StandardOpenOption> arry = new ArrayList<StandardOpenOption>();
+ arry.add(READ);
+ arry.add(WRITE);
+ return FileChannel.open(jsa.toPath(), new HashSet<StandardOpenOption>(arry));
+ }
+
+ public static void modifyJsaHeaderCRC(File jsa) throws Exception {
+ FileChannel fc = getFileChannel(jsa);
+ int_size = wb.getOffsetForName("int_size");
+ System.out.println(" int_size " + int_size);
+ ByteBuffer bbuf = ByteBuffer.allocateDirect(int_size);
+ for (int i = 0; i < int_size; i++) {
+ bbuf.put((byte)0);
+ }
+
+ int baseArchiveCRCOffset = wb.getOffsetForName("DynamicArchiveHeader::_base_archive_crc");
+ int crc = 0;
+ System.out.printf("%-12s%-12s\n", "Space name", "CRC");
+ for (int i = 0; i < 4; i++) {
+ baseArchiveCRCOffset += int_size * i;
+ System.out.println(" baseArchiveCRCOffset " + baseArchiveCRCOffset);
+ crc = (int)readInt(fc, baseArchiveCRCOffset, int_size );
+ System.out.printf("%-11s%-12d\n", shared_region_name[i], crc);
+ bbuf.rewind();
+ writeData(fc, baseArchiveCRCOffset, bbuf);
+ }
+ fc.force(true);
+ if (fc.isOpen()) {
+ fc.close();
+ }
+ }
+
+ private static void doTest(String baseArchiveName, String topArchiveName) throws Exception {
+ String appJar = ClassFileInstaller.getJarPath("hello.jar");
+ String mainClass = "Hello";
+ dump2(baseArchiveName, topArchiveName,
+ "-Xlog:cds",
+ "-Xlog:cds+dynamic=debug",
+ "-cp", appJar, mainClass)
+ .assertNormalExit(output -> {
+ output.shouldContain("Buffer-space to target-space delta")
+ .shouldContain("Written dynamic archive 0x");
+ });
+
+ File jsa = new File(topArchiveName);
+ if (!jsa.exists()) {
+ throw new IOException(jsa + " does not exist!");
+ }
+
+ // Modify the CRC values in the header of the top archive.
+ wb = WhiteBox.getWhiteBox();
+ setReadWritePermission(jsa);
+ modifyJsaHeaderCRC(jsa);
+
+ run2(baseArchiveName, topArchiveName,
+ "-Xlog:class+load",
+ "-Xlog:cds+dynamic=debug,cds=debug",
+ "-XX:+VerifySharedSpaces",
+ "-cp", appJar, mainClass)
+ .assertAbnormalExit(output -> {
+ output.shouldContain("Header checksum verification failed")
+ .shouldContain("Unable to use shared archive")
+ .shouldHaveExitValue(1);
+ });
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/runtime/appcds/dynamicArchive/ArrayKlasses.java Thu May 23 11:07:37 2019 +0100
@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+/*
+ * @test
+ * @summary handling of the existence of InstanceKlass::array_klasses()
+ * @requires vm.cds
+ * @library /test/lib /test/hotspot/jtreg/runtime/appcds
+ * /test/hotspot/jtreg/runtime/appcds/dynamicArchive/test-classes
+ * @build ArrayKlassesApp
+ * @run driver ClassFileInstaller -jar ArrayKlasses.jar
+ * ArrayKlassesApp
+ * @run driver ArrayKlasses
+ */
+
+public class ArrayKlasses extends DynamicArchiveTestBase {
+ public static void main(String[] args) throws Exception {
+ runTest(ArrayKlasses::test);
+ }
+
+ static void test() throws Exception {
+ String topArchiveName = getNewArchiveName();
+ String appJar = ClassFileInstaller.getJarPath("ArrayKlasses.jar");
+ String mainClass = "ArrayKlassesApp";
+
+ dumpAndRun(topArchiveName, "-Xlog:cds+dynamic=debug", "-cp", appJar, mainClass);
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/runtime/appcds/dynamicArchive/ClassResolutionFailure.java Thu May 23 11:07:37 2019 +0100
@@ -0,0 +1,73 @@
+/*
+ * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+/*
+ * @test
+ * @summary Test with a jar file which contains only the main class but not the dependent class.
+ * The main class should be archived. During run time, the main class
+ * should be loaded from the archive.
+ * @requires vm.cds
+ * @library /test/lib /test/hotspot/jtreg/runtime/appcds /test/hotspot/jtreg/runtime/appcds/dynamicArchive/test-classes
+ * @build StrConcatApp
+ * @build MissingDependent
+ * @run driver ClassFileInstaller -jar missingDependent.jar MissingDependent
+ * @run driver ClassResolutionFailure
+ */
+
+public class ClassResolutionFailure extends DynamicArchiveTestBase {
+
+ public static void main(String[] args) throws Exception {
+ runTest(ClassResolutionFailure::testDefaultBase);
+ }
+
+ // Test with default base archive + top archive
+ static void testDefaultBase() throws Exception {
+ String topArchiveName = getNewArchiveName("top");
+ doTest(topArchiveName);
+ }
+
+ private static void doTest(String topArchiveName) throws Exception {
+ String appJar = ClassFileInstaller.getJarPath("missingDependent.jar");
+ String mainClass = "MissingDependent";
+
+ dump(topArchiveName,
+ "-Xlog:cds",
+ "-Xlog:cds+dynamic=debug",
+ "-Xlog:class+load=trace",
+ "-cp", appJar, mainClass)
+ .assertNormalExit(output -> {
+ output.shouldContain("Buffer-space to target-space delta")
+ .shouldContain("Written dynamic archive 0x");
+ });
+
+ run(topArchiveName,
+ "-Xlog:class+load",
+ "-Xlog:cds+dynamic=debug,cds=debug",
+ "-cp", appJar, mainClass)
+ .assertNormalExit(output -> {
+ output.shouldContain("MissingDependent source: shared objects file")
+ .shouldHaveExitValue(0);
+ });
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/runtime/appcds/dynamicArchive/DynamicArchiveTestBase.java Thu May 23 11:07:37 2019 +0100
@@ -0,0 +1,246 @@
+/*
+ * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+import java.io.File;
+import jdk.test.lib.process.OutputAnalyzer;
+import jdk.test.lib.process.ProcessTools;
+import jdk.test.lib.cds.CDSOptions;
+import jdk.test.lib.cds.CDSTestUtils;
+import jdk.test.lib.cds.CDSTestUtils.Result;
+
+/**
+ * Base class for test cases in test/hotspot/jtreg/runtime/appcds/dynamicArchive/
+ */
+class DynamicArchiveTestBase {
+ private static boolean executedIn_run = false;
+
+ public static interface DynamicArchiveTest {
+ public void run() throws Exception;
+ }
+
+ public static interface DynamicArchiveTestWithArgs {
+ public void run(String args[]) throws Exception;
+ }
+
+
+ /*
+ * Tests for dynamic archives should be written using this pattern:
+ *
+ * public class HelloDynamic extends DynamicArchiveTestBase {
+ * public static void main(String[] args) throws Exception {
+ * runTest(HelloDynamic::testDefaultBase); // launch one test case
+ * }
+ *
+ * // the body of a test case
+ * static void testDefaultBase() throws Exception {
+ * String topArchiveName = getNewArchiveName("top");
+ * doTest(null, topArchiveName);
+ * }
+ * }
+ *
+ * The reason for this is so that we can clean up the archive files
+ * created by prior test cases. Otherwise tests with lots of
+ * test cases may fill up the scratch directory.
+ */
+ public static void runTest(DynamicArchiveTest t) throws Exception {
+ executedIn_run = true;
+ try {
+ TestCommon.deletePriorArchives();
+ t.run();
+ } finally {
+ executedIn_run = false;
+ }
+ }
+
+ public static void runTest(DynamicArchiveTestWithArgs t, String... args) throws Exception {
+ executedIn_run = true;
+ try {
+ TestCommon.deletePriorArchives();
+ t.run(args);
+ } finally {
+ executedIn_run = false;
+ }
+ }
+
+ public static String getNewArchiveName() {
+ return TestCommon.getNewArchiveName();
+ }
+ public static String getNewArchiveName(String stem) {
+ return TestCommon.getNewArchiveName(stem);
+ }
+
+ /**
+ * Execute a JVM using the base archive (given by baseArchiveName) with the command line
+ * (given by cmdLineSuffix). At JVM exit, dump all eligible classes into the top archive
+ * (give by topArchiveName).
+ *
+ * If baseArchiveName is null, use the JDK's default archive as the base archive.
+ */
+ public static Result dump2(String baseArchiveName, String topArchiveName, String ... cmdLineSuffix)
+ throws Exception
+ {
+ String[] cmdLine = TestCommon.concat(
+ "-XX:ArchiveClassesAtExit=" + topArchiveName);
+ // to allow dynamic archive tests to be run in the "rt-non-cds-mode"
+ cmdLine = TestCommon.concat(cmdLine, "-Xshare:auto");
+ if (baseArchiveName != null) {
+ cmdLine = TestCommon.concat(cmdLine, "-XX:SharedArchiveFile=" + baseArchiveName);
+ }
+ cmdLine = TestCommon.concat(cmdLine, cmdLineSuffix);
+ return execProcess("dump", cmdLine);
+ }
+
+ public static Result dump2_WB(String baseArchiveName, String topArchiveName, String ... cmdLineSuffix)
+ throws Exception
+ {
+ return dump2(baseArchiveName, topArchiveName,
+ TestCommon.concat(wbRuntimeArgs(), cmdLineSuffix));
+ }
+
+ /**
+ * A convenience method similar to dump2, but always use the JDK's default archive
+ * as the base archive.
+ *
+ * Most dynamicArchive/*.java test cases should be using this method instead of run2.
+ */
+ public static Result dump(String topArchiveName, String ... cmdLineSuffix)
+ throws Exception
+ {
+ return dump2(null, topArchiveName, cmdLineSuffix);
+ }
+
+ /**
+ * Dump the base archive. The JDK's default class list is used (unless otherwise specified
+ * in cmdLineSuffix).
+ */
+ public static void dumpBaseArchive(String baseArchiveName, String ... cmdLineSuffix)
+ throws Exception
+ {
+ CDSOptions opts = new CDSOptions();
+ opts.setArchiveName(baseArchiveName);
+ opts.addSuffix(cmdLineSuffix);
+ opts.addSuffix("-Djava.class.path=");
+ OutputAnalyzer out = CDSTestUtils.createArchive(opts);
+ CDSTestUtils.checkDump(out);
+ }
+
+ /**
+ * Same as dumpBaseArchive, but also add WhiteBox to the bootcp
+ */
+ public static void dumpBaseArchive_WB(String baseArchiveName, String ... cmdLineSuffix)
+ throws Exception
+ {
+ dumpBaseArchive(baseArchiveName,
+ TestCommon.concat("-Xbootclasspath/a:" + getWhiteBoxJar(), cmdLineSuffix));
+ }
+
+ private static String getWhiteBoxJar() {
+ String wbJar = ClassFileInstaller.getJarPath("WhiteBox.jar");
+ if (!(new File(wbJar)).exists()) {
+ throw new RuntimeException("Test error: your test must have " +
+ "'@run driver ClassFileInstaller -jar WhiteBox.jar sun.hotspot.WhiteBox'");
+ }
+ return wbJar;
+ }
+
+ private static String[] wbRuntimeArgs() {
+ return TestCommon.concat("-Xbootclasspath/a:" + getWhiteBoxJar(),
+ "-XX:+UnlockDiagnosticVMOptions",
+ "-XX:+WhiteBoxAPI");
+ }
+
+ /**
+ * Execute a JVM using the base archive (given by baseArchiveName) and the top archive
+ * (give by topArchiveName), using the command line (given by cmdLineSuffix).
+ *
+ * If baseArchiveName is null, use the JDK's default archive as the base archive.
+ */
+ public static Result run2(String baseArchiveName, String topArchiveName, String ... cmdLineSuffix)
+ throws Exception {
+ if (baseArchiveName == null && topArchiveName == null) {
+ throw new RuntimeException("Both baseArchiveName and topArchiveName cannot be null at the same time.");
+ }
+ String archiveFiles = (baseArchiveName == null) ? topArchiveName :
+ (topArchiveName == null) ? baseArchiveName :
+ baseArchiveName + File.pathSeparator + topArchiveName;
+ String[] cmdLine = TestCommon.concat(
+ "-Xshare:on",
+ "-XX:SharedArchiveFile=" + archiveFiles);
+ cmdLine = TestCommon.concat(cmdLine, cmdLineSuffix);
+ return execProcess("exec", cmdLine);
+ }
+
+ public static Result run2_WB(String baseArchiveName, String topArchiveName, String ... cmdLineSuffix)
+ throws Exception
+ {
+ return run2(baseArchiveName, topArchiveName,
+ TestCommon.concat(wbRuntimeArgs(), cmdLineSuffix));
+ }
+
+ /**
+ * A convenience method similar to run2, but always use the JDK's default archive
+ * as the base archive.
+ *
+ * Most dynamicArchive/*.java test cases should be using this method instead of run2.
+ */
+ public static Result run(String topArchiveName, String ... cmdLineSuffix)
+ throws Exception
+ {
+ return run2(null, topArchiveName, cmdLineSuffix);
+ }
+
+ private static String getXshareMode(String[] cmdLine) {
+ for (int i = 0; i <= cmdLine.length - 1; i++) {
+ int j = cmdLine[i].indexOf("-Xshare:");
+ if (j != -1) {
+ return (cmdLine[i].substring(j));
+ }
+ }
+ return null;
+ }
+
+
+ private static Result execProcess(String mode, String[] cmdLine) throws Exception {
+ if (!executedIn_run) {
+ throw new Exception("Test error: dynamic archive tests must be executed via DynamicArchiveTestBase.run()");
+ }
+ ProcessBuilder pb = ProcessTools.createJavaProcessBuilder(true, cmdLine);
+ OutputAnalyzer output = TestCommon.executeAndLog(pb, mode);
+ CDSOptions opts = new CDSOptions();
+ String xShareMode = getXshareMode(cmdLine);
+ if (xShareMode != null) {
+ opts.setXShareMode(xShareMode);
+ }
+ return new Result(opts, output);
+ }
+
+ /**
+ * A convenience method for dumping and running, using the default CDS archive from the
+ * JDK. Both dumping and running should exit normally.
+ */
+ public static void dumpAndRun(String topArchiveName, String ... cmdLineSuffix) throws Exception {
+ dump(topArchiveName, cmdLineSuffix).assertNormalExit();
+ run(topArchiveName, cmdLineSuffix).assertNormalExit();
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/runtime/appcds/dynamicArchive/DynamicFlag.java Thu May 23 11:07:37 2019 +0100
@@ -0,0 +1,41 @@
+/*
+ * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+/*
+ * @test
+ * @summary The DynamicDumpShareSpaces flag is internal, setting it at the command line should have no effect.
+ * @requires vm.cds
+ * @library /test/lib /test/hotspot/jtreg/runtime/appcds
+ * @modules java.base/jdk.internal.misc
+ * jdk.jartool/sun.tools.jar
+ * @compile ../test-classes/Hello.java
+ * @run driver DynamicFlag
+ */
+
+public class DynamicFlag {
+ public static void main(String[] args) throws Exception {
+ TestCommon.test(JarBuilder.getOrCreateHelloJar(),
+ TestCommon.list("Hello"), "-XX:+DynamicDumpSharedSpaces", "Hello");
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/runtime/appcds/dynamicArchive/DynamicLotsOfClasses.java Thu May 23 11:07:37 2019 +0100
@@ -0,0 +1,93 @@
+/*
+ * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+import java.io.File;
+import java.nio.charset.Charset;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.List;
+import java.util.ArrayList;
+
+/*
+ * @test
+ * @summary Try to archive lots of classes by searching for classes from the jrt:/ file system. With JDK 12
+ * this will produce an archive with over 30,000 classes.
+ * @requires vm.cds
+ * @library /test/lib /test/hotspot/jtreg/runtime/appcds /test/hotspot/jtreg/runtime/appcds/dynamicArchive/test-classes
+ * @build LoadClasses
+ * @build sun.hotspot.WhiteBox
+ * @modules jdk.jartool/sun.tools.jar
+ * @run driver ClassFileInstaller -jar loadclasses.jar LoadClasses
+ * @run driver ClassFileInstaller -jar whitebox.jar sun.hotspot.WhiteBox
+ * @run driver/timeout=500 DynamicLotsOfClasses
+ */
+
+public class DynamicLotsOfClasses extends DynamicArchiveTestBase {
+
+ public static void main(String[] args) throws Throwable {
+ runTest(DynamicLotsOfClasses::testDefaultBase);
+ }
+
+ static void testDefaultBase() throws Exception {
+ String topArchiveName = getNewArchiveName("top");
+ try {
+ doTest(topArchiveName);
+ } catch (Throwable th) {
+ System.out.println(th.toString());
+ Exception ex = new Exception(th);
+ throw ex;
+ }
+ }
+
+ private static void doTest(String topArchiveName) throws Throwable {
+ ArrayList<String> list = new ArrayList<>();
+ TestCommon.findAllClasses(list);
+
+ String classList = System.getProperty("user.dir") + File.separator +
+ "LotsOfClasses.list";
+ List<String> lines = list;
+ Path file = Paths.get(classList);
+ Files.write(file, lines, Charset.forName("UTF-8"));
+
+ String appJar = ClassFileInstaller.getJarPath("loadclasses.jar");
+ String mainClass = "LoadClasses";
+
+ String whiteBoxJar = ClassFileInstaller.getJarPath("whitebox.jar");
+ String bootClassPath = "-Xbootclasspath/a:" + whiteBoxJar;
+ dump(topArchiveName,
+ "--add-modules",
+ "ALL-SYSTEM",
+ "-Xlog:hashtables",
+ "-Xmx500m",
+ "-Xlog:cds,cds+dynamic",
+ bootClassPath,
+ "-XX:+UnlockDiagnosticVMOptions", "-XX:+WhiteBoxAPI",
+ "-cp", appJar, mainClass, classList)
+ .assertNormalExit(output -> {
+ output.shouldContain("Buffer-space to target-space delta")
+ .shouldContain("Written dynamic archive 0x");
+ });
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/runtime/appcds/dynamicArchive/ExcludedClasses.java Thu May 23 11:07:37 2019 +0100
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+/*
+ * @test
+ * @summary Unreferenced app classes during dump time should not be included in the archive.
+ * @requires vm.cds
+ * @library /test/lib /test/hotspot/jtreg/runtime/appcds
+ * /test/hotspot/jtreg/runtime/appcds/dynamicArchive/test-classes
+ * @build ExcludedClassesApp
+ * @run driver ClassFileInstaller -jar ExcludedClasses.jar
+ * ExcludedClassesApp
+ * ExcludedClassesApp$NotLinkedSuper
+ * ExcludedClassesApp$NotLinkedChild
+ * ExcludedClassesApp$NotLinkedInterface
+ * @run driver ExcludedClasses
+ */
+
+public class ExcludedClasses extends DynamicArchiveTestBase {
+ public static void main(String[] args) throws Exception {
+ runTest(ExcludedClasses::test);
+ }
+
+ static void test() throws Exception {
+ String topArchiveName = getNewArchiveName();
+ String appJar = ClassFileInstaller.getJarPath("ExcludedClasses.jar");
+ String mainClass = "ExcludedClassesApp";
+
+ dumpAndRun(topArchiveName, "-Xlog:cds+dynamic=debug", "-cp", appJar, mainClass);
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/runtime/appcds/dynamicArchive/HelloDynamic.java Thu May 23 11:07:37 2019 +0100
@@ -0,0 +1,75 @@
+/*
+ * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+/*
+ * @test
+ * @summary Hello World test for dynamic archive
+ * @requires vm.cds
+ * @library /test/lib /test/hotspot/jtreg/runtime/appcds /test/hotspot/jtreg/runtime/appcds/test-classes
+ * @build Hello
+ * @run driver ClassFileInstaller -jar hello.jar Hello
+ * @run driver HelloDynamic
+ */
+
+public class HelloDynamic extends DynamicArchiveTestBase {
+ public static void main(String[] args) throws Exception {
+ runTest(HelloDynamic::testDefaultBase);
+ runTest(HelloDynamic::testCustomBase);
+ }
+
+ // (1) Test with default base archive + top archive
+ static void testDefaultBase() throws Exception {
+ String topArchiveName = getNewArchiveName("top");
+ doTest(null, topArchiveName);
+ }
+
+ // (2) Test with custom base archive + top archive
+ static void testCustomBase() throws Exception {
+ String topArchiveName = getNewArchiveName("top2");
+ String baseArchiveName = getNewArchiveName("base");
+ dumpBaseArchive(baseArchiveName);
+ doTest(baseArchiveName, topArchiveName);
+ }
+
+ private static void doTest(String baseArchiveName, String topArchiveName) throws Exception {
+ String appJar = ClassFileInstaller.getJarPath("hello.jar");
+ String mainClass = "Hello";
+ dump2(baseArchiveName, topArchiveName,
+ "-Xlog:cds",
+ "-Xlog:cds+dynamic=debug",
+ "-cp", appJar, mainClass)
+ .assertNormalExit(output -> {
+ output.shouldContain("Buffer-space to target-space delta")
+ .shouldContain("Written dynamic archive 0x");
+ });
+ run2(baseArchiveName, topArchiveName,
+ "-Xlog:class+load",
+ "-Xlog:cds+dynamic=debug,cds=debug",
+ "-cp", appJar, mainClass)
+ .assertNormalExit(output -> {
+ output.shouldContain("Hello source: shared objects file")
+ .shouldHaveExitValue(0);
+ });
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/runtime/appcds/dynamicArchive/HelloDynamicCustom.java Thu May 23 11:07:37 2019 +0100
@@ -0,0 +1,85 @@
+/*
+ * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+/*
+ * @test
+ * @summary Hello World test for dynamic archive with custom loader
+ * @requires vm.cds
+ * @library /test/lib /test/hotspot/jtreg/runtime/appcds /test/hotspot/jtreg/runtime/appcds/customLoader/test-classes /runtime/testlibrary
+ * @build HelloUnload CustomLoadee ClassUnloadCommon
+ * @build sun.hotspot.WhiteBox
+ * @run driver ClassFileInstaller -jar hello.jar HelloUnload ClassUnloadCommon ClassUnloadCommon$1 ClassUnloadCommon$TestFailure
+ * @run driver ClassFileInstaller -jar hello_custom.jar CustomLoadee
+ * @run driver ClassFileInstaller -jar WhiteBox.jar sun.hotspot.WhiteBox
+ * @run driver HelloDynamicCustom
+ */
+
+import java.io.File;
+import jdk.test.lib.process.OutputAnalyzer;
+import jdk.test.lib.process.ProcessTools;
+
+public class HelloDynamicCustom {
+ private static final String ARCHIVE_NAME =
+ System.getProperty("test.classes") + File.separator + "HelloDynamicCustom.jsa";
+
+ public static void main(String[] args) throws Exception {
+ String wbJar = ClassFileInstaller.getJarPath("WhiteBox.jar");
+ String use_whitebox_jar = "-Xbootclasspath/a:" + wbJar;
+ String appJar = ClassFileInstaller.getJarPath("hello.jar");
+ String customJarPath = ClassFileInstaller.getJarPath("hello_custom.jar");
+ String mainAppClass = "HelloUnload";
+
+ ProcessBuilder dumpPb = ProcessTools.createJavaProcessBuilder(true,
+ use_whitebox_jar,
+ "-XX:+UnlockDiagnosticVMOptions",
+ "-XX:+WhiteBoxAPI",
+ "-Xlog:cds",
+ "-Xlog:cds+dynamic=debug",
+ "-Xshare:auto",
+ "-XX:ArchiveClassesAtExit=" + ARCHIVE_NAME,
+ "-cp", appJar,
+ mainAppClass, customJarPath, "false", "false");
+ TestCommon.executeAndLog(dumpPb, "dump")
+ .shouldContain("Buffer-space to target-space delta")
+ .shouldContain("Written dynamic archive 0x")
+ .shouldNotContain("klasses.*=.*CustomLoadee") // Fixme -- use a better way to decide if a class has been archived
+ .shouldHaveExitValue(0);
+
+ ProcessBuilder execPb = ProcessTools.createJavaProcessBuilder(true,
+ use_whitebox_jar,
+ "-XX:+UnlockDiagnosticVMOptions",
+ "-XX:+WhiteBoxAPI",
+ "-Xlog:class+load",
+ "-Xlog:cds=debug",
+ "-Xlog:cds+dynamic=info",
+ "-Xshare:auto",
+ "-XX:SharedArchiveFile=" + ARCHIVE_NAME,
+ "-cp", appJar,
+ mainAppClass, customJarPath, "false", "true");
+ TestCommon.executeAndLog(execPb, "exec")
+ .shouldContain("HelloUnload source: shared objects file")
+ .shouldContain("CustomLoadee source: shared objects file")
+ .shouldHaveExitValue(0);
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/runtime/appcds/dynamicArchive/HelloDynamicCustomUnload.java Thu May 23 11:07:37 2019 +0100
@@ -0,0 +1,93 @@
+/*
+ * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+/*
+ * @test
+ * @summary Hello World test for dynamic archive with custom loader.
+ * Attempt will be made to unload the custom loader during
+ * dump time and run time. The custom loader will be unloaded
+ * during dump time.
+ * @requires vm.cds
+ * @library /test/lib /test/hotspot/jtreg/runtime/appcds /test/hotspot/jtreg/runtime/appcds/customLoader/test-classes /runtime/testlibrary
+ * @build HelloUnload CustomLoadee ClassUnloadCommon
+ * @build sun.hotspot.WhiteBox
+ * @run driver ClassFileInstaller -jar hello.jar HelloUnload ClassUnloadCommon ClassUnloadCommon$1 ClassUnloadCommon$TestFailure
+ * @run driver ClassFileInstaller -jar hello_custom.jar CustomLoadee
+ * @run driver ClassFileInstaller -jar WhiteBox.jar sun.hotspot.WhiteBox
+ * @run driver HelloDynamicCustomUnload
+ */
+
+import java.io.File;
+
+public class HelloDynamicCustomUnload extends DynamicArchiveTestBase {
+ private static final String ARCHIVE_NAME =
+ System.getProperty("test.classes") + File.separator + "HelloDynamicCustomUnload.jsa";
+
+ public static void main(String[] args) throws Exception {
+ runTest(HelloDynamicCustomUnload::testDefaultBase);
+ }
+
+ static void testDefaultBase() throws Exception {
+ String topArchiveName = getNewArchiveName("HelloDynamicCustomUnload-top");
+ doTest(topArchiveName);
+ }
+
+ private static void doTest(String topArchiveName) throws Exception {
+ String wbJar = ClassFileInstaller.getJarPath("WhiteBox.jar");
+ String use_whitebox_jar = "-Xbootclasspath/a:" + wbJar;
+ String appJar = ClassFileInstaller.getJarPath("hello.jar");
+ String customJarPath = ClassFileInstaller.getJarPath("hello_custom.jar");
+ String mainAppClass = "HelloUnload";
+
+ dump(topArchiveName,
+ use_whitebox_jar,
+ "-XX:+UnlockDiagnosticVMOptions",
+ "-XX:+WhiteBoxAPI",
+ "-Xmn8m",
+ "-Xlog:cds,cds+dynamic=debug,class+unload=debug",
+ "-XX:ArchiveClassesAtExit=" + ARCHIVE_NAME,
+ "-cp", appJar,
+ mainAppClass, customJarPath, "true", "false")
+ .assertNormalExit(output -> {
+ output.shouldContain("Buffer-space to target-space delta")
+ .shouldContain("Written dynamic archive 0x")
+ .shouldNotContain("klasses.*=.*CustomLoadee") // Fixme -- use a better way to decide if a class has been archived
+ .shouldHaveExitValue(0);
+ });
+
+ run(topArchiveName,
+ use_whitebox_jar,
+ "-XX:+UnlockDiagnosticVMOptions",
+ "-XX:+WhiteBoxAPI",
+ "-Xlog:class+load,cds=debug,class+unload=debug",
+ "-XX:SharedArchiveFile=" + ARCHIVE_NAME,
+ "-cp", appJar,
+ mainAppClass, customJarPath, "true", "false")
+ .assertNormalExit(output -> {
+ output.shouldContain("HelloUnload source: shared objects file")
+ .shouldMatch(".class.load. CustomLoadee source:.*hello_custom.jar")
+ .shouldHaveExitValue(0);
+ });
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/runtime/appcds/dynamicArchive/JITInteraction.java Thu May 23 11:07:37 2019 +0100
@@ -0,0 +1,65 @@
+/*
+ * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+/*
+ * @test
+ * @summary Test interaction with JIT threads during vm exit.
+ * @requires vm.cds
+ * @library /test/lib /test/hotspot/jtreg/runtime/appcds /test/hotspot/jtreg/runtime/appcds/dynamicArchive/test-classes
+ * @build TestJIT
+ * @modules jdk.jartool/sun.tools.jar
+ * @build sun.hotspot.WhiteBox
+ * @run driver ClassFileInstaller -jar WhiteBox.jar sun.hotspot.WhiteBox
+ * @run driver ClassFileInstaller -jar testjit.jar TestJIT
+ * @run driver JITInteraction
+ */
+
+public class JITInteraction extends DynamicArchiveTestBase {
+
+ public static void main(String[] args) throws Exception {
+ runTest(JITInteraction::testDefaultBase);
+ }
+
+ // Test with default base archive + top archive
+ static void testDefaultBase() throws Exception {
+ String topArchiveName = getNewArchiveName("top");
+ doTest(topArchiveName);
+ }
+
+ private static void doTest(String topArchiveName) throws Exception {
+ String appJar = ClassFileInstaller.getJarPath("testjit.jar");
+ String mainClass = "TestJIT";
+
+ dump2_WB(null, topArchiveName,
+ "-Xlog:cds",
+ "-Xlog:cds+dynamic",
+ "-XX:-UseOnStackReplacement",
+ "-XX:+PrintCompilation",
+ "-cp", appJar, mainClass)
+ .assertNormalExit(output -> {
+ output.shouldContain("Buffer-space to target-space delta")
+ .shouldContain("Written dynamic archive 0x");
+ });
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/runtime/appcds/dynamicArchive/MainModuleOnly.java Thu May 23 11:07:37 2019 +0100
@@ -0,0 +1,259 @@
+/*
+ * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+/**
+ * @test
+ * @requires vm.cds
+ * @library /test/lib /test/hotspot/jtreg/runtime/appcds
+ * @modules jdk.compiler
+ * jdk.jartool/sun.tools.jar
+ * jdk.jlink
+ * @run driver MainModuleOnly
+ * @summary Test some scenarios with a main modular jar specified in the --module-path and -cp options in the command line.
+ */
+
+import java.io.File;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.Arrays;
+
+import jdk.test.lib.process.OutputAnalyzer;
+import jdk.test.lib.Platform;
+
+public class MainModuleOnly extends DynamicArchiveTestBase {
+
+ private static final Path USER_DIR = Paths.get(System.getProperty("user.dir"));
+
+ private static final String FS = File.separator;
+ private static final String TEST_SRC = System.getProperty("test.src") +
+ FS + ".." + FS + "jigsaw" + FS + "modulepath";
+
+ private static final Path SRC_DIR = Paths.get(TEST_SRC, "src");
+ private static final Path MODS_DIR = Paths.get("mods");
+
+ // the module name of the test module
+ private static final String TEST_MODULE1 = "com.simple";
+
+ // the module main class
+ private static final String MAIN_CLASS = "com.simple.Main";
+
+ private static Path moduleDir = null;
+ private static Path moduleDir2 = null;
+ private static Path destJar = null;
+
+ public static void buildTestModule() throws Exception {
+
+ // javac -d mods/$TESTMODULE --module-path MOD_DIR src/$TESTMODULE/**
+ JarBuilder.compileModule(SRC_DIR.resolve(TEST_MODULE1),
+ MODS_DIR.resolve(TEST_MODULE1),
+ MODS_DIR.toString());
+
+
+ moduleDir = Files.createTempDirectory(USER_DIR, "mlib");
+ moduleDir2 = Files.createTempDirectory(USER_DIR, "mlib2");
+
+ Path srcJar = moduleDir.resolve(TEST_MODULE1 + ".jar");
+ destJar = moduleDir2.resolve(TEST_MODULE1 + ".jar");
+ String classes = MODS_DIR.resolve(TEST_MODULE1).toString();
+ JarBuilder.createModularJar(srcJar.toString(), classes, MAIN_CLASS);
+ Files.copy(srcJar, destJar);
+
+ }
+
+ static void testDefaultBase() throws Exception {
+ String topArchiveName = getNewArchiveName("top");
+ doTest(topArchiveName);
+ }
+
+ public static void main(String... args) throws Exception {
+ runTest(MainModuleOnly::testDefaultBase);
+ }
+
+ public static void doTest(String topArchiveName) throws Exception {
+ // compile the modules and create the modular jar files
+ buildTestModule();
+ // create an archive with both -cp and --module-path in the command line.
+ // Only the class in the modular jar in the --module-path will be archived;
+ // the class in the modular jar in the -cp won't be archived.
+ dump2(null, topArchiveName,
+ "-Xlog:cds+dynamic=debug,cds=debug",
+ "-cp", destJar.toString(),
+ "--module-path", moduleDir.toString(),
+ "-m", TEST_MODULE1)
+ .assertNormalExit(output -> {
+ output.shouldContain("Buffer-space to target-space delta")
+ .shouldContain("Written dynamic archive 0x");
+ });
+
+ // run with the archive using the same command line as in dump time.
+ // The main class should be loaded from the archive.
+ run2(null, topArchiveName,
+ "-Xlog:cds+dynamic=debug,cds=debug,class+load=trace",
+ "-cp", destJar.toString(),
+ "--module-path", moduleDir.toString(),
+ "-m", TEST_MODULE1)
+ .assertNormalExit(output -> {
+ output.shouldContain("[class,load] com.simple.Main source: shared objects file")
+ .shouldHaveExitValue(0);
+ });
+
+ // run with the archive with the main class name inserted before the -m.
+ // The main class name will be picked up before the module name. So the
+ // main class should be loaded from the jar in the -cp.
+ run2(null, topArchiveName,
+ "-Xlog:cds+dynamic=debug,cds=debug,class+load=trace",
+ "-cp", destJar.toString(),
+ "--module-path", moduleDir.toString(),
+ MAIN_CLASS, "-m", TEST_MODULE1)
+ .assertNormalExit(out ->
+ out.shouldMatch(".class.load. com.simple.Main source:.*com.simple.jar"));
+
+ // run with the archive with exploded module. Since during dump time, we
+ // only archive classes from the modular jar in the --module-path, the
+ // main class should be loaded from the exploded module directory.
+ run2(null, topArchiveName,
+ "-Xlog:cds+dynamic=debug,cds=debug,class+load=trace",
+ "-cp", destJar.toString(),
+ "--module-path", MODS_DIR.toString(),
+ "-m", TEST_MODULE1 + "/" + MAIN_CLASS)
+ .assertNormalExit(out -> {
+ out.shouldMatch(".class.load. com.simple.Main source:.*com.simple")
+ .shouldContain(MODS_DIR.toString());
+ });
+
+ // run with the archive with the --upgrade-module-path option.
+ // CDS will be disabled with this options and the main class will be
+ // loaded from the modular jar.
+ run2(null, topArchiveName,
+ "-Xlog:cds+dynamic=debug,cds=debug,class+load=trace",
+ "-cp", destJar.toString(),
+ "--upgrade-module-path", moduleDir.toString(),
+ "--module-path", moduleDir.toString(),
+ "-m", TEST_MODULE1)
+ .assertSilentlyDisabledCDS(out -> {
+ out.shouldHaveExitValue(0)
+ .shouldMatch("CDS is disabled when the.*option is specified")
+ .shouldMatch(".class.load. com.simple.Main source:.*com.simple.jar");
+ });
+ // run with the archive with the --limit-modules option.
+ // CDS will be disabled with this options and the main class will be
+ // loaded from the modular jar.
+ run2(null, topArchiveName,
+ "-Xlog:cds+dynamic=debug,cds=debug,class+load=trace",
+ "-cp", destJar.toString(),
+ "--limit-modules", "java.base," + TEST_MODULE1,
+ "--module-path", moduleDir.toString(),
+ "-m", TEST_MODULE1)
+ .assertSilentlyDisabledCDS(out -> {
+ out.shouldHaveExitValue(0)
+ .shouldMatch("CDS is disabled when the.*option is specified")
+ .shouldMatch(".class.load. com.simple.Main source:.*com.simple.jar");
+ });
+ // run with the archive with the --patch-module option.
+ // CDS will be disabled with this options and the main class will be
+ // loaded from the modular jar.
+ run2(null, topArchiveName,
+ "-Xlog:cds+dynamic=debug,cds=debug,class+load=trace",
+ "-cp", destJar.toString(),
+ "--patch-module", TEST_MODULE1 + "=" + MODS_DIR.toString(),
+ "--module-path", moduleDir.toString(),
+ "-m", TEST_MODULE1)
+ .assertSilentlyDisabledCDS(out -> {
+ out.shouldHaveExitValue(0)
+ .shouldMatch("CDS is disabled when the.*option is specified")
+ .shouldMatch(".class.load. com.simple.Main source:.*com.simple.jar");
+ });
+ // modify the timestamp of the jar file
+ (new File(destJar.toString())).setLastModified(System.currentTimeMillis() + 2000);
+ // run with the archive and the jar with modified timestamp.
+ // It should fail due to timestamp of the jar doesn't match the one
+ // used during dump time.
+ run2(null, topArchiveName,
+ "-Xlog:cds+dynamic=debug,cds=debug,class+load=trace",
+ "-cp", destJar.toString(),
+ "--module-path", moduleDir.toString(),
+ "-m", TEST_MODULE1)
+ .assertAbnormalExit(
+ "A jar file is not the one used while building the shared archive file:");
+ // create an archive with a non-empty directory in the --module-path.
+ // The dumping process will exit with an error due to non-empty directory
+ // in the --module-path.
+ dump2(null, topArchiveName,
+ "-Xlog:cds+dynamic=debug,cds=debug",
+ "-cp", destJar.toString(),
+ "--module-path", MODS_DIR.toString(),
+ "-m", TEST_MODULE1 + "/" + MAIN_CLASS)
+ .assertAbnormalExit(output -> {
+ output.shouldMatch("Error: non-empty directory.*com.simple");
+ });
+
+ // test module path with very long length
+ //
+ // This test can't be run on the windows platform due to an existing
+ // issue in ClassLoader::get_canonical_path() (JDK-8190737).
+ if (Platform.isWindows()) {
+ System.out.println("Long module path test cannot be tested on the Windows platform.");
+ return;
+ }
+ Path longDir = USER_DIR;
+ int pathLen = longDir.toString().length();
+ int PATH_LEN = 2034;
+ int MAX_DIR_LEN = 250;
+ while (pathLen < PATH_LEN) {
+ int remaining = PATH_LEN - pathLen;
+ int subPathLen = remaining > MAX_DIR_LEN ? MAX_DIR_LEN : remaining;
+ char[] chars = new char[subPathLen];
+ Arrays.fill(chars, 'x');
+ String subPath = new String(chars);
+ longDir = Paths.get(longDir.toString(), subPath);
+ pathLen = longDir.toString().length();
+ }
+ File longDirFile = new File(longDir.toString());
+ try {
+ longDirFile.mkdirs();
+ } catch (Exception e) {
+ throw e;
+ }
+ Path longDirJar = longDir.resolve(TEST_MODULE1 + ".jar");
+ // IOException results from the Files.copy() call on platform
+ // such as MacOS X. Test can't be proceeded further with the
+ // exception.
+ try {
+ Files.copy(destJar, longDirJar);
+ } catch (java.io.IOException ioe) {
+ System.out.println("Caught IOException from Files.copy(). Cannot continue.");
+ return;
+ }
+ dump2(null, topArchiveName,
+ "-Xlog:cds+dynamic=debug,cds=debug",
+ "-cp", destJar.toString(),
+ "-Xlog:exceptions=trace",
+ "--module-path", longDirJar.toString(),
+ "-m", TEST_MODULE1)
+ .ifAbnormalExit(output -> {
+ output.shouldMatch("os::stat error.*CDS dump aborted");
+ });
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/runtime/appcds/dynamicArchive/MethodSorting.java Thu May 23 11:07:37 2019 +0100
@@ -0,0 +1,62 @@
+/*
+ * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+/*
+ * @test
+ * @summary When HelloA and HelloB are copied into the dynamic archive, the Symbols
+ * for their method's names will have a different sorting order. This requires
+ * that the dumped InstanceKlass to re-sort their "methods" array and re-layout the vtables/itables.
+ * A regression test for an earlier bug in DynamicArchiveBuilder::relocate_buffer_to_target().
+ * @requires vm.cds
+ * @library /test/lib /test/hotspot/jtreg/runtime/appcds /test/hotspot/jtreg/runtime/appcds/test-classes
+ * /test/hotspot/jtreg/runtime/appcds/dynamicArchive/test-classes
+ * @build MethodSortingApp
+ * @run driver ClassFileInstaller -jar method_sorting.jar
+ * MethodSortingApp
+ * MethodSortingApp$HelloA
+ * MethodSortingApp$HelloA1
+ * MethodSortingApp$HelloB
+ * MethodSortingApp$HelloB1
+ * MethodSortingApp$InterfaceA
+ * MethodSortingApp$InterfaceB
+ * MethodSortingApp$ImplementorA
+ * MethodSortingApp$ImplementorA1
+ * MethodSortingApp$ImplementorB
+ * MethodSortingApp$ImplementorB1
+ * @run driver MethodSorting
+ */
+
+public class MethodSorting extends DynamicArchiveTestBase {
+ public static void main(String[] args) throws Exception {
+ runTest(MethodSorting::test);
+ }
+
+ static void test() throws Exception {
+ String topArchiveName = getNewArchiveName();
+ String appJar = ClassFileInstaller.getJarPath("method_sorting.jar");
+ String mainClass = "MethodSortingApp";
+
+ dumpAndRun(topArchiveName, "-Xlog:cds+dynamic=debug", "-cp", appJar, mainClass);
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/runtime/appcds/dynamicArchive/MissingArchive.java Thu May 23 11:07:37 2019 +0100
@@ -0,0 +1,101 @@
+/*
+ * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+import java.io.File;
+
+/*
+ * @test
+ * @summary error handling when either (or both) of the base/top archives are missing.
+ * @requires vm.cds
+ * @library /test/lib /test/hotspot/jtreg/runtime/appcds /test/hotspot/jtreg/runtime/appcds/test-classes
+ * @build GenericTestApp sun.hotspot.WhiteBox
+ * @run driver ClassFileInstaller -jar WhiteBox.jar sun.hotspot.WhiteBox
+ * @run driver ClassFileInstaller -jar GenericTestApp.jar GenericTestApp
+ * @run driver MissingArchive
+ */
+
+public class MissingArchive extends DynamicArchiveTestBase {
+ private static final String TOP = "top";
+ private static final String BASE = "base";
+ private static final String BOTH = "base/top";
+ private static final String NONE = "none";
+
+ public static void main(String[] args) throws Exception {
+ runTest(MissingArchive::test, TOP);
+ runTest(MissingArchive::test, BASE);
+ runTest(MissingArchive::test, BOTH);
+ runTest(MissingArchive::test, NONE);
+ }
+
+ static void delete(String fileName) {
+ File f = new File(fileName);
+ f.delete();
+ }
+
+ static void test(String args[]) throws Exception {
+ String topArchiveName = getNewArchiveName("top");
+ String baseArchiveName = getNewArchiveName("base");
+ dumpBaseArchive(baseArchiveName);
+
+ String appJar = ClassFileInstaller.getJarPath("GenericTestApp.jar");
+ String mainClass = "GenericTestApp";
+ dump2_WB(baseArchiveName, topArchiveName,
+ "-Xlog:cds",
+ "-Xlog:cds+dynamic=debug",
+ "-cp", appJar, mainClass)
+ .assertNormalExit(output -> {
+ output.shouldContain("Buffer-space to target-space delta")
+ .shouldContain("Written dynamic archive 0x");
+ });
+
+ // Use -Xshare:auto so top archive can fail after base archive has succeeded,
+ // but the app will continue to run.
+ String[] cmdline = TestCommon.concat(
+ "-Xlog:cds*",
+ "-Xshare:auto",
+ "-cp", appJar, mainClass);
+
+
+ String mode = args[0];
+
+ if (mode.contains(BASE)) {
+ delete(baseArchiveName);
+ cmdline = TestCommon.concat(cmdline, "assertNotShared:java.lang.Object");
+ } else {
+ cmdline = TestCommon.concat(cmdline, "assertShared:java.lang.Object");
+ }
+
+ if (mode.contains(TOP)) {
+ delete(topArchiveName);
+ }
+
+ if (mode.equals(NONE)) {
+ cmdline = TestCommon.concat(cmdline, "assertShared:GenericTestApp");
+ } else {
+ cmdline = TestCommon.concat(cmdline, "assertNotShared:GenericTestApp");
+ }
+
+ run2_WB(baseArchiveName, topArchiveName, cmdline).assertNormalExit();
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/runtime/appcds/dynamicArchive/NoClassToArchive.java Thu May 23 11:07:37 2019 +0100
@@ -0,0 +1,111 @@
+/*
+ * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+/*
+ * @test
+ * @summary A few edge cases where there's no class to be included in the dynamic archive.
+ * @requires vm.cds
+ * @library /test/lib /test/hotspot/jtreg/runtime/appcds /test/hotspot/jtreg/runtime/appcds/dynamicArchive/test-classes
+ * @build StrConcatApp
+ * @run driver ClassFileInstaller -jar strConcatApp.jar StrConcatApp
+ * @run driver NoClassToArchive
+ */
+
+import java.io.File;
+import jdk.test.lib.process.OutputAnalyzer;
+import jdk.test.lib.process.ProcessTools;
+
+public class NoClassToArchive extends DynamicArchiveTestBase {
+ static final String warningMessage =
+ "There is no class to be included in the dynamic archive";
+ static final String classList = System.getProperty("test.classes") +
+ File.separator + "NoClassToArchive.list";
+ static final String appClass = "StrConcatApp";
+
+ public static void main(String[] args) throws Exception {
+ runTest(NoClassToArchive::testDefaultBase);
+ runTest(NoClassToArchive::testCustomBase);
+ }
+
+ // (1) Test with default base archive + top archive
+ static void testDefaultBase() throws Exception {
+ String topArchiveName = getNewArchiveName("top");
+ doTest(null, topArchiveName);
+ }
+
+ // (2) Test with custom base archive + top archive
+ static void testCustomBase() throws Exception {
+ String topArchiveName = getNewArchiveName("top2");
+ String baseArchiveName = getNewArchiveName("base");
+ doTestCustomBase(baseArchiveName, topArchiveName);
+ }
+
+ private static void doTest(String baseArchiveName, String topArchiveName) throws Exception {
+ dump2(baseArchiveName, topArchiveName,
+ "-Xlog:cds",
+ "-Xlog:cds+dynamic=debug",
+ "-Xlog:class+load=trace",
+ "-version")
+ .assertNormalExit(output -> {
+ if (output.getStdout().contains("jrt:/")) {
+ System.out.println("test skipped: this platform uses non-archived classes when running -version");
+ } else {
+ output.shouldContain(warningMessage);
+ }
+ });
+
+ dump2(baseArchiveName, topArchiveName,
+ "-Xlog:cds",
+ "-Xlog:cds+dynamic=debug",
+ "-Xlog:class+load=trace",
+ "-help")
+ .assertNormalExit(output -> {
+ // some classes will be loaded from the java.base module
+ output.shouldContain("java.text.MessageFormat source: jrt:/java.base");
+ });
+ }
+
+ private static void doTestCustomBase(String baseArchiveName, String topArchiveName) throws Exception {
+ String appJar = ClassFileInstaller.getJarPath("strConcatApp.jar");
+ // dump class list by running the StrConcatApp
+ ProcessBuilder pb = ProcessTools.createJavaProcessBuilder(
+ true,
+ "-XX:DumpLoadedClassList=" + classList,
+ "-cp",
+ appJar,
+ appClass);
+ OutputAnalyzer output = TestCommon.executeAndLog(pb, "dumpClassList");
+ TestCommon.checkExecReturn(output, 0, true, "length = 0");
+
+ // create a custom base archive based on the class list
+ dumpBaseArchive(baseArchiveName, "-XX:SharedClassListFile=" + classList);
+
+ // create a dynamic archive with the custom base archive
+ // no class should be included in the dynamic archive
+ dump2(baseArchiveName, topArchiveName, "-version")
+ .assertNormalExit(out -> {
+ out.shouldMatch(warningMessage);
+ });
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/runtime/appcds/dynamicArchive/SharedArchiveFileOption.java Thu May 23 11:07:37 2019 +0100
@@ -0,0 +1,150 @@
+/*
+ * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+/*
+ * @test
+ * @summary Some negative tests for the SharedArchiveFile option
+ * @requires vm.cds
+ * @library /test/lib /test/hotspot/jtreg/runtime/appcds /test/hotspot/jtreg/runtime/appcds/test-classes
+ * @build Hello
+ * @run driver ClassFileInstaller -jar hello.jar Hello
+ * @run driver SharedArchiveFileOption
+ */
+
+import java.io.File;
+
+public class SharedArchiveFileOption extends DynamicArchiveTestBase {
+ public static void main(String[] args) throws Exception {
+ runTest(SharedArchiveFileOption::testCustomBase);
+ }
+
+ static String baseArchiveName2;
+ static void testCustomBase() throws Exception {
+ String topArchiveName = getNewArchiveName("top");
+ String baseArchiveName = getNewArchiveName("base");
+ baseArchiveName2 = getNewArchiveName("base2");
+ dumpBaseArchive(baseArchiveName);
+ dumpBaseArchive(baseArchiveName2);
+ doTest(baseArchiveName, topArchiveName);
+ }
+
+ private static void doTest(String baseArchiveName, String topArchiveName) throws Exception {
+ String appJar = ClassFileInstaller.getJarPath("hello.jar");
+ String mainClass = "Hello";
+ String dummyArchiveName = getNewArchiveName("dummy");
+
+ // -Xshare:dump specified with -XX:ArchiveClassesAtExit
+ dump2(dummyArchiveName, dummyArchiveName,
+ "-Xlog:cds",
+ "-Xlog:cds+dynamic=debug",
+ "-Xshare:dump",
+ "-cp", appJar, mainClass)
+ .assertAbnormalExit(output -> {
+ output.shouldContain("-XX:ArchiveClassesAtExit cannot be used with -Xshare:dump");
+ });
+
+ // more than 1 archive file specified in -XX:SharedArchiveFile during
+ // dynamic dumpgin
+ String dummyArchives = dummyArchiveName + File.pathSeparator + dummyArchiveName;
+ dump2(dummyArchives, dummyArchiveName,
+ "-Xlog:cds",
+ "-Xlog:cds+dynamic=debug",
+ "-cp", appJar, mainClass)
+ .assertAbnormalExit(output -> {
+ output.shouldContain("Cannot have more than 1 archive file specified in -XX:SharedArchiveFile during CDS dumping");
+ });
+
+ // normal dynamic archive dumping
+ dump2(baseArchiveName, topArchiveName,
+ "-Xlog:cds",
+ "-Xlog:cds+dynamic=debug",
+ "-cp", appJar, mainClass)
+ .assertNormalExit(output -> {
+ output.shouldContain("Buffer-space to target-space delta")
+ .shouldContain("Written dynamic archive 0x");
+ });
+
+ // same archive file specified for -XX:SharedArchiveFile and -XX:ArchiveClassesAtExit
+ dump2(baseArchiveName, baseArchiveName,
+ "-Xlog:cds",
+ "-Xlog:cds+dynamic=debug",
+ "-cp", appJar, mainClass)
+ .assertAbnormalExit(output -> {
+ output.shouldContain("Cannot have the same archive file specified for -XX:SharedArchiveFile and -XX:ArchiveClassesAtExit: "
+ + baseArchiveName);
+ });
+
+
+ // a top archive specified in the base archive position
+ run2(topArchiveName, baseArchiveName,
+ "-Xlog:class+load",
+ "-Xlog:cds+dynamic=debug,cds=debug",
+ "-cp", appJar, mainClass)
+ .assertAbnormalExit(output -> {
+ output.shouldMatch("Not a base shared archive:.*top.*.jsa");
+ });
+
+ // a base archive specified in the top archive position
+ run2(baseArchiveName, baseArchiveName2,
+ "-Xlog:class+load",
+ "-Xlog:cds+dynamic=debug,cds=debug",
+ "-cp", appJar, mainClass)
+ .assertAbnormalExit(output -> {
+ output.shouldMatch("Not a top shared archive:.*base.*.jsa");
+ });
+
+ // more than 2 archives specified in the -XX:ShareArchiveFile option
+ String baseArchives = baseArchiveName + File.pathSeparator + baseArchiveName2;
+ run2(baseArchives, topArchiveName,
+ "-Xlog:class+load",
+ "-Xlog:cds+dynamic=debug,cds=debug",
+ "-cp", appJar, mainClass)
+ .assertAbnormalExit(output -> {
+ output.shouldContain(
+ "Cannot have more than 2 archive files specified in the -XX:SharedArchiveFile option");
+ });
+
+ // base archive not specified
+ final String topArchive = File.pathSeparator + topArchiveName;
+ run2(topArchive, null,
+ "-Xlog:class+load",
+ "-Xlog:cds+dynamic=debug,cds=debug",
+ "-cp", appJar, mainClass)
+ .assertAbnormalExit(output -> {
+ output.shouldContain(
+ "Base archive was not specified: " + topArchive);
+ });
+
+ // top archive not specified
+ final String baseArchive = baseArchiveName + File.pathSeparator;
+ run2(baseArchive, null,
+ "-Xlog:class+load",
+ "-Xlog:cds+dynamic=debug,cds=debug",
+ "-cp", appJar, mainClass)
+ .assertAbnormalExit(output -> {
+ output.shouldContain(
+ "Top archive was not specified: " + baseArchive);
+ });
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/runtime/appcds/dynamicArchive/UnsupportedBaseArchive.java Thu May 23 11:07:37 2019 +0100
@@ -0,0 +1,125 @@
+/*
+ * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+import java.io.File;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+
+/*
+ * @test
+ * @summary unsupported base archive tests
+ * @requires vm.cds
+ * @library /test/lib /test/hotspot/jtreg/runtime/appcds /test/hotspot/jtreg/runtime/appcds/test-classes
+ * @modules jdk.jartool/sun.tools.jar
+ * @compile ../test-classes/Hello.java
+ * @build sun.hotspot.WhiteBox
+ * @run driver ClassFileInstaller -jar WhiteBox.jar sun.hotspot.WhiteBox
+ * @run driver UnsupportedBaseArchive
+ */
+
+public class UnsupportedBaseArchive extends DynamicArchiveTestBase {
+ private static final Path USER_DIR = Paths.get(System.getProperty("user.dir"));
+
+ private static final String FS = File.separator;
+ private static final String TEST_SRC = System.getProperty("test.src") +
+ FS + ".." + FS + "jigsaw" + FS + "modulepath";
+
+ private static final Path SRC_DIR = Paths.get(TEST_SRC, "src");
+ private static final Path MODS_DIR = Paths.get("mods");
+
+ // the module name of the test module
+ private static final String TEST_MODULE = "com.simple";
+
+ // the module main class
+ private static final String MAIN_CLASS = "com.simple.Main";
+
+ private static Path moduleDir = null;
+ private static Path srcJar = null;
+
+ private static final String warningBCP =
+ "Dynamic archiving is disabled because base layer archive has appended boot classpath";
+
+ private static final String warningModulePath =
+ "Dynamic archiving is disabled because base layer archive has module path";
+
+ public static void buildTestModule() throws Exception {
+
+ // javac -d mods/$TESTMODULE --module-path MOD_DIR src/$TESTMODULE/**
+ JarBuilder.compileModule(SRC_DIR.resolve(TEST_MODULE),
+ MODS_DIR.resolve(TEST_MODULE),
+ MODS_DIR.toString());
+
+
+ moduleDir = Files.createTempDirectory(USER_DIR, "mlib");
+ srcJar = moduleDir.resolve(TEST_MODULE + ".jar");
+ String classes = MODS_DIR.resolve(TEST_MODULE).toString();
+ JarBuilder.createModularJar(srcJar.toString(), classes, MAIN_CLASS);
+ }
+
+ public static void main(String[] args) throws Exception {
+ runTest(UnsupportedBaseArchive::test);
+ }
+
+ static void test(String args[]) throws Exception {
+ String topArchiveName = getNewArchiveName("top");
+ String baseArchiveName = getNewArchiveName("base");
+
+ // create a base archive with -Xbootclasspath/a:whitebox.jar
+ dumpBaseArchive_WB(baseArchiveName);
+
+ String appJar = JarBuilder.getOrCreateHelloJar();
+ String mainClass = "Hello";
+
+ // dumping of dynamic archive should be disabled with a warning message
+ // if the base archive contains -Xbootclasspath/a entries.
+ dump2_WB(baseArchiveName, topArchiveName,
+ "-Xlog:cds*",
+ "-Xlog:cds+dynamic=debug",
+ "-Xlog:class+path=info",
+ "-cp", appJar, mainClass)
+ .assertNormalExit(warningBCP);
+
+ // create a base archive with the --module-path option
+ buildTestModule();
+ baseArchiveName = getNewArchiveName("base-with-module");
+ dumpBaseArchive(baseArchiveName,
+ "-cp", srcJar.toString(),
+ "--module-path", moduleDir.toString(),
+ "-m", TEST_MODULE);
+
+ // dumping of dynamic archive should be disabled with a warning message
+ // if the base archive contains --module-path entries.
+ topArchiveName = getNewArchiveName("top-with-module");
+ dump2(baseArchiveName, topArchiveName,
+ "-Xlog:cds*",
+ "-Xlog:cds+dynamic=debug",
+ "-Xlog:class+path=info",
+ "-cp", srcJar.toString(),
+ "--module-path", moduleDir.toString(),
+ "-m", TEST_MODULE)
+ .assertNormalExit(warningModulePath);
+
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/runtime/appcds/dynamicArchive/UnusedCPDuringDump.java Thu May 23 11:07:37 2019 +0100
@@ -0,0 +1,84 @@
+/*
+ * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+/*
+ * @test
+ * @summary non-empty dir in -cp should be fine during dump time if only classes
+ * from the system modules are being loaded even though some are
+ * defined to the PlatformClassLoader and AppClassLoader.
+ * @requires vm.cds
+ * @library /test/lib /test/hotspot/jtreg/runtime/appcds
+ * @modules jdk.jartool/sun.tools.jar
+ * @compile ../test-classes/Hello.java
+ * @run main/othervm -Dtest.cds.copy.child.stdout=false UnusedCPDuringDump
+ */
+
+import java.io.File;
+
+public class UnusedCPDuringDump extends DynamicArchiveTestBase {
+
+ public static void main(String[] args) throws Exception {
+ runTest(UnusedCPDuringDump::testDefaultBase);
+ }
+
+ static void testDefaultBase() throws Exception {
+ String topArchiveName = getNewArchiveName("top");
+ doTest(topArchiveName);
+ }
+
+ private static void doTest(String topArchiveName) throws Exception {
+ File dir = new File(System.getProperty("user.dir"));
+ File emptydir = new File(dir, "emptydir");
+ emptydir.mkdir();
+ String appJar = JarBuilder.getOrCreateHelloJar();
+ String bootClassPath = "-Xbootclasspath/a:" + appJar;
+
+ // Dumping with a non-empty directory in the -cp.
+ // It should be fine because the app class won't be loaded from the
+ // -cp, it is being loaded from the bootclasspath.
+ dump(topArchiveName,
+ "-Xlog:cds",
+ "-Xlog:cds+dynamic=debug",
+ bootClassPath,
+ "-cp", dir.getPath(),
+ "Hello")
+ .assertNormalExit(output -> {
+ output.shouldContain("Buffer-space to target-space delta")
+ .shouldContain("Written dynamic archive 0x");
+ });
+
+ // Running with -cp different from dumping. It should be fine because
+ // the runtime classpath won't be checked against unused classpath
+ // during dump time.
+ run(topArchiveName,
+ "-Xlog:class+load",
+ "-Xlog:cds+dynamic=debug,cds=debug",
+ bootClassPath,
+ "-cp", appJar, "Hello")
+ .assertNormalExit(output -> {
+ output.shouldContain("Hello World")
+ .shouldHaveExitValue(0);
+ });
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/runtime/appcds/dynamicArchive/WrongTopClasspath.java Thu May 23 11:07:37 2019 +0100
@@ -0,0 +1,74 @@
+/*
+ * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+import java.io.File;
+
+/*
+ * @test
+ * @summary correct classpath for bottom archive, but bad classpath for top archive
+ * @requires vm.cds
+ * @library /test/lib /test/hotspot/jtreg/runtime/appcds /test/hotspot/jtreg/runtime/appcds/test-classes
+ * @build GenericTestApp sun.hotspot.WhiteBox
+ * @run driver ClassFileInstaller -jar WhiteBox.jar sun.hotspot.WhiteBox
+ * @run driver ClassFileInstaller -jar GenericTestApp.jar GenericTestApp
+ * @run driver ClassFileInstaller -jar WrongJar.jar GenericTestApp
+ * @run driver WrongTopClasspath
+ */
+
+public class WrongTopClasspath extends DynamicArchiveTestBase {
+
+ public static void main(String[] args) throws Exception {
+ runTest(WrongTopClasspath::test);
+ }
+
+ static void test(String args[]) throws Exception {
+ String topArchiveName = getNewArchiveName("top");
+ String baseArchiveName = getNewArchiveName("base");
+ dumpBaseArchive(baseArchiveName);
+
+ String appJar = ClassFileInstaller.getJarPath("GenericTestApp.jar");
+ String wrongJar = ClassFileInstaller.getJarPath("WrongJar.jar");
+ String mainClass = "GenericTestApp";
+
+ // Dump the top archive using "-cp GenericTestApp.jar" ...
+ dump2_WB(baseArchiveName, topArchiveName,
+ "-Xlog:cds*",
+ "-Xlog:cds+dynamic=debug",
+ "-cp", appJar, mainClass)
+ .assertNormalExit();
+
+ // ... but try to load the top archive using "-cp WrongJar.jar".
+ // Use -Xshare:auto so top archive can fail after base archive has succeeded,
+ // but the app will continue to run.
+ run2_WB(baseArchiveName, topArchiveName,
+ "-Xlog:cds*",
+ "-Xlog:cds+dynamic=debug",
+ "-Xlog:class+path=info",
+ "-Xshare:auto",
+ "-cp", wrongJar, mainClass,
+ "assertShared:java.lang.Object", // base archive still useable
+ "assertNotShared:GenericTestApp") // but top archive is not useable
+ .assertNormalExit("The top archive failed to load");
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/runtime/appcds/dynamicArchive/test-classes/ArrayKlassesApp.java Thu May 23 11:07:37 2019 +0100
@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+public class ArrayKlassesApp {
+ public static void main(String args[]) {
+ ArrayKlassesApp[][] array = new ArrayKlassesApp[1][2];
+ for (int i=0; i<1; i++) {
+ for (int j=0; j<2; j++) {
+ array[i][j] = new ArrayKlassesApp();
+ }
+ }
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/runtime/appcds/dynamicArchive/test-classes/ExcludedClassesApp.java Thu May 23 11:07:37 2019 +0100
@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+public class ExcludedClassesApp {
+ interface NotLinkedInterface {}
+ static class NotLinkedSuper {
+
+ }
+
+ static class NotLinkedChild extends NotLinkedSuper implements NotLinkedInterface {
+
+ }
+
+ public static NotLinkedSuper notUsedMethod() {
+ return new NotLinkedChild();
+ }
+
+ public static void main(String args[]) {
+
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/runtime/appcds/dynamicArchive/test-classes/LoadClasses.java Thu May 23 11:07:37 2019 +0100
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+import java.io.File;
+import java.util.List;
+import java.util.Scanner;
+import sun.hotspot.WhiteBox;
+
+public class LoadClasses {
+
+ public static void main (String[] args) throws Throwable {
+ String classList = args[0];
+ Scanner sc = new Scanner(new File(classList));
+ WhiteBox wb = WhiteBox.getWhiteBox();
+ int count = 0;
+ while (sc.hasNextLine()) {
+ String cn = sc.nextLine().replace('/', '.');
+ try {
+ Class<?> cls = Class.forName(cn, false, LoadClasses.class.getClassLoader());
+ wb.linkClass(cls);
+ count++;
+ } catch (Throwable ex) {
+ System.out.println("Loading failed: " + cn);
+ System.out.println(ex.toString());
+ }
+ }
+ System.out.println("Loaded classes = " + count);
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/runtime/appcds/dynamicArchive/test-classes/MethodSortingApp.java Thu May 23 11:07:37 2019 +0100
@@ -0,0 +1,177 @@
+/*
+ * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+import java.util.concurrent.BlockingQueue;
+import java.util.concurrent.SynchronousQueue;
+
+public class MethodSortingApp {
+ static class HelloA {
+ String aaaa() { return "aaaa"; }
+ String bbbb() { return "bbbb"; }
+ String dddd() { return "dddd"; }
+ String eeee() { return "eeee"; }
+ String gggg() { return "gggg"; }
+ }
+
+ static class HelloA1 extends HelloA {
+ String aaaa() { return "aaa-"; }
+ String dddd() { return "ddd-"; }
+ String gggg() { return "ggg-"; }
+ }
+
+ static class HelloB {
+ String aaaa() { return "aaaa"; }
+ String cccc() { return "cccc"; }
+ String dddd() { return "dddd"; }
+ String ffff() { return "ffff"; }
+ String gggg() { return "gggg"; }
+ }
+
+ static class HelloB1 extends HelloB {
+ String aaaa() { return "aaa-"; }
+ String dddd() { return "ddd-"; }
+ String gggg() { return "ggg-"; }
+ }
+
+ // Default methods in interfaces must be sorted
+ static interface InterfaceA {
+ default public String aaa() { return "aaa";}
+ default public String bbb() { return "bbb";}
+ default public String ddd() { return "ddd";}
+ default public String eee() { return "eee";}
+ default public String ggg() { return "ggg";}
+ }
+
+ static class ImplementorA implements InterfaceA {
+ public String aaa() { return "aa-";}
+ }
+
+ static class ImplementorA1 extends ImplementorA {
+ public String bbb() { return "bb-";}
+ }
+
+ static interface InterfaceB {
+ default public String aaa() { return "aaa"; }
+ default public String ccc() { return "ccc"; }
+ default public String ddd() { return "ddd"; }
+ default public String fff() { return "fff"; }
+ default public String ggg() { return "ggg"; }
+ }
+
+ static class ImplementorB implements InterfaceB {
+ public String ggg() { return "gg-";}
+ }
+
+ static class ImplementorB1 extends ImplementorB {
+ public String fff() { return "ff-";}
+ }
+
+
+ public static void main(String args[]) {
+ testSimpleMethods();
+ testDefaultMethods();
+ testMixedInterfaces();
+ }
+
+ static void testSimpleMethods() {
+ // When HelloA and HelloB are copied into the dynamic archive, the Symbols
+ // for their method's names will have a different sorting order. This requires
+ // that the dumped InstanceKlass to re-sort their "methods" array and re-layout
+ // the vtables/itables.
+ HelloA1 a1 = new HelloA1();
+ HelloA a = new HelloA();
+ assertEqual(a.aaaa(), "aaaa");
+ assertEqual(a.bbbb(), "bbbb");
+ assertEqual(a.dddd(), "dddd");
+ assertEqual(a.eeee(), "eeee");
+ assertEqual(a.gggg(), "gggg");
+
+ assertEqual(a1.aaaa(), "aaa-");
+ assertEqual(a1.bbbb(), "bbbb");
+ assertEqual(a1.dddd(), "ddd-");
+ assertEqual(a1.eeee(), "eeee");
+ assertEqual(a1.gggg(), "ggg-");
+
+ HelloB b = new HelloB();
+ assertEqual(b.aaaa(), "aaaa");
+ assertEqual(b.cccc(), "cccc");
+ assertEqual(b.dddd(), "dddd");
+ assertEqual(b.ffff(), "ffff");
+ assertEqual(b.gggg(), "gggg");
+
+ HelloB b1 = new HelloB1();
+ assertEqual(b1.aaaa(), "aaa-");
+ assertEqual(b1.cccc(), "cccc");
+ assertEqual(b1.dddd(), "ddd-");
+ assertEqual(b1.ffff(), "ffff");
+ assertEqual(b1.gggg(), "ggg-");
+ }
+
+ static void testDefaultMethods() {
+ InterfaceA a1 = new ImplementorA1();
+ InterfaceA a = new ImplementorA();
+
+ assertEqual(a.aaa(), "aa-");
+ assertEqual(a.bbb(), "bbb");
+ assertEqual(a.ddd(), "ddd");
+ assertEqual(a.eee(), "eee");
+ assertEqual(a.ggg(), "ggg");
+
+ assertEqual(a1.aaa(), "aa-");
+ assertEqual(a1.bbb(), "bb-");
+ assertEqual(a1.ddd(), "ddd");
+ assertEqual(a1.eee(), "eee");
+ assertEqual(a1.ggg(), "ggg");
+
+ InterfaceB b = new ImplementorB();
+ InterfaceB b1 = new ImplementorB1();
+
+ assertEqual(b.aaa(), "aaa");
+ assertEqual(b.ccc(), "ccc");
+ assertEqual(b.ddd(), "ddd");
+ assertEqual(b.fff(), "fff");
+ assertEqual(b.ggg(), "gg-");
+
+ assertEqual(b1.aaa(), "aaa");
+ assertEqual(b1.ccc(), "ccc");
+ assertEqual(b1.ddd(), "ddd");
+ assertEqual(b1.fff(), "ff-");
+ assertEqual(b1.ggg(), "gg-");
+ }
+
+ // This is a regression test for an earlier bug in
+ // DynamicArchiveBuilder::relocate_buffer_to_target()
+ static void testMixedInterfaces() {
+ Object xx = new SynchronousQueue();
+ BlockingQueue yy = (BlockingQueue)xx;
+ }
+
+ static private void assertEqual(String a, String b) {
+ if (!a.equals(b)) {
+ throw new RuntimeException(a + " is not equal to " + b);
+ } else {
+ System.out.println("Expected: " + a + ", got: " + b);
+ }
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/runtime/appcds/dynamicArchive/test-classes/MissingDependent.java Thu May 23 11:07:37 2019 +0100
@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+public class MissingDependent {
+ public static void main(String args[]) throws Exception {
+ try {
+ Object obj = new StrConcatApp();
+ } catch (Throwable e) {
+ String cause = e.getCause().toString();
+ if (cause.equals("java.lang.ClassNotFoundException: StrConcatApp")) {
+ e.printStackTrace();
+ } else {
+ throw e;
+ }
+ }
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/runtime/appcds/dynamicArchive/test-classes/StrConcatApp.java Thu May 23 11:07:37 2019 +0100
@@ -0,0 +1,29 @@
+/*
+ * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+public class StrConcatApp {
+ public static void main(String args[]) {
+ System.out.println("length = " + args.length);
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/runtime/appcds/dynamicArchive/test-classes/TestJIT.java Thu May 23 11:07:37 2019 +0100
@@ -0,0 +1,59 @@
+/*
+ * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+import sun.hotspot.WhiteBox;
+
+import java.lang.reflect.Method;
+import java.util.HashMap;
+
+public class TestJIT {
+
+ private static final WhiteBox WHITE_BOX = WhiteBox.getWhiteBox();
+
+ static void doSomething() {
+ HashMap<String,String> map = new HashMap<>();
+ for (int i=0; i<400; i++) {
+ // Call these methods so that the class/field/method references used
+ // by these methods are resolved. This allows C2 to compile more code.
+ String x = "Hello" + i;
+ map.put(x, x);
+ map.get(x);
+ }
+ }
+
+ static public void main(String[] args) throws NoSuchMethodException {
+ Method put_method = HashMap.class.getDeclaredMethod("put", Object.class, Object.class);
+ Method get_method = HashMap.class.getDeclaredMethod("get", Object.class);
+ Method test_method = TestJIT.class.getDeclaredMethod("doSomething");
+
+ doSomething();
+
+ // 4 == CompilerWhiteBoxTest.COMP_LEVEL_FULL_OPTIMIZATION => C2
+ WHITE_BOX.enqueueMethodForCompilation(get_method, 4);
+ WHITE_BOX.enqueueMethodForCompilation(put_method, 4);
+ WHITE_BOX.enqueueMethodForCompilation(test_method, 4);
+
+ // Try to start dynamic dumping while the above compilations are still in progesss
+ System.exit(0);
+ }
+}
--- a/test/hotspot/jtreg/runtime/appcds/jigsaw/PatchModule/MismatchedPatchModule.java Fri May 17 13:21:44 2019 +0100
+++ b/test/hotspot/jtreg/runtime/appcds/jigsaw/PatchModule/MismatchedPatchModule.java Thu May 23 11:07:37 2019 +0100
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2016, 2019, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -74,11 +74,12 @@
// Case 2: --patch-module specified for run time but not for dump time
System.out.println("Case 2: --patch-module specified for run time but not for dump time");
+ String appJar = JarBuilder.build("PatchMain-app", "PatchMain");
output =
- TestCommon.dump(null,
+ TestCommon.dump(appJar,
TestCommon.list("javax/naming/spi/NamingManager"),
"PatchMain", "javax.naming.spi.NamingManager");
- TestCommon.checkDump(output, "Loading classes to share");
+ TestCommon.checkDump(output);
// javax.naming.spi.NamingManager is patched at runtime
TestCommon.run(
--- a/test/hotspot/jtreg/runtime/appcds/jigsaw/PatchModule/PatchJavaBase.java Fri May 17 13:21:44 2019 +0100
+++ b/test/hotspot/jtreg/runtime/appcds/jigsaw/PatchModule/PatchJavaBase.java Thu May 23 11:07:37 2019 +0100
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2016, 2019, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -58,18 +58,25 @@
moduleJar = TestCommon.getTestJar("javabase.jar");
System.out.println("Test dumping with --patch-module");
+ String runError = "Unable to use shared archive: CDS is disabled when java.base module is patched";
+ String dumpingError = "Cannot use the following option when dumping the shared archive: --patch-module";
+ String errMsg;
+ if (TestCommon.isDynamicArchive()) {
+ errMsg = runError;
+ } else {
+ errMsg = dumpingError;
+ }
OutputAnalyzer output =
TestCommon.dump(null, null,
"--patch-module=java.base=" + moduleJar,
"PatchMain", "java.lang.NewClass");
output.shouldHaveExitValue(1)
- .shouldContain("Cannot use the following option when dumping the shared archive: --patch-module");
+ .shouldContain(errMsg);
TestCommon.run(
"-XX:+UnlockDiagnosticVMOptions",
"--patch-module=java.base=" + moduleJar,
"PatchMain", "java.lang.NewClass")
- .assertAbnormalExit("Unable to use shared archive",
- "CDS is disabled when java.base module is patched");
+ .assertAbnormalExit(runError);
}
}
--- a/test/hotspot/jtreg/runtime/appcds/jigsaw/PatchModule/PatchMain.java Fri May 17 13:21:44 2019 +0100
+++ b/test/hotspot/jtreg/runtime/appcds/jigsaw/PatchModule/PatchMain.java Thu May 23 11:07:37 2019 +0100
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2016, 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2016, 2019, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -27,6 +27,9 @@
public class PatchMain {
public static void main(String[] args) throws Exception {
for (int i = 0; i < args.length; i++) {
+ if (args[i].equals("cdsutils.DynamicDumpHelper")) {
+ break;
+ }
Class.forName(args[i]);
}
}
--- a/test/hotspot/jtreg/runtime/appcds/jigsaw/modulepath/AddModules.java Fri May 17 13:21:44 2019 +0100
+++ b/test/hotspot/jtreg/runtime/appcds/jigsaw/modulepath/AddModules.java Thu May 23 11:07:37 2019 +0100
@@ -29,6 +29,7 @@
* @modules jdk.compiler
* jdk.jartool/sun.tools.jar
* jdk.jlink
+ * @compile ../../test-classes/Hello.java
* @run driver AddModules
* @summary sanity test the --add-modules option
*/
@@ -63,6 +64,7 @@
private static Path subJar = null;
private static Path mainJar1 = null;
private static Path mainJar2 = null;
+ private static String appJar;
public static void buildTestModule() throws Exception {
@@ -96,18 +98,19 @@
}
public static void main(String... args) throws Exception {
+ appJar = JarBuilder.getOrCreateHelloJar();
// compile the modules and create the modular jar files
buildTestModule();
String appClasses[] = {MAIN_CLASS1, MAIN_CLASS2, APP_CLASS};
// create an archive with the classes in the modules built in the
// previous step
OutputAnalyzer output = TestCommon.createArchive(
- null, appClasses,
+ appJar, appClasses,
"--module-path", moduleDir.toString(),
"--add-modules",
MAIN_MODULE1 + "," + MAIN_MODULE2);
TestCommon.checkDump(output);
- String prefix[] = {"-Djava.class.path=", "-Xlog:class+load=trace"};
+ String prefix[] = {"-Djava.class.path=" + appJar, "-Xlog:class+load=trace"};
// run the com.greetings module with the archive with the --module-path
// the same as the one during dump time.
--- a/test/hotspot/jtreg/runtime/appcds/jigsaw/modulepath/JvmtiAddPath.java Fri May 17 13:21:44 2019 +0100
+++ b/test/hotspot/jtreg/runtime/appcds/jigsaw/modulepath/JvmtiAddPath.java Thu May 23 11:07:37 2019 +0100
@@ -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
@@ -121,7 +121,9 @@
"-Xlog:class+load", "JvmtiApp", "noadd", MAIN_CLASS); // appcds should be enabled
System.out.println("Test case 2: add to boot classpath only - should find Hello.class in boot loader");
- run(check_appcds_disabled, appJar,
+ String[] toCheck = TestCommon.isDynamicArchive() ? check_appcds_enabled :
+ check_appcds_disabled;
+ run(toCheck, appJar,
"-Xlog:class+load=trace",
modulePath,
"JvmtiApp", "bootonly", addbootJar, MAIN_CLASS); // appcds should be disabled
--- a/test/hotspot/jtreg/runtime/appcds/jigsaw/modulepath/MainModuleOnly.java Fri May 17 13:21:44 2019 +0100
+++ b/test/hotspot/jtreg/runtime/appcds/jigsaw/modulepath/MainModuleOnly.java Thu May 23 11:07:37 2019 +0100
@@ -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
@@ -29,7 +29,7 @@
* @modules jdk.compiler
* jdk.jartool/sun.tools.jar
* jdk.jlink
- * @run driver MainModuleOnly
+ * @run main/othervm MainModuleOnly
* @summary Test some scenarios with a main modular jar specified in the --module-path and -cp options in the command line.
*/
@@ -39,6 +39,7 @@
import java.nio.file.Paths;
import java.util.Arrays;
+import jdk.test.lib.cds.CDSTestUtils.Result;
import jdk.test.lib.process.OutputAnalyzer;
import jdk.test.lib.Platform;
@@ -61,6 +62,8 @@
private static Path moduleDir2 = null;
private static Path destJar = null;
+ private static final String jarFileError = "A jar file is not the one used while building the shared archive file:";
+
public static void buildTestModule() throws Exception {
// javac -d mods/$TESTMODULE --module-path MOD_DIR src/$TESTMODULE/**
@@ -167,17 +170,21 @@
// run with the archive and the jar with modified timestamp.
// It should fail due to timestamp of the jar doesn't match the one
// used during dump time.
- TestCommon.run("-cp", destJar.toString(),
+ Result res = TestCommon.run("-cp", destJar.toString(),
+ "-Xlog:cds",
"--module-path", moduleDir.toString(),
- "-m", TEST_MODULE1)
- .assertAbnormalExit(
- "A jar file is not the one used while building the shared archive file:");
+ "-m", TEST_MODULE1);
+ res.assertAbnormalExit(jarFileError);
// create an archive with a non-empty directory in the --module-path.
// The dumping process will exit with an error due to non-empty directory
// in the --module-path.
+ String mainModule = TEST_MODULE1;
+ if (TestCommon.isDynamicArchive()) {
+ mainModule += "/" + MAIN_CLASS;
+ }
output = TestCommon.createArchive(destJar.toString(), appClasses,
"--module-path", MODS_DIR.toString(),
- "-m", TEST_MODULE1);
+ "-m", mainModule);
output.shouldHaveExitValue(1)
.shouldMatch("Error: non-empty directory.*com.simple");
--- a/test/hotspot/jtreg/runtime/appcds/jigsaw/overridetests/OverrideTests.java Fri May 17 13:21:44 2019 +0100
+++ b/test/hotspot/jtreg/runtime/appcds/jigsaw/overridetests/OverrideTests.java Thu May 23 11:07:37 2019 +0100
@@ -26,8 +26,10 @@
* @test
* @requires vm.cds
* @modules java.base/jdk.internal.misc
+ * jdk.jartool/sun.tools.jar
* @library ../..
* @library /test/lib
+ * @compile ../../test-classes/Hello.java
* @run driver OverrideTests
* @summary AppCDS tests for overriding archived classes with -p and --upgrade-module-path
*/
@@ -65,7 +67,7 @@
private static final String TEST_SRC = System.getProperty("test.src");
private static final Path SRC_DIR = Paths.get(TEST_SRC, "src");
private static final Path MODS_DIR = Paths.get("mods");
-
+ private static String appJar;
// the module that is upgraded
private static final String[] UPGRADED_MODULES = {"jdk.compiler", "java.net.http"};
private static final Path[] UPGRADEDMODS_DIR = {Paths.get("upgradedmod1"), Paths.get("upgradedmod2")};
@@ -82,6 +84,7 @@
public static void main(String[] args) throws Exception {
+ appJar = JarBuilder.getOrCreateHelloJar();
OverrideTests tests = new OverrideTests();
tests.compileModulesAndDumpArchive();
tests.testAppClassOverriding();
@@ -111,7 +114,7 @@
Asserts.assertTrue(compiled, TEST_MODULE + " did not compile");
// dump the archive with jdk.compiler and java.net.http classes in the class list
- OutputAnalyzer output = TestCommon.dump(null /* appJar*/, TestCommon.list(ARCHIVE_CLASSES));
+ OutputAnalyzer output = TestCommon.dump(appJar, TestCommon.list(ARCHIVE_CLASSES));
TestCommon.checkDump(output);
// Make sure all the classes where successfully archived.
for (String archiveClass : ARCHIVE_CLASSES) {
@@ -160,7 +163,7 @@
int upgradeModIdx = isAppLoader ? 0 : 1;
String expectedException = "java.lang.module.FindException: Unable to compute the hash";
String prefix[] = new String[3];
- prefix[0] = "-Djava.class.path=";
+ prefix[0] = "-Djava.class.path=" + appJar;
prefix[1] = "--add-modules";
prefix[2] = "java.net.http";
--- a/test/hotspot/jtreg/runtime/appcds/jvmti/dumpingWithAgent/DumpingWithJavaAgent.java Fri May 17 13:21:44 2019 +0100
+++ b/test/hotspot/jtreg/runtime/appcds/jvmti/dumpingWithAgent/DumpingWithJavaAgent.java Thu May 23 11:07:37 2019 +0100
@@ -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
@@ -105,7 +105,7 @@
if (!TestCommon.isUnableToMap(output)) {
output.shouldHaveExitValue(0);
output.shouldContain(errorMessage);
- output.shouldMatch(".class.load. Hello source:.*DumpingWithJavaAgent.jar");
+ output.shouldMatch(".class.load.* Hello source:.*DumpingWithJavaAgent.jar");
// CDS dumping with a java agent without the AllowArchvingWithJavaAgent diagnostic option.
// VM will exit with an error message.
@@ -116,4 +116,3 @@
.shouldHaveExitValue(1);
}
}
-
--- a/test/hotspot/jtreg/runtime/appcds/jvmti/transformRelatedClasses/TransformRelatedClassesAppCDS.java Fri May 17 13:21:44 2019 +0100
+++ b/test/hotspot/jtreg/runtime/appcds/jvmti/transformRelatedClasses/TransformRelatedClassesAppCDS.java Thu May 23 11:07:37 2019 +0100
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2016, 2019, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -154,6 +154,12 @@
return;
}
+ if (TestCommon.isDynamicArchive()) {
+ log("custom loader class list not applicable to dynamic archive" +
+ " - skipping test case for custom loader");
+ return;
+ }
+
String appClasses[] = {
"CustomLoaderApp",
};
--- a/test/hotspot/jtreg/runtime/appcds/test-classes/DummyClassHelper.java Fri May 17 13:21:44 2019 +0100
+++ b/test/hotspot/jtreg/runtime/appcds/test-classes/DummyClassHelper.java Thu May 23 11:07:37 2019 +0100
@@ -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,6 +24,7 @@
import java.lang.*;
import java.lang.reflect.*;
+import jdk.test.lib.cds.CDSTestUtils;
import sun.hotspot.WhiteBox;
public class DummyClassHelper {
@@ -50,9 +51,14 @@
cls = Class.forName(classNames[i]);
checkDummyMethod(cls, classNames[i]);
if (doWBCheck) {
- if (!wb.isSharedClass(cls)) {
- throw new java.lang.RuntimeException(classNames[i] +
- ".class should be in shared space.");
+ // FIXME: for dynamic archive, the class loaded from the
+ // bootclasspath jar during dump time is not loaded from the
+ // archive during run time.
+ if (!CDSTestUtils.isDynamicArchive()) {
+ if (!wb.isSharedClass(cls)) {
+ throw new java.lang.RuntimeException(classNames[i] +
+ ".class should be in shared space.");
+ }
}
}
}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/runtime/appcds/test-classes/GenericTestApp.java Thu May 23 11:07:37 2019 +0100
@@ -0,0 +1,91 @@
+/*
+ * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+import sun.hotspot.WhiteBox;
+
+/**
+ * This is a generic test app for testing if classes are loaded from the CDS archive
+ * or not (without having to parse -Xlog:class+load, or writing your own WhiteBox apps).
+ * Usage:
+ * [1] Create an archive with WhiteBox enabled.
+ * [2] Run this app with arguments such as
+ * "assertShared:java.lang.Object"
+ * "assertNotShared:NotSharedClassName"
+ *
+ * We can probably add other kinds of simple tests as well ....
+ *
+ * FIXME: enhance WB API to check if a particular archive has failed. So you can say
+ * assertShared:0,java.lang.Object
+ * to assert that java.lang.Object is shared from archive #0 (i.e., base archive).
+ */
+public class GenericTestApp {
+ private static final WhiteBox wb = WhiteBox.getWhiteBox();
+
+ public static void main(String args[]) throws Exception {
+ System.out.println("GenericTestApp started. WhiteBox = " + wb);
+ System.out.println("cdsMemoryMappingFailed() = " + cdsMemoryMappingFailed());
+
+ for (String s : args) {
+ Class c;
+ if ((c = getClass(s, "assertShared:")) != null) {
+ assertShared(c);
+ }
+ else if ((c = getClass(s, "assertNotShared:")) != null) {
+ assertNotShared(c);
+ }
+ else {
+ throw new RuntimeException("Unknown option: " + s);
+ }
+ System.out.println("passed: " + s);
+ }
+ }
+
+ private static Class getClass(String s, String prefix) throws Exception {
+ if (s.startsWith(prefix)) {
+ return Class.forName(s.substring(prefix.length()));
+ } else {
+ return null;
+ }
+ }
+
+ private static boolean cdsMemoryMappingFailed() {
+ return wb.cdsMemoryMappingFailed();
+ }
+
+ private static void assertShared(Class klass) {
+ if (!cdsMemoryMappingFailed()) {
+ if (!wb.isSharedClass(klass)) {
+ throw new RuntimeException("Class should be shared but is not: " + klass);
+ }
+ } else {
+ // FIXME -- need to throw jtreg.SkippedException
+ System.out.println("Cannot test for wb.isSharedClass(" + klass + ") because CDS mapping has failed");
+ }
+ }
+
+ private static void assertNotShared(Class klass) {
+ if (wb.isSharedClass(klass)) {
+ throw new RuntimeException("Class should be shared but is not: " + klass);
+ }
+ }
+}
--- a/test/hotspot/jtreg/runtime/logging/SafepointCleanupTest.java Fri May 17 13:21:44 2019 +0100
+++ b/test/hotspot/jtreg/runtime/logging/SafepointCleanupTest.java Thu May 23 11:07:37 2019 +0100
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2016, 2019, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -43,7 +43,6 @@
output.shouldContain("deflating per-thread idle monitors");
output.shouldContain("updating inline caches");
output.shouldContain("compilation policy safepoint handler");
- output.shouldContain("purging class loader data graph");
output.shouldHaveExitValue(0);
}
--- a/test/hotspot/jtreg/serviceability/AsyncGetCallTrace/MyPackage/ASGCTBaseTest.java Fri May 17 13:21:44 2019 +0100
+++ b/test/hotspot/jtreg/serviceability/AsyncGetCallTrace/MyPackage/ASGCTBaseTest.java Thu May 23 11:07:37 2019 +0100
@@ -29,7 +29,7 @@
* @summary Verifies that AsyncGetCallTrace is call-able and provides sane information.
* @compile ASGCTBaseTest.java
* @requires os.family == "linux"
- * @requires os.arch=="x86" | os.arch=="i386" | os.arch=="amd64" | os.arch=="x86_64" | os.arch=="arm" | os.arch=="sparc" | os.arch=="aarch64"
+ * @requires os.arch=="x86" | os.arch=="i386" | os.arch=="amd64" | os.arch=="x86_64" | os.arch=="arm" | os.arch=="sparc" | os.arch=="aarch64" | os.arch=="ppc64" | os.arch=="s390"
* @run main/othervm/native -agentlib:AsyncGetCallTraceTest MyPackage.ASGCTBaseTest
*/
--- a/test/hotspot/jtreg/serviceability/sa/ClhsdbField.java Fri May 17 13:21:44 2019 +0100
+++ b/test/hotspot/jtreg/serviceability/sa/ClhsdbField.java Thu May 23 11:07:37 2019 +0100
@@ -55,7 +55,6 @@
"field InstanceKlass _methods Array<Method*>*",
"field InstanceKlass _constants ConstantPool*",
"field Klass _name Symbol*",
- "field JavaThread _next JavaThread*",
"field JavaThread _osthread OSThread*",
"field JVMState _bci",
"field TenuredGeneration _the_space ContiguousSpace*",
--- a/test/hotspot/jtreg/serviceability/sa/ClhsdbPrintStatics.java Fri May 17 13:21:44 2019 +0100
+++ b/test/hotspot/jtreg/serviceability/sa/ClhsdbPrintStatics.java Thu May 23 11:07:37 2019 +0100
@@ -68,8 +68,7 @@
"SystemDictionary::Object_klass_knum"));
expStrMap.put("printstatics Threads", List.of(
"Static fields of Threads",
- "_number_of_threads", "_number_of_non_daemon_threads",
- "JavaThread\\* Threads"));
+ "_number_of_threads", "_number_of_non_daemon_threads"));
expStrMap.put("printstatics Universe", List.of(
"Static fields of Universe",
"uintptr_t Universe::_verify_oop_mask",
--- a/test/hotspot/jtreg/serviceability/sa/ClhsdbVmStructsDump.java Fri May 17 13:21:44 2019 +0100
+++ b/test/hotspot/jtreg/serviceability/sa/ClhsdbVmStructsDump.java Thu May 23 11:07:37 2019 +0100
@@ -57,7 +57,6 @@
"field Klass _name Symbol*",
"type ClassLoaderData* null",
"type DictionaryEntry KlassHashtableEntry",
- "field JavaThread _next JavaThread*",
"field JavaThread _osthread OSThread*",
"type TenuredGeneration CardGeneration",
"field JVMState _bci",
--- a/test/hotspot/jtreg/serviceability/sa/sadebugd/SADebugDTest.java Fri May 17 13:21:44 2019 +0100
+++ b/test/hotspot/jtreg/serviceability/sa/sadebugd/SADebugDTest.java Thu May 23 11:07:37 2019 +0100
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2016, 2019, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -32,50 +32,42 @@
* @run main/othervm SADebugDTest
*/
-import java.io.File;
-import java.util.concurrent.CountDownLatch;
-import java.io.InputStreamReader;
-import java.io.BufferedReader;
-import java.io.Reader;
import java.util.concurrent.TimeUnit;
-import java.util.function.Predicate;
-import static jdk.test.lib.Asserts.assertTrue;
+
+import jdk.test.lib.apps.LingeredApp;
+import jdk.test.lib.JDKToolLauncher;
import static jdk.test.lib.process.ProcessTools.startProcess;
public class SADebugDTest {
- private static final String GOLDEN = "Attaching to process ID %d and starting RMI services, please wait...";
-
- private static final String JAVA_HOME = (System.getProperty("test.jdk") != null)
- ? System.getProperty("test.jdk") : System.getProperty("java.home");
-
- private static final String JAVA_BIN_DIR
- = JAVA_HOME + File.separator + "bin" + File.separator;
-
- private static final String JHSDB = JAVA_BIN_DIR + "jhsdb";
+ private static final String GOLDEN = "Attaching to process";
public static void main(String[] args) throws Exception {
+ LingeredApp app = null;
- long ourPid = ProcessHandle.current().pid();
+ try {
+ app = LingeredApp.startApp();
+ System.out.println("Started LingeredApp with pid " + app.getPid());
- // The string we are expecting in the debugd ouput
- String golden = String.format(GOLDEN, ourPid);
+ JDKToolLauncher jhsdbLauncher = JDKToolLauncher.createUsingTestJDK("jhsdb");
+ jhsdbLauncher.addToolArg("debugd");
+ jhsdbLauncher.addToolArg("--pid");
+ jhsdbLauncher.addToolArg(Long.toString(app.getPid()));
+ ProcessBuilder pb = new ProcessBuilder(jhsdbLauncher.getCommand());
- // We are going to run 'jhsdb debugd <our pid>'
- // The startProcess will block untl the 'golden' string appears in either process' stdout or stderr
- // In case of timeout startProcess kills the debugd process
- ProcessBuilder pb = new ProcessBuilder();
- pb.command(JHSDB, "debugd", String.valueOf(ourPid));
- Process debugd = startProcess("debugd", pb, null, (line) -> line.trim().contains(golden), 0, TimeUnit.SECONDS);
+ // The startProcess will block untl the 'golden' string appears in either process' stdout or stderr
+ // In case of timeout startProcess kills the debugd process
+ Process debugd = startProcess("debugd", pb, null, l -> l.contains(GOLDEN), 0, TimeUnit.SECONDS);
- // If we are here, this means we have received the golden line and the test has passed
- // The debugd remains running, we have to kill it
- debugd.destroy();
+ // If we are here, this means we have received the golden line and the test has passed
+ // The debugd remains running, we have to kill it
+ debugd.destroy();
+ } finally {
+ if (app != null) {
+ LingeredApp.stopApp(app);
+ }
+ }
}
- private static void log(String string) {
- System.out.println(string);
- }
-
}
--- a/test/jaxp/javax/xml/jaxp/unittest/parsers/BaseParsingTest.java Fri May 17 13:21:44 2019 +0100
+++ b/test/jaxp/javax/xml/jaxp/unittest/parsers/BaseParsingTest.java Thu May 23 11:07:37 2019 +0100
@@ -26,18 +26,27 @@
import java.io.StringReader;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
+import javax.xml.parsers.ParserConfigurationException;
+import javax.xml.parsers.SAXParser;
+import javax.xml.parsers.SAXParserFactory;
import javax.xml.stream.XMLInputFactory;
import javax.xml.stream.XMLStreamReader;
+import org.testng.Assert;
import static org.testng.Assert.assertEquals;
import org.testng.annotations.DataProvider;
import org.testng.annotations.Listeners;
import org.testng.annotations.Test;
import org.w3c.dom.Document;
+import org.w3c.dom.ls.DOMImplementationLS;
+import org.w3c.dom.ls.LSSerializer;
+import org.xml.sax.Attributes;
import org.xml.sax.InputSource;
+import org.xml.sax.SAXException;
+import org.xml.sax.helpers.DefaultHandler;
/**
* @test
- * @bug 8169450 8222415
+ * @bug 8169450 8222415 8219692
* @library /javax/xml/jaxp/libs /javax/xml/jaxp/unittest
* @run testng/othervm -DrunSecMngr=true parsers.BaseParsingTest
* @run testng/othervm parsers.BaseParsingTest
@@ -45,6 +54,84 @@
*/
@Listeners({jaxp.library.BasePolicy.class})
public class BaseParsingTest {
+ private static final String DOM_IMPL =
+ "com.sun.org.apache.xerces.internal.jaxp.DocumentBuilderFactoryImpl";
+ private static final String SAX_IMPL =
+ "com.sun.org.apache.xerces.internal.jaxp.SAXParserFactoryImpl";
+
+ String xml_8219692 = "<a "
+ + "xmlns=\"http://openjdk_java_net/xml/defaultNS\" "
+ + "xmlns:p1=\"http://openjdk_java_net/xml/serializer/\">"
+ + "<b>in default namespace</b></a>";
+
+ /**
+ * Creates NamespaceAware parsers using old and new factory methods.
+ * @return NamespaceAware parsers
+ * @throws ParserConfigurationException
+ */
+ @DataProvider(name = "NSAwareDOMFactory")
+ public static Object[][] getNSDOMFactory() throws Exception {
+ boolean isNSAware = true;
+
+ return new Object[][]{
+ {getDOMParser(DocumentBuilderFactory.newDefaultInstance(), isNSAware)},
+ {getDOMParser(DocumentBuilderFactory.newInstance(), isNSAware)},
+ {getDOMParser(DocumentBuilderFactory.newInstance(DOM_IMPL, null), isNSAware)},
+ // using the new methods
+ {DocumentBuilderFactory.newDefaultNSInstance().newDocumentBuilder()},
+ {DocumentBuilderFactory.newNSInstance().newDocumentBuilder()},
+ {DocumentBuilderFactory.newNSInstance(DOM_IMPL, null).newDocumentBuilder()}
+ };
+ }
+
+ /**
+ * Creates parsers using the old instance methods. By default, they are
+ * not Namespace Aware.
+ * @return non-NamespaceAware parsers
+ * @throws ParserConfigurationException
+ */
+ @DataProvider(name = "DOMFactory")
+ public static Object[][] getDOMFactory() throws Exception {
+ boolean isNSAware = false;
+
+ return new Object[][]{
+ {getDOMParser(DocumentBuilderFactory.newDefaultInstance(), isNSAware)},
+ {getDOMParser(DocumentBuilderFactory.newInstance(), isNSAware)},
+ {getDOMParser(DocumentBuilderFactory.newInstance(DOM_IMPL, null), isNSAware)}
+ };
+ }
+
+
+ /**
+ * Creates NamespaceAware parsers using old and new factory methods.
+ * @return NamespaceAware parsers
+ * @throws ParserConfigurationException
+ */
+ @DataProvider(name = "NSAwareSAXFactory")
+ public static Object[][] getNSSAXFactory() throws Exception {
+ boolean isNSAware = true;
+
+ return new Object[][]{
+ {getSAXParser(SAXParserFactory.newDefaultInstance(), isNSAware)},
+ {getSAXParser(SAXParserFactory.newInstance(), isNSAware)},
+ {getSAXParser(SAXParserFactory.newInstance(SAX_IMPL, null), isNSAware)},
+ // using the new methods
+ {SAXParserFactory.newDefaultNSInstance().newSAXParser()},
+ {SAXParserFactory.newNSInstance().newSAXParser()},
+ {SAXParserFactory.newNSInstance(SAX_IMPL, null).newSAXParser()},
+ };
+ }
+
+ @DataProvider(name = "SAXFactory")
+ public static Object[][] getSAXFactory() throws Exception {
+ boolean isNSAware = false;
+
+ return new Object[][]{
+ {getSAXParser(SAXParserFactory.newDefaultInstance(), isNSAware)},
+ {getSAXParser(SAXParserFactory.newInstance(), isNSAware)},
+ {getSAXParser(SAXParserFactory.newInstance(SAX_IMPL, null), isNSAware)},
+ };
+ }
@DataProvider(name = "xmlDeclarations")
public static Object[][] xmlDeclarations() {
@@ -174,4 +261,96 @@
Document doc = db.parse(is);
assertEquals("UTF-16LE", doc.getInputEncoding());
}
+
+ /**
+ * @bug 8219692
+ * Verifies that the default namespace declaration is preserved when
+ * NamespaceAware is set on the parser.
+ * @throws Exception
+ */
+ @Test(dataProvider = "NSAwareDOMFactory")
+ public void testNSAwareDOMFactory(DocumentBuilder db) throws Exception {
+ LSSerializer ls = getSerializer(db);
+ String out = ls.writeToString(getDoc(db, xml_8219692));
+ System.out.println(out);
+ Assert.assertTrue(out.contains("http://openjdk_java_net/xml/defaultNS"));
+ }
+
+ /**
+ * @bug 8219692
+ * Verifies that the default namespace declaration is missing when the
+ * old factory methods are used.
+ * @throws Exception
+ */
+ @Test(dataProvider = "DOMFactory")
+ public void testDOMFactory(DocumentBuilder db) throws Exception {
+ LSSerializer ls = getSerializer(db);
+ String out = ls.writeToString(getDoc(db, xml_8219692));
+ System.out.println(out);
+ Assert.assertFalse(out.contains("http://openjdk_java_net/xml/defaultNS"));
+ }
+
+ /**
+ * @bug 8219692
+ * Verifies that the default namespace declaration is preserved when
+ * NamespaceAware is set on the parser.
+ * @throws Exception
+ */
+ @Test(dataProvider = "NSAwareSAXFactory")
+ public void testNSAwareSAXFactory(SAXParser sp) throws Exception {
+ MyHandler h = new MyHandler();
+ sp.parse(new InputSource(new StringReader(xml_8219692)), h);
+
+ Assert.assertTrue(h.isNSAware);
+ }
+
+ /**
+ * @bug 8219692
+ * Verifies that the default namespace declaration is missing when the
+ * old factory methods are used.
+ * @throws Exception
+ */
+ @Test(dataProvider = "SAXFactory")
+ public void testSAXFactory(SAXParser sp) throws Exception {
+ MyHandler h = new MyHandler();
+ sp.parse(new InputSource(new StringReader(xml_8219692)), h);
+
+ Assert.assertFalse(h.isNSAware);
+ }
+
+ private static DocumentBuilder getDOMParser(DocumentBuilderFactory dbf, boolean isNSAware)
+ throws Exception {
+ dbf.setNamespaceAware(isNSAware);
+ return dbf.newDocumentBuilder();
+ }
+
+ private static SAXParser getSAXParser(SAXParserFactory spf, boolean isNSAware)
+ throws Exception {
+ spf.setNamespaceAware(isNSAware);
+ return spf.newSAXParser();
+ }
+
+ private LSSerializer getSerializer(DocumentBuilder db) throws Exception {
+ DOMImplementationLS di = (DOMImplementationLS) db.getDOMImplementation();
+ return di.createLSSerializer();
+ }
+
+ private Document getDoc(DocumentBuilder db, String xml) throws Exception {
+ InputSource is = new InputSource(new StringReader(xml));
+ return db.parse(is);
+ }
+
+ /**
+ * SAX Handler
+ */
+ class MyHandler extends DefaultHandler {
+ boolean isNSAware = false;
+
+ @Override
+ public void startElement(String uri, String localName, String qName,
+ Attributes attributes) throws SAXException {
+ isNSAware = "http://openjdk_java_net/xml/defaultNS".equals(uri)
+ && ("a".equals(localName) || "b".equals(localName));
+ }
+ }
}
--- a/test/jdk/TEST.ROOT Fri May 17 13:21:44 2019 +0100
+++ b/test/jdk/TEST.ROOT Thu May 23 11:07:37 2019 +0100
@@ -43,6 +43,7 @@
sun.arch.data.model \
java.runtime.name \
vm.gc.Z \
+ vm.gc.Shenandoah \
vm.graal.enabled \
vm.compiler1.enabled \
vm.compiler2.enabled \
--- a/test/jdk/com/sun/net/httpserver/SimpleHttpServerTest.java Fri May 17 13:21:44 2019 +0100
+++ b/test/jdk/com/sun/net/httpserver/SimpleHttpServerTest.java Thu May 23 11:07:37 2019 +0100
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2014, 2019, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -24,8 +24,12 @@
/**
* @test
* @bug 8015692
+ * @key intermittent
* @summary Test HttpServer instantiation, start, and stop repeated in a loop
- * Testing for Bind exception on Windows
+ * Testing for Bind exception on Windows. This test may fail
+ * intermittently if other tests / process manage to bind to
+ * the same port that the test is using in the short window
+ * time where the port might appear available again.
*/
import java.net.InetSocketAddress;
@@ -41,24 +45,40 @@
System.out.println(System.getProperty("java.version"));
InetSocketAddress serverAddr = new InetSocketAddress(0);
HttpServer server = HttpServer.create(serverAddr, 0);
- final int serverPort = server.getAddress().getPort();
+ int serverPort = server.getAddress().getPort();
server.start();
server.stop(0);
serverAddr = new InetSocketAddress(serverPort);
int exceptionCount = 0;
+ boolean failedOnce = false;
System.out.println("Using serverPort == " + serverPort);
- for (int i = 0; i < 100; i++) {
- try {
- server = HttpServer.create(serverAddr, 0);
- server.start();
- server.stop(0);
- } catch (Exception ex) {
- ex.printStackTrace();
- exceptionCount++;
+ RETRY: while (exceptionCount == 0) {
+ for (int i = 0; i < 100; i++) {
+ try {
+ server = HttpServer.create(serverAddr, 0);
+ server.start();
+ server.stop(0);
+ } catch (Exception ex) {
+ if (!failedOnce) {
+ failedOnce = true;
+ server = HttpServer.create(new InetSocketAddress(0), 0);
+ serverPort = server.getAddress().getPort();
+ server.start();
+ server.stop(0);
+ serverAddr = new InetSocketAddress(serverPort);
+ System.out.println("Retrying with serverPort == " + serverPort);
+ continue RETRY;
+ }
+ System.err.println("Got exception at iteration: " + i );
+ ex.printStackTrace();
+ exceptionCount++;
+ }
}
+ break;
}
if (exceptionCount > 0) {
- throw new RuntimeException("Test Failed");
+ throw new RuntimeException("Test Failed: got "
+ + exceptionCount + " exceptions.");
}
}
}
--- a/test/jdk/java/lang/constant/MethodTypeDescTest.java Fri May 17 13:21:44 2019 +0100
+++ b/test/jdk/java/lang/constant/MethodTypeDescTest.java Thu May 23 11:07:37 2019 +0100
@@ -171,6 +171,34 @@
} catch (IndexOutOfBoundsException ex) {
// good
}
+
+ try {
+ ClassDesc[] newParamTypes = new ClassDesc[1];
+ newParamTypes[0] = CD_void;
+ MethodTypeDesc newDesc = MethodTypeDesc.of(returnType, CD_int);
+ newDesc = newDesc.insertParameterTypes(0, newParamTypes);
+ fail("shouldn't allow parameters with class descriptor CD_void");
+ } catch (IllegalArgumentException ex) {
+ // good
+ }
+
+ try {
+ MethodTypeDesc newDesc = MethodTypeDesc.of(returnType, CD_int);
+ newDesc = newDesc.insertParameterTypes(0, null);
+ fail("should fail with NPE");
+ } catch (NullPointerException ex) {
+ // good
+ }
+
+ try {
+ ClassDesc[] newParamTypes = new ClassDesc[1];
+ newParamTypes[0] = null;
+ MethodTypeDesc newDesc = MethodTypeDesc.of(returnType, CD_int);
+ newDesc = newDesc.insertParameterTypes(0, newParamTypes);
+ fail("should fail with NPE");
+ } catch (NullPointerException ex) {
+ // good
+ }
}
private void badDropParametersTypes(ClassDesc returnType, String... paramDescTypes) {
@@ -209,7 +237,7 @@
try {
MethodTypeDesc newDesc = mtDesc.dropParameterTypes(1, 0);
fail("start index > end index should have failed");
- } catch (IllegalArgumentException ex) {
+ } catch (IndexOutOfBoundsException ex) {
// good
}
}
@@ -258,5 +286,23 @@
catch (IllegalArgumentException e) {
// good
}
+
+ try {
+ MethodTypeDesc r = MethodTypeDesc.of(CD_int, null);
+ fail("ClassDesc array should not be null");
+ }
+ catch (NullPointerException e) {
+ // good
+ }
+
+ try {
+ ClassDesc[] paramDescs = new ClassDesc[1];
+ paramDescs[0] = null;
+ MethodTypeDesc r = MethodTypeDesc.of(CD_int, paramDescs);
+ fail("ClassDesc should not be null");
+ }
+ catch (NullPointerException e) {
+ // good
+ }
}
}
--- a/test/jdk/java/net/BindException/Test.java Fri May 17 13:21:44 2019 +0100
+++ b/test/jdk/java/net/BindException/Test.java Thu May 23 11:07:37 2019 +0100
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2001, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2001, 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,18 +51,24 @@
static int count;
static int failures;
+ static boolean retried;
static void doTest(Object test[], InetAddress ia1, InetAddress ia2,
boolean silent) throws Exception {
- String s1_type = (String)test[0];
- String s2_type = (String)test[1];
- int port = 0;
-
/*
* Increment test count
*/
count++;
+ doTest(test, count, ia1, ia2, silent, !retried);
+ }
+
+ static void doTest(Object test[], int count, InetAddress ia1, InetAddress ia2,
+ boolean silent, boolean retry) throws Exception {
+ String s1_type = (String)test[0];
+ String s2_type = (String)test[1];
+ int port = 0;
+
/*
* Do the test
*/
@@ -74,6 +80,8 @@
Socket sock1 = null;
ServerSocket ss = null;
DatagramSocket dsock1 = null;
+ boolean firstBound = false;
+
try {
/* bind the first socket */
@@ -95,6 +103,13 @@
/* bind the second socket */
+ // The fact that the port was available for ia1 does not
+ // guarantee that it will also be available for ia2 as something
+ // else might already be bound to that port.
+ // For the sake of test stability we will retry once in
+ // case of unexpected bind exception.
+
+ firstBound = true;
if (s2_type.equals("Socket")) {
try (Socket sock2 = new Socket()) {
sock2.bind( new InetSocketAddress(ia2, port));
@@ -148,6 +163,18 @@
return;
}
+ if (failed && retry && firstBound) {
+ // retry once at the first failure only
+ retried = true;
+ if (!silent) {
+ System.out.println("");
+ System.out.println("**************************");
+ System.out.println("Test " + count + ": Retrying...");
+ }
+ doTest(test, count, ia1, ia2, silent, false);
+ return;
+ }
+
if (failed || !silent) {
System.out.println("");
System.out.println("**************************");
--- a/test/jdk/java/net/InetAddress/CheckJNI.java Fri May 17 13:21:44 2019 +0100
+++ b/test/jdk/java/net/InetAddress/CheckJNI.java Thu May 23 11:07:37 2019 +0100
@@ -34,25 +34,27 @@
import java.util.*;
import java.util.stream.Collectors;
import jdk.test.lib.NetworkConfiguration;
+import jdk.test.lib.net.IPSupport;
public class CheckJNI {
- static Socket s;
- static ServerSocket server;
- static DatagramSocket dg1, dg2;
-
public static void main (String[] args) throws Exception {
/* try to invoke as much java.net native code as possible */
- System.out.println ("Testing IPv4 Socket/ServerSocket");
- server = new ServerSocket (0);
- s = new Socket ("127.0.0.1", server.getLocalPort());
- s.close();
- server.close();
+ InetAddress loopback = InetAddress.getLoopbackAddress();
+ System.out.println("Testing loopback Socket/ServerSocket");
+ testSocket(loopback);
+
+ System.out.println("Testing loopback DatagramSocket");
+ testDatagram(loopback);
- System.out.println ("Testing IPv4 DatagramSocket");
- dg1 = new DatagramSocket (0, InetAddress.getByName ("127.0.0.1"));
- dg2 = new DatagramSocket (0, InetAddress.getByName ("127.0.0.1"));
- testDatagrams (dg1, dg2);
+ if (IPSupport.hasIPv4()) {
+ InetAddress loopback4 = InetAddress.getByName("127.0.0.1");
+ System.out.println("Testing IPv4 Socket/ServerSocket");
+ testSocket(loopback4);
+
+ System.out.println("Testing IPv4 DatagramSocket");
+ testDatagram(loopback4);
+ }
/* Find link local IPv6 addrs to test */
List<Inet6Address> addrs = NetworkConfiguration.probe()
@@ -60,33 +62,38 @@
.filter(Inet6Address::isLinkLocalAddress)
.collect(Collectors.toList());
- server = new ServerSocket(0);
for (Inet6Address ia6 : addrs) {
System.out.println("Address:" + ia6);
System.out.println("Testing IPv6 Socket");
- s = new Socket(ia6, server.getLocalPort());
- s.close();
+ testSocket(ia6);
System.out.println("Testing IPv6 DatagramSocket");
- dg1 = new DatagramSocket(0, ia6);
- dg2 = new DatagramSocket(0, ia6);
- testDatagrams(dg1, dg2);
+ testDatagram(ia6);
}
- server.close();
- System.out.println ("OK");
+ System.out.println("OK");
}
- static void testDatagrams (DatagramSocket s1, DatagramSocket s2) throws Exception {
+ static void testSocket(InetAddress ia) throws Exception {
+ ServerSocket server = new ServerSocket(0);
+ Socket s = new Socket(ia, server.getLocalPort());
+ s.close();
+ server.close();
+ }
+
+ static void testDatagram(InetAddress ia) throws Exception {
+ DatagramSocket s1 = new DatagramSocket(0, ia);
+ DatagramSocket s2 = new DatagramSocket(0, ia);
+
DatagramPacket p1 = new DatagramPacket (
"hello world".getBytes(),
0, "hello world".length(), s2.getLocalAddress(),
s2.getLocalPort()
);
- DatagramPacket p2 = new DatagramPacket (new byte[128], 128);
- s1.send (p1);
- s2.receive (p2);
- s1.close ();
- s2.close ();
+ DatagramPacket p2 = new DatagramPacket(new byte[128], 128);
+ s1.send(p1);
+ s2.receive(p2);
+ s1.close();
+ s2.close();
}
}
--- a/test/jdk/java/net/NetworkInterface/IPv4Only.java Fri May 17 13:21:44 2019 +0100
+++ b/test/jdk/java/net/NetworkInterface/IPv4Only.java Thu May 23 11:07:37 2019 +0100
@@ -23,6 +23,7 @@
/* @test
* @bug 6964714
+ * @library /test/lib
* @run main/othervm -Djava.net.preferIPv4Stack=true IPv4Only
* @summary Test the networkinterface listing with java.net.preferIPv4Stack=true.
*/
@@ -30,19 +31,36 @@
import java.net.*;
import java.util.*;
-
+import jdk.test.lib.net.IPSupport;
public class IPv4Only {
public static void main(String[] args) throws Exception {
- Enumeration<NetworkInterface> nifs = NetworkInterface.getNetworkInterfaces();
- while (nifs.hasMoreElements()) {
- NetworkInterface nif = nifs.nextElement();
- Enumeration<InetAddress> addrs = nif.getInetAddresses();
- while (addrs.hasMoreElements()) {
- InetAddress hostAddr = addrs.nextElement();
- if ( hostAddr instanceof Inet6Address ){
- throw new RuntimeException( "NetworkInterfaceV6List failed - found v6 address " + hostAddr.getHostAddress() );
- }
+ if (IPSupport.hasIPv4()) {
+ System.out.println("Testing IPv4");
+ Enumeration<NetworkInterface> nifs = NetworkInterface.getNetworkInterfaces();
+ while (nifs.hasMoreElements()) {
+ NetworkInterface nif = nifs.nextElement();
+ Enumeration<InetAddress> addrs = nif.getInetAddresses();
+ while (addrs.hasMoreElements()) {
+ InetAddress hostAddr = addrs.nextElement();
+ if ( hostAddr instanceof Inet6Address ){
+ throw new RuntimeException( "NetworkInterfaceV6List failed - found v6 address " + hostAddr.getHostAddress() );
+ }
+ }
+ }
+ } else {
+ try {
+ NetworkInterface.getNetworkInterfaces();
+ throw new RuntimeException("NetworkInterface.getNetworkInterfaces() should throw SocketException");
+ } catch (SocketException expected) {
+ System.out.println("caught expected exception: " + expected);
+ }
+
+ try {
+ NetworkInterface.networkInterfaces();
+ throw new RuntimeException("NetworkInterface.networkInterfaces() should throw SocketException");
+ } catch (SocketException expected) {
+ System.out.println("caught expected exception: " + expected);
}
}
}
--- a/test/jdk/java/net/PlainSocketImpl/SetOption.java Fri May 17 13:21:44 2019 +0100
+++ b/test/jdk/java/net/PlainSocketImpl/SetOption.java Thu May 23 11:07:37 2019 +0100
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2000, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2000, 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
@@ -35,8 +35,10 @@
public static void main(String args[]) throws Exception {
- ServerSocket ss = new ServerSocket(0);
- Socket s1 = new Socket("localhost", ss.getLocalPort());
+ InetAddress loopback = InetAddress.getLoopbackAddress();
+ ServerSocket ss = new ServerSocket(0, 0, loopback);
+
+ Socket s1 = new Socket(loopback, ss.getLocalPort());
Socket s2 = ss.accept();
s1.close();
--- a/test/jdk/java/net/Socket/RST.java Fri May 17 13:21:44 2019 +0100
+++ b/test/jdk/java/net/Socket/RST.java Thu May 23 11:07:37 2019 +0100
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2001, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2001, 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,8 +47,10 @@
}
RST() throws Exception {
- ServerSocket ss = new ServerSocket(0);
- client = new Socket("localhost", ss.getLocalPort());
+ InetAddress loopback = InetAddress.getLoopbackAddress();
+ ServerSocket ss = new ServerSocket();
+ ss.bind(new InetSocketAddress(loopback, 0));
+ client = new Socket(loopback, ss.getLocalPort());
Socket server = ss.accept();
Thread thr = new Thread(this);
--- a/test/jdk/java/net/URLConnection/URLConnectionHeaders.java Fri May 17 13:21:44 2019 +0100
+++ b/test/jdk/java/net/URLConnection/URLConnectionHeaders.java Thu May 23 11:07:37 2019 +0100
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2001, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2001, 2019, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -27,12 +27,14 @@
* @summary URLConnection cannot enumerate request properties,
* and URLConnection can neither get nor set multiple
* request properties w/ same key
+ * @library /test/lib
*
*/
import java.net.*;
import java.util.*;
import java.io.*;
+import jdk.test.lib.net.URIBuilder;
public class URLConnectionHeaders {
@@ -77,15 +79,22 @@
}
}
- public static void main(String[] args) {
+ public static void main(String[] args) throws Exception {
try {
- ServerSocket serversocket = new ServerSocket (0);
- int port = serversocket.getLocalPort ();
- XServer server = new XServer (serversocket);
- server.start ();
- Thread.sleep (200);
- URL url = new URL ("http://localhost:"+port+"/index.html");
- URLConnection uc = url.openConnection ();
+ InetAddress loopback = InetAddress.getLoopbackAddress();
+ ServerSocket serversocket = new ServerSocket();
+ serversocket.bind(new InetSocketAddress(loopback, 0));
+ int port = serversocket.getLocalPort();
+ XServer server = new XServer(serversocket);
+ server.start();
+ Thread.sleep(200);
+ URL url = URIBuilder.newBuilder()
+ .scheme("http")
+ .loopback()
+ .port(port)
+ .path("/index.html")
+ .toURL();
+ URLConnection uc = url.openConnection();
// add request properties
uc.addRequestProperty("Cookie", "cookie1");
@@ -106,6 +115,7 @@
} catch (Exception e) {
e.printStackTrace();
+ throw e;
}
}
}
--- a/test/jdk/java/net/ipv6tests/UdpTest.java Fri May 17 13:21:44 2019 +0100
+++ b/test/jdk/java/net/ipv6tests/UdpTest.java Thu May 23 11:07:37 2019 +0100
@@ -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
@@ -24,11 +24,14 @@
/*
* @test
* @bug 4868820
- * @summary IPv6 support for Windows XP and 2003 server
+ * @key intermittent
+ * @summary IPv6 support for Windows XP and 2003 server.
+ * This test requires binding to the wildcard address and as such
+ * may fail intermittently on some platforms.
* @library /test/lib
* @build jdk.test.lib.NetworkConfiguration
* jdk.test.lib.Platform
- * @run main UdpTest
+ * @run main UdpTest -d
*/
import java.net.DatagramPacket;
@@ -92,6 +95,7 @@
/* basic UDP connectivity test using IPv6 only and IPv4/IPv6 together */
static void test1 () throws Exception {
+ System.out.println("Test1 starting");
s1 = new DatagramSocket ();
s2 = new DatagramSocket ();
simpleDataExchange (s1, ia4addr, s2, ia4addr);
@@ -130,6 +134,7 @@
/* check timeouts on receive */
static void test2 () throws Exception {
+ System.out.println("Test2 starting");
s1 = new DatagramSocket ();
s2 = new DatagramSocket ();
s1.setSoTimeout (4000);
@@ -180,6 +185,7 @@
/* check connected sockets */
static void test3 () throws Exception {
+ System.out.println("Test3 starting");
s1 = new DatagramSocket ();
s2 = new DatagramSocket ();
s1.connect (ia6addr, s2.getLocalPort());
@@ -191,6 +197,7 @@
/* check PortUnreachable */
static void test4 () throws Exception {
+ System.out.println("Test4 starting");
s1 = new DatagramSocket ();
s1.connect (ia6addr, 5000);
s1.setSoTimeout (3000);
--- a/test/jdk/java/nio/channels/DatagramChannel/BasicMulticastTests.java Fri May 17 13:21:44 2019 +0100
+++ b/test/jdk/java/nio/channels/DatagramChannel/BasicMulticastTests.java Thu May 23 11:07:37 2019 +0100
@@ -38,6 +38,7 @@
import java.io.IOException;
import jdk.test.lib.NetworkConfiguration;
+import jdk.test.lib.net.IPSupport;
public class BasicMulticastTests {
@@ -45,17 +46,15 @@
* Tests that existing membership key is returned by join methods and that
* membership key methods return the expected results
*/
- static void membershipKeyTests(NetworkInterface nif,
+ static void membershipKeyTests(StandardProtocolFamily family,
InetAddress group,
+ NetworkInterface nif,
InetAddress source)
throws IOException
{
System.out.format("MembershipKey test using %s @ %s\n",
group.getHostAddress(), nif.getName());
- ProtocolFamily family = (group instanceof Inet4Address) ?
- StandardProtocolFamily.INET : StandardProtocolFamily.INET6;
-
DatagramChannel dc = DatagramChannel.open(family)
.setOption(StandardSocketOptions.SO_REUSEADDR, true)
.bind(new InetSocketAddress(source, 0));
@@ -114,31 +113,31 @@
/**
* Tests exceptions for invalid arguments or scenarios
*/
- static void exceptionTests(NetworkInterface nif)
+ static void exceptionTests(StandardProtocolFamily family,
+ InetAddress group,
+ InetAddress notGroup,
+ NetworkInterface nif,
+ InetAddress loopback)
throws IOException
{
System.out.println("Exception Tests");
- DatagramChannel dc = DatagramChannel.open(StandardProtocolFamily.INET)
+ DatagramChannel dc = DatagramChannel.open(family)
.setOption(StandardSocketOptions.SO_REUSEADDR, true)
.bind(new InetSocketAddress(0));
- InetAddress group = InetAddress.getByName("225.4.5.6");
- InetAddress notGroup = InetAddress.getByName("1.2.3.4");
- InetAddress thisHost = InetAddress.getLocalHost();
-
// IllegalStateException
MembershipKey key;
key = dc.join(group, nif);
try {
- dc.join(group, nif, thisHost);
+ dc.join(group, nif, loopback);
throw new RuntimeException("IllegalStateException not thrown");
} catch (IllegalStateException x) {
} catch (UnsupportedOperationException x) {
}
key.drop();
try {
- key = dc.join(group, nif, thisHost);
+ key = dc.join(group, nif, loopback);
try {
dc.join(group, nif);
throw new RuntimeException("IllegalStateException not thrown");
@@ -155,7 +154,7 @@
} catch (IllegalArgumentException x) {
}
try {
- dc.join(notGroup, nif, thisHost);
+ dc.join(notGroup, nif, loopback);
throw new RuntimeException("IllegalArgumentException not thrown");
} catch (IllegalArgumentException x) {
} catch (UnsupportedOperationException x) {
@@ -188,7 +187,7 @@
} catch (ClosedChannelException x) {
}
try {
- dc.join(group, nif, thisHost);
+ dc.join(group, nif, loopback);
throw new RuntimeException("ClosedChannelException not thrown");
} catch (ClosedChannelException x) {
} catch (UnsupportedOperationException x) {
@@ -201,26 +200,28 @@
* and invoke tests.
*/
public static void main(String[] args) throws IOException {
-
- // multicast groups used for the test
- InetAddress ip4Group = InetAddress.getByName("225.4.5.6");
- InetAddress ip6Group = InetAddress.getByName("ff02::a");
-
-
NetworkConfiguration config = NetworkConfiguration.probe();
- NetworkInterface nif = config.ip4MulticastInterfaces().iterator().next();
- InetAddress anySource = config.ip4Addresses(nif).iterator().next();
- membershipKeyTests(nif, ip4Group, anySource);
- exceptionTests(nif);
+ // test IPv4 if available
+ if (IPSupport.hasIPv4()) {
+ InetAddress group = InetAddress.getByName("225.4.5.6");
+ InetAddress notGroup = InetAddress.getByName("1.2.3.4");
+ InetAddress loopback = InetAddress.getByName("127.0.0.1");
+ NetworkInterface nif = config.ip4MulticastInterfaces().iterator().next();
+ InetAddress anySource = config.ip4Addresses(nif).iterator().next();
+ membershipKeyTests(StandardProtocolFamily.INET, group, nif, anySource);
+ exceptionTests(StandardProtocolFamily.INET, group, notGroup, nif, loopback);
+ }
- // re-run the membership key tests with IPv6 if available
-
- Iterator<NetworkInterface> iter = config.ip6MulticastInterfaces().iterator();
- if (iter.hasNext()) {
- nif = iter.next();
- anySource = config.ip6Addresses(nif).iterator().next();
- membershipKeyTests(nif, ip6Group, anySource);
+ // test IPv6 if available
+ if (IPSupport.hasIPv6()) {
+ InetAddress group = InetAddress.getByName("ff02::a");
+ InetAddress notGroup = InetAddress.getByName("fe80::1234");
+ InetAddress loopback = InetAddress.getByName("::1");
+ NetworkInterface nif = config.ip6MulticastInterfaces().iterator().next();
+ InetAddress anySource = config.ip6Addresses(nif).iterator().next();
+ membershipKeyTests(StandardProtocolFamily.INET6, group, nif, anySource);
+ exceptionTests(StandardProtocolFamily.INET6, group, notGroup, nif, loopback);
}
}
}
--- a/test/jdk/java/security/SecureClassLoader/DefineClass.java Fri May 17 13:21:44 2019 +0100
+++ b/test/jdk/java/security/SecureClassLoader/DefineClass.java Thu May 23 11:07:37 2019 +0100
@@ -51,10 +51,13 @@
import java.util.Enumeration;
import java.util.List;
import java.util.PropertyPermission;
+import jdk.test.lib.net.IPSupport;
/*
* @test
* @bug 6826789 8131486 8130181
+ * @library /test/lib
+ * @build jdk.test.lib.net.IPSupport
* @summary Make sure equivalent ProtectionDomains are granted the same
* permissions when the CodeSource URLs are different but resolve
* to the same ip address after name service resolution.
@@ -85,6 +88,15 @@
"AAUAAQAGAAAAHQABAAEAAAAFKrcAAbEAAAABAAcAAAAGAAEAAAABAAEACAAA" +
"AAIACQ==";
+ // Base64 encoded bytes of simple class: "package bar2; public class Bar2 {}"
+ private final static String BAR2_CLASS =
+ "yv66vgAAADQADwoAAwAMBwANBwAOAQAGPGluaXQ+AQADKClWAQAEQ29kZQEA" +
+ "D0xpbmVOdW1iZXJUYWJsZQEABG1haW4BABYoW0xqYXZhL2xhbmcvU3RyaW5n" +
+ "OylWAQAKU291cmNlRmlsZQEACUJhcjIuamF2YQwABAAFAQAJYmFyMi9CYXIy" +
+ "AQAQamF2YS9sYW5nL09iamVjdAAhAAIAAwAAAAAAAgABAAQABQABAAYAAAAd" +
+ "AAEAAQAAAAUqtwABsQAAAAEABwAAAAYAAQAAAAEACQAIAAkAAQAGAAAAGQAA" +
+ "AAEAAAABsQAAAAEABwAAAAYAAQAAAAEAAQAKAAAAAgAL";
+
// Base64 encoded bytes of simple class: "package baz; public class Baz {}"
private final static String BAZ_CLASS =
"yv66vgAAADQADQoAAwAKBwALBwAMAQAGPGluaXQ+AQADKClWAQAEQ29kZQEA" +
@@ -137,12 +149,23 @@
"foo.Foo", FOO_CLASS,
null);
checkPerms(perms1, GRANTED_PERMS);
- ArrayList<Permission> perms2 = getPermissions(scl, p,
- "http://127.0.0.1/",
- "bar.Bar", BAR_CLASS,
- null);
- checkPerms(perms2, GRANTED_PERMS);
- assert(perms1.equals(perms2));
+
+ if (IPSupport.hasIPv4()) {
+ ArrayList<Permission> perms2 = getPermissions(scl, p,
+ "http://127.0.0.1/",
+ "bar.Bar", BAR_CLASS,
+ null);
+ checkPerms(perms2, GRANTED_PERMS);
+ assert(perms1.equals(perms2));
+ }
+ if (IPSupport.hasIPv6()) {
+ ArrayList<Permission> perms2 = getPermissions(scl, p,
+ "http://[::1]/",
+ "bar2.Bar2", BAR2_CLASS,
+ null);
+ checkPerms(perms2, GRANTED_PERMS);
+ assert(perms1.equals(perms2));
+ }
// check that class signed by baz is granted an additional permission
Certificate[] chain = new Certificate[] {getCert(BAZ_CERT)};
--- a/test/jdk/java/security/SecureClassLoader/DefineClass.policy Fri May 17 13:21:44 2019 +0100
+++ b/test/jdk/java/security/SecureClassLoader/DefineClass.policy Thu May 23 11:07:37 2019 +0100
@@ -9,6 +9,14 @@
grant codebase "http://127.0.0.1/" {
permission java.util.PropertyPermission "user.name", "read";
};
+grant codebase "http://[::1]/" {
+ permission java.util.PropertyPermission "user.name", "read";
+};
grant codebase "http://localhost/", signedby "baz" {
permission java.util.PropertyPermission "user.dir", "read";
};
+// For IPSupport
+grant codebase "file:${test.classes}/../../../../test/lib/-" {
+ permission java.net.SocketPermission "localhost:0", "listen,resolve";
+ permission java.util.PropertyPermission "java.net.preferIPv4Stack", "read";
+};
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/java/text/Format/NumberFormat/TestPeruCurrencyFormat.java Thu May 23 11:07:37 2019 +0100
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/**
+ * @test
+ * @bug 8206879
+ * @summary Currency decimal marker incorrect for Peru.
+ * @modules jdk.localedata
+ * @run main/othervm -Djava.locale.providers=JRE TestPeruCurrencyFormat
+ */
+
+import java.text.NumberFormat;
+import java.util.Locale;
+
+public class TestPeruCurrencyFormat {
+
+ public static void main(String[] args) {
+ final String expected = "S/.1,234.56";
+ NumberFormat currencyFmt =
+ NumberFormat.getCurrencyInstance(new Locale("es", "PE"));
+ String s = currencyFmt.format(1234.56);
+
+ if (!s.equals(expected)) {
+ throw new RuntimeException("Currency format for Peru failed, expected " + expected + ", got " + s);
+ }
+ }
+}
--- a/test/jdk/java/time/test/java/time/chrono/TestEraDisplayName.java Fri May 17 13:21:44 2019 +0100
+++ b/test/jdk/java/time/test/java/time/chrono/TestEraDisplayName.java Thu May 23 11:07:37 2019 +0100
@@ -28,7 +28,9 @@
import java.time.*;
import java.time.chrono.*;
import java.time.format.*;
+import java.util.Arrays;
import java.util.Locale;
+import java.util.stream.Stream;
import org.testng.annotations.DataProvider;
import org.testng.annotations.Test;
@@ -39,13 +41,18 @@
* chrono implementation.
* Note: The exact result may depend on locale data provider's implementation.
*
- * @bug 8171049
+ * @bug 8171049 8224105
*/
@Test
public class TestEraDisplayName {
private static final Locale THAI = Locale.forLanguageTag("th-TH");
private static final Locale EGYPT = Locale.forLanguageTag("ar-EG");
+ private static final LocalDate REIWA_1ST = LocalDate.of(2019, 5, 1);
+ private static final DateTimeFormatter JAPANESE_FORMATTER =
+ DateTimeFormatter.ofPattern("yyyy MM dd GGGG G GGGGG")
+ .withChronology(JapaneseChronology.INSTANCE);
+
@DataProvider(name="eraDisplayName")
Object[][] eraDisplayName() {
return new Object[][] {
@@ -135,8 +142,22 @@
};
}
+ @DataProvider
+ Object[][] allLocales() {
+ return Arrays.stream(Locale.getAvailableLocales())
+ .map(Stream::of)
+ .map(Stream::toArray)
+ .toArray(Object[][]::new);
+ }
+
@Test(dataProvider="eraDisplayName")
public void test_eraDisplayName(Era era, TextStyle style, Locale locale, String expected) {
assertEquals(era.getDisplayName(style, locale), expected);
}
+
+ @Test(dataProvider="allLocales")
+ public void test_reiwaNames(Locale locale) throws DateTimeParseException {
+ DateTimeFormatter f = JAPANESE_FORMATTER.withLocale(locale);
+ assertEquals(LocalDate.parse(REIWA_1ST.format(f), f), REIWA_1ST);
+ }
}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/java/util/Calendar/JapanEraNameCompatTest.java Thu May 23 11:07:37 2019 +0100
@@ -0,0 +1,144 @@
+/*
+ * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @bug 8218781
+ * @summary Test the localized names of Japanese era Reiwa from COMPAT provider.
+ * @modules jdk.localedata
+ * @run testng/othervm -Djava.locale.providers=COMPAT JapanEraNameCompatTest
+ */
+
+import static java.util.Calendar.*;
+import static java.util.Locale.*;
+
+import java.time.LocalDate;
+import java.time.chrono.JapaneseChronology;
+import java.time.chrono.JapaneseEra;
+import java.time.format.DateTimeFormatter;
+import java.time.format.DateTimeParseException;
+import java.time.format.TextStyle;
+import java.util.Calendar;
+import java.util.Locale;
+
+import org.testng.annotations.DataProvider;
+import org.testng.annotations.Test;
+import static org.testng.Assert.assertEquals;
+
+@Test
+public class JapanEraNameCompatTest {
+ static final Calendar c = new Calendar.Builder()
+ .setCalendarType("japanese")
+ .setFields(ERA, 5, YEAR, 1, MONTH, MAY, DAY_OF_MONTH, 1)
+ .build();
+ static final String EngName = "Reiwa";
+ static final String CJName = "\u4ee4\u548c";
+ static final String KoreanName = "\ub808\uc774\uc640";
+ static final String ArabicName = "\u0631\u064a\u0648\u0627";
+ static final String ThaiName = "\u0e40\u0e23\u0e27\u0e30";
+ static final String HindiName = "\u0930\u0947\u0907\u0935\u093e";
+ static final String RussianName = "\u0420\u044d\u0439\u0432\u0430";
+ static final String SerbianName = "\u0420\u0435\u0438\u0432\u0430";
+ static final String SerbLatinName = "Reiva";
+
+ @DataProvider(name="UtilCalendar")
+ Object[][] dataUtilCalendar() {
+ return new Object[][] {
+ //locale, long, short
+ { JAPAN, CJName, "R" },
+ { KOREAN, KoreanName, "R" },
+ { CHINA, CJName, "R" },
+ { TAIWAN, CJName, "R" }, // fallback to zh
+ { new Locale("ar"), ArabicName, ArabicName },
+ { new Locale("th"), ThaiName, "R" },
+ // hi_IN fallback to root
+ { new Locale("hi", "IN"), EngName, "R" }
+ };
+ }
+
+ @Test(dataProvider="UtilCalendar")
+ public void testCalendarEraDisplayName(Locale locale,
+ String longName, String shortName) {
+ assertEquals(c.getDisplayName(ERA, LONG, locale), longName);
+ assertEquals(c.getDisplayName(ERA, SHORT, locale), shortName);
+ }
+
+ @DataProvider(name="JavaTime")
+ Object[][] dataJavaTime() {
+ return new Object[][] {
+ // locale, full, short
+ { JAPAN, CJName, CJName },
+ { KOREAN, KoreanName, KoreanName },
+ { CHINA, CJName, CJName },
+ { TAIWAN, CJName, CJName },
+ { new Locale("ar"), ArabicName, ArabicName },
+ { new Locale("th"), ThaiName, ThaiName },
+ { new Locale("hi", "IN"), HindiName, HindiName },
+ { new Locale("ru"), RussianName, RussianName },
+ { new Locale("sr"), SerbianName, SerbianName },
+ { Locale.forLanguageTag("sr-Latn"), SerbLatinName, SerbLatinName },
+ { new Locale("hr"), EngName, EngName },
+ { new Locale("in"), EngName, EngName },
+ { new Locale("lt"), EngName, EngName },
+ { new Locale("nl"), EngName, EngName },
+ { new Locale("no"), EngName, "R" },
+ { new Locale("sv"), EngName, EngName },
+ // el fallback to root
+ { new Locale("el"), EngName, EngName }
+ };
+ }
+
+ @Test(dataProvider="JavaTime")
+ public void testChronoJapanEraDisplayName(Locale locale,
+ String fullName, String shortName) {
+
+ JapaneseEra era = JapaneseEra.valueOf("Reiwa");
+ assertEquals(era.getDisplayName(TextStyle.FULL, locale), fullName);
+ assertEquals(era.getDisplayName(TextStyle.SHORT, locale), shortName);
+ assertEquals(era.getDisplayName(TextStyle.NARROW, locale), "R");
+ }
+
+ @Test
+ public void testFormatParseEraName() {
+ LocalDate date = LocalDate.of(2019, 5, 1);
+ DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy MM dd GGGG");
+ formatter = formatter.withChronology(JapaneseChronology.INSTANCE);
+
+ int num = 0;
+ for (Locale locale : Calendar.getAvailableLocales()) {
+ formatter = formatter.withLocale(locale);
+ try {
+ LocalDate.parse(date.format(formatter), formatter);
+ } catch (DateTimeParseException e) {
+ // If an array is defined for Japanese eras in java.time resource,
+ // but an era entry is missing, format fallback to English name
+ // while parse throw DateTimeParseException.
+ num++;
+ System.out.println("Missing java.time resource data for locale: " + locale);
+ }
+ }
+ if (num > 0) {
+ throw new RuntimeException("Missing java.time data for " + num + " locales");
+ }
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/event/gc/detailed/TestShenandoahHeapRegionInformationEvent.java Thu May 23 11:07:37 2019 +0100
@@ -0,0 +1,70 @@
+/*
+ * Copyright (c) 2019, Red Hat, Inc. All rights reserved.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * 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 jdk.jfr.event.gc.detailed;
+
+import java.nio.file.Paths;
+import java.util.List;
+
+import jdk.jfr.EventType;
+import jdk.jfr.FlightRecorder;
+import jdk.jfr.Recording;
+import jdk.jfr.consumer.RecordedEvent;
+import jdk.test.lib.Asserts;
+import jdk.test.lib.jfr.EventNames;
+import jdk.test.lib.jfr.Events;
+import jdk.test.lib.jfr.GCHelper;
+
+/**
+ * @test
+ * @bug 8221507
+ * @requires vm.hasJFR & vm.gc.Shenandoah
+ * @key jfr
+ * @library /test/lib /test/jdk
+ * @run main/othervm -Xmx32m -XX:+UnlockExperimentalVMOptions -XX:+UseShenandoahGC -XX:ShenandoahGarbageThreshold=1 jdk.jfr.event.gc.detailed.TestShenandoahHeapRegionInformationEvent
+ */
+
+
+public class TestShenandoahHeapRegionInformationEvent {
+ private final static String EVENT_NAME = EventNames.ShenandoahHeapRegionInformation;
+ public static void main(String[] args) throws Exception {
+ try (Recording recording = new Recording()) {
+ // activate the event we are interested in and start recording
+ for (EventType t : FlightRecorder.getFlightRecorder().getEventTypes()) {
+ System.out.println(t.getName());
+ }
+ recording.enable(EVENT_NAME);
+ recording.start();
+ recording.stop();
+
+ // Verify recording
+ List<RecordedEvent> events = Events.fromRecording(recording);
+ Events.hasEvents(events);
+ for (RecordedEvent event : events) {
+ Events.assertField(event, "index").notEqual(-1);
+ GCHelper.assertIsValidShenandoahHeapRegionState(Events.assertField(event, "state").getValue());
+ Events.assertField(event, "used").atMost(1L*1024*1024);
+ }
+ }
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/event/gc/detailed/TestShenandoahHeapRegionStateChangeEvent.java Thu May 23 11:07:37 2019 +0100
@@ -0,0 +1,73 @@
+/*
+ * Copyright (c) 2019, Red Hat, Inc. All rights reserved.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * 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 jdk.jfr.event.gc.detailed;
+
+import java.nio.file.Paths;
+import java.time.Duration;
+import java.util.List;
+
+import jdk.jfr.Recording;
+import jdk.jfr.consumer.RecordedEvent;
+import jdk.test.lib.Asserts;
+import jdk.test.lib.jfr.EventNames;
+import jdk.test.lib.jfr.Events;
+import jdk.test.lib.jfr.GCHelper;
+
+/**
+ * @test
+ * @bug 8221507
+ * @requires vm.hasJFR & vm.gc.Shenandoah
+ * @key jfr
+ * @library /test/lib /test/jdk
+ * @run main/othervm -Xmx32m -XX:+UnlockExperimentalVMOptions -XX:+UseShenandoahGC -XX:ShenandoahGarbageThreshold=1 jdk.jfr.event.gc.detailed.TestShenandoahHeapRegionStateChangeEvent
+ */
+
+public class TestShenandoahHeapRegionStateChangeEvent {
+ private final static String EVENT_NAME = EventNames.ShenandoahHeapRegionStateChange;
+
+ public static void main(String[] args) throws Exception {
+ try (Recording recording = new Recording()) {
+ // activate the event we are interested in and start recording
+ recording.enable(EVENT_NAME).withThreshold(Duration.ofMillis(0));
+ recording.start();
+
+ byte[][] array = new byte[1024][];
+ for (int i = 0; i < array.length; i++) {
+ array[i] = new byte[20 * 1024];
+ }
+ recording.stop();
+
+ // Verify recording
+ List<RecordedEvent> events = Events.fromRecording(recording);
+ Asserts.assertFalse(events.isEmpty(), "No events found");
+
+ for (RecordedEvent event : events) {
+ Events.assertField(event, "index").notEqual(-1);
+ GCHelper.assertIsValidShenandoahHeapRegionState(Events.assertField(event, "from").getValue());
+ GCHelper.assertIsValidShenandoahHeapRegionState(Events.assertField(event, "to").getValue());
+ Events.assertField(event, "used").atMost(1L*1024*1024);
+ }
+ }
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/nio/zipfs/InvalidZipHeaderTests.java Thu May 23 11:07:37 2019 +0100
@@ -0,0 +1,129 @@
+/*
+ * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+import org.testng.annotations.AfterClass;
+import org.testng.annotations.BeforeClass;
+import org.testng.annotations.DataProvider;
+import org.testng.annotations.Test;
+
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.nio.file.FileSystem;
+import java.nio.file.FileSystems;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.util.List;
+import java.util.jar.JarEntry;
+import java.util.jar.JarOutputStream;
+import java.util.stream.Collectors;
+
+import static java.nio.file.Files.walk;
+import static org.testng.Assert.*;
+
+/**
+ * @test
+ * @bug 8222807
+ * @summary Validate that you can iterate a ZIP file with invalid ZIP header entries
+ * @modules jdk.zipfs
+ * @compile InvalidZipHeaderTests.java
+ * @run testng InvalidZipHeaderTests
+ * @run testng/othervm/java.security.policy=test.policy InvalidZipHeaderTests
+ */
+public class InvalidZipHeaderTests {
+
+
+ // Name of Jar file used in tests
+ private static final String INVALID_JAR_FILE = "invalid.jar";
+
+ /**
+ * Create the JAR files used by the tests
+ */
+ @BeforeClass
+ public void setUp() throws Exception {
+ createInvalidJarFile();
+ }
+
+ /**
+ * Remove JAR files used by test as part of clean-up
+ */
+ @AfterClass
+ public void tearDown() throws Exception {
+ Files.deleteIfExists(Path.of(INVALID_JAR_FILE));
+ }
+
+
+ /**
+ * Validate that you can walk a ZIP archive with header entries
+ * such as "foo//"
+ */
+ @Test(dataProvider = "startPaths")
+ public void walkInvalidHeaderTest(String startPath, List<String> expectedPaths)
+ throws IOException {
+ try (FileSystem zipfs =
+ FileSystems.newFileSystem(Path.of(INVALID_JAR_FILE))) {
+ List<String> result = walk(zipfs.getPath(startPath))
+ .map(f -> f.toString()).collect(Collectors.toList());
+ assertTrue(result.equals(expectedPaths),
+ String.format("Error: Expected paths not found when walking"
+ + "%s, starting at %s%n", INVALID_JAR_FILE,
+ startPath));
+ }
+ }
+
+
+ /**
+ * Starting Path for walking the ZIP archive and the expected paths to be returned
+ * when traversing the archive
+ */
+ @DataProvider(name = "startPaths")
+ public static Object[][] Name() {
+ return new Object[][]{
+
+ {"luckydog", List.of("luckydog", "luckydog/outfile.txt")},
+ {"/luckydog", List.of("/luckydog", "/luckydog/outfile.txt")},
+ {"./luckydog", List.of("./luckydog", "./luckydog/outfile.txt")},
+ {"", List.of( "", "luckydog", "luckydog/outfile.txt")},
+ {"/", List.of("/", "/luckydog", "/luckydog/outfile.txt")},
+ {".", List.of(".", "./luckydog", "./luckydog/outfile.txt")},
+ {"./", List.of(".", "./luckydog", "./luckydog/outfile.txt")}
+ };
+ }
+
+ /**
+ * Create a jar file with invalid CEN and LOC headers
+ * @throws IOException
+ */
+ static void createInvalidJarFile() throws IOException {
+
+ try (JarOutputStream jos = new JarOutputStream(new FileOutputStream(INVALID_JAR_FILE))) {
+ JarEntry je = new JarEntry("luckydog//");
+ jos.putNextEntry(je);
+ jos.closeEntry();
+ je = new JarEntry("luckydog//outfile.txt");
+ jos.putNextEntry(je);
+ jos.write("Tennis Anyone!!".getBytes());
+ jos.closeEntry();
+ }
+ }
+
+}
--- a/test/jdk/sun/management/jmxremote/bootstrap/GeneratePropertyPassword.sh Fri May 17 13:21:44 2019 +0100
+++ b/test/jdk/sun/management/jmxremote/bootstrap/GeneratePropertyPassword.sh Thu May 23 11:07:37 2019 +0100
@@ -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
@@ -70,13 +70,11 @@
if [ "$OS" = "Windows_NT" ]; then
USER=`id -u -n`
CACLS="$SystemRoot/system32/cacls.exe"
- TEST_SRC=`cygpath ${TESTSRC}`
- REVOKEALL="$TEST_SRC/../../windows/revokeall.exe"
- if [ ! -f "$REVOKEALL" ] ; then
- echo "$REVOKEALL missing"
+ REVOKEALL="$TESTNATIVEPATH/revokeall.exe"
+ if [ ! -x "$REVOKEALL" ] ; then
+ echo "$REVOKEALL doesn't exist or is not executable"
exit 1
fi
- chmod ug+x $REVOKEALL
fi
;;
*)
--- a/test/jdk/sun/management/windows/README Fri May 17 13:21:44 2019 +0100
+++ b/test/jdk/sun/management/windows/README Thu May 23 11:07:37 2019 +0100
@@ -1,6 +1,29 @@
+/*
+ * Copyright (c) 2004, 2019, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
-This directory contains the source and the binary version of a Windows
-utility to remove all non-owner Access Control Entries from a given file.
+
+This directory contains the source of a Windows utility to remove all
+non-owner Access Control Entries from a given file.
The tool is used by regression tests in the following directories :-
@@ -10,18 +33,3 @@
be "secured" (meaning that only the owner should have access to the
files).
-Both the source and the binary version are checked into SCCS. If
-you require to make changes to the tool then you need to Visual
-C++ to rebuild revokeall.exe after changing the source.
-
-To rebuild the tool you need to setup your environment (by
-calling the VC++ VCVARS32.BAT script), and then executing the
-following command :-
-
-cl /mt revokeall.c advapi32.lib
-
-This will generate revokeall.exe.
-
-Note that a 32-bit version of revokeall.exe is checked into SCCS
-- this 32-bit application is also used when running on 64-bit
-versions of Windows (AMD64 and IA64).
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/sun/management/windows/exerevokeall.c Thu May 23 11:07:37 2019 +0100
@@ -0,0 +1,463 @@
+/*
+ * Copyright (c) 2004, 2019, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+#include <stdio.h>
+#include <windows.h>
+#include <malloc.h>
+#include <string.h>
+
+/*
+ * Simple Windows utility to remove all non-owner access to a given file.
+ */
+
+
+/*
+ * Access mask to represent any file access
+ */
+#define ANY_ACCESS (FILE_GENERIC_READ | FILE_GENERIC_WRITE | FILE_GENERIC_EXECUTE)
+
+
+/*
+ * Print error message to stderr
+ */
+static void printLastError(const char* msg) {
+ int len;
+ char buf[128];
+ DWORD errval;
+
+ buf[0] = '\0';
+ len = sizeof(buf);
+
+ errval = GetLastError();
+ if (errval != 0) {
+ int n = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM|FORMAT_MESSAGE_IGNORE_INSERTS,
+ NULL, errval,
+ 0, buf, len, NULL);
+ if (n > 3) {
+ /* Drop final '.', CR, LF */
+ if (buf[n - 1] == '\n') n--;
+ if (buf[n - 1] == '\r') n--;
+ if (buf[n - 1] == '.') n--;
+ buf[n] = '\0';
+ }
+ }
+
+ if (strlen(buf) > 0) {
+ fprintf(stderr, "revokeall %s: %s\n", msg, buf);
+ } else {
+ fprintf(stderr, "revokeall %s\n", msg);
+ }
+}
+
+
+
+/*
+ * Return a string that includes all the components of a given SID.
+ * See here for a description of the SID components :-
+ * http://msdn.microsoft.com/library/default.asp?url=/library/en-us/security/security/sid_components.asp
+ */
+static char *getTextualSid(SID* sid) {
+ SID_IDENTIFIER_AUTHORITY* sia;
+ DWORD i, count;
+ DWORD len;
+ char* name;
+
+ /*
+ * Get the identifier authority and the number of sub-authorities
+ */
+ sia = GetSidIdentifierAuthority(sid);
+ count = *GetSidSubAuthorityCount(sid);
+
+ /*
+ * Allocate buffer for the string - buffer is :-
+ * S-SID_REVISION- + identifierAuthority- + subauthorities- + NULL
+ */
+ len=(15 + 12 + (12 * count) + 1) * sizeof(char);
+ name = (char*)malloc(len);
+ if (name == NULL) {
+ return NULL;
+ }
+
+ // S-SID_REVISION
+ sprintf(name, "S-%lu-", SID_REVISION );
+
+ // Identifier authority
+ if ((sia->Value[0] != 0) || (sia->Value[1] != 0))
+ {
+ sprintf(name + strlen(name), "0x%02hx%02hx%02hx%02hx%02hx%02hx",
+ (USHORT)sia->Value[0],
+ (USHORT)sia->Value[1],
+ (USHORT)sia->Value[2],
+ (USHORT)sia->Value[3],
+ (USHORT)sia->Value[4],
+ (USHORT)sia->Value[5]);
+ }
+ else
+ {
+ sprintf(name + strlen(name), "%lu",
+ (ULONG)(sia->Value[5] ) +
+ (ULONG)(sia->Value[4] << 8) +
+ (ULONG)(sia->Value[3] << 16) +
+ (ULONG)(sia->Value[2] << 24) );
+ }
+
+ // finally, the sub-authorities
+ for (i=0 ; i<count; i++) {
+ sprintf(name + strlen(name), "-%lu",
+ *GetSidSubAuthority(sid, i) );
+ }
+
+ return name;
+}
+
+/*
+ * Returns a string to represent the given security identifier (SID).
+ * If the account is known to the local computer then the account
+ * domain is returned. The format will be \\name or domain\\name depending
+ * on if the computer belongs to a domain.
+ * If the account name is not known then the textual representation of
+ * SID is returned -- eg: S-1-5-21-2818032319-470147023-1036452850-13037.
+ */
+static char *getSIDString(SID* sid) {
+ char domain[255];
+ char name[255];
+ DWORD domainLen = sizeof(domain);
+ DWORD nameLen = sizeof(name);
+ SID_NAME_USE use;
+
+ if(!IsValidSid(sid)) {
+ return strdup("<Invalid SID>");
+ }
+
+ if (LookupAccountSid(NULL, sid, name, &nameLen, domain, &domainLen, &use)) {
+ size_t len = strlen(name) + strlen(domain) + 3;
+ char* s = (char*)malloc(len);
+ if (s != NULL) {
+ strcpy(s, domain);
+ strcat(s, "\\\\");
+ strcat(s, name);
+ }
+ return s;
+ } else {
+ return getTextualSid(sid);
+ }
+}
+
+
+
+/*
+ * Returns 1 if the specified file is on a file system that supports
+ * persistent ACLs (On NTFS file systems returns true, on FAT32 file systems
+ * returns false), otherwise 0. Returns -1 if error.
+ */
+static int isSecuritySupported(const char* path) {
+ char* root;
+ char* p;
+ BOOL res;
+ DWORD dwMaxComponentLength;
+ DWORD dwFlags;
+ char fsName[128];
+ DWORD fsNameLength;
+
+ /*
+ * Get root directory. For UNCs the slash after the share name is required.
+ */
+ root = strdup(path);
+ if (*root == '\\') {
+ /*
+ * \\server\share\file ==> \\server\share\
+ */
+ int slashskip = 3;
+ p = root;
+ while ((*p == '\\') && (slashskip > 0)) {
+ char* p2;
+ p++;
+ p2 = strchr(p, '\\');
+ if ((p2 == NULL) || (*p2 != '\\')) {
+ free(root);
+ fprintf(stderr, "Malformed UNC");
+ return -1;
+ }
+ p = p2;
+ slashskip--;
+ }
+ if (slashskip != 0) {
+ free(root);
+ fprintf(stderr, "Malformed UNC");
+ return -1;
+ }
+ p++;
+ *p = '\0';
+
+ } else {
+ p = strchr(root, '\\');
+
+ /*
+ * Relative path so use current directory
+ */
+ if (p == NULL) {
+ free(root);
+ root = malloc(255);
+ if (GetCurrentDirectory(255, root) == 0) {
+ printLastError("GetCurrentDirectory failed");
+ return -1;
+ }
+ p = strchr(root, '\\');
+ if (p == NULL) {
+ fprintf(stderr, "GetCurrentDirectory doesn't include drive letter!!!!\n");
+ return -1;
+ }
+ }
+ p++;
+ *p = '\0';
+ }
+
+ /*
+ * Get the volume information - this gives us the file system file and
+ * also tells us if the file system supports persistent ACLs.
+ */
+ fsNameLength = sizeof(fsName)-1;
+ res = GetVolumeInformation(root,
+ NULL, // address of name of the volume, can be NULL
+ 0, // length of volume name
+ NULL, // address of volume serial number, can be NULL
+ &dwMaxComponentLength,
+ &dwFlags,
+ fsName,
+ fsNameLength);
+ if (res == 0) {
+ printLastError("GetVolumeInformation failed");
+ free(root);
+ return -1;
+ }
+
+ free(root);
+ return (dwFlags & FS_PERSISTENT_ACLS) ? 1 : 0;
+}
+
+
+/*
+ * Returns the security descriptor for a file.
+ */
+static SECURITY_DESCRIPTOR* getFileSecurityDescriptor(const char* path) {
+ SECURITY_DESCRIPTOR* sd;
+ DWORD len = 0;
+ SECURITY_INFORMATION info =
+ OWNER_SECURITY_INFORMATION | DACL_SECURITY_INFORMATION;
+
+ GetFileSecurity(path, info , 0, 0, &len);
+ if (GetLastError() != ERROR_INSUFFICIENT_BUFFER) {
+ printLastError("GetFileSecurity failed");
+ return NULL;
+ }
+ sd = (SECURITY_DESCRIPTOR *)malloc(len);
+ if (sd == NULL) {
+ fprintf(stderr, "Out of memory");
+ } else {
+ if (!GetFileSecurity(path, info, sd, len, &len)) {
+ printLastError("GetFileSecurity failed");
+ free(sd);
+ return NULL;
+ }
+ }
+ return sd;
+}
+
+
+/*
+ * Revoke all access to the specific file
+ */
+static int revokeAll(const char* path) {
+ SECURITY_DESCRIPTOR* sd;
+ SID* owner;
+ ACL *acl;
+ BOOL defaulted, present;
+ ACL_SIZE_INFORMATION acl_size_info;
+ DWORD i, count;
+ char* str;
+
+ /*
+ * Get security descriptor for file; From security descriptor get the
+ * owner SID, and the DACL.
+ */
+ sd = getFileSecurityDescriptor(path);
+ if (sd == NULL) {
+ return -1; /* error already reported */
+ }
+ if (!GetSecurityDescriptorOwner(sd, &owner, &defaulted)) {
+ printLastError("GetSecurityDescriptorOwner failed");
+ return -1;
+ }
+ str = getSIDString(owner);
+ if (str != NULL) {
+ printf("owner: %s\n", str);
+ free(str);
+ }
+ if (!GetSecurityDescriptorDacl(sd, &present, &acl, &defaulted)) {
+ printLastError("GetSecurityDescriptorDacl failed");
+ return -1;
+ }
+ if (!present) {
+ fprintf(stderr, "Security descriptor does not contain a DACL");
+ return -1;
+ }
+
+ /*
+ * If DACL is NULL there is no access to the file - we are done
+ */
+ if (acl == NULL) {
+ return 1;
+ }
+
+ /*
+ * Iterate over the ACEs. For each "allow" type check that the SID
+ * matches the owner - if not we remove the ACE from the ACL
+ */
+ if (!GetAclInformation(acl, (void *) &acl_size_info, sizeof(acl_size_info),
+ AclSizeInformation)) {
+ printLastError("GetAclInformation failed");
+ return -1;
+ }
+ count = acl_size_info.AceCount;
+ i = 0;
+ while (count > 0) {
+ void* ace;
+ ACCESS_ALLOWED_ACE *access;
+ SID* sid;
+ BOOL deleted;
+
+ if (!GetAce(acl, i, &ace)) {
+ printLastError("GetAce failed");
+ return -1;
+ }
+ if (((ACCESS_ALLOWED_ACE *)ace)->Header.AceType != ACCESS_ALLOWED_ACE_TYPE) {
+ i++;
+ count--;
+ continue;
+ }
+ access = (ACCESS_ALLOWED_ACE *)ace;
+ sid = (SID *) &access->SidStart;
+
+
+ deleted = FALSE;
+ if (!EqualSid(owner, sid)) {
+ /*
+ * If the ACE allows any access then the file then we
+ * delete it.
+ */
+ if (access->Mask & ANY_ACCESS) {
+ str = getSIDString(sid);
+ if (str != NULL) {
+ printf("remove ALLOW %s\n", str);
+ free(str);
+ }
+ if (DeleteAce(acl, i) == 0) {
+ printLastError("DeleteAce failed");
+ return -1;
+ }
+ deleted = TRUE;
+ }
+ }
+
+ if (!deleted) {
+ str = getSIDString(sid);
+ if (str != NULL) {
+ printf("ALLOW %s (access mask=%x)\n", str, access->Mask);
+ free(str);
+ }
+
+ /* onto the next ACE */
+ i++;
+ }
+ count--;
+ }
+
+ /*
+ * No changes - only owner has access
+ */
+ if (i == acl_size_info.AceCount) {
+ printf("No changes.\n");
+ return 1;
+ }
+
+ /*
+ * Create security descriptor and set its DACL to the version
+ * that we just edited
+ */
+ if (!InitializeSecurityDescriptor(sd, SECURITY_DESCRIPTOR_REVISION)) {
+ printLastError("InitializeSecurityDescriptor failed");
+ return -1;
+ }
+ if (!SetSecurityDescriptorDacl(sd, present, acl, defaulted)) {
+ printLastError("SetSecurityDescriptorDacl failed");
+ return -1;
+ }
+ if (!SetFileSecurity(path, DACL_SECURITY_INFORMATION, sd)) {
+ printLastError("SetFileSecurity failed");
+ return -1;
+ }
+
+ printf("File updated.\n");
+
+ return 1;
+}
+
+/*
+ * Convert slashes in the pathname to backslashes if needed.
+ */
+static char* convert_path(const char* p) {
+ int i = 0;
+ char* path = strdup(p);
+ while (p[i] != '\0') {
+ if (p[i] == '/') {
+ path[i] = '\\';
+ }
+ i++;
+ }
+ return path;
+}
+
+/*
+ * Usage: revokeall file
+ */
+int main( int argc, char *argv[])
+{
+ int rc;
+ const char* path;
+
+ if (argc != 2) {
+ fprintf(stderr, "Usage: %s file\n", argv[0]);
+ return -1;
+ }
+ path = convert_path(argv[1]);
+ printf("Revoking all non-owner access to %s\n", path);
+ rc = isSecuritySupported(path);
+ if (rc != 1) {
+ if (rc == 0) {
+ printf("File security not supported on this file system\n");
+ }
+ return rc;
+ } else {
+ return revokeAll(path);
+ }
+}
--- a/test/jdk/sun/management/windows/revokeall.c Fri May 17 13:21:44 2019 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,462 +0,0 @@
-/*
- * Copyright (c) 2004, 2007, 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 <stdio.h>
-#include <windows.h>
-#include <malloc.h>
-#include <string.h>
-
-/*
- * Simple Windows utility to remove all non-owner access to a given
- * file - suitable for NT/2000/XP only.
- */
-
-
-/*
- * Access mask to represent any file access
- */
-#define ANY_ACCESS (FILE_GENERIC_READ | FILE_GENERIC_WRITE | FILE_GENERIC_EXECUTE)
-
-
-/*
- * Print error message to stderr
- */
-static void printLastError(const char* msg) {
- int len;
- char buf[128];
- DWORD errval;
-
- buf[0] = '\0';
- len = sizeof(buf);
-
- errval = GetLastError();
- if (errval != 0) {
- int n = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM|FORMAT_MESSAGE_IGNORE_INSERTS,
- NULL, errval,
- 0, buf, len, NULL);
- if (n > 3) {
- /* Drop final '.', CR, LF */
- if (buf[n - 1] == '\n') n--;
- if (buf[n - 1] == '\r') n--;
- if (buf[n - 1] == '.') n--;
- buf[n] = '\0';
- }
- }
-
- if (strlen(buf) > 0) {
- fprintf(stderr, "revokeall %s: %s\n", msg, buf);
- } else {
- fprintf(stderr, "revokeall %s\n", msg);
- }
-}
-
-
-
-/*
- * Return a string that includes all the components of a given SID.
- * See here for a description of the SID components :-
- * http://msdn.microsoft.com/library/default.asp?url=/library/en-us/security/security/sid_components.asp
- */
-static char *getTextualSid(SID* sid) {
- SID_IDENTIFIER_AUTHORITY* sia;
- DWORD i, count;
- DWORD len;
- char* name;
-
- /*
- * Get the identifier authority and the number of sub-authorities
- */
- sia = GetSidIdentifierAuthority(sid);
- count = *GetSidSubAuthorityCount(sid);
-
- /*
- * Allocate buffer for the string - buffer is :-
- * S-SID_REVISION- + identifierAuthority- + subauthorities- + NULL
- */
- len=(15 + 12 + (12 * count) + 1) * sizeof(char);
- name = (char*)malloc(len);
- if (name == NULL) {
- return NULL;
- }
-
- // S-SID_REVISION
- sprintf(name, "S-%lu-", SID_REVISION );
-
- // Identifier authority
- if ((sia->Value[0] != 0) || (sia->Value[1] != 0))
- {
- sprintf(name + strlen(name), "0x%02hx%02hx%02hx%02hx%02hx%02hx",
- (USHORT)sia->Value[0],
- (USHORT)sia->Value[1],
- (USHORT)sia->Value[2],
- (USHORT)sia->Value[3],
- (USHORT)sia->Value[4],
- (USHORT)sia->Value[5]);
- }
- else
- {
- sprintf(name + strlen(name), "%lu",
- (ULONG)(sia->Value[5] ) +
- (ULONG)(sia->Value[4] << 8) +
- (ULONG)(sia->Value[3] << 16) +
- (ULONG)(sia->Value[2] << 24) );
- }
-
- // finally, the sub-authorities
- for (i=0 ; i<count; i++) {
- sprintf(name + strlen(name), "-%lu",
- *GetSidSubAuthority(sid, i) );
- }
-
- return name;
-}
-
-/*
- * Returns a string to represent the given security identifier (SID).
- * If the account is known to the local computer then the account
- * domain is returned. The format will be \\name or domain\\name depending
- * on if the computer belongs to a domain.
- * If the account name is not known then the textual representation of
- * SID is returned -- eg: S-1-5-21-2818032319-470147023-1036452850-13037.
- */
-static char *getSIDString(SID* sid) {
- char domain[255];
- char name[255];
- DWORD domainLen = sizeof(domain);
- DWORD nameLen = sizeof(name);
- SID_NAME_USE use;
-
- if(!IsValidSid(sid)) {
- return strdup("<Invalid SID>");
- }
-
- if (LookupAccountSid(NULL, sid, name, &nameLen, domain, &domainLen, &use)) {
- int len = strlen(name) + strlen(domain) + 3;
- char* s = (char*)malloc(len);
- if (s != NULL) {
- strcpy(s, domain);
- strcat(s, "\\\\");
- strcat(s, name);
- }
- return s;
- } else {
- return getTextualSid(sid);
- }
-}
-
-
-
-/*
- * Returns 1 if the specified file is on a file system that supports
- * persistent ACLs (On NTFS file systems returns true, on FAT32 file systems
- * returns false), otherwise 0. Returns -1 if error.
- */
-static int isSecuritySupported(const char* path) {
- char* root;
- char* p;
- BOOL res;
- DWORD dwMaxComponentLength;
- DWORD dwFlags;
- char fsName[128];
- DWORD fsNameLength;
-
- /*
- * Get root directory. For UNCs the slash after the share name is required.
- */
- root = strdup(path);
- if (*root == '\\') {
- /*
- * \\server\share\file ==> \\server\share\
- */
- int slashskip = 3;
- p = root;
- while ((*p == '\\') && (slashskip > 0)) {
- char* p2;
- p++;
- p2 = strchr(p, '\\');
- if ((p2 == NULL) || (*p2 != '\\')) {
- free(root);
- fprintf(stderr, "Malformed UNC");
- return -1;
- }
- p = p2;
- slashskip--;
- }
- if (slashskip != 0) {
- free(root);
- fprintf(stderr, "Malformed UNC");
- return -1;
- }
- p++;
- *p = '\0';
-
- } else {
- p = strchr(root, '\\');
-
- /*
- * Relative path so use current directory
- */
- if (p == NULL) {
- free(root);
- root = malloc(255);
- if (GetCurrentDirectory(255, root) == 0) {
- printLastError("GetCurrentDirectory failed");
- return -1;
- }
- p = strchr(root, '\\');
- if (p == NULL) {
- fprintf(stderr, "GetCurrentDirectory doesn't include drive letter!!!!\n");
- return -1;
- }
- }
- p++;
- *p = '\0';
- }
-
- /*
- * Get the volume information - this gives us the file system file and
- * also tells us if the file system supports persistent ACLs.
- */
- fsNameLength = sizeof(fsName)-1;
- res = GetVolumeInformation(root,
- NULL, // address of name of the volume, can be NULL
- 0, // length of volume name
- NULL, // address of volume serial number, can be NULL
- &dwMaxComponentLength,
- &dwFlags,
- fsName,
- fsNameLength);
- if (res == 0) {
- printLastError("GetVolumeInformation failed");
- free(root);
- return -1;
- }
-
- free(root);
- return (dwFlags & FS_PERSISTENT_ACLS) ? 1 : 0;
-}
-
-
-/*
- * Returns the security descriptor for a file.
- */
-static SECURITY_DESCRIPTOR* getFileSecurityDescriptor(const char* path) {
- SECURITY_DESCRIPTOR* sd;
- DWORD len = 0;
- SECURITY_INFORMATION info =
- OWNER_SECURITY_INFORMATION | DACL_SECURITY_INFORMATION;
-
- GetFileSecurity(path, info , 0, 0, &len);
- if (GetLastError() != ERROR_INSUFFICIENT_BUFFER) {
- printLastError("GetFileSecurity failed");
- return NULL;
- }
- sd = (SECURITY_DESCRIPTOR *)malloc(len);
- if (sd == NULL) {
- fprintf(stderr, "Out of memory");
- } else {
- if (!GetFileSecurity(path, info, sd, len, &len)) {
- printLastError("GetFileSecurity failed");
- free(sd);
- return NULL;
- }
- }
- return sd;
-}
-
-
-/*
- * Revoke all access to the specific file
- */
-static int revokeAll(const char* path) {
- SECURITY_DESCRIPTOR* sd;
- SID* owner;
- ACL *acl;
- BOOL defaulted, present;
- ACL_SIZE_INFORMATION acl_size_info;
- DWORD i, count;
- char* str;
-
- /*
- * Get security descriptor for file; From security descriptor get the
- * owner SID, and the DACL.
- */
- sd = getFileSecurityDescriptor(path);
- if (sd == NULL) {
- return -1; /* error already reported */
- }
- if (!GetSecurityDescriptorOwner(sd, &owner, &defaulted)) {
- printLastError("GetSecurityDescriptorOwner failed");
- return -1;
- }
- str = getSIDString(owner);
- if (str != NULL) {
- printf("owner: %s\n", str);
- free(str);
- }
- if (!GetSecurityDescriptorDacl(sd, &present, &acl, &defaulted)) {
- printLastError("GetSecurityDescriptorDacl failed");
- return -1;
- }
- if (!present) {
- fprintf(stderr, "Security descriptor does not contain a DACL");
- return -1;
- }
-
- /*
- * If DACL is NULL there is no access to the file - we are done
- */
- if (acl == NULL) {
- return 1;
- }
-
- /*
- * Iterate over the ACEs. For each "allow" type check that the SID
- * matches the owner - if not we remove the ACE from the ACL
- */
- if (!GetAclInformation(acl, (void *) &acl_size_info, sizeof(acl_size_info),
- AclSizeInformation)) {
- printLastError("GetAclInformation failed");
- return -1;
- }
- count = acl_size_info.AceCount;
- i = 0;
- while (count > 0) {
- void* ace;
- ACCESS_ALLOWED_ACE *access;
- SID* sid;
- BOOL deleted;
-
- if (!GetAce(acl, i, &ace)) {
- printLastError("GetAce failed");
- return -1;
- }
- if (((ACCESS_ALLOWED_ACE *)ace)->Header.AceType != ACCESS_ALLOWED_ACE_TYPE) {
- continue;
- }
- access = (ACCESS_ALLOWED_ACE *)ace;
- sid = (SID *) &access->SidStart;
-
-
- deleted = FALSE;
- if (!EqualSid(owner, sid)) {
- /*
- * If the ACE allows any access then the file then we
- * delete it.
- */
- if (access->Mask & ANY_ACCESS) {
- str = getSIDString(sid);
- if (str != NULL) {
- printf("remove ALLOW %s\n", str);
- free(str);
- }
- if (DeleteAce(acl, i) == 0) {
- printLastError("DeleteAce failed");
- return -1;
- }
- deleted = TRUE;
- }
- }
-
- if (!deleted) {
- str = getSIDString(sid);
- if (str != NULL) {
- printf("ALLOW %s (access mask=%x)\n", str, access->Mask);
- free(str);
- }
-
- /* onto the next ACE */
- i++;
- }
- count--;
- }
-
- /*
- * No changes - only owner has access
- */
- if (i == acl_size_info.AceCount) {
- printf("No changes.\n");
- return 1;
- }
-
- /*
- * Create security descriptor and set its DACL to the version
- * that we just edited
- */
- if (!InitializeSecurityDescriptor(sd, SECURITY_DESCRIPTOR_REVISION)) {
- printLastError("InitializeSecurityDescriptor failed");
- return -1;
- }
- if (!SetSecurityDescriptorDacl(sd, present, acl, defaulted)) {
- printLastError("SetSecurityDescriptorDacl failed");
- return -1;
- }
- if (!SetFileSecurity(path, DACL_SECURITY_INFORMATION, sd)) {
- printLastError("SetFileSecurity failed");
- return -1;
- }
-
- printf("File updated.\n");
-
- return 1;
-}
-
-/*
- * Convert slashes in the pathname to backslashes if needed.
- */
-static char* convert_path(const char* p) {
- int i = 0;
- char* path = strdup(p);
- while (p[i] != '\0') {
- if (p[i] == '/') {
- path[i] = '\\';
- }
- i++;
- }
- return path;
-}
-
-/*
- * Usage: revokeall file
- */
-int main( int argc, char *argv[])
-{
- int rc;
- const char* path;
-
- if (argc != 2) {
- fprintf(stderr, "Usage: %s file\n", argv[0]);
- return -1;
- }
- path = convert_path(argv[1]);
- printf("Revoking all non-owner access to %s\n", path);
- rc = isSecuritySupported(path);
- if (rc != 1) {
- if (rc == 0) {
- printf("File security not supported on this file system\n");
- }
- return rc;
- } else {
- return revokeAll(path);
- }
-}
Binary file test/jdk/sun/management/windows/revokeall.exe has changed
--- a/test/jdk/sun/net/InetAddress/nameservice/simple/DefaultCaching.java Fri May 17 13:21:44 2019 +0100
+++ b/test/jdk/sun/net/InetAddress/nameservice/simple/DefaultCaching.java Thu May 23 11:07:37 2019 +0100
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2006, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2006, 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,98 +33,112 @@
import java.io.FileWriter;
import java.io.PrintWriter;
import java.io.BufferedWriter;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import static java.nio.file.StandardCopyOption.REPLACE_EXISTING;
public class DefaultCaching {
public static void main(String args[]) throws Exception {
- String hostsFileName = System.getProperty("test.src", ".") + "/DefaultCachingHosts";
+ String hostsFileNameSrc = System.getProperty("test.src", ".") + "/DefaultCachingHosts";
+ String hostsFileName = System.getProperty("user.dir", ".") + "/DefaultCachingHosts";
+ if (!hostsFileNameSrc.equals(hostsFileName)) {
+ Files.copy(Path.of(hostsFileNameSrc), Path.of(hostsFileName), REPLACE_EXISTING);
+ System.out.println("Host file created: " + hostsFileName);
+ }
System.setProperty("jdk.net.hosts.file", hostsFileName);
// initial mapping
// name service needs to resolve this.
addMappingToHostsFile("theclub", "129.156.220.219", hostsFileName, false);
- test ("theclub", "129.156.220.219", true); // lk: 1
- test ("luster", "1.16.20.2", false); // lk: 2
+ test("theclub", "129.156.220.219", true); // lk: 1
+ test("luster", "1.16.20.2", false); // lk: 2
// name service now needs to know about luster
addMappingToHostsFile("luster", "10.5.18.21", hostsFileName, true);
- test ("luster", "1.16.20.2", false); // lk: 2
- sleep (10+1);
+ test("luster", "1.16.20.2", false); // lk: 2
+ sleep(10+1);
test("luster", "10.5.18.21", true, 3); // lk: 3
- sleep (5);
+ sleep(5);
// new mapping for theclub and rewrite existing foo and luster mappings
addMappingToHostsFile("theclub", "129.156.220.1", hostsFileName, false);
addMappingToHostsFile("foo", "10.5.18.22", hostsFileName, true);
addMappingToHostsFile("luster", "10.5.18.21", hostsFileName, true);
- test ("theclub", "129.156.220.219", true, 3);
- test ("luster", "10.5.18.21", true, 3);
- test ("bar", "10.5.18.22", false, 4);
- test ("foo", "10.5.18.22", true, 5);
+ test("theclub", "129.156.220.219", true, 3);
+ test("luster", "10.5.18.21", true, 3);
+ test("bar", "10.5.18.22", false, 4);
+ test("foo", "10.5.18.22", true, 5);
// now delay to see if theclub has expired
- sleep (5);
+ sleep(5);
- test ("foo", "10.5.18.22", true, 5);
- test ("theclub", "129.156.220.1", true, 6);
+ test("foo", "10.5.18.22", true, 5);
+ test("theclub", "129.156.220.1", true, 6);
- sleep (11);
+ sleep(11);
// now see if luster has expired
- test ("luster", "10.5.18.21", true, 7);
- test ("theclub", "129.156.220.1", true, 7);
+ test("luster", "10.5.18.21", true, 7);
+ test("theclub", "129.156.220.1", true, 7);
// now delay to see if 3rd has expired
- sleep (10+6);
+ sleep(10+6);
- test ("theclub", "129.156.220.1", true, 8);
- test ("luster", "10.5.18.21", true, 8);
- test ("foo", "10.5.18.22", true, 9);
+ test("theclub", "129.156.220.1", true, 8);
+ test("luster", "10.5.18.21", true, 8);
+ test("foo", "10.5.18.22", true, 9);
}
/* throws RuntimeException if it fails */
- static void test (String host, String address,
- boolean shouldSucceed, int count) {
- test (host, address, shouldSucceed);
+ static void test(String host, String address,
+ boolean shouldSucceed, int count) {
+ test(host, address, shouldSucceed);
}
- static void sleep (int seconds) {
+ static void sleep(int seconds) {
try {
- Thread.sleep (seconds * 1000);
+ Thread.sleep(seconds * 1000);
} catch (InterruptedException e) {}
}
- static void test (String host, String address, boolean shouldSucceed) {
+ static void test(String host, String address, boolean shouldSucceed) {
InetAddress addr = null;
try {
- addr = InetAddress.getByName (host);
+ addr = InetAddress.getByName(host);
if (!shouldSucceed) {
- throw new RuntimeException (host+":"+address+": should fail");
-
+ throw new RuntimeException(host+":"+address+": should fail (got "
+ + addr + ")");
}
if (!address.equals(addr.getHostAddress())) {
- throw new RuntimeException(host+":"+address+": compare failed");
+ throw new RuntimeException(host+":"+address+": compare failed (found "
+ + addr + ")");
}
+ System.out.println("test: " + host + "/" + address
+ + " succeeded - got " + addr);
} catch (UnknownHostException e) {
if (shouldSucceed) {
throw new RuntimeException(host+":"+address+": should succeed");
+ } else {
+ System.out.println("test: " + host + "/" + address
+ + " succeeded - got expected " + e);
}
}
}
- private static void addMappingToHostsFile (String host,
- String addr,
- String hostsFileName,
- boolean append)
+ private static void addMappingToHostsFile(String host,
+ String addr,
+ String hostsFileName,
+ boolean append)
throws Exception {
String mapping = addr + " " + host;
try (PrintWriter hfPWriter = new PrintWriter(new BufferedWriter(
new FileWriter(hostsFileName, append)))) {
hfPWriter.println(mapping);
-}
+ }
}
}
--- a/test/jdk/sun/net/ftp/B6427768.java Fri May 17 13:21:44 2019 +0100
+++ b/test/jdk/sun/net/ftp/B6427768.java Thu May 23 11:07:37 2019 +0100
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2006, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2006, 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
@@ -105,13 +105,14 @@
}
public static void main(String[] args) throws IOException {
- FtpServer server = new FtpServer(0);
+ InetAddress loopback = InetAddress.getLoopbackAddress();
+ FtpServer server = new FtpServer(loopback, 0);
int port = server.getLocalPort();
server.setFileSystemHandler(new MyFileSystemHandler("/"));
server.setAuthHandler(new MyAuthHandler());
server.start();
- URL url = new URL("ftp://user:passwd@localhost:" + port + "/foo.txt");
- URLConnection con = url.openConnection();
+ URL url = new URL("ftp://user:passwd@" + server.getAuthority() + "/foo.txt");
+ URLConnection con = url.openConnection(Proxy.NO_PROXY);
// triggers the connection
try {
con.getInputStream();
--- a/test/jdk/sun/net/www/ftptest/FtpCommandHandler.java Fri May 17 13:21:44 2019 +0100
+++ b/test/jdk/sun/net/www/ftptest/FtpCommandHandler.java Thu May 23 11:07:37 2019 +0100
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2006, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2006, 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
@@ -238,14 +238,14 @@
return;
}
try {
- if (pasv == null)
- pasv = new ServerSocket(0);
- int port = pasv.getLocalPort();
InetAddress rAddress = cmd.getLocalAddress();
if (rAddress instanceof Inet6Address) {
out.println("500 PASV illegal over IPv6 addresses, use EPSV.");
return;
}
+ if (pasv == null)
+ pasv = new ServerSocket(0, 0, rAddress);
+ int port = pasv.getLocalPort();
byte[] a = rAddress.getAddress();
out.println("227 Entering Passive Mode " + a[0] + "," + a[1] + "," + a[2] + "," + a[3] + "," +
(port >> 8) + "," + (port & 0xff) );
@@ -266,7 +266,7 @@
}
try {
if (pasv == null)
- pasv = new ServerSocket(0);
+ pasv = new ServerSocket(0, 0, parent.getInetAddress());
int port = pasv.getLocalPort();
out.println("229 Entering Extended Passive Mode (|||" + port + "|)");
} catch (IOException e) {
--- a/test/jdk/sun/net/www/ftptest/FtpServer.java Fri May 17 13:21:44 2019 +0100
+++ b/test/jdk/sun/net/www/ftptest/FtpServer.java Thu May 23 11:07:37 2019 +0100
@@ -110,8 +110,12 @@
return listener.getLocalPort();
}
+ public InetAddress getInetAddress() {
+ return listener.getInetAddress();
+ }
+
public String getAuthority() {
- InetAddress address = listener.getInetAddress();
+ InetAddress address = getInetAddress();
String hostaddr = address.isAnyLocalAddress()
? "localhost" : address.getHostAddress();
if (hostaddr.indexOf(':') > -1) {
--- a/test/jdk/sun/net/www/http/HttpClient/RetryPost.java Fri May 17 13:21:44 2019 +0100
+++ b/test/jdk/sun/net/www/http/HttpClient/RetryPost.java Thu May 23 11:07:37 2019 +0100
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2006, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2006, 2019, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -25,6 +25,7 @@
* @test
* @bug 6427251 6382788
* @modules jdk.httpserver
+ * @library /test/lib
* @run main RetryPost
* @run main/othervm -Dsun.net.http.retryPost=false RetryPost noRetry
* @summary HttpURLConnection automatically retries non-idempotent method POST
@@ -36,12 +37,14 @@
import java.io.IOException;
import java.io.OutputStream;
import java.net.HttpURLConnection;
+import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.Proxy;
import java.net.SocketException;
import java.net.URL;
import java.util.concurrent.Executors;
import java.util.concurrent.ExecutorService;
+import jdk.test.lib.net.URIBuilder;
public class RetryPost
{
@@ -70,7 +73,12 @@
void doClient() {
try {
InetSocketAddress address = httpServer.getAddress();
- URL url = new URL("http://localhost:" + address.getPort() + "/test/");
+ URL url = URIBuilder.newBuilder()
+ .scheme("http")
+ .host(address.getAddress())
+ .port(address.getPort())
+ .path("/test/")
+ .toURLUnchecked();
HttpURLConnection uc = (HttpURLConnection)url.openConnection(Proxy.NO_PROXY);
uc.setDoOutput(true);
uc.setRequestMethod("POST");
@@ -99,7 +107,8 @@
* Http Server
*/
public void startHttpServer(boolean shouldRetry) throws IOException {
- httpServer = com.sun.net.httpserver.HttpServer.create(new InetSocketAddress(0), 0);
+ InetAddress loopback = InetAddress.getLoopbackAddress();
+ httpServer = com.sun.net.httpserver.HttpServer.create(new InetSocketAddress(loopback, 0), 0);
httpHandler = new MyHandler(shouldRetry);
HttpContext ctx = httpServer.createContext("/test/", httpHandler);
--- a/test/jdk/sun/net/www/http/KeepAliveCache/KeepAliveTimerThread.java Fri May 17 13:21:44 2019 +0100
+++ b/test/jdk/sun/net/www/http/KeepAliveCache/KeepAliveTimerThread.java Thu May 23 11:07:37 2019 +0100
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2002, 2010, 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
@@ -26,6 +26,8 @@
* @library /test/lib
* @bug 4701299
* @summary Keep-Alive-Timer thread management in KeepAliveCache causes memory leak
+ * @run main KeepAliveTimerThread
+ * @run main/othervm -Djava.net.preferIPv6Addresses=true KeepAliveTimerThread
*/
import java.net.*;
@@ -103,8 +105,10 @@
public static void main(String args[]) throws Exception {
- ServerSocket ss = new ServerSocket(0);
- Server s = new Server (ss);
+ InetAddress loopback = InetAddress.getLoopbackAddress();
+ ServerSocket ss = new ServerSocket();
+ ss.bind(new InetSocketAddress(loopback, 0));
+ Server s = new Server(ss);
s.start();
URL url = URIBuilder.newBuilder()
--- a/test/jdk/sun/net/www/http/KeepAliveStream/InfiniteLoop.java Fri May 17 13:21:44 2019 +0100
+++ b/test/jdk/sun/net/www/http/KeepAliveStream/InfiniteLoop.java Thu May 23 11:07:37 2019 +0100
@@ -26,6 +26,9 @@
* @bug 8004863
* @modules jdk.httpserver
* @summary Checks for proper close code in KeepAliveStream
+ * @library /test/lib
+ * @run main InfiniteLoop
+ * @run main/othervm -Djava.net.preferIPv6Addresses=true InfiniteLoop
*/
import com.sun.net.httpserver.HttpExchange;
@@ -35,10 +38,14 @@
import java.io.IOException;
import java.io.OutputStream;
import java.net.HttpURLConnection;
+import java.net.InetAddress;
import java.net.InetSocketAddress;
+import java.net.Proxy;
import java.net.URL;
import java.util.concurrent.Phaser;
+import jdk.test.lib.net.URIBuilder;
+
// Racey test, will not always fail, but if it does then we have a problem.
public class InfiniteLoop {
@@ -49,11 +56,16 @@
server.start();
try {
InetSocketAddress address = server.getAddress();
- URL url = new URL("http://localhost:" + address.getPort()
- + "/test/InfiniteLoop");
+ URL url = URIBuilder.newBuilder()
+ .scheme("http")
+ .host(server.getAddress().getAddress())
+ .port(server.getAddress().getPort())
+ .path("/test/InfiniteLoop")
+ .toURL();
final Phaser phaser = new Phaser(2);
for (int i=0; i<10; i++) {
- HttpURLConnection uc = (HttpURLConnection)url.openConnection();
+ HttpURLConnection uc = (HttpURLConnection)
+ url.openConnection(Proxy.NO_PROXY);
final InputStream is = uc.getInputStream();
final Thread thread = new Thread() {
public void run() {
--- a/test/jdk/sun/net/www/protocol/http/B6369510.java Fri May 17 13:21:44 2019 +0100
+++ b/test/jdk/sun/net/www/protocol/http/B6369510.java Thu May 23 11:07:37 2019 +0100
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2006, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2006, 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
@@ -59,11 +59,12 @@
void doClient() {
try {
InetSocketAddress address = httpServer.getAddress();
- String urlString = "http://" + InetAddress.getLocalHost().getHostName() + ":" + address.getPort() + "/test/";
+ String urlString = "http://" + InetAddress.getLocalHost().getHostName()
+ + ":" + address.getPort() + "/test/";
System.out.println("URL == " + urlString);
// GET Request
- URL url = new URL("http://" + InetAddress.getLocalHost().getHostName() + ":" + address.getPort() + "/test/");
+ URL url = new URL(urlString);
HttpURLConnection uc = (HttpURLConnection)url.openConnection(Proxy.NO_PROXY);
int resp = uc.getResponseCode();
if (resp != 200)
@@ -95,7 +96,8 @@
* Http Server
*/
public void startHttpServer() throws IOException {
- httpServer = com.sun.net.httpserver.HttpServer.create(new InetSocketAddress(0), 0);
+ InetAddress localhost = InetAddress.getLocalHost();
+ httpServer = HttpServer.create(new InetSocketAddress(localhost, 0), 0);
// create HttpServer context
HttpContext ctx = httpServer.createContext("/test/", new MyHandler());
--- a/test/jdk/sun/net/www/protocol/http/BasicLongCredentials.java Fri May 17 13:21:44 2019 +0100
+++ b/test/jdk/sun/net/www/protocol/http/BasicLongCredentials.java Thu May 23 11:07:37 2019 +0100
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2010, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2010, 2019, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -26,6 +26,9 @@
* @bug 6947917
* @modules jdk.httpserver
* @summary Error in basic authentication when user name and password are long
+ * @library /test/lib
+ * @run main BasicLongCredentials
+ * @run main/othervm -Djava.net.preferIPv6Addresses=true BasicLongCredentials
*/
import com.sun.net.httpserver.BasicAuthenticator;
@@ -37,11 +40,15 @@
import java.io.InputStream;
import java.io.IOException;
import java.net.Authenticator;
+import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.PasswordAuthentication;
+import java.net.Proxy;
import java.net.HttpURLConnection;
import java.net.URL;
+import jdk.test.lib.net.URIBuilder;
+
public class BasicLongCredentials {
static final String USERNAME = "ThisIsMyReallyReallyReallyReallyReallyReally" +
@@ -51,7 +58,8 @@
static final String REALM = "foobar@test.realm";
public static void main (String[] args) throws Exception {
- HttpServer server = HttpServer.create(new InetSocketAddress(0), 0);
+ InetAddress loopback = InetAddress.getLoopbackAddress();
+ HttpServer server = HttpServer.create(new InetSocketAddress(loopback, 0), 0);
try {
Handler handler = new Handler();
HttpContext ctx = server.createContext("/test", handler);
@@ -66,8 +74,13 @@
Authenticator.setDefault(new MyAuthenticator());
- URL url = new URL("http://localhost:"+server.getAddress().getPort()+"/test/");
- HttpURLConnection urlc = (HttpURLConnection)url.openConnection();
+ URL url = URIBuilder.newBuilder()
+ .scheme("http")
+ .host(server.getAddress().getAddress())
+ .port(server.getAddress().getPort())
+ .path("/test/")
+ .toURL();
+ HttpURLConnection urlc = (HttpURLConnection)url.openConnection(Proxy.NO_PROXY);
InputStream is = urlc.getInputStream();
int c = 0;
while (is.read()!= -1) { c ++; }
--- a/test/jdk/sun/net/www/protocol/http/NTLMTest.java Fri May 17 13:21:44 2019 +0100
+++ b/test/jdk/sun/net/www/protocol/http/NTLMTest.java Thu May 23 11:07:37 2019 +0100
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2007, 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
@@ -25,6 +25,7 @@
* @test
* @bug 6520665 6357133
* @modules java.base/sun.net.www
+ * @library /test/lib
* @run main/othervm NTLMTest
* @summary 6520665 & 6357133: NTLM authentication issues.
*/
@@ -32,35 +33,41 @@
import java.net.*;
import java.io.*;
import sun.net.www.MessageHeader;
+import jdk.test.lib.net.URIBuilder;
public class NTLMTest
{
- public static void main(String[] args) {
+ public static void main(String[] args) throws Exception {
Authenticator.setDefault(new NullAuthenticator());
try {
+ InetAddress loopback = InetAddress.getLoopbackAddress();
+
// Test with direct connection.
- ServerSocket serverSS = new ServerSocket(0);
- startServer(serverSS, false);
- runClient(Proxy.NO_PROXY, serverSS.getLocalPort());
-
+ try (NTLMServer server = startServer(new ServerSocket(0, 0, loopback), false)) {
+ runClient(Proxy.NO_PROXY, server.getLocalPort());
+ }
// Test with proxy.
- serverSS = new ServerSocket(0);
- startServer(serverSS, true /*proxy*/);
- SocketAddress proxyAddr = new InetSocketAddress("localhost", serverSS.getLocalPort());
- runClient(new Proxy(java.net.Proxy.Type.HTTP, proxyAddr), 8888);
-
+ try (NTLMServer server =
+ startServer(new ServerSocket(0, 0, loopback), true /*proxy*/)) {
+ SocketAddress proxyAddr = new InetSocketAddress(loopback, server.getLocalPort());
+ runClient(new Proxy(java.net.Proxy.Type.HTTP, proxyAddr), 8888);
+ }
} catch (IOException e) {
- e.printStackTrace();
+ throw e;
}
}
static void runClient(Proxy proxy, int serverPort) {
try {
- String urlStr = "http://localhost:" + serverPort + "/";
- URL url = new URL(urlStr);
+ URL url = URIBuilder.newBuilder()
+ .scheme("http")
+ .loopback()
+ .port(serverPort)
+ .path("/")
+ .toURLUnchecked();
HttpURLConnection uc = (HttpURLConnection) url.openConnection(proxy);
- uc.getInputStream();
+ uc.getInputStream().readAllBytes();
} catch (ProtocolException e) {
/* java.net.ProtocolException: Server redirected too many times (20) */
@@ -70,6 +77,7 @@
* returned HTTP response code: 401 for URL: ..."
*/
//ioe.printStackTrace();
+ System.out.println("Got expected " + ioe);
} catch (NullPointerException npe) {
throw new RuntimeException("Failed: NPE thrown ", npe);
}
@@ -93,34 +101,56 @@
"Content-Length: 0\r\n" +
"Proxy-Authenticate: NTLM TlRMTVNTUAACAAAAAAAAACgAAAABggAAU3J2Tm9uY2UAAAAAAAAAAA==\r\n\r\n"};
- static void startServer(ServerSocket serverSS, boolean proxy) {
- final ServerSocket ss = serverSS;
- final boolean isProxy = proxy;
+ static class NTLMServer extends Thread implements AutoCloseable {
+ final ServerSocket ss;
+ final boolean isProxy;
+ volatile boolean closed;
+
+ NTLMServer(ServerSocket serverSS, boolean proxy) {
+ super();
+ setDaemon(true);
+ ss = serverSS;
+ isProxy = proxy;
+ }
+
+ public int getLocalPort() { return ss.getLocalPort(); }
- Thread thread = new Thread(new Runnable() {
- public void run() {
- boolean doing2ndStageNTLM = false;
- while (true) {
- try {
- Socket s = ss.accept();
- if (!doing2ndStageNTLM) {
- handleConnection(s, isProxy ? proxyResp : serverResp, 0, 1);
- doing2ndStageNTLM = true;
- } else {
- handleConnection(s, isProxy ? proxyResp : serverResp, 1, 2);
- doing2ndStageNTLM = false;
- }
- connectionCount++;
- //System.out.println("connectionCount = " + connectionCount);
+ @Override
+ public void run() {
+ boolean doing2ndStageNTLM = false;
+ while (!closed) {
+ try {
+ Socket s = ss.accept();
+ if (!doing2ndStageNTLM) {
+ handleConnection(s, isProxy ? proxyResp : serverResp, 0, 1);
+ doing2ndStageNTLM = true;
+ } else {
+ handleConnection(s, isProxy ? proxyResp : serverResp, 1, 2);
+ doing2ndStageNTLM = false;
+ }
+ connectionCount++;
+ //System.out.println("connectionCount = " + connectionCount);
+ } catch (IOException ioe) {
+ if (!closed) ioe.printStackTrace();
+ }
+ }
+ }
- } catch (IOException ioe) {
- ioe.printStackTrace();
- }
- }
- } });
- thread.setDaemon(true);
- thread.start();
+ @Override
+ public void close() {
+ if (closed) return;
+ synchronized(this) {
+ if (closed) return;
+ closed = true;
+ }
+ try { ss.close(); } catch (IOException x) { };
+ }
+ }
+ public static NTLMServer startServer(ServerSocket serverSS, boolean proxy) {
+ NTLMServer server = new NTLMServer(serverSS, proxy);
+ server.start();
+ return server;
}
static int connectionCount = 0;
--- a/test/jdk/sun/net/www/protocol/https/HttpsURLConnection/CookieHttpsClientTest.java Fri May 17 13:21:44 2019 +0100
+++ b/test/jdk/sun/net/www/protocol/https/HttpsURLConnection/CookieHttpsClientTest.java Thu May 23 11:07:37 2019 +0100
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 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
@@ -29,21 +29,25 @@
* @bug 7129083
* @summary Cookiemanager does not store cookies if url is read
* before setting cookiemanager
+ * @library /test/lib
* @run main/othervm CookieHttpsClientTest
*/
import java.net.CookieHandler;
import java.net.CookieManager;
import java.net.CookiePolicy;
+import java.net.InetAddress;
import java.net.URL;
import java.io.InputStream;
import java.io.IOException;
import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.HttpsURLConnection;
+import javax.net.ssl.SSLHandshakeException;
import javax.net.ssl.SSLServerSocket;
import javax.net.ssl.SSLServerSocketFactory;
import javax.net.ssl.SSLSession;
import javax.net.ssl.SSLSocket;
+import jdk.test.lib.net.URIBuilder;
public class CookieHttpsClientTest {
static final int TIMEOUT = 10 * 1000;
@@ -91,10 +95,11 @@
* to avoid infinite hangs.
*/
void doServerSide() throws Exception {
+ InetAddress loopback = InetAddress.getLoopbackAddress();
SSLServerSocketFactory sslssf =
(SSLServerSocketFactory) SSLServerSocketFactory.getDefault();
SSLServerSocket sslServerSocket =
- (SSLServerSocket) sslssf.createServerSocket(serverPort);
+ (SSLServerSocket) sslssf.createServerSocket(serverPort, 0, loopback);
serverPort = sslServerSocket.getLocalPort();
/*
@@ -137,10 +142,17 @@
return true;
}});
- URL url = new URL("https://localhost:" + serverPort +"/");
+ URL url = URIBuilder.newBuilder()
+ .scheme("https")
+ .loopback()
+ .port(serverPort)
+ .path("/")
+ .toURL();
+
+ System.out.println("Client ready to connect to: " + url);
// Run without a CookieHandler first
- InputStream in = url.openConnection().getInputStream();
+ InputStream in = url.openConnection(java.net.Proxy.NO_PROXY).getInputStream();
while (in.read() != -1); // read response body so connection can be reused
// Set a CookeHandler and retest using the HttpClient from the KAC
@@ -183,6 +195,10 @@
volatile Exception serverException = null;
volatile Exception clientException = null;
+ private boolean sslConnectionFailed() {
+ return clientException instanceof SSLHandshakeException;
+ }
+
public static void main(String args[]) throws Exception {
String keyFilename =
System.getProperty("test.src", ".") + "/" + pathToStores +
@@ -229,7 +245,11 @@
*/
if (separateServerThread) {
if (serverThread != null) {
- serverThread.join();
+ // don't join the server thread if the
+ // client failed to connect
+ if (!sslConnectionFailed()) {
+ serverThread.join();
+ }
}
} else {
if (clientThread != null) {
@@ -259,7 +279,7 @@
*/
if ((local != null) && (remote != null)) {
// If both failed, return the curthread's exception.
- local.initCause(remote);
+ local.addSuppressed(remote);
exception = local;
} else if (local != null) {
exception = local;
@@ -274,7 +294,7 @@
* output it.
*/
if (exception != null) {
- if (exception != startException) {
+ if (exception != startException && startException != null) {
exception.addSuppressed(startException);
}
throw exception;
@@ -323,7 +343,7 @@
/*
* Our client thread just died.
*/
- System.err.println("Client died...");
+ System.err.println("Client died: " + e);
clientException = e;
}
}
@@ -333,6 +353,7 @@
try {
doClientSide();
} catch (Exception e) {
+ System.err.println("Client died: " + e);
clientException = e;
}
}
--- a/test/jdk/sun/net/www/protocol/https/HttpsURLConnection/HttpsPost.java Fri May 17 13:21:44 2019 +0100
+++ b/test/jdk/sun/net/www/protocol/https/HttpsURLConnection/HttpsPost.java Thu May 23 11:07:37 2019 +0100
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2001, 2011, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2001, 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,7 +26,9 @@
* @bug 4423074
* @summary Need to rebase all the duplicated classes from Merlin.
* This test will check out http POST
+ * @library /test/lib
* @run main/othervm HttpsPost
+ * @run main/othervm -Djava.net.preferIPv6Addresses=true HttpsPost
*
* SunJSSE does not support dynamic system properties, no way to re-use
* system properties in samevm/agentvm mode.
@@ -35,6 +37,7 @@
import java.io.*;
import java.net.*;
import javax.net.ssl.*;
+import jdk.test.lib.net.URIBuilder;
public class HttpsPost {
@@ -95,12 +98,16 @@
* to avoid infinite hangs.
*/
void doServerSide() throws Exception {
+ InetAddress loopback = InetAddress.getLoopbackAddress();
SSLServerSocketFactory sslssf =
(SSLServerSocketFactory) SSLServerSocketFactory.getDefault();
SSLServerSocket sslServerSocket =
- (SSLServerSocket) sslssf.createServerSocket(serverPort);
+ (SSLServerSocket) sslssf.createServerSocket(serverPort, 0, loopback);
serverPort = sslServerSocket.getLocalPort();
+ System.out.println("Starting server at: "
+ + sslServerSocket.getInetAddress()
+ + ":" + serverPort);
/*
* Signal Client, we're ready for his connect.
*/
@@ -155,10 +162,15 @@
}
// Send HTTP POST request to server
- URL url = new URL("https://localhost:"+serverPort);
+ URL url = URIBuilder.newBuilder()
+ .scheme("https")
+ .loopback()
+ .port(serverPort)
+ .toURL();
+ System.out.println("Client connecting to: " + url);
HttpsURLConnection.setDefaultHostnameVerifier(new NameVerifier());
- HttpsURLConnection http = (HttpsURLConnection)url.openConnection();
+ HttpsURLConnection http = (HttpsURLConnection)url.openConnection(Proxy.NO_PROXY);
http.setDoOutput(true);
http.setRequestMethod("POST");
--- a/test/jdk/sun/net/www/protocol/https/HttpsURLConnection/PostThruProxy.java Fri May 17 13:21:44 2019 +0100
+++ b/test/jdk/sun/net/www/protocol/https/HttpsURLConnection/PostThruProxy.java Thu May 23 11:07:37 2019 +0100
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2001, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2001, 2019, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -27,8 +27,7 @@
import javax.net.*;
import javax.net.ssl.*;
-import jdk.test.lib.process.OutputAnalyzer;
-import jdk.test.lib.process.ProcessTools;
+import jdk.test.lib.net.URIBuilder;
/*
* @test
@@ -39,12 +38,6 @@
* that serves http POST method requests in secure channel, and a client
* that makes https POST request through a proxy.
* @library /test/lib
- * @build jdk.test.lib.Utils
- * jdk.test.lib.Asserts
- * jdk.test.lib.JDKToolFinder
- * jdk.test.lib.JDKToolLauncher
- * jdk.test.lib.Platform
- * jdk.test.lib.process.*
* @compile OriginServer.java ProxyTunnelServer.java
* @run main/othervm PostThruProxy
*/
@@ -62,6 +55,9 @@
static String passwd = "passphrase";
private static int serverPort = 0;
+ private static ProxyTunnelServer pserver;
+ private static TestServer server;
+ static final String RESPONSE_MSG = "Https POST thru proxy is successful";
/*
* The TestServer implements a OriginServer that
@@ -79,8 +75,7 @@
* @return bytes for the data in the response
*/
public byte[] getBytes() {
- return "Https POST thru proxy is successful".
- getBytes();
+ return RESPONSE_MSG.getBytes();
}
}
@@ -88,6 +83,7 @@
* Main method to create the server and client
*/
public static void main(String args[]) throws Exception {
+
String keyFilename = TEST_SRC + "/" + pathToStores + "/" + keyStoreFile;
String trustFilename = TEST_SRC + "/" + pathToStores + "/"
+ trustStoreFile;
@@ -97,16 +93,18 @@
System.setProperty("javax.net.ssl.trustStore", trustFilename);
System.setProperty("javax.net.ssl.trustStorePassword", passwd);
+ InetAddress loopback = InetAddress.getLoopbackAddress();
boolean useSSL = true;
/*
* setup the server
*/
try {
ServerSocketFactory ssf = getServerSocketFactory(useSSL);
- ServerSocket ss = ssf.createServerSocket(serverPort);
+ ServerSocket ss = ssf.createServerSocket(serverPort, 0, loopback);
ss.setSoTimeout(TIMEOUT); // 30 seconds
serverPort = ss.getLocalPort();
- new TestServer(ss);
+ server = new TestServer(ss);
+ System.out.println("Server started at: " + ss);
} catch (Exception e) {
System.out.println("Server side failed:" +
e.getMessage());
@@ -120,6 +118,12 @@
e.getMessage());
throw e;
}
+ long connectCount = pserver.getConnectCount();
+ if (connectCount == 0) {
+ throw new AssertionError("Proxy was not used!");
+ } else {
+ System.out.println("Proxy CONNECT count: " + connectCount);
+ }
}
private static ServerSocketFactory getServerSocketFactory
@@ -162,9 +166,15 @@
*/
HttpsURLConnection.setDefaultHostnameVerifier(
new NameVerifier());
- URL url = new URL("https://" + getHostname() +":" + serverPort);
+ URL url = URIBuilder.newBuilder()
+ .scheme("https")
+ .loopback()
+ .port(serverPort)
+ .toURL();
Proxy p = new Proxy(Proxy.Type.HTTP, pAddr);
+ System.out.println("Client connecting to: " + url);
+ System.out.println("Through proxy: " + pAddr);
HttpsURLConnection https = (HttpsURLConnection)url.openConnection(p);
https.setConnectTimeout(TIMEOUT);
https.setReadTimeout(TIMEOUT);
@@ -185,9 +195,15 @@
new InputStreamReader(
https.getInputStream()));
String inputLine;
- while ((inputLine = in.readLine()) != null)
+ boolean msgFound = false;
+ while ((inputLine = in.readLine()) != null) {
System.out.println("Client received: " + inputLine);
+ if (inputLine.contains(RESPONSE_MSG)) msgFound = true;
+ }
in.close();
+ if (!msgFound) {
+ throw new RuntimeException("POST message not found.");
+ }
} catch (SSLException e) {
if (ps != null)
ps.close();
@@ -208,20 +224,13 @@
}
static SocketAddress setupProxy() throws IOException {
- ProxyTunnelServer pserver = new ProxyTunnelServer();
+ InetAddress loopback = InetAddress.getLoopbackAddress();
+ pserver = new ProxyTunnelServer(loopback);
// disable proxy authentication
pserver.needUserAuth(false);
pserver.start();
- return new InetSocketAddress("localhost", pserver.getPort());
+ return new InetSocketAddress(loopback, pserver.getPort());
}
- private static String getHostname() {
- try {
- OutputAnalyzer oa = ProcessTools.executeCommand("hostname");
- return oa.getOutput().trim();
- } catch (Throwable e) {
- throw new RuntimeException("Get hostname failed.", e);
- }
- }
}
--- a/test/jdk/sun/net/www/protocol/https/HttpsURLConnection/PostThruProxyWithAuth.java Fri May 17 13:21:44 2019 +0100
+++ b/test/jdk/sun/net/www/protocol/https/HttpsURLConnection/PostThruProxyWithAuth.java Thu May 23 11:07:37 2019 +0100
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2001, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2001, 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
@@ -29,6 +29,7 @@
import jdk.test.lib.process.OutputAnalyzer;
import jdk.test.lib.process.ProcessTools;
+import jdk.test.lib.net.URIBuilder;
/*
* @test
@@ -47,6 +48,8 @@
* jdk.test.lib.process.*
* @compile OriginServer.java ProxyTunnelServer.java
* @run main/othervm -Djdk.http.auth.tunneling.disabledSchemes= PostThruProxyWithAuth
+ * @run main/othervm -Djava.net.preferIPv6Addresses=true
+ -Djdk.http.auth.tunneling.disabledSchemes= PostThruProxyWithAuth
*/
public class PostThruProxyWithAuth {
@@ -62,6 +65,11 @@
static String passwd = "passphrase";
volatile private static int serverPort = 0;
+ private static ProxyTunnelServer pserver;
+ private static TestServer server;
+
+ static final String RESPONSE_MSG =
+ "Https POST thru proxy is successful with proxy authentication";
/*
* The TestServer implements a OriginServer that
@@ -79,9 +87,7 @@
* @return bytes for the data in the response
*/
public byte[] getBytes() {
- return
- "Https POST thru proxy is successful with proxy authentication".
- getBytes();
+ return RESPONSE_MSG.getBytes();
}
}
@@ -103,11 +109,13 @@
* setup the server
*/
try {
+ InetAddress localhost = InetAddress.getLocalHost();
ServerSocketFactory ssf = getServerSocketFactory(useSSL);
- ServerSocket ss = ssf.createServerSocket(serverPort);
+ ServerSocket ss = ssf.createServerSocket(serverPort, 0, localhost);
ss.setSoTimeout(TIMEOUT); // 30 seconds
serverPort = ss.getLocalPort();
- new TestServer(ss);
+ server = new TestServer(ss);
+ System.out.println("Server started at: " + ss);
} catch (Exception e) {
System.out.println("Server side failed:" +
e.getMessage());
@@ -120,7 +128,13 @@
System.out.println("Client side failed: " +
e.getMessage());
throw e;
- }
+ }
+ long connectCount = pserver.getConnectCount();
+ if (connectCount == 0) {
+ throw new AssertionError("Proxy was not used!");
+ } else {
+ System.out.println("Proxy CONNECT count: " + connectCount);
+ }
}
private static ServerSocketFactory getServerSocketFactory
@@ -160,9 +174,16 @@
*/
HttpsURLConnection.setDefaultHostnameVerifier(
new NameVerifier());
- URL url = new URL("https://" + getHostname() + ":" + serverPort);
+
+ URL url = URIBuilder.newBuilder()
+ .scheme("https")
+ .host(getHostname())
+ .port(serverPort)
+ .toURL();
Proxy p = new Proxy(Proxy.Type.HTTP, pAddr);
+ System.out.println("Client connecting to: " + url);
+ System.out.println("Through proxy: " + pAddr);
HttpsURLConnection https = (HttpsURLConnection)url.openConnection(p);
https.setConnectTimeout(TIMEOUT);
https.setReadTimeout(TIMEOUT);
@@ -182,9 +203,15 @@
new InputStreamReader(
https.getInputStream()));
String inputLine;
- while ((inputLine = in.readLine()) != null)
- System.out.println("Client received: " + inputLine);
+ boolean msgFound = false;
+ while ((inputLine = in.readLine()) != null) {
+ System.out.println("Client received: " + inputLine);
+ if (inputLine.contains(RESPONSE_MSG)) msgFound = true;
+ }
in.close();
+ if (!msgFound) {
+ throw new RuntimeException("POST message not found.");
+ }
} catch (SSLException e) {
if (ps != null)
ps.close();
@@ -202,7 +229,9 @@
}
static SocketAddress setupProxy() throws IOException {
- ProxyTunnelServer pserver = new ProxyTunnelServer();
+
+ InetAddress localhost = InetAddress.getLocalHost();
+ pserver = new ProxyTunnelServer(localhost);
/*
* register a system wide authenticator and setup the proxy for
@@ -216,7 +245,7 @@
pserver.start();
- return new InetSocketAddress("localhost", pserver.getPort());
+ return new InetSocketAddress(localhost, pserver.getPort());
}
public static class TestAuthenticator extends Authenticator {
--- a/test/jdk/sun/net/www/protocol/https/HttpsURLConnection/ProxyTunnelServer.java Fri May 17 13:21:44 2019 +0100
+++ b/test/jdk/sun/net/www/protocol/https/HttpsURLConnection/ProxyTunnelServer.java Thu May 23 11:07:37 2019 +0100
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2001, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2001, 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
@@ -63,11 +63,23 @@
*/
static boolean needAuth = false;
+ volatile long connectCount;
+
public ProxyTunnelServer() throws IOException {
if (ss == null) {
ss = (ServerSocket) ServerSocketFactory.getDefault()
.createServerSocket(0);
ss.setSoTimeout(TIMEOUT);
+ System.out.println("Proxy server created: " + ss);
+ }
+ }
+
+ public ProxyTunnelServer(InetAddress address) throws IOException {
+ if (ss == null) {
+ ss = (ServerSocket) ServerSocketFactory.getDefault()
+ .createServerSocket(0, 0, address);
+ ss.setSoTimeout(TIMEOUT);
+ System.out.println("Proxy server created: " + ss);
}
}
@@ -86,7 +98,9 @@
public void run() {
try {
+ System.out.println("Proxy server listening at: " + ss);
clientSocket = ss.accept();
+ System.out.println("Proxy server accepted connection: " + clientSocket);
processRequests();
} catch (SocketTimeoutException e) {
System.out.println(
@@ -101,7 +115,9 @@
System.out.println("ProxyServer close error: " + excep);
excep.printStackTrace();
}
- }
+ } finally {
+ System.out.println("Proxy server: request served");
+ }
}
/*
@@ -118,6 +134,7 @@
String statusLine = mheader.getValue(0);
if (statusLine.startsWith("CONNECT")) {
+ synchronized(this) { connectCount++; }
// retrieve the host and port info from the status-line
retrieveConnectInfo(statusLine);
if (needAuth) {
@@ -154,6 +171,10 @@
}
}
+ public long getConnectCount() {
+ return connectCount;
+ }
+
private void respondForConnect(boolean needAuth) throws Exception {
OutputStream out = clientSocket.getOutputStream();
@@ -273,13 +294,19 @@
endi = connectStr.lastIndexOf(' ');
connectInfo = connectStr.substring(starti+1, endi).trim();
// retrieve server name and port
- endi = connectInfo.indexOf(':');
- serverName = connectInfo.substring(0, endi);
+ if (connectInfo.charAt(0) == '[') {
+ endi = connectInfo.indexOf(']');
+ serverName = connectInfo.substring(1, endi++);
+ assert connectInfo.charAt(endi) == ':' : "Expected [IPv6]:port";
+ } else {
+ endi = connectInfo.indexOf(':');
+ serverName = connectInfo.substring(0, endi);
+ }
serverPort = Integer.parseInt(connectInfo.substring(endi+1));
} catch (Exception e) {
throw new IOException("Proxy recieved a request: "
+ connectStr, e);
- }
+ }
serverInetAddr = InetAddress.getByName(serverName);
}
--- a/test/jdk/sun/net/www/protocol/https/HttpsURLConnection/ReadTimeout.java Fri May 17 13:21:44 2019 +0100
+++ b/test/jdk/sun/net/www/protocol/https/HttpsURLConnection/ReadTimeout.java Thu May 23 11:07:37 2019 +0100
@@ -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
@@ -32,12 +32,14 @@
* @summary sun.net.client.defaultConnectTimeout should work with
* HttpsURLConnection; HTTP client: Connect and read timeouts;
* Https needs to support new tiger features that went into http
+ * @library /test/lib
* @run main/othervm ReadTimeout
*/
import java.io.*;
import java.net.*;
import javax.net.ssl.*;
+import jdk.test.lib.net.URIBuilder;
public class ReadTimeout {
@@ -93,10 +95,11 @@
* to avoid infinite hangs.
*/
void doServerSide() throws Exception {
+ InetAddress loopback = InetAddress.getLoopbackAddress();
SSLServerSocketFactory sslssf =
(SSLServerSocketFactory) SSLServerSocketFactory.getDefault();
SSLServerSocket sslServerSocket =
- (SSLServerSocket) sslssf.createServerSocket(serverPort);
+ (SSLServerSocket) sslssf.createServerSocket(serverPort, 0, loopback);
serverPort = sslServerSocket.getLocalPort();
/*
@@ -163,7 +166,11 @@
}
HttpsURLConnection http = null;
try {
- URL url = new URL("https://localhost:" + serverPort);
+ URL url = URIBuilder.newBuilder()
+ .scheme("https")
+ .loopback()
+ .port(serverPort)
+ .toURL();
// set read timeout through system property
System.setProperty("sun.net.client.defaultReadTimeout", "2000");
@@ -184,7 +191,11 @@
}
try {
- URL url = new URL("https://localhost:" + serverPort);
+ URL url = URIBuilder.newBuilder()
+ .scheme("https")
+ .loopback()
+ .port(serverPort)
+ .toURL();
HttpsURLConnection.setDefaultHostnameVerifier(
new NameVerifier());
@@ -239,6 +250,10 @@
volatile Exception serverException = null;
volatile Exception clientException = null;
+ private boolean sslConnectionFailed() {
+ return clientException instanceof SSLHandshakeException;
+ }
+
public static void main(String[] args) throws Exception {
String keyFilename =
System.getProperty("test.src", "./") + "/" + pathToStores +
@@ -282,7 +297,9 @@
* Wait for other side to close down.
*/
if (separateServerThread) {
- serverThread.join();
+ if (!sslConnectionFailed()) {
+ serverThread.join();
+ }
} else {
clientThread.join();
}
--- a/test/jdk/sun/net/www/protocol/https/HttpsURLConnection/Redirect.java Fri May 17 13:21:44 2019 +0100
+++ b/test/jdk/sun/net/www/protocol/https/HttpsURLConnection/Redirect.java Thu May 23 11:07:37 2019 +0100
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2001, 2011, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2001, 2019, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -26,6 +26,7 @@
* @bug 4423074
* @summary Need to rebase all the duplicated classes from Merlin.
* This test will check out http POST
+ * @library /test/lib
* @run main/othervm Redirect
*
* SunJSSE does not support dynamic system properties, no way to re-use
@@ -35,6 +36,7 @@
import java.io.*;
import java.net.*;
import javax.net.ssl.*;
+import jdk.test.lib.net.URIBuilder;
public class Redirect {
@@ -95,10 +97,11 @@
* to avoid infinite hangs.
*/
void doServerSide() throws Exception {
+ InetAddress loopback = InetAddress.getLoopbackAddress();
SSLServerSocketFactory sslssf =
(SSLServerSocketFactory) SSLServerSocketFactory.getDefault();
SSLServerSocket sslServerSocket =
- (SSLServerSocket) sslssf.createServerSocket(serverPort);
+ (SSLServerSocket) sslssf.createServerSocket(serverPort, 0, loopback);
serverPort = sslServerSocket.getLocalPort();
/*
@@ -154,7 +157,11 @@
}
// Send HTTP POST request to server
- URL url = new URL("https://localhost:"+serverPort);
+ URL url = URIBuilder.newBuilder()
+ .scheme("https")
+ .loopback()
+ .port(serverPort)
+ .toURL();
HttpsURLConnection.setDefaultHostnameVerifier(
new NameVerifier());
@@ -190,6 +197,10 @@
volatile Exception serverException = null;
volatile Exception clientException = null;
+ private boolean sslConnectionFailed() {
+ return clientException instanceof SSLHandshakeException;
+ }
+
public static void main(String[] args) throws Exception {
String keyFilename =
System.getProperty("test.src", "./") + "/" + pathToStores +
@@ -233,7 +244,9 @@
* Wait for other side to close down.
*/
if (separateServerThread) {
- serverThread.join();
+ if (!sslConnectionFailed()) {
+ serverThread.join();
+ }
} else {
clientThread.join();
}
--- a/test/jdk/sun/net/www/protocol/https/HttpsURLConnection/RetryHttps.java Fri May 17 13:21:44 2019 +0100
+++ b/test/jdk/sun/net/www/protocol/https/HttpsURLConnection/RetryHttps.java Thu May 23 11:07:37 2019 +0100
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2003, 2015, 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
@@ -24,7 +24,9 @@
/* @test
* @bug 4799427
* @summary Https can not retry request
+ * @library /test/lib
* @run main/othervm RetryHttps
+ * @run main/othervm -Djava.net.preferIPv6Addresses=true RetryHttps
*
* SunJSSE does not support dynamic system properties, no way to re-use
* system properties in samevm/agentvm mode.
@@ -35,6 +37,7 @@
import java.util.*;
import java.io.*;
import javax.net.ssl.*;
+import jdk.test.lib.net.URIBuilder;
public class RetryHttps {
static Map cookies;
@@ -80,12 +83,17 @@
* to avoid infinite hangs.
*/
void doServerSide() throws Exception {
+ InetAddress loopback = InetAddress.getLoopbackAddress();
SSLServerSocketFactory sslssf =
(SSLServerSocketFactory) SSLServerSocketFactory.getDefault();
sslServerSocket =
- (SSLServerSocket) sslssf.createServerSocket(serverPort);
+ (SSLServerSocket) sslssf.createServerSocket(serverPort, 0, loopback);
serverPort = sslServerSocket.getLocalPort();
+ System.out.println("Starting server at: "
+ + sslServerSocket.getInetAddress()
+ + ":" + serverPort);
+
/*
* Signal Client, we're ready for his connect.
*/
@@ -145,11 +153,16 @@
try {
HttpsURLConnection http = null;
/* establish http connection to server */
- URL url = new URL("https://localhost:" + serverPort+"/file1");
+ URL url = URIBuilder.newBuilder()
+ .scheme("https")
+ .loopback()
+ .port(serverPort)
+ .path("/file1")
+ .toURL();
System.out.println("url is "+url.toString());
HttpsURLConnection.setDefaultHostnameVerifier(
new NameVerifier());
- http = (HttpsURLConnection)url.openConnection();
+ http = (HttpsURLConnection)url.openConnection(Proxy.NO_PROXY);
int respCode = http.getResponseCode();
int cl = http.getContentLength();
InputStream is = http.getInputStream ();
@@ -157,8 +170,13 @@
while (is.read() != -1 && count++ < cl);
System.out.println("respCode1 = "+respCode);
Thread.sleep(2000);
- url = new URL("https://localhost:" + serverPort+"/file2");
- http = (HttpsURLConnection)url.openConnection();
+ url = URIBuilder.newBuilder()
+ .scheme("https")
+ .loopback()
+ .port(serverPort)
+ .path("/file2")
+ .toURL();
+ http = (HttpsURLConnection)url.openConnection(Proxy.NO_PROXY);
respCode = http.getResponseCode();
System.out.println("respCode2 = "+respCode);
} catch (IOException ioex) {
--- a/test/jdk/sun/text/resources/LocaleData Fri May 17 13:21:44 2019 +0100
+++ b/test/jdk/sun/text/resources/LocaleData Thu May 23 11:07:37 2019 +0100
@@ -614,8 +614,6 @@
FormatData/es_PE/DatePatterns/2=dd/MM/yyyy
FormatData/es_PE/DatePatterns/3=dd/MM/yy
FormatData/es_PE/DateTimePatterns/0={1} {0}
-FormatData/es_PE/NumberElements/0=,
-FormatData/es_PE/NumberElements/1=.
FormatData/es_PE/NumberElements/2=;
FormatData/es_PR/NumberPatterns/0=#,##0.###;-#,##0.###
# FormatData/es_PR/NumberPatterns/1=$#,##0.00;($#,##0.00) # Changed; see bug 4122840
@@ -8323,3 +8321,8 @@
# bug #8208746
CurrencyNames//ves=Venezuelan Bol\u00edvar Soberano
+
+# bug# 8206879
+# For Peru decimal separator is changed to dot(.) and grouping separator is changed to comma(,)
+FormatData/es_PE/NumberElements/0=.
+FormatData/es_PE/NumberElements/1=,
--- a/test/langtools/jdk/javadoc/doclet/testAnnotationTypes/TestAnnotationTypes.java Fri May 17 13:21:44 2019 +0100
+++ b/test/langtools/jdk/javadoc/doclet/testAnnotationTypes/TestAnnotationTypes.java Thu May 23 11:07:37 2019 +0100
@@ -79,7 +79,7 @@
"<ul class=\"blockList\">",
"<li class=\"blockList\">",
"<section class=\"memberDetails\">",
- "<h2>Element Detail</h2>",
+ "<h2>Element Details</h2>",
"<a id=\"annotation.type.element.detail\">",
"<!-- -->",
"</a>",
--- a/test/langtools/jdk/javadoc/doclet/testHtmlVersion/TestHtmlVersion.java Fri May 17 13:21:44 2019 +0100
+++ b/test/langtools/jdk/javadoc/doclet/testHtmlVersion/TestHtmlVersion.java Thu May 23 11:07:37 2019 +0100
@@ -24,7 +24,7 @@
/*
* @test
* @bug 8072945 8081854 8141492 8148985 8150188 4649116 8173707 8151743 8169819 8183037 8182765 8196202
- * 8202624 8210047 8184205 8221871
+ * 8202624 8210047 8184205 8221871 8223733
* @summary Test the version of HTML generated by the javadoc tool.
* @author bpatel
* @library ../../lib
@@ -324,17 +324,17 @@
+ "</a>\n"
+ "<h2>Method Summary</h2>",
"<section class=\"fieldDetails\">\n"
- + "<h2>Field Detail</h2>\n"
+ + "<h2>Field Details</h2>\n"
+ "<a id=\"field.detail\">\n"
+ "<!-- -->\n"
+ "</a>",
"<section class=\"constructorDetails\">\n"
- + "<h2>Constructor Detail</h2>\n"
+ + "<h2>Constructor Details</h2>\n"
+ "<a id=\"constructor.detail\">\n"
+ "<!-- -->\n"
+ "</a>",
"<section class=\"methodDetails\">\n"
- + "<h2>Method Detail</h2>\n"
+ + "<h2>Method Details</h2>\n"
+ "<a id=\"method.detail\">\n"
+ "<!-- -->\n"
+ "</a>",
@@ -368,12 +368,12 @@
+ "<div class=\"memberSummary\">\n",
"<table aria-labelledby=\"t0\">",
"<section class=\"constantDetails\">\n"
- + "<h2>Enum Constant Detail</h2>\n"
+ + "<h2>Enum Constant Details</h2>\n"
+ "<a id=\"enum.constant.detail\">\n"
+ "<!-- -->\n"
+ "</a>\n",
"<section class=\"methodDetails\">\n"
- + "<h2>Method Detail</h2>\n"
+ + "<h2>Method Details</h2>\n"
+ "<a id=\"method.detail\">\n"
+ "<!-- -->\n"
+ "</a>\n",
@@ -401,7 +401,7 @@
+ "<div class=\"memberSummary\">\n",
"<table aria-labelledby=\"t0\">\n",
"<section class=\"methodDetails\">\n"
- + "<h2>Method Detail</h2>\n"
+ + "<h2>Method Details</h2>\n"
+ "<a id=\"method.detail\">\n"
+ "<!-- -->\n"
+ "</a>\n",
@@ -427,7 +427,7 @@
+ "</a>\n"
+ "<h2>Constructor Summary</h2>",
"<section class=\"constructorDetails\">\n"
- + "<h2>Constructor Detail</h2>\n"
+ + "<h2>Constructor Details</h2>\n"
+ "<a id=\"constructor.detail\">\n"
+ "<!-- -->\n"
+ "</a>\n",
@@ -453,7 +453,7 @@
+ "</a>\n"
+ "<h2>Constructor Summary</h2>",
"<section class=\"constructorDetails\">\n"
- + "<h2>Constructor Detail</h2>\n"
+ + "<h2>Constructor Details</h2>\n"
+ "<a id=\"constructor.detail\">\n"
+ "<!-- -->\n"
+ "</a>\n",
@@ -485,7 +485,7 @@
+ "<h2>Optional Element Summary</h2>\n"
+ "<div class=\"memberSummary\">\n<table>",
"<section class=\"memberDetails\">\n"
- + "<h2>Element Detail</h2>\n"
+ + "<h2>Element Details</h2>\n"
+ "<a id=\"annotation.type.element.detail\">\n"
+ "<!-- -->\n"
+ "</a>\n",
@@ -742,19 +742,19 @@
+ "<li class=\"blockList\"><a name=\"field.detail\">\n"
+ "<!-- -->\n"
+ "</a>\n"
- + "<h2>Field Detail</h2>",
+ + "<h2>Field Details</h2>",
"<!-- ========= CONSTRUCTOR DETAIL ======== -->\n"
+ "<ul class=\"blockList\">\n"
+ "<li class=\"blockList\"><a name=\"constructor.detail\">\n"
+ "<!-- -->\n"
+ "</a>\n"
- + "<h2>Constructor Detail</h2>",
+ + "<h2>Constructor Details</h2>",
"<!-- ============ METHOD DETAIL ========== -->\n"
+ "<ul class=\"blockList\">\n"
+ "<li class=\"blockList\"><a name=\"method.detail\">\n"
+ "<!-- -->\n"
+ "</a>\n"
- + "<h2>Method Detail</h2>");
+ + "<h2>Method Details</h2>");
// Negated test for enum page
checkOutput("pkg/AnotherClass.ModalExclusionType.html", false,
@@ -786,13 +786,13 @@
+ "<li class=\"blockList\"><a name=\"enum.constant.detail\">\n"
+ "<!-- -->\n"
+ "</a>\n"
- + "<h2>Enum Constant Detail</h2>",
+ + "<h2>Enum Constant Details</h2>",
"<!-- ============ METHOD DETAIL ========== -->\n"
+ "<ul class=\"blockList\">\n"
+ "<li class=\"blockList\"><a name=\"method.detail\">\n"
+ "<!-- -->\n"
+ "</a>\n"
- + "<h2>Method Detail</h2>");
+ + "<h2>Method Details</h2>");
// Negated test for interface page
checkOutput("pkg2/Interface.html", false,
@@ -816,7 +816,7 @@
+ "<li class=\"blockList\"><a name=\"method.detail\">\n"
+ "<!-- -->\n"
+ "</a>\n"
- + "<h2>Method Detail</h2>");
+ + "<h2>Method Details</h2>");
// Negated test for error page
checkOutput("pkg/TestError.html", false,
@@ -838,7 +838,7 @@
+ "<li class=\"blockList\"><a name=\"constructor.detail\">\n"
+ "<!-- -->\n"
+ "</a>\n"
- + "<h2>Constructor Detail</h2>");
+ + "<h2>Constructor Details</h2>");
// Negated test for exception page
checkOutput("pkg/TestException.html", false,
@@ -860,7 +860,7 @@
+ "<li class=\"blockList\"><a name=\"constructor.detail\">\n"
+ "<!-- -->\n"
+ "</a>\n"
- + "<h2>Constructor Detail</h2>");
+ + "<h2>Constructor Details</h2>");
// Negated test for annotation page
checkOutput("pkg2/TestAnnotationType.html", false,
@@ -892,7 +892,7 @@
+ "<li class=\"blockList\"><a name=\"annotation.type.element.detail\">\n"
+ "<!-- -->\n"
+ "</a>\n"
- + "<h2>Element Detail</h2>");
+ + "<h2>Element Details</h2>");
// Negated test for class use page
checkOutput("pkg1/class-use/RegClass.html", false,
--- a/test/langtools/jdk/javadoc/doclet/testIndexTaglet/TestIndexTaglet.java Fri May 17 13:21:44 2019 +0100
+++ b/test/langtools/jdk/javadoc/doclet/testIndexTaglet/TestIndexTaglet.java Thu May 23 11:07:37 2019 +0100
@@ -75,7 +75,7 @@
checkExit(Exit.OK);
checkOrder("pkg/A.html",
- "<h2>Method Detail</h2>\n",
+ "<h2>Method Details</h2>\n",
"<div class=\"block\">test description with <a id=\"search_phrase_a\" "
+ "class=\"searchTagResult\">search_phrase_a</a></div>");
--- a/test/langtools/jdk/javadoc/doclet/testJavaFX/TestJavaFX.java Fri May 17 13:21:44 2019 +0100
+++ b/test/langtools/jdk/javadoc/doclet/testJavaFX/TestJavaFX.java Thu May 23 11:07:37 2019 +0100
@@ -213,7 +213,7 @@
"pkg2");
checkExit(Exit.OK);
checkOutput("pkg2/Test.html", true,
- "<h2>Property Detail</h2>\n"
+ "<h2>Property Details</h2>\n"
+ "<a id=\"property.detail\">\n"
+ "<!-- -->\n"
+ "</a>\n"
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/jdk/javadoc/doclet/testModuleSpecificStylesheet/TestModuleSpecificStylesheet.java Thu May 23 11:07:37 2019 +0100
@@ -0,0 +1,103 @@
+/*
+ * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @bug 8219313
+ * @summary Support module specific stylesheets
+ * @library /tools/lib ../../lib
+ * @modules jdk.compiler/com.sun.tools.javac.api
+ * jdk.compiler/com.sun.tools.javac.main
+ * jdk.javadoc/jdk.javadoc.internal.tool
+ * @build javadoc.tester.* toolbox.ToolBox
+ * @run main TestModuleSpecificStylesheet
+ */
+
+
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.List;
+
+import toolbox.ModuleBuilder;
+import toolbox.ToolBox;
+
+import javadoc.tester.JavadocTester;
+
+public class TestModuleSpecificStylesheet extends JavadocTester {
+
+ final ToolBox tb;
+
+ public static void main(String... args) throws Exception {
+ TestModuleSpecificStylesheet tester = new TestModuleSpecificStylesheet();
+ tester.runTests(m -> new Object[]{Paths.get(m.getName())});
+ }
+
+ TestModuleSpecificStylesheet() {
+ tb = new ToolBox();
+ }
+
+ @Test
+ public void test(Path base) throws Exception {
+ Path srcDir = base.resolve("src");
+ Path outDir = base.resolve("out");
+
+ new ModuleBuilder(tb, "ma")
+ .classes("package pa; public class A{}")
+ .classes("package pa.pb; public class B{}")
+ .exports("pa")
+ .exports("pa.pb")
+ .write(srcDir);
+
+ Path docFilesDir = Files.createDirectories(srcDir.resolve("ma").resolve("doc-files"));
+ Path stylesheet = docFilesDir.resolve("spanstyle.css");
+ Files.createFile(stylesheet);
+ Files.write(stylesheet, List.of("span{ color:blue; }"));
+
+ javadoc("-d", outDir.toString(),
+ "--module-source-path", srcDir.toString(),
+ "--module", "ma");
+
+ checkExit(Exit.OK);
+
+ checkOutput("ma/module-summary.html", true,
+ "<link rel=\"stylesheet\" type=\"text/css\" href=\"../ma/doc-files/spanstyle.css\"" +
+ " title=\"Style\">");
+
+ checkOutput("ma/pa/package-summary.html", true,
+ "<link rel=\"stylesheet\" type=\"text/css\" href=\"../../ma/doc-files/spanstyle.css\"" +
+ " title=\"Style\">");
+
+ checkOutput("ma/pa/A.html", true,
+ "<link rel=\"stylesheet\" type=\"text/css\" href=\"../../ma/doc-files/spanstyle.css\"" +
+ " title=\"Style\">");
+
+ checkOutput("ma/pa/pb/B.html", true,
+ "<link rel=\"stylesheet\" type=\"text/css\" href=\"../../../ma/doc-files/spanstyle.css\"" +
+ " title=\"Style\">");
+
+ checkOutput("ma/pa/pb/package-summary.html", true,
+ "<link rel=\"stylesheet\" type=\"text/css\" href=\"../../../ma/doc-files/spanstyle.css\"" +
+ " title=\"Style\">");
+ }
+}
--- a/test/langtools/jdk/javadoc/doclet/testOrdering/TestOrdering.java Fri May 17 13:21:44 2019 +0100
+++ b/test/langtools/jdk/javadoc/doclet/testOrdering/TestOrdering.java Thu May 23 11:07:37 2019 +0100
@@ -515,7 +515,7 @@
checkExit(Exit.OK);
checkOrder("pkg5/AnnoFieldTest.html",
- "<h2>Field Detail</h2>",
+ "<h2>Field Details</h2>",
"<pre>static final int one</pre>",
"<pre>static final int two</pre>",
"<pre>static final int three</pre>",
@@ -527,7 +527,7 @@
"<a href=\"#one()\">one</a>",
"<a href=\"#three()\">three</a>",
"<a href=\"#two()\">two</a>",
- "<h2>Element Detail</h2>",
+ "<h2>Element Details</h2>",
"<h3>one</h3>",
"<h3>two</h3>",
"<h3>three</h3>",
@@ -539,7 +539,7 @@
"<a href=\"#one()\">one</a>",
"<a href=\"#three()\">three</a>",
"<a href=\"#two()\">two</a>",
- "<h2>Element Detail</h2>",
+ "<h2>Element Details</h2>",
"<h3>one</h3>",
"<h3>two</h3>",
"<h3>three</h3>",
@@ -551,7 +551,7 @@
"<a href=\"#%3Cinit%3E(int,int)\"",
"<a href=\"#%3Cinit%3E(int,int,int)\"",
"<a href=\"#%3Cinit%3E(int,int,int,int)\"",
- "<h2>Constructor Detail</h2>",
+ "<h2>Constructor Details</h2>",
"<a id=\"<init>(int,int,int,int)\">",
"<a id=\"<init>(int,int,int)\">",
"<a id=\"<init>(int,int)\">",
@@ -563,7 +563,7 @@
"<a href=\"#ONE\">ONE</a>",
"<a href=\"#THREE\">THREE</a>",
"<a href=\"#TWO\">TWO</a>",
- "<h2>Enum Constant Detail</h2>",
+ "<h2>Enum Constant Details</h2>",
"<h3>ONE</h3>",
"<h3>TWO</h3>",
"<h3>THREE</h3>",
@@ -575,7 +575,7 @@
"<a href=\"#one\">one</a>",
"<a href=\"#three\">three</a>",
"<a href=\"#two\">two</a>",
- "<h2>Field Detail</h2>",
+ "<h2>Field Details</h2>",
"<h3>one</h3>",
"<h3>two</h3>",
"<h3>three</h3>",
@@ -587,7 +587,7 @@
"<a href=\"#one()\">one</a>",
"<a href=\"#three()\">three</a>",
"<a href=\"#two()\">two</a>",
- "<h2>Method Detail</h2>",
+ "<h2>Method Details</h2>",
"<h3>one</h3>",
"<h3>two</h3>",
"<h3>three</h3>",
@@ -599,7 +599,7 @@
"<a href=\"#one()\">one</a>",
"<a href=\"#three()\">three</a>",
"<a href=\"#two()\">two</a>",
- "<h2>Method Detail</h2>",
+ "<h2>Method Details</h2>",
"<h3>one</h3>",
"<h3>two</h3>",
"<h3>three</h3>",
@@ -611,7 +611,7 @@
"<a href=\"#oneProperty\">one</a>",
"<a href=\"#threeProperty\">three</a>",
"<a href=\"#twoProperty\">two</a>",
- "<h2>Property Detail</h2>",
+ "<h2>Property Details</h2>",
"<h3>oneProperty</h3>",
"<h3>twoProperty</h3>",
"<h3>threeProperty</h3>",
--- a/test/langtools/jdk/javadoc/doclet/testPackageSpecificStylesheet/TestPackageSpecificStylesheet.java Fri May 17 13:21:44 2019 +0100
+++ b/test/langtools/jdk/javadoc/doclet/testPackageSpecificStylesheet/TestPackageSpecificStylesheet.java Thu May 23 11:07:37 2019 +0100
@@ -81,15 +81,15 @@
checkExit(Exit.OK);
checkOutput("pkg/A.html", true,
- "<link rel=\"stylesheet\" type=\"text/css\" href=\"doc-files/spanstyle.css\"" +
+ "<link rel=\"stylesheet\" type=\"text/css\" href=\"../pkg/doc-files/spanstyle.css\"" +
" title=\"Style\">");
checkOutput("pkg/package-summary.html", true,
- "<link rel=\"stylesheet\" type=\"text/css\" href=\"doc-files/spanstyle.css\"" +
+ "<link rel=\"stylesheet\" type=\"text/css\" href=\"../pkg/doc-files/spanstyle.css\"" +
" title=\"Style\">");
checkOutput("pkg2/B.html", false,
- "<link rel=\"stylesheet\" type=\"text/css\" href=\"doc-files/spanstyle.css\"" +
+ "<link rel=\"stylesheet\" type=\"text/css\" href=\"../pkg2/doc-files/spanstyle.css\"" +
" title=\"Style\">");
}
--- a/test/langtools/jdk/javadoc/doclet/testSystemPropertyTaglet/TestSystemPropertyTaglet.java Fri May 17 13:21:44 2019 +0100
+++ b/test/langtools/jdk/javadoc/doclet/testSystemPropertyTaglet/TestSystemPropertyTaglet.java Thu May 23 11:07:37 2019 +0100
@@ -78,7 +78,7 @@
checkOrder("pkg/A.html",
"<h1 title=\"Class A\" class=\"title\">Class A</h1>",
"test with <code><a id=\"user.name\" class=\"searchTagResult\">user.name</a></code>",
- "<h2>Method Detail</h2>",
+ "<h2>Method Details</h2>",
"test with <code><a id=\"java.version\" class=\"searchTagResult\">java.version</a></code>");
checkOrder("index-all.html",
--- a/test/lib/jdk/test/lib/cds/CDSTestUtils.java Fri May 17 13:21:44 2019 +0100
+++ b/test/lib/jdk/test/lib/cds/CDSTestUtils.java Thu May 23 11:07:37 2019 +0100
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2017, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2017, 2019, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -43,6 +43,8 @@
public static final String MSG_COMPRESSION_MUST_BE_USED =
"Unable to use shared archive: UseCompressedOops and UseCompressedClassPointers must be on for UseSharedSpaces.";
+ public static final boolean DYNAMIC_DUMP = Boolean.getBoolean("test.dynamic.cds.archive");
+
public interface Checker {
public void check(OutputAnalyzer output) throws Exception;
}
@@ -246,7 +248,7 @@
cmd.add("-Xlog:cds,cds+hashtables");
if (opts.archiveName == null)
opts.archiveName = getDefaultArchiveName();
- cmd.add("-XX:SharedArchiveFile=./" + opts.archiveName);
+ cmd.add("-XX:SharedArchiveFile=" + opts.archiveName);
if (opts.classList != null) {
File classListFile = makeClassList(opts.classList);
@@ -260,12 +262,20 @@
return executeAndLog(pb, "dump");
}
+ public static boolean isDynamicArchive() {
+ return DYNAMIC_DUMP;
+ }
// check result of 'dump-the-archive' operation, that is "-Xshare:dump"
public static OutputAnalyzer checkDump(OutputAnalyzer output, String... extraMatches)
throws Exception {
- output.shouldContain("Loading classes to share");
+ if (!DYNAMIC_DUMP) {
+ output.shouldContain("Loading classes to share");
+ } else {
+ output.shouldContain("Buffer-space to target-space delta")
+ .shouldContain("Written dynamic archive 0x");
+ }
output.shouldHaveExitValue(0);
for (String match : extraMatches) {
--- a/test/lib/jdk/test/lib/jfr/EventNames.java Fri May 17 13:21:44 2019 +0100
+++ b/test/lib/jdk/test/lib/jfr/EventNames.java Thu May 23 11:07:37 2019 +0100
@@ -101,6 +101,8 @@
public final static String G1HeapSummary = PREFIX + "G1HeapSummary";
public final static String G1HeapRegionInformation = PREFIX + "G1HeapRegionInformation";
public final static String G1HeapRegionTypeChange = PREFIX + "G1HeapRegionTypeChange";
+ public final static String ShenandoahHeapRegionInformation = PREFIX + "ShenandoahHeapRegionInformation";
+ public final static String ShenandoahHeapRegionStateChange = PREFIX + "ShenandoahHeapRegionStateChange";
public final static String TenuringDistribution = PREFIX + "TenuringDistribution";
public final static String GarbageCollection = PREFIX + "GarbageCollection";
public final static String ParallelOldGarbageCollection = PREFIX + "ParallelOldGarbageCollection";
--- a/test/lib/jdk/test/lib/jfr/GCHelper.java Fri May 17 13:21:44 2019 +0100
+++ b/test/lib/jdk/test/lib/jfr/GCHelper.java Thu May 23 11:07:37 2019 +0100
@@ -80,6 +80,7 @@
public static final String pauseLevelEvent = "GCPhasePauseLevel";
private static final List<String> g1HeapRegionTypes;
+ private static final List<String> shenandoahHeapRegionStates;
private static PrintStream defaultErrorLog = null;
public static int getGcId(RecordedEvent event) {
@@ -207,6 +208,21 @@
};
g1HeapRegionTypes = Collections.unmodifiableList(Arrays.asList(g1HeapRegionTypeLiterals));
+
+ String[] shenandoahHeapRegionStateLiterals = new String[] {
+ "Empty Uncommitted",
+ "Empty Committed",
+ "Regular",
+ "Humongous Start",
+ "Humongous Continuation",
+ "Humongous Start, Pinned",
+ "Collection Set",
+ "Pinned",
+ "Collection Set, Pinned",
+ "Trash"
+ };
+
+ shenandoahHeapRegionStates = Collections.unmodifiableList(Arrays.asList(shenandoahHeapRegionStateLiterals));
}
/**
@@ -443,6 +459,13 @@
return g1HeapRegionTypes.contains(type);
}
+ public static boolean assertIsValidShenandoahHeapRegionState(final String state) {
+ if (!shenandoahHeapRegionStates.contains(state)) {
+ throw new AssertionError("Unknown state '" + state + "', valid heap region states are " + shenandoahHeapRegionStates);
+ }
+ return true;
+ }
+
/**
* Helper function to align heap size up.
*
--- a/test/lib/sun/hotspot/WhiteBox.java Fri May 17 13:21:44 2019 +0100
+++ b/test/lib/sun/hotspot/WhiteBox.java Thu May 23 11:07:37 2019 +0100
@@ -514,6 +514,7 @@
// Sharing & archiving
public native String getDefaultArchivePath();
+ public native boolean cdsMemoryMappingFailed();
public native boolean isSharingEnabled();
public native boolean isShared(Object o);
public native boolean isSharedClass(Class<?> c);
@@ -522,6 +523,7 @@
public native boolean isJFRIncludedInVmBuild();
public native boolean isJavaHeapArchiveSupported();
public native Object getResolvedReferences(Class<?> c);
+ public native void linkClass(Class<?> c);
public native boolean areOpenArchiveHeapObjectsMapped();
// Compiler Directive