This commit is contained in:
Henry Jen 2018-12-13 11:47:35 -08:00
commit d77f96b0b2
684 changed files with 47732 additions and 20486 deletions

View File

@ -1,19 +1,24 @@
<!DOCTYPE html>
<html>
<html xmlns="http://www.w3.org/1999/xhtml" lang="" xml:lang="">
<head>
<meta charset="utf-8">
<meta name="generator" content="pandoc">
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=yes">
<meta charset="utf-8" />
<meta name="generator" content="pandoc" />
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=yes" />
<title>Building the JDK</title>
<style type="text/css">code{white-space: pre;}</style>
<link rel="stylesheet" href="../make/data/docs-resources/resources/jdk-default.css">
<style type="text/css">
code{white-space: pre-wrap;}
span.smallcaps{font-variant: small-caps;}
span.underline{text-decoration: underline;}
div.column{display: inline-block; vertical-align: top; width: 50%;}
</style>
<link rel="stylesheet" href="../make/data/docs-resources/resources/jdk-default.css" />
<!--[if lt IE 9]>
<script src="//cdnjs.cloudflare.com/ajax/libs/html5shiv/3.7.3/html5shiv-printshiv.min.js"></script>
<![endif]-->
<style type="text/css">pre, code, tt { color: #1d6ae5; }</style>
</head>
<body>
<header>
<header id="title-block-header">
<h1 class="title">Building the JDK</h1>
</header>
<nav id="TOC">
@ -640,11 +645,13 @@ x86_64-linux-gnu-to-ppc64le-linux-gnu</code></pre>
<p>Note that alsa is needed even if you only want to build a headless JDK.</p>
<ul>
<li><p>Go to <a href="https://www.debian.org/distrib/packages">Debian Package Search</a> and search for the <code>libasound2</code> and <code>libasound2-dev</code> packages for your <em>target</em> system. Download them to /tmp.</p></li>
<li><p>Install the libraries into the cross-compilation toolchain. For instance:</p>
<li>Install the libraries into the cross-compilation toolchain. For instance:</li>
</ul>
<pre><code>cd /tools/gcc-linaro-arm-linux-gnueabihf-raspbian-2012.09-20120921_linux/arm-linux-gnueabihf/libc
dpkg-deb -x /tmp/libasound2_1.0.25-4_armhf.deb .
dpkg-deb -x /tmp/libasound2-dev_1.0.25-4_armhf.deb .</code></pre></li>
<li><p>If alsa is not properly detected by <code>configure</code>, you can point it out by <code>--with-alsa</code>.</p></li>
dpkg-deb -x /tmp/libasound2-dev_1.0.25-4_armhf.deb .</code></pre>
<ul>
<li>If alsa is not properly detected by <code>configure</code>, you can point it out by <code>--with-alsa</code>.</li>
</ul>
<h4 id="x11-1">X11</h4>
<p>You will need X11 libraries suitable for your <em>target</em> system. For most cases, using Debian's pre-built libraries work fine.</p>
@ -690,17 +697,21 @@ cp: cannot stat `arm-linux-gnueabihf/libXt.so&#39;: No such file or directory</c
<p>Fortunately, you can create sysroots for foreign architectures with tools provided by your OS. On Debian/Ubuntu systems, one could use <code>qemu-deboostrap</code> to create the <em>target</em> system chroot, which would have the native libraries and headers specific to that <em>target</em> system. After that, we can use the cross-compiler on the <em>build</em> system, pointing into chroot to get the build dependencies right. This allows building for foreign architectures with native compilation speed.</p>
<p>For example, cross-compiling to AArch64 from x86_64 could be done like this:</p>
<ul>
<li><p>Install cross-compiler on the <em>build</em> system:</p>
<pre><code>apt install g++-aarch64-linux-gnu gcc-aarch64-linux-gnu</code></pre></li>
<li><p>Create chroot on the <em>build</em> system, configuring it for <em>target</em> system:</p>
<li>Install cross-compiler on the <em>build</em> system:</li>
</ul>
<pre><code>apt install g++-aarch64-linux-gnu gcc-aarch64-linux-gnu</code></pre>
<ul>
<li>Create chroot on the <em>build</em> system, configuring it for <em>target</em> system:</li>
</ul>
<pre><code>sudo qemu-debootstrap --arch=arm64 --verbose \
--include=fakeroot,build-essential,libx11-dev,libxext-dev,libxrender-dev,libxrandr-dev,libxtst-dev,libxt-dev,libcups2-dev,libfontconfig1-dev,libasound2-dev,libfreetype6-dev,libpng12-dev \
--resolve-deps jessie /chroots/arm64 http://httpredir.debian.org/debian/</code></pre></li>
<li><p>Configure and build with newly created chroot as sysroot/toolchain-path:</p>
--include=fakeroot,build-essential,libx11-dev,libxext-dev,libxrender-dev,libxrandr-dev,libxtst-dev,libxt-dev,libcups2-dev,libfontconfig1-dev,libasound2-dev,libfreetype6-dev,libpng12-dev \
--resolve-deps jessie /chroots/arm64 http://httpredir.debian.org/debian/</code></pre>
<ul>
<li>Configure and build with newly created chroot as sysroot/toolchain-path:</li>
</ul>
<pre><code>CC=aarch64-linux-gnu-gcc CXX=aarch64-linux-gnu-g++ sh ./configure --openjdk-target=aarch64-linux-gnu --with-sysroot=/chroots/arm64/ --with-toolchain-path=/chroots/arm64/
make images
ls build/linux-aarch64-normal-server-release/</code></pre></li>
</ul>
ls build/linux-aarch64-normal-server-release/</code></pre>
<p>The build does not create new files in that chroot, so it can be reused for multiple builds without additional cleanup.</p>
<p>Architectures that are known to successfully cross-compile like this are:</p>
<table>
@ -860,12 +871,7 @@ cannot create ... Permission denied
spawn failed</code></pre>
<p>This can be a sign of a Cygwin problem. See the information about solving problems in the <a href="#cygwin">Cygwin</a> section. Rebooting the computer might help temporarily.</p>
<h3 id="getting-help">Getting Help</h3>
<p>If none of the suggestions in this document helps you, or if you find what you believe is a bug in the build system, please contact the Build Group by sending a mail to <script type="text/javascript">
<!--
h='&#x6f;&#112;&#x65;&#110;&#106;&#100;&#x6b;&#46;&#106;&#x61;&#118;&#x61;&#46;&#110;&#x65;&#116;';a='&#64;';n='&#98;&#x75;&#x69;&#108;&#100;&#x2d;&#100;&#x65;&#118;';e=n+a+h;
document.write('<a h'+'ref'+'="ma'+'ilto'+':'+e+'" clas'+'s="em' + 'ail">'+e+'<\/'+'a'+'>');
// -->
</script><noscript>&#98;&#x75;&#x69;&#108;&#100;&#x2d;&#100;&#x65;&#118;&#32;&#x61;&#116;&#32;&#x6f;&#112;&#x65;&#110;&#106;&#100;&#x6b;&#32;&#100;&#x6f;&#116;&#32;&#106;&#x61;&#118;&#x61;&#32;&#100;&#x6f;&#116;&#32;&#110;&#x65;&#116;</noscript>. Please include the relevant parts of the configure and/or build log.</p>
<p>If none of the suggestions in this document helps you, or if you find what you believe is a bug in the build system, please contact the Build Group by sending a mail to <a href="mailto:build-dev@openjdk.java.net">build-dev@openjdk.java.net</a>. Please include the relevant parts of the configure and/or build log.</p>
<p>If you need general help or advice about developing for the JDK, you can also contact the Adoption Group. See the section on <a href="#contributing-to-openjdk">Contributing to OpenJDK</a> for more information.</p>
<h2 id="hints-and-suggestions-for-advanced-users">Hints and Suggestions for Advanced Users</h2>
<h3 id="setting-up-a-repository-for-pushing-changes-defpath">Setting Up a Repository for Pushing Changes (defpath)</h3>

View File

@ -918,7 +918,7 @@ targets are given, a native toolchain for the current platform will be
created. Currently, at least the following targets are known to work:
Supported devkit targets
------------------------
-------------------------
x86_64-linux-gnu
aarch64-linux-gnu
arm-linux-gnueabihf
@ -1129,13 +1129,13 @@ without additional cleanup.
Architectures that are known to successfully cross-compile like this are:
Target `CC` `CXX` `--arch=...` `--openjdk-target=...`
------------ ------------------------- --------------------------- ------------ ----------------------
x86 default default i386 i386-linux-gnu
armhf gcc-arm-linux-gnueabihf g++-arm-linux-gnueabihf armhf arm-linux-gnueabihf
aarch64 gcc-aarch64-linux-gnu g++-aarch64-linux-gnu arm64 aarch64-linux-gnu
ppc64el gcc-powerpc64le-linux-gnu g++-powerpc64le-linux-gnu ppc64el powerpc64le-linux-gnu
s390x gcc-s390x-linux-gnu g++-s390x-linux-gnu s390x s390x-linux-gnu
Target `CC` `CXX` `--arch=...` `--openjdk-target=...`
------------ ------------------------- --------------------------- ------------- -----------------------
x86 default default i386 i386-linux-gnu
armhf gcc-arm-linux-gnueabihf g++-arm-linux-gnueabihf armhf arm-linux-gnueabihf
aarch64 gcc-aarch64-linux-gnu g++-aarch64-linux-gnu arm64 aarch64-linux-gnu
ppc64el gcc-powerpc64le-linux-gnu g++-powerpc64le-linux-gnu ppc64el powerpc64le-linux-gnu
s390x gcc-s390x-linux-gnu g++-s390x-linux-gnu s390x s390x-linux-gnu
Additional architectures might be supported by Debian/Ubuntu Ports.

View File

@ -1,19 +1,24 @@
<!DOCTYPE html>
<html>
<html xmlns="http://www.w3.org/1999/xhtml" lang="" xml:lang="">
<head>
<meta charset="utf-8">
<meta name="generator" content="pandoc">
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=yes">
<meta charset="utf-8" />
<meta name="generator" content="pandoc" />
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=yes" />
<title>Testing the JDK</title>
<style type="text/css">code{white-space: pre;}</style>
<link rel="stylesheet" href="../make/data/docs-resources/resources/jdk-default.css">
<style type="text/css">
code{white-space: pre-wrap;}
span.smallcaps{font-variant: small-caps;}
span.underline{text-decoration: underline;}
div.column{display: inline-block; vertical-align: top; width: 50%;}
</style>
<link rel="stylesheet" href="../make/data/docs-resources/resources/jdk-default.css" />
<!--[if lt IE 9]>
<script src="//cdnjs.cloudflare.com/ajax/libs/html5shiv/3.7.3/html5shiv-printshiv.min.js"></script>
<![endif]-->
<style type="text/css">pre, code, tt { color: #1d6ae5; }</style>
</head>
<body>
<header>
<header id="title-block-header">
<h1 class="title">Testing the JDK</h1>
</header>
<nav id="TOC">

View File

@ -321,7 +321,7 @@ jdk.jshell_COPY += .jsh .properties
################################################################################
jdk.internal.le_COPY += .properties
jdk.internal.le_COPY += .properties .caps .txt
################################################################################

View File

@ -91,15 +91,17 @@ TARGETS += $(COMPILE_DEPEND) $(DEPEND_SERVICE_PROVIDER)
# To be able to call the javascript filter when generating man pages using
# pandoc, we need to create this executable wrapper script.
ifneq ($(PANDOC), )
# PANDOC_FILTER is duplicated for export in ToolsJdk.gmk.
PANDOC_FILTER := $(BUILDTOOLS_OUTPUTDIR)/manpages/pandoc-manpage-filter
PANDOC_FILTER_SETUP := $(BUILDTOOLS_OUTPUTDIR)/manpages/_pandoc_filter_setup.marker
# PANDOC_TROFF_MANPAGE_FILTER is duplicated for export in ToolsJdk.gmk.
PANDOC_TROFF_MANPAGE_FILTER := \
$(BUILDTOOLS_OUTPUTDIR)/manpages/pandoc-troff-manpage-filter
PANDOC_TROFF_MANPAGE_FILTER_SETUP := \
$(BUILDTOOLS_OUTPUTDIR)/manpages/_pandoc_troff_manpage_filter_setup.marker
# Create a usable instance of the wrapper script that calls the pandoc filter
# (which is written in javascript).
$(eval $(call SetupTextFileProcessing, CREATE_PANDOC_FILTER, \
SOURCE_FILES := $(TOPDIR)/make/scripts/pandoc-manpage-filter.sh.template, \
OUTPUT_FILE := $(PANDOC_FILTER), \
$(eval $(call SetupTextFileProcessing, CREATE_PANDOC_TROFF_MANPAGE_FILTER, \
SOURCE_FILES := $(TOPDIR)/make/scripts/pandoc-troff-manpage-filter.sh.template, \
OUTPUT_FILE := $(PANDOC_TROFF_MANPAGE_FILTER), \
REPLACEMENTS := \
@@BOOT_JDK@@ => $(BOOT_JDK) ; \
@@TOPDIR@@ => $(TOPDIR) ; \
@ -107,11 +109,35 @@ ifneq ($(PANDOC), )
))
# Created script must be made executable
$(PANDOC_FILTER_SETUP): $(CREATE_PANDOC_FILTER)
$(CHMOD) a+rx $(PANDOC_FILTER)
$(PANDOC_TROFF_MANPAGE_FILTER_SETUP): $(CREATE_PANDOC_TROFF_MANPAGE_FILTER)
$(CHMOD) a+rx $(PANDOC_TROFF_MANPAGE_FILTER)
$(TOUCH) $@
TARGETS += $(PANDOC_FILTER_SETUP)
TARGETS += $(PANDOC_TROFF_MANPAGE_FILTER_SETUP)
# PANDOC_HTML_MANPAGE_FILTER is duplicated for export in ToolsJdk.gmk.
PANDOC_HTML_MANPAGE_FILTER := \
$(BUILDTOOLS_OUTPUTDIR)/manpages/pandoc-html-manpage-filter
PANDOC_HTML_MANPAGE_FILTER_SETUP := \
$(BUILDTOOLS_OUTPUTDIR)/manpages/_pandoc_html_manpage_filter_setup.marker
# Create a usable instance of the wrapper script that calls the pandoc filter
# (which is written in javascript).
$(eval $(call SetupTextFileProcessing, CREATE_PANDOC_HTML_MANPAGE_FILTER, \
SOURCE_FILES := $(TOPDIR)/make/scripts/pandoc-html-manpage-filter.sh.template, \
OUTPUT_FILE := $(PANDOC_HTML_MANPAGE_FILTER), \
REPLACEMENTS := \
@@BOOT_JDK@@ => $(BOOT_JDK) ; \
@@TOPDIR@@ => $(TOPDIR) ; \
@@JJS_FLAGS@@ => $(addprefix -J, $(JAVA_FLAGS_SMALL)), \
))
# Created script must be made executable
$(PANDOC_HTML_MANPAGE_FILTER_SETUP): $(CREATE_PANDOC_HTML_MANPAGE_FILTER)
$(CHMOD) a+rx $(PANDOC_HTML_MANPAGE_FILTER)
$(TOUCH) $@
TARGETS += $(PANDOC_HTML_MANPAGE_FILTER_SETUP)
endif
all: $(TARGETS)

View File

@ -27,10 +27,10 @@ default: all
include $(SPEC)
include MakeBase.gmk
include Modules.gmk
include ModuleTools.gmk
include ProcessMarkdown.gmk
include ToolsJdk.gmk
include ZipArchive.gmk
include $(TOPDIR)/make/ToolsJdk.gmk
include $(TOPDIR)/make/ModuleTools.gmk
# This is needed to properly setup DOCS_MODULES.
$(eval $(call ReadImportMetaData))
@ -168,14 +168,6 @@ JAVADOC_TOP := \
font-family: DejaVu Sans, Arial, Helvetica, sans-serif; \
font-weight: normal;">$(DRAFT_TEXT)</div>
JDK_INDEX_CONTENT := \
<!DOCTYPE html> \
<html lang="en"> \
<head> \
<meta http-equiv="refresh" content="0;url=api/index.html"> \
</head> \
</html>
################################################################################
# JDK javadoc titles/text snippets
@ -485,14 +477,7 @@ $(eval $(call SetupApiDocsGeneration, REFERENCE_API, \
################################################################################
JDK_INDEX_HTML := $(DOCS_OUTPUTDIR)/index.html
$(JDK_INDEX_HTML):
$(ECHO) '$(JDK_INDEX_CONTENT)' > $@
JDK_INDEX_TARGETS += $(JDK_INDEX_HTML)
# Copy the global resources
# Copy the global resources, including the top-level redirect index.html
GLOBAL_SPECS_RESOURCES_DIR := $(TOPDIR)/make/data/docs-resources/
$(eval $(call SetupCopyFiles, COPY_GLOBAL_RESOURCES, \
SRC := $(GLOBAL_SPECS_RESOURCES_DIR), \
@ -532,9 +517,9 @@ $(foreach m, $(ALL_MODULES), \
) \
)
ifeq ($(ENABLE_FULL_DOCS), true)
ifneq ($(PANDOC), )
# For all markdown files in $module/share/specs directories, convert them to
# html.
# html, if we have pandoc (otherwise we'll just skip this).
GLOBAL_SPECS_DEFAULT_CSS_FILE := $(DOCS_OUTPUTDIR)/resources/jdk-default.css
@ -556,6 +541,15 @@ ifeq ($(ENABLE_FULL_DOCS), true)
# For all markdown files in $module/share/man directories, convert them to
# html.
# Create dynamic man pages from markdown using pandoc. We need
# 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
$(foreach m, $(ALL_MODULES), \
$(eval MAN_$m := $(call FindModuleManDirs, $m)) \
$(foreach d, $(MAN_$m), \
@ -565,8 +559,11 @@ ifeq ($(ENABLE_FULL_DOCS), true)
SRC := $d, \
FILES := $(filter %.md, $(call CacheFind, $d)), \
DEST := $(DOCS_OUTPUTDIR)/specs/man, \
FILTER := $(PANDOC_HTML_MANPAGE_FILTER), \
CSS := $(GLOBAL_SPECS_DEFAULT_CSS_FILE), \
REPLACEMENTS := @@VERSION_SHORT@@ => $(VERSION_SHORT), \
EXTRA_DEPS := $(PANDOC_HTML_MANPAGE_FILTER) \
$(PANDOC_HTML_MANPAGE_FILTER_JAVASCRIPT), \
)) \
$(eval JDK_SPECS_TARGETS += $($($m_$d_NAME))) \
) \

View File

@ -36,7 +36,7 @@ JRE_TARGETS :=
# Hook to include the corresponding custom file, if present.
$(eval $(call IncludeCustomExtension, Images-pre.gmk))
############################################################################
################################################################################
# All modules for the current target platform.
ALL_MODULES := $(call FindAllModules)
@ -57,7 +57,7 @@ BASE_RELEASE_FILE := $(JDK_OUTPUTDIR)/release
JMODS := $(wildcard $(IMAGES_OUTPUTDIR)/jmods/*.jmod)
# Use this file inside the image as target for make rule
JIMAGE_TARGET_FILE := bin/java$(EXE_SUFFIX)
JIMAGE_TARGET_FILE := release
JLINK_ORDER_RESOURCES := **module-info.class
JLINK_JLI_CLASSES :=

View File

@ -862,8 +862,6 @@ else
docs-jdk-specs: $(JVM_DOCS_TARGETS) jdk.jdi-gensrc \
docs-jdk-index
docs-jdk-index: exploded-image buildtools-modules
docs-zip: docs-jdk
# Tests

View File

@ -118,7 +118,8 @@ TOOL_PUBLICSUFFIXLIST = $(JAVA_SMALL) -cp $(BUILDTOOLS_OUTPUTDIR)/jdk_tools_clas
# Executable javascript filter for man page generation using pandoc.
PANDOC_FILTER := $(BUILDTOOLS_OUTPUTDIR)/manpages/pandoc-manpage-filter
PANDOC_TROFF_MANPAGE_FILTER := $(BUILDTOOLS_OUTPUTDIR)/manpages/pandoc-troff-manpage-filter
PANDOC_HTML_MANPAGE_FILTER := $(BUILDTOOLS_OUTPUTDIR)/manpages/pandoc-html-manpage-filter
##########################################################################################

View File

@ -80,7 +80,7 @@ define ProcessMarkdown
$$(call LogInfo, Converting $2 to $$($1_FORMAT))
$$(call MakeDir, $$(SUPPORT_OUTPUTDIR)/markdown $$(dir $$($1_$2_PANDOC_OUTPUT)))
$$(call ExecuteWithLog, $$(SUPPORT_OUTPUTDIR)/markdown/$$($1_$2_MARKER), \
$$(PANDOC) $$($1_OPTIONS) -f markdown -t $$($1_FORMAT) --standalone \
$$(PANDOC) $$($1_OPTIONS) -f markdown-smart -t $$($1_FORMAT) --standalone \
$$($1_$2_CSS_OPTION) $$($1_$2_OPTIONS) '$$($1_$2_PANDOC_INPUT)' \
-o '$$($1_$2_PANDOC_OUTPUT)')
ifneq ($$(findstring $$(LOG_LEVEL), debug trace),)

View File

@ -754,6 +754,21 @@ class CharacterData00 extends CharacterData {
return retval;
}
boolean isDigit(int ch) {
int props = getProperties(ch);
return (props & $$maskType) == Character.DECIMAL_DIGIT_NUMBER;
}
boolean isLowerCase(int ch) {
int props = getProperties(ch);
return (props & $$maskType) == Character.LOWERCASE_LETTER;
}
boolean isUpperCase(int ch) {
int props = getProperties(ch);
return (props & $$maskType) == Character.UPPERCASE_LETTER;
}
boolean isWhitespace(int ch) {
int props = getProperties(ch);
return ((props & $$maskIdentifierInfo) == $$valueJavaWhitespace);

View File

@ -460,6 +460,21 @@ class CharacterData01 extends CharacterData {
return retval;
}
boolean isDigit(int ch) {
int props = getProperties(ch);
return (props & $$maskType) == Character.DECIMAL_DIGIT_NUMBER;
}
boolean isLowerCase(int ch) {
int props = getProperties(ch);
return (props & $$maskType) == Character.LOWERCASE_LETTER;
}
boolean isUpperCase(int ch) {
int props = getProperties(ch);
return (props & $$maskType) == Character.UPPERCASE_LETTER;
}
boolean isWhitespace(int ch) {
int props = getProperties(ch);
return ((props & $$maskIdentifierInfo) == $$valueJavaWhitespace);

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2003, 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
@ -217,6 +217,21 @@ class CharacterData02 extends CharacterData {
return retval;
}
boolean isDigit(int ch) {
int props = getProperties(ch);
return (props & $$maskType) == Character.DECIMAL_DIGIT_NUMBER;
}
boolean isLowerCase(int ch) {
int props = getProperties(ch);
return (props & $$maskType) == Character.LOWERCASE_LETTER;
}
boolean isUpperCase(int ch) {
int props = getProperties(ch);
return (props & $$maskType) == Character.UPPERCASE_LETTER;
}
boolean isWhitespace(int ch) {
return (getProperties(ch) & $$maskIdentifierInfo) == $$valueJavaWhitespace;
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2003, 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
@ -217,6 +217,21 @@ class CharacterData0E extends CharacterData {
return retval;
}
boolean isDigit(int ch) {
int props = getProperties(ch);
return (props & $$maskType) == Character.DECIMAL_DIGIT_NUMBER;
}
boolean isLowerCase(int ch) {
int props = getProperties(ch);
return (props & $$maskType) == Character.LOWERCASE_LETTER;
}
boolean isUpperCase(int ch) {
int props = getProperties(ch);
return (props & $$maskType) == Character.UPPERCASE_LETTER;
}
boolean isWhitespace(int ch) {
int props = getProperties(ch);
return ((props & $$maskIdentifierInfo) == $$valueJavaWhitespace);

View File

@ -25,6 +25,8 @@
package java.lang;
import jdk.internal.HotSpotIntrinsicCandidate;
/** The CharacterData class encapsulates the large tables found in
Java.lang.Character. */
@ -78,6 +80,23 @@ class CharacterDataLatin1 extends CharacterData {
return props;
}
@HotSpotIntrinsicCandidate
boolean isDigit(int ch) {
return '0' <= ch && ch <= '9';
}
@HotSpotIntrinsicCandidate
boolean isLowerCase(int ch) {
int props = getProperties(ch);
return (props & $$maskType) == Character.LOWERCASE_LETTER;
}
@HotSpotIntrinsicCandidate
boolean isUpperCase(int ch) {
int props = getProperties(ch);
return (props & $$maskType) == Character.UPPERCASE_LETTER;
}
boolean isOtherLowercase(int ch) {
int props = getPropertiesEx(ch);
return (props & $$maskOtherLowercase) != 0;
@ -214,6 +233,7 @@ class CharacterDataLatin1 extends CharacterData {
return retval;
}
@HotSpotIntrinsicCandidate
boolean isWhitespace(int ch) {
int props = getProperties(ch);
return ((props & $$maskIdentifierInfo) == $$valueJavaWhitespace);

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2003, 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
@ -41,47 +41,59 @@ class CharacterDataPrivateUse extends CharacterData {
}
boolean isJavaIdentifierStart(int ch) {
return false;
return false;
}
boolean isJavaIdentifierPart(int ch) {
return false;
return false;
}
boolean isUnicodeIdentifierStart(int ch) {
return false;
return false;
}
boolean isUnicodeIdentifierPart(int ch) {
return false;
return false;
}
boolean isIdentifierIgnorable(int ch) {
return false;
return false;
}
int toLowerCase(int ch) {
return ch;
return ch;
}
int toUpperCase(int ch) {
return ch;
return ch;
}
int toTitleCase(int ch) {
return ch;
return ch;
}
int digit(int ch, int radix) {
return -1;
return -1;
}
int getNumericValue(int ch) {
return -1;
return -1;
}
boolean isDigit(int ch) {
return false;
}
boolean isLowerCase(int ch) {
return false;
}
boolean isUpperCase(int ch) {
return false;
}
boolean isWhitespace(int ch) {
return false;
return false;
}
byte getDirectionality(int ch) {
@ -91,7 +103,7 @@ class CharacterDataPrivateUse extends CharacterData {
}
boolean isMirrored(int ch) {
return false;
return false;
}
static final CharacterData instance = new CharacterDataPrivateUse();

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2003, 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
@ -35,59 +35,71 @@ class CharacterDataUndefined extends CharacterData {
}
int getType(int ch) {
return Character.UNASSIGNED;
return Character.UNASSIGNED;
}
boolean isJavaIdentifierStart(int ch) {
return false;
return false;
}
boolean isJavaIdentifierPart(int ch) {
return false;
return false;
}
boolean isUnicodeIdentifierStart(int ch) {
return false;
return false;
}
boolean isUnicodeIdentifierPart(int ch) {
return false;
return false;
}
boolean isIdentifierIgnorable(int ch) {
return false;
return false;
}
int toLowerCase(int ch) {
return ch;
return ch;
}
int toUpperCase(int ch) {
return ch;
return ch;
}
int toTitleCase(int ch) {
return ch;
return ch;
}
int digit(int ch, int radix) {
return -1;
return -1;
}
int getNumericValue(int ch) {
return -1;
return -1;
}
boolean isDigit(int ch) {
return false;
}
boolean isLowerCase(int ch) {
return false;
}
boolean isUpperCase(int ch) {
return false;
}
boolean isWhitespace(int ch) {
return false;
return false;
}
byte getDirectionality(int ch) {
return Character.DIRECTIONALITY_UNDEFINED;
return Character.DIRECTIONALITY_UNDEFINED;
}
boolean isMirrored(int ch) {
return false;
return false;
}
static final CharacterData instance = new CharacterDataUndefined();

View File

@ -1,5 +1,6 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN">
<!--
Copyright (c) 1998, Oracle and/or its affiliates. All rights reserved.
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
@ -22,34 +23,11 @@
or visit www.oracle.com if you need additional information or have any
questions.
-->
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
<html>
<body bgcolor="white">
Provides classes and interface for RMI distributed
garbage-collection (DGC). When the RMI server returns an object to
its client (caller of the remote method), it tracks the remote
object's usage in the client. When there are no more references to the
remote object on the client, or if the reference's ``lease'' expires and
not renewed, the server garbage-collects the remote object.
<!--
<h2>Package Specification</h2>
##### FILL IN ANY SPECS NEEDED BY JAVA COMPATIBILITY KIT #####
<ul>
<li><a href="">##### REFER TO ANY FRAMEMAKER SPECIFICATION HERE #####</a>
</ul>
<h2>Related Documentation</h2>
For overviews, tutorials, examples, guides, and tool documentation, please see:
<ul>
<li><a href="">##### REFER TO NON-SPEC DOCUMENTATION HERE #####</a>
</ul>
-->
@since 1.1
<html lang="en">
<head>
<meta http-equiv="refresh" content="0;url=api/index.html">
<title>Java API Documentation redirect</title>
</head>
<body>
</body>
</html>

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2014, 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
@ -36,11 +36,13 @@ import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Arrays;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.Date;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;
@ -552,6 +554,21 @@ public class ModuleSummary {
return sb.toString();
}
private String providesEntry(Provides p) {
StringBuilder sb = new StringBuilder();
sb.append(String.format("provides %s<br>\n", p.service()));
List<String> pvs = new ArrayList<>(p.providers());
pvs.sort(Comparator.naturalOrder());
for (int i = 0; i < pvs.size(); i++) { // My kingdom for Stream::zip ...
String fmt = ((i == 0)
? "&nbsp;&nbsp;&nbsp;&nbsp;with %s"
: ",<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; %s");
sb.append(String.format(fmt, pvs.get(i)));
}
sb.append("\n");
return sb.toString();
}
public String servicesColumn() {
StringBuilder sb = new StringBuilder();
sb.append(String.format(" <td class=\"%s\">", CODE));
@ -560,8 +577,7 @@ public class ModuleSummary {
.forEach(s -> sb.append("uses ").append(s).append("<br>").append("\n"));
ms.descriptor().provides().stream()
.sorted(Comparator.comparing(Provides::service))
.map(p -> String.format("provides %s<br>&nbsp;&nbsp;&nbsp;&nbsp;with %s",
p.service(), p.providers()))
.map(this::providesEntry)
.forEach(p -> sb.append(p).append("<br>").append("\n"));
sb.append("</td>");
return sb.toString();

View File

@ -207,11 +207,12 @@ ifeq ($(OPENJDK_TARGET_OS_TYPE), unix)
$(info Warning: pandoc not found. Not generating man pages)
else
# Create dynamic man pages from markdown using pandoc. We need
# PANDOC_FILTER, a wrapper around PANDOC_FILTER_JAVASCRIPT. This is
# created by buildtools-jdk.
# 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_FILTER_JAVASCRIPT := $(TOPDIR)/make/scripts/pandoc-manpage-filter.js
PANDOC_TROFF_MANPAGE_FILTER_JAVASCRIPT := \
$(TOPDIR)/make/scripts/pandoc-troff-manpage-filter.js
# The norm in man pages is to display code literals as bold, but pandoc
# "correctly" converts these constructs (encoded in markdown using `...`
@ -234,10 +235,11 @@ ifeq ($(OPENJDK_TARGET_OS_TYPE), unix)
DEST := $(SUPPORT_OUTPUTDIR)/modules_man/$(MODULE)/man1, \
FILES := $(MAN_FILES_MD), \
FORMAT := man, \
FILTER := $(PANDOC_FILTER), \
FILTER := $(PANDOC_TROFF_MANPAGE_FILTER), \
POST_PROCESS := $(MAN_POST_PROCESS), \
REPLACEMENTS := @@VERSION_SHORT@@ => $(VERSION_SHORT), \
EXTRA_DEPS := $(PANDOC_FILTER) $(PANDOC_FILTER_JAVASCRIPT), \
EXTRA_DEPS := $(PANDOC_TROFF_MANPAGE_FILTER) \
$(PANDOC_TROFF_MANPAGE_FILTER_JAVASCRIPT), \
))
TARGETS += $(BUILD_MAN_PAGES)

View File

@ -0,0 +1,125 @@
//
// 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-Z]+)\([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();

View File

@ -25,4 +25,4 @@
# Simple wrapper script to call Nashorn with the javascript pandoc filter
@@BOOT_JDK@@/bin/jjs @@JJS_FLAGS@@ -scripting \
"@@TOPDIR@@/make/scripts/pandoc-manpage-filter.js" 2> /dev/null
"@@TOPDIR@@/make/scripts/pandoc-html-manpage-filter.js" 2> /dev/null

View File

@ -0,0 +1,28 @@
#!/bin/bash
#
# 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.
#
# Simple wrapper script to call Nashorn with the javascript pandoc filter
@@BOOT_JDK@@/bin/jjs @@JJS_FLAGS@@ -scripting \
"@@TOPDIR@@/make/scripts/pandoc-troff-manpage-filter.js" 2> /dev/null

View File

@ -725,8 +725,11 @@ class StubGenerator: public StubCodeGenerator {
stub_name = "forward_copy_longs";
else
stub_name = "backward_copy_longs";
StubCodeMark mark(this, "StubRoutines", stub_name);
__ align(CodeEntryAlignment);
StubCodeMark mark(this, "StubRoutines", stub_name);
__ bind(start);
Label unaligned_copy_long;
@ -1976,9 +1979,10 @@ class StubGenerator: public StubCodeGenerator {
const Register dst_pos = c_rarg3; // destination position
const Register length = c_rarg4;
__ align(CodeEntryAlignment);
StubCodeMark mark(this, "StubRoutines", name);
__ align(CodeEntryAlignment);
address start = __ pc();
__ enter(); // required for proper stackwalking of RuntimeStub frame
@ -3653,7 +3657,6 @@ class StubGenerator: public StubCodeGenerator {
}
address generate_has_negatives(address &has_negatives_long) {
StubCodeMark mark(this, "StubRoutines", "has_negatives");
const u1 large_loop_size = 64;
const uint64_t UPPER_BIT_MASK=0x8080808080808080;
int dcache_line = VM_Version::dcache_line_size();
@ -3661,6 +3664,9 @@ class StubGenerator: public StubCodeGenerator {
Register ary1 = r1, len = r2, result = r0;
__ align(CodeEntryAlignment);
StubCodeMark mark(this, "StubRoutines", "has_negatives");
address entry = __ pc();
__ enter();
@ -3900,7 +3906,6 @@ class StubGenerator: public StubCodeGenerator {
// cnt1 = r10 - amount of elements left to check, reduced by wordSize
// r3-r5 are reserved temporary registers
address generate_large_array_equals() {
StubCodeMark mark(this, "StubRoutines", "large_array_equals");
Register a1 = r1, a2 = r2, result = r0, cnt1 = r10, tmp1 = rscratch1,
tmp2 = rscratch2, tmp3 = r3, tmp4 = r4, tmp5 = r5, tmp6 = r11,
tmp7 = r12, tmp8 = r13;
@ -3915,6 +3920,9 @@ class StubGenerator: public StubCodeGenerator {
tmp5, tmp6, tmp7, tmp8);
__ align(CodeEntryAlignment);
StubCodeMark mark(this, "StubRoutines", "large_array_equals");
address entry = __ pc();
__ enter();
__ sub(cnt1, cnt1, wordSize); // first 8 bytes were loaded outside of stub

View File

@ -1,6 +1,6 @@
/*
* Copyright (c) 2002, 2018, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2012, 2017 SAP SE. All rights reserved.
* Copyright (c) 2012, 2018 SAP SE. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -299,6 +299,8 @@ class Assembler : public AbstractAssembler {
CMPI_OPCODE = (11u << OPCODE_SHIFT),
CMPL_OPCODE = (31u << OPCODE_SHIFT | 32u << 1),
CMPLI_OPCODE = (10u << OPCODE_SHIFT),
CMPRB_OPCODE = (31u << OPCODE_SHIFT | 192u << 1),
CMPEQB_OPCODE = (31u << OPCODE_SHIFT | 224u << 1),
ISEL_OPCODE = (31u << OPCODE_SHIFT | 15u << 1),
@ -336,6 +338,7 @@ class Assembler : public AbstractAssembler {
MTCRF_OPCODE = (31u << OPCODE_SHIFT | 144u << 1),
MFCR_OPCODE = (31u << OPCODE_SHIFT | 19u << 1),
MCRF_OPCODE = (19u << OPCODE_SHIFT | 0u << 1),
SETB_OPCODE = (31u << OPCODE_SHIFT | 128u << 1),
// condition register logic instructions
CRAND_OPCODE = (19u << OPCODE_SHIFT | 257u << 1),
@ -1076,7 +1079,7 @@ class Assembler : public AbstractAssembler {
static int frs( int x) { return opp_u_field(x, 10, 6); }
static int frt( int x) { return opp_u_field(x, 10, 6); }
static int fxm( int x) { return opp_u_field(x, 19, 12); }
static int l10( int x) { return opp_u_field(x, 10, 10); }
static int l10( int x) { assert(x == 0 || x == 1, "must be 0 or 1"); return opp_u_field(x, 10, 10); }
static int l14( int x) { return opp_u_field(x, 15, 14); }
static int l15( int x) { return opp_u_field(x, 15, 15); }
static int l910( int x) { return opp_u_field(x, 10, 9); }
@ -1443,6 +1446,10 @@ class Assembler : public AbstractAssembler {
inline void cmplw( ConditionRegister crx, Register a, Register b);
inline void cmpld( ConditionRegister crx, Register a, Register b);
// >= Power9
inline void cmprb( ConditionRegister bf, int l, Register a, Register b);
inline void cmpeqb(ConditionRegister bf, Register a, Register b);
inline void isel( Register d, Register a, Register b, int bc);
// Convenient version which takes: Condition register, Condition code and invert flag. Omit b to keep old value.
inline void isel( Register d, ConditionRegister cr, Condition cc, bool inv, Register a, Register b = noreg);
@ -1642,6 +1649,8 @@ class Assembler : public AbstractAssembler {
inline void mfcr( Register d);
inline void mcrf( ConditionRegister crd, ConditionRegister cra);
inline void mtcr( Register s);
// >= Power9
inline void setb( Register d, ConditionRegister cra);
// Special purpose registers
// Exception Register

View File

@ -171,6 +171,8 @@ inline void Assembler::cmpi( ConditionRegister f, int l, Register a, int si16)
inline void Assembler::cmp( ConditionRegister f, int l, Register a, Register b) { emit_int32( CMP_OPCODE | bf(f) | l10(l) | ra(a) | rb(b)); }
inline void Assembler::cmpli( ConditionRegister f, int l, Register a, int ui16) { emit_int32( CMPLI_OPCODE | bf(f) | l10(l) | ra(a) | uimm(ui16,16)); }
inline void Assembler::cmpl( ConditionRegister f, int l, Register a, Register b) { emit_int32( CMPL_OPCODE | bf(f) | l10(l) | ra(a) | rb(b)); }
inline void Assembler::cmprb( ConditionRegister f, int l, Register a, Register b) { emit_int32( CMPRB_OPCODE | bf(f) | l10(l) | ra(a) | rb(b)); }
inline void Assembler::cmpeqb(ConditionRegister f, Register a, Register b) { emit_int32( CMPEQB_OPCODE| bf(f) | ra(a) | rb(b)); }
// extended mnemonics of Compare Instructions
inline void Assembler::cmpwi( ConditionRegister crx, Register a, int si16) { Assembler::cmpi( crx, 0, a, si16); }
@ -371,6 +373,8 @@ inline void Assembler::mfcr( Register d ) { emit_int32(MFCR_OPCODE | rt
inline void Assembler::mcrf( ConditionRegister crd, ConditionRegister cra)
{ emit_int32(MCRF_OPCODE | bf(crd) | bfa(cra)); }
inline void Assembler::mtcr( Register s) { Assembler::mtcrf(0xff, s); }
inline void Assembler::setb(Register d, ConditionRegister cra)
{ emit_int32(SETB_OPCODE | rt(d) | bfa(cra)); }
// Special purpose registers
// Exception Register

View File

@ -2273,7 +2273,7 @@ void MacroAssembler::tlab_allocate(
) {
// make sure arguments make sense
assert_different_registers(obj, var_size_in_bytes, t1);
assert(0 <= con_size_in_bytes && is_simm13(con_size_in_bytes), "illegal object size");
assert(0 <= con_size_in_bytes && is_simm16(con_size_in_bytes), "illegal object size");
assert((con_size_in_bytes & MinObjAlignmentInBytesMask) == 0, "object size is not multiple of alignment");
const Register new_top = t1;

View File

@ -2257,6 +2257,11 @@ const bool Matcher::match_rule_supported(int opcode) {
return SuperwordUseVSX;
case Op_PopCountVI:
return (SuperwordUseVSX && UsePopCountInstruction);
case Op_Digit:
case Op_LowerCase:
case Op_UpperCase:
case Op_Whitespace:
return UseCharacterCompareIntrinsics;
}
return true; // Per default match rules are supported.
@ -12400,6 +12405,132 @@ instruct cmpD3_reg_reg_ExEx(iRegIdst dst, regD src1, regD src2) %{
%}
%}
// Compare char
instruct cmprb_Digit_reg_reg(iRegIdst dst, iRegIsrc src1, iRegIsrc src2, flagsReg crx) %{
match(Set dst (Digit src1));
effect(TEMP src2, TEMP crx);
ins_cost(3 * DEFAULT_COST);
format %{ "LI $src2, 0x3930\n\t"
"CMPRB $crx, 0, $src1, $src2\n\t"
"SETB $dst, $crx" %}
size(12);
ins_encode %{
// 0x30: 0, 0x39: 9
__ li($src2$$Register, 0x3930);
// compare src1 with ranges 0x30 to 0x39
__ cmprb($crx$$CondRegister, 0, $src1$$Register, $src2$$Register);
__ setb($dst$$Register, $crx$$CondRegister);
%}
ins_pipe(pipe_class_default);
%}
instruct cmprb_LowerCase_reg_reg(iRegIdst dst, iRegIsrc src1, iRegIsrc src2, flagsReg crx) %{
match(Set dst (LowerCase src1));
effect(TEMP src2, TEMP crx);
ins_cost(12 * DEFAULT_COST);
format %{ "LI $src2, 0x7A61\n\t"
"CMPRB $crx, 0, $src1, $src2\n\t"
"BGT $crx, done\n\t"
"LIS $src2, (signed short)0xF6DF\n\t"
"ORI $src2, $src2, 0xFFF8\n\t"
"CMPRB $crx, 1, $src1, $src2\n\t"
"BGT $crx, done\n\t"
"LIS $src2, (signed short)0xAAB5\n\t"
"ORI $src2, $src2, 0xBABA\n\t"
"INSRDI $src2, $src2, 32, 0\n\t"
"CMPEQB $crx, 1, $src1, $src2\n"
"done:\n\t"
"SETB $dst, $crx" %}
size(48);
ins_encode %{
Label done;
// 0x61: a, 0x7A: z
__ li($src2$$Register, 0x7A61);
// compare src1 with ranges 0x61 to 0x7A
__ cmprb($crx$$CondRegister, 0, $src1$$Register, $src2$$Register);
__ bgt($crx$$CondRegister, done);
// 0xDF: sharp s, 0xFF: y with diaeresis, 0xF7 is not the lower case
__ lis($src2$$Register, (signed short)0xF6DF);
__ ori($src2$$Register, $src2$$Register, 0xFFF8);
// compare src1 with ranges 0xDF to 0xF6 and 0xF8 to 0xFF
__ cmprb($crx$$CondRegister, 1, $src1$$Register, $src2$$Register);
__ bgt($crx$$CondRegister, done);
// 0xAA: feminine ordinal indicator
// 0xB5: micro sign
// 0xBA: masculine ordinal indicator
__ lis($src2$$Register, (signed short)0xAAB5);
__ ori($src2$$Register, $src2$$Register, 0xBABA);
__ insrdi($src2$$Register, $src2$$Register, 32, 0);
// compare src1 with 0xAA, 0xB5, and 0xBA
__ cmpeqb($crx$$CondRegister, $src1$$Register, $src2$$Register);
__ bind(done);
__ setb($dst$$Register, $crx$$CondRegister);
%}
ins_pipe(pipe_class_default);
%}
instruct cmprb_UpperCase_reg_reg(iRegIdst dst, iRegIsrc src1, iRegIsrc src2, flagsReg crx) %{
match(Set dst (UpperCase src1));
effect(TEMP src2, TEMP crx);
ins_cost(7 * DEFAULT_COST);
format %{ "LI $src2, 0x5A41\n\t"
"CMPRB $crx, 0, $src1, $src2\n\t"
"BGT $crx, done\n\t"
"LIS $src2, (signed short)0xD6C0\n\t"
"ORI $src2, $src2, 0xDED8\n\t"
"CMPRB $crx, 1, $src1, $src2\n"
"done:\n\t"
"SETB $dst, $crx" %}
size(28);
ins_encode %{
Label done;
// 0x41: A, 0x5A: Z
__ li($src2$$Register, 0x5A41);
// compare src1 with a range 0x41 to 0x5A
__ cmprb($crx$$CondRegister, 0, $src1$$Register, $src2$$Register);
__ bgt($crx$$CondRegister, done);
// 0xC0: a with grave, 0xDE: thorn, 0xD7 is not the upper case
__ lis($src2$$Register, (signed short)0xD6C0);
__ ori($src2$$Register, $src2$$Register, 0xDED8);
// compare src1 with ranges 0xC0 to 0xD6 and 0xD8 to 0xDE
__ cmprb($crx$$CondRegister, 1, $src1$$Register, $src2$$Register);
__ bind(done);
__ setb($dst$$Register, $crx$$CondRegister);
%}
ins_pipe(pipe_class_default);
%}
instruct cmprb_Whitespace_reg_reg(iRegIdst dst, iRegIsrc src1, iRegIsrc src2, flagsReg crx) %{
match(Set dst (Whitespace src1));
effect(TEMP src2, TEMP crx);
ins_cost(4 * DEFAULT_COST);
format %{ "LI $src2, 0x0D09\n\t"
"ADDIS $src2, 0x201C\n\t"
"CMPRB $crx, 1, $src1, $src2\n\t"
"SETB $dst, $crx" %}
size(16);
ins_encode %{
// 0x09 to 0x0D, 0x1C to 0x20
__ li($src2$$Register, 0x0D09);
__ addis($src2$$Register, $src2$$Register, 0x0201C);
// compare src with ranges 0x09 to 0x0D and 0x1C to 0x20
__ cmprb($crx$$CondRegister, 1, $src1$$Register, $src2$$Register);
__ setb($dst$$Register, $crx$$CondRegister);
%}
ins_pipe(pipe_class_default);
%}
//----------Branches---------------------------------------------------------
// Jump

View File

@ -134,11 +134,18 @@ void VM_Version::initialize() {
if (FLAG_IS_DEFAULT(UseCountTrailingZerosInstructionsPPC64)) {
FLAG_SET_ERGO(bool, UseCountTrailingZerosInstructionsPPC64, true);
}
if (FLAG_IS_DEFAULT(UseCharacterCompareIntrinsics)) {
FLAG_SET_ERGO(bool, UseCharacterCompareIntrinsics, true);
}
} else {
if (UseCountTrailingZerosInstructionsPPC64) {
warning("UseCountTrailingZerosInstructionsPPC64 specified, but needs at least Power9.");
FLAG_SET_DEFAULT(UseCountTrailingZerosInstructionsPPC64, false);
}
if (UseCharacterCompareIntrinsics) {
warning("UseCharacterCompareIntrinsics specified, but needs at least Power9.");
FLAG_SET_DEFAULT(UseCharacterCompareIntrinsics, false);
}
}
#endif

View File

@ -3966,6 +3966,34 @@ void Assembler::vpmovzxwd(XMMRegister dst, XMMRegister src, int vector_len) {
emit_int8((unsigned char)(0xC0 | encode));
}
void Assembler::pmaddwd(XMMRegister dst, XMMRegister src) {
NOT_LP64(assert(VM_Version::supports_sse2(), ""));
InstructionAttr attributes(AVX_128bit, /* rex_w */ false, /* legacy_mode */ _legacy_mode_bw, /* no_mask_reg */ true, /* uses_vl */ true);
int encode = simd_prefix_and_encode(dst, dst, src, VEX_SIMD_66, VEX_OPCODE_0F, &attributes);
emit_int8((unsigned char)0xF5);
emit_int8((unsigned char)(0xC0 | encode));
}
void Assembler::vpmaddwd(XMMRegister dst, XMMRegister nds, XMMRegister src, int vector_len) {
assert(vector_len == AVX_128bit ? VM_Version::supports_avx() :
(vector_len == AVX_256bit ? VM_Version::supports_avx2() :
(vector_len == AVX_512bit ? VM_Version::supports_evex() : 0)), "");
InstructionAttr attributes(vector_len, /* rex_w */ false, /* legacy_mode */ _legacy_mode_bw, /* no_mask_reg */ true, /* uses_vl */ true);
int encode = simd_prefix_and_encode(dst, nds, src, VEX_SIMD_66, VEX_OPCODE_0F, &attributes);
emit_int8((unsigned char)0xF5);
emit_int8((unsigned char)(0xC0 | encode));
}
void Assembler::evpdpwssd(XMMRegister dst, XMMRegister nds, XMMRegister src, int vector_len) {
assert(VM_Version::supports_evex(), "");
assert(VM_Version::supports_vnni(), "must support vnni");
InstructionAttr attributes(vector_len, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ true);
attributes.set_is_evex_instruction();
int encode = vex_prefix_and_encode(dst->encoding(), nds->encoding(), src->encoding(), VEX_SIMD_66, VEX_OPCODE_0F_38, &attributes);
emit_int8(0x52);
emit_int8((unsigned char)(0xC0 | encode));
}
// generic
void Assembler::pop(Register dst) {
int encode = prefix_and_encode(dst->encoding());
@ -4178,6 +4206,17 @@ void Assembler::psrldq(XMMRegister dst, int shift) {
emit_int8(shift);
}
void Assembler::vpsrldq(XMMRegister dst, XMMRegister src, int shift, int vector_len) {
assert(vector_len == AVX_128bit ? VM_Version::supports_avx() :
vector_len == AVX_256bit ? VM_Version::supports_avx2() :
vector_len == AVX_512bit ? VM_Version::supports_avx512bw() : 0, "");
InstructionAttr attributes(vector_len, /*vex_w */ false, /* legacy_mode */ _legacy_mode_bw, /* no_mask_reg */ true, /* uses_vl */ true);
int encode = vex_prefix_and_encode(xmm3->encoding(), dst->encoding(), src->encoding(), VEX_SIMD_66, VEX_OPCODE_0F, &attributes);
emit_int8(0x73);
emit_int8((unsigned char)(0xC0 | encode));
emit_int8(shift & 0xFF);
}
void Assembler::pslldq(XMMRegister dst, int shift) {
// Shift left 128 bit value in dst XMMRegister by shift number of bytes.
NOT_LP64(assert(VM_Version::supports_sse2(), ""));
@ -4189,6 +4228,17 @@ void Assembler::pslldq(XMMRegister dst, int shift) {
emit_int8(shift);
}
void Assembler::vpslldq(XMMRegister dst, XMMRegister src, int shift, int vector_len) {
assert(vector_len == AVX_128bit ? VM_Version::supports_avx() :
vector_len == AVX_256bit ? VM_Version::supports_avx2() :
vector_len == AVX_512bit ? VM_Version::supports_avx512bw() : 0, "");
InstructionAttr attributes(vector_len, /*vex_w */ false, /* legacy_mode */ _legacy_mode_bw, /* no_mask_reg */ true, /* uses_vl */ true);
int encode = vex_prefix_and_encode(xmm7->encoding(), dst->encoding(), src->encoding(), VEX_SIMD_66, VEX_OPCODE_0F, &attributes);
emit_int8(0x73);
emit_int8((unsigned char)(0xC0 | encode));
emit_int8(shift & 0xFF);
}
void Assembler::ptest(XMMRegister dst, Address src) {
assert(VM_Version::supports_sse4_1(), "");
assert((UseAVX > 0), "SSE mode requires address alignment 16 bytes");
@ -4200,7 +4250,7 @@ void Assembler::ptest(XMMRegister dst, Address src) {
}
void Assembler::ptest(XMMRegister dst, XMMRegister src) {
assert(VM_Version::supports_sse4_1(), "");
assert(VM_Version::supports_sse4_1() || VM_Version::supports_avx(), "");
InstructionAttr attributes(AVX_128bit, /* rex_w */ false, /* legacy_mode */ true, /* no_mask_reg */ true, /* uses_vl */ false);
int encode = simd_prefix_and_encode(dst, xnoreg, src, VEX_SIMD_66, VEX_OPCODE_0F_38, &attributes);
emit_int8(0x17);

View File

@ -1668,6 +1668,12 @@ private:
void evpmovdb(Address dst, XMMRegister src, int vector_len);
// Multiply add
void pmaddwd(XMMRegister dst, XMMRegister src);
void vpmaddwd(XMMRegister dst, XMMRegister nds, XMMRegister src, int vector_len);
// Multiply add accumulate
void evpdpwssd(XMMRegister dst, XMMRegister nds, XMMRegister src, int vector_len);
#ifndef _LP64 // no 32bit push/pop on amd64
void popl(Address dst);
#endif
@ -2055,6 +2061,7 @@ private:
void vpsllw(XMMRegister dst, XMMRegister src, XMMRegister shift, int vector_len);
void vpslld(XMMRegister dst, XMMRegister src, XMMRegister shift, int vector_len);
void vpsllq(XMMRegister dst, XMMRegister src, XMMRegister shift, int vector_len);
void vpslldq(XMMRegister dst, XMMRegister src, int shift, int vector_len);
// Logical shift right packed integers
void psrlw(XMMRegister dst, int shift);
@ -2069,6 +2076,7 @@ private:
void vpsrlw(XMMRegister dst, XMMRegister src, XMMRegister shift, int vector_len);
void vpsrld(XMMRegister dst, XMMRegister src, XMMRegister shift, int vector_len);
void vpsrlq(XMMRegister dst, XMMRegister src, XMMRegister shift, int vector_len);
void vpsrldq(XMMRegister dst, XMMRegister src, int shift, int vector_len);
void evpsrlvw(XMMRegister dst, XMMRegister nds, XMMRegister src, int vector_len);
void evpsllvw(XMMRegister dst, XMMRegister nds, XMMRegister src, int vector_len);

View File

@ -943,12 +943,17 @@ class MacroAssembler: public Assembler {
int iter);
void addm(int disp, Register r1, Register r2);
void gfmul(XMMRegister tmp0, XMMRegister t);
void schoolbookAAD(int i, Register subkeyH, XMMRegister data, XMMRegister tmp0,
XMMRegister tmp1, XMMRegister tmp2, XMMRegister tmp3);
void generateHtbl_one_block(Register htbl);
void generateHtbl_eight_blocks(Register htbl);
public:
void sha256_AVX2(XMMRegister msg, XMMRegister state0, XMMRegister state1, XMMRegister msgtmp0,
XMMRegister msgtmp1, XMMRegister msgtmp2, XMMRegister msgtmp3, XMMRegister msgtmp4,
Register buf, Register state, Register ofs, Register limit, Register rsp,
bool multi_block, XMMRegister shuf_mask);
void avx_ghash(Register state, Register htbl, Register data, Register blocks);
#endif
#ifdef _LP64
@ -1498,6 +1503,15 @@ public:
// 0x11 - multiply upper 64 bits [64:127]
Assembler::vpclmulqdq(dst, nds, src, 0x11);
}
void vpclmullqhqdq(XMMRegister dst, XMMRegister nds, XMMRegister src) {
// 0x10 - multiply nds[0:63] and src[64:127]
Assembler::vpclmulqdq(dst, nds, src, 0x10);
}
void vpclmulhqlqdq(XMMRegister dst, XMMRegister nds, XMMRegister src) {
//0x01 - multiply nds[64:127] and src[0:63]
Assembler::vpclmulqdq(dst, nds, src, 0x01);
}
void evpclmulldq(XMMRegister dst, XMMRegister nds, XMMRegister src, int vector_len) {
// 0x00 - multiply lower 64 bits [0:63]
Assembler::evpclmulqdq(dst, nds, src, 0x00, vector_len);

View File

@ -0,0 +1,322 @@
/*
* Copyright (c) 2018, Intel Corporation.
*
* 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 "asm/assembler.hpp"
#include "asm/assembler.inline.hpp"
#include "runtime/stubRoutines.hpp"
#include "macroAssembler_x86.hpp"
// Multiply 128 x 128 bits, using 4 pclmulqdq operations
void MacroAssembler::schoolbookAAD(int i, Register htbl, XMMRegister data,
XMMRegister tmp0, XMMRegister tmp1, XMMRegister tmp2, XMMRegister tmp3) {
movdqu(xmm15, Address(htbl, i * 16));
vpclmulhqlqdq(tmp3, data, xmm15); // 0x01
vpxor(tmp2, tmp2, tmp3, Assembler::AVX_128bit);
vpclmulldq(tmp3, data, xmm15); // 0x00
vpxor(tmp0, tmp0, tmp3, Assembler::AVX_128bit);
vpclmulhdq(tmp3, data, xmm15); // 0x11
vpxor(tmp1, tmp1, tmp3, Assembler::AVX_128bit);
vpclmullqhqdq(tmp3, data, xmm15); // 0x10
vpxor(tmp2, tmp2, tmp3, Assembler::AVX_128bit);
}
// Multiply two 128 bit numbers resulting in a 256 bit value
// Result of the multiplication followed by reduction stored in state
void MacroAssembler::gfmul(XMMRegister tmp0, XMMRegister state) {
const XMMRegister tmp1 = xmm4;
const XMMRegister tmp2 = xmm5;
const XMMRegister tmp3 = xmm6;
const XMMRegister tmp4 = xmm7;
vpclmulldq(tmp1, state, tmp0); //0x00 (a0 * b0)
vpclmulhdq(tmp4, state, tmp0);//0x11 (a1 * b1)
vpclmullqhqdq(tmp2, state, tmp0);//0x10 (a1 * b0)
vpclmulhqlqdq(tmp3, state, tmp0); //0x01 (a0 * b1)
vpxor(tmp2, tmp2, tmp3, Assembler::AVX_128bit); // (a0 * b1) + (a1 * b0)
vpslldq(tmp3, tmp2, 8, Assembler::AVX_128bit);
vpsrldq(tmp2, tmp2, 8, Assembler::AVX_128bit);
vpxor(tmp1, tmp1, tmp3, Assembler::AVX_128bit); // tmp1 and tmp4 hold the result
vpxor(tmp4, tmp4, tmp2, Assembler::AVX_128bit); // of carryless multiplication
// Follows the reduction technique mentioned in
// Shift-XOR reduction described in Gueron-Kounavis May 2010
// First phase of reduction
//
vpslld(xmm8, tmp1, 31, Assembler::AVX_128bit); // packed right shift shifting << 31
vpslld(xmm9, tmp1, 30, Assembler::AVX_128bit); // packed right shift shifting << 30
vpslld(xmm10, tmp1, 25, Assembler::AVX_128bit);// packed right shift shifting << 25
// xor the shifted versions
vpxor(xmm8, xmm8, xmm9, Assembler::AVX_128bit);
vpxor(xmm8, xmm8, xmm10, Assembler::AVX_128bit);
vpslldq(xmm9, xmm8, 12, Assembler::AVX_128bit);
vpsrldq(xmm8, xmm8, 4, Assembler::AVX_128bit);
vpxor(tmp1, tmp1, xmm9, Assembler::AVX_128bit);// first phase of the reduction complete
//
// Second phase of the reduction
//
vpsrld(xmm9, tmp1, 1, Assembler::AVX_128bit);// packed left shifting >> 1
vpsrld(xmm10, tmp1, 2, Assembler::AVX_128bit);// packed left shifting >> 2
vpsrld(xmm11, tmp1, 7, Assembler::AVX_128bit);// packed left shifting >> 7
vpxor(xmm9, xmm9, xmm10, Assembler::AVX_128bit);// xor the shifted versions
vpxor(xmm9, xmm9, xmm11, Assembler::AVX_128bit);
vpxor(xmm9, xmm9, xmm8, Assembler::AVX_128bit);
vpxor(tmp1, tmp1, xmm9, Assembler::AVX_128bit);
vpxor(state, tmp4, tmp1, Assembler::AVX_128bit);// the result is in state
ret(0);
}
// This method takes the subkey after expansion as input and generates 1 * 16 power of subkey H.
// The power of H is used in reduction process for one block ghash
void MacroAssembler::generateHtbl_one_block(Register htbl) {
const XMMRegister t = xmm13;
// load the original subkey hash
movdqu(t, Address(htbl, 0));
// shuffle using long swap mask
movdqu(xmm10, ExternalAddress(StubRoutines::x86::ghash_long_swap_mask_addr()));
vpshufb(t, t, xmm10, Assembler::AVX_128bit);
// Compute H' = GFMUL(H, 2)
vpsrld(xmm3, t, 7, Assembler::AVX_128bit);
movdqu(xmm4, ExternalAddress(StubRoutines::x86::ghash_shufflemask_addr()));
vpshufb(xmm3, xmm3, xmm4, Assembler::AVX_128bit);
movl(rax, 0xff00);
movdl(xmm4, rax);
vpshufb(xmm4, xmm4, xmm3, Assembler::AVX_128bit);
movdqu(xmm5, ExternalAddress(StubRoutines::x86::ghash_polynomial_addr()));
vpand(xmm5, xmm5, xmm4, Assembler::AVX_128bit);
vpsrld(xmm3, t, 31, Assembler::AVX_128bit);
vpslld(xmm4, t, 1, Assembler::AVX_128bit);
vpslldq(xmm3, xmm3, 4, Assembler::AVX_128bit);
vpxor(t, xmm4, xmm3, Assembler::AVX_128bit);// t holds p(x) <<1 or H * 2
//Adding p(x)<<1 to xmm5 which holds the reduction polynomial
vpxor(t, t, xmm5, Assembler::AVX_128bit);
movdqu(Address(htbl, 1 * 16), t); // H * 2
ret(0);
}
// This method takes the subkey after expansion as input and generates the remaining powers of subkey H.
// The power of H is used in reduction process for eight block ghash
void MacroAssembler::generateHtbl_eight_blocks(Register htbl) {
const XMMRegister t = xmm13;
const XMMRegister tmp0 = xmm1;
Label GFMUL;
movdqu(t, Address(htbl, 1 * 16));
movdqu(tmp0, t);
// tmp0 and t hold H. Now we compute powers of H by using GFMUL(H, H)
call(GFMUL, relocInfo::none);
movdqu(Address(htbl, 2 * 16), t); //H ^ 2 * 2
call(GFMUL, relocInfo::none);
movdqu(Address(htbl, 3 * 16), t); //H ^ 3 * 2
call(GFMUL, relocInfo::none);
movdqu(Address(htbl, 4 * 16), t); //H ^ 4 * 2
call(GFMUL, relocInfo::none);
movdqu(Address(htbl, 5 * 16), t); //H ^ 5 * 2
call(GFMUL, relocInfo::none);
movdqu(Address(htbl, 6 * 16), t); //H ^ 6 * 2
call(GFMUL, relocInfo::none);
movdqu(Address(htbl, 7 * 16), t); //H ^ 7 * 2
call(GFMUL, relocInfo::none);
movdqu(Address(htbl, 8 * 16), t); //H ^ 8 * 2
ret(0);
bind(GFMUL);
gfmul(tmp0, t);
}
// Multiblock and single block GHASH computation using Shift XOR reduction technique
void MacroAssembler::avx_ghash(Register input_state, Register htbl,
Register input_data, Register blocks) {
// temporary variables to hold input data and input state
const XMMRegister data = xmm1;
const XMMRegister state = xmm0;
// temporary variables to hold intermediate results
const XMMRegister tmp0 = xmm3;
const XMMRegister tmp1 = xmm4;
const XMMRegister tmp2 = xmm5;
const XMMRegister tmp3 = xmm6;
// temporary variables to hold byte and long swap masks
const XMMRegister bswap_mask = xmm2;
const XMMRegister lswap_mask = xmm14;
Label GENERATE_HTBL_1_BLK, GENERATE_HTBL_8_BLKS, BEGIN_PROCESS, GFMUL, BLOCK8_REDUCTION,
ONE_BLK_INIT, PROCESS_1_BLOCK, PROCESS_8_BLOCKS, SAVE_STATE, EXIT_GHASH;
testptr(blocks, blocks);
jcc(Assembler::zero, EXIT_GHASH);
// Check if Hashtable (1*16) has been already generated
// For anything less than 8 blocks, we generate only the first power of H.
movdqu(tmp2, Address(htbl, 1 * 16));
ptest(tmp2, tmp2);
jcc(Assembler::notZero, BEGIN_PROCESS);
call(GENERATE_HTBL_1_BLK, relocInfo::none);
// Shuffle the input state
bind(BEGIN_PROCESS);
movdqu(lswap_mask, ExternalAddress(StubRoutines::x86::ghash_long_swap_mask_addr()));
movdqu(state, Address(input_state, 0));
vpshufb(state, state, lswap_mask, Assembler::AVX_128bit);
cmpl(blocks, 8);
jcc(Assembler::below, ONE_BLK_INIT);
// If we have 8 blocks or more data, then generate remaining powers of H
movdqu(tmp2, Address(htbl, 8 * 16));
ptest(tmp2, tmp2);
jcc(Assembler::notZero, PROCESS_8_BLOCKS);
call(GENERATE_HTBL_8_BLKS, relocInfo::none);
//Do 8 multiplies followed by a reduction processing 8 blocks of data at a time
//Each block = 16 bytes.
bind(PROCESS_8_BLOCKS);
subl(blocks, 8);
movdqu(bswap_mask, ExternalAddress(StubRoutines::x86::ghash_byte_swap_mask_addr()));
movdqu(data, Address(input_data, 16 * 7));
vpshufb(data, data, bswap_mask, Assembler::AVX_128bit);
//Loading 1*16 as calculated powers of H required starts at that location.
movdqu(xmm15, Address(htbl, 1 * 16));
//Perform carryless multiplication of (H*2, data block #7)
vpclmulhqlqdq(tmp2, data, xmm15);//a0 * b1
vpclmulldq(tmp0, data, xmm15);//a0 * b0
vpclmulhdq(tmp1, data, xmm15);//a1 * b1
vpclmullqhqdq(tmp3, data, xmm15);//a1* b0
vpxor(tmp2, tmp2, tmp3, Assembler::AVX_128bit);// (a0 * b1) + (a1 * b0)
movdqu(data, Address(input_data, 16 * 6));
vpshufb(data, data, bswap_mask, Assembler::AVX_128bit);
// Perform carryless multiplication of (H^2 * 2, data block #6)
schoolbookAAD(2, htbl, data, tmp0, tmp1, tmp2, tmp3);
movdqu(data, Address(input_data, 16 * 5));
vpshufb(data, data, bswap_mask, Assembler::AVX_128bit);
// Perform carryless multiplication of (H^3 * 2, data block #5)
schoolbookAAD(3, htbl, data, tmp0, tmp1, tmp2, tmp3);
movdqu(data, Address(input_data, 16 * 4));
vpshufb(data, data, bswap_mask, Assembler::AVX_128bit);
// Perform carryless multiplication of (H^4 * 2, data block #4)
schoolbookAAD(4, htbl, data, tmp0, tmp1, tmp2, tmp3);
movdqu(data, Address(input_data, 16 * 3));
vpshufb(data, data, bswap_mask, Assembler::AVX_128bit);
// Perform carryless multiplication of (H^5 * 2, data block #3)
schoolbookAAD(5, htbl, data, tmp0, tmp1, tmp2, tmp3);
movdqu(data, Address(input_data, 16 * 2));
vpshufb(data, data, bswap_mask, Assembler::AVX_128bit);
// Perform carryless multiplication of (H^6 * 2, data block #2)
schoolbookAAD(6, htbl, data, tmp0, tmp1, tmp2, tmp3);
movdqu(data, Address(input_data, 16 * 1));
vpshufb(data, data, bswap_mask, Assembler::AVX_128bit);
// Perform carryless multiplication of (H^7 * 2, data block #1)
schoolbookAAD(7, htbl, data, tmp0, tmp1, tmp2, tmp3);
movdqu(data, Address(input_data, 16 * 0));
// xor data block#0 with input state before perfoming carry-less multiplication
vpshufb(data, data, bswap_mask, Assembler::AVX_128bit);
vpxor(data, data, state, Assembler::AVX_128bit);
// Perform carryless multiplication of (H^8 * 2, data block #0)
schoolbookAAD(8, htbl, data, tmp0, tmp1, tmp2, tmp3);
vpslldq(tmp3, tmp2, 8, Assembler::AVX_128bit);
vpsrldq(tmp2, tmp2, 8, Assembler::AVX_128bit);
vpxor(tmp0, tmp0, tmp3, Assembler::AVX_128bit);// tmp0, tmp1 contains aggregated results of
vpxor(tmp1, tmp1, tmp2, Assembler::AVX_128bit);// the multiplication operation
// we have the 2 128-bit partially accumulated multiplication results in tmp0:tmp1
// with higher 128-bit in tmp1 and lower 128-bit in corresponding tmp0
// Follows the reduction technique mentioned in
// Shift-XOR reduction described in Gueron-Kounavis May 2010
bind(BLOCK8_REDUCTION);
// First Phase of the reduction
vpslld(xmm8, tmp0, 31, Assembler::AVX_128bit); // packed right shifting << 31
vpslld(xmm9, tmp0, 30, Assembler::AVX_128bit); // packed right shifting << 30
vpslld(xmm10, tmp0, 25, Assembler::AVX_128bit); // packed right shifting << 25
// xor the shifted versions
vpxor(xmm8, xmm8, xmm10, Assembler::AVX_128bit);
vpxor(xmm8, xmm8, xmm9, Assembler::AVX_128bit);
vpslldq(xmm9, xmm8, 12, Assembler::AVX_128bit);
vpsrldq(xmm8, xmm8, 4, Assembler::AVX_128bit);
vpxor(tmp0, tmp0, xmm9, Assembler::AVX_128bit); // first phase of reduction is complete
// second phase of the reduction
vpsrld(xmm9, tmp0, 1, Assembler::AVX_128bit); // packed left shifting >> 1
vpsrld(xmm10, tmp0, 2, Assembler::AVX_128bit); // packed left shifting >> 2
vpsrld(tmp2, tmp0, 7, Assembler::AVX_128bit); // packed left shifting >> 7
// xor the shifted versions
vpxor(xmm9, xmm9, xmm10, Assembler::AVX_128bit);
vpxor(xmm9, xmm9, tmp2, Assembler::AVX_128bit);
vpxor(xmm9, xmm9, xmm8, Assembler::AVX_128bit);
vpxor(tmp0, xmm9, tmp0, Assembler::AVX_128bit);
// Final result is in state
vpxor(state, tmp0, tmp1, Assembler::AVX_128bit);
lea(input_data, Address(input_data, 16 * 8));
cmpl(blocks, 8);
jcc(Assembler::below, ONE_BLK_INIT);
jmp(PROCESS_8_BLOCKS);
// Since this is one block operation we will only use H * 2 i.e. the first power of H
bind(ONE_BLK_INIT);
movdqu(tmp0, Address(htbl, 1 * 16));
movdqu(bswap_mask, ExternalAddress(StubRoutines::x86::ghash_byte_swap_mask_addr()));
//Do one (128 bit x 128 bit) carry-less multiplication at a time followed by a reduction.
bind(PROCESS_1_BLOCK);
cmpl(blocks, 0);
jcc(Assembler::equal, SAVE_STATE);
subl(blocks, 1);
movdqu(data, Address(input_data, 0));
vpshufb(data, data, bswap_mask, Assembler::AVX_128bit);
vpxor(state, state, data, Assembler::AVX_128bit);
// gfmul(H*2, state)
call(GFMUL, relocInfo::none);
addptr(input_data, 16);
jmp(PROCESS_1_BLOCK);
bind(SAVE_STATE);
vpshufb(state, state, lswap_mask, Assembler::AVX_128bit);
movdqu(Address(input_state, 0), state);
jmp(EXIT_GHASH);
bind(GFMUL);
gfmul(tmp0, state);
bind(GENERATE_HTBL_1_BLK);
generateHtbl_one_block(htbl);
bind(GENERATE_HTBL_8_BLKS);
generateHtbl_eight_blocks(htbl);
bind(EXIT_GHASH);
// zero out xmm registers used for Htbl storage
vpxor(xmm0, xmm0, xmm0, Assembler::AVX_128bit);
vpxor(xmm1, xmm1, xmm1, Assembler::AVX_128bit);
vpxor(xmm3, xmm3, xmm3, Assembler::AVX_128bit);
vpxor(xmm15, xmm15, xmm15, Assembler::AVX_128bit);
}

View File

@ -4388,6 +4388,45 @@ address generate_cipherBlockChaining_decryptVectorAESCrypt() {
return start;
}
// Polynomial x^128+x^127+x^126+x^121+1
address ghash_polynomial_addr() {
__ align(CodeEntryAlignment);
StubCodeMark mark(this, "StubRoutines", "_ghash_poly_addr");
address start = __ pc();
__ emit_data64(0x0000000000000001, relocInfo::none);
__ emit_data64(0xc200000000000000, relocInfo::none);
return start;
}
address ghash_shufflemask_addr() {
__ align(CodeEntryAlignment);
StubCodeMark mark(this, "StubRoutines", "_ghash_shuffmask_addr");
address start = __ pc();
__ emit_data64(0x0f0f0f0f0f0f0f0f, relocInfo::none);
__ emit_data64(0x0f0f0f0f0f0f0f0f, relocInfo::none);
return start;
}
// Ghash single and multi block operations using AVX instructions
address generate_avx_ghash_processBlocks() {
__ align(CodeEntryAlignment);
StubCodeMark mark(this, "StubRoutines", "ghash_processBlocks");
address start = __ pc();
// arguments
const Register state = c_rarg0;
const Register htbl = c_rarg1;
const Register data = c_rarg2;
const Register blocks = c_rarg3;
__ enter();
// Save state before entering routine
__ avx_ghash(state, htbl, data, blocks);
__ leave(); // required for proper stackwalking of RuntimeStub frame
__ ret(0);
return start;
}
// byte swap x86 long
address generate_ghash_long_swap_mask() {
__ align(CodeEntryAlignment);
@ -5886,9 +5925,15 @@ address generate_cipherBlockChaining_decryptVectorAESCrypt() {
// Generate GHASH intrinsics code
if (UseGHASHIntrinsics) {
StubRoutines::x86::_ghash_long_swap_mask_addr = generate_ghash_long_swap_mask();
StubRoutines::x86::_ghash_byte_swap_mask_addr = generate_ghash_byte_swap_mask();
StubRoutines::_ghash_processBlocks = generate_ghash_processBlocks();
StubRoutines::x86::_ghash_long_swap_mask_addr = generate_ghash_long_swap_mask();
StubRoutines::x86::_ghash_byte_swap_mask_addr = generate_ghash_byte_swap_mask();
if (VM_Version::supports_avx()) {
StubRoutines::x86::_ghash_shuffmask_addr = ghash_shufflemask_addr();
StubRoutines::x86::_ghash_poly_addr = ghash_polynomial_addr();
StubRoutines::_ghash_processBlocks = generate_avx_ghash_processBlocks();
} else {
StubRoutines::_ghash_processBlocks = generate_ghash_processBlocks();
}
}
if (UseBASE64Intrinsics) {

View File

@ -38,6 +38,8 @@ address StubRoutines::x86::_key_shuffle_mask_addr = NULL;
address StubRoutines::x86::_counter_shuffle_mask_addr = NULL;
address StubRoutines::x86::_ghash_long_swap_mask_addr = NULL;
address StubRoutines::x86::_ghash_byte_swap_mask_addr = NULL;
address StubRoutines::x86::_ghash_poly_addr = NULL;
address StubRoutines::x86::_ghash_shuffmask_addr = NULL;
address StubRoutines::x86::_upper_word_mask_addr = NULL;
address StubRoutines::x86::_shuffle_byte_flip_mask_addr = NULL;
address StubRoutines::x86::_k256_adr = NULL;

View File

@ -128,6 +128,8 @@ class x86 {
// swap mask for ghash
static address _ghash_long_swap_mask_addr;
static address _ghash_byte_swap_mask_addr;
static address _ghash_poly_addr;
static address _ghash_shuffmask_addr;
// upper word mask for sha1
static address _upper_word_mask_addr;
@ -205,6 +207,8 @@ class x86 {
static address crc_by128_masks_addr() { return (address)_crc_by128_masks; }
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; }
static address ghash_polynomial_addr() { return _ghash_poly_addr; }
static address upper_word_mask_addr() { return _upper_word_mask_addr; }
static address shuffle_byte_flip_mask_addr() { return _shuffle_byte_flip_mask_addr; }
static address k256_addr() { return _k256_adr; }

View File

@ -1289,7 +1289,7 @@ void VM_Version::get_processor_features() {
if (FLAG_IS_DEFAULT(UseXMMForArrayCopy)) {
UseXMMForArrayCopy = true; // use SSE2 movq on new Intel cpus
}
if (supports_sse4_2() && supports_ht()) { // Newest Intel cpus
if ((supports_sse4_2() && supports_ht()) || supports_avx()) { // Newest Intel cpus
if (FLAG_IS_DEFAULT(UseUnalignedLoadStores)) {
UseUnalignedLoadStores = true; // use movdqu on newest Intel cpus
}

View File

@ -336,6 +336,7 @@ protected:
#define CPU_AVX512_VPOPCNTDQ ((uint64_t)UCONST64(0x2000000000)) // Vector popcount
#define CPU_VPCLMULQDQ ((uint64_t)UCONST64(0x4000000000)) //Vector carryless multiplication
#define CPU_VAES ((uint64_t)UCONST64(0x8000000000)) // Vector AES instructions
#define CPU_VNNI ((uint64_t)UCONST64(0x16000000000)) // Vector Neural Network Instructions
enum Extended_Family {
// AMD
@ -548,6 +549,8 @@ protected:
result |= CPU_VPCLMULQDQ;
if (_cpuid_info.sef_cpuid7_ecx.bits.vaes != 0)
result |= CPU_VAES;
if (_cpuid_info.sef_cpuid7_ecx.bits.avx512_vnni != 0)
result |= CPU_VNNI;
}
}
if(_cpuid_info.sef_cpuid7_ebx.bits.bmi1 != 0)
@ -828,6 +831,7 @@ public:
static bool supports_vpopcntdq() { return (_features & CPU_AVX512_VPOPCNTDQ) != 0; }
static bool supports_vpclmulqdq() { return (_features & CPU_VPCLMULQDQ) != 0; }
static bool supports_vaes() { return (_features & CPU_VAES) != 0; }
static bool supports_vnni() { return (_features & CPU_VNNI) != 0; }
// Intel features
static bool is_intel_family_core() { return is_intel() &&

View File

@ -1446,6 +1446,10 @@ const bool Matcher::match_rule_supported(int opcode) {
if (VM_Version::supports_on_spin_wait() == false)
ret_value = false;
break;
case Op_MulAddVS2VI:
if (UseSSE < 2)
ret_value = false;
break;
}
return ret_value; // Per default match rules are supported.
@ -9855,6 +9859,118 @@ instruct vfma16F_mem(vecZ a, memory b, vecZ c) %{
ins_pipe( pipe_slow );
%}
// --------------------------------- Vector Multiply Add --------------------------------------
instruct smuladd4S2I_reg(vecD dst, vecD src1) %{
predicate(UseSSE >= 2 && UseAVX == 0 && n->as_Vector()->length() == 2);
match(Set dst (MulAddVS2VI dst src1));
format %{ "pmaddwd $dst,$dst,$src1\t! muladd packed4Sto2I" %}
ins_encode %{
__ pmaddwd($dst$$XMMRegister, $src1$$XMMRegister);
%}
ins_pipe( pipe_slow );
%}
instruct vmuladd4S2I_reg(vecD dst, vecD src1, vecD src2) %{
predicate(UseAVX > 0 && n->as_Vector()->length() == 2);
match(Set dst (MulAddVS2VI src1 src2));
format %{ "vpmaddwd $dst,$src1,$src2\t! muladd packed4Sto2I" %}
ins_encode %{
int vector_len = 0;
__ vpmaddwd($dst$$XMMRegister, $src1$$XMMRegister, $src2$$XMMRegister, vector_len);
%}
ins_pipe( pipe_slow );
%}
instruct smuladd8S4I_reg(vecX dst, vecX src1) %{
predicate(UseSSE >= 2 && UseAVX == 0 && n->as_Vector()->length() == 4);
match(Set dst (MulAddVS2VI dst src1));
format %{ "pmaddwd $dst,$dst,$src1\t! muladd packed8Sto4I" %}
ins_encode %{
__ pmaddwd($dst$$XMMRegister, $src1$$XMMRegister);
%}
ins_pipe( pipe_slow );
%}
instruct vmuladd8S4I_reg(vecX dst, vecX src1, vecX src2) %{
predicate(UseAVX > 0 && n->as_Vector()->length() == 4);
match(Set dst (MulAddVS2VI src1 src2));
format %{ "vpmaddwd $dst,$src1,$src2\t! muladd packed8Sto4I" %}
ins_encode %{
int vector_len = 0;
__ vpmaddwd($dst$$XMMRegister, $src1$$XMMRegister, $src2$$XMMRegister, vector_len);
%}
ins_pipe( pipe_slow );
%}
instruct vmuladd16S8I_reg(vecY dst, vecY src1, vecY src2) %{
predicate(UseAVX > 1 && n->as_Vector()->length() == 8);
match(Set dst (MulAddVS2VI src1 src2));
format %{ "vpmaddwd $dst,$src1,$src2\t! muladd packed16Sto8I" %}
ins_encode %{
int vector_len = 1;
__ vpmaddwd($dst$$XMMRegister, $src1$$XMMRegister, $src2$$XMMRegister, vector_len);
%}
ins_pipe( pipe_slow );
%}
instruct vmuladd32S16I_reg(vecZ dst, vecZ src1, vecZ src2) %{
predicate(UseAVX > 2 && n->as_Vector()->length() == 16);
match(Set dst (MulAddVS2VI src1 src2));
format %{ "vpmaddwd $dst,$src1,$src2\t! muladd packed32Sto16I" %}
ins_encode %{
int vector_len = 2;
__ vpmaddwd($dst$$XMMRegister, $src1$$XMMRegister, $src2$$XMMRegister, vector_len);
%}
ins_pipe( pipe_slow );
%}
// --------------------------------- Vector Multiply Add Add ----------------------------------
instruct vmuladdadd4S2I_reg(vecD dst, vecD src1, vecD src2) %{
predicate(VM_Version::supports_vnni() && UseAVX > 2 && n->as_Vector()->length() == 2);
match(Set dst (AddVI (MulAddVS2VI src1 src2) dst));
format %{ "evpdpwssd $dst,$src1,$src2\t! muladdadd packed4Sto2I" %}
ins_encode %{
int vector_len = 0;
__ evpdpwssd($dst$$XMMRegister, $src1$$XMMRegister, $src2$$XMMRegister, vector_len);
%}
ins_pipe( pipe_slow );
%}
instruct vmuladdadd8S4I_reg(vecX dst, vecX src1, vecX src2) %{
predicate(VM_Version::supports_vnni() && UseAVX > 2 && n->as_Vector()->length() == 4);
match(Set dst (AddVI (MulAddVS2VI src1 src2) dst));
format %{ "evpdpwssd $dst,$src1,$src2\t! muladdadd packed8Sto4I" %}
ins_encode %{
int vector_len = 0;
__ evpdpwssd($dst$$XMMRegister, $src1$$XMMRegister, $src2$$XMMRegister, vector_len);
%}
ins_pipe( pipe_slow );
%}
instruct vmuladdadd16S8I_reg(vecY dst, vecY src1, vecY src2) %{
predicate(VM_Version::supports_vnni() && UseAVX > 2 && n->as_Vector()->length() == 8);
match(Set dst (AddVI (MulAddVS2VI src1 src2) dst));
format %{ "evpdpwssd $dst,$src1,$src2\t! muladdadd packed16Sto8I" %}
ins_encode %{
int vector_len = 1;
__ evpdpwssd($dst$$XMMRegister, $src1$$XMMRegister, $src2$$XMMRegister, vector_len);
%}
ins_pipe( pipe_slow );
%}
instruct vmuladdadd32S16I_reg(vecZ dst, vecZ src1, vecZ src2) %{
predicate(VM_Version::supports_vnni() && UseAVX > 2 && n->as_Vector()->length() == 16);
match(Set dst (AddVI (MulAddVS2VI src1 src2) dst));
format %{ "evpdpwssd $dst,$src1,$src2\t! muladdadd packed32Sto16I" %}
ins_encode %{
int vector_len = 2;
__ evpdpwssd($dst$$XMMRegister, $src1$$XMMRegister, $src2$$XMMRegister, vector_len);
%}
ins_pipe( pipe_slow );
%}
// --------------------------------- PopCount --------------------------------------
instruct vpopcount2I(vecD dst, vecD src) %{

View File

@ -7755,6 +7755,16 @@ instruct mulI(rRegI dst, memory src, eFlagsReg cr) %{
ins_pipe( ialu_reg_mem_alu0 );
%}
instruct mulAddS2I_rReg(rRegI dst, rRegI src1, rRegI src2, rRegI src3, eFlagsReg cr)
%{
match(Set dst (MulAddS2I (Binary dst src1) (Binary src2 src3)));
effect(KILL cr, KILL src2);
expand %{ mulI_rReg(dst, src1, cr);
mulI_rReg(src2, src3, cr);
addI_rReg(dst, src2, cr); %}
%}
// Multiply Register Int to Long
instruct mulI2L(eADXRegL dst, eAXRegI src, nadxRegI src1, eFlagsReg flags) %{
// Basic Idea: long = (long)int * (long)int

View File

@ -8175,6 +8175,16 @@ instruct mulI_mem_imm(rRegI dst, memory src, immI imm, rFlagsReg cr)
ins_pipe(ialu_reg_mem_alu0);
%}
instruct mulAddS2I_rReg(rRegI dst, rRegI src1, rRegI src2, rRegI src3, rFlagsReg cr)
%{
match(Set dst (MulAddS2I (Binary dst src1) (Binary src2 src3)));
effect(KILL cr, KILL src2);
expand %{ mulI_rReg(dst, src1, cr);
mulI_rReg(src2, src3, cr);
addI_rReg(dst, src2, cr); %}
%}
instruct mulL_rReg(rRegL dst, rRegL src, rFlagsReg cr)
%{
match(Set dst (MulL dst src));

View File

@ -67,6 +67,11 @@
" of quotas (if set), when true. Otherwise, use the CPU" \
" shares value, provided it is less than quota.") \
\
diagnostic(bool, DumpPrivateMappingsInCore, true, \
"If true, sets bit 2 of /proc/PID/coredump_filter, thus " \
"resulting in file-backed private mappings of the process to "\
"be dumped into the corefile, if UseSharedSpaces is true.") \
\
diagnostic(bool, UseCpuAllocPath, false, \
"Use CPU_ALLOC code path in os::active_processor_count ")

View File

@ -128,8 +128,12 @@
// for timer info max values which include all bits
#define ALL_64_BITS CONST64(0xFFFFFFFFFFFFFFFF)
#define LARGEPAGES_BIT (1 << 6)
#define DAX_SHARED_BIT (1 << 8)
enum CoredumpFilterBit {
FILE_BACKED_PVT_BIT = 1 << 2,
LARGEPAGES_BIT = 1 << 6,
DAX_SHARED_BIT = 1 << 8
};
////////////////////////////////////////////////////////////////////////////////
// global variables
julong os::Linux::_physical_memory = 0;
@ -1350,6 +1354,9 @@ void os::shutdown() {
void os::abort(bool dump_core, void* siginfo, const void* context) {
os::shutdown();
if (dump_core) {
if (UseSharedSpaces && DumpPrivateMappingsInCore) {
ClassLoader::close_jrt_image();
}
#ifndef PRODUCT
fdStream out(defaultStream::output_fd());
out.print_raw("Current thread is ");
@ -3401,10 +3408,9 @@ bool os::Linux::hugetlbfs_sanity_check(bool warn, size_t page_size) {
// - (bit 7) dax private memory
// - (bit 8) dax shared memory
//
static void set_coredump_filter(bool largepages, bool dax_shared) {
static void set_coredump_filter(CoredumpFilterBit bit) {
FILE *f;
long cdm;
bool filter_changed = false;
if ((f = fopen("/proc/self/coredump_filter", "r+")) == NULL) {
return;
@ -3415,17 +3421,11 @@ static void set_coredump_filter(bool largepages, bool dax_shared) {
return;
}
long saved_cdm = cdm;
rewind(f);
cdm |= bit;
if (largepages && (cdm & LARGEPAGES_BIT) == 0) {
cdm |= LARGEPAGES_BIT;
filter_changed = true;
}
if (dax_shared && (cdm & DAX_SHARED_BIT) == 0) {
cdm |= DAX_SHARED_BIT;
filter_changed = true;
}
if (filter_changed) {
if (cdm != saved_cdm) {
fprintf(f, "%#lx", cdm);
}
@ -3564,7 +3564,7 @@ void os::large_page_init() {
size_t large_page_size = Linux::setup_large_page_size();
UseLargePages = Linux::setup_large_page_type(large_page_size);
set_coredump_filter(true /*largepages*/, false /*dax_shared*/);
set_coredump_filter(LARGEPAGES_BIT);
}
#ifndef SHM_HUGETLB
@ -5072,8 +5072,13 @@ jint os::init_2(void) {
prio_init();
if (!FLAG_IS_DEFAULT(AllocateHeapAt)) {
set_coredump_filter(false /*largepages*/, true /*dax_shared*/);
set_coredump_filter(DAX_SHARED_BIT);
}
if (UseSharedSpaces && DumpPrivateMappingsInCore) {
set_coredump_filter(FILE_BACKED_PVT_BIT);
}
return JNI_OK;
}

View File

@ -74,15 +74,17 @@
// * 63-47 Fixed (17-bits, always zero)
//
const size_t ZPlatformPageSizeSmallShift = 21; // 2M
const size_t ZPlatformPageSizeSmallShift = 21; // 2M
const size_t ZPlatformAddressOffsetBits = 42; // 4TB
const size_t ZPlatformAddressOffsetBits = 42; // 4TB
const uintptr_t ZPlatformAddressMetadataShift = ZPlatformAddressOffsetBits;
const uintptr_t ZPlatformAddressMetadataShift = ZPlatformAddressOffsetBits;
const uintptr_t ZPlatformAddressSpaceStart = (uintptr_t)1 << ZPlatformAddressOffsetBits;
const uintptr_t ZPlatformAddressSpaceSize = ((uintptr_t)1 << ZPlatformAddressOffsetBits) * 4;
const uintptr_t ZPlatformAddressSpaceStart = (uintptr_t)1 << ZPlatformAddressOffsetBits;
const uintptr_t ZPlatformAddressSpaceSize = ((uintptr_t)1 << ZPlatformAddressOffsetBits) * 4;
const size_t ZPlatformCacheLineSize = 64;
const size_t ZPlatformNMethodDisarmedOffset = 4;
const size_t ZPlatformCacheLineSize = 64;
#endif // OS_CPU_LINUX_X86_ZGLOBALS_LINUX_X86_HPP

View File

@ -4181,6 +4181,7 @@ bool MatchRule::is_vector() const {
"AddReductionVF", "AddReductionVD",
"MulReductionVI", "MulReductionVL",
"MulReductionVF", "MulReductionVD",
"MulAddVS2VI",
"LShiftCntV","RShiftCntV",
"LShiftVB","LShiftVS","LShiftVI","LShiftVL",
"RShiftVB","RShiftVS","RShiftVI","RShiftVL",

View File

@ -5703,7 +5703,8 @@ void ClassFileParser::fill_instance_klass(InstanceKlass* ik, bool changed_by_loa
ik->major_version() != JAVA_MIN_SUPPORTED_VERSION &&
log_is_enabled(Info, class, preview)) {
ResourceMark rm;
log_info(class, preview)("Loading preview feature type %s", ik->external_name());
log_info(class, preview)("Loading class %s that depends on preview features (class file version %d.65535)",
ik->external_name(), ik->major_version());
}
if (log_is_enabled(Debug, class, resolve)) {

View File

@ -363,6 +363,13 @@ void ClassPathZipEntry::contents_do(void f(const char* name, void* context), voi
}
}
void ClassPathImageEntry::close_jimage() {
if (_jimage != NULL) {
(*JImageClose)(_jimage);
_jimage = NULL;
}
}
ClassPathImageEntry::ClassPathImageEntry(JImageFile* jimage, const char* name) :
ClassPathEntry(),
_jimage(jimage) {
@ -614,6 +621,12 @@ void ClassLoader::update_module_path_entry_list(const char *path, TRAPS) {
void ClassLoader::setup_module_search_path(const char* path, TRAPS) {
update_module_path_entry_list(path, THREAD);
}
void ClassLoader::close_jrt_image() {
assert(ClassLoader::has_jrt_entry(), "Not applicable for exploded builds");
_jrt_entry->close_jimage();
}
#endif // INCLUDE_CDS
// Construct the array of module/path pairs as specified to --patch-module

View File

@ -55,6 +55,7 @@ public:
virtual bool is_jar_file() const = 0;
virtual const char* name() const = 0;
virtual JImageFile* jimage() const = 0;
virtual void close_jimage() = 0;
// Constructor
ClassPathEntry() : _next(NULL) {}
// Attempt to locate file_name through this class path entry.
@ -70,6 +71,7 @@ class ClassPathDirEntry: public ClassPathEntry {
bool is_jar_file() const { return false; }
const char* name() const { return _dir; }
JImageFile* jimage() const { return NULL; }
void close_jimage() {}
ClassPathDirEntry(const char* dir);
virtual ~ClassPathDirEntry() {}
ClassFileStream* open_stream(const char* name, TRAPS);
@ -98,6 +100,7 @@ class ClassPathZipEntry: public ClassPathEntry {
bool is_jar_file() const { return true; }
const char* name() const { return _zip_name; }
JImageFile* jimage() const { return NULL; }
void close_jimage() {}
ClassPathZipEntry(jzfile* zip, const char* zip_name, bool is_boot_append);
virtual ~ClassPathZipEntry();
u1* open_entry(const char* name, jint* filesize, bool nul_terminate, TRAPS);
@ -117,6 +120,7 @@ public:
bool is_open() const { return _jimage != NULL; }
const char* name() const { return _name == NULL ? "" : _name; }
JImageFile* jimage() const { return _jimage; }
void close_jimage();
ClassPathImageEntry(JImageFile* jimage, const char* name);
virtual ~ClassPathImageEntry();
ClassFileStream* open_stream(const char* name, TRAPS);
@ -333,6 +337,7 @@ class ClassLoader: AllStatic {
// Modular java runtime image is present vs. a build with exploded modules
static bool has_jrt_entry() { return (_jrt_entry != NULL); }
static ClassPathEntry* get_jrt_entry() { return _jrt_entry; }
static void close_jrt_image();
// Add a module's exploded directory to the boot loader's exploded module build list
static void add_to_exploded_build_list(Symbol* module_name, TRAPS);

View File

@ -116,14 +116,17 @@ public:
return SymbolTableHash::BaseConfig::allocate_node(size, value);
}
static void free_node(void* memory, Symbol* const& value) {
// We get here either because #1 some threads lost a race
// to insert a newly created Symbol, or #2 we are freeing
// a symbol during normal cleanup deletion.
// If #1, then the symbol can be a permanent (refcount==PERM_REFCOUNT),
// or regular newly created one but with refcount==0 (see SymbolTableCreateEntry)
// If #2, then the symbol must have refcount==0
assert((value->refcount() == PERM_REFCOUNT) || (value->refcount() == 0),
// We get here because #1 some threads lost a race to insert a newly created Symbol
// or #2 we're cleaning up unused symbol.
// If #1, then the symbol can be either permanent (refcount==PERM_REFCOUNT),
// or regular newly created one (refcount==1)
// If #2, then the symbol is dead (refcount==0)
assert((value->refcount() == PERM_REFCOUNT) || (value->refcount() == 1) || (value->refcount() == 0),
"refcount %d", value->refcount());
if (value->refcount() == 1) {
value->decrement_refcount();
assert(value->refcount() == 0, "expected dead symbol");
}
SymbolTable::delete_symbol(value);
SymbolTableHash::BaseConfig::free_node(memory, value);
SymbolTable::item_removed();
@ -162,6 +165,12 @@ void SymbolTable::delete_symbol(Symbol* sym) {
}
}
void SymbolTable::update_needs_rehash(bool rehash) {
if (rehash) {
_needs_rehashing = true;
}
}
void SymbolTable::item_added() {
Atomic::inc(&(SymbolTable::the_table()->_items_count));
}
@ -398,9 +407,7 @@ Symbol* SymbolTable::do_lookup(const char* name, int len, uintx hash) {
SymbolTableGet stg;
bool rehash_warning = false;
_local_table->get(thread, lookup, stg, &rehash_warning);
if (rehash_warning) {
_needs_rehashing = true;
}
update_needs_rehash(rehash_warning);
Symbol* sym = stg.get_res_sym();
assert((sym == NULL) || sym->refcount() != 0, "found dead symbol");
return sym;
@ -462,71 +469,26 @@ void SymbolTable::add(ClassLoaderData* loader_data, const constantPoolHandle& cp
}
}
class SymbolTableCreateEntry : public StackObj {
private:
Thread* _thread;
const char* _name;
int _len;
bool _heap;
Symbol* _return;
Symbol* _created;
void assert_for_name(Symbol* sym, const char* where) const {
#ifdef ASSERT
assert(sym->utf8_length() == _len, "%s [%d,%d]", where, sym->utf8_length(), _len);
for (int i = 0; i < _len; i++) {
assert(sym->char_at(i) == _name[i],
"%s [%d,%d,%d]", where, i, sym->char_at(i), _name[i]);
}
#endif
}
public:
SymbolTableCreateEntry(Thread* thread, const char* name, int len, bool heap)
: _thread(thread), _name(name) , _len(len), _heap(heap), _return(NULL) , _created(NULL) {
assert(_name != NULL, "expected valid name");
}
Symbol* operator()() {
_created = SymbolTable::the_table()->allocate_symbol(_name, _len, _heap, _thread);
assert(_created != NULL, "expected created symbol");
assert_for_name(_created, "operator()()");
assert(_created->equals(_name, _len),
"symbol must be properly initialized [%p,%d,%d]", _name, _len, (int)_heap);
return _created;
}
void operator()(bool inserted, Symbol** value) {
assert(value != NULL, "expected valid value");
assert(*value != NULL, "value should point to a symbol");
if (!inserted && (_created != NULL)) {
// We created our symbol, but someone else inserted
// theirs first, so ours will be destroyed.
// Since symbols are created with refcount of 1,
// we must decrement it here to 0 to delete,
// unless it's a permanent one.
if (_created->refcount() != PERM_REFCOUNT) {
assert(_created->refcount() == 1, "expected newly created symbol");
_created->decrement_refcount();
assert(_created->refcount() == 0, "expected dead symbol");
}
}
_return = *value;
assert_for_name(_return, "operator()");
}
Symbol* get_new_sym() const {
assert_for_name(_return, "get_new_sym");
return _return;
}
};
Symbol* SymbolTable::do_add_if_needed(const char* name, int len, uintx hash, bool heap, TRAPS) {
SymbolTableLookup lookup(THREAD, name, len, hash);
SymbolTableCreateEntry stce(THREAD, name, len, heap);
bool rehash_warning = false;
SymbolTableGet stg;
bool clean_hint = false;
_local_table->get_insert_lazy(THREAD, lookup, stce, stce, &rehash_warning, &clean_hint);
if (rehash_warning) {
_needs_rehashing = true;
}
bool rehash_warning = false;
Symbol* sym = NULL;
do {
if (_local_table->get(THREAD, lookup, stg, &rehash_warning)) {
sym = stg.get_res_sym();
break;
}
sym = SymbolTable::the_table()->allocate_symbol(name, len, heap, THREAD);
if (_local_table->insert(THREAD, lookup, sym, &rehash_warning, &clean_hint)) {
break;
}
} while(true);
update_needs_rehash(rehash_warning);
if (clean_hint) {
// we just found out that there is a dead item,
// which we were unable to clean right now,
@ -536,8 +498,8 @@ Symbol* SymbolTable::do_add_if_needed(const char* name, int len, uintx hash, boo
mark_item_clean_count();
check_concurrent_work();
}
Symbol* sym = stce.get_new_sym();
assert(sym->refcount() != 0, "zero is invalid");
assert((sym == NULL) || sym->refcount() != 0, "found dead symbol");
return sym;
}

View File

@ -169,6 +169,7 @@ private:
void try_rehash_table();
bool do_rehash();
inline void update_needs_rehash(bool rehash);
public:
// The symbol table

View File

@ -379,6 +379,10 @@ bool vmIntrinsics::preserves_state(vmIntrinsics::ID id) {
case vmIntrinsics::_vectorizedMismatch:
case vmIntrinsics::_fmaD:
case vmIntrinsics::_fmaF:
case vmIntrinsics::_isDigit:
case vmIntrinsics::_isLowerCase:
case vmIntrinsics::_isUpperCase:
case vmIntrinsics::_isWhitespace:
return true;
default:
return false;
@ -828,6 +832,12 @@ bool vmIntrinsics::is_disabled_by_flags(vmIntrinsics::ID id) {
case vmIntrinsics::_subtractExactL:
if (!UseMathExactIntrinsics || !InlineMathNatives) return true;
break;
case vmIntrinsics::_isDigit:
case vmIntrinsics::_isLowerCase:
case vmIntrinsics::_isUpperCase:
case vmIntrinsics::_isWhitespace:
if (!UseCharacterCompareIntrinsics) return true;
break;
#endif // COMPILER2
default:
return false;

View File

@ -71,6 +71,7 @@
template(java_lang_Boolean, "java/lang/Boolean") \
template(java_lang_Character, "java/lang/Character") \
template(java_lang_Character_CharacterCache, "java/lang/Character$CharacterCache") \
template(java_lang_CharacterDataLatin1, "java/lang/CharacterDataLatin1") \
template(java_lang_Float, "java/lang/Float") \
template(java_lang_Double, "java/lang/Double") \
template(java_lang_Byte, "java/lang/Byte") \
@ -933,6 +934,15 @@
do_intrinsic(_equalsL, java_lang_StringLatin1,equals_name, equalsB_signature, F_S) \
do_intrinsic(_equalsU, java_lang_StringUTF16, equals_name, equalsB_signature, F_S) \
\
do_intrinsic(_isDigit, java_lang_CharacterDataLatin1, isDigit_name, int_bool_signature, F_R) \
do_name( isDigit_name, "isDigit") \
do_intrinsic(_isLowerCase, java_lang_CharacterDataLatin1, isLowerCase_name, int_bool_signature, F_R) \
do_name( isLowerCase_name, "isLowerCase") \
do_intrinsic(_isUpperCase, java_lang_CharacterDataLatin1, isUpperCase_name, int_bool_signature, F_R) \
do_name( isUpperCase_name, "isUpperCase") \
do_intrinsic(_isWhitespace, java_lang_CharacterDataLatin1, isWhitespace_name, int_bool_signature, F_R) \
do_name( isWhitespace_name, "isWhitespace") \
\
do_intrinsic(_Preconditions_checkIndex, jdk_internal_util_Preconditions, checkIndex_name, Preconditions_checkIndex_signature, F_S) \
do_signature(Preconditions_checkIndex_signature, "(IILjava/util/function/BiFunction;)I") \
\

View File

@ -51,6 +51,7 @@ VMReg VtableStub::_receiver_location = VMRegImpl::Bad();
void* VtableStub::operator new(size_t size, int code_size) throw() {
assert_lock_strong(VtableStubs_lock);
assert(size == sizeof(VtableStub), "mismatched size");
// compute real VtableStub size (rounded to nearest word)
const int real_size = align_up(code_size + (int)sizeof(VtableStub), wordSize);
@ -208,31 +209,35 @@ void VtableStubs::bookkeeping(MacroAssembler* masm, outputStream* out, VtableStu
address VtableStubs::find_stub(bool is_vtable_stub, int vtable_index) {
assert(vtable_index >= 0, "must be positive");
VtableStub* s = ShareVtableStubs ? lookup(is_vtable_stub, vtable_index) : NULL;
if (s == NULL) {
if (is_vtable_stub) {
s = create_vtable_stub(vtable_index);
} else {
s = create_itable_stub(vtable_index);
}
// Creation of vtable or itable can fail if there is not enough free space in the code cache.
VtableStub* s;
{
MutexLockerEx ml(VtableStubs_lock, Mutex::_no_safepoint_check_flag);
s = ShareVtableStubs ? lookup(is_vtable_stub, vtable_index) : NULL;
if (s == NULL) {
return NULL;
}
if (is_vtable_stub) {
s = create_vtable_stub(vtable_index);
} else {
s = create_itable_stub(vtable_index);
}
enter(is_vtable_stub, vtable_index, s);
if (PrintAdapterHandlers) {
tty->print_cr("Decoding VtableStub %s[%d]@" INTX_FORMAT,
is_vtable_stub? "vtbl": "itbl", vtable_index, p2i(VtableStub::receiver_location()));
Disassembler::decode(s->code_begin(), s->code_end());
}
// Notify JVMTI about this stub. The event will be recorded by the enclosing
// JvmtiDynamicCodeEventCollector and posted when this thread has released
// all locks.
if (JvmtiExport::should_post_dynamic_code_generated()) {
JvmtiExport::post_dynamic_code_generated_while_holding_locks(is_vtable_stub? "vtable stub": "itable stub",
s->code_begin(), s->code_end());
// Creation of vtable or itable can fail if there is not enough free space in the code cache.
if (s == NULL) {
return NULL;
}
enter(is_vtable_stub, vtable_index, s);
if (PrintAdapterHandlers) {
tty->print_cr("Decoding VtableStub %s[%d]@" INTX_FORMAT,
is_vtable_stub? "vtbl": "itbl", vtable_index, p2i(VtableStub::receiver_location()));
Disassembler::decode(s->code_begin(), s->code_end());
}
// Notify JVMTI about this stub. The event will be recorded by the enclosing
// JvmtiDynamicCodeEventCollector and posted when this thread has released
// all locks.
if (JvmtiExport::should_post_dynamic_code_generated()) {
JvmtiExport::post_dynamic_code_generated_while_holding_locks(is_vtable_stub? "vtable stub": "itable stub",
s->code_begin(), s->code_end());
}
}
}
return s->entry_point();
@ -247,7 +252,7 @@ inline uint VtableStubs::hash(bool is_vtable_stub, int vtable_index){
VtableStub* VtableStubs::lookup(bool is_vtable_stub, int vtable_index) {
MutexLockerEx ml(VtableStubs_lock, Mutex::_no_safepoint_check_flag);
assert_lock_strong(VtableStubs_lock);
unsigned hash = VtableStubs::hash(is_vtable_stub, vtable_index);
VtableStub* s = _table[hash];
while( s && !s->matches(is_vtable_stub, vtable_index)) s = s->next();
@ -256,7 +261,7 @@ VtableStub* VtableStubs::lookup(bool is_vtable_stub, int vtable_index) {
void VtableStubs::enter(bool is_vtable_stub, int vtable_index, VtableStub* s) {
MutexLockerEx ml(VtableStubs_lock, Mutex::_no_safepoint_check_flag);
assert_lock_strong(VtableStubs_lock);
assert(s->matches(is_vtable_stub, vtable_index), "bad vtable stub");
unsigned int h = VtableStubs::hash(is_vtable_stub, vtable_index);
// enter s at the beginning of the corresponding list

View File

@ -70,19 +70,24 @@ CMSHeap::CMSHeap(GenCollectorPolicy *policy) :
Generation::ParNew,
Generation::ConcurrentMarkSweep,
"ParNew:CMS"),
_workers(NULL),
_eden_pool(NULL),
_survivor_pool(NULL),
_old_pool(NULL) {
_workers = new WorkGang("GC Thread", ParallelGCThreads,
/* are_GC_task_threads */true,
/* are_ConcurrentGC_threads */false);
_workers->initialize_workers();
}
jint CMSHeap::initialize() {
jint status = GenCollectedHeap::initialize();
if (status != JNI_OK) return status;
_workers = new WorkGang("GC Thread", ParallelGCThreads,
/* are_GC_task_threads */true,
/* are_ConcurrentGC_threads */false);
if (_workers == NULL) {
return JNI_ENOMEM;
}
_workers->initialize_workers();
// If we are running CMS, create the collector responsible
// for collecting the CMS generations.
if (!create_cms_collector()) {

View File

@ -1531,10 +1531,6 @@ G1CollectedHeap::G1CollectedHeap(G1CollectorPolicy* collector_policy) :
_is_subject_to_discovery_cm(this),
_in_cset_fast_test() {
_workers = new WorkGang("GC Thread", ParallelGCThreads,
true /* are_GC_task_threads */,
false /* are_ConcurrentGC_threads */);
_workers->initialize_workers();
_verifier = new G1HeapVerifier(this);
_allocator = new G1Allocator(this);
@ -1767,6 +1763,14 @@ jint G1CollectedHeap::initialize() {
_humongous_reclaim_candidates.initialize(start, end, granularity);
}
_workers = new WorkGang("GC Thread", ParallelGCThreads,
true /* are_GC_task_threads */,
false /* are_ConcurrentGC_threads */);
if (_workers == NULL) {
return JNI_ENOMEM;
}
_workers->initialize_workers();
// Create the G1ConcurrentMark data structure and thread.
// (Must do this late, so that "max_regions" is defined.)
_cm = new G1ConcurrentMark(this, prev_bitmap_storage, next_bitmap_storage);

View File

@ -1026,6 +1026,9 @@ public:
// The number of regions that are completely free.
uint num_free_regions() const { return _hrm.num_free_regions(); }
// The number of regions that can be allocated into.
uint num_free_or_available_regions() const { return num_free_regions() + _hrm.available(); }
MemoryUsage get_auxiliary_data_memory_usage() const {
return _hrm.get_auxiliary_data_memory_usage();
}

View File

@ -89,7 +89,7 @@ void G1HeapTransition::print() {
Data after(_g1_heap);
size_t eden_capacity_length_after_gc = _g1_heap->g1_policy()->young_list_target_length() - after._survivor_length;
size_t survivor_capacity_length_after_gc = _g1_heap->g1_policy()->max_survivor_regions();
size_t survivor_capacity_length_before_gc = _g1_heap->g1_policy()->max_survivor_regions();
DetailedUsage usage;
if (log_is_enabled(Trace, gc, heap)) {
@ -112,7 +112,7 @@ void G1HeapTransition::print() {
log_trace(gc, heap)(" Used: 0K, Waste: 0K");
log_info(gc, heap)("Survivor regions: " SIZE_FORMAT "->" SIZE_FORMAT "(" SIZE_FORMAT ")",
_before._survivor_length, after._survivor_length, survivor_capacity_length_after_gc);
_before._survivor_length, after._survivor_length, survivor_capacity_length_before_gc);
log_trace(gc, heap)(" Used: " SIZE_FORMAT "K, Waste: " SIZE_FORMAT "K",
usage._survivor_used / K, ((after._survivor_length * HeapRegion::GrainBytes) - usage._survivor_used) / K);

View File

@ -470,6 +470,10 @@ void G1Policy::record_collection_pause_start(double start_time_sec) {
// every time we calculate / recalculate the target young length.
update_survivors_policy();
assert(max_survivor_regions() + _g1h->num_used_regions() <= _g1h->max_regions(),
"Maximum survivor regions %u plus used regions %u exceeds max regions %u",
max_survivor_regions(), _g1h->num_used_regions(), _g1h->max_regions());
assert(_g1h->used() == _g1h->recalculate_used(),
"sanity, used: " SIZE_FORMAT " recalculate_used: " SIZE_FORMAT,
_g1h->used(), _g1h->recalculate_used());
@ -899,8 +903,8 @@ bool G1Policy::adaptive_young_list_length() const {
return _young_gen_sizer.adaptive_young_list_length();
}
size_t G1Policy::desired_survivor_size() const {
size_t const survivor_capacity = HeapRegion::GrainWords * _max_survivor_regions;
size_t G1Policy::desired_survivor_size(uint max_regions) const {
size_t const survivor_capacity = HeapRegion::GrainWords * max_regions;
return (size_t)((((double)survivor_capacity) * TargetSurvivorRatio) / 100);
}
@ -927,15 +931,22 @@ void G1Policy::update_max_gc_locker_expansion() {
void G1Policy::update_survivors_policy() {
double max_survivor_regions_d =
(double) _young_list_target_length / (double) SurvivorRatio;
// We use ceiling so that if max_survivor_regions_d is > 0.0 (but
// smaller than 1.0) we'll get 1.
_max_survivor_regions = (uint) ceil(max_survivor_regions_d);
_tenuring_threshold = _survivors_age_table.compute_tenuring_threshold(desired_survivor_size());
// Calculate desired survivor size based on desired max survivor regions (unconstrained
// by remaining heap). Otherwise we may cause undesired promotions as we are
// already getting close to end of the heap, impacting performance even more.
uint const desired_max_survivor_regions = ceil(max_survivor_regions_d);
size_t const survivor_size = desired_survivor_size(desired_max_survivor_regions);
_tenuring_threshold = _survivors_age_table.compute_tenuring_threshold(survivor_size);
if (UsePerfData) {
_policy_counters->tenuring_threshold()->set_value(_tenuring_threshold);
_policy_counters->desired_survivor_size()->set_value(desired_survivor_size() * oopSize);
_policy_counters->desired_survivor_size()->set_value(survivor_size * oopSize);
}
// The real maximum survivor size is bounded by the number of regions that can
// be allocated into.
_max_survivor_regions = MIN2(desired_max_survivor_regions,
_g1h->num_free_or_available_regions());
}
bool G1Policy::force_initial_mark_if_outside_cycle(GCCause::Cause gc_cause) {

View File

@ -399,7 +399,7 @@ private:
AgeTable _survivors_age_table;
size_t desired_survivor_size() const;
size_t desired_survivor_size(uint max_regions) const;
public:
// Fraction used when predicting how many optional regions to include in
// the CSet. This fraction of the available time is used for optional regions,

View File

@ -26,47 +26,24 @@
#include "gc/shared/barrierSet.hpp"
#include "gc/shared/barrierSetAssembler.hpp"
#include "runtime/thread.hpp"
#include "utilities/debug.hpp"
#include "utilities/macros.hpp"
BarrierSet* BarrierSet::_barrier_set = NULL;
class SetBarrierSetNonJavaThread : public ThreadClosure {
BarrierSet* _barrier_set;
size_t _count;
public:
SetBarrierSetNonJavaThread(BarrierSet* barrier_set) :
_barrier_set(barrier_set), _count(0) {}
virtual void do_thread(Thread* thread) {
_barrier_set->on_thread_create(thread);
++_count;
}
size_t count() const { return _count; }
};
void BarrierSet::set_barrier_set(BarrierSet* barrier_set) {
assert(_barrier_set == NULL, "Already initialized");
_barrier_set = barrier_set;
// Some threads are created before the barrier set, so the call to
// BarrierSet::on_thread_create had to be deferred for them. Now that
// we have the barrier set, do those deferred calls.
// First do any non-JavaThreads.
SetBarrierSetNonJavaThread njt_closure(_barrier_set);
Threads::non_java_threads_do(&njt_closure);
// Do the current (main) thread. Ensure it's the one and only
// JavaThread so far. Also verify that it isn't yet on the thread
// Notify barrier set of the current (main) thread. Normally the
// Thread constructor deals with this, but the main thread is
// created before we get here. Verify it isn't yet on the thread
// list, else we'd also need to call BarrierSet::on_thread_attach.
// This is the only thread that can exist at this point; the Thread
// constructor objects to other threads being created before the
// barrier set is available.
assert(Thread::current()->is_Java_thread(),
"Expected main thread to be a JavaThread");
assert((njt_closure.count() + 1) == Threads::threads_before_barrier_set(),
"Unexpected JavaThreads before barrier set initialization: "
"Non-JavaThreads: " SIZE_FORMAT ", all: " SIZE_FORMAT,
njt_closure.count(), Threads::threads_before_barrier_set());
assert(!JavaThread::current()->on_thread_list(),
"Main thread already on thread list.");
_barrier_set->on_thread_create(Thread::current());

View File

@ -80,10 +80,6 @@ void ZArguments::initialize() {
FLAG_SET_DEFAULT(UseCompressedOops, false);
FLAG_SET_DEFAULT(UseCompressedClassPointers, false);
// ClassUnloading not (yet) supported
FLAG_SET_DEFAULT(ClassUnloading, false);
FLAG_SET_DEFAULT(ClassUnloadingWithConcurrentMark, false);
// Verification before startup and after exit not (yet) supported
FLAG_SET_DEFAULT(VerifyDuringStartup, false);
FLAG_SET_DEFAULT(VerifyBeforeExit, false);

View File

@ -81,6 +81,7 @@ public:
static void load_barrier_on_oop_fields(oop o);
static oop load_barrier_on_weak_oop_field_preloaded(volatile oop* p, oop o);
static oop load_barrier_on_phantom_oop_field_preloaded(volatile oop* p, oop o);
static void load_barrier_on_root_oop_field(oop* p);
// Weak load barrier
static oop weak_load_barrier_on_oop_field(volatile oop* p);
@ -99,6 +100,7 @@ public:
// Keep alive barrier
static void keep_alive_barrier_on_weak_oop_field(volatile oop* p);
static void keep_alive_barrier_on_phantom_oop_field(volatile oop* p);
static void keep_alive_barrier_on_phantom_root_oop_field(oop* p);
// Mark barrier
static void mark_barrier_on_oop_field(volatile oop* p, bool finalizable);

View File

@ -111,11 +111,12 @@ inline void ZBarrier::root_barrier(oop* p, oop o) {
const uintptr_t good_addr = slow_path(addr);
// Non-atomic healing helps speed up root scanning. This is safe to do
// since we are always healing roots in a safepoint, which means we are
// never racing with mutators modifying roots while we are healing them.
// It's also safe in case multiple GC threads try to heal the same root,
// since they would always heal the root in the same way and it does not
// matter in which order it happens.
// since we are always healing roots in a safepoint, or under a lock,
// which ensures we are never racing with mutators modifying roots while
// we are healing them. It's also safe in case multiple GC threads try
// to heal the same root if it is aligned, since they would always heal
// the root in the same way and it does not matter in which order it
// happens. For misaligned oops, there needs to be mutual exclusion.
*p = ZOop::to_oop(good_addr);
}
@ -188,6 +189,11 @@ inline oop ZBarrier::load_barrier_on_phantom_oop_field_preloaded(volatile oop* p
return load_barrier_on_oop_field_preloaded(p, o);
}
inline void ZBarrier::load_barrier_on_root_oop_field(oop* p) {
const oop o = *p;
root_barrier<is_good_or_null_fast_path, load_barrier_on_oop_slow_path>(p, o);
}
//
// Weak load barrier
//
@ -269,6 +275,13 @@ inline void ZBarrier::keep_alive_barrier_on_phantom_oop_field(volatile oop* p) {
barrier<is_good_or_null_fast_path, keep_alive_barrier_on_phantom_oop_slow_path>(p, o);
}
inline void ZBarrier::keep_alive_barrier_on_phantom_root_oop_field(oop* p) {
// This operation is only valid when resurrection is blocked.
assert(ZResurrection::is_blocked(), "Invalid phase");
const oop o = *p;
root_barrier<is_good_or_null_fast_path, keep_alive_barrier_on_phantom_oop_slow_path>(p, o);
}
//
// Mark barrier
//

View File

@ -24,6 +24,7 @@
#include "precompiled.hpp"
#include "gc/z/zBarrierSet.hpp"
#include "gc/z/zBarrierSetAssembler.hpp"
#include "gc/z/zBarrierSetNMethod.hpp"
#include "gc/z/zGlobals.hpp"
#include "gc/z/zHeap.inline.hpp"
#include "gc/z/zThreadLocalData.hpp"
@ -39,11 +40,20 @@
class ZBarrierSetC1;
class ZBarrierSetC2;
static BarrierSetNMethod* make_barrier_set_nmethod() {
// NMethod barriers are only used when class unloading is enabled
if (!ClassUnloading) {
return NULL;
}
return new ZBarrierSetNMethod();
}
ZBarrierSet::ZBarrierSet() :
BarrierSet(make_barrier_set_assembler<ZBarrierSetAssembler>(),
make_barrier_set_c1<ZBarrierSetC1>(),
make_barrier_set_c2<ZBarrierSetC2>(),
NULL /* barrier_set_nmethod */,
make_barrier_set_nmethod(),
BarrierSet::FakeRtti(BarrierSet::ZBarrierSet)) {}
ZBarrierSetAssembler* ZBarrierSet::assembler() {

View File

@ -0,0 +1,73 @@
/*
* 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.
*/
#include "precompiled.hpp"
#include "code/nmethod.hpp"
#include "gc/z/zBarrierSetNMethod.hpp"
#include "gc/z/zGlobals.hpp"
#include "gc/z/zLock.inline.hpp"
#include "gc/z/zOopClosures.hpp"
#include "gc/z/zNMethodTable.hpp"
#include "gc/z/zThreadLocalData.hpp"
#include "logging/log.hpp"
bool ZBarrierSetNMethod::nmethod_entry_barrier(nmethod* nm) {
ZLocker<ZReentrantLock> locker(ZNMethodTable::lock_for_nmethod(nm));
log_trace(nmethod, barrier)("Entered critical zone for %p", nm);
if (!is_armed(nm)) {
// Some other thread got here first and healed the oops
// and disarmed the nmethod.
return true;
}
if (nm->is_unloading()) {
// We can end up calling nmethods that are unloading
// since we clear compiled ICs lazily. Returning false
// will re-resovle the call and update the compiled IC.
return false;
}
// Heal oops and disarm
ZNMethodOopClosure cl;
nm->oops_do(&cl);
nm->fix_oop_relocations();
OrderAccess::release();
disarm(nm);
return true;
}
int ZBarrierSetNMethod::disarmed_value() const {
// We override the default BarrierSetNMethod::disarmed_value() since
// this can be called by GC threads, which doesn't keep an up to date
// address_bad_mask.
const uintptr_t disarmed_addr = ((uintptr_t)&ZAddressBadMask) + ZNMethodDisarmedOffset;
return *((int*)disarmed_addr);
}
ByteSize ZBarrierSetNMethod::thread_disarmed_offset() const {
return ZThreadLocalData::nmethod_disarmed_offset();
}

View File

@ -0,0 +1,41 @@
/*
* 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.
*/
#ifndef SHARE_GC_Z_ZBARRIERSETNMETHOD_HPP
#define SHARE_GC_Z_ZBARRIERSETNMETHOD_HPP
#include "gc/shared/barrierSetNMethod.hpp"
#include "memory/allocation.hpp"
class nmethod;
class ZBarrierSetNMethod : public BarrierSetNMethod {
protected:
virtual int disarmed_value() const;
virtual bool nmethod_entry_barrier(nmethod* nm);
public:
virtual ByteSize thread_disarmed_offset() const;
};
#endif // SHARE_GC_Z_ZBARRIERSETNMETHOD_HPP

View File

@ -259,12 +259,10 @@ bool ZCollectedHeap::block_is_obj(const HeapWord* addr) const {
}
void ZCollectedHeap::register_nmethod(nmethod* nm) {
assert_locked_or_safepoint(CodeCache_lock);
ZNMethodTable::register_nmethod(nm);
}
void ZCollectedHeap::unregister_nmethod(nmethod* nm) {
assert_locked_or_safepoint(CodeCache_lock);
ZNMethodTable::unregister_nmethod(nm);
}

View File

@ -91,6 +91,9 @@ const uintptr_t ZAddressSpaceStart = ZPlatformAddressSpaceStart;
const uintptr_t ZAddressSpaceSize = ZPlatformAddressSpaceSize;
const uintptr_t ZAddressSpaceEnd = ZAddressSpaceStart + ZAddressSpaceSize;
// NMethod entry barrier
const size_t ZNMethodDisarmedOffset = ZPlatformNMethodDisarmedOffset;
// Cache line size
const size_t ZCacheLineSize = ZPlatformCacheLineSize;

View File

@ -69,6 +69,7 @@ ZHeap::ZHeap() :
_weak_roots_processor(&_workers),
_relocate(&_workers),
_relocation_set(),
_unload(&_workers),
_serviceability(heap_min_size(), heap_max_size()) {
// Install global heap instance
assert(_heap == NULL, "Already initialized");
@ -353,9 +354,6 @@ bool ZHeap::mark_end() {
// Enter mark completed phase
ZGlobalPhase = ZPhaseMarkCompleted;
// Resize metaspace
MetaspaceGC::compute_new_size();
// Update statistics
ZStatSample(ZSamplerHeapUsedAfterMark, used());
ZStatHeap::set_at_mark_end(capacity(), allocated(), used());
@ -366,6 +364,9 @@ bool ZHeap::mark_end() {
// Process weak roots
_weak_roots_processor.process_weak_roots();
// Prepare to unload unused classes and code
_unload.prepare();
return true;
}
@ -380,6 +381,9 @@ void ZHeap::process_non_strong_references() {
// Process concurrent weak roots
_weak_roots_processor.process_concurrent_weak_roots();
// Unload unused classes and code
_unload.unload();
// Unblock resurrection of weak/phantom references
ZResurrection::unblock();
@ -463,8 +467,8 @@ void ZHeap::reset_relocation_set() {
void ZHeap::relocate_start() {
assert(SafepointSynchronize::is_at_safepoint(), "Should be at safepoint");
// Update statistics
ZStatSample(ZSamplerHeapUsedBeforeRelocation, used());
// Finish unloading of classes and code
_unload.finish();
// Flip address view
ZAddressMasks::flip_to_remapped();
@ -474,6 +478,7 @@ void ZHeap::relocate_start() {
ZGlobalPhase = ZPhaseRelocate;
// Update statistics
ZStatSample(ZSamplerHeapUsedBeforeRelocation, used());
ZStatHeap::set_at_relocate_start(capacity(), allocated(), used());
// Remap/Relocate roots

View File

@ -41,6 +41,7 @@
#include "gc/z/zRootsIterator.hpp"
#include "gc/z/zWeakRootsProcessor.hpp"
#include "gc/z/zServiceability.hpp"
#include "gc/z/zUnload.hpp"
#include "gc/z/zWorkers.hpp"
#include "memory/allocation.hpp"
@ -59,6 +60,7 @@ private:
ZWeakRootsProcessor _weak_roots_processor;
ZRelocate _relocate;
ZRelocationSet _relocation_set;
ZUnload _unload;
ZServiceability _serviceability;
size_t heap_min_size() const;

View File

@ -287,6 +287,14 @@ void ZMark::follow_partial_array(ZMarkStackEntry entry, bool finalizable) {
}
void ZMark::follow_array_object(objArrayOop obj, bool finalizable) {
if (finalizable) {
ZMarkBarrierOopClosure<true /* finalizable */> cl;
cl.do_klass(obj->klass());
} else {
ZMarkBarrierOopClosure<false /* finalizable */> cl;
cl.do_klass(obj->klass());
}
const uintptr_t addr = (uintptr_t)obj->base();
const size_t size = (size_t)obj->length() * oopSize;

View File

@ -23,45 +23,62 @@
#include "precompiled.hpp"
#include "code/relocInfo.hpp"
#include "code/nativeInst.hpp"
#include "code/nmethod.hpp"
#include "code/icBuffer.hpp"
#include "gc/shared/barrierSet.hpp"
#include "gc/shared/barrierSetNMethod.hpp"
#include "gc/z/zArray.inline.hpp"
#include "gc/z/zGlobals.hpp"
#include "gc/z/zHash.inline.hpp"
#include "gc/z/zLock.inline.hpp"
#include "gc/z/zNMethodTable.hpp"
#include "gc/z/zOopClosures.inline.hpp"
#include "gc/z/zTask.hpp"
#include "gc/z/zWorkers.hpp"
#include "logging/log.hpp"
#include "memory/allocation.inline.hpp"
#include "memory/resourceArea.hpp"
#include "oops/oop.inline.hpp"
#include "runtime/atomic.hpp"
#include "runtime/orderAccess.hpp"
#include "runtime/os.hpp"
#include "utilities/debug.hpp"
class ZNMethodWithImmediateOops {
class ZNMethodDataImmediateOops {
private:
nmethod* const _nm;
const size_t _nimmediate_oops;
const size_t _nimmediate_oops;
static size_t header_size();
ZNMethodWithImmediateOops(nmethod* nm, const GrowableArray<oop*>& immediate_oops);
ZNMethodDataImmediateOops(const GrowableArray<oop*>& immediate_oops);
public:
static ZNMethodWithImmediateOops* create(nmethod* nm, const GrowableArray<oop*>& immediate_oops);
static void destroy(ZNMethodWithImmediateOops* nmi);
static ZNMethodDataImmediateOops* create(const GrowableArray<oop*>& immediate_oops);
static void destroy(ZNMethodDataImmediateOops* data_immediate_oops);
nmethod* method() const;
size_t immediate_oops_count() const;
oop** immediate_oops_begin() const;
oop** immediate_oops_end() const;
};
size_t ZNMethodWithImmediateOops::header_size() {
const size_t size = sizeof(ZNMethodWithImmediateOops);
size_t ZNMethodDataImmediateOops::header_size() {
const size_t size = sizeof(ZNMethodDataImmediateOops);
assert(is_aligned(size, sizeof(oop*)), "Header misaligned");
return size;
}
ZNMethodWithImmediateOops::ZNMethodWithImmediateOops(nmethod* nm, const GrowableArray<oop*>& immediate_oops) :
_nm(nm),
ZNMethodDataImmediateOops* ZNMethodDataImmediateOops::create(const GrowableArray<oop*>& immediate_oops) {
// Allocate memory for the ZNMethodDataImmediateOops object
// plus the immediate oop* array that follows right after.
const size_t size = ZNMethodDataImmediateOops::header_size() + (sizeof(oop*) * immediate_oops.length());
void* const data_immediate_oops = NEW_C_HEAP_ARRAY(uint8_t, size, mtGC);
return ::new (data_immediate_oops) ZNMethodDataImmediateOops(immediate_oops);
}
void ZNMethodDataImmediateOops::destroy(ZNMethodDataImmediateOops* data_immediate_oops) {
ZNMethodTable::safe_delete(data_immediate_oops);
}
ZNMethodDataImmediateOops::ZNMethodDataImmediateOops(const GrowableArray<oop*>& immediate_oops) :
_nimmediate_oops(immediate_oops.length()) {
// Save all immediate oops
for (size_t i = 0; i < _nimmediate_oops; i++) {
@ -69,41 +86,97 @@ ZNMethodWithImmediateOops::ZNMethodWithImmediateOops(nmethod* nm, const Growable
}
}
ZNMethodWithImmediateOops* ZNMethodWithImmediateOops::create(nmethod* nm, const GrowableArray<oop*>& immediate_oops) {
// Allocate memory for the ZNMethodWithImmediateOops object
// plus the immediate oop* array that follows right after.
const size_t size = header_size() + (sizeof(oop*) * immediate_oops.length());
void* const method_with_immediate_oops = NEW_C_HEAP_ARRAY(uint8_t, size, mtGC);
return ::new (method_with_immediate_oops) ZNMethodWithImmediateOops(nm, immediate_oops);
}
void ZNMethodWithImmediateOops::destroy(ZNMethodWithImmediateOops* nmi) {
FREE_C_HEAP_ARRAY(uint8_t, nmi);
}
nmethod* ZNMethodWithImmediateOops::method() const {
return _nm;
}
size_t ZNMethodWithImmediateOops::immediate_oops_count() const {
size_t ZNMethodDataImmediateOops::immediate_oops_count() const {
return _nimmediate_oops;
}
oop** ZNMethodWithImmediateOops::immediate_oops_begin() const {
oop** ZNMethodDataImmediateOops::immediate_oops_begin() const {
// The immediate oop* array starts immediately after this object
return (oop**)((uintptr_t)this + header_size());
}
oop** ZNMethodWithImmediateOops::immediate_oops_end() const {
oop** ZNMethodDataImmediateOops::immediate_oops_end() const {
return immediate_oops_begin() + immediate_oops_count();
}
class ZNMethodData {
private:
ZReentrantLock _lock;
ZNMethodDataImmediateOops* volatile _immediate_oops;
ZNMethodData(nmethod* nm);
public:
static ZNMethodData* create(nmethod* nm);
static void destroy(ZNMethodData* data);
ZReentrantLock* lock();
ZNMethodDataImmediateOops* immediate_oops() const;
ZNMethodDataImmediateOops* swap_immediate_oops(const GrowableArray<oop*>& immediate_oops);
};
ZNMethodData* ZNMethodData::create(nmethod* nm) {
void* const method = NEW_C_HEAP_ARRAY(uint8_t, sizeof(ZNMethodData), mtGC);
return ::new (method) ZNMethodData(nm);
}
void ZNMethodData::destroy(ZNMethodData* data) {
ZNMethodDataImmediateOops::destroy(data->immediate_oops());
ZNMethodTable::safe_delete(data);
}
ZNMethodData::ZNMethodData(nmethod* nm) :
_lock(),
_immediate_oops(NULL) {}
ZReentrantLock* ZNMethodData::lock() {
return &_lock;
}
ZNMethodDataImmediateOops* ZNMethodData::immediate_oops() const {
return OrderAccess::load_acquire(&_immediate_oops);
}
ZNMethodDataImmediateOops* ZNMethodData::swap_immediate_oops(const GrowableArray<oop*>& immediate_oops) {
ZNMethodDataImmediateOops* const data_immediate_oops =
immediate_oops.is_empty() ? NULL : ZNMethodDataImmediateOops::create(immediate_oops);
return Atomic::xchg(data_immediate_oops, &_immediate_oops);
}
static ZNMethodData* gc_data(const nmethod* nm) {
return nm->gc_data<ZNMethodData>();
}
static void set_gc_data(nmethod* nm, ZNMethodData* data) {
return nm->set_gc_data<ZNMethodData>(data);
}
ZNMethodTableEntry* ZNMethodTable::_table = NULL;
size_t ZNMethodTable::_size = 0;
ZLock ZNMethodTable::_iter_lock;
ZNMethodTableEntry* ZNMethodTable::_iter_table = NULL;
size_t ZNMethodTable::_iter_table_size = 0;
ZArray<void*> ZNMethodTable::_iter_deferred_deletes;
size_t ZNMethodTable::_nregistered = 0;
size_t ZNMethodTable::_nunregistered = 0;
volatile size_t ZNMethodTable::_claimed = 0;
void ZNMethodTable::safe_delete(void* data) {
if (data == NULL) {
return;
}
ZLocker<ZLock> locker(&_iter_lock);
if (_iter_table != NULL) {
// Iteration in progress, defer delete
_iter_deferred_deletes.add(data);
} else {
// Iteration not in progress, delete now
FREE_C_HEAP_ARRAY(uint8_t, data);
}
}
ZNMethodTableEntry ZNMethodTable::create_entry(nmethod* nm) {
GrowableArray<oop*> immediate_oops;
bool non_immediate_oops = false;
@ -132,29 +205,27 @@ ZNMethodTableEntry ZNMethodTable::create_entry(nmethod* nm) {
}
}
// oops_count() returns the number of oops in the oop table plus one
if (immediate_oops.is_empty() && nm->oops_count() == 1) {
// No oops found, return empty entry
return ZNMethodTableEntry();
// Attach GC data to nmethod
ZNMethodData* data = gc_data(nm);
if (data == NULL) {
data = ZNMethodData::create(nm);
set_gc_data(nm, data);
}
if (immediate_oops.is_empty()) {
// No immediate oops found, return entry without immediate oops
return ZNMethodTableEntry(nm, non_immediate_oops);
}
// Attach immediate oops in GC data
ZNMethodDataImmediateOops* const old_data_immediate_oops = data->swap_immediate_oops(immediate_oops);
ZNMethodDataImmediateOops::destroy(old_data_immediate_oops);
// Return entry with immediate oops
return ZNMethodTableEntry(ZNMethodWithImmediateOops::create(nm, immediate_oops), non_immediate_oops);
// Create entry
return ZNMethodTableEntry(nm, non_immediate_oops, !immediate_oops.is_empty());
}
void ZNMethodTable::destroy_entry(ZNMethodTableEntry entry) {
if (entry.immediate_oops()) {
ZNMethodWithImmediateOops::destroy(entry.method_with_immediate_oops());
ZReentrantLock* ZNMethodTable::lock_for_nmethod(nmethod* nm) {
ZNMethodData* const data = gc_data(nm);
if (data == NULL) {
return NULL;
}
}
nmethod* ZNMethodTable::method(ZNMethodTableEntry entry) {
return entry.immediate_oops() ? entry.method_with_immediate_oops()->method() : entry.method();
return data->lock();
}
size_t ZNMethodTable::first_index(const nmethod* nm, size_t size) {
@ -171,7 +242,7 @@ size_t ZNMethodTable::next_index(size_t prev_index, size_t size) {
}
bool ZNMethodTable::register_entry(ZNMethodTableEntry* table, size_t size, ZNMethodTableEntry entry) {
const nmethod* const nm = method(entry);
const nmethod* const nm = entry.method();
size_t index = first_index(nm, size);
for (;;) {
@ -183,9 +254,8 @@ bool ZNMethodTable::register_entry(ZNMethodTableEntry* table, size_t size, ZNMet
return true;
}
if (table_entry.registered() && method(table_entry) == nm) {
if (table_entry.registered() && table_entry.method() == nm) {
// Replace existing entry
destroy_entry(table_entry);
table[index] = entry;
return false;
}
@ -194,7 +264,7 @@ bool ZNMethodTable::register_entry(ZNMethodTableEntry* table, size_t size, ZNMet
}
}
bool ZNMethodTable::unregister_entry(ZNMethodTableEntry* table, size_t size, const nmethod* nm) {
bool ZNMethodTable::unregister_entry(ZNMethodTableEntry* table, size_t size, nmethod* nm) {
if (size == 0) {
// Table is empty
return false;
@ -210,10 +280,13 @@ bool ZNMethodTable::unregister_entry(ZNMethodTableEntry* table, size_t size, con
return false;
}
if (table_entry.registered() && method(table_entry) == nm) {
if (table_entry.registered() && table_entry.method() == nm) {
// Remove entry
destroy_entry(table_entry);
table[index] = ZNMethodTableEntry(true /* unregistered */);
// Destroy GC data
ZNMethodData::destroy(gc_data(nm));
set_gc_data(nm, NULL);
return true;
}
@ -222,6 +295,7 @@ bool ZNMethodTable::unregister_entry(ZNMethodTableEntry* table, size_t size, con
}
void ZNMethodTable::rebuild(size_t new_size) {
ZLocker<ZLock> locker(&_iter_lock);
assert(is_power_of_2(new_size), "Invalid size");
log_debug(gc, nmethod)("Rebuilding NMethod Table: "
@ -243,8 +317,10 @@ void ZNMethodTable::rebuild(size_t new_size) {
}
}
// Delete old table
delete [] _table;
if (_iter_table != _table) {
// Delete old table
delete [] _table;
}
// Install new table
_table = new_table;
@ -294,8 +370,8 @@ void ZNMethodTable::log_register(const nmethod* nm, ZNMethodTableEntry entry) {
p2i(nm),
nm->compiler_name(),
nm->oops_count() - 1,
entry.immediate_oops() ? entry.method_with_immediate_oops()->immediate_oops_count() : 0,
BOOL_TO_STR(entry.non_immediate_oops()));
entry.immediate_oops() ? gc_data(nm)->immediate_oops()->immediate_oops_count() : 0,
entry.non_immediate_oops() ? "Yes" : "No");
LogTarget(Trace, gc, nmethod, oops) log_oops;
if (!log_oops.is_enabled()) {
@ -312,12 +388,14 @@ void ZNMethodTable::log_register(const nmethod* nm, ZNMethodTableEntry entry) {
if (entry.immediate_oops()) {
// Print nmethod immediate oops
const ZNMethodWithImmediateOops* const nmi = entry.method_with_immediate_oops();
oop** const begin = nmi->immediate_oops_begin();
oop** const end = nmi->immediate_oops_end();
for (oop** p = begin; p < end; p++) {
log_oops.print(" ImmediateOop[" SIZE_FORMAT "] " PTR_FORMAT " @ " PTR_FORMAT " (%s)",
(p - begin), p2i(**p), p2i(*p), (**p)->klass()->external_name());
const ZNMethodDataImmediateOops* const nmi = gc_data(nm)->immediate_oops();
if (nmi != NULL) {
oop** const begin = nmi->immediate_oops_begin();
oop** const end = nmi->immediate_oops_end();
for (oop** p = begin; p < end; p++) {
log_oops.print(" ImmediateOop[" SIZE_FORMAT "] " PTR_FORMAT " @ " PTR_FORMAT " (%s)",
(p - begin), p2i(**p), p2i(*p), (**p)->klass()->external_name());
}
}
}
}
@ -343,21 +421,17 @@ size_t ZNMethodTable::unregistered_nmethods() {
}
void ZNMethodTable::register_nmethod(nmethod* nm) {
assert(CodeCache_lock->owned_by_self(), "Lock must be held");
ResourceMark rm;
// Grow/Shrink/Prune table if needed
rebuild_if_needed();
// Create entry
const ZNMethodTableEntry entry = create_entry(nm);
log_register(nm, entry);
if (!entry.registered()) {
// Method doesn't have any oops, ignore it
return;
}
// Grow/Shrink/Prune table if needed
rebuild_if_needed();
// Insert new entry
if (register_entry(_table, _size, entry)) {
// New entry registered. When register_entry() instead returns
@ -365,11 +439,31 @@ void ZNMethodTable::register_nmethod(nmethod* nm) {
// to increase number of registered entries in that case.
_nregistered++;
}
// Disarm nmethod entry barrier
disarm_nmethod(nm);
}
void ZNMethodTable::sweeper_wait_for_iteration() {
// The sweeper must wait for any ongoing iteration to complete
// before it can unregister an nmethod.
if (!Thread::current()->is_Code_cache_sweeper_thread()) {
return;
}
assert(CodeCache_lock->owned_by_self(), "Lock must be held");
while (_iter_table != NULL) {
MutexUnlockerEx mu(CodeCache_lock, Mutex::_no_safepoint_check_flag);
os::naked_short_sleep(1);
}
}
void ZNMethodTable::unregister_nmethod(nmethod* nm) {
ResourceMark rm;
sweeper_wait_for_iteration();
log_unregister(nm);
// Remove entry
@ -383,20 +477,45 @@ void ZNMethodTable::unregister_nmethod(nmethod* nm) {
}
}
void ZNMethodTable::gc_prologue() {
_claimed = 0;
void ZNMethodTable::disarm_nmethod(nmethod* nm) {
BarrierSetNMethod* const bs = BarrierSet::barrier_set()->barrier_set_nmethod();
if (bs != NULL) {
bs->disarm(nm);
}
}
void ZNMethodTable::gc_epilogue() {
assert(_claimed >= _size, "Failed to claim all table entries");
void ZNMethodTable::nmethod_entries_do_begin() {
MutexLockerEx mu(CodeCache_lock, Mutex::_no_safepoint_check_flag);
ZLocker<ZLock> locker(&_iter_lock);
// Prepare iteration
_iter_table = _table;
_iter_table_size = _size;
_claimed = 0;
assert(_iter_deferred_deletes.is_empty(), "Should be emtpy");
}
void ZNMethodTable::nmethod_entries_do_end() {
MutexLockerEx mu(CodeCache_lock, Mutex::_no_safepoint_check_flag);
ZLocker<ZLock> locker(&_iter_lock);
// Finish iteration
if (_iter_table != _table) {
delete [] _iter_table;
}
_iter_table = NULL;
assert(_claimed >= _iter_table_size, "Failed to claim all table entries");
// Process deferred deletes
ZArrayIterator<void*> iter(&_iter_deferred_deletes);
for (void* data; iter.next(&data);) {
FREE_C_HEAP_ARRAY(uint8_t, data);
}
_iter_deferred_deletes.clear();
}
void ZNMethodTable::entry_oops_do(ZNMethodTableEntry entry, OopClosure* cl) {
nmethod* const nm = method(entry);
if (!nm->is_alive()) {
// No need to visit oops
return;
}
nmethod* const nm = entry.method();
// Process oops table
oop* const begin = nm->oops_begin();
@ -407,29 +526,52 @@ void ZNMethodTable::entry_oops_do(ZNMethodTableEntry entry, OopClosure* cl) {
}
}
// Process immediate oops
if (entry.immediate_oops()) {
// Process immediate oops
const ZNMethodWithImmediateOops* const nmi = entry.method_with_immediate_oops();
oop** const begin = nmi->immediate_oops_begin();
oop** const end = nmi->immediate_oops_end();
for (oop** p = begin; p < end; p++) {
cl->do_oop(*p);
const ZNMethodDataImmediateOops* const nmi = gc_data(nm)->immediate_oops();
if (nmi != NULL) {
oop** const begin = nmi->immediate_oops_begin();
oop** const end = nmi->immediate_oops_end();
for (oop** p = begin; p < end; p++) {
if (**p != Universe::non_oop_word()) {
cl->do_oop(*p);
}
}
}
}
// Process non-immediate oops
if (entry.non_immediate_oops()) {
// Process non-immediate oops
nmethod* const nm = entry.method();
nm->fix_oop_relocations();
}
}
class ZNMethodTableEntryToOopsDo : public ZNMethodTableEntryClosure {
private:
OopClosure* _cl;
public:
ZNMethodTableEntryToOopsDo(OopClosure* cl) :
_cl(cl) {}
void do_nmethod_entry(ZNMethodTableEntry entry) {
ZNMethodTable::entry_oops_do(entry, _cl);
}
};
void ZNMethodTable::oops_do(OopClosure* cl) {
ZNMethodTableEntryToOopsDo entry_cl(cl);
nmethod_entries_do(&entry_cl);
}
void ZNMethodTable::nmethod_entries_do(ZNMethodTableEntryClosure* cl) {
for (;;) {
// Claim table partition. Each partition is currently sized to span
// two cache lines. This number is just a guess, but seems to work well.
const size_t partition_size = (ZCacheLineSize * 2) / sizeof(ZNMethodTableEntry);
const size_t partition_start = MIN2(Atomic::add(partition_size, &_claimed) - partition_size, _size);
const size_t partition_end = MIN2(partition_start + partition_size, _size);
const size_t partition_start = MIN2(Atomic::add(partition_size, &_claimed) - partition_size, _iter_table_size);
const size_t partition_end = MIN2(partition_start + partition_size, _iter_table_size);
if (partition_start == partition_end) {
// End of table
break;
@ -437,10 +579,141 @@ void ZNMethodTable::oops_do(OopClosure* cl) {
// Process table partition
for (size_t i = partition_start; i < partition_end; i++) {
const ZNMethodTableEntry entry = _table[i];
const ZNMethodTableEntry entry = _iter_table[i];
if (entry.registered()) {
entry_oops_do(entry, cl);
cl->do_nmethod_entry(entry);
}
}
}
}
class ZNMethodTableUnlinkClosure : public ZNMethodTableEntryClosure {
private:
bool _unloading_occurred;
volatile bool _failed;
void set_failed() {
Atomic::store(true, &_failed);
}
public:
ZNMethodTableUnlinkClosure(bool unloading_occurred) :
_unloading_occurred(unloading_occurred),
_failed(false) {}
virtual void do_nmethod_entry(ZNMethodTableEntry entry) {
if (failed()) {
return;
}
nmethod* const nm = entry.method();
if (!nm->is_alive()) {
return;
}
if (nm->is_unloading()) {
// Unlinking of the dependencies must happen before the
// handshake separating unlink and purge.
nm->flush_dependencies(false /* delete_immediately */);
return;
}
ZLocker<ZReentrantLock> locker(ZNMethodTable::lock_for_nmethod(nm));
// Heal oops and disarm
ZNMethodOopClosure cl;
ZNMethodTable::entry_oops_do(entry, &cl);
ZNMethodTable::disarm_nmethod(nm);
// Clear compiled ICs and exception caches
if (!nm->unload_nmethod_caches(_unloading_occurred)) {
set_failed();
}
}
bool failed() const {
return Atomic::load(&_failed);
}
};
class ZNMethodTableUnlinkTask : public ZTask {
private:
ZNMethodTableUnlinkClosure _cl;
ICRefillVerifier* _verifier;
public:
ZNMethodTableUnlinkTask(bool unloading_occurred, ICRefillVerifier* verifier) :
ZTask("ZNMethodTableUnlinkTask"),
_cl(unloading_occurred),
_verifier(verifier) {
ZNMethodTable::nmethod_entries_do_begin();
}
~ZNMethodTableUnlinkTask() {
ZNMethodTable::nmethod_entries_do_end();
}
virtual void work() {
ICRefillVerifierMark mark(_verifier);
ZNMethodTable::nmethod_entries_do(&_cl);
}
bool success() const {
return !_cl.failed();
}
};
void ZNMethodTable::unlink(ZWorkers* workers, bool unloading_occurred) {
for (;;) {
ICRefillVerifier verifier;
{
ZNMethodTableUnlinkTask task(unloading_occurred, &verifier);
workers->run_concurrent(&task);
if (task.success()) {
return;
}
}
// Cleaning failed because we ran out of transitional IC stubs,
// so we have to refill and try again. Refilling requires taking
// a safepoint, so we temporarily leave the suspendible thread set.
SuspendibleThreadSetLeaver sts;
InlineCacheBuffer::refill_ic_stubs();
}
}
class ZNMethodTablePurgeClosure : public ZNMethodTableEntryClosure {
public:
virtual void do_nmethod_entry(ZNMethodTableEntry entry) {
nmethod* const nm = entry.method();
if (nm->is_alive() && nm->is_unloading()) {
nm->make_unloaded();
}
}
};
class ZNMethodTablePurgeTask : public ZTask {
private:
ZNMethodTablePurgeClosure _cl;
public:
ZNMethodTablePurgeTask() :
ZTask("ZNMethodTablePurgeTask"),
_cl() {
ZNMethodTable::nmethod_entries_do_begin();
}
~ZNMethodTablePurgeTask() {
ZNMethodTable::nmethod_entries_do_end();
}
virtual void work() {
ZNMethodTable::nmethod_entries_do(&_cl);
}
};
void ZNMethodTable::purge(ZWorkers* workers) {
ZNMethodTablePurgeTask task;
workers->run_concurrent(&task);
}

View File

@ -24,28 +24,40 @@
#ifndef SHARE_GC_Z_ZNMETHODTABLE_HPP
#define SHARE_GC_Z_ZNMETHODTABLE_HPP
#include "gc/z/zArray.hpp"
#include "gc/z/zGlobals.hpp"
#include "gc/z/zLock.hpp"
#include "gc/z/zNMethodTableEntry.hpp"
#include "memory/allocation.hpp"
class ZWorkers;
class ZNMethodTableEntryClosure {
public:
virtual void do_nmethod_entry(ZNMethodTableEntry entry) = 0;
};
class ZNMethodTable : public AllStatic {
private:
static ZNMethodTableEntry* _table;
static size_t _size;
static ZLock _iter_lock;
static ZNMethodTableEntry* _iter_table;
static size_t _iter_table_size;
static ZArray<void*> _iter_deferred_deletes;
static size_t _nregistered;
static size_t _nunregistered;
static volatile size_t _claimed ATTRIBUTE_ALIGNED(ZCacheLineSize);
static ZNMethodTableEntry create_entry(nmethod* nm);
static void destroy_entry(ZNMethodTableEntry entry);
static nmethod* method(ZNMethodTableEntry entry);
static size_t first_index(const nmethod* nm, size_t size);
static size_t next_index(size_t prev_index, size_t size);
static void sweeper_wait_for_iteration();
static bool register_entry(ZNMethodTableEntry* table, size_t size, ZNMethodTableEntry entry);
static bool unregister_entry(ZNMethodTableEntry* table, size_t size, const nmethod* nm);
static bool unregister_entry(ZNMethodTableEntry* table, size_t size, nmethod* nm);
static void rebuild(size_t new_size);
static void rebuild_if_needed();
@ -53,19 +65,28 @@ private:
static void log_register(const nmethod* nm, ZNMethodTableEntry entry);
static void log_unregister(const nmethod* nm);
static void entry_oops_do(ZNMethodTableEntry entry, OopClosure* cl);
public:
static void safe_delete(void* data);
static size_t registered_nmethods();
static size_t unregistered_nmethods();
static void register_nmethod(nmethod* nm);
static void unregister_nmethod(nmethod* nm);
static void disarm_nmethod(nmethod* nm);
static void gc_prologue();
static void gc_epilogue();
static ZReentrantLock* lock_for_nmethod(nmethod* nm);
static void oops_do(OopClosure* cl);
static void entry_oops_do(ZNMethodTableEntry entry, OopClosure* cl);
static void nmethod_entries_do_begin();
static void nmethod_entries_do_end();
static void nmethod_entries_do(ZNMethodTableEntryClosure* cl);
static void unlink(ZWorkers* workers, bool unloading_occurred);
static void purge(ZWorkers* workers);
};
#endif // SHARE_GC_Z_ZNMETHODTABLE_HPP

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2017, 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
@ -43,38 +43,30 @@
// | |
// | 0-0 Registered Flag (1-bits) *
// |
// * 63-3 NMethod/ZNMethodWithImmediateOops Address (61-bits)
// * 63-3 NMethod Address (61-bits)
//
class nmethod;
class ZNMethodWithImmediateOops;
class ZNMethodTableEntry : public CHeapObj<mtGC> {
private:
typedef ZBitField<uint64_t, bool, 0, 1> field_registered;
typedef ZBitField<uint64_t, bool, 1, 1> field_unregistered;
typedef ZBitField<uint64_t, bool, 1, 1> field_immediate_oops;
typedef ZBitField<uint64_t, bool, 2, 1> field_non_immediate_oops;
typedef ZBitField<uint64_t, nmethod*, 3, 61, 3> field_method;
typedef ZBitField<uint64_t, ZNMethodWithImmediateOops*, 3, 61, 3> field_method_with_immediate_oops;
typedef ZBitField<uint64_t, bool, 0, 1> field_registered;
typedef ZBitField<uint64_t, bool, 1, 1> field_unregistered;
typedef ZBitField<uint64_t, bool, 1, 1> field_immediate_oops;
typedef ZBitField<uint64_t, bool, 2, 1> field_non_immediate_oops;
typedef ZBitField<uint64_t, nmethod*, 3, 61, 3> field_method;
uint64_t _entry;
public:
ZNMethodTableEntry(bool unregistered = false) :
explicit ZNMethodTableEntry(bool unregistered = false) :
_entry(field_unregistered::encode(unregistered) |
field_registered::encode(false)) {}
ZNMethodTableEntry(nmethod* method, bool non_immediate_oops) :
ZNMethodTableEntry(nmethod* method, bool non_immediate_oops, bool immediate_oops) :
_entry(field_method::encode(method) |
field_non_immediate_oops::encode(non_immediate_oops) |
field_immediate_oops::encode(false) |
field_registered::encode(true)) {}
ZNMethodTableEntry(ZNMethodWithImmediateOops* method_with_immediate_oops, bool non_immediate_oops) :
_entry(field_method_with_immediate_oops::encode(method_with_immediate_oops) |
field_non_immediate_oops::encode(non_immediate_oops) |
field_immediate_oops::encode(true) |
field_immediate_oops::encode(immediate_oops) |
field_registered::encode(true)) {}
bool registered() const {
@ -96,10 +88,6 @@ public:
nmethod* method() const {
return field_method::decode(_entry);
}
ZNMethodWithImmediateOops* method_with_immediate_oops() const {
return field_method_with_immediate_oops::decode(_entry);
}
};
#endif // SHARE_GC_Z_ZNMETHODTABLEENTRY_HPP

View File

@ -39,14 +39,23 @@ public:
#endif
};
class ZNMethodOopClosure : public OopClosure {
public:
virtual void do_oop(oop* p);
virtual void do_oop(narrowOop* p);
};
template <bool finalizable>
class ZMarkBarrierOopClosure : public BasicOopIterateClosure {
class ZMarkBarrierOopClosure : public MetadataVisitingOopIterateClosure {
public:
ZMarkBarrierOopClosure();
virtual void do_oop(oop* p);
virtual void do_oop(narrowOop* p);
virtual void do_klass(Klass* k);
virtual void do_cld(ClassLoaderData* cld);
#ifdef ASSERT
virtual bool should_verify_oops() {
return false;

View File

@ -24,6 +24,7 @@
#ifndef SHARE_GC_Z_ZOOPCLOSURES_INLINE_HPP
#define SHARE_GC_Z_ZOOPCLOSURES_INLINE_HPP
#include "classfile/classLoaderData.hpp"
#include "gc/z/zBarrier.inline.hpp"
#include "gc/z/zHeap.inline.hpp"
#include "gc/z/zOop.inline.hpp"
@ -40,9 +41,21 @@ inline void ZLoadBarrierOopClosure::do_oop(narrowOop* p) {
ShouldNotReachHere();
}
inline void ZNMethodOopClosure::do_oop(oop* p) {
if (ZResurrection::is_blocked()) {
ZBarrier::keep_alive_barrier_on_phantom_root_oop_field(p);
} else {
ZBarrier::load_barrier_on_root_oop_field(p);
}
}
inline void ZNMethodOopClosure::do_oop(narrowOop* p) {
ShouldNotReachHere();
}
template <bool finalizable>
inline ZMarkBarrierOopClosure<finalizable>::ZMarkBarrierOopClosure() :
BasicOopIterateClosure(finalizable ? NULL : ZHeap::heap()->reference_discoverer()) {}
MetadataVisitingOopIterateClosure(finalizable ? NULL : ZHeap::heap()->reference_discoverer()) {}
template <bool finalizable>
inline void ZMarkBarrierOopClosure<finalizable>::do_oop(oop* p) {
@ -54,6 +67,18 @@ inline void ZMarkBarrierOopClosure<finalizable>::do_oop(narrowOop* p) {
ShouldNotReachHere();
}
template <bool finalizable>
inline void ZMarkBarrierOopClosure<finalizable>::do_klass(Klass* k) {
ClassLoaderData* const cld = k->class_loader_data();
ZMarkBarrierOopClosure<finalizable>::do_cld(cld);
}
template <bool finalizable>
inline void ZMarkBarrierOopClosure<finalizable>::do_cld(ClassLoaderData* cld) {
const int claim = finalizable ? ClassLoaderData::_claim_finalizable : ClassLoaderData::_claim_strong;
cld->oops_do(this, claim);
}
inline bool ZPhantomIsAliveObjectClosure::do_object_b(oop o) {
return ZBarrier::is_alive_barrier_on_phantom_oop(o);
}

View File

@ -27,8 +27,11 @@
#include "classfile/systemDictionary.hpp"
#include "code/codeCache.hpp"
#include "compiler/oopMap.hpp"
#include "gc/shared/barrierSet.hpp"
#include "gc/shared/barrierSetNMethod.hpp"
#include "gc/shared/oopStorageParState.inline.hpp"
#include "gc/shared/suspendibleThreadSet.hpp"
#include "gc/z/zBarrierSetNMethod.hpp"
#include "gc/z/zGlobals.hpp"
#include "gc/z/zNMethodTable.hpp"
#include "gc/z/zOopClosures.inline.hpp"
@ -132,6 +135,30 @@ void ZParallelWeakOopsDo<T, F>::weak_oops_do(BoolObjectClosure* is_alive, ZRoots
}
}
class ZCodeBlobClosure : public CodeBlobToOopClosure {
private:
BarrierSetNMethod* _bs;
public:
ZCodeBlobClosure(OopClosure* cl) :
CodeBlobToOopClosure(cl, true /* fix_relocations */),
_bs(BarrierSet::barrier_set()->barrier_set_nmethod()) {}
virtual void do_code_blob(CodeBlob* cb) {
nmethod* const nm = cb->as_nmethod_or_null();
if (nm == NULL || nm->test_set_oops_do_mark()) {
return;
}
CodeBlobToOopClosure::do_code_blob(cb);
_bs->disarm(nm);
}
};
void ZRootsIteratorClosure::do_thread(Thread* thread) {
ZCodeBlobClosure code_cl(this);
thread->oops_do(this, ClassUnloading ? &code_cl : NULL);
}
ZRootsIterator::ZRootsIterator() :
_universe(this),
_object_synchronizer(this),
@ -145,16 +172,23 @@ ZRootsIterator::ZRootsIterator() :
ZStatTimer timer(ZSubPhasePauseRootsSetup);
Threads::change_thread_claim_parity();
COMPILER2_PRESENT(DerivedPointerTable::clear());
CodeCache::gc_prologue();
ZNMethodTable::gc_prologue();
if (ClassUnloading) {
nmethod::oops_do_marking_prologue();
} else {
ZNMethodTable::nmethod_entries_do_begin();
}
}
ZRootsIterator::~ZRootsIterator() {
ZStatTimer timer(ZSubPhasePauseRootsTeardown);
ResourceMark rm;
ZNMethodTable::gc_epilogue();
CodeCache::gc_epilogue();
if (ClassUnloading) {
nmethod::oops_do_marking_epilogue();
} else {
ZNMethodTable::nmethod_entries_do_end();
}
JvmtiExport::gc_epilogue();
COMPILER2_PRESENT(DerivedPointerTable::update_pointers());
Threads::assert_all_threads_claimed();
}
@ -209,7 +243,9 @@ void ZRootsIterator::oops_do(ZRootsIteratorClosure* cl, bool visit_jvmti_weak_ex
_jvmti_export.oops_do(cl);
_system_dictionary.oops_do(cl);
_threads.oops_do(cl);
_code_cache.oops_do(cl);
if (!ClassUnloading) {
_code_cache.oops_do(cl);
}
if (visit_jvmti_weak_export) {
_jvmti_weak_export.oops_do(cl);
}
@ -242,8 +278,13 @@ void ZConcurrentRootsIterator::do_jni_handles(ZRootsIteratorClosure* cl) {
void ZConcurrentRootsIterator::do_class_loader_data_graph(ZRootsIteratorClosure* cl) {
ZStatTimer timer(ZSubPhaseConcurrentRootsClassLoaderDataGraph);
CLDToOopClosure cld_cl(cl, _marking ? ClassLoaderData::_claim_strong : ClassLoaderData::_claim_none);
ClassLoaderDataGraph::cld_do(&cld_cl);
if (_marking) {
CLDToOopClosure cld_cl(cl, ClassLoaderData::_claim_strong);
ClassLoaderDataGraph::always_strong_cld_do(&cld_cl);
} else {
CLDToOopClosure cld_cl(cl, ClassLoaderData::_claim_none);
ClassLoaderDataGraph::cld_do(&cld_cl);
}
}
void ZConcurrentRootsIterator::oops_do(ZRootsIteratorClosure* cl) {

View File

@ -33,9 +33,7 @@
class ZRootsIteratorClosure : public OopClosure, public ThreadClosure {
public:
virtual void do_thread(Thread* thread) {
thread->oops_do(this, NULL);
}
virtual void do_thread(Thread* thread);
};
typedef OopStorage::ParState<true /* concurrent */, false /* is_const */> ZOopStorageIterator;

View File

@ -25,6 +25,7 @@
#define SHARE_GC_Z_ZTHREADLOCALDATA_HPP
#include "gc/z/zMarkStack.hpp"
#include "gc/z/zGlobals.hpp"
#include "runtime/thread.hpp"
#include "utilities/debug.hpp"
#include "utilities/sizes.hpp"
@ -62,6 +63,10 @@ public:
static ByteSize address_bad_mask_offset() {
return Thread::gc_data_offset() + byte_offset_of(ZThreadLocalData, _address_bad_mask);
}
static ByteSize nmethod_disarmed_offset() {
return address_bad_mask_offset() + in_ByteSize(ZNMethodDisarmedOffset);
}
};
#endif // SHARE_GC_Z_ZTHREADLOCALDATA_HPP

View File

@ -0,0 +1,194 @@
/*
* 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.
*/
#include "precompiled.hpp"
#include "classfile/classLoaderDataGraph.hpp"
#include "classfile/systemDictionary.hpp"
#include "code/codeBehaviours.hpp"
#include "code/codeCache.hpp"
#include "code/dependencyContext.hpp"
#include "gc/shared/gcBehaviours.hpp"
#include "gc/shared/suspendibleThreadSet.hpp"
#include "gc/z/zLock.inline.hpp"
#include "gc/z/zNMethodTable.hpp"
#include "gc/z/zOopClosures.hpp"
#include "gc/z/zStat.hpp"
#include "gc/z/zUnload.hpp"
#include "oops/access.inline.hpp"
static const ZStatSubPhase ZSubPhaseConcurrentClassesUnload("Concurrent Classes Unload");
class ZIsUnloadingOopClosure : public OopClosure {
private:
ZPhantomIsAliveObjectClosure _is_alive;
bool _is_unloading;
public:
ZIsUnloadingOopClosure() :
_is_alive(),
_is_unloading(false) {}
virtual void do_oop(oop* p) {
const oop o = RawAccess<>::oop_load(p);
if (o != NULL && !_is_alive.do_object_b(o)) {
_is_unloading = true;
}
}
virtual void do_oop(narrowOop* p) {
ShouldNotReachHere();
}
bool is_unloading() const {
return _is_unloading;
}
};
class ZIsUnloadingBehaviour : public IsUnloadingBehaviour {
private:
bool is_unloading(nmethod* nm) const {
ZIsUnloadingOopClosure cl;
nm->oops_do(&cl, true /* allow_zombie */);
return cl.is_unloading();
}
public:
virtual bool is_unloading(CompiledMethod* method) const {
nmethod* const nm = method->as_nmethod();
ZReentrantLock* const lock = ZNMethodTable::lock_for_nmethod(nm);
if (lock == NULL) {
return is_unloading(nm);
} else {
ZLocker<ZReentrantLock> locker(lock);
return is_unloading(nm);
}
}
};
class ZCompiledICProtectionBehaviour : public CompiledICProtectionBehaviour {
public:
virtual bool lock(CompiledMethod* method) {
nmethod* const nm = method->as_nmethod();
ZReentrantLock* const lock = ZNMethodTable::lock_for_nmethod(nm);
if (lock != NULL) {
lock->lock();
}
return true;
}
virtual void unlock(CompiledMethod* method) {
nmethod* const nm = method->as_nmethod();
ZReentrantLock* const lock = ZNMethodTable::lock_for_nmethod(nm);
if (lock != NULL) {
lock->unlock();
}
}
virtual bool is_safe(CompiledMethod* method) {
if (SafepointSynchronize::is_at_safepoint()) {
return true;
}
nmethod* const nm = method->as_nmethod();
ZReentrantLock* const lock = ZNMethodTable::lock_for_nmethod(nm);
return lock == NULL || lock->is_owned();
}
};
ZUnload::ZUnload(ZWorkers* workers) :
_workers(workers) {
if (!ClassUnloading) {
return;
}
static ZIsUnloadingBehaviour is_unloading_behaviour;
IsUnloadingBehaviour::set_current(&is_unloading_behaviour);
static ZCompiledICProtectionBehaviour ic_protection_behaviour;
CompiledICProtectionBehaviour::set_current(&ic_protection_behaviour);
}
void ZUnload::prepare() {
if (!ClassUnloading) {
return;
}
CodeCache::increment_unloading_cycle();
DependencyContext::cleaning_start();
}
void ZUnload::unlink() {
SuspendibleThreadSetJoiner sts;
bool unloading_occurred;
{
MutexLockerEx ml(ClassLoaderDataGraph_lock);
unloading_occurred = SystemDictionary::do_unloading(ZStatPhase::timer());
}
Klass::clean_weak_klass_links(unloading_occurred);
ZNMethodTable::unlink(_workers, unloading_occurred);
DependencyContext::cleaning_end();
}
void ZUnload::purge() {
{
SuspendibleThreadSetJoiner sts;
ZNMethodTable::purge(_workers);
}
ClassLoaderDataGraph::purge();
CodeCache::purge_exception_caches();
}
class ZUnloadRendezvousClosure : public ThreadClosure {
public:
void do_thread(Thread* thread) {}
};
void ZUnload::unload() {
if (!ClassUnloading) {
return;
}
ZStatTimer timer(ZSubPhaseConcurrentClassesUnload);
// Unlink stale metadata and nmethods
unlink();
// Make sure stale metadata and nmethods are no longer observable
ZUnloadRendezvousClosure cl;
Handshake::execute(&cl);
// Purge stale metadata and nmethods that were unlinked
purge();
}
void ZUnload::finish() {
// Resize and verify metaspace
MetaspaceGC::compute_new_size();
MetaspaceUtils::verify_metrics();
}

View File

@ -0,0 +1,44 @@
/*
* 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.
*/
#ifndef SHARE_GC_Z_ZUNLOAD_HPP
#define SHARE_GC_Z_ZUNLOAD_HPP
class ZWorkers;
class ZUnload {
private:
ZWorkers* const _workers;
void unlink();
void purge();
public:
ZUnload(ZWorkers* workers);
void prepare();
void unload();
void finish();
};
#endif // SHARE_GC_Z_ZUNLOAD_HPP

View File

@ -153,9 +153,9 @@ void InvocationCounter::reinitialize(bool delay_overflow) {
// don't need the shift by number_of_noncount_bits, but we do need to adjust
// the factor by which we scale the threshold.
if (ProfileInterpreter) {
InterpreterBackwardBranchLimit = (CompileThreshold * (OnStackReplacePercentage - InterpreterProfilePercentage)) / 100;
InterpreterBackwardBranchLimit = (int)((int64_t)CompileThreshold * (OnStackReplacePercentage - InterpreterProfilePercentage) / 100);
} else {
InterpreterBackwardBranchLimit = ((CompileThreshold * OnStackReplacePercentage) / 100) << number_of_noncount_bits;
InterpreterBackwardBranchLimit = (int)(((int64_t)CompileThreshold * OnStackReplacePercentage / 100) << number_of_noncount_bits);
}
assert(0 <= InterpreterBackwardBranchLimit,

View File

@ -40,7 +40,8 @@
<Event name="ThreadPark" category="Java Application" label="Java Thread Park" thread="true" stackTrace="true">
<Field type="Class" name="parkedClass" label="Class Parked On" />
<Field type="long" contentType="millis" name="timeout" label="Park Timeout" />
<Field type="long" contentType="nanos" name="timeout" label="Park Timeout" />
<Field type="long" contentType="epochmillis" name="until" label="Park Until" />
<Field type="ulong" contentType="address" name="address" label="Address of Object Parked" relation="JavaMonitorAddress" />
</Event>
@ -1140,5 +1141,6 @@
<XmlContentType name="address" annotationType="jdk.jfr.MemoryAddress" />
<XmlContentType name="percentage" annotationType="jdk.jfr.Percentage" />
<XmlContentType name="millis" annotationType="jdk.jfr.Timespan" annotationValue="MILLISECONDS" />
<XmlContentType name="nanos" annotationType="jdk.jfr.Timespan" annotationValue="NANOSECONDS" />
</Metadata>

View File

@ -103,9 +103,9 @@ class MethodCounters : public Metadata {
// If interpreter profiling is enabled, the backward branch limit
// is compared against the method data counter rather than an invocation
// counter, therefore no shifting of bits is required.
_interpreter_backward_branch_limit = (compile_threshold * (OnStackReplacePercentage - InterpreterProfilePercentage)) / 100;
_interpreter_backward_branch_limit = (int)((int64_t)compile_threshold * (OnStackReplacePercentage - InterpreterProfilePercentage) / 100);
} else {
_interpreter_backward_branch_limit = ((compile_threshold * OnStackReplacePercentage) / 100) << InvocationCounter::count_shift;
_interpreter_backward_branch_limit = (int)(((int64_t)compile_threshold * OnStackReplacePercentage / 100) << InvocationCounter::count_shift);
}
_interpreter_profile_limit = ((compile_threshold * InterpreterProfilePercentage) / 100) << InvocationCounter::count_shift;
_invoke_mask = right_n_bits(CompilerConfig::scaled_freq_log(Tier0InvokeNotifyFreqLog, scale)) << InvocationCounter::count_shift;

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2000, 2016, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2000, 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
@ -710,6 +710,9 @@
diagnostic(bool, UseMathExactIntrinsics, true, \
"Enables intrinsification of various java.lang.Math functions") \
\
diagnostic(bool, UseCharacterCompareIntrinsics, false, \
"Enables intrinsification of java.lang.Character functions") \
\
diagnostic(bool, UseMultiplyToLenIntrinsic, false, \
"Enables intrinsification of BigInteger.multiplyToLen()") \
\

View File

@ -428,6 +428,18 @@ bool C2Compiler::is_intrinsic_supported(const methodHandle& method, bool is_virt
case vmIntrinsics::_fmaF:
if (!UseFMA || !Matcher::match_rule_supported(Op_FmaF)) return false;
break;
case vmIntrinsics::_isDigit:
if (!Matcher::match_rule_supported(Op_Digit)) return false;
break;
case vmIntrinsics::_isLowerCase:
if (!Matcher::match_rule_supported(Op_LowerCase)) return false;
break;
case vmIntrinsics::_isUpperCase:
if (!Matcher::match_rule_supported(Op_UpperCase)) return false;
break;
case vmIntrinsics::_isWhitespace:
if (!Matcher::match_rule_supported(Op_Whitespace)) return false;
break;
case vmIntrinsics::_hashCode:
case vmIntrinsics::_identityHashCode:
case vmIntrinsics::_getClass:

View File

@ -201,6 +201,7 @@ macro(Loop)
macro(LoopLimit)
macro(Mach)
macro(MachProj)
macro(MulAddS2I)
macro(MaxI)
macro(MemBarAcquire)
macro(LoadFence)
@ -341,6 +342,7 @@ macro(MulVF)
macro(MulReductionVF)
macro(MulVD)
macro(MulReductionVD)
macro(MulAddVS2VI)
macro(FmaVD)
macro(FmaVF)
macro(DivVF)
@ -394,3 +396,7 @@ macro(ExtractI)
macro(ExtractL)
macro(ExtractF)
macro(ExtractD)
macro(Digit)
macro(LowerCase)
macro(UpperCase)
macro(Whitespace)

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2015, 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
@ -180,4 +180,40 @@ class EncodeISOArrayNode: public Node {
virtual const Type* Value(PhaseGVN* phase) const;
};
//-------------------------------DigitNode----------------------------------------
class DigitNode : public Node {
public:
DigitNode(Node* control, Node *in1) : Node(control, in1) {}
virtual int Opcode() const;
const Type* bottom_type() const { return TypeInt::BOOL; }
virtual uint ideal_reg() const { return Op_RegI; }
};
//------------------------------LowerCaseNode------------------------------------
class LowerCaseNode : public Node {
public:
LowerCaseNode(Node* control, Node *in1) : Node(control, in1) {}
virtual int Opcode() const;
const Type* bottom_type() const { return TypeInt::BOOL; }
virtual uint ideal_reg() const { return Op_RegI; }
};
//------------------------------UpperCaseNode------------------------------------
class UpperCaseNode : public Node {
public:
UpperCaseNode(Node* control, Node *in1) : Node(control, in1) {}
virtual int Opcode() const;
const Type* bottom_type() const { return TypeInt::BOOL; }
virtual uint ideal_reg() const { return Op_RegI; }
};
//------------------------------WhitespaceCode-----------------------------------
class WhitespaceNode : public Node {
public:
WhitespaceNode(Node* control, Node *in1) : Node(control, in1) {}
virtual int Opcode() const;
const Type* bottom_type() const { return TypeInt::BOOL; }
virtual uint ideal_reg() const { return Op_RegI; }
};
#endif // SHARE_VM_OPTO_INTRINSICNODE_HPP

View File

@ -324,6 +324,7 @@ class LibraryCallKit : public GraphKit {
bool inline_montgomerySquare();
bool inline_vectorizedMismatch();
bool inline_fma(vmIntrinsics::ID id);
bool inline_character_compare(vmIntrinsics::ID id);
bool inline_profileBoolean();
bool inline_isCompileConstant();
@ -867,6 +868,12 @@ bool LibraryCallKit::try_to_inline(int predicate) {
case vmIntrinsics::_fmaF:
return inline_fma(intrinsic_id());
case vmIntrinsics::_isDigit:
case vmIntrinsics::_isLowerCase:
case vmIntrinsics::_isUpperCase:
case vmIntrinsics::_isWhitespace:
return inline_character_compare(intrinsic_id());
default:
// If you get here, it may be that someone has added a new intrinsic
// to the list in vmSymbols.hpp without implementing it here.
@ -6555,6 +6562,32 @@ bool LibraryCallKit::inline_fma(vmIntrinsics::ID id) {
return true;
}
bool LibraryCallKit::inline_character_compare(vmIntrinsics::ID id) {
// argument(0) is receiver
Node* codePoint = argument(1);
Node* n = NULL;
switch (id) {
case vmIntrinsics::_isDigit :
n = new DigitNode(control(), codePoint);
break;
case vmIntrinsics::_isLowerCase :
n = new LowerCaseNode(control(), codePoint);
break;
case vmIntrinsics::_isUpperCase :
n = new UpperCaseNode(control(), codePoint);
break;
case vmIntrinsics::_isWhitespace :
n = new WhitespaceNode(control(), codePoint);
break;
default:
fatal_unexpected_iid(id);
}
set_result(_gvn.transform(n));
return true;
}
bool LibraryCallKit::inline_profileBoolean() {
Node* counts = argument(1);
const TypeAryPtr* ary = NULL;

View File

@ -1249,6 +1249,9 @@ public:
// important (common) to do address expressions.
Node *remix_address_expressions( Node *n );
// Convert add to muladd to generate MuladdS2I under certain criteria
Node * convert_add_to_muladd(Node * n);
// Attempt to use a conditional move instead of a phi/branch
Node *conditional_move( Node *n );

View File

@ -493,6 +493,54 @@ Node *PhaseIdealLoop::remix_address_expressions( Node *n ) {
return NULL;
}
// Optimize ((in1[2*i] * in2[2*i]) + (in1[2*i+1] * in2[2*i+1]))
Node *PhaseIdealLoop::convert_add_to_muladd(Node* n) {
assert(n->Opcode() == Op_AddI, "sanity");
Node * nn = NULL;
Node * in1 = n->in(1);
Node * in2 = n->in(2);
if (in1->Opcode() == Op_MulI && in2->Opcode() == Op_MulI) {
IdealLoopTree* loop_n = get_loop(get_ctrl(n));
if (loop_n->_head->as_Loop()->is_valid_counted_loop() &&
Matcher::match_rule_supported(Op_MulAddS2I) &&
Matcher::match_rule_supported(Op_MulAddVS2VI)) {
Node* mul_in1 = in1->in(1);
Node* mul_in2 = in1->in(2);
Node* mul_in3 = in2->in(1);
Node* mul_in4 = in2->in(2);
if (mul_in1->Opcode() == Op_LoadS &&
mul_in2->Opcode() == Op_LoadS &&
mul_in3->Opcode() == Op_LoadS &&
mul_in4->Opcode() == Op_LoadS) {
IdealLoopTree* loop1 = get_loop(get_ctrl(mul_in1));
IdealLoopTree* loop2 = get_loop(get_ctrl(mul_in2));
IdealLoopTree* loop3 = get_loop(get_ctrl(mul_in3));
IdealLoopTree* loop4 = get_loop(get_ctrl(mul_in4));
IdealLoopTree* loop5 = get_loop(get_ctrl(in1));
IdealLoopTree* loop6 = get_loop(get_ctrl(in2));
// All nodes should be in the same counted loop.
if (loop_n == loop1 && loop_n == loop2 && loop_n == loop3 &&
loop_n == loop4 && loop_n == loop5 && loop_n == loop6) {
Node* adr1 = mul_in1->in(MemNode::Address);
Node* adr2 = mul_in2->in(MemNode::Address);
Node* adr3 = mul_in3->in(MemNode::Address);
Node* adr4 = mul_in4->in(MemNode::Address);
if (adr1->is_AddP() && adr2->is_AddP() && adr3->is_AddP() && adr4->is_AddP()) {
if ((adr1->in(AddPNode::Base) == adr3->in(AddPNode::Base)) &&
(adr2->in(AddPNode::Base) == adr4->in(AddPNode::Base))) {
nn = new MulAddS2INode(mul_in1, mul_in2, mul_in3, mul_in4);
register_new_node(nn, get_ctrl(n));
_igvn.replace_node(n, nn);
return nn;
}
}
}
}
}
}
return nn;
}
//------------------------------conditional_move-------------------------------
// Attempt to replace a Phi with a conditional move. We have some pretty
// strict profitability requirements. All Phis at the merge point must
@ -927,6 +975,11 @@ Node *PhaseIdealLoop::split_if_with_blocks_pre( Node *n ) {
Node *m = remix_address_expressions( n );
if( m ) return m;
if (n_op == Op_AddI) {
Node *nn = convert_add_to_muladd( n );
if ( nn ) return nn;
}
if (n->is_ConstraintCast()) {
Node* dom_cast = n->as_ConstraintCast()->dominating_cast(&_igvn, this);
// ConstraintCastNode::dominating_cast() uses node control input to determine domination.

View File

@ -2352,6 +2352,15 @@ void Matcher::find_shared_post_visit(Node* n, uint opcode) {
n->del_req(3);
break;
}
case Op_MulAddS2I: {
Node* pair1 = new BinaryNode(n->in(1), n->in(2));
Node* pair2 = new BinaryNode(n->in(3), n->in(4));
n->set_req(1, pair1);
n->set_req(2, pair2);
n->del_req(4);
n->del_req(3);
break;
}
default:
break;
}

View File

@ -285,4 +285,15 @@ public:
virtual const Type* Value(PhaseGVN* phase) const;
};
//------------------------------MulAddS2INode----------------------------------
// Multiply shorts into integers and add them.
// Semantics: I_OUT = S1 * S2 + S3 * S4
class MulAddS2INode : public Node {
public:
MulAddS2INode(Node* in1, Node *in2, Node *in3, Node* in4) : Node(0, in1, in2, in3, in4) {}
virtual int Opcode() const;
const Type *bottom_type() const { return TypeInt::INT; }
virtual uint ideal_reg() const { return Op_RegI; }
};
#endif // SHARE_VM_OPTO_MULNODE_HPP

View File

@ -471,15 +471,15 @@ void Parse::profile_taken_branch(int target_bci, bool force_update) {
if (osr_site) {
ciProfileData* data = md->bci_to_data(cur_bci);
assert(data != NULL && data->is_JumpData(), "need JumpData for taken branch");
int limit = (CompileThreshold
* (OnStackReplacePercentage - InterpreterProfilePercentage)) / 100;
int limit = (int)((int64_t)CompileThreshold
* (OnStackReplacePercentage - InterpreterProfilePercentage) / 100);
test_for_osr_md_counter_at(md, data, JumpData::taken_offset(), limit);
}
} else {
// With method data update off, use the invocation counter to trigger an
// OSR compilation, as done in the interpreter.
if (osr_site) {
int limit = (CompileThreshold * OnStackReplacePercentage) / 100;
int limit = (int)((int64_t)CompileThreshold * OnStackReplacePercentage / 100);
increment_and_test_invocation_counter(limit);
}
}

View File

@ -645,6 +645,10 @@ void SuperWord::find_adjacent_refs() {
// with a different alignment were created before.
for (uint i = 0; i < align_to_refs.size(); i++) {
MemNode* mr = align_to_refs.at(i)->as_Mem();
if (mr == mem_ref) {
// Skip when we are looking at same memory operation.
continue;
}
if (same_velt_type(mr, mem_ref) &&
memory_alignment(mr, iv_adjustment) != 0)
create_pack = false;
@ -846,6 +850,27 @@ MemNode* SuperWord::find_align_to_ref(Node_List &memops) {
return NULL;
}
//------------------span_works_for_memory_size-----------------------------
static bool span_works_for_memory_size(MemNode* mem, int span, int mem_size, int offset) {
bool span_matches_memory = false;
if ((mem_size == type2aelembytes(T_BYTE) || mem_size == type2aelembytes(T_SHORT))
&& ABS(span) == type2aelembytes(T_INT)) {
// There is a mismatch on span size compared to memory.
for (DUIterator_Fast jmax, j = mem->fast_outs(jmax); j < jmax; j++) {
Node* use = mem->fast_out(j);
if (!VectorNode::is_type_transition_to_int(use)) {
return false;
}
}
// If all uses transition to integer, it means that we can successfully align even on mismatch.
return true;
}
else {
span_matches_memory = ABS(span) == mem_size;
}
return span_matches_memory && (ABS(offset) % mem_size) == 0;
}
//------------------------------ref_is_alignable---------------------------
// Can the preloop align the reference to position zero in the vector?
bool SuperWord::ref_is_alignable(SWPointer& p) {
@ -862,7 +887,7 @@ bool SuperWord::ref_is_alignable(SWPointer& p) {
int offset = p.offset_in_bytes();
// Stride one accesses are alignable if offset is aligned to memory operation size.
// Offset can be unaligned when UseUnalignedAccesses is used.
if (ABS(span) == mem_size && (ABS(offset) % mem_size) == 0) {
if (span_works_for_memory_size(p.mem(), span, mem_size, offset)) {
return true;
}
// If the initial offset from start of the object is computable,
@ -915,6 +940,28 @@ bool SuperWord::ref_is_alignable(SWPointer& p) {
}
return false;
}
//---------------------------get_vw_bytes_special------------------------
int SuperWord::get_vw_bytes_special(MemNode* s) {
// Get the vector width in bytes.
int vw = vector_width_in_bytes(s);
// Check for special case where there is an MulAddS2I usage where short vectors are going to need combined.
BasicType btype = velt_basic_type(s);
if (type2aelembytes(btype) == 2) {
bool should_combine_adjacent = true;
for (DUIterator_Fast imax, i = s->fast_outs(imax); i < imax; i++) {
Node* user = s->fast_out(i);
if (!VectorNode::is_muladds2i(user)) {
should_combine_adjacent = false;
}
}
if (should_combine_adjacent) {
vw = MIN2(Matcher::max_vector_size(btype)*type2aelembytes(btype), vw * 2);
}
}
return vw;
}
//---------------------------get_iv_adjustment---------------------------
// Calculate loop's iv adjustment for this memory ops.
@ -923,7 +970,7 @@ int SuperWord::get_iv_adjustment(MemNode* mem_ref) {
int offset = align_to_ref_p.offset_in_bytes();
int scale = align_to_ref_p.scale_in_bytes();
int elt_size = align_to_ref_p.memory_size();
int vw = vector_width_in_bytes(mem_ref);
int vw = get_vw_bytes_special(mem_ref);
assert(vw > 1, "sanity");
int iv_adjustment;
if (scale != 0) {
@ -2303,6 +2350,12 @@ void SuperWord::output() {
const TypePtr* atyp = n->adr_type();
vn = StoreVectorNode::make(opc, ctl, mem, adr, atyp, val, vlen);
vlen_in_bytes = vn->as_StoreVector()->memory_size();
} else if (VectorNode::is_muladds2i(n)) {
assert(n->req() == 5u, "MulAddS2I should have 4 operands.");
Node* in1 = vector_opd(p, 1);
Node* in2 = vector_opd(p, 2);
vn = VectorNode::make(opc, in1, in2, vlen, velt_basic_type(n));
vlen_in_bytes = vn->as_Vector()->length_in_bytes();
} else if (n->req() == 3 && !is_cmov_pack(p)) {
// Promote operands to vector
Node* in1 = NULL;
@ -2615,6 +2668,16 @@ Node* SuperWord::vector_opd(Node_List* p, int opd_idx) {
}
assert(opd_bt == in->bottom_type()->basic_type(), "all same type");
pk->add_opd(in);
if (VectorNode::is_muladds2i(pi)) {
Node* in2 = pi->in(opd_idx + 2);
assert(my_pack(in2) == NULL, "Should already have been unpacked");
if (my_pack(in2) != NULL) {
NOT_PRODUCT(if (is_trace_loop_reverse() || TraceLoopOpts) { tty->print_cr("Should already have been unpacked"); })
return NULL;
}
assert(opd_bt == in2->bottom_type()->basic_type(), "all same type");
pk->add_opd(in2);
}
}
_igvn.register_new_node_with_optimizer(pk);
_phase->set_ctrl(pk, _phase->get_ctrl(opd));
@ -2692,6 +2755,21 @@ bool SuperWord::is_vector_use(Node* use, int u_idx) {
}
return true;
}
if (VectorNode::is_muladds2i(use)) {
// MulAddS2I takes shorts and produces ints - hence the special checks
// on alignment and size.
if (u_pk->size() * 2 != d_pk->size()) {
return false;
}
for (uint i = 0; i < MIN2(d_pk->size(), u_pk->size()); i++) {
Node* ui = u_pk->at(i);
Node* di = d_pk->at(i);
if (alignment(ui) != alignment(di) * 2) {
return false;
}
}
return true;
}
if (u_pk->size() != d_pk->size())
return false;
for (uint i = 0; i < u_pk->size(); i++) {
@ -3017,7 +3095,7 @@ int SuperWord::memory_alignment(MemNode* s, int iv_adjust) {
NOT_PRODUCT(if(is_trace_alignment()) tty->print("SWPointer::memory_alignment: SWPointer p invalid, return bottom_align");)
return bottom_align;
}
int vw = vector_width_in_bytes(s);
int vw = get_vw_bytes_special(s);
if (vw < 2) {
NOT_PRODUCT(if(is_trace_alignment()) tty->print_cr("SWPointer::memory_alignment: vector_width_in_bytes < 2, return bottom_align");)
return bottom_align; // No vectors for this type

View File

@ -347,6 +347,7 @@ class SuperWord : public ResourceObj {
BasicType bt = velt_basic_type(n);
return vector_width(n)*type2aelembytes(bt);
}
int get_vw_bytes_special(MemNode* s);
MemNode* align_to_ref() { return _align_to_ref; }
void set_align_to_ref(MemNode* m) { _align_to_ref = m; }

View File

@ -196,6 +196,8 @@ int VectorNode::opcode(int sopc, BasicType bt) {
case Op_StoreF:
case Op_StoreD:
return Op_StoreVector;
case Op_MulAddS2I:
return Op_MulAddVS2VI;
default:
return 0; // Unimplemented
@ -214,6 +216,25 @@ bool VectorNode::implemented(int opc, uint vlen, BasicType bt) {
return false;
}
bool VectorNode::is_type_transition_short_to_int(Node* n) {
switch (n->Opcode()) {
case Op_MulAddS2I:
return true;
}
return false;
}
bool VectorNode::is_type_transition_to_int(Node* n) {
return is_type_transition_short_to_int(n);
}
bool VectorNode::is_muladds2i(Node* n) {
if (n->Opcode() == Op_MulAddS2I) {
return true;
}
return false;
}
bool VectorNode::is_shift(Node* n) {
switch (n->Opcode()) {
case Op_LShiftI:
@ -277,6 +298,7 @@ void VectorNode::vector_operands(Node* n, uint* start, uint* end) {
case Op_AndI: case Op_AndL:
case Op_OrI: case Op_OrL:
case Op_XorI: case Op_XorL:
case Op_MulAddS2I:
*start = 1;
*end = 3; // 2 vector operands
break;
@ -354,6 +376,8 @@ VectorNode* VectorNode::make(int opc, Node* n1, Node* n2, uint vlen, BasicType b
case Op_AndV: return new AndVNode(n1, n2, vt);
case Op_OrV: return new OrVNode (n1, n2, vt);
case Op_XorV: return new XorVNode(n1, n2, vt);
case Op_MulAddVS2VI: return new MulAddVS2VINode(n1, n2, vt);
default:
fatal("Missed vector creation for '%s'", NodeClassNames[vopc]);
return NULL;

View File

@ -67,6 +67,9 @@ class VectorNode : public TypeNode {
static int opcode(int opc, BasicType bt);
static bool implemented(int opc, uint vlen, BasicType bt);
static bool is_shift(Node* n);
static bool is_type_transition_short_to_int(Node* n);
static bool is_type_transition_to_int(Node* n);
static bool is_muladds2i(Node* n);
static bool is_invariant_vector(Node* n);
// [Start, end) half-open range defining which operands are vectors
static void vector_operands(Node* n, uint* start, uint* end);
@ -261,6 +264,14 @@ public:
virtual int Opcode() const;
};
//------------------------------MulAddVS2VINode--------------------------------
// Vector multiply shorts to int and add adjacent ints.
class MulAddVS2VINode : public VectorNode {
public:
MulAddVS2VINode(Node* in1, Node* in2, const TypeVect* vt) : VectorNode(in1, in2, vt) {}
virtual int Opcode() const;
};
//------------------------------FmaVDNode--------------------------------------
// Vector multiply double
class FmaVDNode : public VectorNode {

View File

@ -926,11 +926,12 @@ UNSAFE_ENTRY(jboolean, Unsafe_CompareAndSetLong(JNIEnv *env, jobject unsafe, job
}
} UNSAFE_END
static void post_thread_park_event(EventThreadPark* event, const oop obj, jlong timeout) {
static void post_thread_park_event(EventThreadPark* event, const oop obj, jlong timeout_nanos, jlong until_epoch_millis) {
assert(event != NULL, "invariant");
assert(event->should_commit(), "invariant");
event->set_parkedClass((obj != NULL) ? obj->klass() : NULL);
event->set_timeout(timeout);
event->set_timeout(timeout_nanos);
event->set_until(until_epoch_millis);
event->set_address((obj != NULL) ? (u8)cast_from_oop<uintptr_t>(obj) : 0);
event->commit();
}
@ -942,7 +943,16 @@ UNSAFE_ENTRY(void, Unsafe_Park(JNIEnv *env, jobject unsafe, jboolean isAbsolute,
JavaThreadParkedState jtps(thread, time != 0);
thread->parker()->park(isAbsolute != 0, time);
if (event.should_commit()) {
post_thread_park_event(&event, thread->current_park_blocker(), time);
const oop obj = thread->current_park_blocker();
if (time == 0) {
post_thread_park_event(&event, obj, min_jlong, min_jlong);
} else {
if (isAbsolute != 0) {
post_thread_park_event(&event, obj, min_jlong, time);
} else {
post_thread_park_event(&event, obj, time, min_jlong);
}
}
}
HOTSPOT_THREAD_PARK_END((uintptr_t) thread->parker());
} UNSAFE_END

Some files were not shown because too many files have changed in this diff Show More