mirror of
https://github.com/openjdk/jdk.git
synced 2026-01-31 21:48:23 +00:00
Merge
This commit is contained in:
commit
41c5a07fa9
1
.hgtags
1
.hgtags
@ -638,3 +638,4 @@ f143729ca00ec14a98ea5c7f73acba88da97746e jdk-15+23
|
||||
58833044988772ca06c97ab2f142474a8627af80 jdk-15+25
|
||||
58833044988772ca06c97ab2f142474a8627af80 jdk-15+25
|
||||
90b266a84c06f1b3dc0ed8767856793e8c1c357e jdk-15+25
|
||||
0a32396f7a690015d22ca3328ac441a358295d90 jdk-15+26
|
||||
|
||||
@ -103,8 +103,8 @@ ifeq ($(ENABLE_PANDOC), true)
|
||||
SOURCE_FILES := $(TOPDIR)/make/scripts/pandoc-troff-manpage-filter.sh.template, \
|
||||
OUTPUT_FILE := $(PANDOC_TROFF_MANPAGE_FILTER), \
|
||||
REPLACEMENTS := \
|
||||
@@JJS@@ => $(JJS) ; \
|
||||
@@TOPDIR@@ => $(TOPDIR) ; \
|
||||
@@JAVA_SMALL@@ => $(JAVA_SMALL) ; \
|
||||
@@BUILDTOOLS_OUTPUTDIR@@ => $(BUILDTOOLS_OUTPUTDIR) ; \
|
||||
))
|
||||
|
||||
# Created script must be made executable
|
||||
@ -126,8 +126,8 @@ ifeq ($(ENABLE_PANDOC), true)
|
||||
SOURCE_FILES := $(TOPDIR)/make/scripts/pandoc-html-manpage-filter.sh.template, \
|
||||
OUTPUT_FILE := $(PANDOC_HTML_MANPAGE_FILTER), \
|
||||
REPLACEMENTS := \
|
||||
@@JJS@@ => $(JJS) ; \
|
||||
@@TOPDIR@@ => $(TOPDIR) ; \
|
||||
@@JAVA_SMALL@@ => $(JAVA_SMALL) ; \
|
||||
@@BUILDTOOLS_OUTPUTDIR@@ => $(BUILDTOOLS_OUTPUTDIR) ; \
|
||||
))
|
||||
|
||||
# Created script must be made executable
|
||||
|
||||
@ -610,9 +610,9 @@ ifeq ($(ENABLE_PANDOC), true)
|
||||
# PANDOC_HTML_MANPAGE_FILTER, a wrapper around
|
||||
# PANDOC_HTML_MANPAGE_FILTER_JAVASCRIPT. This is created by buildtools-jdk.
|
||||
|
||||
# We should also depend on the source javascript filter
|
||||
PANDOC_HTML_MANPAGE_FILTER_JAVASCRIPT := \
|
||||
$(TOPDIR)/make/scripts/pandoc-html-manpage-filter.js
|
||||
# We should also depend on the source code for the filter
|
||||
PANDOC_HTML_MANPAGE_FILTER_SOURCE := $(call FindFiles, \
|
||||
$(TOPDIR)/make/jdk/src/classes/build/tools/pandocfilter)
|
||||
|
||||
$(foreach m, $(ALL_MODULES), \
|
||||
$(eval MAN_$m := $(call FindModuleManDirs, $m)) \
|
||||
@ -632,7 +632,7 @@ ifeq ($(ENABLE_PANDOC), true)
|
||||
OPTIONS := --toc -V include-before='$(SPECS_TOP)' -V include-after='$(SPECS_BOTTOM_1)', \
|
||||
POST_PROCESS := $(TOOL_FIXUPPANDOC), \
|
||||
EXTRA_DEPS := $(PANDOC_HTML_MANPAGE_FILTER) \
|
||||
$(PANDOC_HTML_MANPAGE_FILTER_JAVASCRIPT), \
|
||||
$(PANDOC_HTML_MANPAGE_FILTER_SOURCE), \
|
||||
)) \
|
||||
$(eval JDK_SPECS_TARGETS += $($($m_$f_NAME))) \
|
||||
) \
|
||||
|
||||
@ -69,10 +69,12 @@ $(CLASSLIST_FILE): $(INTERIM_IMAGE_DIR)/bin/java$(EXE_SUFFIX) $(CLASSLIST_JAR)
|
||||
-Duser.language=en -Duser.country=US \
|
||||
-cp $(SUPPORT_OUTPUTDIR)/classlist.jar \
|
||||
build.tools.classlist.HelloClasslist $(LOG_DEBUG)
|
||||
$(GREP) -v HelloClasslist $@.raw > $(INTERIM_IMAGE_DIR)/lib/classlist
|
||||
$(GREP) -v HelloClasslist $@.raw > $@.interim
|
||||
$(FIXPATH) $(INTERIM_IMAGE_DIR)/bin/java -Xshare:dump \
|
||||
-XX:SharedClassListFile=$@.interim -XX:SharedArchiveFile=$@.jsa \
|
||||
-Xmx128M -Xms128M $(LOG_INFO)
|
||||
$(FIXPATH) $(INTERIM_IMAGE_DIR)/bin/java -XX:DumpLoadedClassList=$@.raw \
|
||||
$(FIXPATH) $(INTERIM_IMAGE_DIR)/bin/java -XX:DumpLoadedClassList=$@.raw.2 \
|
||||
-XX:SharedClassListFile=$@.interim -XX:SharedArchiveFile=$@.jsa \
|
||||
-Djava.lang.invoke.MethodHandle.TRACE_RESOLVE=true \
|
||||
-Duser.language=en -Duser.country=US \
|
||||
--module-path $(SUPPORT_OUTPUTDIR)/classlist.jar \
|
||||
@ -86,7 +88,7 @@ $(CLASSLIST_FILE): $(INTERIM_IMAGE_DIR)/bin/java$(EXE_SUFFIX) $(CLASSLIST_JAR)
|
||||
$(CAT) $(LINK_OPT_DIR)/stderr $(JLI_TRACE_FILE) ; \
|
||||
exit $$exitcode \
|
||||
)
|
||||
$(GREP) -v HelloClasslist $@.raw > $@
|
||||
$(GREP) -v HelloClasslist $@.raw.2 > $@
|
||||
|
||||
# The jli trace is created by the same recipe as classlist. By declaring these
|
||||
# dependencies, make will correctly rebuild both jli trace and classlist
|
||||
|
||||
@ -372,6 +372,10 @@ else # $(HAS_SPEC)=true
|
||||
else ifeq ($$(wildcard $$(COMPARE_BUILD_PATCH)), )
|
||||
$$(error Patch file $$(COMPARE_BUILD_PATCH) does not exist)
|
||||
endif
|
||||
PATCH_DRY_RUN := $$(shell cd $$(topdir) && $$(PATCH) --dry-run -p1 < $$(COMPARE_BUILD_PATCH) > /dev/null 2>&1 || $$(ECHO) FAILED)
|
||||
ifeq ($$(PATCH_DRY_RUN), FAILED)
|
||||
$$(error Patch file $$(COMPARE_BUILD_PATCH) does not apply cleanly)
|
||||
endif
|
||||
endif
|
||||
ifneq ($$(COMPARE_BUILD_FAIL), true)
|
||||
COMPARE_BUILD_IGNORE_RESULT := || true
|
||||
|
||||
@ -687,13 +687,15 @@ define SetupRunMicroTestBody
|
||||
$1_MICRO_BASIC_OPTIONS += -rff $$($1_TEST_RESULTS_DIR)/jmh-result.$(MICRO_RESULTS_FORMAT)
|
||||
endif
|
||||
|
||||
# Set library path for native dependencies
|
||||
$1_JMH_JVM_ARGS := -Djava.library.path=$$(TEST_IMAGE_DIR)/micro/native
|
||||
|
||||
ifneq ($$(MICRO_VM_OPTIONS)$$(MICRO_JAVA_OPTIONS), )
|
||||
JMH_JVM_ARGS := $$(MICRO_VM_OPTIONS) $$(MICRO_JAVA_OPTIONS)
|
||||
# Set library path for native dependencies
|
||||
JMH_JVM_ARGS += -Djava.library.path=$$(TEST_IMAGE_DIR)/micro/native
|
||||
$1_MICRO_VM_OPTIONS := -jvmArgs $(call ShellQuote,$$(JMH_JVM_ARGS))
|
||||
$1_JMH_JVM_ARGS += $$(MICRO_VM_OPTIONS) $$(MICRO_JAVA_OPTIONS)
|
||||
endif
|
||||
|
||||
$1_MICRO_VM_OPTIONS := -jvmArgs $(call ShellQuote,$$($1_JMH_JVM_ARGS))
|
||||
|
||||
ifneq ($$(MICRO_ITER), )
|
||||
$1_MICRO_ITER := -i $$(MICRO_ITER)
|
||||
endif
|
||||
|
||||
@ -381,22 +381,6 @@ AC_DEFUN_ONCE([BOOTJDK_SETUP_BOOT_JDK],
|
||||
BOOTJDK_USE_LOCAL_CDS=false
|
||||
AC_MSG_RESULT([no, -XX:SharedArchiveFile not supported])
|
||||
fi
|
||||
|
||||
# Check for jjs in bootjdk
|
||||
UTIL_SETUP_TOOL(JJS,
|
||||
[
|
||||
AC_MSG_CHECKING([for jjs in Boot JDK])
|
||||
JJS=$BOOT_JDK/bin/jjs
|
||||
if test ! -x $JJS; then
|
||||
AC_MSG_RESULT(not found)
|
||||
JJS=""
|
||||
AC_MSG_NOTICE([Cannot use pandoc without jjs])
|
||||
ENABLE_PANDOC=false
|
||||
else
|
||||
AC_MSG_RESULT(ok)
|
||||
fi
|
||||
AC_SUBST(JJS)
|
||||
])
|
||||
])
|
||||
|
||||
AC_DEFUN_ONCE([BOOTJDK_SETUP_BOOT_JDK_ARGUMENTS],
|
||||
|
||||
@ -239,21 +239,11 @@ AC_DEFUN([FLAGS_SETUP_OPTIMIZATION],
|
||||
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
|
||||
# we should do for all platforms?
|
||||
C_O_FLAG_HIGHEST_JVM="-Os"
|
||||
C_O_FLAG_HIGHEST="-Os"
|
||||
C_O_FLAG_HI="-Os"
|
||||
C_O_FLAG_NORM="-Os"
|
||||
C_O_FLAG_DEBUG_JVM=""
|
||||
else
|
||||
C_O_FLAG_HIGHEST_JVM="-O3"
|
||||
C_O_FLAG_HIGHEST="-O3"
|
||||
C_O_FLAG_HI="-O3"
|
||||
C_O_FLAG_NORM="-O2"
|
||||
C_O_FLAG_DEBUG_JVM="-O0"
|
||||
fi
|
||||
C_O_FLAG_HIGHEST_JVM="-O3"
|
||||
C_O_FLAG_HIGHEST="-O3"
|
||||
C_O_FLAG_HI="-O3"
|
||||
C_O_FLAG_NORM="-O2"
|
||||
C_O_FLAG_DEBUG_JVM="-O0"
|
||||
C_O_FLAG_SIZE="-Os"
|
||||
C_O_FLAG_DEBUG="-O0"
|
||||
C_O_FLAG_NONE="-O0"
|
||||
|
||||
@ -625,7 +625,6 @@ JAR_CMD:=@JAR@
|
||||
JLINK_CMD := @JLINK@
|
||||
JMOD_CMD := @JMOD@
|
||||
JARSIGNER_CMD:=@JARSIGNER@
|
||||
JJS_CMD:=@JJS@
|
||||
# These variables are meant to be used. They are defined with = instead of := to make
|
||||
# it possible to override only the *_CMD variables.
|
||||
JAVA=@FIXPATH@ $(JAVA_CMD) $(JAVA_FLAGS_BIG) $(JAVA_FLAGS)
|
||||
@ -637,7 +636,6 @@ JAR=@FIXPATH@ $(JAR_CMD)
|
||||
JLINK = @FIXPATH@ $(JLINK_CMD)
|
||||
JMOD = @FIXPATH@ $(JMOD_CMD) $(JAVA_TOOL_FLAGS_SMALL)
|
||||
JARSIGNER=@FIXPATH@ $(JARSIGNER_CMD)
|
||||
JJS=@FIXPATH@ $(JJS_CMD) $(JAVA_TOOL_FLAGS_SMALL)
|
||||
|
||||
BUILD_JAVA_FLAGS := @BOOTCYCLE_JVM_ARGS_BIG@
|
||||
BUILD_JAVA=@FIXPATH@ $(BUILD_JDK)/bin/java $(BUILD_JAVA_FLAGS)
|
||||
@ -650,6 +648,7 @@ INTERIM_LANGTOOLS_ADD_EXPORTS := \
|
||||
--add-exports java.base/sun.reflect.annotation=jdk.compiler.interim \
|
||||
--add-exports java.base/jdk.internal.jmod=jdk.compiler.interim \
|
||||
--add-exports java.base/jdk.internal.misc=jdk.compiler.interim \
|
||||
--add-exports java.base/sun.invoke.util=jdk.compiler.interim \
|
||||
#
|
||||
INTERIM_LANGTOOLS_MODULES_COMMA := $(strip $(subst $(SPACE),$(COMMA),$(strip \
|
||||
$(INTERIM_LANGTOOLS_MODULES))))
|
||||
|
||||
@ -199,9 +199,9 @@ ifeq ($(call isTargetOsType, unix), true)
|
||||
# PANDOC_TROFF_MANPAGE_FILTER, a wrapper around
|
||||
# PANDOC_TROFF_MANPAGE_FILTER_JAVASCRIPT. This is created by buildtools-jdk.
|
||||
|
||||
# We should also depend on the source javascript filter
|
||||
PANDOC_TROFF_MANPAGE_FILTER_JAVASCRIPT := \
|
||||
$(TOPDIR)/make/scripts/pandoc-troff-manpage-filter.js
|
||||
# We should also depend on the source code for the filter
|
||||
PANDOC_TROFF_MANPAGE_FILTER_SOURCE := $(call FindFiles, \
|
||||
$(TOPDIR)/make/jdk/src/classes/build/tools/pandocfilter)
|
||||
|
||||
# The norm in man pages is to display code literals as bold, but pandoc
|
||||
# "correctly" converts these constructs (encoded in markdown using `...`
|
||||
@ -231,7 +231,7 @@ ifeq ($(call isTargetOsType, unix), true)
|
||||
@@VERSION_SHORT@@ => $(VERSION_SHORT) ; \
|
||||
@@VERSION_SPECIFICATION@@ => $(VERSION_SPECIFICATION), \
|
||||
EXTRA_DEPS := $(PANDOC_TROFF_MANPAGE_FILTER) \
|
||||
$(PANDOC_TROFF_MANPAGE_FILTER_JAVASCRIPT), \
|
||||
$(PANDOC_TROFF_MANPAGE_FILTER_SOURCE), \
|
||||
))
|
||||
|
||||
TARGETS += $(BUILD_MAN_PAGES)
|
||||
|
||||
@ -604,10 +604,6 @@ var getJibProfilesProfiles = function (input, common, data) {
|
||||
dependencies: [ name + ".jdk" ],
|
||||
configure_args: [
|
||||
"--with-boot-jdk=" + input.get(name + ".jdk", "home_path"),
|
||||
// Full docs do not currently work with bootcycle build
|
||||
// since Nashorn was removed. This negates the
|
||||
// --enable-full-docs from the main profile.
|
||||
"--enable-full-docs=auto",
|
||||
]
|
||||
}
|
||||
profiles[bootcyclePrebuiltName] = concatObjects(profiles[name],
|
||||
@ -688,7 +684,7 @@ var getJibProfilesProfiles = function (input, common, data) {
|
||||
local: "bundles/\\(jdk.*doc-api-spec.tar.gz\\)",
|
||||
remote: [
|
||||
"bundles/common/jdk-" + data.version + "_doc-api-spec.tar.gz",
|
||||
"bundles/linux-x64/\\1"
|
||||
"bundles/common/\\1"
|
||||
],
|
||||
},
|
||||
}
|
||||
@ -765,7 +761,7 @@ var getJibProfilesProfiles = function (input, common, data) {
|
||||
profiles[cmpBaselineName].make_args = [ "COMPARE_BUILD=CONF=" ];
|
||||
profiles[cmpBaselineName].configure_args = concat(
|
||||
profiles[cmpBaselineName].configure_args,
|
||||
"--with-hotspot-build-time=n/a",
|
||||
"--with-hotspot-build-time=n/a",
|
||||
"--disable-precompiled-headers");
|
||||
// Do not inherit artifact definitions from base profile
|
||||
delete profiles[cmpBaselineName].artifacts;
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 1998, 2019, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 1998, 2020, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -393,11 +393,14 @@ JDWP "Java(tm) Debug Wire Protocol"
|
||||
(boolean canRedefineClasses
|
||||
"Can the VM redefine classes?")
|
||||
(boolean canAddMethod
|
||||
"Can the VM add methods when redefining "
|
||||
"classes?")
|
||||
"Can the VM add methods when redefining classes? "
|
||||
"<p>@Deprecated(since=\"15\") A JVM TI based JDWP back-end "
|
||||
"will never set this capability to true.")
|
||||
(boolean canUnrestrictedlyRedefineClasses
|
||||
"Can the VM redefine classes "
|
||||
"in ways that are normally restricted?")
|
||||
"in ways that are normally restricted?"
|
||||
"<p>@Deprecated(since=\"15\") A JVM TI based JDWP back-end "
|
||||
"will never set this capability to true.")
|
||||
(boolean canPopFrames
|
||||
"Can the VM pop stack frames?")
|
||||
(boolean canUseInstanceFilters
|
||||
@ -467,6 +470,7 @@ JDWP "Java(tm) Debug Wire Protocol"
|
||||
"<p>"
|
||||
"Requires canRedefineClasses capability - see "
|
||||
"<a href=\"#JDWP_VirtualMachine_CapabilitiesNew\">CapabilitiesNew</a>. "
|
||||
"<p>@Deprecated(since=\"15\") "
|
||||
"In addition to the canRedefineClasses capability, the target VM must "
|
||||
"have the canAddMethod capability to add methods when redefining classes, "
|
||||
"or the canUnrestrictedlyRedefineClasses capability to redefine classes in ways "
|
||||
@ -3160,8 +3164,8 @@ JDWP "Java(tm) Debug Wire Protocol"
|
||||
"canUnrestrictedlyRedefineClasses is false.")
|
||||
(Constant CLASS_ATTRIBUTE_CHANGE_NOT_IMPLEMENTED
|
||||
=72 "The new class version has a different NestHost, "
|
||||
"NestMembers, or Record class attribute and "
|
||||
"canUnrestrictedlyRedefineClasses is false.")
|
||||
"NestMembers, PermittedSubclasses, or Record class attribute "
|
||||
"and canUnrestrictedlyRedefineClasses is false.")
|
||||
(Constant NOT_IMPLEMENTED =99 "The functionality is not implemented in "
|
||||
"this virtual machine.")
|
||||
(Constant NULL_POINTER =100 "Invalid pointer.")
|
||||
|
||||
@ -119,6 +119,7 @@ JVM_GetMethodTypeAnnotations
|
||||
JVM_GetNanoTimeAdjustment
|
||||
JVM_GetNestHost
|
||||
JVM_GetNestMembers
|
||||
JVM_GetPermittedSubclasses
|
||||
JVM_GetPrimitiveArrayElement
|
||||
JVM_GetProperties
|
||||
JVM_GetProtectionDomain
|
||||
|
||||
@ -74,31 +74,40 @@ public class HelloClasslist {
|
||||
.forEach(System.out::println);
|
||||
|
||||
// Common concatenation patterns
|
||||
String SS = String.valueOf(args.length) + String.valueOf(args.length);
|
||||
String CS = "string" + String.valueOf(args.length);
|
||||
String SC = String.valueOf(args.length) + "string";
|
||||
String SCS = String.valueOf(args.length) + "string" + String.valueOf(args.length);
|
||||
String CSS = "string" + String.valueOf(args.length) + String.valueOf(args.length);
|
||||
String CSC = "string" + String.valueOf(args.length) + "string";
|
||||
String SSC = String.valueOf(args.length) + String.valueOf(args.length) + "string";
|
||||
String CSCS = "string" + String.valueOf(args.length) + "string" + String.valueOf(args.length);
|
||||
String SCSC = String.valueOf(args.length) + "string" + String.valueOf(args.length) + "string";
|
||||
String CSCSC = "string" + String.valueOf(args.length) + "string" + String.valueOf(args.length) + "string";
|
||||
String SCSCS = String.valueOf(args.length) + "string" + String.valueOf(args.length) + "string" + String.valueOf(args.length);
|
||||
String CI = "string" + args.length;
|
||||
String IC = args.length + "string";
|
||||
String SI = String.valueOf(args.length) + args.length;
|
||||
String IS = args.length + String.valueOf(args.length);
|
||||
String CIS = "string" + args.length + String.valueOf(args.length);
|
||||
String CSCI = "string" + String.valueOf(args.length) + "string" + args.length;
|
||||
String CIC = "string" + args.length + "string";
|
||||
String CICI = "string" + args.length + "string" + args.length;
|
||||
String CJ = "string" + System.currentTimeMillis();
|
||||
String JC = System.currentTimeMillis() + "string";
|
||||
String CD = "string" + (args.length/2.0);
|
||||
String CJC = "string" + System.currentTimeMillis() + "string";
|
||||
String CJCJ = "string" + System.currentTimeMillis() + "string" + System.currentTimeMillis();
|
||||
String CJCJC = "string" + System.currentTimeMillis() + "string" + System.currentTimeMillis() + "string";
|
||||
int i = args.length;
|
||||
String s = String.valueOf(i);
|
||||
|
||||
String SS = s + s;
|
||||
String CS = "string" + s;
|
||||
String SC = s + "string";
|
||||
String SCS = s + "string" + s;
|
||||
String CSS = "string" + s + s;
|
||||
String CSC = "string" + s + "string";
|
||||
String SSC = s + s + "string";
|
||||
String CSCS = "string" + s + "string" + s;
|
||||
String SCSC = s + "string" + s + "string";
|
||||
String CSCSC = "string" + s + "string" + s + "string";
|
||||
String SCSCS = s + "string" + s + "string" + s;
|
||||
String SSCSS = s + s + "string" + s + s;
|
||||
String SSSSS = s + s + s + s + s;
|
||||
|
||||
String CI = "string" + i;
|
||||
String IC = i + "string";
|
||||
String SI = s + i;
|
||||
String IS = i + s;
|
||||
String CIS = "string" + i + s;
|
||||
String CSCI = "string" + s + "string" + i;
|
||||
String CIC = "string" + i + "string";
|
||||
String CICI = "string" + i + "string" + i;
|
||||
|
||||
long l = System.currentTimeMillis();
|
||||
String CJ = "string" + l;
|
||||
String JC = l + "string";
|
||||
String CJC = "string" + l + "string";
|
||||
String CJCJ = "string" + l + "string" + l;
|
||||
String CJCJC = "string" + l + "string" + l + "string";
|
||||
double d = i / 2.0;
|
||||
String CD = "string" + d;
|
||||
|
||||
String newDate = DateTimeFormatter.ISO_LOCAL_DATE_TIME.format(
|
||||
LocalDateTime.now(ZoneId.of("GMT")));
|
||||
|
||||
108
make/jdk/src/classes/build/tools/pandocfilter/PandocFilter.java
Normal file
108
make/jdk/src/classes/build/tools/pandocfilter/PandocFilter.java
Normal file
@ -0,0 +1,108 @@
|
||||
package build.tools.pandocfilter;
|
||||
|
||||
import build.tools.pandocfilter.json.JSON;
|
||||
import build.tools.pandocfilter.json.JSONArray;
|
||||
import build.tools.pandocfilter.json.JSONObject;
|
||||
import build.tools.pandocfilter.json.JSONString;
|
||||
import build.tools.pandocfilter.json.JSONValue;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.FileReader;
|
||||
import java.io.InputStreamReader;
|
||||
import java.util.Map;
|
||||
|
||||
public class PandocFilter {
|
||||
/**
|
||||
* Traverse a tree of pandoc format objects, calling callback on each
|
||||
* element, and replacing it if callback returns a new object.
|
||||
* <p>
|
||||
* Inspired by the walk method in
|
||||
* https://github.com/jgm/pandocfilters/blob/master/pandocfilters.py
|
||||
*/
|
||||
public JSONValue traverse(JSONValue obj, Callback callback, boolean deep) {
|
||||
if (obj instanceof JSONArray) {
|
||||
JSONArray array = (JSONArray) obj;
|
||||
|
||||
JSONArray processed_array = new JSONArray();
|
||||
for (JSONValue elem : array) {
|
||||
if (elem instanceof JSONObject && elem.contains("t")) {
|
||||
JSONValue replacement = callback.invoke(elem.get("t").asString(), elem.contains("c") ? elem.get("c") : new JSONArray());
|
||||
if (replacement == null) {
|
||||
// no replacement object returned, use original
|
||||
processed_array.add(traverse(elem, callback, deep));
|
||||
} else if (replacement instanceof JSONArray) {
|
||||
// array of objects returned, splice all elements into array
|
||||
JSONArray replacement_array = (JSONArray) replacement;
|
||||
for (JSONValue repl_elem : replacement_array) {
|
||||
processed_array.add(traverse(repl_elem, callback, deep));
|
||||
}
|
||||
} else {
|
||||
// replacement object given, traverse it
|
||||
processed_array.add(traverse(replacement, callback, deep));
|
||||
}
|
||||
} else {
|
||||
processed_array.add(traverse(elem, callback, deep));
|
||||
}
|
||||
}
|
||||
return processed_array;
|
||||
} else if (obj instanceof JSONObject) {
|
||||
if (deep && obj.contains("t")) {
|
||||
JSONValue replacement = callback.invoke(obj.get("t").asString(), obj.contains("c") ? obj.get("c") : new JSONArray());
|
||||
if (replacement != null) {
|
||||
return replacement;
|
||||
}
|
||||
} JSONObject obj_obj = (JSONObject) obj;
|
||||
var processed_obj = new JSONObject();
|
||||
for (String key : obj_obj.keys()) {
|
||||
processed_obj.put(key, traverse(obj_obj.get(key), callback, deep));
|
||||
}
|
||||
return processed_obj;
|
||||
} else {
|
||||
return obj;
|
||||
}
|
||||
}
|
||||
|
||||
public JSONValue createPandocNode(String type, JSONValue content) {
|
||||
if (content == null) {
|
||||
return new JSONObject(Map.of(
|
||||
"t", new JSONString(type)));
|
||||
} else {
|
||||
return new JSONObject(Map.of(
|
||||
"t", new JSONString(type),
|
||||
"c", content));
|
||||
}
|
||||
}
|
||||
|
||||
public JSONValue createPandocNode(String type) {
|
||||
return createPandocNode(type, null);
|
||||
}
|
||||
|
||||
/*
|
||||
* Helper constructors to create pandoc format objects
|
||||
*/
|
||||
public JSONValue createSpace() {
|
||||
return createPandocNode("Space");
|
||||
}
|
||||
|
||||
public JSONValue createStr(String string) {
|
||||
return createPandocNode("Str", new JSONString(string));
|
||||
}
|
||||
|
||||
public static JSONValue loadJson(String[] args) throws FileNotFoundException {
|
||||
StringBuffer input = new StringBuffer();
|
||||
InputStreamReader reader;
|
||||
if (args.length > 0)
|
||||
reader = new FileReader(args[0]);
|
||||
else {
|
||||
reader = new InputStreamReader(System.in);
|
||||
}
|
||||
new BufferedReader(reader).lines().forEach(line -> input.append(line));
|
||||
|
||||
return JSON.parse(input.toString());
|
||||
}
|
||||
|
||||
public interface Callback {
|
||||
JSONValue invoke(String type, JSONValue value);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,79 @@
|
||||
/*
|
||||
* Copyright (c) 2018, 2020, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package build.tools.pandocfilter;
|
||||
|
||||
import build.tools.pandocfilter.json.JSONArray;
|
||||
import build.tools.pandocfilter.json.JSONObject;
|
||||
import build.tools.pandocfilter.json.JSONValue;
|
||||
|
||||
import java.io.FileNotFoundException;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
public class PandocManPageHtmlFilter extends PandocFilter {
|
||||
|
||||
private JSONValue MetaInlines(JSONValue value) {
|
||||
return createPandocNode("MetaInlines", value);
|
||||
}
|
||||
|
||||
private JSONValue changeTitle(String type, JSONValue value) {
|
||||
if (type.equals("MetaInlines")) {
|
||||
String subType = value.get(0).get("t").asString();
|
||||
String subContent = value.get(0).get("c").asString();
|
||||
if (subType.equals("Str")) {
|
||||
Pattern pattern = Pattern.compile("^([A-Z0-9]+)\\([0-9]+\\)$");
|
||||
Matcher matcher = pattern.matcher(subContent);
|
||||
if (matcher.find()) {
|
||||
String commandName = matcher.group(1).toLowerCase();
|
||||
return MetaInlines(new JSONArray(
|
||||
createStr("The"), createSpace(),
|
||||
createStr(commandName),
|
||||
createSpace(), createStr("Command")));
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Main function
|
||||
*/
|
||||
public static void main(String[] args) throws FileNotFoundException {
|
||||
JSONValue json = loadJson(args);
|
||||
|
||||
PandocManPageHtmlFilter filter = new PandocManPageHtmlFilter();
|
||||
|
||||
JSONValue meta = json.get("meta");
|
||||
if (meta != null && meta instanceof JSONObject) {
|
||||
JSONObject metaobj = (JSONObject) meta;
|
||||
metaobj.remove("date");
|
||||
JSONValue title = meta.get("title");
|
||||
if (title != null) {
|
||||
metaobj.put("title", filter.traverse(title, filter::changeTitle, true));
|
||||
}
|
||||
}
|
||||
|
||||
System.out.println(json);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,100 @@
|
||||
/*
|
||||
* Copyright (c) 2018, 2020, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package build.tools.pandocfilter;
|
||||
|
||||
import build.tools.pandocfilter.json.JSONArray;
|
||||
import build.tools.pandocfilter.json.JSONValue;
|
||||
|
||||
import java.io.FileNotFoundException;
|
||||
|
||||
public class PandocManPageTroffFilter extends PandocFilter {
|
||||
|
||||
private JSONValue createStrong(JSONValue value) {
|
||||
return createPandocNode("Strong", value);
|
||||
}
|
||||
|
||||
private JSONValue createHeader(JSONValue value) {
|
||||
return createPandocNode("Header", value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Callback to change all Str texts to upper case
|
||||
*/
|
||||
private JSONValue uppercase(String type, JSONValue value) {
|
||||
if (type.equals("Str")) {
|
||||
return createStr(value.asString().toUpperCase());
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Main callback function that performs our man page AST rewrites
|
||||
*/
|
||||
private JSONValue manpageFilter(String type, JSONValue value) {
|
||||
// If it is a header, decrease the heading level by one, and
|
||||
// if it is a level 1 header, convert it to upper case.
|
||||
if (type.equals("Header")) {
|
||||
JSONArray array = value.asArray();
|
||||
int level = array.get(0).asInt();
|
||||
array.set(0, JSONValue.from(level - 1));
|
||||
if (value.asArray().get(0).asInt() == 1) {
|
||||
return createHeader(traverse(value, this::uppercase, false));
|
||||
}
|
||||
}
|
||||
|
||||
// Man pages does not have superscript. We use it for footnotes, so
|
||||
// enclose in [...] for best representation.
|
||||
if (type.equals("Superscript")) {
|
||||
return new JSONArray(createStr("["), value, createStr("]"));
|
||||
}
|
||||
|
||||
// If it is a link, put the link name in bold. If it is an external
|
||||
// link, put it in brackets. Otherwise, it is either an internal link
|
||||
// (like "#next-heading"), or a relative link to another man page
|
||||
// (like "java.html"), so remove it for man pages.
|
||||
if (type.equals("Link")) {
|
||||
JSONValue target = value.asArray().get(2).asArray().get(0);
|
||||
String targetStr = target.asString();
|
||||
if (targetStr.startsWith("https:") || targetStr.startsWith("http:")) {
|
||||
return new JSONArray(createStrong(value.asArray().get(1)), createSpace(), createStr("[" + targetStr + "]"));
|
||||
} else {
|
||||
return createStrong(value.asArray().get(1));
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Main function
|
||||
*/
|
||||
public static void main(String[] args) throws FileNotFoundException {
|
||||
JSONValue json = loadJson(args);
|
||||
build.tools.pandocfilter.PandocManPageTroffFilter filter = new build.tools.pandocfilter.PandocManPageTroffFilter();
|
||||
|
||||
JSONValue transformed_json = filter.traverse(json, filter::manpageFilter, false);
|
||||
|
||||
System.out.println(transformed_json);
|
||||
}
|
||||
}
|
||||
61
make/jdk/src/classes/build/tools/pandocfilter/json/JSON.java
Normal file
61
make/jdk/src/classes/build/tools/pandocfilter/json/JSON.java
Normal file
@ -0,0 +1,61 @@
|
||||
/*
|
||||
* Copyright (c) 2018, 2020, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
package build.tools.pandocfilter.json;
|
||||
|
||||
public class JSON {
|
||||
public static JSONValue parse(String s) {
|
||||
return new JSONParser().parse(s);
|
||||
}
|
||||
|
||||
public static JSONValue of(int i) {
|
||||
return JSONValue.from(i);
|
||||
}
|
||||
|
||||
public static JSONValue of(long l) {
|
||||
return JSONValue.from(l);
|
||||
}
|
||||
|
||||
public static JSONValue of(double d) {
|
||||
return JSONValue.from(d);
|
||||
}
|
||||
|
||||
public static JSONValue of(boolean b) {
|
||||
return JSONValue.from(b);
|
||||
}
|
||||
|
||||
public static JSONValue of(String s) {
|
||||
return JSONValue.from(s);
|
||||
}
|
||||
|
||||
public static JSONValue of() {
|
||||
return JSONValue.fromNull();
|
||||
}
|
||||
|
||||
public static JSONArray array() {
|
||||
return new JSONArray();
|
||||
}
|
||||
|
||||
public static JSONObject object() {
|
||||
return new JSONObject();
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,176 @@
|
||||
/*
|
||||
* Copyright (c) 2018, 2020, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
package build.tools.pandocfilter.json;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
public class JSONArray implements JSONValue, Iterable<JSONValue> {
|
||||
private final List<JSONValue> values;
|
||||
|
||||
public JSONArray() {
|
||||
this.values = new ArrayList<JSONValue>();
|
||||
}
|
||||
|
||||
public JSONArray(JSONValue[] array) {
|
||||
this.values = new ArrayList<JSONValue>(array.length);
|
||||
for (var v : array) {
|
||||
values.add(v);
|
||||
}
|
||||
}
|
||||
|
||||
private void append(JSONValue value) {
|
||||
if (value instanceof JSONArray) {
|
||||
for (var v : value.asArray()) {
|
||||
append(v);
|
||||
}
|
||||
} else {
|
||||
this.values.add(value);
|
||||
}
|
||||
}
|
||||
|
||||
public JSONArray(JSONValue value, JSONValue... values) {
|
||||
this.values = new ArrayList<JSONValue>(values.length + 1);
|
||||
append(value);
|
||||
for (var v : values) {
|
||||
append(v);
|
||||
}
|
||||
}
|
||||
|
||||
public JSONArray(List<JSONValue> values) {
|
||||
this.values = new ArrayList<JSONValue>(values);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isArray() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public JSONArray asArray() {
|
||||
return this;
|
||||
}
|
||||
|
||||
public JSONArray set(int i, boolean value) {
|
||||
values.set(i, JSON.of(value));
|
||||
return this;
|
||||
}
|
||||
|
||||
public JSONArray set(int i, int value) {
|
||||
values.set(i, JSON.of(value));
|
||||
return this;
|
||||
}
|
||||
|
||||
public JSONArray set(int i, long value) {
|
||||
values.set(i, JSON.of(value));
|
||||
return this;
|
||||
}
|
||||
|
||||
public JSONArray set(int i, String value) {
|
||||
values.set(i, JSON.of(value));
|
||||
return this;
|
||||
}
|
||||
|
||||
public JSONArray set(int i, double value) {
|
||||
values.set(i, JSON.of(value));
|
||||
return this;
|
||||
}
|
||||
|
||||
public JSONArray set(int i, JSONValue value) {
|
||||
values.set(i, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
public JSONArray setNull(int i) {
|
||||
values.set(i, JSON.of());
|
||||
return this;
|
||||
}
|
||||
|
||||
public JSONArray add(boolean value) {
|
||||
values.add(JSON.of(value));
|
||||
return this;
|
||||
}
|
||||
|
||||
public JSONArray add(int value) {
|
||||
values.add(JSON.of(value));
|
||||
return this;
|
||||
}
|
||||
|
||||
public JSONArray add(long value) {
|
||||
values.add(JSON.of(value));
|
||||
return this;
|
||||
}
|
||||
|
||||
public JSONArray add(String value) {
|
||||
values.add(JSON.of(value));
|
||||
return this;
|
||||
}
|
||||
|
||||
public JSONArray add(double value) {
|
||||
values.add(JSON.of(value));
|
||||
return this;
|
||||
}
|
||||
|
||||
public JSONArray add(JSONValue value) {
|
||||
values.add(value);
|
||||
return this;
|
||||
}
|
||||
|
||||
public JSONArray addNull() {
|
||||
values.add(JSON.of());
|
||||
return this;
|
||||
}
|
||||
|
||||
public JSONValue get(int i) {
|
||||
return values.get(i);
|
||||
}
|
||||
|
||||
public int size() {
|
||||
return values.size();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
var builder = new StringBuilder();
|
||||
|
||||
builder.append("[");
|
||||
for (var i = 0; i < size(); i++) {
|
||||
builder.append(get(i).toString());
|
||||
if (i != (size() - 1)) {
|
||||
builder.append(",");
|
||||
}
|
||||
}
|
||||
builder.append("]");
|
||||
return builder.toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Stream<JSONValue> stream() {
|
||||
return values.stream();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterator<JSONValue> iterator() {
|
||||
return values.iterator();
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,46 @@
|
||||
/*
|
||||
* Copyright (c) 2018, 2020, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
package build.tools.pandocfilter.json;
|
||||
|
||||
public class JSONBoolean implements JSONValue {
|
||||
private boolean value;
|
||||
|
||||
public JSONBoolean(boolean value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isBoolean() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean asBoolean() {
|
||||
return value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return value ? "true" : "false";
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,46 @@
|
||||
/*
|
||||
* Copyright (c) 2018, 2020, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
package build.tools.pandocfilter.json;
|
||||
|
||||
public class JSONDecimal implements JSONValue {
|
||||
private double value;
|
||||
|
||||
public JSONDecimal(double value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isDouble() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public double asDouble() {
|
||||
return value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return Double.toString(value);
|
||||
}
|
||||
}
|
||||
@ -1,12 +1,10 @@
|
||||
/*
|
||||
* Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2018, 2020, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
* 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
|
||||
@ -22,19 +20,34 @@
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
package build.tools.pandocfilter.json;
|
||||
|
||||
public class JSONNull implements JSONValue {
|
||||
public JSONNull() {
|
||||
}
|
||||
|
||||
import java.awt.Frame;
|
||||
@Override
|
||||
public boolean isNull() {
|
||||
return true;
|
||||
}
|
||||
|
||||
public class LoadFrame {
|
||||
@Override
|
||||
public String asString() {
|
||||
return null;
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
new Frame().show();
|
||||
// This starts a thread which never exits - so we suicide.
|
||||
try {
|
||||
Thread.sleep(5000);
|
||||
} catch (Exception e) {
|
||||
}
|
||||
System.exit(0);
|
||||
@Override
|
||||
public JSONArray asArray() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public JSONObject asObject() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "null";
|
||||
}
|
||||
}
|
||||
@ -1,12 +1,10 @@
|
||||
/*
|
||||
* Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2018, 2020, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
* 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
|
||||
@ -22,27 +20,41 @@
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
package build.tools.pandocfilter.json;
|
||||
|
||||
public class JSONNumber implements JSONValue {
|
||||
private long value;
|
||||
|
||||
import java.awt.*;
|
||||
import java.io.PrintStream;
|
||||
import javax.swing.*;
|
||||
|
||||
public class JHello extends JFrame {
|
||||
|
||||
JHello() {
|
||||
JLabel jlabel = new JLabel("Hello");
|
||||
jlabel.setFont(new Font("Monospaced", 0, 144));
|
||||
getContentPane().add(jlabel);
|
||||
pack();
|
||||
public JSONNumber(int value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
public static void main(String args[]) {
|
||||
new JHello().show();
|
||||
try {
|
||||
Thread.sleep(10000);
|
||||
} catch (Exception e) {
|
||||
}
|
||||
System.exit(0);
|
||||
public JSONNumber(long value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isInt() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isLong() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int asInt() {
|
||||
return Math.toIntExact(value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public long asLong() {
|
||||
return value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return Long.toString(value);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,155 @@
|
||||
/*
|
||||
* Copyright (c) 2018, 2020, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
package build.tools.pandocfilter.json;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
public class JSONObject implements JSONValue {
|
||||
public static class Field {
|
||||
private final String name;
|
||||
private final JSONValue value;
|
||||
|
||||
private Field(String name, JSONValue value) {
|
||||
this.name = name;
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
public String name() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public JSONValue value() {
|
||||
return value;
|
||||
}
|
||||
}
|
||||
|
||||
private final Map<String, JSONValue> value;
|
||||
|
||||
public JSONObject() {
|
||||
this.value = new HashMap<String, JSONValue>();
|
||||
}
|
||||
|
||||
public JSONObject(Map<String, JSONValue> map) {
|
||||
this.value = new HashMap<String, JSONValue>(map);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isObject() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public JSONObject asObject() {
|
||||
return this;
|
||||
}
|
||||
|
||||
public JSONObject put(String k, boolean v) {
|
||||
value.put(k, JSON.of(v));
|
||||
return this;
|
||||
}
|
||||
|
||||
public JSONObject put(String k, int v) {
|
||||
value.put(k, JSON.of(v));
|
||||
return this;
|
||||
}
|
||||
|
||||
public JSONObject put(String k, long v) {
|
||||
value.put(k, JSON.of(v));
|
||||
return this;
|
||||
}
|
||||
|
||||
public JSONObject put(String k, String v) {
|
||||
value.put(k, JSON.of(v));
|
||||
return this;
|
||||
}
|
||||
|
||||
public JSONObject put(String k, double v) {
|
||||
value.put(k, JSON.of(v));
|
||||
return this;
|
||||
}
|
||||
|
||||
public JSONObject put(String k, JSONArray v) {
|
||||
value.put(k, v);
|
||||
return this;
|
||||
}
|
||||
|
||||
public JSONObject put(String k, JSONObject v) {
|
||||
value.put(k, v);
|
||||
return this;
|
||||
}
|
||||
|
||||
public JSONObject put(String k, JSONValue v) {
|
||||
value.put(k, v);
|
||||
return this;
|
||||
}
|
||||
|
||||
public JSONObject putNull(String k) {
|
||||
value.put(k, JSON.of());
|
||||
return this;
|
||||
}
|
||||
|
||||
public JSONValue remove(String k) {
|
||||
return value.remove(k);
|
||||
}
|
||||
|
||||
public JSONValue get(String k) {
|
||||
return value.get(k);
|
||||
}
|
||||
|
||||
public List<Field> fields() {
|
||||
return value.entrySet()
|
||||
.stream()
|
||||
.map(e -> new Field(e.getKey(), e.getValue()))
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
public boolean contains(String field) {
|
||||
return value.containsKey(field);
|
||||
}
|
||||
|
||||
public Set<String> keys() {
|
||||
return value.keySet();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
var builder = new StringBuilder();
|
||||
builder.append("{");
|
||||
for (var key : value.keySet()) {
|
||||
builder.append("\"");
|
||||
builder.append(key);
|
||||
builder.append("\":");
|
||||
builder.append(value.get(key).toString());
|
||||
builder.append(",");
|
||||
}
|
||||
|
||||
var end = builder.length() - 1;
|
||||
if (builder.charAt(end) == ',') {
|
||||
builder.deleteCharAt(end);
|
||||
}
|
||||
|
||||
builder.append("}");
|
||||
return builder.toString();
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,391 @@
|
||||
/*
|
||||
* Copyright (c) 2018, 2020, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
package build.tools.pandocfilter.json;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
class JSONParser {
|
||||
private int pos = 0;
|
||||
private String input;
|
||||
|
||||
JSONParser() {
|
||||
}
|
||||
|
||||
private IllegalStateException failure(String message) {
|
||||
return new IllegalStateException(String.format("[%d]: %s : %s", pos, message, input));
|
||||
}
|
||||
|
||||
private char current() {
|
||||
return input.charAt(pos);
|
||||
}
|
||||
|
||||
private void advance() {
|
||||
pos++;
|
||||
}
|
||||
|
||||
private boolean hasInput() {
|
||||
return pos < input.length();
|
||||
}
|
||||
|
||||
private void expectMoreInput(String message) {
|
||||
if (!hasInput()) {
|
||||
throw failure(message);
|
||||
}
|
||||
}
|
||||
|
||||
private char next(String message) {
|
||||
advance();
|
||||
if (!hasInput()) {
|
||||
throw failure(message);
|
||||
}
|
||||
return current();
|
||||
}
|
||||
|
||||
|
||||
private void expect(char c) {
|
||||
var msg = String.format("Expected character %c", c);
|
||||
|
||||
var n = next(msg);
|
||||
if (n != c) {
|
||||
throw failure(msg);
|
||||
}
|
||||
}
|
||||
|
||||
private void assume(char c, String message) {
|
||||
expectMoreInput(message);
|
||||
if (current() != c) {
|
||||
throw failure(message);
|
||||
}
|
||||
}
|
||||
|
||||
private JSONBoolean parseBoolean() {
|
||||
if (current() == 't') {
|
||||
expect('r');
|
||||
expect('u');
|
||||
expect('e');
|
||||
advance();
|
||||
return new JSONBoolean(true);
|
||||
}
|
||||
|
||||
if (current() == 'f') {
|
||||
expect('a');
|
||||
expect('l');
|
||||
expect('s');
|
||||
expect('e');
|
||||
advance();
|
||||
return new JSONBoolean(false);
|
||||
}
|
||||
|
||||
throw failure("a boolean can only be 'true' or 'false'");
|
||||
}
|
||||
|
||||
private JSONValue parseNumber() {
|
||||
var isInteger = true;
|
||||
var builder = new StringBuilder();
|
||||
|
||||
if (current() == '-') {
|
||||
builder.append(current());
|
||||
advance();
|
||||
expectMoreInput("a number cannot consist of only '-'");
|
||||
}
|
||||
|
||||
if (current() == '0') {
|
||||
builder.append(current());
|
||||
advance();
|
||||
|
||||
if (hasInput() && current() == '.') {
|
||||
isInteger = false;
|
||||
builder.append(current());
|
||||
advance();
|
||||
|
||||
expectMoreInput("a number cannot end with '.'");
|
||||
|
||||
if (!isDigit(current())) {
|
||||
throw failure("must be at least one digit after '.'");
|
||||
}
|
||||
|
||||
while (hasInput() && isDigit(current())) {
|
||||
builder.append(current());
|
||||
advance();
|
||||
}
|
||||
}
|
||||
} else {
|
||||
while (hasInput() && isDigit(current())) {
|
||||
builder.append(current());
|
||||
advance();
|
||||
}
|
||||
|
||||
if (hasInput() && current() == '.') {
|
||||
isInteger = false;
|
||||
builder.append(current());
|
||||
advance();
|
||||
|
||||
expectMoreInput("a number cannot end with '.'");
|
||||
|
||||
if (!isDigit(current())) {
|
||||
throw failure("must be at least one digit after '.'");
|
||||
}
|
||||
|
||||
while (hasInput() && isDigit(current())) {
|
||||
builder.append(current());
|
||||
advance();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (hasInput() && (current() == 'e' || current() == 'E')) {
|
||||
isInteger = false;
|
||||
|
||||
builder.append(current());
|
||||
advance();
|
||||
expectMoreInput("a number cannot end with 'e' or 'E'");
|
||||
|
||||
if (current() == '+' || current() == '-') {
|
||||
builder.append(current());
|
||||
advance();
|
||||
}
|
||||
|
||||
if (!isDigit(current())) {
|
||||
throw failure("a digit must follow {'e','E'}{'+','-'}");
|
||||
}
|
||||
|
||||
while (hasInput() && isDigit(current())) {
|
||||
builder.append(current());
|
||||
advance();
|
||||
}
|
||||
}
|
||||
|
||||
var value = builder.toString();
|
||||
return isInteger ? new JSONNumber(Long.parseLong(value)) :
|
||||
new JSONDecimal(Double.parseDouble(value));
|
||||
|
||||
}
|
||||
|
||||
private JSONString parseString() {
|
||||
var missingEndChar = "string is not terminated with '\"'";
|
||||
var builder = new StringBuilder();
|
||||
for (var c = next(missingEndChar); c != '"'; c = next(missingEndChar)) {
|
||||
if (c == '\\') {
|
||||
var n = next(missingEndChar);
|
||||
switch (n) {
|
||||
case '"':
|
||||
builder.append("\"");
|
||||
break;
|
||||
case '\\':
|
||||
builder.append("\\");
|
||||
break;
|
||||
case '/':
|
||||
builder.append("/");
|
||||
break;
|
||||
case 'b':
|
||||
builder.append("\b");
|
||||
break;
|
||||
case 'f':
|
||||
builder.append("\f");
|
||||
break;
|
||||
case 'n':
|
||||
builder.append("\n");
|
||||
break;
|
||||
case 'r':
|
||||
builder.append("\r");
|
||||
break;
|
||||
case 't':
|
||||
builder.append("\t");
|
||||
break;
|
||||
case 'u':
|
||||
var u1 = next(missingEndChar);
|
||||
var u2 = next(missingEndChar);
|
||||
var u3 = next(missingEndChar);
|
||||
var u4 = next(missingEndChar);
|
||||
var cp = Integer.parseInt(String.format("%c%c%c%c", u1, u2, u3, u4), 16);
|
||||
builder.append(new String(new int[]{cp}, 0, 1));
|
||||
break;
|
||||
default:
|
||||
throw failure(String.format("Unexpected escaped character '%c'", n));
|
||||
}
|
||||
} else {
|
||||
builder.append(c);
|
||||
}
|
||||
}
|
||||
|
||||
advance(); // step beyond closing "
|
||||
return new JSONString(builder.toString());
|
||||
}
|
||||
|
||||
private JSONArray parseArray() {
|
||||
var error = "array is not terminated with ']'";
|
||||
var list = new ArrayList<JSONValue>();
|
||||
|
||||
advance(); // step beyond opening '['
|
||||
consumeWhitespace();
|
||||
expectMoreInput(error);
|
||||
|
||||
while (current() != ']') {
|
||||
var val = parseValue();
|
||||
list.add(val);
|
||||
|
||||
expectMoreInput(error);
|
||||
if (current() == ',') {
|
||||
advance();
|
||||
}
|
||||
expectMoreInput(error);
|
||||
}
|
||||
|
||||
advance(); // step beyond closing ']'
|
||||
return new JSONArray(list.toArray(new JSONValue[0]));
|
||||
}
|
||||
|
||||
public JSONNull parseNull() {
|
||||
expect('u');
|
||||
expect('l');
|
||||
expect('l');
|
||||
advance();
|
||||
return new JSONNull();
|
||||
}
|
||||
|
||||
public JSONObject parseObject() {
|
||||
var error = "object is not terminated with '}'";
|
||||
var map = new HashMap<String, JSONValue>();
|
||||
|
||||
advance(); // step beyond opening '{'
|
||||
consumeWhitespace();
|
||||
expectMoreInput(error);
|
||||
|
||||
while (current() != '}') {
|
||||
var key = parseValue();
|
||||
if (!(key instanceof JSONString)) {
|
||||
throw failure("a field must of type string");
|
||||
}
|
||||
|
||||
if (!hasInput() || current() != ':') {
|
||||
throw failure("a field must be followed by ':'");
|
||||
}
|
||||
advance(); // skip ':'
|
||||
|
||||
var val = parseValue();
|
||||
map.put(key.asString(), val);
|
||||
|
||||
expectMoreInput(error);
|
||||
if (current() == ',') {
|
||||
advance();
|
||||
}
|
||||
expectMoreInput(error);
|
||||
}
|
||||
|
||||
advance(); // step beyond '}'
|
||||
return new JSONObject(map);
|
||||
}
|
||||
|
||||
private boolean isDigit(char c) {
|
||||
return c == '0' ||
|
||||
c == '1' ||
|
||||
c == '2' ||
|
||||
c == '3' ||
|
||||
c == '4' ||
|
||||
c == '5' ||
|
||||
c == '6' ||
|
||||
c == '7' ||
|
||||
c == '8' ||
|
||||
c == '9';
|
||||
}
|
||||
|
||||
private boolean isStartOfNumber(char c) {
|
||||
return isDigit(c) || c == '-';
|
||||
}
|
||||
|
||||
private boolean isStartOfString(char c) {
|
||||
return c == '"';
|
||||
}
|
||||
|
||||
private boolean isStartOfBoolean(char c) {
|
||||
return c == 't' || c == 'f';
|
||||
}
|
||||
|
||||
private boolean isStartOfArray(char c) {
|
||||
return c == '[';
|
||||
}
|
||||
|
||||
private boolean isStartOfNull(char c) {
|
||||
return c == 'n';
|
||||
}
|
||||
|
||||
private boolean isWhitespace(char c) {
|
||||
return c == '\r' ||
|
||||
c == '\n' ||
|
||||
c == '\t' ||
|
||||
c == ' ';
|
||||
}
|
||||
|
||||
private boolean isStartOfObject(char c) {
|
||||
return c == '{';
|
||||
}
|
||||
|
||||
private void consumeWhitespace() {
|
||||
while (hasInput() && isWhitespace(current())) {
|
||||
advance();
|
||||
}
|
||||
}
|
||||
|
||||
public JSONValue parseValue() {
|
||||
JSONValue ret = null;
|
||||
|
||||
consumeWhitespace();
|
||||
if (hasInput()) {
|
||||
var c = current();
|
||||
|
||||
if (isStartOfNumber(c)) {
|
||||
ret = parseNumber();
|
||||
} else if (isStartOfString(c)) {
|
||||
ret = parseString();
|
||||
} else if (isStartOfBoolean(c)) {
|
||||
ret = parseBoolean();
|
||||
} else if (isStartOfArray(c)) {
|
||||
ret = parseArray();
|
||||
} else if (isStartOfNull(c)) {
|
||||
ret = parseNull();
|
||||
} else if (isStartOfObject(c)) {
|
||||
ret = parseObject();
|
||||
} else {
|
||||
throw failure("not a valid start of a JSON value");
|
||||
}
|
||||
}
|
||||
consumeWhitespace();
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
public JSONValue parse(String s) {
|
||||
if (s == null || s.equals("")) {
|
||||
return null;
|
||||
}
|
||||
|
||||
pos = 0;
|
||||
input = s;
|
||||
|
||||
var result = parseValue();
|
||||
if (hasInput()) {
|
||||
throw failure("can only have one top-level JSON value");
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,84 @@
|
||||
/*
|
||||
* Copyright (c) 2018, 2020, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
package build.tools.pandocfilter.json;
|
||||
|
||||
public class JSONString implements JSONValue {
|
||||
private String value;
|
||||
|
||||
public JSONString(String value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isString() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String asString() {
|
||||
return value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
var builder = new StringBuilder();
|
||||
builder.append("\"");
|
||||
|
||||
for (var i = 0; i < value.length(); i++) {
|
||||
var c = value.charAt(i);
|
||||
|
||||
switch (c) {
|
||||
case '"':
|
||||
builder.append("\\\"");
|
||||
break;
|
||||
case '\\':
|
||||
builder.append("\\\\");
|
||||
break;
|
||||
case '/':
|
||||
builder.append("\\/");
|
||||
break;
|
||||
case '\b':
|
||||
builder.append("\\b");
|
||||
break;
|
||||
case '\f':
|
||||
builder.append("\\f");
|
||||
break;
|
||||
case '\n':
|
||||
builder.append("\\n");
|
||||
break;
|
||||
case '\r':
|
||||
builder.append("\\r");
|
||||
break;
|
||||
case '\t':
|
||||
builder.append("\\t");
|
||||
break;
|
||||
default:
|
||||
builder.append(c);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
builder.append("\"");
|
||||
return builder.toString();
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,132 @@
|
||||
/*
|
||||
* Copyright (c) 2018, 2020, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
package build.tools.pandocfilter.json;
|
||||
|
||||
import java.util.stream.Stream;
|
||||
import java.util.List;
|
||||
|
||||
public interface JSONValue {
|
||||
default int asInt() {
|
||||
throw new IllegalStateException("Unsupported conversion to int");
|
||||
}
|
||||
|
||||
default long asLong() {
|
||||
throw new IllegalStateException("Unsupported conversion to long");
|
||||
}
|
||||
|
||||
default double asDouble() {
|
||||
throw new IllegalStateException("Unsupported conversion to double");
|
||||
}
|
||||
|
||||
default String asString() {
|
||||
throw new IllegalStateException("Unsupported conversion to String");
|
||||
}
|
||||
|
||||
default boolean asBoolean() {
|
||||
throw new IllegalStateException("Unsupported conversion to boolean");
|
||||
}
|
||||
|
||||
default JSONArray asArray() {
|
||||
throw new IllegalStateException("Unsupported conversion to array");
|
||||
}
|
||||
|
||||
default JSONObject asObject() {
|
||||
throw new IllegalStateException("Unsupported conversion to object");
|
||||
}
|
||||
|
||||
default boolean isInt() {
|
||||
return false;
|
||||
}
|
||||
|
||||
default boolean isLong() {
|
||||
return false;
|
||||
}
|
||||
|
||||
default boolean isDouble() {
|
||||
return false;
|
||||
}
|
||||
|
||||
default boolean isString() {
|
||||
return false;
|
||||
}
|
||||
|
||||
default boolean isBoolean() {
|
||||
return false;
|
||||
}
|
||||
|
||||
default boolean isArray() {
|
||||
return false;
|
||||
}
|
||||
|
||||
default boolean isObject() {
|
||||
return false;
|
||||
}
|
||||
|
||||
default boolean isNull() {
|
||||
return false;
|
||||
}
|
||||
|
||||
default List<JSONObject.Field> fields() {
|
||||
return asObject().fields();
|
||||
}
|
||||
|
||||
default boolean contains(String key) {
|
||||
return asObject().contains(key);
|
||||
}
|
||||
|
||||
default JSONValue get(String key) {
|
||||
return asObject().get(key);
|
||||
}
|
||||
|
||||
default JSONValue get(int i) {
|
||||
return asArray().get(i);
|
||||
}
|
||||
|
||||
default Stream<JSONValue> stream() {
|
||||
return Stream.of(this);
|
||||
}
|
||||
|
||||
static JSONValue from(int i) {
|
||||
return new JSONNumber(i);
|
||||
}
|
||||
|
||||
static JSONValue from(long l) {
|
||||
return new JSONNumber(l);
|
||||
}
|
||||
|
||||
static JSONValue from(double d) {
|
||||
return new JSONDecimal(d);
|
||||
}
|
||||
|
||||
static JSONValue from(boolean b) {
|
||||
return new JSONBoolean(b);
|
||||
}
|
||||
|
||||
static JSONValue from(String s) {
|
||||
return new JSONString(s);
|
||||
}
|
||||
|
||||
static JSONValue fromNull() {
|
||||
return new JSONNull();
|
||||
}
|
||||
}
|
||||
@ -1,125 +0,0 @@
|
||||
//
|
||||
// Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
|
||||
// DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
//
|
||||
// This code is free software; you can redistribute it and/or modify it
|
||||
// under the terms of the GNU General Public License version 2 only, as
|
||||
// published by the Free Software Foundation.
|
||||
//
|
||||
// This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
// version 2 for more details (a copy is included in the LICENSE file that
|
||||
// accompanied this code).
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License version
|
||||
// 2 along with this work; if not, write to the Free Software Foundation,
|
||||
// Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
//
|
||||
// Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
// or visit www.oracle.com if you need additional information or have any
|
||||
// questions.
|
||||
//
|
||||
|
||||
//
|
||||
// Traverse a tree of pandoc format objects, calling callback on each
|
||||
// element, and replacing it if callback returns a new object.
|
||||
//
|
||||
// Inspired by the walk method in
|
||||
// https://github.com/jgm/pandocfilters/blob/master/pandocfilters.py
|
||||
//
|
||||
function traverse(obj, callback) {
|
||||
if (Array.isArray(obj)) {
|
||||
var processed_array = [];
|
||||
obj.forEach(function(elem) {
|
||||
if (elem === Object(elem) && elem.t) {
|
||||
var replacement = callback(elem.t, elem.c || []);
|
||||
if (!replacement) {
|
||||
// no replacement object returned, use original
|
||||
processed_array.push(traverse(elem, callback));
|
||||
} else if (Array.isArray(replacement)) {
|
||||
// array of objects returned, splice all elements into array
|
||||
replacement.forEach(function(repl_elem) {
|
||||
processed_array.push(traverse(repl_elem, callback));
|
||||
})
|
||||
} else {
|
||||
// replacement object given, traverse it
|
||||
processed_array.push(traverse(replacement, callback));
|
||||
}
|
||||
} else {
|
||||
processed_array.push(traverse(elem, callback));
|
||||
}
|
||||
})
|
||||
return processed_array;
|
||||
} else if (obj === Object(obj)) {
|
||||
if (obj.t) {
|
||||
var replacement = callback(obj.t, obj.c || []);
|
||||
if (replacement) {
|
||||
return replacement;
|
||||
}
|
||||
}
|
||||
var processed_obj = {};
|
||||
Object.keys(obj).forEach(function(key) {
|
||||
processed_obj[key] = traverse(obj[key], callback);
|
||||
})
|
||||
return processed_obj;
|
||||
} else {
|
||||
return obj;
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Helper constructors to create pandoc format objects
|
||||
//
|
||||
function Space() {
|
||||
return { 't': 'Space' };
|
||||
}
|
||||
|
||||
function Str(value) {
|
||||
return { 't': 'Str', 'c': value };
|
||||
}
|
||||
|
||||
function MetaInlines(value) {
|
||||
return { 't': 'MetaInlines', 'c': value };
|
||||
}
|
||||
|
||||
function change_title(type, value) {
|
||||
if (type === 'MetaInlines') {
|
||||
if (value[0].t === 'Str') {
|
||||
var match = value[0].c.match(/^([A-Z0-9]+)\([0-9]+\)$/);
|
||||
if (match) {
|
||||
return MetaInlines([
|
||||
Str("The"), Space(),
|
||||
Str(match[1].toLowerCase()),
|
||||
Space(), Str("Command")
|
||||
]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Main function
|
||||
//
|
||||
function main() {
|
||||
var input = "";
|
||||
while (line = readLine()) {
|
||||
input = input.concat(line);
|
||||
}
|
||||
|
||||
var json = JSON.parse(input);
|
||||
|
||||
var meta = json.meta;
|
||||
if (meta) {
|
||||
meta.date = undefined;
|
||||
var title = meta.title;
|
||||
if (meta.title) {
|
||||
meta.title = traverse(meta.title, change_title);
|
||||
}
|
||||
}
|
||||
|
||||
print(JSON.stringify(json));
|
||||
}
|
||||
|
||||
// ... and execute it
|
||||
main();
|
||||
@ -22,7 +22,7 @@
|
||||
# questions.
|
||||
#
|
||||
|
||||
# Simple wrapper script to call Nashorn with the javascript pandoc filter
|
||||
# Simple wrapper script to call Java with the pandoc filter
|
||||
|
||||
@@JJS@@ -scripting \
|
||||
"@@TOPDIR@@/make/scripts/pandoc-html-manpage-filter.js" 2> /dev/null
|
||||
@@JAVA_SMALL@@ -cp @@BUILDTOOLS_OUTPUTDIR@@/jdk_tools_classes \
|
||||
build.tools.pandocfilter.PandocManPageHtmlFilter
|
||||
|
||||
@ -1,142 +0,0 @@
|
||||
//
|
||||
// Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
|
||||
// DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
//
|
||||
// This code is free software; you can redistribute it and/or modify it
|
||||
// under the terms of the GNU General Public License version 2 only, as
|
||||
// published by the Free Software Foundation.
|
||||
//
|
||||
// This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
// version 2 for more details (a copy is included in the LICENSE file that
|
||||
// accompanied this code).
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License version
|
||||
// 2 along with this work; if not, write to the Free Software Foundation,
|
||||
// Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
//
|
||||
// Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
// or visit www.oracle.com if you need additional information or have any
|
||||
// questions.
|
||||
//
|
||||
|
||||
//
|
||||
// Traverse a tree of pandoc format objects, calling callback on each
|
||||
// element, and replacing it if callback returns a new object.
|
||||
//
|
||||
// Inspired by the walk method in
|
||||
// https://github.com/jgm/pandocfilters/blob/master/pandocfilters.py
|
||||
//
|
||||
function traverse(obj, callback) {
|
||||
if (Array.isArray(obj)) {
|
||||
var processed_array = [];
|
||||
obj.forEach(function(elem) {
|
||||
if (elem === Object(elem) && elem.t) {
|
||||
var replacement = callback(elem.t, elem.c || []);
|
||||
if (!replacement) {
|
||||
// no replacement object returned, use original
|
||||
processed_array.push(traverse(elem, callback));
|
||||
} else if (Array.isArray(replacement)) {
|
||||
// array of objects returned, splice all elements into array
|
||||
replacement.forEach(function(repl_elem) {
|
||||
processed_array.push(traverse(repl_elem, callback));
|
||||
})
|
||||
} else {
|
||||
// replacement object given, traverse it
|
||||
processed_array.push(traverse(replacement, callback));
|
||||
}
|
||||
} else {
|
||||
processed_array.push(traverse(elem, callback));
|
||||
}
|
||||
})
|
||||
return processed_array;
|
||||
} else if (obj === Object(obj)) {
|
||||
var processed_obj = {};
|
||||
Object.keys(obj).forEach(function(key) {
|
||||
processed_obj[key] = traverse(obj[key], callback);
|
||||
})
|
||||
return processed_obj;
|
||||
} else {
|
||||
return obj;
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Helper constructors to create pandoc format objects
|
||||
//
|
||||
function Space() {
|
||||
return { 't': 'Space', 'c': [] };
|
||||
}
|
||||
|
||||
function Str(value) {
|
||||
return { 't': 'Str', 'c': value };
|
||||
}
|
||||
|
||||
function Strong(value) {
|
||||
return { 't': 'Strong', 'c': value };
|
||||
}
|
||||
|
||||
function Header(value) {
|
||||
return { 't': 'Header', 'c': value };
|
||||
}
|
||||
|
||||
//
|
||||
// Callback to change all Str texts to upper case
|
||||
//
|
||||
function uppercase(type, value) {
|
||||
if (type === 'Str') {
|
||||
return Str(value.toUpperCase());
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Main callback function that performs our man page AST rewrites
|
||||
//
|
||||
function manpage_filter(type, value) {
|
||||
// If it is a header, decrease the heading level by one, and
|
||||
// if it is a level 1 header, convert it to upper case.
|
||||
if (type === 'Header') {
|
||||
value[0] = Math.max(1, value[0] - 1);
|
||||
if (value[0] == 1) {
|
||||
return Header(traverse(value, uppercase));
|
||||
}
|
||||
}
|
||||
|
||||
// Man pages does not have superscript. We use it for footnotes, so
|
||||
// enclose in [...] for best representation.
|
||||
if (type === 'Superscript') {
|
||||
return [ Str('['), value[0], Str(']') ];
|
||||
}
|
||||
|
||||
// If it is a link, put the link name in bold. If it is an external
|
||||
// link, put it in brackets. Otherwise, it is either an internal link
|
||||
// (like "#next-heading"), or a relative link to another man page
|
||||
// (like "java.html"), so remove it for man pages.
|
||||
if (type === 'Link') {
|
||||
var target = value[2][0];
|
||||
if (target.match(/^http[s]?:/)) {
|
||||
return [ Strong(value[1]), Space(), Str('[' + target + ']') ];
|
||||
} else {
|
||||
return Strong(value[1]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Main function
|
||||
//
|
||||
function main() {
|
||||
var input = "";
|
||||
while (line = readLine()) {
|
||||
input = input.concat(line);
|
||||
}
|
||||
var json = JSON.parse(input);
|
||||
|
||||
var transformed_json = traverse(json, manpage_filter);
|
||||
|
||||
print(JSON.stringify(transformed_json));
|
||||
}
|
||||
|
||||
// ... and execute it
|
||||
main();
|
||||
@ -22,7 +22,7 @@
|
||||
# questions.
|
||||
#
|
||||
|
||||
# Simple wrapper script to call Nashorn with the javascript pandoc filter
|
||||
# Simple wrapper script to call Java with the pandoc filter
|
||||
|
||||
@@JJS@@ -scripting \
|
||||
"@@TOPDIR@@/make/scripts/pandoc-troff-manpage-filter.js" 2> /dev/null
|
||||
@@JAVA_SMALL@@ -cp @@BUILDTOOLS_OUTPUTDIR@@/jdk_tools_classes \
|
||||
build.tools.pandocfilter.PandocManPageTroffFilter
|
||||
|
||||
@ -404,7 +404,8 @@ public class GenerateJfrFiles {
|
||||
out.write(" jlong cutoff_ticks;");
|
||||
out.write(" u1 stacktrace;");
|
||||
out.write(" u1 enabled;");
|
||||
out.write(" u1 pad[6]; // Because GCC on linux ia32 at least tries to pack this.");
|
||||
out.write(" u1 large;");
|
||||
out.write(" u1 pad[5]; // Because GCC on linux ia32 at least tries to pack this.");
|
||||
out.write("};");
|
||||
out.write("");
|
||||
out.write("union JfrNativeSettings {");
|
||||
|
||||
@ -13108,6 +13108,40 @@ instruct negD_reg_reg(vRegD dst, vRegD src) %{
|
||||
ins_pipe(fp_uop_d);
|
||||
%}
|
||||
|
||||
instruct absI_reg(iRegINoSp dst, iRegIorL2I src, rFlagsReg cr)
|
||||
%{
|
||||
match(Set dst (AbsI src));
|
||||
|
||||
effect(KILL cr);
|
||||
ins_cost(INSN_COST * 2);
|
||||
format %{ "cmpw $src, zr\n\t"
|
||||
"cnegw $dst, $src, Assembler::LT\t# int abs"
|
||||
%}
|
||||
|
||||
ins_encode %{
|
||||
__ cmpw(as_Register($src$$reg), zr);
|
||||
__ cnegw(as_Register($dst$$reg), as_Register($src$$reg), Assembler::LT);
|
||||
%}
|
||||
ins_pipe(pipe_class_default);
|
||||
%}
|
||||
|
||||
instruct absL_reg(iRegLNoSp dst, iRegL src, rFlagsReg cr)
|
||||
%{
|
||||
match(Set dst (AbsL src));
|
||||
|
||||
effect(KILL cr);
|
||||
ins_cost(INSN_COST * 2);
|
||||
format %{ "cmp $src, zr\n\t"
|
||||
"cneg $dst, $src, Assembler::LT\t# long abs"
|
||||
%}
|
||||
|
||||
ins_encode %{
|
||||
__ cmp(as_Register($src$$reg), zr);
|
||||
__ cneg(as_Register($dst$$reg), as_Register($src$$reg), Assembler::LT);
|
||||
%}
|
||||
ins_pipe(pipe_class_default);
|
||||
%}
|
||||
|
||||
instruct absF_reg(vRegF dst, vRegF src) %{
|
||||
match(Set dst (AbsF src));
|
||||
|
||||
@ -16998,6 +17032,91 @@ instruct vsqrt2D(vecX dst, vecX src)
|
||||
|
||||
// --------------------------------- ABS --------------------------------------
|
||||
|
||||
instruct vabs8B(vecD dst, vecD src)
|
||||
%{
|
||||
predicate(n->as_Vector()->length() == 4 ||
|
||||
n->as_Vector()->length() == 8);
|
||||
match(Set dst (AbsVB src));
|
||||
ins_cost(INSN_COST);
|
||||
format %{ "abs $dst, $src\t# vector (8B)" %}
|
||||
ins_encode %{
|
||||
__ absr(as_FloatRegister($dst$$reg), __ T8B, as_FloatRegister($src$$reg));
|
||||
%}
|
||||
ins_pipe(vlogical64);
|
||||
%}
|
||||
|
||||
instruct vabs16B(vecX dst, vecX src)
|
||||
%{
|
||||
predicate(n->as_Vector()->length() == 16);
|
||||
match(Set dst (AbsVB src));
|
||||
ins_cost(INSN_COST);
|
||||
format %{ "abs $dst, $src\t# vector (16B)" %}
|
||||
ins_encode %{
|
||||
__ absr(as_FloatRegister($dst$$reg), __ T16B, as_FloatRegister($src$$reg));
|
||||
%}
|
||||
ins_pipe(vlogical128);
|
||||
%}
|
||||
|
||||
instruct vabs4S(vecD dst, vecD src)
|
||||
%{
|
||||
predicate(n->as_Vector()->length() == 4);
|
||||
match(Set dst (AbsVS src));
|
||||
ins_cost(INSN_COST);
|
||||
format %{ "abs $dst, $src\t# vector (4H)" %}
|
||||
ins_encode %{
|
||||
__ absr(as_FloatRegister($dst$$reg), __ T4H, as_FloatRegister($src$$reg));
|
||||
%}
|
||||
ins_pipe(vlogical64);
|
||||
%}
|
||||
|
||||
instruct vabs8S(vecX dst, vecX src)
|
||||
%{
|
||||
predicate(n->as_Vector()->length() == 8);
|
||||
match(Set dst (AbsVS src));
|
||||
ins_cost(INSN_COST);
|
||||
format %{ "abs $dst, $src\t# vector (8H)" %}
|
||||
ins_encode %{
|
||||
__ absr(as_FloatRegister($dst$$reg), __ T8H, as_FloatRegister($src$$reg));
|
||||
%}
|
||||
ins_pipe(vlogical128);
|
||||
%}
|
||||
|
||||
instruct vabs2I(vecD dst, vecD src)
|
||||
%{
|
||||
predicate(n->as_Vector()->length() == 2);
|
||||
match(Set dst (AbsVI src));
|
||||
ins_cost(INSN_COST);
|
||||
format %{ "abs $dst, $src\t# vector (2S)" %}
|
||||
ins_encode %{
|
||||
__ absr(as_FloatRegister($dst$$reg), __ T2S, as_FloatRegister($src$$reg));
|
||||
%}
|
||||
ins_pipe(vlogical64);
|
||||
%}
|
||||
|
||||
instruct vabs4I(vecX dst, vecX src)
|
||||
%{
|
||||
predicate(n->as_Vector()->length() == 4);
|
||||
match(Set dst (AbsVI src));
|
||||
ins_cost(INSN_COST);
|
||||
format %{ "abs $dst, $src\t# vector (4S)" %}
|
||||
ins_encode %{
|
||||
__ absr(as_FloatRegister($dst$$reg), __ T4S, as_FloatRegister($src$$reg));
|
||||
%}
|
||||
ins_pipe(vlogical128);
|
||||
%}
|
||||
|
||||
instruct vabs2L(vecX dst, vecX src)
|
||||
%{
|
||||
predicate(n->as_Vector()->length() == 2);
|
||||
match(Set dst (AbsVL src));
|
||||
ins_cost(INSN_COST);
|
||||
format %{ "abs $dst, $src\t# vector (2D)" %}
|
||||
ins_encode %{
|
||||
__ absr(as_FloatRegister($dst$$reg), __ T2D, as_FloatRegister($src$$reg));
|
||||
%}
|
||||
ins_pipe(vlogical128);
|
||||
%}
|
||||
|
||||
instruct vabs2F(vecD dst, vecD src)
|
||||
%{
|
||||
predicate(n->as_Vector()->length() == 2);
|
||||
|
||||
@ -2278,12 +2278,12 @@ public:
|
||||
rf(Vn, 5), rf(Vd, 0); \
|
||||
}
|
||||
|
||||
INSN(absr, 0, 0b100000101110, 1); // accepted arrangements: T8B, T16B, T4H, T8H, T4S
|
||||
INSN(absr, 0, 0b100000101110, 3); // accepted arrangements: T8B, T16B, T4H, T8H, T2S, T4S, T2D
|
||||
INSN(negr, 1, 0b100000101110, 3); // accepted arrangements: T8B, T16B, T4H, T8H, T2S, T4S, T2D
|
||||
INSN(notr, 1, 0b100000010110, 0); // accepted arrangements: T8B, T16B
|
||||
INSN(addv, 0, 0b110001101110, 1); // accepted arrangements: T8B, T16B, T4H, T8H, T4S
|
||||
INSN(cls, 0, 0b100000010010, 1); // accepted arrangements: T8B, T16B, T4H, T8H, T4S
|
||||
INSN(clz, 1, 0b100000010010, 1); // accepted arrangements: T8B, T16B, T4H, T8H, T4S
|
||||
INSN(cls, 0, 0b100000010010, 2); // accepted arrangements: T8B, T16B, T4H, T8H, T2S, T4S
|
||||
INSN(clz, 1, 0b100000010010, 2); // accepted arrangements: T8B, T16B, T4H, T8H, T2S, T4S
|
||||
INSN(cnt, 0, 0b100000010110, 0); // accepted arrangements: T8B, T16B
|
||||
INSN(uaddlp, 1, 0b100000001010, 2); // accepted arrangements: T8B, T16B, T4H, T8H, T2S, T4S
|
||||
INSN(uaddlv, 1, 0b110000001110, 1); // accepted arrangements: T8B, T16B, T4H, T8H, T4S
|
||||
|
||||
@ -459,7 +459,7 @@ void LIRGenerator::do_ArithmeticOp_Long(ArithmeticOp* x) {
|
||||
if (need_zero_check) {
|
||||
CodeEmitInfo* info = state_for(x);
|
||||
__ cmp(lir_cond_equal, right.result(), LIR_OprFact::longConst(0));
|
||||
__ branch(lir_cond_equal, T_LONG, new DivByZeroStub(info));
|
||||
__ branch(lir_cond_equal, new DivByZeroStub(info));
|
||||
}
|
||||
|
||||
rlock_result(x);
|
||||
@ -534,7 +534,7 @@ void LIRGenerator::do_ArithmeticOp_Int(ArithmeticOp* x) {
|
||||
if (need_zero_check) {
|
||||
CodeEmitInfo* info = state_for(x);
|
||||
__ cmp(lir_cond_equal, right_arg->result(), LIR_OprFact::longConst(0));
|
||||
__ branch(lir_cond_equal, T_INT, new DivByZeroStub(info));
|
||||
__ branch(lir_cond_equal, new DivByZeroStub(info));
|
||||
}
|
||||
|
||||
LIR_Opr ill = LIR_OprFact::illegalOpr;
|
||||
@ -1384,9 +1384,9 @@ void LIRGenerator::do_If(If* x) {
|
||||
profile_branch(x, cond);
|
||||
move_to_phi(x->state());
|
||||
if (x->x()->type()->is_float_kind()) {
|
||||
__ branch(lir_cond(cond), right->type(), x->tsux(), x->usux());
|
||||
__ branch(lir_cond(cond), x->tsux(), x->usux());
|
||||
} else {
|
||||
__ branch(lir_cond(cond), right->type(), x->tsux());
|
||||
__ branch(lir_cond(cond), x->tsux());
|
||||
}
|
||||
assert(x->default_sux() == x->fsux(), "wrong destination above");
|
||||
__ jump(x->default_sux());
|
||||
|
||||
@ -8963,7 +8963,7 @@ instruct ShouldNotReachHere( )
|
||||
format %{ "ShouldNotReachHere" %}
|
||||
ins_encode %{
|
||||
if (is_reachable()) {
|
||||
__ udf(0xdead);
|
||||
__ stop(_halt_reason);
|
||||
}
|
||||
%}
|
||||
ins_pipe(tail_call);
|
||||
|
||||
@ -390,7 +390,7 @@ void LIRGenerator::CardTableBarrierSet_post_barrier_helper(LIR_OprDesc* addr, LI
|
||||
|
||||
LabelObj* L_already_dirty = new LabelObj();
|
||||
__ cmp(lir_cond_equal, cur_value, LIR_OprFact::intConst(CardTable::dirty_card_val()));
|
||||
__ branch(lir_cond_equal, T_BYTE, L_already_dirty->label());
|
||||
__ branch(lir_cond_equal, L_already_dirty->label());
|
||||
set_card(tmp, card_addr);
|
||||
__ branch_destination(L_already_dirty->label());
|
||||
} else {
|
||||
@ -539,7 +539,7 @@ void LIRGenerator::do_ArithmeticOp_FPU(ArithmeticOp* x) {
|
||||
void LIRGenerator::make_div_by_zero_check(LIR_Opr right_arg, BasicType type, CodeEmitInfo* info) {
|
||||
assert(right_arg->is_register(), "must be");
|
||||
__ cmp(lir_cond_equal, right_arg, make_constant(type, 0));
|
||||
__ branch(lir_cond_equal, type, new DivByZeroStub(info));
|
||||
__ branch(lir_cond_equal, new DivByZeroStub(info));
|
||||
}
|
||||
|
||||
|
||||
@ -1227,7 +1227,7 @@ void LIRGenerator::do_soft_float_compare(If* x) {
|
||||
LIR_OprFact::intConst(0) : LIR_OprFact::intConst(1));
|
||||
profile_branch(x, cond);
|
||||
move_to_phi(x->state());
|
||||
__ branch(lir_cond_equal, T_INT, x->tsux());
|
||||
__ branch(lir_cond_equal, x->tsux());
|
||||
}
|
||||
#endif // __SOFTFP__
|
||||
|
||||
@ -1285,9 +1285,9 @@ void LIRGenerator::do_If(If* x) {
|
||||
profile_branch(x, cond);
|
||||
move_to_phi(x->state());
|
||||
if (x->x()->type()->is_float_kind()) {
|
||||
__ branch(lir_cond(cond), right->type(), x->tsux(), x->usux());
|
||||
__ branch(lir_cond(cond), x->tsux(), x->usux());
|
||||
} else {
|
||||
__ branch(lir_cond(cond), right->type(), x->tsux());
|
||||
__ branch(lir_cond(cond), x->tsux());
|
||||
}
|
||||
assert(x->default_sux() == x->fsux(), "wrong destination above");
|
||||
__ jump(x->default_sux());
|
||||
|
||||
@ -440,7 +440,7 @@ void LIRGenerator::do_ArithmeticOp_Long(ArithmeticOp* x) {
|
||||
if (divisor->is_register()) {
|
||||
CodeEmitInfo* null_check_info = state_for(x);
|
||||
__ cmp(lir_cond_equal, divisor, LIR_OprFact::longConst(0));
|
||||
__ branch(lir_cond_equal, T_LONG, new DivByZeroStub(null_check_info));
|
||||
__ branch(lir_cond_equal, new DivByZeroStub(null_check_info));
|
||||
} else {
|
||||
jlong const_divisor = divisor->as_constant_ptr()->as_jlong();
|
||||
if (const_divisor == 0) {
|
||||
@ -494,7 +494,7 @@ void LIRGenerator::do_ArithmeticOp_Int(ArithmeticOp* x) {
|
||||
if (divisor->is_register()) {
|
||||
CodeEmitInfo* null_check_info = state_for(x);
|
||||
__ cmp(lir_cond_equal, divisor, LIR_OprFact::intConst(0));
|
||||
__ branch(lir_cond_equal, T_INT, new DivByZeroStub(null_check_info));
|
||||
__ branch(lir_cond_equal, new DivByZeroStub(null_check_info));
|
||||
} else {
|
||||
jint const_divisor = divisor->as_constant_ptr()->as_jint();
|
||||
if (const_divisor == 0) {
|
||||
@ -1171,9 +1171,9 @@ void LIRGenerator::do_If(If* x) {
|
||||
profile_branch(x, cond);
|
||||
move_to_phi(x->state());
|
||||
if (x->x()->type()->is_float_kind()) {
|
||||
__ branch(lir_cond(cond), right->type(), x->tsux(), x->usux());
|
||||
__ branch(lir_cond(cond), x->tsux(), x->usux());
|
||||
} else {
|
||||
__ branch(lir_cond(cond), right->type(), x->tsux());
|
||||
__ branch(lir_cond(cond), x->tsux());
|
||||
}
|
||||
assert(x->default_sux() == x->fsux(), "wrong destination above");
|
||||
__ jump(x->default_sux());
|
||||
|
||||
@ -192,7 +192,10 @@ void Disassembler::annotate(address here, outputStream* st) {
|
||||
st->fill_to(aligned_pos + tabspacing);
|
||||
st->print(";trap: ic miss check");
|
||||
} else if ((stop_type = MacroAssembler::tdi_get_si16(instruction, Assembler::traptoUnconditional, 0)) != -1) {
|
||||
bool msg_present = (stop_type & MacroAssembler::stop_msg_present);
|
||||
stop_type = (stop_type &~ MacroAssembler::stop_msg_present);
|
||||
const char **detail_msg_ptr = (const char**)(here + 4);
|
||||
st->fill_to(aligned_pos + tabspacing);
|
||||
st->print(";trap: stop type %d", stop_type);
|
||||
st->print(";trap: stop type %d: %s", stop_type, msg_present ? *detail_msg_ptr : "no details provided");
|
||||
}
|
||||
}
|
||||
|
||||
@ -4432,17 +4432,21 @@ void MacroAssembler::verify_oop_addr(RegisterOrConstant offs, Register base, con
|
||||
|
||||
// Call a C-function that prints output.
|
||||
void MacroAssembler::stop(int type, const char* msg) {
|
||||
bool msg_present = (msg != NULL);
|
||||
|
||||
#ifndef PRODUCT
|
||||
block_comment(err_msg("stop(type %d): %s {", type, msg));
|
||||
block_comment(err_msg("stop(type %d): %s {", type, msg_present ? msg : "null"));
|
||||
#else
|
||||
block_comment("stop {");
|
||||
#endif
|
||||
|
||||
if (type != stop_shouldnotreachhere) {
|
||||
// Use R0 to pass msg. "shouldnotreachhere" preserves R0.
|
||||
load_const_optimized(R0, (void*)msg);
|
||||
if (msg_present) {
|
||||
type |= stop_msg_present;
|
||||
}
|
||||
tdi_unchecked(traptoUnconditional, 0/*reg 0*/, type);
|
||||
if (msg_present) {
|
||||
emit_int64((uintptr_t)msg);
|
||||
}
|
||||
|
||||
block_comment("} stop;");
|
||||
}
|
||||
|
||||
@ -901,17 +901,18 @@ class MacroAssembler: public Assembler {
|
||||
|
||||
public:
|
||||
enum {
|
||||
stop_stop = 0,
|
||||
stop_untested = 1,
|
||||
stop_unimplemented = 2,
|
||||
stop_shouldnotreachhere = 3
|
||||
stop_stop = 0,
|
||||
stop_untested = 1,
|
||||
stop_unimplemented = 2,
|
||||
stop_shouldnotreachhere = 3,
|
||||
stop_msg_present = -0x8000
|
||||
};
|
||||
|
||||
// Prints msg, dumps registers and stops execution.
|
||||
void stop (const char* msg = NULL) { stop(stop_stop, msg ); }
|
||||
void untested (const char* msg = NULL) { stop(stop_untested, msg ); }
|
||||
void unimplemented(const char* msg = NULL) { stop(stop_unimplemented, msg ); }
|
||||
void should_not_reach_here() { stop(stop_shouldnotreachhere, NULL); }
|
||||
void stop (const char* msg = NULL) { stop(stop_stop, msg); }
|
||||
void untested (const char* msg = NULL) { stop(stop_untested, msg); }
|
||||
void unimplemented (const char* msg = NULL) { stop(stop_unimplemented, msg); }
|
||||
void should_not_reach_here(const char* msg = NULL) { stop(stop_shouldnotreachhere, msg); }
|
||||
|
||||
void zap_from_to(Register low, int before, Register high, int after, Register val, Register addr) PRODUCT_RETURN;
|
||||
};
|
||||
|
||||
@ -15196,7 +15196,7 @@ instruct ShouldNotReachHere() %{
|
||||
ins_encode %{
|
||||
if (is_reachable()) {
|
||||
// TODO: PPC port $archOpcode(ppc64Opcode_tdi);
|
||||
__ should_not_reach_here();
|
||||
__ stop(_halt_reason);
|
||||
}
|
||||
%}
|
||||
ins_pipe(pipe_class_default);
|
||||
|
||||
@ -385,7 +385,7 @@ void LIRGenerator::do_ArithmeticOp_Long(ArithmeticOp* x) {
|
||||
|
||||
if (!ImplicitDiv0Checks) {
|
||||
__ cmp(lir_cond_equal, right.result(), LIR_OprFact::longConst(0));
|
||||
__ branch(lir_cond_equal, T_LONG, new DivByZeroStub(info));
|
||||
__ branch(lir_cond_equal, new DivByZeroStub(info));
|
||||
// Idiv/irem cannot trap (passing info would generate an assertion).
|
||||
info = NULL;
|
||||
}
|
||||
@ -461,7 +461,7 @@ void LIRGenerator::do_ArithmeticOp_Int(ArithmeticOp* x) {
|
||||
|
||||
if (!ImplicitDiv0Checks) {
|
||||
__ cmp(lir_cond_equal, right.result(), LIR_OprFact::intConst(0));
|
||||
__ branch(lir_cond_equal, T_INT, new DivByZeroStub(info));
|
||||
__ branch(lir_cond_equal, new DivByZeroStub(info));
|
||||
// Idiv/irem cannot trap (passing info would generate an assertion).
|
||||
info = NULL;
|
||||
}
|
||||
@ -988,9 +988,9 @@ void LIRGenerator::do_If (If* x) {
|
||||
profile_branch(x, cond);
|
||||
move_to_phi(x->state());
|
||||
if (x->x()->type()->is_float_kind()) {
|
||||
__ branch(lir_cond(cond), right->type(), x->tsux(), x->usux());
|
||||
__ branch(lir_cond(cond), x->tsux(), x->usux());
|
||||
} else {
|
||||
__ branch(lir_cond(cond), right->type(), x->tsux());
|
||||
__ branch(lir_cond(cond), x->tsux());
|
||||
}
|
||||
assert(x->default_sux() == x->fsux(), "wrong destination above");
|
||||
__ jump(x->default_sux());
|
||||
|
||||
@ -9889,7 +9889,7 @@ instruct ShouldNotReachHere() %{
|
||||
format %{ "ILLTRAP; ShouldNotReachHere" %}
|
||||
ins_encode %{
|
||||
if (is_reachable()) {
|
||||
__ z_illtrap();
|
||||
__ stop(_halt_reason);
|
||||
}
|
||||
%}
|
||||
ins_pipe(pipe_class_dummy);
|
||||
|
||||
@ -6241,6 +6241,17 @@ void Assembler::vpternlogd(XMMRegister dst, int imm8, XMMRegister src2, Address
|
||||
emit_int8(imm8);
|
||||
}
|
||||
|
||||
void Assembler::vpternlogq(XMMRegister dst, int imm8, XMMRegister src2, XMMRegister src3, int vector_len) {
|
||||
assert(VM_Version::supports_evex(), "requires EVEX support");
|
||||
assert(vector_len == Assembler::AVX_512bit || VM_Version::supports_avx512vl(), "requires VL support");
|
||||
InstructionAttr attributes(vector_len, /* vex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ true);
|
||||
attributes.set_is_evex_instruction();
|
||||
int encode = vex_prefix_and_encode(dst->encoding(), src2->encoding(), src3->encoding(), VEX_SIMD_66, VEX_OPCODE_0F_3A, &attributes);
|
||||
emit_int8(0x25);
|
||||
emit_int8((unsigned char)(0xC0 | encode));
|
||||
emit_int8(imm8);
|
||||
}
|
||||
|
||||
// vinserti forms
|
||||
|
||||
void Assembler::vinserti128(XMMRegister dst, XMMRegister nds, XMMRegister src, uint8_t imm8) {
|
||||
@ -6693,6 +6704,21 @@ void Assembler::vpbroadcastq(XMMRegister dst, Address src, int vector_len) {
|
||||
emit_int8(0x59);
|
||||
emit_operand(dst, src);
|
||||
}
|
||||
|
||||
void Assembler::evbroadcasti32x4(XMMRegister dst, Address src, int vector_len) {
|
||||
assert(vector_len != Assembler::AVX_128bit, "");
|
||||
assert(VM_Version::supports_avx512dq(), "");
|
||||
assert(dst != xnoreg, "sanity");
|
||||
InstructionMark im(this);
|
||||
InstructionAttr attributes(vector_len, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ true);
|
||||
attributes.set_rex_vex_w_reverted();
|
||||
attributes.set_address_attributes(/* tuple_type */ EVEX_T2, /* input_size_in_bits */ EVEX_64bit);
|
||||
// swap src<->dst for encoding
|
||||
vex_prefix(src, 0, dst->encoding(), VEX_SIMD_66, VEX_OPCODE_0F_38, &attributes);
|
||||
emit_int8(0x5A);
|
||||
emit_operand(dst, src);
|
||||
}
|
||||
|
||||
void Assembler::evbroadcasti64x2(XMMRegister dst, XMMRegister src, int vector_len) {
|
||||
assert(vector_len != Assembler::AVX_128bit, "");
|
||||
assert(VM_Version::supports_avx512dq(), "");
|
||||
@ -7587,6 +7613,15 @@ void Assembler::cmppd(XMMRegister dst, XMMRegister nds, XMMRegister src, int cop
|
||||
emit_int24((unsigned char)0xC2, (0xC0 | encode), (0xF & cop));
|
||||
}
|
||||
|
||||
void Assembler::blendvpb(XMMRegister dst, XMMRegister nds, XMMRegister src1, XMMRegister src2, int vector_len) {
|
||||
assert(VM_Version::supports_avx(), "");
|
||||
assert(vector_len <= AVX_256bit, "");
|
||||
InstructionAttr attributes(vector_len, /* vex_w */ false, /* legacy_mode */ true, /* no_mask_reg */ true, /* uses_vl */ true);
|
||||
int encode = vex_prefix_and_encode(dst->encoding(), nds->encoding(), src1->encoding(), VEX_SIMD_66, VEX_OPCODE_0F_3A, &attributes);
|
||||
int src2_enc = src2->encoding();
|
||||
emit_int24(0x4C, (0xC0 | encode), (0xF0 & src2_enc << 4));
|
||||
}
|
||||
|
||||
void Assembler::blendvpd(XMMRegister dst, XMMRegister nds, XMMRegister src1, XMMRegister src2, int vector_len) {
|
||||
assert(VM_Version::supports_avx(), "");
|
||||
assert(vector_len <= AVX_256bit, "");
|
||||
|
||||
@ -2201,6 +2201,7 @@ private:
|
||||
// Ternary logic instruction.
|
||||
void vpternlogd(XMMRegister dst, int imm8, XMMRegister src2, XMMRegister src3, int vector_len);
|
||||
void vpternlogd(XMMRegister dst, int imm8, XMMRegister src2, Address src3, int vector_len);
|
||||
void vpternlogq(XMMRegister dst, int imm8, XMMRegister src2, XMMRegister src3, int vector_len);
|
||||
|
||||
// vinserti forms
|
||||
void vinserti128(XMMRegister dst, XMMRegister nds, XMMRegister src, uint8_t imm8);
|
||||
@ -2245,6 +2246,7 @@ private:
|
||||
void vpbroadcastq(XMMRegister dst, XMMRegister src, int vector_len);
|
||||
void vpbroadcastq(XMMRegister dst, Address src, int vector_len);
|
||||
|
||||
void evbroadcasti32x4(XMMRegister dst, Address src, int vector_len);
|
||||
void evbroadcasti64x2(XMMRegister dst, XMMRegister src, int vector_len);
|
||||
void evbroadcasti64x2(XMMRegister dst, Address src, int vector_len);
|
||||
|
||||
@ -2274,6 +2276,7 @@ private:
|
||||
void vzeroupper();
|
||||
|
||||
// AVX support for vectorized conditional move (float/double). The following two instructions used only coupled.
|
||||
void blendvpb(XMMRegister dst, XMMRegister nds, XMMRegister src1, XMMRegister src2, int vector_len);
|
||||
void cmppd(XMMRegister dst, XMMRegister nds, XMMRegister src, int cop, int vector_len);
|
||||
void blendvpd(XMMRegister dst, XMMRegister nds, XMMRegister src1, XMMRegister src2, int vector_len);
|
||||
void cmpps(XMMRegister dst, XMMRegister nds, XMMRegister src, int cop, int vector_len);
|
||||
|
||||
@ -481,7 +481,7 @@ void LIRGenerator::do_ArithmeticOp_Long(ArithmeticOp* x) {
|
||||
__ move(right.result(), cc->at(0));
|
||||
|
||||
__ cmp(lir_cond_equal, right.result(), LIR_OprFact::longConst(0));
|
||||
__ branch(lir_cond_equal, T_LONG, new DivByZeroStub(info));
|
||||
__ branch(lir_cond_equal, new DivByZeroStub(info));
|
||||
|
||||
address entry = NULL;
|
||||
switch (x->op()) {
|
||||
@ -565,7 +565,7 @@ void LIRGenerator::do_ArithmeticOp_Int(ArithmeticOp* x) {
|
||||
|
||||
if (!ImplicitDiv0Checks) {
|
||||
__ cmp(lir_cond_equal, right.result(), LIR_OprFact::intConst(0));
|
||||
__ branch(lir_cond_equal, T_INT, new DivByZeroStub(info));
|
||||
__ branch(lir_cond_equal, new DivByZeroStub(info));
|
||||
// Idiv/irem cannot trap (passing info would generate an assertion).
|
||||
info = NULL;
|
||||
}
|
||||
@ -1503,9 +1503,9 @@ void LIRGenerator::do_If(If* x) {
|
||||
profile_branch(x, cond);
|
||||
move_to_phi(x->state());
|
||||
if (x->x()->type()->is_float_kind()) {
|
||||
__ branch(lir_cond(cond), right->type(), x->tsux(), x->usux());
|
||||
__ branch(lir_cond(cond), x->tsux(), x->usux());
|
||||
} else {
|
||||
__ branch(lir_cond(cond), right->type(), x->tsux());
|
||||
__ branch(lir_cond(cond), x->tsux());
|
||||
}
|
||||
assert(x->default_sux() == x->fsux(), "wrong destination above");
|
||||
__ jump(x->default_sux());
|
||||
|
||||
@ -6479,16 +6479,6 @@ void MacroAssembler::update_byte_crc32(Register crc, Register val, Register tabl
|
||||
xorl(crc, Address(table, val, Address::times_4, 0));
|
||||
}
|
||||
|
||||
/**
|
||||
* Fold four 128-bit data chunks
|
||||
*/
|
||||
void MacroAssembler::fold_128bit_crc32_avx512(XMMRegister xcrc, XMMRegister xK, XMMRegister xtmp, Register buf, int offset) {
|
||||
evpclmulhdq(xtmp, xK, xcrc, Assembler::AVX_512bit); // [123:64]
|
||||
evpclmulldq(xcrc, xK, xcrc, Assembler::AVX_512bit); // [63:0]
|
||||
evpxorq(xcrc, xcrc, Address(buf, offset), Assembler::AVX_512bit /* vector_len */);
|
||||
evpxorq(xcrc, xcrc, xtmp, Assembler::AVX_512bit /* vector_len */);
|
||||
}
|
||||
|
||||
/**
|
||||
* Fold 128-bit data chunk
|
||||
*/
|
||||
@ -6692,6 +6682,372 @@ void MacroAssembler::kernel_crc32(Register crc, Register buf, Register len, Regi
|
||||
}
|
||||
|
||||
#ifdef _LP64
|
||||
// Helper function for AVX 512 CRC32
|
||||
// Fold 512-bit data chunks
|
||||
void MacroAssembler::fold512bit_crc32_avx512(XMMRegister xcrc, XMMRegister xK, XMMRegister xtmp, Register buf,
|
||||
Register pos, int offset) {
|
||||
evmovdquq(xmm3, Address(buf, pos, Address::times_1, offset), Assembler::AVX_512bit);
|
||||
evpclmulqdq(xtmp, xcrc, xK, 0x10, Assembler::AVX_512bit); // [123:64]
|
||||
evpclmulqdq(xmm2, xcrc, xK, 0x01, Assembler::AVX_512bit); // [63:0]
|
||||
evpxorq(xcrc, xtmp, xmm2, Assembler::AVX_512bit /* vector_len */);
|
||||
evpxorq(xcrc, xcrc, xmm3, Assembler::AVX_512bit /* vector_len */);
|
||||
}
|
||||
|
||||
// Helper function for AVX 512 CRC32
|
||||
// Compute CRC32 for < 256B buffers
|
||||
void MacroAssembler::kernel_crc32_avx512_256B(Register crc, Register buf, Register len, Register key, Register pos,
|
||||
Register tmp1, Register tmp2, Label& L_barrett, Label& L_16B_reduction_loop,
|
||||
Label& L_get_last_two_xmms, Label& L_128_done, Label& L_cleanup) {
|
||||
|
||||
Label L_less_than_32, L_exact_16_left, L_less_than_16_left;
|
||||
Label L_less_than_8_left, L_less_than_4_left, L_less_than_2_left, L_zero_left;
|
||||
Label L_only_less_than_4, L_only_less_than_3, L_only_less_than_2;
|
||||
|
||||
// check if there is enough buffer to be able to fold 16B at a time
|
||||
cmpl(len, 32);
|
||||
jcc(Assembler::less, L_less_than_32);
|
||||
|
||||
// if there is, load the constants
|
||||
movdqu(xmm10, Address(key, 1 * 16)); //rk1 and rk2 in xmm10
|
||||
movdl(xmm0, crc); // get the initial crc value
|
||||
movdqu(xmm7, Address(buf, pos, Address::times_1, 0 * 16)); //load the plaintext
|
||||
pxor(xmm7, xmm0);
|
||||
|
||||
// update the buffer pointer
|
||||
addl(pos, 16);
|
||||
//update the counter.subtract 32 instead of 16 to save one instruction from the loop
|
||||
subl(len, 32);
|
||||
jmp(L_16B_reduction_loop);
|
||||
|
||||
bind(L_less_than_32);
|
||||
//mov initial crc to the return value. this is necessary for zero - length buffers.
|
||||
movl(rax, crc);
|
||||
testl(len, len);
|
||||
jcc(Assembler::equal, L_cleanup);
|
||||
|
||||
movdl(xmm0, crc); //get the initial crc value
|
||||
|
||||
cmpl(len, 16);
|
||||
jcc(Assembler::equal, L_exact_16_left);
|
||||
jcc(Assembler::less, L_less_than_16_left);
|
||||
|
||||
movdqu(xmm7, Address(buf, pos, Address::times_1, 0 * 16)); //load the plaintext
|
||||
pxor(xmm7, xmm0); //xor the initial crc value
|
||||
addl(pos, 16);
|
||||
subl(len, 16);
|
||||
movdqu(xmm10, Address(key, 1 * 16)); // rk1 and rk2 in xmm10
|
||||
jmp(L_get_last_two_xmms);
|
||||
|
||||
bind(L_less_than_16_left);
|
||||
//use stack space to load data less than 16 bytes, zero - out the 16B in memory first.
|
||||
pxor(xmm1, xmm1);
|
||||
movptr(tmp1, rsp);
|
||||
movdqu(Address(tmp1, 0 * 16), xmm1);
|
||||
|
||||
cmpl(len, 4);
|
||||
jcc(Assembler::less, L_only_less_than_4);
|
||||
|
||||
//backup the counter value
|
||||
movl(tmp2, len);
|
||||
cmpl(len, 8);
|
||||
jcc(Assembler::less, L_less_than_8_left);
|
||||
|
||||
//load 8 Bytes
|
||||
movq(rax, Address(buf, pos, Address::times_1, 0 * 16));
|
||||
movq(Address(tmp1, 0 * 16), rax);
|
||||
addptr(tmp1, 8);
|
||||
subl(len, 8);
|
||||
addl(pos, 8);
|
||||
|
||||
bind(L_less_than_8_left);
|
||||
cmpl(len, 4);
|
||||
jcc(Assembler::less, L_less_than_4_left);
|
||||
|
||||
//load 4 Bytes
|
||||
movl(rax, Address(buf, pos, Address::times_1, 0));
|
||||
movl(Address(tmp1, 0 * 16), rax);
|
||||
addptr(tmp1, 4);
|
||||
subl(len, 4);
|
||||
addl(pos, 4);
|
||||
|
||||
bind(L_less_than_4_left);
|
||||
cmpl(len, 2);
|
||||
jcc(Assembler::less, L_less_than_2_left);
|
||||
|
||||
// load 2 Bytes
|
||||
movw(rax, Address(buf, pos, Address::times_1, 0));
|
||||
movl(Address(tmp1, 0 * 16), rax);
|
||||
addptr(tmp1, 2);
|
||||
subl(len, 2);
|
||||
addl(pos, 2);
|
||||
|
||||
bind(L_less_than_2_left);
|
||||
cmpl(len, 1);
|
||||
jcc(Assembler::less, L_zero_left);
|
||||
|
||||
// load 1 Byte
|
||||
movb(rax, Address(buf, pos, Address::times_1, 0));
|
||||
movb(Address(tmp1, 0 * 16), rax);
|
||||
|
||||
bind(L_zero_left);
|
||||
movdqu(xmm7, Address(rsp, 0));
|
||||
pxor(xmm7, xmm0); //xor the initial crc value
|
||||
|
||||
lea(rax, ExternalAddress(StubRoutines::x86::shuf_table_crc32_avx512_addr()));
|
||||
movdqu(xmm0, Address(rax, tmp2));
|
||||
pshufb(xmm7, xmm0);
|
||||
jmp(L_128_done);
|
||||
|
||||
bind(L_exact_16_left);
|
||||
movdqu(xmm7, Address(buf, pos, Address::times_1, 0));
|
||||
pxor(xmm7, xmm0); //xor the initial crc value
|
||||
jmp(L_128_done);
|
||||
|
||||
bind(L_only_less_than_4);
|
||||
cmpl(len, 3);
|
||||
jcc(Assembler::less, L_only_less_than_3);
|
||||
|
||||
// load 3 Bytes
|
||||
movb(rax, Address(buf, pos, Address::times_1, 0));
|
||||
movb(Address(tmp1, 0), rax);
|
||||
|
||||
movb(rax, Address(buf, pos, Address::times_1, 1));
|
||||
movb(Address(tmp1, 1), rax);
|
||||
|
||||
movb(rax, Address(buf, pos, Address::times_1, 2));
|
||||
movb(Address(tmp1, 2), rax);
|
||||
|
||||
movdqu(xmm7, Address(rsp, 0));
|
||||
pxor(xmm7, xmm0); //xor the initial crc value
|
||||
|
||||
pslldq(xmm7, 0x5);
|
||||
jmp(L_barrett);
|
||||
bind(L_only_less_than_3);
|
||||
cmpl(len, 2);
|
||||
jcc(Assembler::less, L_only_less_than_2);
|
||||
|
||||
// load 2 Bytes
|
||||
movb(rax, Address(buf, pos, Address::times_1, 0));
|
||||
movb(Address(tmp1, 0), rax);
|
||||
|
||||
movb(rax, Address(buf, pos, Address::times_1, 1));
|
||||
movb(Address(tmp1, 1), rax);
|
||||
|
||||
movdqu(xmm7, Address(rsp, 0));
|
||||
pxor(xmm7, xmm0); //xor the initial crc value
|
||||
|
||||
pslldq(xmm7, 0x6);
|
||||
jmp(L_barrett);
|
||||
|
||||
bind(L_only_less_than_2);
|
||||
//load 1 Byte
|
||||
movb(rax, Address(buf, pos, Address::times_1, 0));
|
||||
movb(Address(tmp1, 0), rax);
|
||||
|
||||
movdqu(xmm7, Address(rsp, 0));
|
||||
pxor(xmm7, xmm0); //xor the initial crc value
|
||||
|
||||
pslldq(xmm7, 0x7);
|
||||
}
|
||||
|
||||
/**
|
||||
* Compute CRC32 using AVX512 instructions
|
||||
* param crc register containing existing CRC (32-bit)
|
||||
* param buf register pointing to input byte buffer (byte*)
|
||||
* param len register containing number of bytes
|
||||
* param tmp1 scratch register
|
||||
* param tmp2 scratch register
|
||||
* return rax result register
|
||||
*/
|
||||
void MacroAssembler::kernel_crc32_avx512(Register crc, Register buf, Register len, Register key, Register tmp1, Register tmp2) {
|
||||
assert_different_registers(crc, buf, len, key, tmp1, tmp2, rax);
|
||||
|
||||
Label L_tail, L_tail_restore, L_tail_loop, L_exit, L_align_loop, L_aligned;
|
||||
Label L_fold_tail, L_fold_128b, L_fold_512b, L_fold_512b_loop, L_fold_tail_loop;
|
||||
Label L_less_than_256, L_fold_128_B_loop, L_fold_256_B_loop;
|
||||
Label L_fold_128_B_register, L_final_reduction_for_128, L_16B_reduction_loop;
|
||||
Label L_128_done, L_get_last_two_xmms, L_barrett, L_cleanup;
|
||||
|
||||
const Register pos = r12;
|
||||
push(r12);
|
||||
subptr(rsp, 16 * 2 + 8);
|
||||
|
||||
// For EVEX with VL and BW, provide a standard mask, VL = 128 will guide the merge
|
||||
// context for the registers used, where all instructions below are using 128-bit mode
|
||||
// On EVEX without VL and BW, these instructions will all be AVX.
|
||||
lea(key, ExternalAddress(StubRoutines::x86::crc_table_avx512_addr()));
|
||||
notl(crc);
|
||||
movl(pos, 0);
|
||||
|
||||
// check if smaller than 256B
|
||||
cmpl(len, 256);
|
||||
jcc(Assembler::less, L_less_than_256);
|
||||
|
||||
// load the initial crc value
|
||||
movdl(xmm10, crc);
|
||||
|
||||
// receive the initial 64B data, xor the initial crc value
|
||||
evmovdquq(xmm0, Address(buf, pos, Address::times_1, 0 * 64), Assembler::AVX_512bit);
|
||||
evmovdquq(xmm4, Address(buf, pos, Address::times_1, 1 * 64), Assembler::AVX_512bit);
|
||||
evpxorq(xmm0, xmm0, xmm10, Assembler::AVX_512bit);
|
||||
evbroadcasti32x4(xmm10, Address(key, 2 * 16), Assembler::AVX_512bit); //zmm10 has rk3 and rk4
|
||||
|
||||
subl(len, 256);
|
||||
cmpl(len, 256);
|
||||
jcc(Assembler::less, L_fold_128_B_loop);
|
||||
|
||||
evmovdquq(xmm7, Address(buf, pos, Address::times_1, 2 * 64), Assembler::AVX_512bit);
|
||||
evmovdquq(xmm8, Address(buf, pos, Address::times_1, 3 * 64), Assembler::AVX_512bit);
|
||||
evbroadcasti32x4(xmm16, Address(key, 0 * 16), Assembler::AVX_512bit); //zmm16 has rk-1 and rk-2
|
||||
subl(len, 256);
|
||||
|
||||
bind(L_fold_256_B_loop);
|
||||
addl(pos, 256);
|
||||
fold512bit_crc32_avx512(xmm0, xmm16, xmm1, buf, pos, 0 * 64);
|
||||
fold512bit_crc32_avx512(xmm4, xmm16, xmm1, buf, pos, 1 * 64);
|
||||
fold512bit_crc32_avx512(xmm7, xmm16, xmm1, buf, pos, 2 * 64);
|
||||
fold512bit_crc32_avx512(xmm8, xmm16, xmm1, buf, pos, 3 * 64);
|
||||
|
||||
subl(len, 256);
|
||||
jcc(Assembler::greaterEqual, L_fold_256_B_loop);
|
||||
|
||||
// Fold 256 into 128
|
||||
addl(pos, 256);
|
||||
evpclmulqdq(xmm1, xmm0, xmm10, 0x01, Assembler::AVX_512bit);
|
||||
evpclmulqdq(xmm2, xmm0, xmm10, 0x10, Assembler::AVX_512bit);
|
||||
vpternlogq(xmm7, 0x96, xmm1, xmm2, Assembler::AVX_512bit); // xor ABC
|
||||
|
||||
evpclmulqdq(xmm5, xmm4, xmm10, 0x01, Assembler::AVX_512bit);
|
||||
evpclmulqdq(xmm6, xmm4, xmm10, 0x10, Assembler::AVX_512bit);
|
||||
vpternlogq(xmm8, 0x96, xmm5, xmm6, Assembler::AVX_512bit); // xor ABC
|
||||
|
||||
evmovdquq(xmm0, xmm7, Assembler::AVX_512bit);
|
||||
evmovdquq(xmm4, xmm8, Assembler::AVX_512bit);
|
||||
|
||||
addl(len, 128);
|
||||
jmp(L_fold_128_B_register);
|
||||
|
||||
// at this section of the code, there is 128 * x + y(0 <= y<128) bytes of buffer.The fold_128_B_loop
|
||||
// loop will fold 128B at a time until we have 128 + y Bytes of buffer
|
||||
|
||||
// fold 128B at a time.This section of the code folds 8 xmm registers in parallel
|
||||
bind(L_fold_128_B_loop);
|
||||
addl(pos, 128);
|
||||
fold512bit_crc32_avx512(xmm0, xmm10, xmm1, buf, pos, 0 * 64);
|
||||
fold512bit_crc32_avx512(xmm4, xmm10, xmm1, buf, pos, 1 * 64);
|
||||
|
||||
subl(len, 128);
|
||||
jcc(Assembler::greaterEqual, L_fold_128_B_loop);
|
||||
|
||||
addl(pos, 128);
|
||||
|
||||
// at this point, the buffer pointer is pointing at the last y Bytes of the buffer, where 0 <= y < 128
|
||||
// the 128B of folded data is in 8 of the xmm registers : xmm0, xmm1, xmm2, xmm3, xmm4, xmm5, xmm6, xmm7
|
||||
bind(L_fold_128_B_register);
|
||||
evmovdquq(xmm16, Address(key, 5 * 16), Assembler::AVX_512bit); // multiply by rk9-rk16
|
||||
evmovdquq(xmm11, Address(key, 9 * 16), Assembler::AVX_512bit); // multiply by rk17-rk20, rk1,rk2, 0,0
|
||||
evpclmulqdq(xmm1, xmm0, xmm16, 0x01, Assembler::AVX_512bit);
|
||||
evpclmulqdq(xmm2, xmm0, xmm16, 0x10, Assembler::AVX_512bit);
|
||||
// save last that has no multiplicand
|
||||
vextracti64x2(xmm7, xmm4, 3);
|
||||
|
||||
evpclmulqdq(xmm5, xmm4, xmm11, 0x01, Assembler::AVX_512bit);
|
||||
evpclmulqdq(xmm6, xmm4, xmm11, 0x10, Assembler::AVX_512bit);
|
||||
// Needed later in reduction loop
|
||||
movdqu(xmm10, Address(key, 1 * 16));
|
||||
vpternlogq(xmm1, 0x96, xmm2, xmm5, Assembler::AVX_512bit); // xor ABC
|
||||
vpternlogq(xmm1, 0x96, xmm6, xmm7, Assembler::AVX_512bit); // xor ABC
|
||||
|
||||
// Swap 1,0,3,2 - 01 00 11 10
|
||||
evshufi64x2(xmm8, xmm1, xmm1, 0x4e, Assembler::AVX_512bit);
|
||||
evpxorq(xmm8, xmm8, xmm1, Assembler::AVX_256bit);
|
||||
vextracti128(xmm5, xmm8, 1);
|
||||
evpxorq(xmm7, xmm5, xmm8, Assembler::AVX_128bit);
|
||||
|
||||
// instead of 128, we add 128 - 16 to the loop counter to save 1 instruction from the loop
|
||||
// instead of a cmp instruction, we use the negative flag with the jl instruction
|
||||
addl(len, 128 - 16);
|
||||
jcc(Assembler::less, L_final_reduction_for_128);
|
||||
|
||||
bind(L_16B_reduction_loop);
|
||||
vpclmulqdq(xmm8, xmm7, xmm10, 0x1);
|
||||
vpclmulqdq(xmm7, xmm7, xmm10, 0x10);
|
||||
vpxor(xmm7, xmm7, xmm8, Assembler::AVX_128bit);
|
||||
movdqu(xmm0, Address(buf, pos, Address::times_1, 0 * 16));
|
||||
vpxor(xmm7, xmm7, xmm0, Assembler::AVX_128bit);
|
||||
addl(pos, 16);
|
||||
subl(len, 16);
|
||||
jcc(Assembler::greaterEqual, L_16B_reduction_loop);
|
||||
|
||||
bind(L_final_reduction_for_128);
|
||||
addl(len, 16);
|
||||
jcc(Assembler::equal, L_128_done);
|
||||
|
||||
bind(L_get_last_two_xmms);
|
||||
movdqu(xmm2, xmm7);
|
||||
addl(pos, len);
|
||||
movdqu(xmm1, Address(buf, pos, Address::times_1, -16));
|
||||
subl(pos, len);
|
||||
|
||||
// get rid of the extra data that was loaded before
|
||||
// load the shift constant
|
||||
lea(rax, ExternalAddress(StubRoutines::x86::shuf_table_crc32_avx512_addr()));
|
||||
movdqu(xmm0, Address(rax, len));
|
||||
addl(rax, len);
|
||||
|
||||
vpshufb(xmm7, xmm7, xmm0, Assembler::AVX_128bit);
|
||||
//Change mask to 512
|
||||
vpxor(xmm0, xmm0, ExternalAddress(StubRoutines::x86::crc_by128_masks_avx512_addr() + 2 * 16), Assembler::AVX_128bit, tmp2);
|
||||
vpshufb(xmm2, xmm2, xmm0, Assembler::AVX_128bit);
|
||||
|
||||
blendvpb(xmm2, xmm2, xmm1, xmm0, Assembler::AVX_128bit);
|
||||
vpclmulqdq(xmm8, xmm7, xmm10, 0x1);
|
||||
vpclmulqdq(xmm7, xmm7, xmm10, 0x10);
|
||||
vpxor(xmm7, xmm7, xmm8, Assembler::AVX_128bit);
|
||||
vpxor(xmm7, xmm7, xmm2, Assembler::AVX_128bit);
|
||||
|
||||
bind(L_128_done);
|
||||
// compute crc of a 128-bit value
|
||||
movdqu(xmm10, Address(key, 3 * 16));
|
||||
movdqu(xmm0, xmm7);
|
||||
|
||||
// 64b fold
|
||||
vpclmulqdq(xmm7, xmm7, xmm10, 0x0);
|
||||
vpsrldq(xmm0, xmm0, 0x8, Assembler::AVX_128bit);
|
||||
vpxor(xmm7, xmm7, xmm0, Assembler::AVX_128bit);
|
||||
|
||||
// 32b fold
|
||||
movdqu(xmm0, xmm7);
|
||||
vpslldq(xmm7, xmm7, 0x4, Assembler::AVX_128bit);
|
||||
vpclmulqdq(xmm7, xmm7, xmm10, 0x10);
|
||||
vpxor(xmm7, xmm7, xmm0, Assembler::AVX_128bit);
|
||||
jmp(L_barrett);
|
||||
|
||||
bind(L_less_than_256);
|
||||
kernel_crc32_avx512_256B(crc, buf, len, key, pos, tmp1, tmp2, L_barrett, L_16B_reduction_loop, L_get_last_two_xmms, L_128_done, L_cleanup);
|
||||
|
||||
//barrett reduction
|
||||
bind(L_barrett);
|
||||
vpand(xmm7, xmm7, ExternalAddress(StubRoutines::x86::crc_by128_masks_avx512_addr() + 1 * 16), Assembler::AVX_128bit, tmp2);
|
||||
movdqu(xmm1, xmm7);
|
||||
movdqu(xmm2, xmm7);
|
||||
movdqu(xmm10, Address(key, 4 * 16));
|
||||
|
||||
pclmulqdq(xmm7, xmm10, 0x0);
|
||||
pxor(xmm7, xmm2);
|
||||
vpand(xmm7, xmm7, ExternalAddress(StubRoutines::x86::crc_by128_masks_avx512_addr()), Assembler::AVX_128bit, tmp2);
|
||||
movdqu(xmm2, xmm7);
|
||||
pclmulqdq(xmm7, xmm10, 0x10);
|
||||
pxor(xmm7, xmm2);
|
||||
pxor(xmm7, xmm1);
|
||||
pextrd(crc, xmm7, 2);
|
||||
|
||||
bind(L_cleanup);
|
||||
notl(crc); // ~c
|
||||
addptr(rsp, 16 * 2 + 8);
|
||||
pop(r12);
|
||||
}
|
||||
|
||||
// S. Gueron / Information Processing Letters 112 (2012) 184
|
||||
// Algorithm 4: Computing carry-less multiplication using a precomputed lookup table.
|
||||
// Input: A 32 bit value B = [byte3, byte2, byte1, byte0].
|
||||
|
||||
@ -1658,6 +1658,15 @@ public:
|
||||
// CRC32 code for java.util.zip.CRC32::updateBytes() intrinsic.
|
||||
void update_byte_crc32(Register crc, Register val, Register table);
|
||||
void kernel_crc32(Register crc, Register buf, Register len, Register table, Register tmp);
|
||||
|
||||
|
||||
#ifdef _LP64
|
||||
void kernel_crc32_avx512(Register crc, Register buf, Register len, Register table, Register tmp1, Register tmp2);
|
||||
void kernel_crc32_avx512_256B(Register crc, Register buf, Register len, Register key, Register pos,
|
||||
Register tmp1, Register tmp2, Label& L_barrett, Label& L_16B_reduction_loop,
|
||||
Label& L_get_last_two_xmms, Label& L_128_done, Label& L_cleanup);
|
||||
#endif // _LP64
|
||||
|
||||
// CRC32C code for java.util.zip.CRC32C::updateBytes() intrinsic
|
||||
// Note on a naming convention:
|
||||
// Prefix w = register only used on a Westmere+ architecture
|
||||
@ -1694,10 +1703,13 @@ public:
|
||||
// Fold 128-bit data chunk
|
||||
void fold_128bit_crc32(XMMRegister xcrc, XMMRegister xK, XMMRegister xtmp, Register buf, int offset);
|
||||
void fold_128bit_crc32(XMMRegister xcrc, XMMRegister xK, XMMRegister xtmp, XMMRegister xbuf);
|
||||
#ifdef _LP64
|
||||
// Fold 512-bit data chunk
|
||||
void fold512bit_crc32_avx512(XMMRegister xcrc, XMMRegister xK, XMMRegister xtmp, Register buf, Register pos, int offset);
|
||||
#endif // _LP64
|
||||
// Fold 8-bit data
|
||||
void fold_8bit_crc32(Register crc, Register table, Register tmp);
|
||||
void fold_8bit_crc32(XMMRegister crc, Register table, XMMRegister xtmp, Register tmp);
|
||||
void fold_128bit_crc32_avx512(XMMRegister xcrc, XMMRegister xK, XMMRegister xtmp, Register buf, int offset);
|
||||
|
||||
// Compress char[] array to byte[].
|
||||
void char_array_compress(Register src, Register dst, Register len,
|
||||
|
||||
@ -5325,13 +5325,20 @@ address generate_avx_ghash_processBlocks() {
|
||||
const Register buf = c_rarg1; // source java byte array address
|
||||
const Register len = c_rarg2; // length
|
||||
const Register table = c_rarg3; // crc_table address (reuse register)
|
||||
const Register tmp = r11;
|
||||
assert_different_registers(crc, buf, len, table, tmp, rax);
|
||||
const Register tmp1 = r11;
|
||||
const Register tmp2 = r10;
|
||||
assert_different_registers(crc, buf, len, table, tmp1, tmp2, rax);
|
||||
|
||||
BLOCK_COMMENT("Entry:");
|
||||
__ enter(); // required for proper stackwalking of RuntimeStub frame
|
||||
|
||||
__ kernel_crc32(crc, buf, len, table, tmp);
|
||||
if (VM_Version::supports_sse4_1() && VM_Version::supports_avx512_vpclmulqdq() &&
|
||||
VM_Version::supports_avx512bw() &&
|
||||
VM_Version::supports_avx512vl()) {
|
||||
__ kernel_crc32_avx512(crc, buf, len, table, tmp1, tmp2);
|
||||
} else {
|
||||
__ kernel_crc32(crc, buf, len, table, tmp1);
|
||||
}
|
||||
|
||||
__ movl(rax, crc);
|
||||
__ vzeroupper();
|
||||
|
||||
@ -184,6 +184,38 @@ juint StubRoutines::x86::_crc_table[] =
|
||||
0x2d02ef8dUL
|
||||
};
|
||||
|
||||
#ifdef _LP64
|
||||
juint StubRoutines::x86::_crc_table_avx512[] =
|
||||
{
|
||||
0xe95c1271UL, 0x00000000UL, 0xce3371cbUL, 0x00000000UL,
|
||||
0xccaa009eUL, 0x00000000UL, 0x751997d0UL, 0x00000001UL,
|
||||
0x4a7fe880UL, 0x00000001UL, 0xe88ef372UL, 0x00000001UL,
|
||||
0xccaa009eUL, 0x00000000UL, 0x63cd6124UL, 0x00000001UL,
|
||||
0xf7011640UL, 0x00000001UL, 0xdb710640UL, 0x00000001UL,
|
||||
0xd7cfc6acUL, 0x00000001UL, 0xea89367eUL, 0x00000001UL,
|
||||
0x8cb44e58UL, 0x00000001UL, 0xdf068dc2UL, 0x00000000UL,
|
||||
0xae0b5394UL, 0x00000000UL, 0xc7569e54UL, 0x00000001UL,
|
||||
0xc6e41596UL, 0x00000001UL, 0x54442bd4UL, 0x00000001UL,
|
||||
0x74359406UL, 0x00000001UL, 0x3db1ecdcUL, 0x00000000UL,
|
||||
0x5a546366UL, 0x00000001UL, 0xf1da05aaUL, 0x00000000UL,
|
||||
0xccaa009eUL, 0x00000000UL, 0x751997d0UL, 0x00000001UL,
|
||||
0x00000000UL, 0x00000000UL, 0x00000000UL, 0x00000000UL
|
||||
};
|
||||
|
||||
juint StubRoutines::x86::_crc_by128_masks_avx512[] =
|
||||
{
|
||||
0xffffffffUL, 0xffffffffUL, 0x00000000UL, 0x00000000UL,
|
||||
0x00000000UL, 0xffffffffUL, 0xffffffffUL, 0xffffffffUL,
|
||||
0x80808080UL, 0x80808080UL, 0x80808080UL, 0x80808080UL
|
||||
};
|
||||
|
||||
juint StubRoutines::x86::_shuf_table_crc32_avx512[] =
|
||||
{
|
||||
0x83828100UL, 0x87868584UL, 0x8b8a8988UL, 0x8f8e8d8cUL,
|
||||
0x03020100UL, 0x07060504UL, 0x0b0a0908UL, 0x000e0d0cUL
|
||||
};
|
||||
#endif // _LP64
|
||||
|
||||
#define D 32
|
||||
#define P 0x82F63B78 // Reflection of Castagnoli (0x11EDC6F41)
|
||||
|
||||
|
||||
@ -120,6 +120,11 @@ class x86 {
|
||||
// masks and table for CRC32
|
||||
static uint64_t _crc_by128_masks[];
|
||||
static juint _crc_table[];
|
||||
#ifdef _LP64
|
||||
static juint _crc_by128_masks_avx512[];
|
||||
static juint _crc_table_avx512[];
|
||||
static juint _shuf_table_crc32_avx512[];
|
||||
#endif // _LP64
|
||||
// table for CRC32C
|
||||
static juint* _crc32c_table;
|
||||
// swap mask for ghash
|
||||
@ -210,6 +215,11 @@ class x86 {
|
||||
static address key_shuffle_mask_addr() { return _key_shuffle_mask_addr; }
|
||||
static address counter_shuffle_mask_addr() { return _counter_shuffle_mask_addr; }
|
||||
static address crc_by128_masks_addr() { return (address)_crc_by128_masks; }
|
||||
#ifdef _LP64
|
||||
static address crc_by128_masks_avx512_addr() { return (address)_crc_by128_masks_avx512; }
|
||||
static address shuf_table_crc32_avx512_addr() { return (address)_shuf_table_crc32_avx512; }
|
||||
static address crc_table_avx512_addr() { return (address)_crc_table_avx512; }
|
||||
#endif // _LP64
|
||||
static address ghash_long_swap_mask_addr() { return _ghash_long_swap_mask_addr; }
|
||||
static address ghash_byte_swap_mask_addr() { return _ghash_byte_swap_mask_addr; }
|
||||
static address ghash_shufflemask_addr() { return _ghash_shuffmask_addr; }
|
||||
|
||||
@ -22,6 +22,7 @@
|
||||
*/
|
||||
|
||||
#include "precompiled.hpp"
|
||||
#include "gc/shared/gcLogPrecious.hpp"
|
||||
#include "gc/z/zErrno.hpp"
|
||||
#include "gc/z/zGlobals.hpp"
|
||||
#include "gc/z/zLargePages.inline.hpp"
|
||||
@ -72,16 +73,15 @@ static ZErrno mremap(uintptr_t from_addr, uintptr_t to_addr, size_t size) {
|
||||
return (res == KERN_SUCCESS) ? ZErrno(0) : ZErrno(EINVAL);
|
||||
}
|
||||
|
||||
ZPhysicalMemoryBacking::ZPhysicalMemoryBacking() :
|
||||
ZPhysicalMemoryBacking::ZPhysicalMemoryBacking(size_t max_capacity) :
|
||||
_base(0),
|
||||
_size(0),
|
||||
_initialized(false) {
|
||||
|
||||
// Reserve address space for backing memory
|
||||
_base = (uintptr_t)os::reserve_memory(MaxHeapSize);
|
||||
_base = (uintptr_t)os::reserve_memory(max_capacity);
|
||||
if (_base == 0) {
|
||||
// Failed
|
||||
log_error(gc)("Failed to reserve address space for backing memory");
|
||||
log_error_pd(gc)("Failed to reserve address space for backing memory");
|
||||
return;
|
||||
}
|
||||
|
||||
@ -93,15 +93,11 @@ bool ZPhysicalMemoryBacking::is_initialized() const {
|
||||
return _initialized;
|
||||
}
|
||||
|
||||
void ZPhysicalMemoryBacking::warn_commit_limits(size_t max) const {
|
||||
void ZPhysicalMemoryBacking::warn_commit_limits(size_t max_capacity) const {
|
||||
// Does nothing
|
||||
}
|
||||
|
||||
size_t ZPhysicalMemoryBacking::size() const {
|
||||
return _size;
|
||||
}
|
||||
|
||||
bool ZPhysicalMemoryBacking::commit_inner(size_t offset, size_t length) {
|
||||
bool ZPhysicalMemoryBacking::commit_inner(size_t offset, size_t length) const {
|
||||
assert(is_aligned(offset, os::vm_page_size()), "Invalid offset");
|
||||
assert(is_aligned(length, os::vm_page_size()), "Invalid length");
|
||||
|
||||
@ -116,17 +112,11 @@ bool ZPhysicalMemoryBacking::commit_inner(size_t offset, size_t length) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const size_t end = offset + length;
|
||||
if (end > _size) {
|
||||
// Record new size
|
||||
_size = end;
|
||||
}
|
||||
|
||||
// Success
|
||||
return true;
|
||||
}
|
||||
|
||||
size_t ZPhysicalMemoryBacking::commit(size_t offset, size_t length) {
|
||||
size_t ZPhysicalMemoryBacking::commit(size_t offset, size_t length) const {
|
||||
// Try to commit the whole region
|
||||
if (commit_inner(offset, length)) {
|
||||
// Success
|
||||
@ -154,7 +144,7 @@ size_t ZPhysicalMemoryBacking::commit(size_t offset, size_t length) {
|
||||
}
|
||||
}
|
||||
|
||||
size_t ZPhysicalMemoryBacking::uncommit(size_t offset, size_t length) {
|
||||
size_t ZPhysicalMemoryBacking::uncommit(size_t offset, size_t length) const {
|
||||
assert(is_aligned(offset, os::vm_page_size()), "Invalid offset");
|
||||
assert(is_aligned(length, os::vm_page_size()), "Invalid length");
|
||||
|
||||
|
||||
@ -27,22 +27,19 @@
|
||||
class ZPhysicalMemoryBacking {
|
||||
private:
|
||||
uintptr_t _base;
|
||||
size_t _size;
|
||||
bool _initialized;
|
||||
|
||||
bool commit_inner(size_t offset, size_t length);
|
||||
bool commit_inner(size_t offset, size_t length) const;
|
||||
|
||||
public:
|
||||
ZPhysicalMemoryBacking();
|
||||
ZPhysicalMemoryBacking(size_t max_capacity);
|
||||
|
||||
bool is_initialized() const;
|
||||
|
||||
void warn_commit_limits(size_t max) const;
|
||||
void warn_commit_limits(size_t max_capacity) const;
|
||||
|
||||
size_t size() const;
|
||||
|
||||
size_t commit(size_t offset, size_t length);
|
||||
size_t uncommit(size_t offset, size_t length);
|
||||
size_t commit(size_t offset, size_t length) const;
|
||||
size_t uncommit(size_t offset, size_t length) const;
|
||||
|
||||
void map(uintptr_t addr, size_t size, uintptr_t offset) const;
|
||||
void unmap(uintptr_t addr, size_t size) const;
|
||||
|
||||
@ -22,11 +22,11 @@
|
||||
*/
|
||||
|
||||
#include "precompiled.hpp"
|
||||
#include "gc/shared/gcLogPrecious.hpp"
|
||||
#include "gc/z/zArray.inline.hpp"
|
||||
#include "gc/z/zErrno.hpp"
|
||||
#include "gc/z/zMountPoint_linux.hpp"
|
||||
#include "runtime/globals.hpp"
|
||||
#include "logging/log.hpp"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
@ -73,7 +73,7 @@ void ZMountPoint::get_mountpoints(const char* filesystem, ZArray<char*>* mountpo
|
||||
FILE* fd = fopen(PROC_SELF_MOUNTINFO, "r");
|
||||
if (fd == NULL) {
|
||||
ZErrno err;
|
||||
log_error(gc)("Failed to open %s: %s", PROC_SELF_MOUNTINFO, err.to_string());
|
||||
log_error_p(gc)("Failed to open %s: %s", PROC_SELF_MOUNTINFO, err.to_string());
|
||||
return;
|
||||
}
|
||||
|
||||
@ -114,10 +114,10 @@ char* ZMountPoint::find_preferred_mountpoint(const char* filesystem,
|
||||
}
|
||||
|
||||
// Preferred mount point not found
|
||||
log_error(gc)("More than one %s filesystem found:", filesystem);
|
||||
log_error_p(gc)("More than one %s filesystem found:", filesystem);
|
||||
ZArrayIterator<char*> iter2(mountpoints);
|
||||
for (char* mountpoint; iter2.next(&mountpoint);) {
|
||||
log_error(gc)(" %s", mountpoint);
|
||||
log_error_p(gc)(" %s", mountpoint);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
@ -131,7 +131,7 @@ char* ZMountPoint::find_mountpoint(const char* filesystem, const char** preferre
|
||||
|
||||
if (mountpoints.size() == 0) {
|
||||
// No mount point found
|
||||
log_error(gc)("Failed to find an accessible %s filesystem", filesystem);
|
||||
log_error_p(gc)("Failed to find an accessible %s filesystem", filesystem);
|
||||
} else if (mountpoints.size() == 1) {
|
||||
// One mount point found
|
||||
path = strdup(mountpoints.at(0));
|
||||
|
||||
@ -22,6 +22,7 @@
|
||||
*/
|
||||
|
||||
#include "precompiled.hpp"
|
||||
#include "gc/shared/gcLogPrecious.hpp"
|
||||
#include "gc/z/zArray.inline.hpp"
|
||||
#include "gc/z/zErrno.hpp"
|
||||
#include "gc/z/zGlobals.hpp"
|
||||
@ -112,9 +113,8 @@ static const char* z_preferred_hugetlbfs_mountpoints[] = {
|
||||
static int z_fallocate_hugetlbfs_attempts = 3;
|
||||
static bool z_fallocate_supported = true;
|
||||
|
||||
ZPhysicalMemoryBacking::ZPhysicalMemoryBacking() :
|
||||
ZPhysicalMemoryBacking::ZPhysicalMemoryBacking(size_t max_capacity) :
|
||||
_fd(-1),
|
||||
_size(0),
|
||||
_filesystem(0),
|
||||
_block_size(0),
|
||||
_available(0),
|
||||
@ -126,11 +126,20 @@ ZPhysicalMemoryBacking::ZPhysicalMemoryBacking() :
|
||||
return;
|
||||
}
|
||||
|
||||
// Truncate backing file
|
||||
while (ftruncate(_fd, max_capacity) == -1) {
|
||||
if (errno != EINTR) {
|
||||
ZErrno err;
|
||||
log_error_p(gc)("Failed to truncate backing file (%s)", err.to_string());
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Get filesystem statistics
|
||||
struct statfs buf;
|
||||
if (fstatfs(_fd, &buf) == -1) {
|
||||
ZErrno err;
|
||||
log_error(gc)("Failed to determine filesystem type for backing file (%s)", err.to_string());
|
||||
log_error_p(gc)("Failed to determine filesystem type for backing file (%s)", err.to_string());
|
||||
return;
|
||||
}
|
||||
|
||||
@ -138,50 +147,50 @@ ZPhysicalMemoryBacking::ZPhysicalMemoryBacking() :
|
||||
_block_size = buf.f_bsize;
|
||||
_available = buf.f_bavail * _block_size;
|
||||
|
||||
log_info(gc, init)("Heap Backing Filesystem: %s (0x" UINT64_FORMAT_X ")",
|
||||
is_tmpfs() ? ZFILESYSTEM_TMPFS : is_hugetlbfs() ? ZFILESYSTEM_HUGETLBFS : "other", _filesystem);
|
||||
log_info_p(gc, init)("Heap Backing Filesystem: %s (0x" UINT64_FORMAT_X ")",
|
||||
is_tmpfs() ? ZFILESYSTEM_TMPFS : is_hugetlbfs() ? ZFILESYSTEM_HUGETLBFS : "other", _filesystem);
|
||||
|
||||
// Make sure the filesystem type matches requested large page type
|
||||
if (ZLargePages::is_transparent() && !is_tmpfs()) {
|
||||
log_error(gc)("-XX:+UseTransparentHugePages can only be enabled when using a %s filesystem",
|
||||
ZFILESYSTEM_TMPFS);
|
||||
log_error_p(gc)("-XX:+UseTransparentHugePages can only be enabled when using a %s filesystem",
|
||||
ZFILESYSTEM_TMPFS);
|
||||
return;
|
||||
}
|
||||
|
||||
if (ZLargePages::is_transparent() && !tmpfs_supports_transparent_huge_pages()) {
|
||||
log_error(gc)("-XX:+UseTransparentHugePages on a %s filesystem not supported by kernel",
|
||||
ZFILESYSTEM_TMPFS);
|
||||
log_error_p(gc)("-XX:+UseTransparentHugePages on a %s filesystem not supported by kernel",
|
||||
ZFILESYSTEM_TMPFS);
|
||||
return;
|
||||
}
|
||||
|
||||
if (ZLargePages::is_explicit() && !is_hugetlbfs()) {
|
||||
log_error(gc)("-XX:+UseLargePages (without -XX:+UseTransparentHugePages) can only be enabled "
|
||||
"when using a %s filesystem", ZFILESYSTEM_HUGETLBFS);
|
||||
log_error_p(gc)("-XX:+UseLargePages (without -XX:+UseTransparentHugePages) can only be enabled "
|
||||
"when using a %s filesystem", ZFILESYSTEM_HUGETLBFS);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!ZLargePages::is_explicit() && is_hugetlbfs()) {
|
||||
log_error(gc)("-XX:+UseLargePages must be enabled when using a %s filesystem",
|
||||
ZFILESYSTEM_HUGETLBFS);
|
||||
log_error_p(gc)("-XX:+UseLargePages must be enabled when using a %s filesystem",
|
||||
ZFILESYSTEM_HUGETLBFS);
|
||||
return;
|
||||
}
|
||||
|
||||
if (ZLargePages::is_explicit() && os::large_page_size() != ZGranuleSize) {
|
||||
log_error(gc)("Incompatible large page size configured " SIZE_FORMAT " (expected " SIZE_FORMAT ")",
|
||||
os::large_page_size(), ZGranuleSize);
|
||||
log_error_p(gc)("Incompatible large page size configured " SIZE_FORMAT " (expected " SIZE_FORMAT ")",
|
||||
os::large_page_size(), ZGranuleSize);
|
||||
return;
|
||||
}
|
||||
|
||||
// Make sure the filesystem block size is compatible
|
||||
if (ZGranuleSize % _block_size != 0) {
|
||||
log_error(gc)("Filesystem backing the heap has incompatible block size (" SIZE_FORMAT ")",
|
||||
_block_size);
|
||||
log_error_p(gc)("Filesystem backing the heap has incompatible block size (" SIZE_FORMAT ")",
|
||||
_block_size);
|
||||
return;
|
||||
}
|
||||
|
||||
if (is_hugetlbfs() && _block_size != ZGranuleSize) {
|
||||
log_error(gc)("%s filesystem has unexpected block size " SIZE_FORMAT " (expected " SIZE_FORMAT ")",
|
||||
ZFILESYSTEM_HUGETLBFS, _block_size, ZGranuleSize);
|
||||
log_error_p(gc)("%s filesystem has unexpected block size " SIZE_FORMAT " (expected " SIZE_FORMAT ")",
|
||||
ZFILESYSTEM_HUGETLBFS, _block_size, ZGranuleSize);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -199,12 +208,12 @@ int ZPhysicalMemoryBacking::create_mem_fd(const char* name) const {
|
||||
const int fd = ZSyscall::memfd_create(filename, MFD_CLOEXEC | extra_flags);
|
||||
if (fd == -1) {
|
||||
ZErrno err;
|
||||
log_debug(gc, init)("Failed to create memfd file (%s)",
|
||||
((ZLargePages::is_explicit() && err == EINVAL) ? "Hugepages not supported" : err.to_string()));
|
||||
log_debug_p(gc, init)("Failed to create memfd file (%s)",
|
||||
((ZLargePages::is_explicit() && err == EINVAL) ? "Hugepages not supported" : err.to_string()));
|
||||
return -1;
|
||||
}
|
||||
|
||||
log_info(gc, init)("Heap Backing File: /memfd:%s", filename);
|
||||
log_info_p(gc, init)("Heap Backing File: /memfd:%s", filename);
|
||||
|
||||
return fd;
|
||||
}
|
||||
@ -220,7 +229,7 @@ int ZPhysicalMemoryBacking::create_file_fd(const char* name) const {
|
||||
// Find mountpoint
|
||||
ZMountPoint mountpoint(filesystem, preferred_mountpoints);
|
||||
if (mountpoint.get() == NULL) {
|
||||
log_error(gc)("Use -XX:AllocateHeapAt to specify the path to a %s filesystem", filesystem);
|
||||
log_error_p(gc)("Use -XX:AllocateHeapAt to specify the path to a %s filesystem", filesystem);
|
||||
return -1;
|
||||
}
|
||||
|
||||
@ -229,23 +238,23 @@ int ZPhysicalMemoryBacking::create_file_fd(const char* name) const {
|
||||
const int fd_anon = os::open(mountpoint.get(), O_TMPFILE|O_EXCL|O_RDWR|O_CLOEXEC, S_IRUSR|S_IWUSR);
|
||||
if (fd_anon == -1) {
|
||||
ZErrno err;
|
||||
log_debug(gc, init)("Failed to create anonymous file in %s (%s)", mountpoint.get(),
|
||||
(err == EINVAL ? "Not supported" : err.to_string()));
|
||||
log_debug_p(gc, init)("Failed to create anonymous file in %s (%s)", mountpoint.get(),
|
||||
(err == EINVAL ? "Not supported" : err.to_string()));
|
||||
} else {
|
||||
// Get inode number for anonymous file
|
||||
struct stat stat_buf;
|
||||
if (fstat(fd_anon, &stat_buf) == -1) {
|
||||
ZErrno err;
|
||||
log_error(gc)("Failed to determine inode number for anonymous file (%s)", err.to_string());
|
||||
log_error_pd(gc)("Failed to determine inode number for anonymous file (%s)", err.to_string());
|
||||
return -1;
|
||||
}
|
||||
|
||||
log_info(gc, init)("Heap Backing File: %s/#" UINT64_FORMAT, mountpoint.get(), (uint64_t)stat_buf.st_ino);
|
||||
log_info_p(gc, init)("Heap Backing File: %s/#" UINT64_FORMAT, mountpoint.get(), (uint64_t)stat_buf.st_ino);
|
||||
|
||||
return fd_anon;
|
||||
}
|
||||
|
||||
log_debug(gc, init)("Falling back to open/unlink");
|
||||
log_debug_p(gc, init)("Falling back to open/unlink");
|
||||
|
||||
// Create file name
|
||||
char filename[PATH_MAX];
|
||||
@ -255,18 +264,18 @@ int ZPhysicalMemoryBacking::create_file_fd(const char* name) const {
|
||||
const int fd = os::open(filename, O_CREAT|O_EXCL|O_RDWR|O_CLOEXEC, S_IRUSR|S_IWUSR);
|
||||
if (fd == -1) {
|
||||
ZErrno err;
|
||||
log_error(gc)("Failed to create file %s (%s)", filename, err.to_string());
|
||||
log_error_p(gc)("Failed to create file %s (%s)", filename, err.to_string());
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Unlink file
|
||||
if (unlink(filename) == -1) {
|
||||
ZErrno err;
|
||||
log_error(gc)("Failed to unlink file %s (%s)", filename, err.to_string());
|
||||
log_error_p(gc)("Failed to unlink file %s (%s)", filename, err.to_string());
|
||||
return -1;
|
||||
}
|
||||
|
||||
log_info(gc, init)("Heap Backing File: %s", filename);
|
||||
log_info_p(gc, init)("Heap Backing File: %s", filename);
|
||||
|
||||
return fd;
|
||||
}
|
||||
@ -283,7 +292,7 @@ int ZPhysicalMemoryBacking::create_fd(const char* name) const {
|
||||
return fd;
|
||||
}
|
||||
|
||||
log_debug(gc, init)("Falling back to searching for an accessible mount point");
|
||||
log_debug_p(gc)("Falling back to searching for an accessible mount point");
|
||||
}
|
||||
|
||||
return create_file_fd(name);
|
||||
@ -293,37 +302,37 @@ bool ZPhysicalMemoryBacking::is_initialized() const {
|
||||
return _initialized;
|
||||
}
|
||||
|
||||
void ZPhysicalMemoryBacking::warn_available_space(size_t max) const {
|
||||
void ZPhysicalMemoryBacking::warn_available_space(size_t max_capacity) const {
|
||||
// Note that the available space on a tmpfs or a hugetlbfs filesystem
|
||||
// will be zero if no size limit was specified when it was mounted.
|
||||
if (_available == 0) {
|
||||
// No size limit set, skip check
|
||||
log_info(gc, init)("Available space on backing filesystem: N/A");
|
||||
log_info_p(gc, init)("Available space on backing filesystem: N/A");
|
||||
return;
|
||||
}
|
||||
|
||||
log_info(gc, init)("Available space on backing filesystem: " SIZE_FORMAT "M", _available / M);
|
||||
log_info_p(gc, init)("Available space on backing filesystem: " SIZE_FORMAT "M", _available / M);
|
||||
|
||||
// Warn if the filesystem doesn't currently have enough space available to hold
|
||||
// the max heap size. The max heap size will be capped if we later hit this limit
|
||||
// when trying to expand the heap.
|
||||
if (_available < max) {
|
||||
log_warning(gc)("***** WARNING! INCORRECT SYSTEM CONFIGURATION DETECTED! *****");
|
||||
log_warning(gc)("Not enough space available on the backing filesystem to hold the current max Java heap");
|
||||
log_warning(gc)("size (" SIZE_FORMAT "M). Please adjust the size of the backing filesystem accordingly "
|
||||
"(available", max / M);
|
||||
log_warning(gc)("space is currently " SIZE_FORMAT "M). Continuing execution with the current filesystem "
|
||||
"size could", _available / M);
|
||||
log_warning(gc)("lead to a premature OutOfMemoryError being thrown, due to failure to map memory.");
|
||||
if (_available < max_capacity) {
|
||||
log_warning_p(gc)("***** WARNING! INCORRECT SYSTEM CONFIGURATION DETECTED! *****");
|
||||
log_warning_p(gc)("Not enough space available on the backing filesystem to hold the current max Java heap");
|
||||
log_warning_p(gc)("size (" SIZE_FORMAT "M). Please adjust the size of the backing filesystem accordingly "
|
||||
"(available", max_capacity / M);
|
||||
log_warning_p(gc)("space is currently " SIZE_FORMAT "M). Continuing execution with the current filesystem "
|
||||
"size could", _available / M);
|
||||
log_warning_p(gc)("lead to a premature OutOfMemoryError being thrown, due to failure to commit memory.");
|
||||
}
|
||||
}
|
||||
|
||||
void ZPhysicalMemoryBacking::warn_max_map_count(size_t max) const {
|
||||
void ZPhysicalMemoryBacking::warn_max_map_count(size_t max_capacity) const {
|
||||
const char* const filename = ZFILENAME_PROC_MAX_MAP_COUNT;
|
||||
FILE* const file = fopen(filename, "r");
|
||||
if (file == NULL) {
|
||||
// Failed to open file, skip check
|
||||
log_debug(gc, init)("Failed to open %s", filename);
|
||||
log_debug_p(gc, init)("Failed to open %s", filename);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -332,7 +341,7 @@ void ZPhysicalMemoryBacking::warn_max_map_count(size_t max) const {
|
||||
fclose(file);
|
||||
if (result != 1) {
|
||||
// Failed to read file, skip check
|
||||
log_debug(gc, init)("Failed to read %s", filename);
|
||||
log_debug_p(gc, init)("Failed to read %s", filename);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -341,28 +350,24 @@ void ZPhysicalMemoryBacking::warn_max_map_count(size_t max) const {
|
||||
// However, ZGC tends to create the most mappings and dominate the total count.
|
||||
// In the worst cases, ZGC will map each granule three times, i.e. once per heap view.
|
||||
// We speculate that we need another 20% to allow for non-ZGC subsystems to map memory.
|
||||
const size_t required_max_map_count = (max / ZGranuleSize) * 3 * 1.2;
|
||||
const size_t required_max_map_count = (max_capacity / ZGranuleSize) * 3 * 1.2;
|
||||
if (actual_max_map_count < required_max_map_count) {
|
||||
log_warning(gc)("***** WARNING! INCORRECT SYSTEM CONFIGURATION DETECTED! *****");
|
||||
log_warning(gc)("The system limit on number of memory mappings per process might be too low for the given");
|
||||
log_warning(gc)("max Java heap size (" SIZE_FORMAT "M). Please adjust %s to allow for at",
|
||||
max / M, filename);
|
||||
log_warning(gc)("least " SIZE_FORMAT " mappings (current limit is " SIZE_FORMAT "). Continuing execution "
|
||||
"with the current", required_max_map_count, actual_max_map_count);
|
||||
log_warning(gc)("limit could lead to a fatal error, due to failure to map memory.");
|
||||
log_warning_p(gc)("***** WARNING! INCORRECT SYSTEM CONFIGURATION DETECTED! *****");
|
||||
log_warning_p(gc)("The system limit on number of memory mappings per process might be too low for the given");
|
||||
log_warning_p(gc)("max Java heap size (" SIZE_FORMAT "M). Please adjust %s to allow for at",
|
||||
max_capacity / M, filename);
|
||||
log_warning_p(gc)("least " SIZE_FORMAT " mappings (current limit is " SIZE_FORMAT "). Continuing execution "
|
||||
"with the current", required_max_map_count, actual_max_map_count);
|
||||
log_warning_p(gc)("limit could lead to a premature OutOfMemoryError being thrown, due to failure to map memory.");
|
||||
}
|
||||
}
|
||||
|
||||
void ZPhysicalMemoryBacking::warn_commit_limits(size_t max) const {
|
||||
void ZPhysicalMemoryBacking::warn_commit_limits(size_t max_capacity) const {
|
||||
// Warn if available space is too low
|
||||
warn_available_space(max);
|
||||
warn_available_space(max_capacity);
|
||||
|
||||
// Warn if max map count is too low
|
||||
warn_max_map_count(max);
|
||||
}
|
||||
|
||||
size_t ZPhysicalMemoryBacking::size() const {
|
||||
return _size;
|
||||
warn_max_map_count(max_capacity);
|
||||
}
|
||||
|
||||
bool ZPhysicalMemoryBacking::is_tmpfs() const {
|
||||
@ -379,18 +384,6 @@ bool ZPhysicalMemoryBacking::tmpfs_supports_transparent_huge_pages() const {
|
||||
return access(ZFILENAME_SHMEM_ENABLED, R_OK) == 0;
|
||||
}
|
||||
|
||||
ZErrno ZPhysicalMemoryBacking::fallocate_compat_ftruncate(size_t size) const {
|
||||
while (ftruncate(_fd, size) == -1) {
|
||||
if (errno != EINTR) {
|
||||
// Failed
|
||||
return errno;
|
||||
}
|
||||
}
|
||||
|
||||
// Success
|
||||
return 0;
|
||||
}
|
||||
|
||||
ZErrno ZPhysicalMemoryBacking::fallocate_compat_mmap_hugetlbfs(size_t offset, size_t length, bool touch) const {
|
||||
// On hugetlbfs, mapping a file segment will fail immediately, without
|
||||
// the need to touch the mapped pages first, if there aren't enough huge
|
||||
@ -484,49 +477,21 @@ ZErrno ZPhysicalMemoryBacking::fallocate_compat_pwrite(size_t offset, size_t len
|
||||
return 0;
|
||||
}
|
||||
|
||||
ZErrno ZPhysicalMemoryBacking::fallocate_fill_hole_compat(size_t offset, size_t length) {
|
||||
ZErrno ZPhysicalMemoryBacking::fallocate_fill_hole_compat(size_t offset, size_t length) const {
|
||||
// fallocate(2) is only supported by tmpfs since Linux 3.5, and by hugetlbfs
|
||||
// since Linux 4.3. When fallocate(2) is not supported we emulate it using
|
||||
// mmap/munmap (for hugetlbfs and tmpfs with transparent huge pages) or pwrite
|
||||
// (for tmpfs without transparent huge pages and other filesystem types).
|
||||
|
||||
const size_t end = offset + length;
|
||||
if (end > _size) {
|
||||
// Increase file size
|
||||
const ZErrno err = fallocate_compat_ftruncate(end);
|
||||
if (err) {
|
||||
// Failed
|
||||
return err;
|
||||
}
|
||||
if (ZLargePages::is_explicit()) {
|
||||
return fallocate_compat_mmap_hugetlbfs(offset, length, false /* touch */);
|
||||
} else if (ZLargePages::is_transparent()) {
|
||||
return fallocate_compat_mmap_tmpfs(offset, length);
|
||||
} else {
|
||||
return fallocate_compat_pwrite(offset, length);
|
||||
}
|
||||
|
||||
// Allocate backing memory
|
||||
const ZErrno err = ZLargePages::is_explicit()
|
||||
? fallocate_compat_mmap_hugetlbfs(offset, length, false /* touch */)
|
||||
: (ZLargePages::is_transparent()
|
||||
? fallocate_compat_mmap_tmpfs(offset, length)
|
||||
: fallocate_compat_pwrite(offset, length));
|
||||
|
||||
if (err) {
|
||||
if (end > _size) {
|
||||
// Restore file size
|
||||
fallocate_compat_ftruncate(_size);
|
||||
}
|
||||
|
||||
// Failed
|
||||
return err;
|
||||
}
|
||||
|
||||
if (end > _size) {
|
||||
// Record new file size
|
||||
_size = end;
|
||||
}
|
||||
|
||||
// Success
|
||||
return 0;
|
||||
}
|
||||
|
||||
ZErrno ZPhysicalMemoryBacking::fallocate_fill_hole_syscall(size_t offset, size_t length) {
|
||||
ZErrno ZPhysicalMemoryBacking::fallocate_fill_hole_syscall(size_t offset, size_t length) const {
|
||||
const int mode = 0; // Allocate
|
||||
const int res = ZSyscall::fallocate(_fd, mode, offset, length);
|
||||
if (res == -1) {
|
||||
@ -534,17 +499,11 @@ ZErrno ZPhysicalMemoryBacking::fallocate_fill_hole_syscall(size_t offset, size_t
|
||||
return errno;
|
||||
}
|
||||
|
||||
const size_t end = offset + length;
|
||||
if (end > _size) {
|
||||
// Record new file size
|
||||
_size = end;
|
||||
}
|
||||
|
||||
// Success
|
||||
return 0;
|
||||
}
|
||||
|
||||
ZErrno ZPhysicalMemoryBacking::fallocate_fill_hole(size_t offset, size_t length) {
|
||||
ZErrno ZPhysicalMemoryBacking::fallocate_fill_hole(size_t offset, size_t length) const {
|
||||
// Using compat mode is more efficient when allocating space on hugetlbfs.
|
||||
// Note that allocating huge pages this way will only reserve them, and not
|
||||
// associate them with segments of the file. We must guarantee that we at
|
||||
@ -564,14 +523,14 @@ ZErrno ZPhysicalMemoryBacking::fallocate_fill_hole(size_t offset, size_t length)
|
||||
}
|
||||
|
||||
// Not supported
|
||||
log_debug(gc)("Falling back to fallocate() compatibility mode");
|
||||
log_debug_p(gc)("Falling back to fallocate() compatibility mode");
|
||||
z_fallocate_supported = false;
|
||||
}
|
||||
|
||||
return fallocate_fill_hole_compat(offset, length);
|
||||
}
|
||||
|
||||
ZErrno ZPhysicalMemoryBacking::fallocate_punch_hole(size_t offset, size_t length) {
|
||||
ZErrno ZPhysicalMemoryBacking::fallocate_punch_hole(size_t offset, size_t length) const {
|
||||
if (ZLargePages::is_explicit()) {
|
||||
// We can only punch hole in pages that have been touched. Non-touched
|
||||
// pages are only reserved, and not associated with any specific file
|
||||
@ -594,7 +553,7 @@ ZErrno ZPhysicalMemoryBacking::fallocate_punch_hole(size_t offset, size_t length
|
||||
return 0;
|
||||
}
|
||||
|
||||
ZErrno ZPhysicalMemoryBacking::split_and_fallocate(bool punch_hole, size_t offset, size_t length) {
|
||||
ZErrno ZPhysicalMemoryBacking::split_and_fallocate(bool punch_hole, size_t offset, size_t length) const {
|
||||
// Try first half
|
||||
const size_t offset0 = offset;
|
||||
const size_t length0 = align_up(length / 2, _block_size);
|
||||
@ -615,7 +574,7 @@ ZErrno ZPhysicalMemoryBacking::split_and_fallocate(bool punch_hole, size_t offse
|
||||
return 0;
|
||||
}
|
||||
|
||||
ZErrno ZPhysicalMemoryBacking::fallocate(bool punch_hole, size_t offset, size_t length) {
|
||||
ZErrno ZPhysicalMemoryBacking::fallocate(bool punch_hole, size_t offset, size_t length) const {
|
||||
assert(is_aligned(offset, _block_size), "Invalid offset");
|
||||
assert(is_aligned(length, _block_size), "Invalid length");
|
||||
|
||||
@ -631,7 +590,7 @@ ZErrno ZPhysicalMemoryBacking::fallocate(bool punch_hole, size_t offset, size_t
|
||||
return err;
|
||||
}
|
||||
|
||||
bool ZPhysicalMemoryBacking::commit_inner(size_t offset, size_t length) {
|
||||
bool ZPhysicalMemoryBacking::commit_inner(size_t offset, size_t length) const {
|
||||
log_trace(gc, heap)("Committing memory: " SIZE_FORMAT "M-" SIZE_FORMAT "M (" SIZE_FORMAT "M)",
|
||||
offset / M, (offset + length) / M, length / M);
|
||||
|
||||
@ -645,7 +604,7 @@ retry:
|
||||
// will fail, since there is a delay between process termination and the
|
||||
// huge pages owned by that process being returned to the huge page pool
|
||||
// and made available for new allocations.
|
||||
log_debug(gc, init)("Failed to commit memory (%s), retrying", err.to_string());
|
||||
log_debug_p(gc, init)("Failed to commit memory (%s), retrying", err.to_string());
|
||||
|
||||
// Wait and retry in one second, in the hope that huge pages will be
|
||||
// available by then.
|
||||
@ -654,7 +613,7 @@ retry:
|
||||
}
|
||||
|
||||
// Failed
|
||||
log_error(gc)("Failed to commit memory (%s)", err.to_string());
|
||||
log_error_p(gc)("Failed to commit memory (%s)", err.to_string());
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -668,7 +627,7 @@ static int offset_to_node(size_t offset) {
|
||||
return mapping->at((int)nindex);
|
||||
}
|
||||
|
||||
size_t ZPhysicalMemoryBacking::commit_numa_interleaved(size_t offset, size_t length) {
|
||||
size_t ZPhysicalMemoryBacking::commit_numa_interleaved(size_t offset, size_t length) const {
|
||||
size_t committed = 0;
|
||||
|
||||
// Commit one granule at a time, so that each granule
|
||||
@ -693,7 +652,7 @@ size_t ZPhysicalMemoryBacking::commit_numa_interleaved(size_t offset, size_t len
|
||||
return committed;
|
||||
}
|
||||
|
||||
size_t ZPhysicalMemoryBacking::commit_default(size_t offset, size_t length) {
|
||||
size_t ZPhysicalMemoryBacking::commit_default(size_t offset, size_t length) const {
|
||||
// Try to commit the whole region
|
||||
if (commit_inner(offset, length)) {
|
||||
// Success
|
||||
@ -721,7 +680,7 @@ size_t ZPhysicalMemoryBacking::commit_default(size_t offset, size_t length) {
|
||||
}
|
||||
}
|
||||
|
||||
size_t ZPhysicalMemoryBacking::commit(size_t offset, size_t length) {
|
||||
size_t ZPhysicalMemoryBacking::commit(size_t offset, size_t length) const {
|
||||
if (ZNUMA::is_enabled() && !ZLargePages::is_explicit()) {
|
||||
// To get granule-level NUMA interleaving when using non-large pages,
|
||||
// we must explicitly interleave the memory at commit/fallocate time.
|
||||
@ -731,7 +690,7 @@ size_t ZPhysicalMemoryBacking::commit(size_t offset, size_t length) {
|
||||
return commit_default(offset, length);
|
||||
}
|
||||
|
||||
size_t ZPhysicalMemoryBacking::uncommit(size_t offset, size_t length) {
|
||||
size_t ZPhysicalMemoryBacking::uncommit(size_t offset, size_t length) const {
|
||||
log_trace(gc, heap)("Uncommitting memory: " SIZE_FORMAT "M-" SIZE_FORMAT "M (" SIZE_FORMAT "M)",
|
||||
offset / M, (offset + length) / M, length / M);
|
||||
|
||||
|
||||
@ -35,8 +35,8 @@ private:
|
||||
size_t _available;
|
||||
bool _initialized;
|
||||
|
||||
void warn_available_space(size_t max) const;
|
||||
void warn_max_map_count(size_t max) const;
|
||||
void warn_available_space(size_t max_capacity) const;
|
||||
void warn_max_map_count(size_t max_capacity) const;
|
||||
|
||||
int create_mem_fd(const char* name) const;
|
||||
int create_file_fd(const char* name) const;
|
||||
@ -46,32 +46,29 @@ private:
|
||||
bool is_hugetlbfs() const;
|
||||
bool tmpfs_supports_transparent_huge_pages() const;
|
||||
|
||||
ZErrno fallocate_compat_ftruncate(size_t size) const;
|
||||
ZErrno fallocate_compat_mmap_hugetlbfs(size_t offset, size_t length, bool touch) const;
|
||||
ZErrno fallocate_compat_mmap_tmpfs(size_t offset, size_t length) const;
|
||||
ZErrno fallocate_compat_pwrite(size_t offset, size_t length) const;
|
||||
ZErrno fallocate_fill_hole_compat(size_t offset, size_t length);
|
||||
ZErrno fallocate_fill_hole_syscall(size_t offset, size_t length);
|
||||
ZErrno fallocate_fill_hole(size_t offset, size_t length);
|
||||
ZErrno fallocate_punch_hole(size_t offset, size_t length);
|
||||
ZErrno split_and_fallocate(bool punch_hole, size_t offset, size_t length);
|
||||
ZErrno fallocate(bool punch_hole, size_t offset, size_t length);
|
||||
ZErrno fallocate_fill_hole_compat(size_t offset, size_t length) const;
|
||||
ZErrno fallocate_fill_hole_syscall(size_t offset, size_t length) const;
|
||||
ZErrno fallocate_fill_hole(size_t offset, size_t length) const;
|
||||
ZErrno fallocate_punch_hole(size_t offset, size_t length) const;
|
||||
ZErrno split_and_fallocate(bool punch_hole, size_t offset, size_t length) const;
|
||||
ZErrno fallocate(bool punch_hole, size_t offset, size_t length) const;
|
||||
|
||||
bool commit_inner(size_t offset, size_t length);
|
||||
size_t commit_numa_interleaved(size_t offset, size_t length);
|
||||
size_t commit_default(size_t offset, size_t length);
|
||||
bool commit_inner(size_t offset, size_t length) const;
|
||||
size_t commit_numa_interleaved(size_t offset, size_t length) const;
|
||||
size_t commit_default(size_t offset, size_t length) const;
|
||||
|
||||
public:
|
||||
ZPhysicalMemoryBacking();
|
||||
ZPhysicalMemoryBacking(size_t max_capacity);
|
||||
|
||||
bool is_initialized() const;
|
||||
|
||||
void warn_commit_limits(size_t max) const;
|
||||
void warn_commit_limits(size_t max_capacity) const;
|
||||
|
||||
size_t size() const;
|
||||
|
||||
size_t commit(size_t offset, size_t length);
|
||||
size_t uncommit(size_t offset, size_t length);
|
||||
size_t commit(size_t offset, size_t length) const;
|
||||
size_t uncommit(size_t offset, size_t length) const;
|
||||
|
||||
void map(uintptr_t addr, size_t size, uintptr_t offset) const;
|
||||
void unmap(uintptr_t addr, size_t size) const;
|
||||
|
||||
@ -2089,40 +2089,42 @@ void os::print_dll_info(outputStream *st) {
|
||||
}
|
||||
}
|
||||
|
||||
int os::get_loaded_modules_info(os::LoadedModulesCallbackFunc callback, void *param) {
|
||||
FILE *procmapsFile = NULL;
|
||||
struct loaded_modules_info_param {
|
||||
os::LoadedModulesCallbackFunc callback;
|
||||
void *param;
|
||||
};
|
||||
|
||||
// Open the procfs maps file for the current process
|
||||
if ((procmapsFile = fopen("/proc/self/maps", "r")) != NULL) {
|
||||
// Allocate PATH_MAX for file name plus a reasonable size for other fields.
|
||||
char line[PATH_MAX + 100];
|
||||
static int dl_iterate_callback(struct dl_phdr_info *info, size_t size, void *data) {
|
||||
if ((info->dlpi_name == NULL) || (*info->dlpi_name == '\0')) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Read line by line from 'file'
|
||||
while (fgets(line, sizeof(line), procmapsFile) != NULL) {
|
||||
u8 base, top, inode;
|
||||
char name[sizeof(line)];
|
||||
struct loaded_modules_info_param *callback_param = reinterpret_cast<struct loaded_modules_info_param *>(data);
|
||||
address base = NULL;
|
||||
address top = NULL;
|
||||
for (int idx = 0; idx < info->dlpi_phnum; idx++) {
|
||||
const ElfW(Phdr) *phdr = info->dlpi_phdr + idx;
|
||||
if (phdr->p_type == PT_LOAD) {
|
||||
address raw_phdr_base = reinterpret_cast<address>(info->dlpi_addr + phdr->p_vaddr);
|
||||
|
||||
// Parse fields from line, discard perms, offset and device
|
||||
int matches = sscanf(line, UINT64_FORMAT_X "-" UINT64_FORMAT_X " %*s %*s %*s " INT64_FORMAT " %s",
|
||||
&base, &top, &inode, name);
|
||||
// the last entry 'name' is empty for some entries, so we might have 3 matches instead of 4 for some lines
|
||||
if (matches < 3) continue;
|
||||
if (matches == 3) name[0] = '\0';
|
||||
address phdr_base = align_down(raw_phdr_base, phdr->p_align);
|
||||
if ((base == NULL) || (base > phdr_base)) {
|
||||
base = phdr_base;
|
||||
}
|
||||
|
||||
// Filter by inode 0 so that we only get file system mapped files.
|
||||
if (inode != 0) {
|
||||
|
||||
// Call callback with the fields of interest
|
||||
if(callback(name, (address)base, (address)top, param)) {
|
||||
// Oops abort, callback aborted
|
||||
fclose(procmapsFile);
|
||||
return 1;
|
||||
}
|
||||
address phdr_top = align_up(raw_phdr_base + phdr->p_memsz, phdr->p_align);
|
||||
if ((top == NULL) || (top < phdr_top)) {
|
||||
top = phdr_top;
|
||||
}
|
||||
}
|
||||
fclose(procmapsFile);
|
||||
}
|
||||
return 0;
|
||||
|
||||
return callback_param->callback(info->dlpi_name, base, top, callback_param->param);
|
||||
}
|
||||
|
||||
int os::get_loaded_modules_info(os::LoadedModulesCallbackFunc callback, void *param) {
|
||||
struct loaded_modules_info_param callback_param = {callback, param};
|
||||
return dl_iterate_phdr(&dl_iterate_callback, &callback_param);
|
||||
}
|
||||
|
||||
void os::print_os_info_brief(outputStream* st) {
|
||||
|
||||
@ -370,6 +370,10 @@ void os::split_reserved_memory(char *base, size_t size, size_t split) {
|
||||
assert(split > 0, "Sanity");
|
||||
assert(is_aligned(base, os::vm_allocation_granularity()), "Sanity");
|
||||
assert(is_aligned(split_address, os::vm_allocation_granularity()), "Sanity");
|
||||
|
||||
// NMT: tell NMT to track both parts individually from now on.
|
||||
MemTracker::record_virtual_memory_split_reserved(base, size, split);
|
||||
|
||||
}
|
||||
|
||||
int os::vsnprintf(char* buf, size_t len, const char* fmt, va_list args) {
|
||||
|
||||
@ -35,22 +35,17 @@
|
||||
// committing and uncommitting, each ZGranuleSize'd chunk is mapped to
|
||||
// a separate paging file mapping.
|
||||
|
||||
ZPhysicalMemoryBacking::ZPhysicalMemoryBacking() :
|
||||
_handles(MaxHeapSize),
|
||||
_size(0) {}
|
||||
ZPhysicalMemoryBacking::ZPhysicalMemoryBacking(size_t max_capacity) :
|
||||
_handles(max_capacity) {}
|
||||
|
||||
bool ZPhysicalMemoryBacking::is_initialized() const {
|
||||
return true;
|
||||
}
|
||||
|
||||
void ZPhysicalMemoryBacking::warn_commit_limits(size_t max) const {
|
||||
void ZPhysicalMemoryBacking::warn_commit_limits(size_t max_capacity) const {
|
||||
// Does nothing
|
||||
}
|
||||
|
||||
size_t ZPhysicalMemoryBacking::size() const {
|
||||
return _size;
|
||||
}
|
||||
|
||||
HANDLE ZPhysicalMemoryBacking::get_handle(uintptr_t offset) const {
|
||||
HANDLE const handle = _handles.get(offset);
|
||||
assert(handle != 0, "Should be set");
|
||||
@ -95,15 +90,7 @@ size_t ZPhysicalMemoryBacking::commit(size_t offset, size_t length) {
|
||||
log_trace(gc, heap)("Committing memory: " SIZE_FORMAT "M-" SIZE_FORMAT "M (" SIZE_FORMAT "M)",
|
||||
offset / M, (offset + length) / M, length / M);
|
||||
|
||||
const size_t committed = commit_from_paging_file(offset, length);
|
||||
|
||||
const size_t end = offset + committed;
|
||||
if (end > _size) {
|
||||
// Update size
|
||||
_size = end;
|
||||
}
|
||||
|
||||
return committed;
|
||||
return commit_from_paging_file(offset, length);
|
||||
}
|
||||
|
||||
size_t ZPhysicalMemoryBacking::uncommit(size_t offset, size_t length) {
|
||||
|
||||
@ -31,7 +31,6 @@
|
||||
class ZPhysicalMemoryBacking {
|
||||
private:
|
||||
ZGranuleMap<HANDLE> _handles;
|
||||
size_t _size;
|
||||
|
||||
HANDLE get_handle(uintptr_t offset) const;
|
||||
void put_handle(uintptr_t offset, HANDLE handle);
|
||||
@ -41,13 +40,11 @@ private:
|
||||
size_t uncommit_from_paging_file(size_t offset, size_t size);
|
||||
|
||||
public:
|
||||
ZPhysicalMemoryBacking();
|
||||
ZPhysicalMemoryBacking(size_t max_capacity);
|
||||
|
||||
bool is_initialized() const;
|
||||
|
||||
void warn_commit_limits(size_t max) const;
|
||||
|
||||
size_t size() const;
|
||||
void warn_commit_limits(size_t max_capacity) const;
|
||||
|
||||
size_t commit(size_t offset, size_t length);
|
||||
size_t uncommit(size_t offset, size_t length);
|
||||
|
||||
@ -22,8 +22,8 @@
|
||||
*/
|
||||
|
||||
#include "precompiled.hpp"
|
||||
#include "gc/shared/gcLogPrecious.hpp"
|
||||
#include "gc/z/zSyscall_windows.hpp"
|
||||
#include "logging/log.hpp"
|
||||
#include "runtime/java.hpp"
|
||||
#include "runtime/os.hpp"
|
||||
|
||||
@ -38,13 +38,13 @@ static void lookup_symbol(Fn*& fn, const char* library, const char* symbol) {
|
||||
char ebuf[1024];
|
||||
void* const handle = os::dll_load(library, ebuf, sizeof(ebuf));
|
||||
if (handle == NULL) {
|
||||
log_error(gc)("Failed to load library: %s", library);
|
||||
log_error_p(gc)("Failed to load library: %s", library);
|
||||
vm_exit_during_initialization("ZGC requires Windows version 1803 or later");
|
||||
}
|
||||
|
||||
fn = reinterpret_cast<Fn*>(os::dll_lookup(handle, symbol));
|
||||
if (fn == NULL) {
|
||||
log_error(gc)("Failed to lookup symbol: %s", symbol);
|
||||
log_error_p(gc)("Failed to lookup symbol: %s", symbol);
|
||||
vm_exit_during_initialization("ZGC requires Windows version 1803 or later");
|
||||
}
|
||||
}
|
||||
|
||||
@ -3237,6 +3237,10 @@ void os::split_reserved_memory(char *base, size_t size, size_t split) {
|
||||
reserve_memory(split, base);
|
||||
reserve_memory(size - split, split_address);
|
||||
|
||||
// NMT: nothing to do here. Since Windows implements the split by
|
||||
// releasing and re-reserving memory, the parts are already registered
|
||||
// as individual mappings with NMT.
|
||||
|
||||
}
|
||||
|
||||
// Multiple threads can race in this code but it's not possible to unmap small sections of
|
||||
|
||||
@ -438,25 +438,28 @@ JVM_handle_aix_signal(int sig, siginfo_t* info, void* ucVoid, int abort_if_unrec
|
||||
|
||||
// stop on request
|
||||
else if (sig == SIGTRAP && (stop_type = nativeInstruction_at(pc)->get_stop_type()) != -1) {
|
||||
const char *msg = NULL,
|
||||
*detail_msg = (const char*)(uc->uc_mcontext.jmp_context.gpr[0]);
|
||||
bool msg_present = (stop_type & MacroAssembler::stop_msg_present);
|
||||
stop_type = (stop_type &~ MacroAssembler::stop_msg_present);
|
||||
|
||||
const char *msg = NULL;
|
||||
switch (stop_type) {
|
||||
case MacroAssembler::stop_stop : msg = "stop"; break;
|
||||
case MacroAssembler::stop_untested : msg = "untested"; break;
|
||||
case MacroAssembler::stop_unimplemented : msg = "unimplemented"; break;
|
||||
case MacroAssembler::stop_shouldnotreachhere: msg = "shouldnotreachhere"; detail_msg = NULL; break;
|
||||
case MacroAssembler::stop_stop : msg = "stop"; break;
|
||||
case MacroAssembler::stop_untested : msg = "untested"; break;
|
||||
case MacroAssembler::stop_unimplemented : msg = "unimplemented"; break;
|
||||
case MacroAssembler::stop_shouldnotreachhere: msg = "shouldnotreachhere"; break;
|
||||
default: msg = "unknown"; break;
|
||||
}
|
||||
if (detail_msg == NULL) {
|
||||
detail_msg = "no details provided";
|
||||
}
|
||||
|
||||
const char **detail_msg_ptr = (const char**)(pc + 4);
|
||||
const char *detail_msg = msg_present ? *detail_msg_ptr : "no details provided";
|
||||
|
||||
if (TraceTraps) {
|
||||
tty->print_cr("trap: %s: %s (SIGTRAP, stop type %d)", msg, detail_msg, stop_type);
|
||||
}
|
||||
|
||||
va_list detail_args;
|
||||
VMError::report_and_die(t, ucVoid, NULL, 0, msg, detail_msg, detail_args);
|
||||
VMError::report_and_die(INTERNAL_ERROR, msg, detail_msg, detail_args, thread,
|
||||
pc, info, ucVoid, NULL, 0, 0);
|
||||
va_end(detail_args);
|
||||
}
|
||||
|
||||
|
||||
@ -468,25 +468,28 @@ JVM_handle_linux_signal(int sig,
|
||||
|
||||
// stop on request
|
||||
else if (sig == SIGTRAP && (stop_type = nativeInstruction_at(pc)->get_stop_type()) != -1) {
|
||||
const char *msg = NULL,
|
||||
*detail_msg = (const char*)(uc->uc_mcontext.regs->gpr[0]);
|
||||
bool msg_present = (stop_type & MacroAssembler::stop_msg_present);
|
||||
stop_type = (stop_type &~ MacroAssembler::stop_msg_present);
|
||||
|
||||
const char *msg = NULL;
|
||||
switch (stop_type) {
|
||||
case MacroAssembler::stop_stop : msg = "stop"; break;
|
||||
case MacroAssembler::stop_untested : msg = "untested"; break;
|
||||
case MacroAssembler::stop_unimplemented : msg = "unimplemented"; break;
|
||||
case MacroAssembler::stop_shouldnotreachhere: msg = "shouldnotreachhere"; detail_msg = NULL; break;
|
||||
case MacroAssembler::stop_stop : msg = "stop"; break;
|
||||
case MacroAssembler::stop_untested : msg = "untested"; break;
|
||||
case MacroAssembler::stop_unimplemented : msg = "unimplemented"; break;
|
||||
case MacroAssembler::stop_shouldnotreachhere: msg = "shouldnotreachhere"; break;
|
||||
default: msg = "unknown"; break;
|
||||
}
|
||||
if (detail_msg == NULL) {
|
||||
detail_msg = "no details provided";
|
||||
}
|
||||
|
||||
const char **detail_msg_ptr = (const char**)(pc + 4);
|
||||
const char *detail_msg = msg_present ? *detail_msg_ptr : "no details provided";
|
||||
|
||||
if (TraceTraps) {
|
||||
tty->print_cr("trap: %s: %s (SIGTRAP, stop type %d)", msg, detail_msg, stop_type);
|
||||
}
|
||||
|
||||
va_list detail_args;
|
||||
VMError::report_and_die(t, ucVoid, NULL, 0, msg, detail_msg, detail_args);
|
||||
VMError::report_and_die(INTERNAL_ERROR, msg, detail_msg, detail_args, thread,
|
||||
pc, info, ucVoid, NULL, 0, 0);
|
||||
va_end(detail_args);
|
||||
}
|
||||
|
||||
|
||||
@ -4050,7 +4050,7 @@ bool GraphBuilder::try_method_handle_inline(ciMethod* callee, bool ignore_return
|
||||
if (ciMethod::is_consistent_info(callee, target)) {
|
||||
Bytecodes::Code bc = target->is_static() ? Bytecodes::_invokestatic : Bytecodes::_invokevirtual;
|
||||
ignore_return = ignore_return || (callee->return_type()->is_void() && !target->return_type()->is_void());
|
||||
if (try_inline(target, /*holder_known*/ true, ignore_return, bc)) {
|
||||
if (try_inline(target, /*holder_known*/ !callee->is_static(), ignore_return, bc)) {
|
||||
return true;
|
||||
}
|
||||
} else {
|
||||
@ -4116,7 +4116,7 @@ bool GraphBuilder::try_method_handle_inline(ciMethod* callee, bool ignore_return
|
||||
// We don't do CHA here so only inline static and statically bindable methods.
|
||||
if (target->is_static() || target->can_be_statically_bound()) {
|
||||
Bytecodes::Code bc = target->is_static() ? Bytecodes::_invokestatic : Bytecodes::_invokevirtual;
|
||||
if (try_inline(target, /*holder_known*/ true, ignore_return, bc)) {
|
||||
if (try_inline(target, /*holder_known*/ !callee->is_static(), ignore_return, bc)) {
|
||||
return true;
|
||||
}
|
||||
} else {
|
||||
|
||||
@ -236,30 +236,27 @@ void LIR_Op2::verify() const {
|
||||
}
|
||||
|
||||
|
||||
LIR_OpBranch::LIR_OpBranch(LIR_Condition cond, BasicType type, BlockBegin* block)
|
||||
LIR_OpBranch::LIR_OpBranch(LIR_Condition cond, BlockBegin* block)
|
||||
: LIR_Op(lir_branch, LIR_OprFact::illegalOpr, (CodeEmitInfo*)NULL)
|
||||
, _cond(cond)
|
||||
, _type(type)
|
||||
, _label(block->label())
|
||||
, _block(block)
|
||||
, _ublock(NULL)
|
||||
, _stub(NULL) {
|
||||
}
|
||||
|
||||
LIR_OpBranch::LIR_OpBranch(LIR_Condition cond, BasicType type, CodeStub* stub) :
|
||||
LIR_OpBranch::LIR_OpBranch(LIR_Condition cond, CodeStub* stub) :
|
||||
LIR_Op(lir_branch, LIR_OprFact::illegalOpr, (CodeEmitInfo*)NULL)
|
||||
, _cond(cond)
|
||||
, _type(type)
|
||||
, _label(stub->entry())
|
||||
, _block(NULL)
|
||||
, _ublock(NULL)
|
||||
, _stub(stub) {
|
||||
}
|
||||
|
||||
LIR_OpBranch::LIR_OpBranch(LIR_Condition cond, BasicType type, BlockBegin* block, BlockBegin* ublock)
|
||||
LIR_OpBranch::LIR_OpBranch(LIR_Condition cond, BlockBegin* block, BlockBegin* ublock)
|
||||
: LIR_Op(lir_cond_float_branch, LIR_OprFact::illegalOpr, (CodeEmitInfo*)NULL)
|
||||
, _cond(cond)
|
||||
, _type(type)
|
||||
, _label(block->label())
|
||||
, _block(block)
|
||||
, _ublock(ublock)
|
||||
@ -1403,7 +1400,7 @@ void LIR_List::null_check(LIR_Opr opr, CodeEmitInfo* info, bool deoptimize_on_nu
|
||||
// Emit an explicit null check and deoptimize if opr is null
|
||||
CodeStub* deopt = new DeoptimizeStub(info, Deoptimization::Reason_null_check, Deoptimization::Action_none);
|
||||
cmp(lir_cond_equal, opr, LIR_OprFact::oopConst(NULL));
|
||||
branch(lir_cond_equal, T_OBJECT, deopt);
|
||||
branch(lir_cond_equal, deopt);
|
||||
} else {
|
||||
// Emit an implicit null check
|
||||
append(new LIR_Op1(lir_null_check, opr, info));
|
||||
|
||||
@ -1404,30 +1404,27 @@ class LIR_OpBranch: public LIR_Op {
|
||||
|
||||
private:
|
||||
LIR_Condition _cond;
|
||||
BasicType _type;
|
||||
Label* _label;
|
||||
BlockBegin* _block; // if this is a branch to a block, this is the block
|
||||
BlockBegin* _ublock; // if this is a float-branch, this is the unorderd block
|
||||
CodeStub* _stub; // if this is a branch to a stub, this is the stub
|
||||
|
||||
public:
|
||||
LIR_OpBranch(LIR_Condition cond, BasicType type, Label* lbl)
|
||||
LIR_OpBranch(LIR_Condition cond, Label* lbl)
|
||||
: LIR_Op(lir_branch, LIR_OprFact::illegalOpr, (CodeEmitInfo*) NULL)
|
||||
, _cond(cond)
|
||||
, _type(type)
|
||||
, _label(lbl)
|
||||
, _block(NULL)
|
||||
, _ublock(NULL)
|
||||
, _stub(NULL) { }
|
||||
|
||||
LIR_OpBranch(LIR_Condition cond, BasicType type, BlockBegin* block);
|
||||
LIR_OpBranch(LIR_Condition cond, BasicType type, CodeStub* stub);
|
||||
LIR_OpBranch(LIR_Condition cond, BlockBegin* block);
|
||||
LIR_OpBranch(LIR_Condition cond, CodeStub* stub);
|
||||
|
||||
// for unordered comparisons
|
||||
LIR_OpBranch(LIR_Condition cond, BasicType type, BlockBegin* block, BlockBegin* ublock);
|
||||
LIR_OpBranch(LIR_Condition cond, BlockBegin* block, BlockBegin* ublock);
|
||||
|
||||
LIR_Condition cond() const { return _cond; }
|
||||
BasicType type() const { return _type; }
|
||||
Label* label() const { return _label; }
|
||||
BlockBegin* block() const { return _block; }
|
||||
BlockBegin* ublock() const { return _ublock; }
|
||||
@ -2176,23 +2173,25 @@ class LIR_List: public CompilationResourceObj {
|
||||
|
||||
// jump is an unconditional branch
|
||||
void jump(BlockBegin* block) {
|
||||
append(new LIR_OpBranch(lir_cond_always, T_ILLEGAL, block));
|
||||
append(new LIR_OpBranch(lir_cond_always, block));
|
||||
}
|
||||
void jump(CodeStub* stub) {
|
||||
append(new LIR_OpBranch(lir_cond_always, T_ILLEGAL, stub));
|
||||
append(new LIR_OpBranch(lir_cond_always, stub));
|
||||
}
|
||||
void branch(LIR_Condition cond, BasicType type, Label* lbl) { append(new LIR_OpBranch(cond, type, lbl)); }
|
||||
void branch(LIR_Condition cond, BasicType type, BlockBegin* block) {
|
||||
assert(type != T_FLOAT && type != T_DOUBLE, "no fp comparisons");
|
||||
append(new LIR_OpBranch(cond, type, block));
|
||||
void branch(LIR_Condition cond, Label* lbl) {
|
||||
append(new LIR_OpBranch(cond, lbl));
|
||||
}
|
||||
void branch(LIR_Condition cond, BasicType type, CodeStub* stub) {
|
||||
assert(type != T_FLOAT && type != T_DOUBLE, "no fp comparisons");
|
||||
append(new LIR_OpBranch(cond, type, stub));
|
||||
// Should not be used for fp comparisons
|
||||
void branch(LIR_Condition cond, BlockBegin* block) {
|
||||
append(new LIR_OpBranch(cond, block));
|
||||
}
|
||||
void branch(LIR_Condition cond, BasicType type, BlockBegin* block, BlockBegin* unordered) {
|
||||
assert(type == T_FLOAT || type == T_DOUBLE, "fp comparisons only");
|
||||
append(new LIR_OpBranch(cond, type, block, unordered));
|
||||
// Should not be used for fp comparisons
|
||||
void branch(LIR_Condition cond, CodeStub* stub) {
|
||||
append(new LIR_OpBranch(cond, stub));
|
||||
}
|
||||
// Should only be used for fp comparisons
|
||||
void branch(LIR_Condition cond, BlockBegin* block, BlockBegin* unordered) {
|
||||
append(new LIR_OpBranch(cond, block, unordered));
|
||||
}
|
||||
|
||||
void shift_left(LIR_Opr value, LIR_Opr count, LIR_Opr dst, LIR_Opr tmp);
|
||||
|
||||
@ -478,11 +478,11 @@ void LIRGenerator::array_range_check(LIR_Opr array, LIR_Opr index,
|
||||
if (index->is_constant()) {
|
||||
cmp_mem_int(lir_cond_belowEqual, array, arrayOopDesc::length_offset_in_bytes(),
|
||||
index->as_jint(), null_check_info);
|
||||
__ branch(lir_cond_belowEqual, T_INT, stub); // forward branch
|
||||
__ branch(lir_cond_belowEqual, stub); // forward branch
|
||||
} else {
|
||||
cmp_reg_mem(lir_cond_aboveEqual, index, array,
|
||||
arrayOopDesc::length_offset_in_bytes(), T_INT, null_check_info);
|
||||
__ branch(lir_cond_aboveEqual, T_INT, stub); // forward branch
|
||||
__ branch(lir_cond_aboveEqual, stub); // forward branch
|
||||
}
|
||||
}
|
||||
|
||||
@ -491,11 +491,11 @@ void LIRGenerator::nio_range_check(LIR_Opr buffer, LIR_Opr index, LIR_Opr result
|
||||
CodeStub* stub = new RangeCheckStub(info, index);
|
||||
if (index->is_constant()) {
|
||||
cmp_mem_int(lir_cond_belowEqual, buffer, java_nio_Buffer::limit_offset(), index->as_jint(), info);
|
||||
__ branch(lir_cond_belowEqual, T_INT, stub); // forward branch
|
||||
__ branch(lir_cond_belowEqual, stub); // forward branch
|
||||
} else {
|
||||
cmp_reg_mem(lir_cond_aboveEqual, index, buffer,
|
||||
java_nio_Buffer::limit_offset(), T_INT, info);
|
||||
__ branch(lir_cond_aboveEqual, T_INT, stub); // forward branch
|
||||
__ branch(lir_cond_aboveEqual, stub); // forward branch
|
||||
}
|
||||
__ move(index, result);
|
||||
}
|
||||
@ -686,7 +686,7 @@ void LIRGenerator::new_instance(LIR_Opr dst, ciInstanceKlass* klass, bool is_unr
|
||||
oopDesc::header_size(), instance_size, klass_reg, !klass->is_initialized(), slow_path);
|
||||
} else {
|
||||
CodeStub* slow_path = new NewInstanceStub(klass_reg, dst, klass, info, Runtime1::new_instance_id);
|
||||
__ branch(lir_cond_always, T_ILLEGAL, slow_path);
|
||||
__ branch(lir_cond_always, slow_path);
|
||||
__ branch_destination(slow_path->continuation());
|
||||
}
|
||||
}
|
||||
@ -1591,7 +1591,7 @@ void LIRGenerator::do_StoreIndexed(StoreIndexed* x) {
|
||||
if (GenerateRangeChecks && needs_range_check) {
|
||||
if (use_length) {
|
||||
__ cmp(lir_cond_belowEqual, length.result(), index.result());
|
||||
__ branch(lir_cond_belowEqual, T_INT, new RangeCheckStub(range_check_info, index.result(), array.result()));
|
||||
__ branch(lir_cond_belowEqual, new RangeCheckStub(range_check_info, index.result(), array.result()));
|
||||
} else {
|
||||
array_range_check(array.result(), index.result(), null_check_info, range_check_info);
|
||||
// range_check also does the null check
|
||||
@ -1780,11 +1780,11 @@ void LIRGenerator::do_NIOCheckIndex(Intrinsic* x) {
|
||||
LIR_Opr buf_obj = access_resolve(IS_NOT_NULL | ACCESS_READ, buf.result());
|
||||
if (index.result()->is_constant()) {
|
||||
cmp_mem_int(lir_cond_belowEqual, buf_obj, java_nio_Buffer::limit_offset(), index.result()->as_jint(), info);
|
||||
__ branch(lir_cond_belowEqual, T_INT, stub);
|
||||
__ branch(lir_cond_belowEqual, stub);
|
||||
} else {
|
||||
cmp_reg_mem(lir_cond_aboveEqual, index.result(), buf_obj,
|
||||
java_nio_Buffer::limit_offset(), T_INT, info);
|
||||
__ branch(lir_cond_aboveEqual, T_INT, stub);
|
||||
__ branch(lir_cond_aboveEqual, stub);
|
||||
}
|
||||
__ move(index.result(), result);
|
||||
} else {
|
||||
@ -1858,12 +1858,12 @@ void LIRGenerator::do_LoadIndexed(LoadIndexed* x) {
|
||||
|
||||
if (GenerateRangeChecks && needs_range_check) {
|
||||
if (StressLoopInvariantCodeMotion && range_check_info->deoptimize_on_exception()) {
|
||||
__ branch(lir_cond_always, T_ILLEGAL, new RangeCheckStub(range_check_info, index.result(), array.result()));
|
||||
__ branch(lir_cond_always, new RangeCheckStub(range_check_info, index.result(), array.result()));
|
||||
} else if (use_length) {
|
||||
// TODO: use a (modified) version of array_range_check that does not require a
|
||||
// constant length to be loaded to a register
|
||||
__ cmp(lir_cond_belowEqual, length.result(), index.result());
|
||||
__ branch(lir_cond_belowEqual, T_INT, new RangeCheckStub(range_check_info, index.result(), array.result()));
|
||||
__ branch(lir_cond_belowEqual, new RangeCheckStub(range_check_info, index.result(), array.result()));
|
||||
} else {
|
||||
array_range_check(array.result(), index.result(), null_check_info, range_check_info);
|
||||
// The range check performs the null check, so clear it out for the load
|
||||
@ -2239,18 +2239,18 @@ void LIRGenerator::do_SwitchRanges(SwitchRangeArray* x, LIR_Opr value, BlockBegi
|
||||
BlockBegin* dest = one_range->sux();
|
||||
if (low_key == high_key) {
|
||||
__ cmp(lir_cond_equal, value, low_key);
|
||||
__ branch(lir_cond_equal, T_INT, dest);
|
||||
__ branch(lir_cond_equal, dest);
|
||||
} else if (high_key - low_key == 1) {
|
||||
__ cmp(lir_cond_equal, value, low_key);
|
||||
__ branch(lir_cond_equal, T_INT, dest);
|
||||
__ branch(lir_cond_equal, dest);
|
||||
__ cmp(lir_cond_equal, value, high_key);
|
||||
__ branch(lir_cond_equal, T_INT, dest);
|
||||
__ branch(lir_cond_equal, dest);
|
||||
} else {
|
||||
LabelObj* L = new LabelObj();
|
||||
__ cmp(lir_cond_less, value, low_key);
|
||||
__ branch(lir_cond_less, T_INT, L->label());
|
||||
__ branch(lir_cond_less, L->label());
|
||||
__ cmp(lir_cond_lessEqual, value, high_key);
|
||||
__ branch(lir_cond_lessEqual, T_INT, dest);
|
||||
__ branch(lir_cond_lessEqual, dest);
|
||||
__ branch_destination(L->label());
|
||||
}
|
||||
}
|
||||
@ -2370,7 +2370,7 @@ void LIRGenerator::do_TableSwitch(TableSwitch* x) {
|
||||
} else {
|
||||
for (int i = 0; i < len; i++) {
|
||||
__ cmp(lir_cond_equal, value, i + lo_key);
|
||||
__ branch(lir_cond_equal, T_INT, x->sux_at(i));
|
||||
__ branch(lir_cond_equal, x->sux_at(i));
|
||||
}
|
||||
__ jump(x->default_sux());
|
||||
}
|
||||
@ -2429,7 +2429,7 @@ void LIRGenerator::do_LookupSwitch(LookupSwitch* x) {
|
||||
int len = x->length();
|
||||
for (int i = 0; i < len; i++) {
|
||||
__ cmp(lir_cond_equal, value, x->key_at(i));
|
||||
__ branch(lir_cond_equal, T_INT, x->sux_at(i));
|
||||
__ branch(lir_cond_equal, x->sux_at(i));
|
||||
}
|
||||
__ jump(x->default_sux());
|
||||
}
|
||||
@ -2975,16 +2975,18 @@ void LIRGenerator::do_ClassIDIntrinsic(Intrinsic* x) {
|
||||
void LIRGenerator::do_getEventWriter(Intrinsic* x) {
|
||||
LabelObj* L_end = new LabelObj();
|
||||
|
||||
// FIXME T_ADDRESS should actually be T_METADATA but it can't because the
|
||||
// meaning of these two is mixed up (see JDK-8026837).
|
||||
LIR_Address* jobj_addr = new LIR_Address(getThreadPointer(),
|
||||
in_bytes(THREAD_LOCAL_WRITER_OFFSET_JFR),
|
||||
T_OBJECT);
|
||||
T_ADDRESS);
|
||||
LIR_Opr result = rlock_result(x);
|
||||
__ move_wide(jobj_addr, result);
|
||||
__ cmp(lir_cond_equal, result, LIR_OprFact::oopConst(NULL));
|
||||
__ branch(lir_cond_equal, T_OBJECT, L_end->label());
|
||||
__ move(LIR_OprFact::oopConst(NULL), result);
|
||||
LIR_Opr jobj = new_register(T_METADATA);
|
||||
__ move_wide(jobj_addr, jobj);
|
||||
__ cmp(lir_cond_equal, jobj, LIR_OprFact::metadataConst(0));
|
||||
__ branch(lir_cond_equal, L_end->label());
|
||||
|
||||
LIR_Opr jobj = new_register(T_OBJECT);
|
||||
__ move(result, jobj);
|
||||
access_load(IN_NATIVE, T_OBJECT, LIR_OprFact::address(new LIR_Address(jobj, T_OBJECT)), result);
|
||||
|
||||
__ branch_destination(L_end->label());
|
||||
@ -3342,7 +3344,7 @@ void LIRGenerator::decrement_age(CodeEmitInfo* info) {
|
||||
CodeStub* deopt = new DeoptimizeStub(info, Deoptimization::Reason_tenured,
|
||||
Deoptimization::Action_make_not_entrant);
|
||||
__ cmp(lir_cond_lessEqual, result, LIR_OprFact::intConst(0));
|
||||
__ branch(lir_cond_lessEqual, T_INT, deopt);
|
||||
__ branch(lir_cond_lessEqual, deopt);
|
||||
}
|
||||
}
|
||||
|
||||
@ -3389,9 +3391,9 @@ void LIRGenerator::increment_event_counter_impl(CodeEmitInfo* info,
|
||||
if (freq == 0) {
|
||||
if (!step->is_constant()) {
|
||||
__ cmp(lir_cond_notEqual, step, LIR_OprFact::intConst(0));
|
||||
__ branch(lir_cond_notEqual, T_ILLEGAL, overflow);
|
||||
__ branch(lir_cond_notEqual, overflow);
|
||||
} else {
|
||||
__ branch(lir_cond_always, T_ILLEGAL, overflow);
|
||||
__ branch(lir_cond_always, overflow);
|
||||
}
|
||||
} else {
|
||||
LIR_Opr mask = load_immediate(freq, T_INT);
|
||||
@ -3402,7 +3404,7 @@ void LIRGenerator::increment_event_counter_impl(CodeEmitInfo* info,
|
||||
}
|
||||
__ logical_and(result, mask, result);
|
||||
__ cmp(lir_cond_equal, result, LIR_OprFact::intConst(0));
|
||||
__ branch(lir_cond_equal, T_INT, overflow);
|
||||
__ branch(lir_cond_equal, overflow);
|
||||
}
|
||||
__ branch_destination(overflow->continuation());
|
||||
}
|
||||
@ -3516,7 +3518,7 @@ void LIRGenerator::do_RangeCheckPredicate(RangeCheckPredicate *x) {
|
||||
CodeStub* stub = new PredicateFailedStub(info);
|
||||
|
||||
__ cmp(lir_cond(cond), left, right);
|
||||
__ branch(lir_cond(cond), right->type(), stub);
|
||||
__ branch(lir_cond(cond), stub);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -3212,6 +3212,41 @@ u2 ClassFileParser::parse_classfile_nest_members_attribute(const ClassFileStream
|
||||
return length;
|
||||
}
|
||||
|
||||
u2 ClassFileParser::parse_classfile_permitted_subclasses_attribute(const ClassFileStream* const cfs,
|
||||
const u1* const permitted_subclasses_attribute_start,
|
||||
TRAPS) {
|
||||
const u1* const current_mark = cfs->current();
|
||||
u2 length = 0;
|
||||
if (permitted_subclasses_attribute_start != NULL) {
|
||||
cfs->set_current(permitted_subclasses_attribute_start);
|
||||
cfs->guarantee_more(2, CHECK_0); // length
|
||||
length = cfs->get_u2_fast();
|
||||
}
|
||||
if (length < 1) {
|
||||
classfile_parse_error("PermittedSubclasses attribute is empty in class file %s", CHECK_0);
|
||||
}
|
||||
const int size = length;
|
||||
Array<u2>* const permitted_subclasses = MetadataFactory::new_array<u2>(_loader_data, size, CHECK_0);
|
||||
_permitted_subclasses = permitted_subclasses;
|
||||
|
||||
int index = 0;
|
||||
cfs->guarantee_more(2 * length, CHECK_0);
|
||||
for (int n = 0; n < length; n++) {
|
||||
const u2 class_info_index = cfs->get_u2_fast();
|
||||
check_property(
|
||||
valid_klass_reference_at(class_info_index),
|
||||
"Permitted subclass class_info_index %u has bad constant type in class file %s",
|
||||
class_info_index, CHECK_0);
|
||||
permitted_subclasses->at_put(index++, class_info_index);
|
||||
}
|
||||
assert(index == size, "wrong size");
|
||||
|
||||
// Restore buffer's current position.
|
||||
cfs->set_current(current_mark);
|
||||
|
||||
return length;
|
||||
}
|
||||
|
||||
// Record {
|
||||
// u2 attribute_name_index;
|
||||
// u4 attribute_length;
|
||||
@ -3476,10 +3511,16 @@ void ClassFileParser::parse_classfile_bootstrap_methods_attribute(const ClassFil
|
||||
CHECK);
|
||||
}
|
||||
|
||||
bool ClassFileParser::supports_sealed_types() {
|
||||
return _major_version == JVM_CLASSFILE_MAJOR_VERSION &&
|
||||
_minor_version == JAVA_PREVIEW_MINOR_VERSION &&
|
||||
Arguments::enable_preview();
|
||||
}
|
||||
|
||||
bool ClassFileParser::supports_records() {
|
||||
return _major_version == JVM_CLASSFILE_MAJOR_VERSION &&
|
||||
_minor_version == JAVA_PREVIEW_MINOR_VERSION &&
|
||||
Arguments::enable_preview();
|
||||
_minor_version == JAVA_PREVIEW_MINOR_VERSION &&
|
||||
Arguments::enable_preview();
|
||||
}
|
||||
|
||||
void ClassFileParser::parse_classfile_attributes(const ClassFileStream* const cfs,
|
||||
@ -3494,11 +3535,14 @@ void ClassFileParser::parse_classfile_attributes(const ClassFileStream* const cf
|
||||
_inner_classes = Universe::the_empty_short_array();
|
||||
// Set nest members attribute to default sentinel
|
||||
_nest_members = Universe::the_empty_short_array();
|
||||
// Set _permitted_subclasses attribute to default sentinel
|
||||
_permitted_subclasses = Universe::the_empty_short_array();
|
||||
cfs->guarantee_more(2, CHECK); // attributes_count
|
||||
u2 attributes_count = cfs->get_u2_fast();
|
||||
bool parsed_sourcefile_attribute = false;
|
||||
bool parsed_innerclasses_attribute = false;
|
||||
bool parsed_nest_members_attribute = false;
|
||||
bool parsed_permitted_subclasses_attribute = false;
|
||||
bool parsed_nest_host_attribute = false;
|
||||
bool parsed_record_attribute = false;
|
||||
bool parsed_enclosingmethod_attribute = false;
|
||||
@ -3522,6 +3566,8 @@ void ClassFileParser::parse_classfile_attributes(const ClassFileStream* const cf
|
||||
u4 nest_members_attribute_length = 0;
|
||||
const u1* record_attribute_start = NULL;
|
||||
u4 record_attribute_length = 0;
|
||||
const u1* permitted_subclasses_attribute_start = NULL;
|
||||
u4 permitted_subclasses_attribute_length = 0;
|
||||
|
||||
// Iterate over attributes
|
||||
while (attributes_count--) {
|
||||
@ -3738,6 +3784,26 @@ void ClassFileParser::parse_classfile_attributes(const ClassFileStream* const cf
|
||||
}
|
||||
}
|
||||
cfs->skip_u1(attribute_length, CHECK);
|
||||
} else if (_major_version >= JAVA_15_VERSION) {
|
||||
// Check for PermittedSubclasses tag
|
||||
if (tag == vmSymbols::tag_permitted_subclasses()) {
|
||||
if (supports_sealed_types()) {
|
||||
if (parsed_permitted_subclasses_attribute) {
|
||||
classfile_parse_error("Multiple PermittedSubclasses attributes in class file %s", CHECK);
|
||||
}
|
||||
// Classes marked ACC_FINAL cannot have a PermittedSubclasses attribute.
|
||||
if (_access_flags.is_final()) {
|
||||
classfile_parse_error("PermittedSubclasses attribute in final class file %s", CHECK);
|
||||
}
|
||||
parsed_permitted_subclasses_attribute = true;
|
||||
permitted_subclasses_attribute_start = cfs->current();
|
||||
permitted_subclasses_attribute_length = attribute_length;
|
||||
}
|
||||
cfs->skip_u1(attribute_length, CHECK);
|
||||
} else {
|
||||
// Unknown attribute
|
||||
cfs->skip_u1(attribute_length, CHECK);
|
||||
}
|
||||
} else {
|
||||
// Unknown attribute
|
||||
cfs->skip_u1(attribute_length, CHECK);
|
||||
@ -3806,6 +3872,18 @@ void ClassFileParser::parse_classfile_attributes(const ClassFileStream* const cf
|
||||
}
|
||||
}
|
||||
|
||||
if (parsed_permitted_subclasses_attribute) {
|
||||
const u2 num_subclasses = parse_classfile_permitted_subclasses_attribute(
|
||||
cfs,
|
||||
permitted_subclasses_attribute_start,
|
||||
CHECK);
|
||||
if (_need_verify) {
|
||||
guarantee_property(
|
||||
permitted_subclasses_attribute_length == sizeof(num_subclasses) + sizeof(u2) * num_subclasses,
|
||||
"Wrong PermittedSubclasses attribute length in class file %s", CHECK);
|
||||
}
|
||||
}
|
||||
|
||||
if (_max_bootstrap_specifier_index >= 0) {
|
||||
guarantee_property(parsed_bootstrap_methods_attribute,
|
||||
"Missing BootstrapMethods attribute in class file %s", CHECK);
|
||||
@ -3871,11 +3949,12 @@ void ClassFileParser::apply_parsed_class_metadata(
|
||||
this_klass->set_inner_classes(_inner_classes);
|
||||
this_klass->set_nest_members(_nest_members);
|
||||
this_klass->set_nest_host_index(_nest_host);
|
||||
this_klass->set_local_interfaces(_local_interfaces);
|
||||
this_klass->set_annotations(_combined_annotations);
|
||||
this_klass->set_permitted_subclasses(_permitted_subclasses);
|
||||
this_klass->set_record_components(_record_components);
|
||||
// Delay the setting of _transitive_interfaces until after initialize_supers() in
|
||||
// fill_instance_klass(). It is because the _transitive_interfaces may be shared with
|
||||
// Delay the setting of _local_interfaces and _transitive_interfaces until after
|
||||
// initialize_supers() in fill_instance_klass(). It is because the _local_interfaces could
|
||||
// be shared with _transitive_interfaces and _transitive_interfaces may be shared with
|
||||
// its _super. If an OOM occurs while loading the current klass, its _super field
|
||||
// may not have been set. When GC tries to free the klass, the _transitive_interfaces
|
||||
// may be deallocated mistakenly in InstanceKlass::deallocate_interfaces(). Subsequent
|
||||
@ -4681,12 +4760,34 @@ static void check_super_class_access(const InstanceKlass* this_klass, TRAPS) {
|
||||
const Klass* const super = this_klass->super();
|
||||
|
||||
if (super != NULL) {
|
||||
const InstanceKlass* super_ik = InstanceKlass::cast(super);
|
||||
|
||||
if (super->is_final()) {
|
||||
ResourceMark rm(THREAD);
|
||||
Exceptions::fthrow(
|
||||
THREAD_AND_LOCATION,
|
||||
vmSymbols::java_lang_VerifyError(),
|
||||
"class %s cannot inherit from final class %s",
|
||||
this_klass->external_name(),
|
||||
super_ik->external_name());
|
||||
return;
|
||||
}
|
||||
|
||||
if (super_ik->is_sealed() && !super_ik->has_as_permitted_subclass(this_klass)) {
|
||||
ResourceMark rm(THREAD);
|
||||
Exceptions::fthrow(
|
||||
THREAD_AND_LOCATION,
|
||||
vmSymbols::java_lang_IncompatibleClassChangeError(),
|
||||
"class %s cannot inherit from sealed class %s",
|
||||
this_klass->external_name(),
|
||||
super_ik->external_name());
|
||||
return;
|
||||
}
|
||||
|
||||
// If the loader is not the boot loader then throw an exception if its
|
||||
// superclass is in package jdk.internal.reflect and its loader is not a
|
||||
// special reflection class loader
|
||||
if (!this_klass->class_loader_data()->is_the_null_class_loader_data()) {
|
||||
assert(super->is_instance_klass(), "super is not instance klass");
|
||||
PackageEntry* super_package = super->package();
|
||||
if (super_package != NULL &&
|
||||
super_package->name()->fast_compare(vmSymbols::jdk_internal_reflect()) == 0 &&
|
||||
@ -4742,6 +4843,19 @@ static void check_super_interface_access(const InstanceKlass* this_klass, TRAPS)
|
||||
for (int i = lng - 1; i >= 0; i--) {
|
||||
InstanceKlass* const k = local_interfaces->at(i);
|
||||
assert (k != NULL && k->is_interface(), "invalid interface");
|
||||
|
||||
if (k->is_sealed() && !k->has_as_permitted_subclass(this_klass)) {
|
||||
ResourceMark rm(THREAD);
|
||||
Exceptions::fthrow(
|
||||
THREAD_AND_LOCATION,
|
||||
vmSymbols::java_lang_IncompatibleClassChangeError(),
|
||||
"class %s cannot %s sealed interface %s",
|
||||
this_klass->external_name(),
|
||||
this_klass->is_interface() ? "extend" : "implement",
|
||||
k->external_name());
|
||||
return;
|
||||
}
|
||||
|
||||
Reflection::VerifyClassAccessResults vca_result =
|
||||
Reflection::verify_class_access(this_klass, k, false);
|
||||
if (vca_result != Reflection::ACCESS_OK) {
|
||||
@ -5674,9 +5788,9 @@ void ClassFileParser::fill_instance_klass(InstanceKlass* ik,
|
||||
assert(NULL == _methods, "invariant");
|
||||
assert(NULL == _inner_classes, "invariant");
|
||||
assert(NULL == _nest_members, "invariant");
|
||||
assert(NULL == _local_interfaces, "invariant");
|
||||
assert(NULL == _combined_annotations, "invariant");
|
||||
assert(NULL == _record_components, "invariant");
|
||||
assert(NULL == _permitted_subclasses, "invariant");
|
||||
|
||||
if (_has_final_method) {
|
||||
ik->set_has_final_method();
|
||||
@ -5747,7 +5861,9 @@ void ClassFileParser::fill_instance_klass(InstanceKlass* ik,
|
||||
// Fill in information needed to compute superclasses.
|
||||
ik->initialize_supers(const_cast<InstanceKlass*>(_super_klass), _transitive_interfaces, CHECK);
|
||||
ik->set_transitive_interfaces(_transitive_interfaces);
|
||||
ik->set_local_interfaces(_local_interfaces);
|
||||
_transitive_interfaces = NULL;
|
||||
_local_interfaces = NULL;
|
||||
|
||||
// Initialize itable offset tables
|
||||
klassItable::setup_itable_offset_table(ik);
|
||||
@ -5965,6 +6081,7 @@ ClassFileParser::ClassFileParser(ClassFileStream* stream,
|
||||
_inner_classes(NULL),
|
||||
_nest_members(NULL),
|
||||
_nest_host(0),
|
||||
_permitted_subclasses(NULL),
|
||||
_record_components(NULL),
|
||||
_local_interfaces(NULL),
|
||||
_transitive_interfaces(NULL),
|
||||
@ -6073,7 +6190,7 @@ void ClassFileParser::clear_class_metadata() {
|
||||
_methods = NULL;
|
||||
_inner_classes = NULL;
|
||||
_nest_members = NULL;
|
||||
_local_interfaces = NULL;
|
||||
_permitted_subclasses = NULL;
|
||||
_combined_annotations = NULL;
|
||||
_class_annotations = _class_type_annotations = NULL;
|
||||
_fields_annotations = _fields_type_annotations = NULL;
|
||||
@ -6109,6 +6226,10 @@ ClassFileParser::~ClassFileParser() {
|
||||
InstanceKlass::deallocate_record_components(_loader_data, _record_components);
|
||||
}
|
||||
|
||||
if (_permitted_subclasses != NULL && _permitted_subclasses != Universe::the_empty_short_array()) {
|
||||
MetadataFactory::free_array<u2>(_loader_data, _permitted_subclasses);
|
||||
}
|
||||
|
||||
// Free interfaces
|
||||
InstanceKlass::deallocate_interfaces(_loader_data, _super_klass,
|
||||
_local_interfaces, _transitive_interfaces);
|
||||
@ -6137,6 +6258,7 @@ ClassFileParser::~ClassFileParser() {
|
||||
|
||||
clear_class_metadata();
|
||||
_transitive_interfaces = NULL;
|
||||
_local_interfaces = NULL;
|
||||
|
||||
// deallocate the klass if already created. Don't directly deallocate, but add
|
||||
// to the deallocate list so that the klass is removed from the CLD::_klasses list
|
||||
@ -6507,10 +6629,6 @@ void ClassFileParser::post_process_parsed_stream(const ClassFileStream* const st
|
||||
);
|
||||
return;
|
||||
}
|
||||
// Make sure super class is not final
|
||||
if (_super_klass->is_final()) {
|
||||
THROW_MSG(vmSymbols::java_lang_VerifyError(), "Cannot inherit from final class");
|
||||
}
|
||||
}
|
||||
|
||||
// Compute the transitive list of all unique interfaces implemented by this class
|
||||
|
||||
@ -132,6 +132,7 @@ class ClassFileParser {
|
||||
Array<u2>* _inner_classes;
|
||||
Array<u2>* _nest_members;
|
||||
u2 _nest_host;
|
||||
Array<u2>* _permitted_subclasses;
|
||||
Array<RecordComponent*>* _record_components;
|
||||
Array<InstanceKlass*>* _local_interfaces;
|
||||
Array<InstanceKlass*>* _transitive_interfaces;
|
||||
@ -327,11 +328,16 @@ class ClassFileParser {
|
||||
const u1* const nest_members_attribute_start,
|
||||
TRAPS);
|
||||
|
||||
u2 parse_classfile_permitted_subclasses_attribute(const ClassFileStream* const cfs,
|
||||
const u1* const permitted_subclasses_attribute_start,
|
||||
TRAPS);
|
||||
|
||||
u2 parse_classfile_record_attribute(const ClassFileStream* const cfs,
|
||||
const ConstantPool* cp,
|
||||
const u1* const record_attribute_start,
|
||||
TRAPS);
|
||||
|
||||
bool supports_sealed_types();
|
||||
bool supports_records();
|
||||
|
||||
void parse_classfile_attributes(const ClassFileStream* const cfs,
|
||||
|
||||
@ -666,6 +666,13 @@ ClassLoaderMetaspace* ClassLoaderDataGraphMetaspaceIterator::get_next() {
|
||||
return result;
|
||||
}
|
||||
|
||||
void ClassLoaderDataGraph::verify() {
|
||||
ClassLoaderDataGraphIterator iter;
|
||||
while (ClassLoaderData* cld = iter.get_next()) {
|
||||
cld->verify();
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef PRODUCT
|
||||
// callable from debugger
|
||||
extern "C" int print_loader_data_graph() {
|
||||
@ -674,13 +681,6 @@ extern "C" int print_loader_data_graph() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
void ClassLoaderDataGraph::verify() {
|
||||
ClassLoaderDataGraphIterator iter;
|
||||
while (ClassLoaderData* cld = iter.get_next()) {
|
||||
cld->verify();
|
||||
}
|
||||
}
|
||||
|
||||
void ClassLoaderDataGraph::print_on(outputStream * const out) {
|
||||
ClassLoaderDataGraphIterator iter;
|
||||
while (ClassLoaderData* cld = iter.get_next()) {
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 1997, 2019, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 1997, 2020, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -31,6 +31,7 @@
|
||||
#include "memory/heapShared.inline.hpp"
|
||||
#include "memory/metadataFactory.hpp"
|
||||
#include "memory/metaspaceShared.hpp"
|
||||
#include "runtime/globals.hpp"
|
||||
#include "runtime/vmThread.hpp"
|
||||
#include "utilities/numberSeq.hpp"
|
||||
#include <sys/stat.h>
|
||||
@ -212,11 +213,13 @@ size_t SimpleCompactHashtable::calculate_header_size() {
|
||||
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);
|
||||
soc->do_ptr((void**)&_buckets);
|
||||
soc->do_ptr((void**)&_entries);
|
||||
if (soc->reading()) {
|
||||
_base_address = (address)SharedBaseAddress;
|
||||
}
|
||||
}
|
||||
#endif // INCLUDE_CDS
|
||||
|
||||
|
||||
@ -33,6 +33,7 @@
|
||||
#include "memory/metaspaceClosure.hpp"
|
||||
#include "memory/resourceArea.hpp"
|
||||
#include "oops/oop.inline.hpp"
|
||||
#include "oops/oopHandle.inline.hpp"
|
||||
#include "runtime/mutexLocker.hpp"
|
||||
#include "runtime/safepointVerifiers.hpp"
|
||||
#include "utilities/hashtable.inline.hpp"
|
||||
@ -400,6 +401,20 @@ void Dictionary::clean_cached_protection_domains() {
|
||||
}
|
||||
}
|
||||
|
||||
oop SymbolPropertyEntry::method_type() const {
|
||||
return _method_type.resolve();
|
||||
}
|
||||
|
||||
void SymbolPropertyEntry::set_method_type(oop p) {
|
||||
_method_type = OopHandle::create(p);
|
||||
}
|
||||
|
||||
void SymbolPropertyEntry::free_entry() {
|
||||
// decrement Symbol refcount here because hashtable doesn't.
|
||||
literal()->decrement_refcount();
|
||||
// Free OopHandle
|
||||
_method_type.release();
|
||||
}
|
||||
|
||||
SymbolPropertyTable::SymbolPropertyTable(int table_size)
|
||||
: Hashtable<Symbol*, mtSymbol>(table_size, sizeof(SymbolPropertyEntry))
|
||||
@ -436,16 +451,6 @@ SymbolPropertyEntry* SymbolPropertyTable::add_entry(int index, unsigned int hash
|
||||
return p;
|
||||
}
|
||||
|
||||
void SymbolPropertyTable::oops_do(OopClosure* f) {
|
||||
for (int index = 0; index < table_size(); index++) {
|
||||
for (SymbolPropertyEntry* p = bucket(index); p != NULL; p = p->next()) {
|
||||
if (p->method_type() != NULL) {
|
||||
f->do_oop(p->method_type_addr());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void SymbolPropertyTable::methods_do(void f(Method*)) {
|
||||
for (int index = 0; index < table_size(); index++) {
|
||||
for (SymbolPropertyEntry* p = bucket(index); p != NULL; p = p->next()) {
|
||||
@ -457,6 +462,11 @@ void SymbolPropertyTable::methods_do(void f(Method*)) {
|
||||
}
|
||||
}
|
||||
|
||||
void SymbolPropertyTable::free_entry(SymbolPropertyEntry* entry) {
|
||||
entry->free_entry();
|
||||
Hashtable<Symbol*, mtSymbol>::free_entry(entry);
|
||||
}
|
||||
|
||||
void DictionaryEntry::verify_protection_domain_set() {
|
||||
MutexLocker ml(ProtectionDomainSet_lock, Mutex::_no_safepoint_check_flag);
|
||||
for (ProtectionDomainEntry* current = pd_set(); // accessed at a safepoint
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2003, 2019, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2003, 2020, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -29,6 +29,7 @@
|
||||
#include "classfile/systemDictionary.hpp"
|
||||
#include "oops/instanceKlass.hpp"
|
||||
#include "oops/oop.hpp"
|
||||
#include "oops/oopHandle.hpp"
|
||||
#include "utilities/hashtable.hpp"
|
||||
#include "utilities/ostream.hpp"
|
||||
|
||||
@ -180,7 +181,7 @@ class SymbolPropertyEntry : public HashtableEntry<Symbol*, mtSymbol> {
|
||||
private:
|
||||
intptr_t _symbol_mode; // secondary key
|
||||
Method* _method;
|
||||
oop _method_type;
|
||||
OopHandle _method_type;
|
||||
|
||||
public:
|
||||
Symbol* symbol() const { return literal(); }
|
||||
@ -191,9 +192,10 @@ class SymbolPropertyEntry : public HashtableEntry<Symbol*, mtSymbol> {
|
||||
Method* method() const { return _method; }
|
||||
void set_method(Method* p) { _method = p; }
|
||||
|
||||
oop method_type() const { return _method_type; }
|
||||
oop* method_type_addr() { return &_method_type; }
|
||||
void set_method_type(oop p) { _method_type = p; }
|
||||
oop method_type() const;
|
||||
void set_method_type(oop p);
|
||||
|
||||
void free_entry();
|
||||
|
||||
SymbolPropertyEntry* next() const {
|
||||
return (SymbolPropertyEntry*)HashtableEntry<Symbol*, mtSymbol>::next();
|
||||
@ -253,11 +255,7 @@ public:
|
||||
SymbolPropertyTable(int table_size);
|
||||
SymbolPropertyTable(int table_size, HashtableBucket<mtSymbol>* t, int number_of_entries);
|
||||
|
||||
void free_entry(SymbolPropertyEntry* entry) {
|
||||
// decrement Symbol refcount here because hashtable doesn't.
|
||||
entry->literal()->decrement_refcount();
|
||||
Hashtable<Symbol*, mtSymbol>::free_entry(entry);
|
||||
}
|
||||
void free_entry(SymbolPropertyEntry* entry);
|
||||
|
||||
unsigned int compute_hash(Symbol* sym, intptr_t symbol_mode) {
|
||||
// Use the regular identity_hash.
|
||||
@ -274,9 +272,6 @@ public:
|
||||
// must be done under SystemDictionary_lock
|
||||
SymbolPropertyEntry* add_entry(int index, unsigned int hash, Symbol* name, intptr_t name_mode);
|
||||
|
||||
// GC support
|
||||
void oops_do(OopClosure* f);
|
||||
|
||||
void methods_do(void f(Method*));
|
||||
|
||||
void verify();
|
||||
|
||||
@ -46,8 +46,6 @@
|
||||
#include "code/codeCache.hpp"
|
||||
#include "compiler/compileBroker.hpp"
|
||||
#include "gc/shared/gcTraceTime.inline.hpp"
|
||||
#include "gc/shared/oopStorage.inline.hpp"
|
||||
#include "gc/shared/oopStorageSet.hpp"
|
||||
#include "interpreter/bytecodeStream.hpp"
|
||||
#include "interpreter/interpreter.hpp"
|
||||
#include "jfr/jfrEvents.hpp"
|
||||
@ -68,6 +66,7 @@
|
||||
#include "oops/objArrayKlass.hpp"
|
||||
#include "oops/objArrayOop.inline.hpp"
|
||||
#include "oops/oop.inline.hpp"
|
||||
#include "oops/oopHandle.inline.hpp"
|
||||
#include "oops/symbol.hpp"
|
||||
#include "oops/typeArrayKlass.hpp"
|
||||
#include "prims/jvmtiExport.hpp"
|
||||
@ -98,15 +97,15 @@ ResolutionErrorTable* SystemDictionary::_resolution_errors = NULL;
|
||||
SymbolPropertyTable* SystemDictionary::_invoke_method_table = NULL;
|
||||
ProtectionDomainCacheTable* SystemDictionary::_pd_cache_table = NULL;
|
||||
|
||||
oop SystemDictionary::_system_loader_lock_obj = NULL;
|
||||
|
||||
InstanceKlass* SystemDictionary::_well_known_klasses[SystemDictionary::WKID_LIMIT]
|
||||
= { NULL /*, NULL...*/ };
|
||||
|
||||
InstanceKlass* SystemDictionary::_box_klasses[T_VOID+1] = { NULL /*, NULL...*/ };
|
||||
|
||||
oop SystemDictionary::_java_system_loader = NULL;
|
||||
oop SystemDictionary::_java_platform_loader = NULL;
|
||||
|
||||
OopHandle SystemDictionary::_system_loader_lock_obj;
|
||||
OopHandle SystemDictionary::_java_system_loader;
|
||||
OopHandle SystemDictionary::_java_platform_loader;
|
||||
|
||||
// Default ProtectionDomainCacheSize value
|
||||
|
||||
@ -155,12 +154,16 @@ ClassLoadInfo::ClassLoadInfo(Handle protection_domain,
|
||||
// ----------------------------------------------------------------------------
|
||||
// Java-level SystemLoader and PlatformLoader
|
||||
|
||||
oop SystemDictionary::system_loader_lock() {
|
||||
return _system_loader_lock_obj.resolve();
|
||||
}
|
||||
|
||||
oop SystemDictionary::java_system_loader() {
|
||||
return _java_system_loader;
|
||||
return _java_system_loader.resolve();
|
||||
}
|
||||
|
||||
oop SystemDictionary::java_platform_loader() {
|
||||
return _java_platform_loader;
|
||||
return _java_platform_loader.resolve();
|
||||
}
|
||||
|
||||
void SystemDictionary::compute_java_loaders(TRAPS) {
|
||||
@ -172,7 +175,7 @@ void SystemDictionary::compute_java_loaders(TRAPS) {
|
||||
vmSymbols::void_classloader_signature(),
|
||||
CHECK);
|
||||
|
||||
_java_system_loader = (oop)result.get_jobject();
|
||||
_java_system_loader = OopHandle::create((oop)result.get_jobject());
|
||||
|
||||
JavaCalls::call_static(&result,
|
||||
class_loader_klass,
|
||||
@ -180,7 +183,7 @@ void SystemDictionary::compute_java_loaders(TRAPS) {
|
||||
vmSymbols::void_classloader_signature(),
|
||||
CHECK);
|
||||
|
||||
_java_platform_loader = (oop)result.get_jobject();
|
||||
_java_platform_loader = OopHandle::create((oop)result.get_jobject());
|
||||
}
|
||||
|
||||
ClassLoaderData* SystemDictionary::register_loader(Handle class_loader, bool create_mirror_cld) {
|
||||
@ -219,7 +222,7 @@ bool SystemDictionary::is_system_class_loader(oop class_loader) {
|
||||
return false;
|
||||
}
|
||||
return (class_loader->klass() == SystemDictionary::jdk_internal_loader_ClassLoaders_AppClassLoader_klass() ||
|
||||
class_loader == _java_system_loader);
|
||||
class_loader == _java_system_loader.peek());
|
||||
}
|
||||
|
||||
// Returns true if the passed class loader is the platform class loader.
|
||||
@ -603,7 +606,8 @@ void SystemDictionary::double_lock_wait(Handle lockObject, TRAPS) {
|
||||
bool calledholdinglock
|
||||
= ObjectSynchronizer::current_thread_holds_lock((JavaThread*)THREAD, lockObject);
|
||||
assert(calledholdinglock,"must hold lock for notify");
|
||||
assert((lockObject() != _system_loader_lock_obj && !is_parallelCapable(lockObject)), "unexpected double_lock_wait");
|
||||
assert((lockObject() != _system_loader_lock_obj.resolve() &&
|
||||
!is_parallelCapable(lockObject)), "unexpected double_lock_wait");
|
||||
ObjectSynchronizer::notifyall(lockObject, THREAD);
|
||||
intx recursions = ObjectSynchronizer::complete_exit(lockObject, THREAD);
|
||||
SystemDictionary_lock->wait();
|
||||
@ -1820,7 +1824,7 @@ InstanceKlass* SystemDictionary::find_or_define_instance_class(Symbol* class_nam
|
||||
Handle SystemDictionary::compute_loader_lock_object(Handle class_loader, TRAPS) {
|
||||
// If class_loader is NULL we synchronize on _system_loader_lock_obj
|
||||
if (class_loader.is_null()) {
|
||||
return Handle(THREAD, _system_loader_lock_obj);
|
||||
return Handle(THREAD, _system_loader_lock_obj.resolve());
|
||||
} else {
|
||||
return class_loader;
|
||||
}
|
||||
@ -1841,7 +1845,7 @@ void SystemDictionary::check_loader_lock_contention(Handle loader_lock, TRAPS) {
|
||||
== ObjectSynchronizer::owner_other) {
|
||||
// contention will likely happen, so increment the corresponding
|
||||
// contention counter.
|
||||
if (loader_lock() == _system_loader_lock_obj) {
|
||||
if (loader_lock() == _system_loader_lock_obj.resolve()) {
|
||||
ClassLoader::sync_systemLoaderLockContentionRate()->inc();
|
||||
} else {
|
||||
ClassLoader::sync_nonSystemLoaderLockContentionRate()->inc();
|
||||
@ -1958,20 +1962,6 @@ bool SystemDictionary::do_unloading(GCTimer* gc_timer) {
|
||||
return unloading_occurred;
|
||||
}
|
||||
|
||||
void SystemDictionary::oops_do(OopClosure* f, bool include_handles) {
|
||||
f->do_oop(&_java_system_loader);
|
||||
f->do_oop(&_java_platform_loader);
|
||||
f->do_oop(&_system_loader_lock_obj);
|
||||
CDS_ONLY(SystemDictionaryShared::oops_do(f);)
|
||||
|
||||
// Visit extra methods
|
||||
invoke_method_table()->oops_do(f);
|
||||
|
||||
if (include_handles) {
|
||||
OopStorageSet::vm_global()->oops_do(f);
|
||||
}
|
||||
}
|
||||
|
||||
// CDS: scan and relocate all classes referenced by _well_known_klasses[].
|
||||
void SystemDictionary::well_known_klasses_do(MetaspaceClosure* it) {
|
||||
for (int id = FIRST_WKID; id < WKID_LIMIT; id++) {
|
||||
@ -1999,7 +1989,9 @@ void SystemDictionary::initialize(TRAPS) {
|
||||
_pd_cache_table = new ProtectionDomainCacheTable(defaultProtectionDomainCacheSize);
|
||||
|
||||
// Allocate private object used as system class loader lock
|
||||
_system_loader_lock_obj = oopFactory::new_intArray(0, CHECK);
|
||||
oop lock_obj = oopFactory::new_intArray(0, CHECK);
|
||||
_system_loader_lock_obj = OopHandle::create(lock_obj);
|
||||
|
||||
// Initialize basic classes
|
||||
resolve_well_known_classes(CHECK);
|
||||
}
|
||||
|
||||
@ -27,6 +27,7 @@
|
||||
|
||||
#include "classfile/classLoaderData.hpp"
|
||||
#include "oops/objArrayOop.hpp"
|
||||
#include "oops/oopHandle.hpp"
|
||||
#include "oops/symbol.hpp"
|
||||
#include "runtime/java.hpp"
|
||||
#include "runtime/mutexLocker.hpp"
|
||||
@ -381,13 +382,8 @@ public:
|
||||
// loaders. Returns "true" iff something was unloaded.
|
||||
static bool do_unloading(GCTimer* gc_timer);
|
||||
|
||||
// Applies "f->do_oop" to all root oops in the system dictionary.
|
||||
// If include_handles is true (the default), then the handles in the
|
||||
// vm_global OopStorage object are included.
|
||||
static void oops_do(OopClosure* f, bool include_handles = true);
|
||||
|
||||
// System loader lock
|
||||
static oop system_loader_lock() { return _system_loader_lock_obj; }
|
||||
static oop system_loader_lock();
|
||||
|
||||
// Protection Domain Table
|
||||
static ProtectionDomainCacheTable* pd_cache_table() { return _pd_cache_table; }
|
||||
@ -585,7 +581,7 @@ public:
|
||||
static PlaceholderTable* _placeholders;
|
||||
|
||||
// Lock object for system class loader
|
||||
static oop _system_loader_lock_obj;
|
||||
static OopHandle _system_loader_lock_obj;
|
||||
|
||||
// Constraints on class loaders
|
||||
static LoaderConstraintTable* _loader_constraints;
|
||||
@ -703,8 +699,8 @@ protected:
|
||||
static InstanceKlass* _box_klasses[T_VOID+1];
|
||||
|
||||
private:
|
||||
static oop _java_system_loader;
|
||||
static oop _java_platform_loader;
|
||||
static OopHandle _java_system_loader;
|
||||
static OopHandle _java_platform_loader;
|
||||
|
||||
public:
|
||||
static TableStatistics placeholders_statistics();
|
||||
|
||||
@ -61,9 +61,9 @@
|
||||
#include "utilities/stringUtils.hpp"
|
||||
|
||||
|
||||
objArrayOop SystemDictionaryShared::_shared_protection_domains = NULL;
|
||||
objArrayOop SystemDictionaryShared::_shared_jar_urls = NULL;
|
||||
objArrayOop SystemDictionaryShared::_shared_jar_manifests = NULL;
|
||||
OopHandle SystemDictionaryShared::_shared_protection_domains = NULL;
|
||||
OopHandle SystemDictionaryShared::_shared_jar_urls = NULL;
|
||||
OopHandle SystemDictionaryShared::_shared_jar_manifests = NULL;
|
||||
DEBUG_ONLY(bool SystemDictionaryShared::_no_class_loading_should_happen = false;)
|
||||
|
||||
class DumpTimeSharedClassInfo: public CHeapObj<mtClass> {
|
||||
@ -460,15 +460,15 @@ static RunTimeSharedDictionary _dynamic_builtin_dictionary;
|
||||
static RunTimeSharedDictionary _dynamic_unregistered_dictionary;
|
||||
|
||||
oop SystemDictionaryShared::shared_protection_domain(int index) {
|
||||
return _shared_protection_domains->obj_at(index);
|
||||
return ((objArrayOop)_shared_protection_domains.resolve())->obj_at(index);
|
||||
}
|
||||
|
||||
oop SystemDictionaryShared::shared_jar_url(int index) {
|
||||
return _shared_jar_urls->obj_at(index);
|
||||
return ((objArrayOop)_shared_jar_urls.resolve())->obj_at(index);
|
||||
}
|
||||
|
||||
oop SystemDictionaryShared::shared_jar_manifest(int index) {
|
||||
return _shared_jar_manifests->obj_at(index);
|
||||
return ((objArrayOop)_shared_jar_manifests.resolve())->obj_at(index);
|
||||
}
|
||||
|
||||
Handle SystemDictionaryShared::get_shared_jar_manifest(int shared_path_index, TRAPS) {
|
||||
@ -926,30 +926,27 @@ InstanceKlass* SystemDictionaryShared::load_shared_class_for_builtin_loader(
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void SystemDictionaryShared::oops_do(OopClosure* f) {
|
||||
f->do_oop((oop*)&_shared_protection_domains);
|
||||
f->do_oop((oop*)&_shared_jar_urls);
|
||||
f->do_oop((oop*)&_shared_jar_manifests);
|
||||
}
|
||||
|
||||
void SystemDictionaryShared::allocate_shared_protection_domain_array(int size, TRAPS) {
|
||||
if (_shared_protection_domains == NULL) {
|
||||
_shared_protection_domains = oopFactory::new_objArray(
|
||||
if (_shared_protection_domains.resolve() == NULL) {
|
||||
oop spd = oopFactory::new_objArray(
|
||||
SystemDictionary::ProtectionDomain_klass(), size, CHECK);
|
||||
_shared_protection_domains = OopHandle::create(spd);
|
||||
}
|
||||
}
|
||||
|
||||
void SystemDictionaryShared::allocate_shared_jar_url_array(int size, TRAPS) {
|
||||
if (_shared_jar_urls == NULL) {
|
||||
_shared_jar_urls = oopFactory::new_objArray(
|
||||
if (_shared_jar_urls.resolve() == NULL) {
|
||||
oop sju = oopFactory::new_objArray(
|
||||
SystemDictionary::URL_klass(), size, CHECK);
|
||||
_shared_jar_urls = OopHandle::create(sju);
|
||||
}
|
||||
}
|
||||
|
||||
void SystemDictionaryShared::allocate_shared_jar_manifest_array(int size, TRAPS) {
|
||||
if (_shared_jar_manifests == NULL) {
|
||||
_shared_jar_manifests = oopFactory::new_objArray(
|
||||
if (_shared_jar_manifests.resolve() == NULL) {
|
||||
oop sjm = oopFactory::new_objArray(
|
||||
SystemDictionary::Jar_Manifest_klass(), size, CHECK);
|
||||
_shared_jar_manifests = OopHandle::create(sjm);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -122,9 +122,9 @@ private:
|
||||
// java.security.ProtectionDomain objects associated with each shared class.
|
||||
//
|
||||
// See SystemDictionaryShared::init_security_info for more info.
|
||||
static objArrayOop _shared_protection_domains;
|
||||
static objArrayOop _shared_jar_urls;
|
||||
static objArrayOop _shared_jar_manifests;
|
||||
static OopHandle _shared_protection_domains;
|
||||
static OopHandle _shared_jar_urls;
|
||||
static OopHandle _shared_jar_manifests;
|
||||
|
||||
static InstanceKlass* load_shared_class_for_builtin_loader(
|
||||
Symbol* class_name,
|
||||
@ -180,12 +180,12 @@ private:
|
||||
ModuleEntry* mod, TRAPS);
|
||||
static Handle init_security_info(Handle class_loader, InstanceKlass* ik, PackageEntry* pkg_entry, TRAPS);
|
||||
|
||||
static void atomic_set_array_index(objArrayOop array, int index, oop o) {
|
||||
static void atomic_set_array_index(OopHandle array, int index, oop o) {
|
||||
// Benign race condition: array.obj_at(index) may already be filled in.
|
||||
// The important thing here is that all threads pick up the same result.
|
||||
// It doesn't matter which racing thread wins, as long as only one
|
||||
// result is used by all threads, and all future queries.
|
||||
array->atomic_compare_exchange_oop(index, o, NULL);
|
||||
((objArrayOop)array.resolve())->atomic_compare_exchange_oop(index, o, NULL);
|
||||
}
|
||||
|
||||
static oop shared_protection_domain(int index);
|
||||
@ -235,7 +235,6 @@ public:
|
||||
|
||||
|
||||
static void allocate_shared_data_arrays(int size, TRAPS);
|
||||
static void oops_do(OopClosure* f);
|
||||
|
||||
// Check if sharing is supported for the class loader.
|
||||
static bool is_sharing_possible(ClassLoaderData* loader_data);
|
||||
|
||||
@ -173,6 +173,7 @@
|
||||
template(tag_runtime_invisible_type_annotations, "RuntimeInvisibleTypeAnnotations") \
|
||||
template(tag_enclosing_method, "EnclosingMethod") \
|
||||
template(tag_bootstrap_methods, "BootstrapMethods") \
|
||||
template(tag_permitted_subclasses, "PermittedSubclasses") \
|
||||
\
|
||||
/* exception klasses: at least all exceptions thrown by the VM have entries here */ \
|
||||
template(java_lang_ArithmeticException, "java/lang/ArithmeticException") \
|
||||
|
||||
@ -484,7 +484,7 @@ CodeBlob* CodeCache::next_blob(CodeHeap* heap, CodeBlob* cb) {
|
||||
*/
|
||||
CodeBlob* CodeCache::allocate(int size, int code_blob_type, int orig_code_blob_type) {
|
||||
// Possibly wakes up the sweeper thread.
|
||||
NMethodSweeper::notify(code_blob_type);
|
||||
NMethodSweeper::report_allocation(code_blob_type);
|
||||
assert_locked_or_safepoint(CodeCache_lock);
|
||||
assert(size > 0, "Code cache allocation request must be > 0 but is %d", size);
|
||||
if (size <= 0) {
|
||||
|
||||
@ -1116,7 +1116,9 @@ bool nmethod::can_convert_to_zombie() {
|
||||
// not_entrant. However, with concurrent code cache unloading, the state
|
||||
// might have moved on to unloaded if it is_unloading(), due to racing
|
||||
// concurrent GC threads.
|
||||
assert(is_not_entrant() || is_unloading(), "must be a non-entrant method");
|
||||
assert(is_not_entrant() || is_unloading() ||
|
||||
!Thread::current()->is_Code_cache_sweeper_thread(),
|
||||
"must be a non-entrant method if called from sweeper");
|
||||
|
||||
// Since the nmethod sweeper only does partial sweep the sweeper's traversal
|
||||
// count can be greater than the stack traversal count before it hits the
|
||||
@ -2004,23 +2006,22 @@ void nmethod::oops_do_marking_epilogue() {
|
||||
|
||||
nmethod* next = _oops_do_mark_nmethods;
|
||||
_oops_do_mark_nmethods = NULL;
|
||||
if (next == NULL) {
|
||||
return;
|
||||
}
|
||||
nmethod* cur;
|
||||
do {
|
||||
cur = next;
|
||||
next = extract_nmethod(cur->_oops_do_mark_link);
|
||||
cur->_oops_do_mark_link = NULL;
|
||||
DEBUG_ONLY(cur->verify_oop_relocations());
|
||||
if (next != NULL) {
|
||||
nmethod* cur;
|
||||
do {
|
||||
cur = next;
|
||||
next = extract_nmethod(cur->_oops_do_mark_link);
|
||||
cur->_oops_do_mark_link = NULL;
|
||||
DEBUG_ONLY(cur->verify_oop_relocations());
|
||||
|
||||
LogTarget(Trace, gc, nmethod) lt;
|
||||
if (lt.is_enabled()) {
|
||||
LogStream ls(lt);
|
||||
CompileTask::print(&ls, cur, "oops_do, unmark", /*short_form:*/ true);
|
||||
}
|
||||
// End if self-loop has been detected.
|
||||
} while (cur != next);
|
||||
LogTarget(Trace, gc, nmethod) lt;
|
||||
if (lt.is_enabled()) {
|
||||
LogStream ls(lt);
|
||||
CompileTask::print(&ls, cur, "oops_do, unmark", /*short_form:*/ true);
|
||||
}
|
||||
// End if self-loop has been detected.
|
||||
} while (cur != next);
|
||||
}
|
||||
log_trace(gc, nmethod)("oops_do_marking_epilogue");
|
||||
}
|
||||
|
||||
|
||||
@ -885,6 +885,9 @@ JavaThread* CompileBroker::make_thread(jobject thread_handle, CompileQueue* queu
|
||||
|
||||
|
||||
void CompileBroker::init_compiler_sweeper_threads() {
|
||||
NMethodSweeper::set_sweep_threshold_bytes(static_cast<size_t>(SweeperThreshold * ReservedCodeCacheSize / 100.0));
|
||||
log_info(codecache, sweep)("Sweeper threshold: " SIZE_FORMAT " bytes", NMethodSweeper::sweep_threshold_bytes());
|
||||
|
||||
// Ensure any exceptions lead to vm_exit_during_initialization.
|
||||
EXCEPTION_MARK;
|
||||
#if !defined(ZERO)
|
||||
@ -1652,7 +1655,8 @@ void CompileBroker::wait_for_completion(CompileTask* task) {
|
||||
bool free_task;
|
||||
#if INCLUDE_JVMCI
|
||||
AbstractCompiler* comp = compiler(task->comp_level());
|
||||
if (comp->is_jvmci()) {
|
||||
if (comp->is_jvmci() && !task->should_wait_for_compilation()) {
|
||||
// It may return before compilation is completed.
|
||||
free_task = wait_for_jvmci_completion((JVMCICompiler*) comp, task, thread);
|
||||
} else
|
||||
#endif
|
||||
|
||||
@ -134,6 +134,20 @@ class CompileTask : public CHeapObj<mtCompiler> {
|
||||
}
|
||||
}
|
||||
#if INCLUDE_JVMCI
|
||||
bool should_wait_for_compilation() const {
|
||||
// Wait for blocking compilation to finish.
|
||||
switch (_compile_reason) {
|
||||
case Reason_CTW:
|
||||
case Reason_Replay:
|
||||
case Reason_Whitebox:
|
||||
case Reason_MustBeCompiled:
|
||||
case Reason_Bootstrap:
|
||||
return _is_blocking;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool has_waiter() const { return _has_waiter; }
|
||||
void clear_waiter() { _has_waiter = false; }
|
||||
CompilerThread* jvmci_compiler_thread() const { return _jvmci_compiler_thread; }
|
||||
|
||||
@ -484,6 +484,13 @@ void CompilerConfig::ergo_initialize() {
|
||||
}
|
||||
}
|
||||
|
||||
if (FLAG_IS_DEFAULT(SweeperThreshold)) {
|
||||
if ((SweeperThreshold * ReservedCodeCacheSize / 100) > (1.2 * M)) {
|
||||
// Cap default SweeperThreshold value to an equivalent of 1.2 Mb
|
||||
FLAG_SET_ERGO(SweeperThreshold, (1.2 * M * 100) / ReservedCodeCacheSize);
|
||||
}
|
||||
}
|
||||
|
||||
if (UseOnStackReplacement && !UseLoopCounter) {
|
||||
warning("On-stack-replacement requires loop counters; enabling loop counters");
|
||||
FLAG_SET_DEFAULT(UseLoopCounter, true);
|
||||
|
||||
@ -286,8 +286,10 @@ void EpsilonHeap::print_on(outputStream *st) const {
|
||||
// Cast away constness:
|
||||
((VirtualSpace)_virtual_space).print_on(st);
|
||||
|
||||
st->print_cr("Allocation space:");
|
||||
_space->print_on(st);
|
||||
if (_space != NULL) {
|
||||
st->print_cr("Allocation space:");
|
||||
_space->print_on(st);
|
||||
}
|
||||
|
||||
MetaspaceUtils::print_on(st);
|
||||
}
|
||||
|
||||
@ -52,7 +52,8 @@ public:
|
||||
static EpsilonHeap* heap();
|
||||
|
||||
EpsilonHeap() :
|
||||
_memory_manager("Epsilon Heap", "") {};
|
||||
_memory_manager("Epsilon Heap", ""),
|
||||
_space(NULL) {};
|
||||
|
||||
virtual Name kind() const {
|
||||
return CollectedHeap::Epsilon;
|
||||
@ -116,7 +117,6 @@ public:
|
||||
bool block_is_obj(const HeapWord* addr) const { return false; }
|
||||
|
||||
// No GC threads
|
||||
virtual void print_gc_threads_on(outputStream* st) const {}
|
||||
virtual void gc_threads_do(ThreadClosure* tc) const {}
|
||||
|
||||
// No nmethod handling
|
||||
|
||||
@ -103,7 +103,7 @@ void G1BarrierSetC1::pre_barrier(LIRAccess& access, LIR_Opr addr_opr,
|
||||
slow = new G1PreBarrierStub(pre_val);
|
||||
}
|
||||
|
||||
__ branch(lir_cond_notEqual, T_INT, slow);
|
||||
__ branch(lir_cond_notEqual, slow);
|
||||
__ branch_destination(slow->continuation());
|
||||
}
|
||||
|
||||
@ -171,7 +171,7 @@ void G1BarrierSetC1::post_barrier(LIRAccess& access, LIR_OprDesc* addr, LIR_OprD
|
||||
__ cmp(lir_cond_notEqual, xor_shift_res, LIR_OprFact::intptrConst(NULL_WORD));
|
||||
|
||||
CodeStub* slow = new G1PostBarrierStub(addr, new_val);
|
||||
__ branch(lir_cond_notEqual, LP64_ONLY(T_LONG) NOT_LP64(T_INT), slow);
|
||||
__ branch(lir_cond_notEqual, slow);
|
||||
__ branch_destination(slow->continuation());
|
||||
}
|
||||
|
||||
|
||||
@ -871,7 +871,8 @@ HeapWord* G1CollectedHeap::attempt_allocation_humongous(size_t word_size) {
|
||||
result = humongous_obj_allocate(word_size);
|
||||
if (result != NULL) {
|
||||
size_t size_in_regions = humongous_obj_size_in_regions(word_size);
|
||||
policy()->add_bytes_allocated_in_old_since_last_gc(size_in_regions * HeapRegion::GrainBytes);
|
||||
policy()->old_gen_alloc_tracker()->
|
||||
add_allocated_bytes_since_last_gc(size_in_regions * HeapRegion::GrainBytes);
|
||||
return result;
|
||||
}
|
||||
|
||||
@ -2507,11 +2508,13 @@ void G1CollectedHeap::print_heap_regions() const {
|
||||
|
||||
void G1CollectedHeap::print_on(outputStream* st) const {
|
||||
st->print(" %-20s", "garbage-first heap");
|
||||
st->print(" total " SIZE_FORMAT "K, used " SIZE_FORMAT "K",
|
||||
capacity()/K, used_unlocked()/K);
|
||||
st->print(" [" PTR_FORMAT ", " PTR_FORMAT ")",
|
||||
p2i(_hrm->reserved().start()),
|
||||
p2i(_hrm->reserved().end()));
|
||||
if (_hrm != NULL) {
|
||||
st->print(" total " SIZE_FORMAT "K, used " SIZE_FORMAT "K",
|
||||
capacity()/K, used_unlocked()/K);
|
||||
st->print(" [" PTR_FORMAT ", " PTR_FORMAT ")",
|
||||
p2i(_hrm->reserved().start()),
|
||||
p2i(_hrm->reserved().end()));
|
||||
}
|
||||
st->cr();
|
||||
st->print(" region size " SIZE_FORMAT "K, ", HeapRegion::GrainBytes / K);
|
||||
uint young_regions = young_regions_count();
|
||||
@ -2526,7 +2529,8 @@ void G1CollectedHeap::print_on(outputStream* st) const {
|
||||
st->print(" remaining free region(s) on each NUMA node: ");
|
||||
const int* node_ids = _numa->node_ids();
|
||||
for (uint node_index = 0; node_index < num_nodes; node_index++) {
|
||||
st->print("%d=%u ", node_ids[node_index], _hrm->num_free_regions(node_index));
|
||||
uint num_free_regions = (_hrm != NULL ? _hrm->num_free_regions(node_index) : 0);
|
||||
st->print("%d=%u ", node_ids[node_index], num_free_regions);
|
||||
}
|
||||
st->cr();
|
||||
}
|
||||
@ -2534,6 +2538,10 @@ void G1CollectedHeap::print_on(outputStream* st) const {
|
||||
}
|
||||
|
||||
void G1CollectedHeap::print_regions_on(outputStream* st) const {
|
||||
if (_hrm == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
st->print_cr("Heap Regions: E=young(eden), S=young(survivor), O=old, "
|
||||
"HS=humongous(starts), HC=humongous(continues), "
|
||||
"CS=collection set, F=free, "
|
||||
@ -2559,18 +2567,6 @@ void G1CollectedHeap::print_on_error(outputStream* st) const {
|
||||
}
|
||||
}
|
||||
|
||||
void G1CollectedHeap::print_gc_threads_on(outputStream* st) const {
|
||||
workers()->print_worker_threads_on(st);
|
||||
_cm_thread->print_on(st);
|
||||
st->cr();
|
||||
_cm->print_worker_threads_on(st);
|
||||
_cr->print_threads_on(st);
|
||||
_young_gen_sampling_thread->print_on(st);
|
||||
if (G1StringDedup::is_enabled()) {
|
||||
G1StringDedup::print_worker_threads_on(st);
|
||||
}
|
||||
}
|
||||
|
||||
void G1CollectedHeap::gc_threads_do(ThreadClosure* tc) const {
|
||||
workers()->threads_do(tc);
|
||||
tc->do_thread(_cm_thread);
|
||||
@ -4085,7 +4081,8 @@ void G1CollectedHeap::post_evacuate_collection_set(G1EvacuationInfo& evacuation_
|
||||
}
|
||||
|
||||
void G1CollectedHeap::record_obj_copy_mem_stats() {
|
||||
policy()->add_bytes_allocated_in_old_since_last_gc(_old_evac_stats.allocated() * HeapWordSize);
|
||||
policy()->old_gen_alloc_tracker()->
|
||||
add_allocated_bytes_since_last_gc(_old_evac_stats.allocated() * HeapWordSize);
|
||||
|
||||
_gc_tracer_stw->report_evacuation_statistics(create_g1_evac_summary(&_survivor_evac_stats),
|
||||
create_g1_evac_summary(&_old_evac_stats));
|
||||
@ -4186,7 +4183,7 @@ class G1FreeCollectionSetTask : public AbstractGangTask {
|
||||
g1h->alloc_buffer_stats(G1HeapRegionAttr::Old)->add_failure_used_and_waste(_failure_used_words, _failure_waste_words);
|
||||
|
||||
G1Policy *policy = g1h->policy();
|
||||
policy->add_bytes_allocated_in_old_since_last_gc(_bytes_allocated_in_old_since_last_gc);
|
||||
policy->old_gen_alloc_tracker()->add_allocated_bytes_since_last_gc(_bytes_allocated_in_old_since_last_gc);
|
||||
policy->record_rs_length(_rs_length);
|
||||
policy->cset_regions_freed();
|
||||
}
|
||||
|
||||
@ -1454,7 +1454,6 @@ public:
|
||||
virtual void print_extended_on(outputStream* st) const;
|
||||
virtual void print_on_error(outputStream* st) const;
|
||||
|
||||
virtual void print_gc_threads_on(outputStream* st) const;
|
||||
virtual void gc_threads_do(ThreadClosure* tc) const;
|
||||
|
||||
// Override
|
||||
|
||||
@ -2026,10 +2026,6 @@ void G1ConcurrentMark::print_summary_info() {
|
||||
cm_thread()->vtime_accum(), cm_thread()->vtime_mark_accum());
|
||||
}
|
||||
|
||||
void G1ConcurrentMark::print_worker_threads_on(outputStream* st) const {
|
||||
_concurrent_workers->print_worker_threads_on(st);
|
||||
}
|
||||
|
||||
void G1ConcurrentMark::threads_do(ThreadClosure* tc) const {
|
||||
_concurrent_workers->threads_do(tc);
|
||||
}
|
||||
|
||||
@ -583,7 +583,6 @@ public:
|
||||
|
||||
void print_summary_info();
|
||||
|
||||
void print_worker_threads_on(outputStream* st) const;
|
||||
void threads_do(ThreadClosure* tc) const;
|
||||
|
||||
void print_on_error(outputStream* st) const;
|
||||
|
||||
@ -114,15 +114,6 @@ void G1ConcurrentRefineThreadControl::maybe_activate_next(uint cur_worker_id) {
|
||||
}
|
||||
}
|
||||
|
||||
void G1ConcurrentRefineThreadControl::print_on(outputStream* st) const {
|
||||
for (uint i = 0; i < _num_max_threads; ++i) {
|
||||
if (_threads[i] != NULL) {
|
||||
_threads[i]->print_on(st);
|
||||
st->cr();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void G1ConcurrentRefineThreadControl::worker_threads_do(ThreadClosure* tc) {
|
||||
for (uint i = 0; i < _num_max_threads; i++) {
|
||||
if (_threads[i] != NULL) {
|
||||
@ -318,10 +309,6 @@ uint G1ConcurrentRefine::max_num_threads() {
|
||||
return G1ConcRefinementThreads;
|
||||
}
|
||||
|
||||
void G1ConcurrentRefine::print_threads_on(outputStream* st) const {
|
||||
_thread_control.print_on(st);
|
||||
}
|
||||
|
||||
static size_t calc_new_green_zone(size_t green,
|
||||
double logged_cards_scan_time,
|
||||
size_t processed_logged_cards,
|
||||
|
||||
@ -57,7 +57,6 @@ public:
|
||||
// activate it.
|
||||
void maybe_activate_next(uint cur_worker_id);
|
||||
|
||||
void print_on(outputStream* st) const;
|
||||
void worker_threads_do(ThreadClosure* tc);
|
||||
void stop();
|
||||
};
|
||||
@ -139,8 +138,6 @@ public:
|
||||
// Maximum number of refinement threads.
|
||||
static uint max_num_threads();
|
||||
|
||||
void print_threads_on(outputStream* st) const;
|
||||
|
||||
// Cards in the dirty card queue set.
|
||||
size_t green_zone() const { return _green_zone; }
|
||||
size_t yellow_zone() const { return _yellow_zone; }
|
||||
|
||||
@ -62,7 +62,7 @@ G1GCPhaseTimes::G1GCPhaseTimes(STWGCTimer* gc_timer, uint max_gc_threads) :
|
||||
_gc_par_phases[JNIRoots] = new WorkerDataArray<double>("JNI Handles Roots (ms):", max_gc_threads);
|
||||
_gc_par_phases[ObjectSynchronizerRoots] = new WorkerDataArray<double>("ObjectSynchronizer Roots (ms):", max_gc_threads);
|
||||
_gc_par_phases[ManagementRoots] = new WorkerDataArray<double>("Management Roots (ms):", max_gc_threads);
|
||||
_gc_par_phases[SystemDictionaryRoots] = new WorkerDataArray<double>("SystemDictionary Roots (ms):", max_gc_threads);
|
||||
_gc_par_phases[VMGlobalRoots] = new WorkerDataArray<double>("VM Global Roots (ms):", max_gc_threads);
|
||||
_gc_par_phases[CLDGRoots] = new WorkerDataArray<double>("CLDG Roots (ms):", max_gc_threads);
|
||||
_gc_par_phases[JVMTIRoots] = new WorkerDataArray<double>("JVMTI Roots (ms):", max_gc_threads);
|
||||
AOT_ONLY(_gc_par_phases[AOTCodeRoots] = new WorkerDataArray<double>("AOT Root Scan (ms):", max_gc_threads);)
|
||||
@ -561,7 +561,7 @@ const char* G1GCPhaseTimes::phase_name(GCParPhases phase) {
|
||||
"JNIRoots",
|
||||
"ObjectSynchronizerRoots",
|
||||
"ManagementRoots",
|
||||
"SystemDictionaryRoots",
|
||||
"VMGlobalRoots",
|
||||
"CLDGRoots",
|
||||
"JVMTIRoots",
|
||||
AOT_ONLY("AOTCodeRoots" COMMA)
|
||||
|
||||
@ -51,7 +51,7 @@ class G1GCPhaseTimes : public CHeapObj<mtGC> {
|
||||
JNIRoots,
|
||||
ObjectSynchronizerRoots,
|
||||
ManagementRoots,
|
||||
SystemDictionaryRoots,
|
||||
VMGlobalRoots,
|
||||
CLDGRoots,
|
||||
JVMTIRoots,
|
||||
AOT_ONLY(AOTCodeRoots COMMA)
|
||||
|
||||
42
src/hotspot/share/gc/g1/g1OldGenAllocationTracker.cpp
Normal file
42
src/hotspot/share/gc/g1/g1OldGenAllocationTracker.cpp
Normal file
@ -0,0 +1,42 @@
|
||||
/*
|
||||
* Copyright (c) 2020, Amazon.com, Inc. or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "precompiled.hpp"
|
||||
#include "gc/g1/g1OldGenAllocationTracker.hpp"
|
||||
|
||||
G1OldGenAllocationTracker::G1OldGenAllocationTracker() :
|
||||
_last_cycle_old_bytes(0),
|
||||
_last_cycle_duration(0.0),
|
||||
_allocated_bytes_since_last_gc(0) {
|
||||
}
|
||||
|
||||
void G1OldGenAllocationTracker::reset_after_full_gc() {
|
||||
_last_cycle_duration = 0;
|
||||
reset_cycle_after_gc();
|
||||
}
|
||||
|
||||
void G1OldGenAllocationTracker::reset_after_young_gc(double allocation_duration_s) {
|
||||
_last_cycle_duration = allocation_duration_s;
|
||||
reset_cycle_after_gc();
|
||||
}
|
||||
61
src/hotspot/share/gc/g1/g1OldGenAllocationTracker.hpp
Normal file
61
src/hotspot/share/gc/g1/g1OldGenAllocationTracker.hpp
Normal file
@ -0,0 +1,61 @@
|
||||
/*
|
||||
* Copyright (c) 2020, Amazon.com, Inc. or its affiliates. All rights reserved.
|
||||
* 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_GC_G1_G1OLDGENALLOCATIONTRACKER_HPP
|
||||
#define SHARE_VM_GC_G1_G1OLDGENALLOCATIONTRACKER_HPP
|
||||
|
||||
#include "gc/g1/heapRegion.hpp"
|
||||
#include "memory/allocation.hpp"
|
||||
|
||||
// Track allocation details in the old generation.
|
||||
class G1OldGenAllocationTracker : public CHeapObj<mtGC> {
|
||||
// New bytes allocated in old gen between the end of the last GC and
|
||||
// the end of the GC before that.
|
||||
size_t _last_cycle_old_bytes;
|
||||
// The number of seconds between the end of the last GC and
|
||||
// the end of the GC before that.
|
||||
double _last_cycle_duration;
|
||||
|
||||
size_t _allocated_bytes_since_last_gc;
|
||||
|
||||
void reset_cycle_after_gc() {
|
||||
_last_cycle_old_bytes = _allocated_bytes_since_last_gc;
|
||||
_allocated_bytes_since_last_gc = 0;
|
||||
}
|
||||
|
||||
public:
|
||||
G1OldGenAllocationTracker();
|
||||
// Add the given number of bytes to the total number of allocated bytes in the old gen.
|
||||
void add_allocated_bytes_since_last_gc(size_t bytes) { _allocated_bytes_since_last_gc += bytes; }
|
||||
|
||||
size_t last_cycle_old_bytes() { return _last_cycle_old_bytes; }
|
||||
|
||||
double last_cycle_duration() { return _last_cycle_duration; }
|
||||
|
||||
// Reset stats after a collection.
|
||||
void reset_after_full_gc();
|
||||
void reset_after_young_gc(double allocation_duration_s);
|
||||
};
|
||||
|
||||
#endif // SHARE_VM_GC_G1_G1OLDGENALLOCATIONTRACKER_HPP
|
||||
@ -73,7 +73,7 @@ G1Policy::G1Policy(STWGCTimer* gc_timer) :
|
||||
_rs_length(0),
|
||||
_rs_length_prediction(0),
|
||||
_pending_cards_at_gc_start(0),
|
||||
_bytes_allocated_in_old_since_last_gc(0),
|
||||
_old_gen_alloc_tracker(),
|
||||
_initial_mark_to_mixed(),
|
||||
_collection_set(NULL),
|
||||
_g1h(NULL),
|
||||
@ -460,7 +460,7 @@ void G1Policy::record_full_collection_end() {
|
||||
update_young_list_max_and_target_length();
|
||||
update_rs_length_prediction();
|
||||
|
||||
_bytes_allocated_in_old_since_last_gc = 0;
|
||||
_old_gen_alloc_tracker.reset_after_full_gc();
|
||||
|
||||
record_pause(FullGC, _full_collection_start_sec, end_sec);
|
||||
}
|
||||
@ -795,11 +795,11 @@ void G1Policy::record_collection_pause_end(double pause_time_ms) {
|
||||
// predicted target occupancy.
|
||||
size_t last_unrestrained_young_length = update_young_list_max_and_target_length();
|
||||
|
||||
update_ihop_prediction(app_time_ms / 1000.0,
|
||||
_bytes_allocated_in_old_since_last_gc,
|
||||
_old_gen_alloc_tracker.reset_after_young_gc(app_time_ms / 1000.0);
|
||||
update_ihop_prediction(_old_gen_alloc_tracker.last_cycle_duration(),
|
||||
_old_gen_alloc_tracker.last_cycle_old_bytes(),
|
||||
last_unrestrained_young_length * HeapRegion::GrainBytes,
|
||||
this_pause_was_young_only);
|
||||
_bytes_allocated_in_old_since_last_gc = 0;
|
||||
|
||||
_ihop_control->send_trace_event(_g1h->gc_tracer_stw());
|
||||
} else {
|
||||
|
||||
@ -30,6 +30,7 @@
|
||||
#include "gc/g1/g1HeapRegionAttr.hpp"
|
||||
#include "gc/g1/g1InitialMarkToMixedTimeTracker.hpp"
|
||||
#include "gc/g1/g1MMUTracker.hpp"
|
||||
#include "gc/g1/g1OldGenAllocationTracker.hpp"
|
||||
#include "gc/g1/g1RemSetTrackingPolicy.hpp"
|
||||
#include "gc/g1/g1Predictions.hpp"
|
||||
#include "gc/g1/g1YoungGenSizer.hpp"
|
||||
@ -102,9 +103,9 @@ class G1Policy: public CHeapObj<mtGC> {
|
||||
|
||||
size_t _pending_cards_at_gc_start;
|
||||
|
||||
// The amount of allocated bytes in old gen during the last mutator and the following
|
||||
// young GC phase.
|
||||
size_t _bytes_allocated_in_old_since_last_gc;
|
||||
// Tracking the allocation in the old generation between
|
||||
// two GCs.
|
||||
G1OldGenAllocationTracker _old_gen_alloc_tracker;
|
||||
|
||||
G1InitialMarkToMixedTimeTracker _initial_mark_to_mixed;
|
||||
|
||||
@ -119,8 +120,7 @@ public:
|
||||
|
||||
G1RemSetTrackingPolicy* remset_tracker() { return &_remset_tracker; }
|
||||
|
||||
// Add the given number of bytes to the total number of allocated bytes in the old gen.
|
||||
void add_bytes_allocated_in_old_since_last_gc(size_t bytes) { _bytes_allocated_in_old_since_last_gc += bytes; }
|
||||
G1OldGenAllocationTracker* old_gen_alloc_tracker() { return &_old_gen_alloc_tracker; }
|
||||
|
||||
void set_region_eden(HeapRegion* hr) {
|
||||
hr->set_eden();
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user