# HG changeset patch # User mgronlun # Date 1571217826 -7200 # Node ID 38176d1c5ec26136c8ae156b232d0b8aaa13eb59 # Parent 496bbf554c5cd5d4a2cb2582b2ca8b493d9cde8d# Parent 55fe0d93bdd39463196651b79c69f2d333e35046 Merge diff -r 496bbf554c5c -r 38176d1c5ec2 .hgtags --- a/.hgtags Wed Oct 16 01:16:12 2019 +0200 +++ b/.hgtags Wed Oct 16 11:23:46 2019 +0200 @@ -590,3 +590,4 @@ 778fc2dcbdaa8981e07e929a2cacef979c72261e jdk-14+15 d29f0181ba424a95d881aba5eabf2e393abcc70f jdk-14+16 5c83830390baafb76a1fbe33443c57620bd45fb9 jdk-14+17 +e84d8379815ba0d3e50fb096d28c25894cb50b8c jdk-14+18 diff -r 496bbf554c5c -r 38176d1c5ec2 doc/building.html --- a/doc/building.html Wed Oct 16 01:16:12 2019 +0200 +++ b/doc/building.html Wed Oct 16 11:23:46 2019 +0200 @@ -281,7 +281,7 @@ Linux -gcc 8.2.0 +gcc 8.3.0 macOS @@ -293,14 +293,14 @@ Windows -Microsoft Visual Studio 2017 update 15.9.6 +Microsoft Visual Studio 2017 update 15.9.16

All compilers are expected to be able to compile to the C99 language standard, as some C99 features are used in the source code. Microsoft Visual Studio doesn't fully support C99 so in practice shared code is limited to using C99 features that it does support.

gcc

The minimum accepted version of gcc is 4.8. Older versions will generate a warning by configure and are unlikely to work.

-

The JDK is currently known to be able to compile with at least version 7.4 of gcc.

+

The JDK is currently known to be able to compile with at least version 8.3 of gcc.

In general, any version between these two should be usable.

clang

The minimum accepted version of clang is 3.2. Older versions will not be accepted by configure.

diff -r 496bbf554c5c -r 38176d1c5ec2 doc/building.md --- a/doc/building.md Wed Oct 16 01:16:12 2019 +0200 +++ b/doc/building.md Wed Oct 16 11:23:46 2019 +0200 @@ -323,10 +323,10 @@ Operating system Toolchain version ------------------ ------------------------------------------------------- - Linux gcc 8.2.0 + Linux gcc 8.3.0 macOS Apple Xcode 10.1 (using clang 10.0.0) Solaris Oracle Solaris Studio 12.6 (with compiler version 5.15) - Windows Microsoft Visual Studio 2017 update 15.9.6 + Windows Microsoft Visual Studio 2017 update 15.9.16 All compilers are expected to be able to compile to the C99 language standard, as some C99 features are used in the source code. Microsoft Visual Studio @@ -338,7 +338,7 @@ The minimum accepted version of gcc is 4.8. Older versions will generate a warning by `configure` and are unlikely to work. -The JDK is currently known to be able to compile with at least version 7.4 of +The JDK is currently known to be able to compile with at least version 8.3 of gcc. In general, any version between these two should be usable. diff -r 496bbf554c5c -r 38176d1c5ec2 make/RunTestsPrebuilt.gmk --- a/make/RunTestsPrebuilt.gmk Wed Oct 16 01:16:12 2019 +0200 +++ b/make/RunTestsPrebuilt.gmk Wed Oct 16 11:23:46 2019 +0200 @@ -230,7 +230,7 @@ NUM_CORES := $(shell /usr/sbin/sysctl -n hw.ncpu) MEMORY_SIZE := $(shell $(EXPR) `/usr/sbin/sysctl -n hw.memsize` / 1024 / 1024) else ifeq ($(OPENJDK_TARGET_OS), solaris) - NUM_CORES := $(shell LC_MESSAGES=C /usr/sbin/psrinfo -v | $(GREP) -c on-line) + NUM_CORES := $(shell /usr/sbin/psrinfo -v | $(GREP) -c on-line) MEMORY_SIZE := $(shell \ /usr/sbin/prtconf 2> /dev/null | $(GREP) "^Memory [Ss]ize" | $(AWK) '{print $$3}' \ ) diff -r 496bbf554c5c -r 38176d1c5ec2 make/RunTestsPrebuiltSpec.gmk --- a/make/RunTestsPrebuiltSpec.gmk Wed Oct 16 01:16:12 2019 +0200 +++ b/make/RunTestsPrebuiltSpec.gmk Wed Oct 16 11:23:46 2019 +0200 @@ -27,6 +27,9 @@ # Fake minimalistic spec file for RunTestsPrebuilt.gmk. ################################################################################ +# Make sure all shell commands are executed with the C locale +export LC_ALL := C + define VerifyVariable ifeq ($$($1), ) $$(info Error: Variable $1 is missing, needed by RunTestPrebuiltSpec.gmk) diff -r 496bbf554c5c -r 38176d1c5ec2 make/autoconf/basics.m4 --- a/make/autoconf/basics.m4 Wed Oct 16 01:16:12 2019 +0200 +++ b/make/autoconf/basics.m4 Wed Oct 16 11:23:46 2019 +0200 @@ -427,7 +427,7 @@ # Save the path variable before it gets changed ORIGINAL_PATH="$PATH" AC_SUBST(ORIGINAL_PATH) - DATE_WHEN_CONFIGURED=`LANG=C date` + DATE_WHEN_CONFIGURED=`date` AC_SUBST(DATE_WHEN_CONFIGURED) AC_MSG_NOTICE([Configuration created at $DATE_WHEN_CONFIGURED.]) ]) diff -r 496bbf554c5c -r 38176d1c5ec2 make/autoconf/build-performance.m4 --- a/make/autoconf/build-performance.m4 Wed Oct 16 01:16:12 2019 +0200 +++ b/make/autoconf/build-performance.m4 Wed Oct 16 11:23:46 2019 +0200 @@ -35,7 +35,7 @@ FOUND_CORES=yes elif test -x /usr/sbin/psrinfo; then # Looks like a Solaris system - NUM_CORES=`LC_MESSAGES=C /usr/sbin/psrinfo -v | grep -c on-line` + NUM_CORES=`/usr/sbin/psrinfo -v | grep -c on-line` FOUND_CORES=yes elif test -x /usr/sbin/sysctl; then # Looks like a MacOSX system diff -r 496bbf554c5c -r 38176d1c5ec2 make/autoconf/configure --- a/make/autoconf/configure Wed Oct 16 01:16:12 2019 +0200 +++ b/make/autoconf/configure Wed Oct 16 11:23:46 2019 +0200 @@ -43,6 +43,9 @@ export CONFIG_SHELL=$BASH export _as_can_reexec=no +# Make sure all shell commands are executed with the C locale +export LC_ALL=C + if test "x$CUSTOM_CONFIG_DIR" != x; then custom_hook=$CUSTOM_CONFIG_DIR/custom-hook.m4 if test ! -e $custom_hook; then diff -r 496bbf554c5c -r 38176d1c5ec2 make/autoconf/spec.gmk.in --- a/make/autoconf/spec.gmk.in Wed Oct 16 01:16:12 2019 +0200 +++ b/make/autoconf/spec.gmk.in Wed Oct 16 11:23:46 2019 +0200 @@ -51,6 +51,9 @@ # What make to use for main processing, after bootstrapping top-level Makefile. MAKE := @MAKE@ +# Make sure all shell commands are executed with the C locale +export LC_ALL := C + # The default make arguments MAKE_ARGS = $(MAKE_LOG_FLAGS) -r -R -I $(TOPDIR)/make/common SPEC=$(SPEC) \ MAKE_LOG_FLAGS="$(MAKE_LOG_FLAGS)" $(MAKE_LOG_VARS) diff -r 496bbf554c5c -r 38176d1c5ec2 make/autoconf/toolchain_windows.m4 --- a/make/autoconf/toolchain_windows.m4 Wed Oct 16 01:16:12 2019 +0200 +++ b/make/autoconf/toolchain_windows.m4 Wed Oct 16 11:23:46 2019 +0200 @@ -209,6 +209,8 @@ eval SDK_INSTALL_DIR="\${VS_SDK_INSTALLDIR_${VS_VERSION}}" eval VS_ENV_ARGS="\${VS_ENV_ARGS_${VS_VERSION}}" eval VS_TOOLSET_SUPPORTED="\${VS_TOOLSET_SUPPORTED_${VS_VERSION}}" + + VS_ENV_CMD="" # When using --with-tools-dir, assume it points to the correct and default # version of Visual Studio or that --with-toolchain-version was also set. @@ -227,8 +229,6 @@ fi fi - VS_ENV_CMD="" - if test "x$VS_COMNTOOLS" != x; then TOOLCHAIN_CHECK_POSSIBLE_VISUAL_STUDIO_ROOT([${VS_VERSION}], [$VS_COMNTOOLS/../..], [$VS_COMNTOOLS_VAR variable]) diff -r 496bbf554c5c -r 38176d1c5ec2 make/common/JavaCompilation.gmk --- a/make/common/JavaCompilation.gmk Wed Oct 16 01:16:12 2019 +0200 +++ b/make/common/JavaCompilation.gmk Wed Oct 16 11:23:46 2019 +0200 @@ -122,7 +122,7 @@ $$($1_BIN)$$($1_MODULE_SUBDIR)$$($2_TARGET) : $2 $$(call LogInfo, Cleaning $$(patsubst $(OUTPUTDIR)/%,%, $$@)) $$(call MakeTargetDir) - export LC_ALL=C ; ( $(CAT) $$< && $(ECHO) "" ) \ + ( $(CAT) $$< && $(ECHO) "" ) \ | $(SED) -e 's/\([^\\]\):/\1\\:/g' -e 's/\([^\\]\)=/\1\\=/g' \ -e 's/\([^\\]\)!/\1\\!/g' -e 's/^[ ]*#.*/#/g' \ | $(SED) -f "$(TOPDIR)/make/common/support/unicode2x.sed" \ diff -r 496bbf554c5c -r 38176d1c5ec2 make/conf/jib-profiles.js --- a/make/conf/jib-profiles.js Wed Oct 16 01:16:12 2019 +0200 +++ b/make/conf/jib-profiles.js Wed Oct 16 11:23:46 2019 +0200 @@ -944,11 +944,11 @@ var getJibProfilesDependencies = function (input, common) { var devkit_platform_revisions = { - linux_x64: "gcc8.2.0-OL6.4+1.0", + linux_x64: "gcc8.3.0-OL6.4+1.0", macosx_x64: "Xcode10.1-MacOSX10.14+1.0", solaris_x64: "SS12u4-Solaris11u1+1.0", solaris_sparcv9: "SS12u6-Solaris11u3+1.0", - windows_x64: "VS2017-15.9.6+1.0", + windows_x64: "VS2017-15.9.16+1.0", linux_aarch64: "gcc8.2.0-Fedora27+1.0", linux_arm: "gcc8.2.0-Fedora27+1.0", linux_ppc64le: "gcc8.2.0-Fedora27+1.0", diff -r 496bbf554c5c -r 38176d1c5ec2 make/data/charsetmapping/SingleByte-X.java.template --- a/make/data/charsetmapping/SingleByte-X.java.template Wed Oct 16 01:16:12 2019 +0200 +++ b/make/data/charsetmapping/SingleByte-X.java.template Wed Oct 16 11:23:46 2019 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2008, 2019, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -48,7 +48,7 @@ } public CharsetDecoder newDecoder() { - return new SingleByte.Decoder(this, b2c, $ASCIICOMPATIBLE$); + return new SingleByte.Decoder(this, b2c, $ASCIICOMPATIBLE$, $LATIN1DECODABLE$); } public CharsetEncoder newEncoder() { diff -r 496bbf554c5c -r 38176d1c5ec2 make/data/lsrdata/language-subtag-registry.txt --- a/make/data/lsrdata/language-subtag-registry.txt Wed Oct 16 01:16:12 2019 +0200 +++ b/make/data/lsrdata/language-subtag-registry.txt Wed Oct 16 11:23:46 2019 +0200 @@ -1,4 +1,4 @@ -File-Date: 2019-04-03 +File-Date: 2019-09-16 %% Type: language Subtag: aa @@ -2096,6 +2096,8 @@ Subtag: ais Description: Nataoran Amis Added: 2009-07-29 +Deprecated: 2019-04-16 +Comments: see ami, szy %% Type: language Subtag: ait @@ -2633,6 +2635,7 @@ Type: language Subtag: ant Description: Antakarinya +Description: Antikarinya Added: 2009-07-29 %% Type: language @@ -3094,6 +3097,8 @@ Subtag: asd Description: Asas Added: 2009-07-29 +Deprecated: 2019-04-16 +Preferred-Value: snz %% Type: language Subtag: ase @@ -4135,7 +4140,7 @@ %% Type: language Subtag: bck -Description: Bunaba +Description: Bunuba Added: 2009-07-29 %% Type: language @@ -6930,7 +6935,7 @@ %% Type: language Subtag: bym -Description: Bidyara +Description: Bidjara Added: 2009-07-29 %% Type: language @@ -7564,6 +7569,11 @@ Added: 2009-07-29 %% Type: language +Subtag: cey +Description: Ekai Chin +Added: 2019-04-16 +%% +Type: language Subtag: cfa Description: Dijim-Bwilim Added: 2009-07-29 @@ -9439,6 +9449,7 @@ Type: language Subtag: dif Description: Dieri +Description: Diyari Added: 2009-07-29 %% Type: language @@ -9515,6 +9526,8 @@ Subtag: dit Description: Dirari Added: 2009-07-29 +Deprecated: 2019-04-29 +Preferred-Value: dif %% Type: language Subtag: diu @@ -9560,6 +9573,7 @@ Type: language Subtag: djd Description: Djamindjung +Description: Ngaliwurru Added: 2009-07-29 %% Type: language @@ -9603,6 +9617,7 @@ %% Type: language Subtag: djn +Description: Jawoyn Description: Djauan Added: 2009-07-29 %% @@ -10191,6 +10206,8 @@ Subtag: dud Description: Hun-Saare Added: 2009-07-29 +Deprecated: 2019-04-16 +Comments: see uth, uss %% Type: language Subtag: due @@ -10382,6 +10399,7 @@ Type: language Subtag: dyn Description: Dyangadi +Description: Dhanggatti Added: 2009-07-29 %% Type: language @@ -10396,6 +10414,7 @@ %% Type: language Subtag: dyy +Description: Djabugay Description: Dyaabugay Added: 2009-07-29 %% @@ -11672,7 +11691,7 @@ %% Type: language Subtag: gbd -Description: Karadjeri +Description: Karajarri Added: 2009-07-29 %% Type: language @@ -12056,7 +12075,7 @@ %% Type: language Subtag: gge -Description: Guragone +Description: Gurr-goni Added: 2009-07-29 %% Type: language @@ -12169,7 +12188,7 @@ %% Type: language Subtag: gia -Description: Kitja +Description: Kija Added: 2009-07-29 %% Type: language @@ -12955,7 +12974,7 @@ %% Type: language Subtag: gue -Description: Gurinji +Description: Gurindji Added: 2009-07-29 %% Type: language @@ -15292,6 +15311,7 @@ Type: language Subtag: jay Description: Yan-nhangu +Description: Nhangu Added: 2009-07-29 %% Type: language @@ -15488,6 +15508,7 @@ %% Type: language Subtag: jig +Description: Jingulu Description: Djingili Added: 2009-07-29 %% @@ -17222,6 +17243,7 @@ Type: language Subtag: kkp Description: Gugubera +Description: Koko-Bera Added: 2009-07-29 %% Type: language @@ -17266,6 +17288,7 @@ %% Type: language Subtag: kky +Description: Guugu Yimidhirr Description: Guguyimidjir Added: 2009-07-29 %% @@ -18320,6 +18343,7 @@ Type: language Subtag: ktd Description: Kokata +Description: Kukatha Added: 2009-07-29 %% Type: language @@ -19341,6 +19365,7 @@ Subtag: lba Description: Lui Added: 2009-07-29 +Deprecated: 2019-04-16 %% Type: language Subtag: lbb @@ -19396,7 +19421,7 @@ %% Type: language Subtag: lbn -Description: Lamet +Description: Rmeet Added: 2009-07-29 %% Type: language @@ -19446,6 +19471,7 @@ %% Type: language Subtag: lby +Description: Lamalama Description: Lamu-Lamu Added: 2009-07-29 %% @@ -20162,6 +20188,8 @@ Subtag: llo Description: Khlor Added: 2009-07-29 +Deprecated: 2019-04-16 +Preferred-Value: ngt %% Type: language Subtag: llp @@ -20654,6 +20682,11 @@ Macrolanguage: luy %% Type: language +Subtag: lsn +Description: Tibetan Sign Language +Added: 2019-04-16 +%% +Type: language Subtag: lso Description: Laos Sign Language Added: 2009-07-29 @@ -20680,6 +20713,11 @@ Added: 2009-07-29 %% Type: language +Subtag: lsv +Description: Sivia Sign Language +Added: 2019-04-16 +%% +Type: language Subtag: lsy Description: Mauritian Sign Language Added: 2010-03-11 @@ -20848,6 +20886,11 @@ Added: 2009-07-29 %% Type: language +Subtag: lvi +Description: Lavi +Added: 2019-04-16 +%% +Type: language Subtag: lvk Description: Lavukaleve Added: 2009-07-29 @@ -21454,7 +21497,7 @@ %% Type: language Subtag: mec -Description: Mara +Description: Marra Added: 2009-07-29 %% Type: language @@ -21523,7 +21566,7 @@ %% Type: language Subtag: mep -Description: Miriwung +Description: Miriwoong Added: 2009-07-29 %% Type: language @@ -21660,7 +21703,7 @@ %% Type: language Subtag: mfr -Description: Marithiel +Description: Marrithiyel Added: 2009-07-29 %% Type: language @@ -22853,12 +22896,13 @@ %% Type: language Subtag: mpb +Description: Malak Malak Description: Mullukmulluk Added: 2009-07-29 %% Type: language Subtag: mpc -Description: Mangarayi +Description: Mangarrayi Added: 2009-07-29 %% Type: language @@ -22889,6 +22933,7 @@ Type: language Subtag: mpj Description: Martu Wangka +Description: Wangkajunga Added: 2009-07-29 %% Type: language @@ -24015,6 +24060,8 @@ Subtag: myd Description: Maramba Added: 2009-07-29 +Deprecated: 2019-04-16 +Preferred-Value: aog %% Type: language Subtag: mye @@ -24040,6 +24087,7 @@ Subtag: myi Description: Mina (India) Added: 2009-07-29 +Deprecated: 2019-04-16 %% Type: language Subtag: myj @@ -24375,7 +24423,7 @@ %% Type: language Subtag: nay -Description: Narrinyeri +Description: Ngarrindjeri Added: 2009-07-29 %% Type: language @@ -24432,7 +24480,7 @@ %% Type: language Subtag: nbj -Description: Ngarinman +Description: Ngarinyman Added: 2009-07-29 %% Type: language @@ -24467,7 +24515,7 @@ %% Type: language Subtag: nbr -Description: Numana-Nunku-Gbantu-Numbu +Description: Numana Added: 2009-07-29 %% Type: language @@ -24559,7 +24607,7 @@ %% Type: language Subtag: nck -Description: Nakara +Description: Na-kara Added: 2009-07-29 %% Type: language @@ -24931,7 +24979,7 @@ %% Type: language Subtag: ngh -Description: Nǀu +Description: Nǁng Added: 2009-07-29 %% Type: language @@ -25176,7 +25224,7 @@ %% Type: language Subtag: nig -Description: Ngalakan +Description: Ngalakgan Added: 2009-07-29 %% Type: language @@ -25798,6 +25846,8 @@ Subtag: nns Description: Ningye Added: 2009-07-29 +Deprecated: 2019-04-16 +Preferred-Value: nbr %% Type: language Subtag: nnt @@ -26658,7 +26708,7 @@ %% Type: language Subtag: nyh -Description: Nyigina +Description: Nyikina Added: 2009-07-29 %% Type: language @@ -26713,7 +26763,7 @@ %% Type: language Subtag: nys -Description: Nyunga +Description: Nyungar Added: 2009-07-29 %% Type: language @@ -28707,6 +28757,11 @@ Added: 2009-07-29 %% Type: language +Subtag: pnd +Description: Mpinda +Added: 2019-04-16 +%% +Type: language Subtag: pne Description: Western Penan Added: 2009-07-29 @@ -28794,6 +28849,7 @@ %% Type: language Subtag: pnw +Description: Banyjima Description: Panytyima Added: 2009-07-29 %% @@ -29251,7 +29307,8 @@ %% Type: language Subtag: pti -Description: Pintiini +Description: Pindiini +Description: Wangkatha Added: 2009-07-29 %% Type: language @@ -30133,6 +30190,7 @@ %% Type: language Subtag: ril +Description: Riang Lang Description: Riang (Myanmar) Added: 2009-07-29 %% @@ -30153,7 +30211,7 @@ %% Type: language Subtag: rit -Description: Ritarungo +Description: Ritharrngu Added: 2009-07-29 %% Type: language @@ -30219,7 +30277,7 @@ %% Type: language Subtag: rmb -Description: Rembarunga +Description: Rembarrnga Added: 2009-07-29 %% Type: language @@ -30641,6 +30699,7 @@ Type: language Subtag: rxw Description: Karuwali +Description: Garuwali Added: 2013-09-10 %% Type: language @@ -32206,7 +32265,7 @@ %% Type: language Subtag: snz -Description: Sinsauru +Description: Kou Added: 2009-07-29 %% Type: language @@ -32883,6 +32942,7 @@ Subtag: suj Description: Shubi Added: 2009-07-29 +Comments: see also xsj %% Type: language Subtag: suk @@ -33312,6 +33372,11 @@ Added: 2009-07-29 %% Type: language +Subtag: szy +Description: Sakizaya +Added: 2019-04-16 +%% +Type: language Subtag: taa Description: Lower Tanana Added: 2009-07-29 @@ -33465,6 +33530,7 @@ %% Type: language Subtag: tbh +Description: Dharawal Description: Thurawal Added: 2009-07-29 %% @@ -33644,6 +33710,7 @@ Type: language Subtag: tcs Description: Torres Strait Creole +Description: Yumplatok Added: 2009-07-29 %% Type: language @@ -34067,6 +34134,7 @@ %% Type: language Subtag: thd +Description: Kuuk Thaayorre Description: Thayore Added: 2009-07-29 %% @@ -34310,6 +34378,11 @@ Added: 2009-07-29 %% Type: language +Subtag: tjj +Description: Tjungundji +Added: 2019-04-16 +%% +Type: language Subtag: tjl Description: Tai Laing Added: 2012-08-12 @@ -34330,6 +34403,11 @@ Added: 2009-07-29 %% Type: language +Subtag: tjp +Description: Tjupany +Added: 2019-04-16 +%% +Type: language Subtag: tjs Description: Southern Tujia Added: 2009-07-29 @@ -35679,6 +35757,11 @@ Added: 2009-07-29 %% Type: language +Subtag: tvx +Description: Taivoan +Added: 2019-04-16 +%% +Type: language Subtag: tvy Description: Timor Pidgin Added: 2009-07-29 @@ -36230,7 +36313,7 @@ %% Type: language Subtag: ulk -Description: Meriam +Description: Meriam Mir Added: 2009-07-29 %% Type: language @@ -36280,6 +36363,7 @@ %% Type: language Subtag: umg +Description: Morrobalama Description: Umbuygamu Added: 2009-07-29 %% @@ -36550,6 +36634,11 @@ Added: 2009-07-29 %% Type: language +Subtag: uss +Description: us-Saare +Added: 2019-04-16 +%% +Type: language Subtag: usu Description: Uya Added: 2009-07-29 @@ -36565,6 +36654,11 @@ Added: 2009-07-29 %% Type: language +Subtag: uth +Description: ut-Hun +Added: 2019-04-16 +%% +Type: language Subtag: utp Description: Amba (Solomon Islands) Added: 2009-07-29 @@ -37178,7 +37272,7 @@ %% Type: language Subtag: waq -Description: Wageman +Description: Wagiman Added: 2009-07-29 %% Type: language @@ -37301,7 +37395,7 @@ %% Type: language Subtag: wbt -Description: Wanman +Description: Warnman Added: 2009-07-29 %% Type: language @@ -37448,6 +37542,7 @@ %% Type: language Subtag: wgg +Description: Wangkangurru Description: Wangganguru Added: 2009-07-29 %% @@ -37521,7 +37616,7 @@ %% Type: language Subtag: wig -Description: Wik-Ngathana +Description: Wik Ngathan Added: 2009-07-29 %% Type: language @@ -37625,6 +37720,11 @@ Added: 2009-07-29 %% Type: language +Subtag: wkr +Description: Keerray-Woorroong +Added: 2019-04-16 +%% +Type: language Subtag: wku Description: Kunduvadi Added: 2009-07-29 @@ -37857,10 +37957,12 @@ Type: language Subtag: wny Description: Wanyi +Description: Waanyi Added: 2012-08-12 %% Type: language Subtag: woa +Description: Kuwema Description: Tyaraity Added: 2009-07-29 %% @@ -37951,6 +38053,7 @@ %% Type: language Subtag: wrb +Description: Waluwarra Description: Warluwara Added: 2009-07-29 %% @@ -37962,11 +38065,12 @@ Type: language Subtag: wrg Description: Warungu +Description: Gudjal Added: 2009-07-29 %% Type: language Subtag: wrh -Description: Wiradhuri +Description: Wiradjuri Added: 2009-07-29 %% Type: language @@ -38439,6 +38543,7 @@ %% Type: language Subtag: xby +Description: Batjala Description: Batyala Added: 2013-09-10 %% @@ -38998,7 +39103,7 @@ %% Type: language Subtag: xmh -Description: Kuku-Muminh +Description: Kugu-Muminh Added: 2009-07-29 %% Type: language @@ -39423,8 +39528,7 @@ Subtag: xsj Description: Subi Added: 2009-07-29 -Deprecated: 2015-02-12 -Preferred-Value: suj +Comments: see also suj %% Type: language Subtag: xsl @@ -40258,6 +40362,7 @@ %% Type: language Subtag: yin +Description: Riang Lai Description: Yinchia Added: 2009-07-29 %% @@ -41562,12 +41667,13 @@ %% Type: language Subtag: zml -Description: Madngele +Description: Matngala Added: 2009-07-29 %% Type: language Subtag: zmm Description: Marimanindji +Description: Marramaninyshi Added: 2009-07-29 %% Type: language @@ -43019,6 +43125,13 @@ Prefix: sgn %% Type: extlang +Subtag: lsn +Description: Tibetan Sign Language +Added: 2019-04-16 +Preferred-Value: lsn +Prefix: sgn +%% +Type: extlang Subtag: lso Description: Laos Sign Language Added: 2009-07-29 @@ -43041,6 +43154,13 @@ Prefix: sgn %% Type: extlang +Subtag: lsv +Description: Sivia Sign Language +Added: 2019-04-16 +Preferred-Value: lsv +Prefix: sgn +%% +Type: extlang Subtag: lsy Description: Mauritian Sign Language Added: 2010-03-11 @@ -43966,6 +44086,11 @@ Added: 2005-10-16 %% Type: script +Subtag: Chrs +Description: Chorasmian +Added: 2019-09-11 +%% +Type: script Subtag: Cirt Description: Cirth Added: 2005-10-16 @@ -44002,6 +44127,11 @@ Added: 2005-10-16 %% Type: script +Subtag: Diak +Description: Dives Akuru +Added: 2019-09-11 +%% +Type: script Subtag: Dogr Description: Dogra Added: 2017-01-13 @@ -44839,6 +44969,11 @@ Added: 2005-10-16 %% Type: script +Subtag: Yezi +Description: Yezidi +Added: 2019-09-11 +%% +Type: script Subtag: Yiii Description: Yi Added: 2005-10-16 @@ -45683,7 +45818,7 @@ %% Type: region Subtag: MK -Description: The Former Yugoslav Republic of Macedonia +Description: North Macedonia Added: 2005-10-16 %% Type: region diff -r 496bbf554c5c -r 38176d1c5ec2 make/devkit/Tools.gmk --- a/make/devkit/Tools.gmk Wed Oct 16 01:16:12 2019 +0200 +++ b/make/devkit/Tools.gmk Wed Oct 16 11:23:46 2019 +0200 @@ -79,20 +79,19 @@ # Define external dependencies # Latest that could be made to work. -GCC_VER := 8.2.0 -ifeq ($(GCC_VER), 8.2.0) - gcc_ver := gcc-8.2.0 - binutils_ver := binutils-2.30 - ccache_ver := ccache-3.5.1a - CCACHE_DIRNAME := ccache-3.5.1 +GCC_VER := 8.3.0 +ifeq ($(GCC_VER), 8.3.0) + gcc_ver := gcc-8.3.0 + binutils_ver := binutils-2.32 + ccache_ver := 3.7.3 mpfr_ver := mpfr-3.1.5 gmp_ver := gmp-6.1.2 mpc_ver := mpc-1.0.3 - gdb_ver := gdb-8.2.1 + gdb_ver := gdb-8.3 else ifeq ($(GCC_VER), 7.3.0) gcc_ver := gcc-7.3.0 binutils_ver := binutils-2.30 - ccache_ver := ccache-3.3.6 + ccache_ver := 3.3.6 mpfr_ver := mpfr-3.1.5 gmp_ver := gmp-6.1.2 mpc_ver := mpc-1.0.3 @@ -100,7 +99,7 @@ else ifeq ($(GCC_VER), 4.9.2) gcc_ver := gcc-4.9.2 binutils_ver := binutils-2.25 - ccache_ver := ccache-3.2.1 + ccache_ver := 3.2.1 mpfr_ver := mpfr-3.0.1 gmp_ver := gmp-4.3.2 mpc_ver := mpc-1.0.1 @@ -111,7 +110,7 @@ GCC := http://ftp.gnu.org/pub/gnu/gcc/$(gcc_ver)/$(gcc_ver).tar.xz BINUTILS := http://ftp.gnu.org/pub/gnu/binutils/$(binutils_ver).tar.xz -CCACHE := https://samba.org/ftp/ccache/$(ccache_ver).tar.xz +CCACHE := https://github.com/ccache/ccache/releases/download/v$(ccache_ver)/ccache-$(ccache_ver).tar.xz MPFR := https://www.mpfr.org/${mpfr_ver}/${mpfr_ver}.tar.bz2 GMP := http://ftp.gnu.org/pub/gnu/gmp/${gmp_ver}.tar.bz2 MPC := http://ftp.gnu.org/pub/gnu/mpc/${mpc_ver}.tar.gz diff -r 496bbf554c5c -r 38176d1c5ec2 make/devkit/createWindowsDevkit2017.sh --- a/make/devkit/createWindowsDevkit2017.sh Wed Oct 16 01:16:12 2019 +0200 +++ b/make/devkit/createWindowsDevkit2017.sh Wed Oct 16 11:23:46 2019 +0200 @@ -32,10 +32,7 @@ VS_VERSION_NUM_NODOT="150" VS_DLL_VERSION="140" SDK_VERSION="10" -SDK_FULL_VERSION="10.0.16299.0" MSVC_DIR="Microsoft.VC141.CRT" -MSVC_FULL_VERSION="14.12.25827" -REDIST_FULL_VERSION="14.12.25810" SCRIPT_DIR="$(cd "$(dirname $0)" > /dev/null && pwd)" BUILD_DIR="${SCRIPT_DIR}/../../build/devkit" diff -r 496bbf554c5c -r 38176d1c5ec2 make/jdk/src/classes/build/tools/charsetmapping/SBCS.java --- a/make/jdk/src/classes/build/tools/charsetmapping/SBCS.java Wed Oct 16 01:16:12 2019 +0200 +++ b/make/jdk/src/classes/build/tools/charsetmapping/SBCS.java Wed Oct 16 11:23:46 2019 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2008, 2019, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -46,6 +46,7 @@ String hisName = cs.hisName; String pkgName = cs.pkgName; boolean isASCII = cs.isASCII; + boolean isLatin1Decodable = true; StringBuilder b2cSB = new StringBuilder(); StringBuilder b2cNRSB = new StringBuilder(); @@ -69,6 +70,9 @@ c2bOff += 0x100; c2bIndex[e.cp>>8] = 1; } + if (e.cp > 0xFF) { + isLatin1Decodable = false; + } } Formatter fm = new Formatter(b2cSB); @@ -178,6 +182,9 @@ if (line.indexOf("$ASCIICOMPATIBLE$") != -1) { line = line.replace("$ASCIICOMPATIBLE$", isASCII ? "true" : "false"); } + if (line.indexOf("$LATIN1DECODABLE$") != -1) { + line = line.replace("$LATIN1DECODABLE$", isLatin1Decodable ? "true" : "false"); + } if (line.indexOf("$B2CTABLE$") != -1) { line = line.replace("$B2CTABLE$", b2c); } diff -r 496bbf554c5c -r 38176d1c5ec2 make/scripts/compare.sh --- a/make/scripts/compare.sh Wed Oct 16 01:16:12 2019 +0200 +++ b/make/scripts/compare.sh Wed Oct 16 11:23:46 2019 +0200 @@ -34,6 +34,9 @@ exit 1 fi +# Make sure all shell commands are executed with the C locale +export LC_ALL=C + if [ "$OPENJDK_TARGET_OS" = "macosx" ]; then FULLDUMP_CMD="$OTOOL -v -V -h -X -d" LDD_CMD="$OTOOL -L" @@ -110,7 +113,7 @@ " fi elif [ "$OPENJDK_TARGET_OS" = "macosx" ]; then - DIS_DIFF_FILTER="LANG=C $SED \ + DIS_DIFF_FILTER="$SED \ -e 's/0x[0-9a-f]\{3,16\}//g' -e 's/^[0-9a-f]\{12,20\}//' \ -e 's/-20[0-9][0-9]-[0-1][0-9]-[0-3][0-9]-[0-2][0-9]\{5\}//g' \ -e 's/), built on .*/), /' \ @@ -134,7 +137,7 @@ if [[ "$THIS_FILE" = *"META-INF/MANIFEST.MF" ]]; then # Filter out date string, ant version and java version differences. - TMP=$(LC_ALL=C $DIFF $OTHER_FILE $THIS_FILE | \ + TMP=$($DIFF $OTHER_FILE $THIS_FILE | \ $GREP '^[<>]' | \ $SED -e '/[<>] Ant-Version: Apache Ant .*/d' \ -e '/[<>] Created-By: .* (Oracle [Corpatin)]*/d' \ @@ -142,7 +145,7 @@ -e '/[<>].*[0-9]\{4\}_[0-9]\{2\}_[0-9]\{2\}_[0-9]\{2\}_[0-9]\{2\}-b[0-9]\{2\}.*/d') fi if test "x$SUFFIX" = "xjava"; then - TMP=$(LC_ALL=C $DIFF $OTHER_FILE $THIS_FILE | \ + TMP=$($DIFF $OTHER_FILE $THIS_FILE | \ $GREP '^[<>]' | \ $SED -e '/[<>] \* from.*\.idl/d' \ -e '/[<>] .*[0-9]\{4\}_[0-9]\{2\}_[0-9]\{2\}_[0-9]\{2\}_[0-9]\{2\}-b[0-9]\{2\}.*/d' \ @@ -197,7 +200,7 @@ fi if test "x$SUFFIX" = "xproperties"; then # Filter out date string differences. - TMP=$(LC_ALL=C $DIFF $OTHER_FILE $THIS_FILE | \ + TMP=$($DIFF $OTHER_FILE $THIS_FILE | \ $GREP '^[<>]' | \ $SED -e '/[<>].*[0-9]\{4\}-[0-9]\{2\}-[0-9]\{2\}-[0-9]\{6\}.*/d') fi @@ -207,7 +210,7 @@ -e 's///g'" $CAT $THIS_FILE | eval "$HTML_FILTER" > $THIS_FILE.filtered $CAT $OTHER_FILE | eval "$HTML_FILTER" > $OTHER_FILE.filtered - TMP=$(LC_ALL=C $DIFF $OTHER_FILE.filtered $THIS_FILE.filtered | \ + TMP=$($DIFF $OTHER_FILE.filtered $THIS_FILE.filtered | \ $GREP '^[<>]' | \ $SED -e '/[<>] /d' \ -e '/[<>] /d' ) @@ -554,11 +557,11 @@ CONTENTS_DIFF_FILE=$WORK_DIR/$ZIP_FILE.diff # On solaris, there is no -q option. if [ "$OPENJDK_TARGET_OS" = "solaris" ]; then - LC_ALL=C $DIFF -r $OTHER_UNZIPDIR $THIS_UNZIPDIR \ + $DIFF -r $OTHER_UNZIPDIR $THIS_UNZIPDIR \ | $GREP -v -e "^<" -e "^>" -e "^Common subdirectories:" \ > $CONTENTS_DIFF_FILE else - LC_ALL=C $DIFF -rq $OTHER_UNZIPDIR $THIS_UNZIPDIR > $CONTENTS_DIFF_FILE + $DIFF -rq $OTHER_UNZIPDIR $THIS_UNZIPDIR > $CONTENTS_DIFF_FILE fi ONLY_OTHER=$($GREP "^Only in $OTHER_UNZIPDIR" $CONTENTS_DIFF_FILE) @@ -605,11 +608,11 @@ if [ -n "$SHOW_DIFFS" ]; then for i in $(cat $WORK_DIR/$ZIP_FILE.difflist) ; do if [ -f "${OTHER_UNZIPDIR}/$i.javap" ]; then - LC_ALL=C $DIFF ${OTHER_UNZIPDIR}/$i.javap ${THIS_UNZIPDIR}/$i.javap + $DIFF ${OTHER_UNZIPDIR}/$i.javap ${THIS_UNZIPDIR}/$i.javap elif [ -f "${OTHER_UNZIPDIR}/$i.cleaned" ]; then - LC_ALL=C $DIFF ${OTHER_UNZIPDIR}/$i.cleaned ${THIS_UNZIPDIR}/$i + $DIFF ${OTHER_UNZIPDIR}/$i.cleaned ${THIS_UNZIPDIR}/$i else - LC_ALL=C $DIFF ${OTHER_UNZIPDIR}/$i ${THIS_UNZIPDIR}/$i + $DIFF ${OTHER_UNZIPDIR}/$i ${THIS_UNZIPDIR}/$i fi done fi @@ -642,7 +645,7 @@ $JMOD list $THIS_JMOD | sort > $THIS_JMOD_LIST $JMOD list $OTHER_JMOD | sort > $OTHER_JMOD_LIST JMOD_LIST_DIFF_FILE=$WORK_DIR/$JMOD_FILE.list.diff - LC_ALL=C $DIFF $THIS_JMOD_LIST $OTHER_JMOD_LIST > $JMOD_LIST_DIFF_FILE + $DIFF $THIS_JMOD_LIST $OTHER_JMOD_LIST > $JMOD_LIST_DIFF_FILE ONLY_THIS=$($GREP "^<" $JMOD_LIST_DIFF_FILE) ONLY_OTHER=$($GREP "^>" $JMOD_LIST_DIFF_FILE) @@ -924,7 +927,7 @@ > $WORK_FILE_BASE.symbols.this fi - LC_ALL=C $DIFF $WORK_FILE_BASE.symbols.other $WORK_FILE_BASE.symbols.this > $WORK_FILE_BASE.symbols.diff + $DIFF $WORK_FILE_BASE.symbols.other $WORK_FILE_BASE.symbols.this > $WORK_FILE_BASE.symbols.diff if [ -s $WORK_FILE_BASE.symbols.diff ]; then SYM_MSG=" diff " if [[ "$ACCEPTED_SYM_DIFF" != *"$BIN_FILE"* ]]; then @@ -964,9 +967,9 @@ | $UNIQ > $WORK_FILE_BASE.deps.this.uniq) (cd $FILE_WORK_DIR && $RM -f $NAME) - LC_ALL=C $DIFF $WORK_FILE_BASE.deps.other $WORK_FILE_BASE.deps.this \ + $DIFF $WORK_FILE_BASE.deps.other $WORK_FILE_BASE.deps.this \ > $WORK_FILE_BASE.deps.diff - LC_ALL=C $DIFF $WORK_FILE_BASE.deps.other.uniq $WORK_FILE_BASE.deps.this.uniq \ + $DIFF $WORK_FILE_BASE.deps.other.uniq $WORK_FILE_BASE.deps.this.uniq \ > $WORK_FILE_BASE.deps.diff.uniq if [ -s $WORK_FILE_BASE.deps.diff ]; then @@ -1016,7 +1019,7 @@ > $WORK_FILE_BASE.fulldump.this 2>&1 & wait - LC_ALL=C $DIFF $WORK_FILE_BASE.fulldump.other $WORK_FILE_BASE.fulldump.this \ + $DIFF $WORK_FILE_BASE.fulldump.other $WORK_FILE_BASE.fulldump.this \ > $WORK_FILE_BASE.fulldump.diff if [ -s $WORK_FILE_BASE.fulldump.diff ]; then @@ -1063,7 +1066,7 @@ | eval "$this_DIS_DIFF_FILTER" > $WORK_FILE_BASE.dis.this 2>&1 & wait - LC_ALL=C $DIFF $WORK_FILE_BASE.dis.other $WORK_FILE_BASE.dis.this > $WORK_FILE_BASE.dis.diff + $DIFF $WORK_FILE_BASE.dis.other $WORK_FILE_BASE.dis.this > $WORK_FILE_BASE.dis.diff if [ -s $WORK_FILE_BASE.dis.diff ]; then DIS_DIFF_SIZE=$(ls -n $WORK_FILE_BASE.dis.diff | awk '{print $5}') diff -r 496bbf554c5c -r 38176d1c5ec2 src/hotspot/cpu/aarch64/abstractInterpreter_aarch64.cpp --- a/src/hotspot/cpu/aarch64/abstractInterpreter_aarch64.cpp Wed Oct 16 01:16:12 2019 +0200 +++ b/src/hotspot/cpu/aarch64/abstractInterpreter_aarch64.cpp Wed Oct 16 11:23:46 2019 +0200 @@ -26,6 +26,7 @@ #include "precompiled.hpp" #include "interpreter/interpreter.hpp" #include "oops/constMethod.hpp" +#include "oops/klass.inline.hpp" #include "oops/method.hpp" #include "runtime/frame.inline.hpp" #include "utilities/align.hpp" diff -r 496bbf554c5c -r 38176d1c5ec2 src/hotspot/cpu/aarch64/compiledIC_aarch64.cpp --- a/src/hotspot/cpu/aarch64/compiledIC_aarch64.cpp Wed Oct 16 01:16:12 2019 +0200 +++ b/src/hotspot/cpu/aarch64/compiledIC_aarch64.cpp Wed Oct 16 11:23:46 2019 +0200 @@ -185,6 +185,10 @@ NativeMovConstReg* method_holder = nativeMovConstReg_at(stub + NativeInstruction::instruction_size); method_holder->set_data(0); + if (!static_stub->is_aot()) { + NativeJump* jump = nativeJump_at(method_holder->next_instruction_address()); + jump->set_jump_destination((address)-1); + } } //----------------------------------------------------------------------------- diff -r 496bbf554c5c -r 38176d1c5ec2 src/hotspot/cpu/aarch64/nativeInst_aarch64.cpp --- a/src/hotspot/cpu/aarch64/nativeInst_aarch64.cpp Wed Oct 16 01:16:12 2019 +0200 +++ b/src/hotspot/cpu/aarch64/nativeInst_aarch64.cpp Wed Oct 16 11:23:46 2019 +0200 @@ -332,9 +332,14 @@ // We use jump to self as the unresolved address which the inline // cache code (and relocs) know about + // As a special case we also use sequence movptr(r,0); br(r); + // i.e. jump to 0 when we need leave space for a wide immediate + // load - // return -1 if jump to self - dest = (dest == (address) this) ? (address) -1 : dest; + // return -1 if jump to self or to 0 + if ((dest == (address)this) || dest == 0) { + dest = (address) -1; + } return dest; } @@ -356,9 +361,13 @@ // We use jump to self as the unresolved address which the inline // cache code (and relocs) know about + // As a special case we also use jump to 0 when first generating + // a general jump - // return -1 if jump to self - dest = (dest == (address) this) ? (address) -1 : dest; + // return -1 if jump to self or to 0 + if ((dest == (address)this) || dest == 0) { + dest = (address) -1; + } return dest; } diff -r 496bbf554c5c -r 38176d1c5ec2 src/hotspot/cpu/aarch64/sharedRuntime_aarch64.cpp --- a/src/hotspot/cpu/aarch64/sharedRuntime_aarch64.cpp Wed Oct 16 01:16:12 2019 +0200 +++ b/src/hotspot/cpu/aarch64/sharedRuntime_aarch64.cpp Wed Oct 16 11:23:46 2019 +0200 @@ -34,6 +34,7 @@ #include "logging/log.hpp" #include "memory/resourceArea.hpp" #include "oops/compiledICHolder.hpp" +#include "oops/klass.inline.hpp" #include "runtime/safepointMechanism.hpp" #include "runtime/sharedRuntime.hpp" #include "runtime/vframeArray.hpp" diff -r 496bbf554c5c -r 38176d1c5ec2 src/hotspot/cpu/arm/abstractInterpreter_arm.cpp --- a/src/hotspot/cpu/arm/abstractInterpreter_arm.cpp Wed Oct 16 01:16:12 2019 +0200 +++ b/src/hotspot/cpu/arm/abstractInterpreter_arm.cpp Wed Oct 16 11:23:46 2019 +0200 @@ -27,6 +27,7 @@ #include "interpreter/bytecode.hpp" #include "interpreter/interpreter.hpp" #include "oops/constMethod.hpp" +#include "oops/klass.inline.hpp" #include "oops/method.hpp" #include "prims/methodHandles.hpp" #include "runtime/handles.inline.hpp" diff -r 496bbf554c5c -r 38176d1c5ec2 src/hotspot/cpu/arm/sharedRuntime_arm.cpp --- a/src/hotspot/cpu/arm/sharedRuntime_arm.cpp Wed Oct 16 01:16:12 2019 +0200 +++ b/src/hotspot/cpu/arm/sharedRuntime_arm.cpp Wed Oct 16 11:23:46 2019 +0200 @@ -32,6 +32,7 @@ #include "logging/log.hpp" #include "memory/resourceArea.hpp" #include "oops/compiledICHolder.hpp" +#include "oops/klass.inline.hpp" #include "runtime/sharedRuntime.hpp" #include "runtime/vframeArray.hpp" #include "utilities/align.hpp" diff -r 496bbf554c5c -r 38176d1c5ec2 src/hotspot/cpu/ppc/abstractInterpreter_ppc.cpp --- a/src/hotspot/cpu/ppc/abstractInterpreter_ppc.cpp Wed Oct 16 01:16:12 2019 +0200 +++ b/src/hotspot/cpu/ppc/abstractInterpreter_ppc.cpp Wed Oct 16 11:23:46 2019 +0200 @@ -26,6 +26,7 @@ #include "precompiled.hpp" #include "interpreter/interpreter.hpp" #include "oops/constMethod.hpp" +#include "oops/klass.inline.hpp" #include "oops/method.hpp" #include "runtime/frame.inline.hpp" #include "utilities/debug.hpp" diff -r 496bbf554c5c -r 38176d1c5ec2 src/hotspot/cpu/ppc/macroAssembler_ppc.cpp --- a/src/hotspot/cpu/ppc/macroAssembler_ppc.cpp Wed Oct 16 01:16:12 2019 +0200 +++ b/src/hotspot/cpu/ppc/macroAssembler_ppc.cpp Wed Oct 16 11:23:46 2019 +0200 @@ -32,6 +32,7 @@ #include "interpreter/interpreter.hpp" #include "memory/resourceArea.hpp" #include "nativeInst_ppc.hpp" +#include "oops/klass.inline.hpp" #include "prims/methodHandles.hpp" #include "runtime/biasedLocking.hpp" #include "runtime/icache.hpp" diff -r 496bbf554c5c -r 38176d1c5ec2 src/hotspot/cpu/ppc/sharedRuntime_ppc.cpp --- a/src/hotspot/cpu/ppc/sharedRuntime_ppc.cpp Wed Oct 16 01:16:12 2019 +0200 +++ b/src/hotspot/cpu/ppc/sharedRuntime_ppc.cpp Wed Oct 16 11:23:46 2019 +0200 @@ -34,6 +34,7 @@ #include "interpreter/interp_masm.hpp" #include "memory/resourceArea.hpp" #include "oops/compiledICHolder.hpp" +#include "oops/klass.inline.hpp" #include "runtime/safepointMechanism.hpp" #include "runtime/sharedRuntime.hpp" #include "runtime/vframeArray.hpp" diff -r 496bbf554c5c -r 38176d1c5ec2 src/hotspot/cpu/ppc/templateTable_ppc_64.cpp --- a/src/hotspot/cpu/ppc/templateTable_ppc_64.cpp Wed Oct 16 01:16:12 2019 +0200 +++ b/src/hotspot/cpu/ppc/templateTable_ppc_64.cpp Wed Oct 16 11:23:46 2019 +0200 @@ -32,6 +32,7 @@ #include "interpreter/templateInterpreter.hpp" #include "interpreter/templateTable.hpp" #include "memory/universe.hpp" +#include "oops/klass.inline.hpp" #include "oops/objArrayKlass.hpp" #include "oops/oop.inline.hpp" #include "prims/methodHandles.hpp" diff -r 496bbf554c5c -r 38176d1c5ec2 src/hotspot/cpu/ppc/vtableStubs_ppc_64.cpp --- a/src/hotspot/cpu/ppc/vtableStubs_ppc_64.cpp Wed Oct 16 01:16:12 2019 +0200 +++ b/src/hotspot/cpu/ppc/vtableStubs_ppc_64.cpp Wed Oct 16 11:23:46 2019 +0200 @@ -30,6 +30,7 @@ #include "memory/resourceArea.hpp" #include "oops/compiledICHolder.hpp" #include "oops/instanceKlass.hpp" +#include "oops/klass.inline.hpp" #include "oops/klassVtable.hpp" #include "runtime/sharedRuntime.hpp" #include "vmreg_ppc.inline.hpp" diff -r 496bbf554c5c -r 38176d1c5ec2 src/hotspot/cpu/s390/abstractInterpreter_s390.cpp --- a/src/hotspot/cpu/s390/abstractInterpreter_s390.cpp Wed Oct 16 01:16:12 2019 +0200 +++ b/src/hotspot/cpu/s390/abstractInterpreter_s390.cpp Wed Oct 16 11:23:46 2019 +0200 @@ -26,6 +26,7 @@ #include "precompiled.hpp" #include "interpreter/interpreter.hpp" #include "oops/constMethod.hpp" +#include "oops/klass.inline.hpp" #include "oops/method.hpp" #include "runtime/frame.inline.hpp" #include "utilities/debug.hpp" diff -r 496bbf554c5c -r 38176d1c5ec2 src/hotspot/cpu/s390/sharedRuntime_s390.cpp --- a/src/hotspot/cpu/s390/sharedRuntime_s390.cpp Wed Oct 16 01:16:12 2019 +0200 +++ b/src/hotspot/cpu/s390/sharedRuntime_s390.cpp Wed Oct 16 11:23:46 2019 +0200 @@ -33,6 +33,7 @@ #include "interpreter/interp_masm.hpp" #include "memory/resourceArea.hpp" #include "oops/compiledICHolder.hpp" +#include "oops/klass.inline.hpp" #include "registerSaver_s390.hpp" #include "runtime/safepointMechanism.hpp" #include "runtime/sharedRuntime.hpp" diff -r 496bbf554c5c -r 38176d1c5ec2 src/hotspot/cpu/s390/vtableStubs_s390.cpp --- a/src/hotspot/cpu/s390/vtableStubs_s390.cpp Wed Oct 16 01:16:12 2019 +0200 +++ b/src/hotspot/cpu/s390/vtableStubs_s390.cpp Wed Oct 16 11:23:46 2019 +0200 @@ -30,6 +30,7 @@ #include "memory/resourceArea.hpp" #include "oops/compiledICHolder.hpp" #include "oops/instanceKlass.hpp" +#include "oops/klass.inline.hpp" #include "oops/klassVtable.hpp" #include "runtime/sharedRuntime.hpp" #include "vmreg_s390.inline.hpp" diff -r 496bbf554c5c -r 38176d1c5ec2 src/hotspot/cpu/sparc/abstractInterpreter_sparc.cpp --- a/src/hotspot/cpu/sparc/abstractInterpreter_sparc.cpp Wed Oct 16 01:16:12 2019 +0200 +++ b/src/hotspot/cpu/sparc/abstractInterpreter_sparc.cpp Wed Oct 16 11:23:46 2019 +0200 @@ -25,6 +25,7 @@ #include "precompiled.hpp" #include "interpreter/interpreter.hpp" #include "oops/constMethod.hpp" +#include "oops/klass.inline.hpp" #include "oops/method.hpp" #include "runtime/arguments.hpp" #include "runtime/frame.inline.hpp" diff -r 496bbf554c5c -r 38176d1c5ec2 src/hotspot/cpu/sparc/sharedRuntime_sparc.cpp --- a/src/hotspot/cpu/sparc/sharedRuntime_sparc.cpp Wed Oct 16 01:16:12 2019 +0200 +++ b/src/hotspot/cpu/sparc/sharedRuntime_sparc.cpp Wed Oct 16 11:23:46 2019 +0200 @@ -32,6 +32,7 @@ #include "logging/log.hpp" #include "memory/resourceArea.hpp" #include "oops/compiledICHolder.hpp" +#include "oops/klass.inline.hpp" #include "runtime/safepointMechanism.hpp" #include "runtime/sharedRuntime.hpp" #include "runtime/vframeArray.hpp" diff -r 496bbf554c5c -r 38176d1c5ec2 src/hotspot/cpu/x86/abstractInterpreter_x86.cpp --- a/src/hotspot/cpu/x86/abstractInterpreter_x86.cpp Wed Oct 16 01:16:12 2019 +0200 +++ b/src/hotspot/cpu/x86/abstractInterpreter_x86.cpp Wed Oct 16 11:23:46 2019 +0200 @@ -25,6 +25,7 @@ #include "precompiled.hpp" #include "ci/ciMethod.hpp" #include "interpreter/interpreter.hpp" +#include "oops/klass.inline.hpp" #include "runtime/frame.inline.hpp" diff -r 496bbf554c5c -r 38176d1c5ec2 src/hotspot/cpu/x86/macroAssembler_x86.cpp --- a/src/hotspot/cpu/x86/macroAssembler_x86.cpp Wed Oct 16 01:16:12 2019 +0200 +++ b/src/hotspot/cpu/x86/macroAssembler_x86.cpp Wed Oct 16 11:23:46 2019 +0200 @@ -824,11 +824,13 @@ } void MacroAssembler::stop(const char* msg) { - address rip = pc(); - pusha(); // get regs on stack + if (ShowMessageBoxOnError) { + address rip = pc(); + pusha(); // get regs on stack + lea(c_rarg1, InternalAddress(rip)); + movq(c_rarg2, rsp); // pass pointer to regs array + } lea(c_rarg0, ExternalAddress((address) msg)); - lea(c_rarg1, InternalAddress(rip)); - movq(c_rarg2, rsp); // pass pointer to regs array andq(rsp, -16); // align stack as required by ABI call(RuntimeAddress(CAST_FROM_FN_PTR(address, MacroAssembler::debug64))); hlt(); @@ -6350,7 +6352,7 @@ movptr(result, str1); if (UseAVX >= 2) { cmpl(cnt1, stride); - jcc(Assembler::less, SCAN_TO_CHAR_LOOP); + jcc(Assembler::less, SCAN_TO_CHAR); cmpl(cnt1, 2*stride); jcc(Assembler::less, SCAN_TO_8_CHAR_INIT); movdl(vec1, ch); @@ -6377,10 +6379,8 @@ } bind(SCAN_TO_8_CHAR); cmpl(cnt1, stride); - if (UseAVX >= 2) { - jcc(Assembler::less, SCAN_TO_CHAR); - } else { - jcc(Assembler::less, SCAN_TO_CHAR_LOOP); + jcc(Assembler::less, SCAN_TO_CHAR); + if (UseAVX < 2) { movdl(vec1, ch); pshuflw(vec1, vec1, 0x00); pshufd(vec1, vec1, 0); diff -r 496bbf554c5c -r 38176d1c5ec2 src/hotspot/cpu/x86/sharedRuntime_x86_32.cpp --- a/src/hotspot/cpu/x86/sharedRuntime_x86_32.cpp Wed Oct 16 01:16:12 2019 +0200 +++ b/src/hotspot/cpu/x86/sharedRuntime_x86_32.cpp Wed Oct 16 11:23:46 2019 +0200 @@ -34,6 +34,7 @@ #include "logging/log.hpp" #include "memory/resourceArea.hpp" #include "oops/compiledICHolder.hpp" +#include "oops/klass.inline.hpp" #include "runtime/safepointMechanism.hpp" #include "runtime/sharedRuntime.hpp" #include "runtime/vframeArray.hpp" @@ -1303,6 +1304,97 @@ } } +// Registers need to be saved for runtime call +static Register caller_saved_registers[] = { + rcx, rdx, rsi, rdi +}; + +// Save caller saved registers except r1 and r2 +static void save_registers_except(MacroAssembler* masm, Register r1, Register r2) { + int reg_len = (int)(sizeof(caller_saved_registers) / sizeof(Register)); + for (int index = 0; index < reg_len; index ++) { + Register this_reg = caller_saved_registers[index]; + if (this_reg != r1 && this_reg != r2) { + __ push(this_reg); + } + } +} + +// Restore caller saved registers except r1 and r2 +static void restore_registers_except(MacroAssembler* masm, Register r1, Register r2) { + int reg_len = (int)(sizeof(caller_saved_registers) / sizeof(Register)); + for (int index = reg_len - 1; index >= 0; index --) { + Register this_reg = caller_saved_registers[index]; + if (this_reg != r1 && this_reg != r2) { + __ pop(this_reg); + } + } +} + +// Pin object, return pinned object or null in rax +static void gen_pin_object(MacroAssembler* masm, + Register thread, VMRegPair reg) { + __ block_comment("gen_pin_object {"); + + Label is_null; + Register tmp_reg = rax; + VMRegPair tmp(tmp_reg->as_VMReg()); + if (reg.first()->is_stack()) { + // Load the arg up from the stack + simple_move32(masm, reg, tmp); + reg = tmp; + } else { + __ movl(tmp_reg, reg.first()->as_Register()); + } + __ testptr(reg.first()->as_Register(), reg.first()->as_Register()); + __ jccb(Assembler::equal, is_null); + + // Save registers that may be used by runtime call + Register arg = reg.first()->is_Register() ? reg.first()->as_Register() : noreg; + save_registers_except(masm, arg, thread); + + __ call_VM_leaf( + CAST_FROM_FN_PTR(address, SharedRuntime::pin_object), + thread, reg.first()->as_Register()); + + // Restore saved registers + restore_registers_except(masm, arg, thread); + + __ bind(is_null); + __ block_comment("} gen_pin_object"); +} + +// Unpin object +static void gen_unpin_object(MacroAssembler* masm, + Register thread, VMRegPair reg) { + __ block_comment("gen_unpin_object {"); + Label is_null; + + // temp register + __ push(rax); + Register tmp_reg = rax; + VMRegPair tmp(tmp_reg->as_VMReg()); + + simple_move32(masm, reg, tmp); + + __ testptr(rax, rax); + __ jccb(Assembler::equal, is_null); + + // Save registers that may be used by runtime call + Register arg = reg.first()->is_Register() ? reg.first()->as_Register() : noreg; + save_registers_except(masm, arg, thread); + + __ call_VM_leaf( + CAST_FROM_FN_PTR(address, SharedRuntime::unpin_object), + thread, rax); + + // Restore saved registers + restore_registers_except(masm, arg, thread); + __ bind(is_null); + __ pop(rax); + __ block_comment("} gen_unpin_object"); +} + // Check GCLocker::needs_gc and enter the runtime if it's true. This // keeps a new JNI critical region from starting until a GC has been // forced. Save down any oops in registers and describe them in an @@ -1836,7 +1928,7 @@ __ get_thread(thread); - if (is_critical_native) { + if (is_critical_native && !Universe::heap()->supports_object_pinning()) { check_needs_gc_for_critical_native(masm, thread, stack_slots, total_c_args, total_in_args, oop_handle_offset, oop_maps, in_regs, in_sig_bt); } @@ -1874,6 +1966,11 @@ // OopMap* map = new OopMap(stack_slots * 2, 0 /* arg_slots*/); + // Inbound arguments that need to be pinned for critical natives + GrowableArray pinned_args(total_in_args); + // Current stack slot for storing register based array argument + int pinned_slot = oop_handle_offset; + // Mark location of rbp, // map->set_callee_saved(VMRegImpl::stack2reg( stack_slots - 2), stack_slots * 2, 0, rbp->as_VMReg()); @@ -1885,7 +1982,28 @@ switch (in_sig_bt[i]) { case T_ARRAY: if (is_critical_native) { - unpack_array_argument(masm, in_regs[i], in_elem_bt[i], out_regs[c_arg + 1], out_regs[c_arg]); + VMRegPair in_arg = in_regs[i]; + if (Universe::heap()->supports_object_pinning()) { + // gen_pin_object handles save and restore + // of any clobbered registers + gen_pin_object(masm, thread, in_arg); + pinned_args.append(i); + + // rax has pinned array + VMRegPair result_reg(rax->as_VMReg()); + if (!in_arg.first()->is_stack()) { + assert(pinned_slot <= stack_slots, "overflow"); + simple_move32(masm, result_reg, VMRegImpl::stack2reg(pinned_slot)); + pinned_slot += VMRegImpl::slots_per_word; + } else { + // Write back pinned value, it will be used to unpin this argument + __ movptr(Address(rbp, reg2offset_in(in_arg.first())), result_reg.first()->as_Register()); + } + // We have the array in register, use it + in_arg = result_reg; + } + + unpack_array_argument(masm, in_arg, in_elem_bt[i], out_regs[c_arg + 1], out_regs[c_arg]); c_arg++; break; } @@ -2078,6 +2196,26 @@ default : ShouldNotReachHere(); } + // unpin pinned arguments + pinned_slot = oop_handle_offset; + if (pinned_args.length() > 0) { + // save return value that may be overwritten otherwise. + save_native_result(masm, ret_type, stack_slots); + for (int index = 0; index < pinned_args.length(); index ++) { + int i = pinned_args.at(index); + assert(pinned_slot <= stack_slots, "overflow"); + if (!in_regs[i].first()->is_stack()) { + int offset = pinned_slot * VMRegImpl::stack_slot_size; + __ movl(in_regs[i].first()->as_Register(), Address(rsp, offset)); + pinned_slot += VMRegImpl::slots_per_word; + } + // gen_pin_object handles save and restore + // of any other clobbered registers + gen_unpin_object(masm, thread, in_regs[i]); + } + restore_native_result(masm, ret_type, stack_slots); + } + // Switch thread to "native transition" state before reading the synchronization state. // This additional state is necessary because reading and testing the synchronization // state is not atomic w.r.t. GC, as this scenario demonstrates: diff -r 496bbf554c5c -r 38176d1c5ec2 src/hotspot/cpu/x86/sharedRuntime_x86_64.cpp --- a/src/hotspot/cpu/x86/sharedRuntime_x86_64.cpp Wed Oct 16 01:16:12 2019 +0200 +++ b/src/hotspot/cpu/x86/sharedRuntime_x86_64.cpp Wed Oct 16 11:23:46 2019 +0200 @@ -41,6 +41,7 @@ #include "memory/resourceArea.hpp" #include "memory/universe.hpp" #include "oops/compiledICHolder.hpp" +#include "oops/klass.inline.hpp" #include "runtime/safepointMechanism.hpp" #include "runtime/sharedRuntime.hpp" #include "runtime/vframeArray.hpp" diff -r 496bbf554c5c -r 38176d1c5ec2 src/hotspot/os/aix/os_aix.cpp --- a/src/hotspot/os/aix/os_aix.cpp Wed Oct 16 01:16:12 2019 +0200 +++ b/src/hotspot/os/aix/os_aix.cpp Wed Oct 16 11:23:46 2019 +0200 @@ -2643,8 +2643,24 @@ 60 // 11 CriticalPriority }; +static int prio_init() { + if (ThreadPriorityPolicy == 1) { + if (geteuid() != 0) { + if (!FLAG_IS_DEFAULT(ThreadPriorityPolicy)) { + warning("-XX:ThreadPriorityPolicy=1 may require system level permission, " \ + "e.g., being the root user. If the necessary permission is not " \ + "possessed, changes to priority will be silently ignored."); + } + } + } + if (UseCriticalJavaThreadPriority) { + os::java_to_os_priority[MaxPriority] = os::java_to_os_priority[CriticalPriority]; + } + return 0; +} + OSReturn os::set_native_priority(Thread* thread, int newpri) { - if (!UseThreadPriorities) return OS_OK; + if (!UseThreadPriorities || ThreadPriorityPolicy == 0) return OS_OK; pthread_t thr = thread->osthread()->pthread_id(); int policy = SCHED_OTHER; struct sched_param param; @@ -2659,7 +2675,7 @@ } OSReturn os::get_native_priority(const Thread* const thread, int *priority_ptr) { - if (!UseThreadPriorities) { + if (!UseThreadPriorities || ThreadPriorityPolicy == 0) { *priority_ptr = java_to_os_priority[NormPriority]; return OS_OK; } @@ -2756,7 +2772,7 @@ os::SuspendResume::State state = osthread->sr.suspended(); if (state == os::SuspendResume::SR_SUSPENDED) { sigset_t suspend_set; // signals for sigsuspend() - + sigemptyset(&suspend_set); // get current set of blocked signals and unblock resume signal pthread_sigmask(SIG_BLOCK, NULL, &suspend_set); sigdelset(&suspend_set, SR_signum); @@ -3042,6 +3058,7 @@ // try to honor the signal mask sigset_t oset; + sigemptyset(&oset); pthread_sigmask(SIG_SETMASK, &(actp->sa_mask), &oset); // call into the chained handler @@ -3052,7 +3069,7 @@ } // restore the signal mask - pthread_sigmask(SIG_SETMASK, &oset, 0); + pthread_sigmask(SIG_SETMASK, &oset, NULL); } // Tell jvm's signal handler the signal is taken care of. return true; @@ -3568,6 +3585,9 @@ } } + // initialize thread priority policy + prio_init(); + return JNI_OK; } @@ -4009,7 +4029,7 @@ void os::pause() { char filename[MAX_PATH]; if (PauseAtStartupFile && PauseAtStartupFile[0]) { - jio_snprintf(filename, MAX_PATH, PauseAtStartupFile); + jio_snprintf(filename, MAX_PATH, "%s", PauseAtStartupFile); } else { jio_snprintf(filename, MAX_PATH, "./vm.paused.%d", current_process_id()); } diff -r 496bbf554c5c -r 38176d1c5ec2 src/hotspot/os/bsd/os_bsd.cpp --- a/src/hotspot/os/bsd/os_bsd.cpp Wed Oct 16 01:16:12 2019 +0200 +++ b/src/hotspot/os/bsd/os_bsd.cpp Wed Oct 16 11:23:46 2019 +0200 @@ -3671,7 +3671,7 @@ void os::pause() { char filename[MAX_PATH]; if (PauseAtStartupFile && PauseAtStartupFile[0]) { - jio_snprintf(filename, MAX_PATH, PauseAtStartupFile); + jio_snprintf(filename, MAX_PATH, "%s", PauseAtStartupFile); } else { jio_snprintf(filename, MAX_PATH, "./vm.paused.%d", current_process_id()); } diff -r 496bbf554c5c -r 38176d1c5ec2 src/hotspot/os/solaris/os_solaris.cpp --- a/src/hotspot/os/solaris/os_solaris.cpp Wed Oct 16 01:16:12 2019 +0200 +++ b/src/hotspot/os/solaris/os_solaris.cpp Wed Oct 16 11:23:46 2019 +0200 @@ -4428,7 +4428,7 @@ void os::pause() { char filename[MAX_PATH]; if (PauseAtStartupFile && PauseAtStartupFile[0]) { - jio_snprintf(filename, MAX_PATH, PauseAtStartupFile); + jio_snprintf(filename, MAX_PATH, "%s", PauseAtStartupFile); } else { jio_snprintf(filename, MAX_PATH, "./vm.paused.%d", current_process_id()); } diff -r 496bbf554c5c -r 38176d1c5ec2 src/hotspot/os/windows/os_windows.cpp --- a/src/hotspot/os/windows/os_windows.cpp Wed Oct 16 01:16:12 2019 +0200 +++ b/src/hotspot/os/windows/os_windows.cpp Wed Oct 16 11:23:46 2019 +0200 @@ -4975,7 +4975,7 @@ void os::pause() { char filename[MAX_PATH]; if (PauseAtStartupFile && PauseAtStartupFile[0]) { - jio_snprintf(filename, MAX_PATH, PauseAtStartupFile); + jio_snprintf(filename, MAX_PATH, "%s", PauseAtStartupFile); } else { jio_snprintf(filename, MAX_PATH, "./vm.paused.%d", current_process_id()); } diff -r 496bbf554c5c -r 38176d1c5ec2 src/hotspot/share/aot/aotCodeHeap.cpp --- a/src/hotspot/share/aot/aotCodeHeap.cpp Wed Oct 16 01:16:12 2019 +0200 +++ b/src/hotspot/share/aot/aotCodeHeap.cpp Wed Oct 16 11:23:46 2019 +0200 @@ -37,6 +37,7 @@ #include "memory/allocation.inline.hpp" #include "memory/universe.hpp" #include "oops/compressedOops.hpp" +#include "oops/klass.inline.hpp" #include "oops/method.inline.hpp" #include "runtime/deoptimization.hpp" #include "runtime/handles.inline.hpp" diff -r 496bbf554c5c -r 38176d1c5ec2 src/hotspot/share/aot/aotCompiledMethod.cpp --- a/src/hotspot/share/aot/aotCompiledMethod.cpp Wed Oct 16 01:16:12 2019 +0200 +++ b/src/hotspot/share/aot/aotCompiledMethod.cpp Wed Oct 16 11:23:46 2019 +0200 @@ -32,6 +32,7 @@ #include "compiler/compilerOracle.hpp" #include "gc/shared/cardTableBarrierSet.hpp" #include "gc/shared/collectedHeap.hpp" +#include "oops/klass.inline.hpp" #include "oops/method.inline.hpp" #include "runtime/frame.inline.hpp" #include "runtime/handles.inline.hpp" diff -r 496bbf554c5c -r 38176d1c5ec2 src/hotspot/share/c1/c1_GraphBuilder.cpp --- a/src/hotspot/share/c1/c1_GraphBuilder.cpp Wed Oct 16 01:16:12 2019 +0200 +++ b/src/hotspot/share/c1/c1_GraphBuilder.cpp Wed Oct 16 11:23:46 2019 +0200 @@ -33,13 +33,13 @@ #include "ci/ciKlass.hpp" #include "ci/ciMemberName.hpp" #include "ci/ciUtilities.inline.hpp" +#include "compiler/compilationPolicy.hpp" #include "compiler/compileBroker.hpp" #include "interpreter/bytecode.hpp" #include "jfr/jfrEvents.hpp" #include "memory/resourceArea.hpp" #include "oops/oop.inline.hpp" #include "runtime/sharedRuntime.hpp" -#include "runtime/compilationPolicy.hpp" #include "runtime/vm_version.hpp" #include "utilities/bitMap.inline.hpp" diff -r 496bbf554c5c -r 38176d1c5ec2 src/hotspot/share/c1/c1_LIRGenerator.cpp --- a/src/hotspot/share/c1/c1_LIRGenerator.cpp Wed Oct 16 01:16:12 2019 +0200 +++ b/src/hotspot/share/c1/c1_LIRGenerator.cpp Wed Oct 16 11:23:46 2019 +0200 @@ -36,6 +36,7 @@ #include "ci/ciUtilities.hpp" #include "gc/shared/barrierSet.hpp" #include "gc/shared/c1/barrierSetC1.hpp" +#include "oops/klass.inline.hpp" #include "runtime/arguments.hpp" #include "runtime/sharedRuntime.hpp" #include "runtime/stubRoutines.hpp" diff -r 496bbf554c5c -r 38176d1c5ec2 src/hotspot/share/c1/c1_Runtime1.cpp --- a/src/hotspot/share/c1/c1_Runtime1.cpp Wed Oct 16 01:16:12 2019 +0200 +++ b/src/hotspot/share/c1/c1_Runtime1.cpp Wed Oct 16 11:23:46 2019 +0200 @@ -37,6 +37,7 @@ #include "code/pcDesc.hpp" #include "code/scopeDesc.hpp" #include "code/vtableStubs.hpp" +#include "compiler/compilationPolicy.hpp" #include "compiler/disassembler.hpp" #include "gc/shared/barrierSet.hpp" #include "gc/shared/c1/barrierSetC1.hpp" @@ -55,7 +56,6 @@ #include "oops/oop.inline.hpp" #include "runtime/atomic.hpp" #include "runtime/biasedLocking.hpp" -#include "runtime/compilationPolicy.hpp" #include "runtime/fieldDescriptor.inline.hpp" #include "runtime/frame.inline.hpp" #include "runtime/handles.inline.hpp" diff -r 496bbf554c5c -r 38176d1c5ec2 src/hotspot/share/c1/c1_ValueStack.cpp --- a/src/hotspot/share/c1/c1_ValueStack.cpp Wed Oct 16 01:16:12 2019 +0200 +++ b/src/hotspot/share/c1/c1_ValueStack.cpp Wed Oct 16 11:23:46 2019 +0200 @@ -42,31 +42,21 @@ verify(); } - ValueStack::ValueStack(ValueStack* copy_from, Kind kind, int bci) : _scope(copy_from->scope()) , _caller_state(copy_from->caller_state()) , _bci(bci) , _kind(kind) - , _locals() - , _stack() + , _locals(copy_from->locals_size_for_copy(kind)) + , _stack(copy_from->stack_size_for_copy(kind)) , _locks(copy_from->locks_size() == 0 ? NULL : new Values(copy_from->locks_size())) { assert(kind != EmptyExceptionState || !Compilation::current()->env()->should_retain_local_variables(), "need locals"); if (kind != EmptyExceptionState) { - // only allocate space if we need to copy the locals-array - _locals = Values(copy_from->locals_size()); _locals.appendAll(©_from->_locals); } if (kind != ExceptionState && kind != EmptyExceptionState) { - if (kind == Parsing) { - // stack will be modified, so reserve enough space to avoid resizing - _stack = Values(scope()->method()->max_stack()); - } else { - // stack will not be modified, so do not waste space - _stack = Values(copy_from->stack_size()); - } _stack.appendAll(©_from->_stack); } @@ -77,6 +67,25 @@ verify(); } +int ValueStack::locals_size_for_copy(Kind kind) const { + if (kind != EmptyExceptionState) { + return locals_size(); + } + return 0; +} + +int ValueStack::stack_size_for_copy(Kind kind) const { + if (kind != ExceptionState && kind != EmptyExceptionState) { + if (kind == Parsing) { + // stack will be modified, so reserve enough space to avoid resizing + return scope()->method()->max_stack(); + } else { + // stack will not be modified, so do not waste space + return stack_size(); + } + } + return 0; +} bool ValueStack::is_same(ValueStack* s) { if (scope() != s->scope()) return false; diff -r 496bbf554c5c -r 38176d1c5ec2 src/hotspot/share/c1/c1_ValueStack.hpp --- a/src/hotspot/share/c1/c1_ValueStack.hpp Wed Oct 16 01:16:12 2019 +0200 +++ b/src/hotspot/share/c1/c1_ValueStack.hpp Wed Oct 16 11:23:46 2019 +0200 @@ -65,6 +65,8 @@ // for simplified copying ValueStack(ValueStack* copy_from, Kind kind, int bci); + int locals_size_for_copy(Kind kind) const; + int stack_size_for_copy(Kind kind) const; public: // creation ValueStack(IRScope* scope, ValueStack* caller_state); diff -r 496bbf554c5c -r 38176d1c5ec2 src/hotspot/share/ci/ciMetadata.hpp --- a/src/hotspot/share/ci/ciMetadata.hpp Wed Oct 16 01:16:12 2019 +0200 +++ b/src/hotspot/share/ci/ciMetadata.hpp Wed Oct 16 11:23:46 2019 +0200 @@ -51,7 +51,6 @@ virtual bool is_metadata() const { return true; } virtual bool is_type() const { return false; } - virtual bool is_cpcache() const { return false; } virtual bool is_return_address() const { return false; } virtual bool is_method() const { return false; } virtual bool is_method_data() const { return false; } diff -r 496bbf554c5c -r 38176d1c5ec2 src/hotspot/share/classfile/classLoader.cpp --- a/src/hotspot/share/classfile/classLoader.cpp Wed Oct 16 01:16:12 2019 +0200 +++ b/src/hotspot/share/classfile/classLoader.cpp Wed Oct 16 11:23:46 2019 +0200 @@ -57,7 +57,6 @@ #include "oops/symbol.hpp" #include "prims/jvm_misc.hpp" #include "runtime/arguments.hpp" -#include "runtime/compilationPolicy.hpp" #include "runtime/handles.inline.hpp" #include "runtime/init.hpp" #include "runtime/interfaceSupport.inline.hpp" diff -r 496bbf554c5c -r 38176d1c5ec2 src/hotspot/share/classfile/javaClasses.cpp --- a/src/hotspot/share/classfile/javaClasses.cpp Wed Oct 16 01:16:12 2019 +0200 +++ b/src/hotspot/share/classfile/javaClasses.cpp Wed Oct 16 11:23:46 2019 +0200 @@ -384,13 +384,17 @@ } jstring js = NULL; - { JavaThread* thread = (JavaThread*)THREAD; - assert(thread->is_Java_thread(), "must be java thread"); + { + assert(THREAD->is_Java_thread(), "must be java thread"); + JavaThread* thread = (JavaThread*)THREAD; HandleMark hm(thread); ThreadToNativeFromVM ttn(thread); js = (_to_java_string_fn)(thread->jni_environment(), str); } - return Handle(THREAD, JNIHandles::resolve(js)); + + Handle native_platform_string(THREAD, JNIHandles::resolve(js)); + JNIHandles::destroy_local(js); // destroy local JNIHandle. + return native_platform_string; } // Converts a Java String to a native C string that can be used for diff -r 496bbf554c5c -r 38176d1c5ec2 src/hotspot/share/classfile/systemDictionaryShared.cpp --- a/src/hotspot/share/classfile/systemDictionaryShared.cpp Wed Oct 16 01:16:12 2019 +0200 +++ b/src/hotspot/share/classfile/systemDictionaryShared.cpp Wed Oct 16 11:23:46 2019 +0200 @@ -905,14 +905,9 @@ return NULL; } - const RunTimeSharedClassInfo* record = find_record(&_unregistered_dictionary, class_name); + const RunTimeSharedClassInfo* record = find_record(&_unregistered_dictionary, &_dynamic_unregistered_dictionary, class_name); if (record == NULL) { - if (DynamicArchive::is_mapped()) { - record = find_record(&_dynamic_unregistered_dictionary, class_name); - } - if (record == NULL) { - return NULL; - } + return NULL; } int clsfile_size = cfs->length(); @@ -1412,29 +1407,34 @@ } const RunTimeSharedClassInfo* -SystemDictionaryShared::find_record(RunTimeSharedDictionary* dict, Symbol* name) { - if (UseSharedSpaces) { - unsigned int hash = primitive_hash(name); - return dict->lookup(name, hash, 0); - } else { +SystemDictionaryShared::find_record(RunTimeSharedDictionary* static_dict, RunTimeSharedDictionary* dynamic_dict, Symbol* name) { + if (!UseSharedSpaces || !name->is_shared()) { + // The names of all shared classes must also be a shared Symbol. return NULL; } + + unsigned int hash = primitive_hash(name); + const RunTimeSharedClassInfo* record = NULL; + if (!MetaspaceShared::is_shared_dynamic(name)) { + // The names of all shared classes in the static dict must also be in the + // static archive + record = static_dict->lookup(name, hash, 0); + } + + if (record == NULL && DynamicArchive::is_mapped()) { + record = dynamic_dict->lookup(name, hash, 0); + } + + return record; } InstanceKlass* SystemDictionaryShared::find_builtin_class(Symbol* name) { - const RunTimeSharedClassInfo* record = find_record(&_builtin_dictionary, name); - if (record) { + const RunTimeSharedClassInfo* record = find_record(&_builtin_dictionary, &_dynamic_builtin_dictionary, name); + if (record != NULL) { return record->_klass; + } else { + return NULL; } - - if (DynamicArchive::is_mapped()) { - record = find_record(&_dynamic_builtin_dictionary, name); - if (record) { - return record->_klass; - } - } - - return NULL; } void SystemDictionaryShared::update_shared_entry(InstanceKlass* k, int id) { diff -r 496bbf554c5c -r 38176d1c5ec2 src/hotspot/share/classfile/systemDictionaryShared.hpp --- a/src/hotspot/share/classfile/systemDictionaryShared.hpp Wed Oct 16 01:16:12 2019 +0200 +++ b/src/hotspot/share/classfile/systemDictionaryShared.hpp Wed Oct 16 11:23:46 2019 +0200 @@ -223,7 +223,9 @@ public: static InstanceKlass* find_builtin_class(Symbol* class_name); - static const RunTimeSharedClassInfo* find_record(RunTimeSharedDictionary* dict, Symbol* name); + static const RunTimeSharedClassInfo* find_record(RunTimeSharedDictionary* static_dict, + RunTimeSharedDictionary* dynamic_dict, + Symbol* name); static bool has_platform_or_app_classes(); diff -r 496bbf554c5c -r 38176d1c5ec2 src/hotspot/share/classfile/verificationType.cpp --- a/src/hotspot/share/classfile/verificationType.cpp Wed Oct 16 01:16:12 2019 +0200 +++ b/src/hotspot/share/classfile/verificationType.cpp Wed Oct 16 11:23:46 2019 +0200 @@ -28,6 +28,7 @@ #include "classfile/verificationType.hpp" #include "classfile/verifier.hpp" #include "logging/log.hpp" +#include "oops/klass.inline.hpp" #include "runtime/handles.inline.hpp" VerificationType VerificationType::from_tag(u1 tag) { diff -r 496bbf554c5c -r 38176d1c5ec2 src/hotspot/share/code/codeCache.cpp --- a/src/hotspot/share/code/codeCache.cpp Wed Oct 16 01:16:12 2019 +0200 +++ b/src/hotspot/share/code/codeCache.cpp Wed Oct 16 11:23:46 2019 +0200 @@ -33,6 +33,7 @@ #include "code/icBuffer.hpp" #include "code/nmethod.hpp" #include "code/pcDesc.hpp" +#include "compiler/compilationPolicy.hpp" #include "compiler/compileBroker.hpp" #include "jfr/jfrEvents.hpp" #include "logging/log.hpp" @@ -46,7 +47,6 @@ #include "oops/oop.inline.hpp" #include "oops/verifyOopClosure.hpp" #include "runtime/arguments.hpp" -#include "runtime/compilationPolicy.hpp" #include "runtime/deoptimization.hpp" #include "runtime/handles.inline.hpp" #include "runtime/icache.hpp" diff -r 496bbf554c5c -r 38176d1c5ec2 src/hotspot/share/compiler/compilationPolicy.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/hotspot/share/compiler/compilationPolicy.cpp Wed Oct 16 11:23:46 2019 +0200 @@ -0,0 +1,506 @@ +/* + * Copyright (c) 2000, 2019, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * 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.inline.hpp" +#include "code/compiledIC.hpp" +#include "code/nmethod.hpp" +#include "code/scopeDesc.hpp" +#include "compiler/compilationPolicy.hpp" +#include "compiler/tieredThresholdPolicy.hpp" +#include "interpreter/interpreter.hpp" +#include "memory/resourceArea.hpp" +#include "oops/methodData.hpp" +#include "oops/method.inline.hpp" +#include "oops/oop.inline.hpp" +#include "prims/nativeLookup.hpp" +#include "runtime/frame.hpp" +#include "runtime/handles.inline.hpp" +#include "runtime/stubRoutines.hpp" +#include "runtime/thread.hpp" +#include "runtime/vframe.hpp" +#include "runtime/vmOperations.hpp" +#include "utilities/events.hpp" +#include "utilities/globalDefinitions.hpp" + +#ifdef COMPILER1 +#include "c1/c1_Compiler.hpp" +#endif +#ifdef COMPILER2 +#include "opto/c2compiler.hpp" +#endif + +CompilationPolicy* CompilationPolicy::_policy; + +// Determine compilation policy based on command line argument +void compilationPolicy_init() { + #ifdef TIERED + if (TieredCompilation) { + CompilationPolicy::set_policy(new TieredThresholdPolicy()); + } else { + CompilationPolicy::set_policy(new SimpleCompPolicy()); + } + #else + CompilationPolicy::set_policy(new SimpleCompPolicy()); + #endif + + CompilationPolicy::policy()->initialize(); +} + +// Returns true if m must be compiled before executing it +// This is intended to force compiles for methods (usually for +// debugging) that would otherwise be interpreted for some reason. +bool CompilationPolicy::must_be_compiled(const methodHandle& m, int comp_level) { + // Don't allow Xcomp to cause compiles in replay mode + if (ReplayCompiles) return false; + + if (m->has_compiled_code()) return false; // already compiled + if (!can_be_compiled(m, comp_level)) return false; + + return !UseInterpreter || // must compile all methods + (UseCompiler && AlwaysCompileLoopMethods && m->has_loops() && CompileBroker::should_compile_new_jobs()); // eagerly compile loop methods +} + +void CompilationPolicy::compile_if_required(const methodHandle& selected_method, TRAPS) { + if (must_be_compiled(selected_method)) { + // This path is unusual, mostly used by the '-Xcomp' stress test mode. + + // Note: with several active threads, the must_be_compiled may be true + // while can_be_compiled is false; remove assert + // assert(CompilationPolicy::can_be_compiled(selected_method), "cannot compile"); + if (!THREAD->can_call_java() || THREAD->is_Compiler_thread()) { + // don't force compilation, resolve was on behalf of compiler + return; + } + if (selected_method->method_holder()->is_not_initialized()) { + // 'is_not_initialized' means not only '!is_initialized', but also that + // initialization has not been started yet ('!being_initialized') + // Do not force compilation of methods in uninitialized classes. + // Note that doing this would throw an assert later, + // in CompileBroker::compile_method. + // We sometimes use the link resolver to do reflective lookups + // even before classes are initialized. + return; + } + CompileBroker::compile_method(selected_method, InvocationEntryBci, + CompilationPolicy::policy()->initial_compile_level(), + methodHandle(), 0, CompileTask::Reason_MustBeCompiled, CHECK); + } +} + +// Returns true if m is allowed to be compiled +bool CompilationPolicy::can_be_compiled(const methodHandle& m, int comp_level) { + // allow any levels for WhiteBox + assert(WhiteBoxAPI || comp_level == CompLevel_all || is_compile(comp_level), "illegal compilation level"); + + if (m->is_abstract()) return false; + if (DontCompileHugeMethods && m->code_size() > HugeMethodLimit) return false; + + // Math intrinsics should never be compiled as this can lead to + // monotonicity problems because the interpreter will prefer the + // compiled code to the intrinsic version. This can't happen in + // production because the invocation counter can't be incremented + // but we shouldn't expose the system to this problem in testing + // modes. + if (!AbstractInterpreter::can_be_compiled(m)) { + return false; + } + if (comp_level == CompLevel_all) { + if (TieredCompilation) { + // enough to be compilable at any level for tiered + return !m->is_not_compilable(CompLevel_simple) || !m->is_not_compilable(CompLevel_full_optimization); + } else { + // must be compilable at available level for non-tiered + return !m->is_not_compilable(CompLevel_highest_tier); + } + } else if (is_compile(comp_level)) { + return !m->is_not_compilable(comp_level); + } + return false; +} + +// Returns true if m is allowed to be osr compiled +bool CompilationPolicy::can_be_osr_compiled(const methodHandle& m, int comp_level) { + bool result = false; + if (comp_level == CompLevel_all) { + if (TieredCompilation) { + // enough to be osr compilable at any level for tiered + result = !m->is_not_osr_compilable(CompLevel_simple) || !m->is_not_osr_compilable(CompLevel_full_optimization); + } else { + // must be osr compilable at available level for non-tiered + result = !m->is_not_osr_compilable(CompLevel_highest_tier); + } + } else if (is_compile(comp_level)) { + result = !m->is_not_osr_compilable(comp_level); + } + return (result && can_be_compiled(m, comp_level)); +} + +bool CompilationPolicy::is_compilation_enabled() { + // NOTE: CompileBroker::should_compile_new_jobs() checks for UseCompiler + return CompileBroker::should_compile_new_jobs(); +} + +CompileTask* CompilationPolicy::select_task_helper(CompileQueue* compile_queue) { + // Remove unloaded methods from the queue + for (CompileTask* task = compile_queue->first(); task != NULL; ) { + CompileTask* next = task->next(); + if (task->is_unloaded()) { + compile_queue->remove_and_mark_stale(task); + } + task = next; + } +#if INCLUDE_JVMCI + if (UseJVMCICompiler && !BackgroundCompilation) { + /* + * In blocking compilation mode, the CompileBroker will make + * compilations submitted by a JVMCI compiler thread non-blocking. These + * compilations should be scheduled after all blocking compilations + * to service non-compiler related compilations sooner and reduce the + * chance of such compilations timing out. + */ + for (CompileTask* task = compile_queue->first(); task != NULL; task = task->next()) { + if (task->is_blocking()) { + return task; + } + } + } +#endif + return compile_queue->first(); +} + +#ifndef PRODUCT +void SimpleCompPolicy::trace_osr_completion(nmethod* osr_nm) { + if (TraceOnStackReplacement) { + if (osr_nm == NULL) tty->print_cr("compilation failed"); + else tty->print_cr("nmethod " INTPTR_FORMAT, p2i(osr_nm)); + } +} +#endif // !PRODUCT + +void SimpleCompPolicy::initialize() { + // Setup the compiler thread numbers + if (CICompilerCountPerCPU) { + // Example: if CICompilerCountPerCPU is true, then we get + // max(log2(8)-1,1) = 2 compiler threads on an 8-way machine. + // May help big-app startup time. + _compiler_count = MAX2(log2_int(os::active_processor_count())-1,1); + // Make sure there is enough space in the code cache to hold all the compiler buffers + size_t buffer_size = 1; +#ifdef COMPILER1 + buffer_size = is_client_compilation_mode_vm() ? Compiler::code_buffer_size() : buffer_size; +#endif +#ifdef COMPILER2 + buffer_size = is_server_compilation_mode_vm() ? C2Compiler::initial_code_buffer_size() : buffer_size; +#endif + int max_count = (ReservedCodeCacheSize - (CodeCacheMinimumUseSpace DEBUG_ONLY(* 3))) / (int)buffer_size; + if (_compiler_count > max_count) { + // Lower the compiler count such that all buffers fit into the code cache + _compiler_count = MAX2(max_count, 1); + } + FLAG_SET_ERGO(CICompilerCount, _compiler_count); + } else { + _compiler_count = CICompilerCount; + } +} + +// Note: this policy is used ONLY if TieredCompilation is off. +// compiler_count() behaves the following way: +// - with TIERED build (with both COMPILER1 and COMPILER2 defined) it should return +// zero for the c1 compilation levels in server compilation mode runs +// and c2 compilation levels in client compilation mode runs. +// - with COMPILER2 not defined it should return zero for c2 compilation levels. +// - with COMPILER1 not defined it should return zero for c1 compilation levels. +// - if neither is defined - always return zero. +int SimpleCompPolicy::compiler_count(CompLevel comp_level) { + assert(!TieredCompilation, "This policy should not be used with TieredCompilation"); + if (COMPILER2_PRESENT(is_server_compilation_mode_vm() && is_c2_compile(comp_level) ||) + is_client_compilation_mode_vm() && is_c1_compile(comp_level)) { + return _compiler_count; + } + return 0; +} + +void SimpleCompPolicy::reset_counter_for_invocation_event(const methodHandle& m) { + // Make sure invocation and backedge counter doesn't overflow again right away + // as would be the case for native methods. + + // BUT also make sure the method doesn't look like it was never executed. + // Set carry bit and reduce counter's value to min(count, CompileThreshold/2). + MethodCounters* mcs = m->method_counters(); + assert(mcs != NULL, "MethodCounters cannot be NULL for profiling"); + mcs->invocation_counter()->set_carry(); + mcs->backedge_counter()->set_carry(); + + assert(!m->was_never_executed(), "don't reset to 0 -- could be mistaken for never-executed"); +} + +void SimpleCompPolicy::reset_counter_for_back_branch_event(const methodHandle& m) { + // Delay next back-branch event but pump up invocation counter to trigger + // whole method compilation. + MethodCounters* mcs = m->method_counters(); + assert(mcs != NULL, "MethodCounters cannot be NULL for profiling"); + InvocationCounter* i = mcs->invocation_counter(); + InvocationCounter* b = mcs->backedge_counter(); + + // Don't set invocation_counter's value too low otherwise the method will + // look like immature (ic < ~5300) which prevents the inlining based on + // the type profiling. + i->set(i->state(), CompileThreshold); + // Don't reset counter too low - it is used to check if OSR method is ready. + b->set(b->state(), CompileThreshold / 2); +} + +// +// CounterDecay +// +// Iterates through invocation counters and decrements them. This +// is done at each safepoint. +// +class CounterDecay : public AllStatic { + static jlong _last_timestamp; + static void do_method(Method* m) { + MethodCounters* mcs = m->method_counters(); + if (mcs != NULL) { + mcs->invocation_counter()->decay(); + } + } +public: + static void decay(); + static bool is_decay_needed() { + return (os::javaTimeMillis() - _last_timestamp) > CounterDecayMinIntervalLength; + } +}; + +jlong CounterDecay::_last_timestamp = 0; + +void CounterDecay::decay() { + _last_timestamp = os::javaTimeMillis(); + + // This operation is going to be performed only at the end of a safepoint + // and hence GC's will not be going on, all Java mutators are suspended + // at this point and hence SystemDictionary_lock is also not needed. + assert(SafepointSynchronize::is_at_safepoint(), "can only be executed at a safepoint"); + size_t nclasses = ClassLoaderDataGraph::num_instance_classes(); + size_t classes_per_tick = nclasses * (CounterDecayMinIntervalLength * 1e-3 / + CounterHalfLifeTime); + for (size_t i = 0; i < classes_per_tick; i++) { + InstanceKlass* k = ClassLoaderDataGraph::try_get_next_class(); + if (k != NULL) { + k->methods_do(do_method); + } + } +} + +// Called at the end of the safepoint +void SimpleCompPolicy::do_safepoint_work() { + if(UseCounterDecay && CounterDecay::is_decay_needed()) { + CounterDecay::decay(); + } +} + +void SimpleCompPolicy::reprofile(ScopeDesc* trap_scope, bool is_osr) { + ScopeDesc* sd = trap_scope; + MethodCounters* mcs; + InvocationCounter* c; + for (; !sd->is_top(); sd = sd->sender()) { + mcs = sd->method()->method_counters(); + if (mcs != NULL) { + // Reset ICs of inlined methods, since they can trigger compilations also. + mcs->invocation_counter()->reset(); + } + } + mcs = sd->method()->method_counters(); + if (mcs != NULL) { + c = mcs->invocation_counter(); + if (is_osr) { + // It was an OSR method, so bump the count higher. + c->set(c->state(), CompileThreshold); + } else { + c->reset(); + } + mcs->backedge_counter()->reset(); + } +} + +// This method can be called by any component of the runtime to notify the policy +// that it's recommended to delay the compilation of this method. +void SimpleCompPolicy::delay_compilation(Method* method) { + MethodCounters* mcs = method->method_counters(); + if (mcs != NULL) { + mcs->invocation_counter()->decay(); + mcs->backedge_counter()->decay(); + } +} + +void SimpleCompPolicy::disable_compilation(Method* method) { + MethodCounters* mcs = method->method_counters(); + if (mcs != NULL) { + mcs->invocation_counter()->set_state(InvocationCounter::wait_for_nothing); + mcs->backedge_counter()->set_state(InvocationCounter::wait_for_nothing); + } +} + +CompileTask* SimpleCompPolicy::select_task(CompileQueue* compile_queue) { + return select_task_helper(compile_queue); +} + +bool SimpleCompPolicy::is_mature(Method* method) { + MethodData* mdo = method->method_data(); + assert(mdo != NULL, "Should be"); + uint current = mdo->mileage_of(method); + uint initial = mdo->creation_mileage(); + if (current < initial) + return true; // some sort of overflow + uint target; + if (ProfileMaturityPercentage <= 0) + target = (uint) -ProfileMaturityPercentage; // absolute value + else + target = (uint)( (ProfileMaturityPercentage * CompileThreshold) / 100 ); + return (current >= initial + target); +} + +nmethod* SimpleCompPolicy::event(const methodHandle& method, const methodHandle& inlinee, int branch_bci, + int bci, CompLevel comp_level, CompiledMethod* nm, JavaThread* thread) { + assert(comp_level == CompLevel_none, "This should be only called from the interpreter"); + NOT_PRODUCT(trace_frequency_counter_overflow(method, branch_bci, bci)); + if (JvmtiExport::can_post_interpreter_events() && thread->is_interp_only_mode()) { + // If certain JVMTI events (e.g. frame pop event) are requested then the + // thread is forced to remain in interpreted code. This is + // implemented partly by a check in the run_compiled_code + // section of the interpreter whether we should skip running + // compiled code, and partly by skipping OSR compiles for + // interpreted-only threads. + if (bci != InvocationEntryBci) { + reset_counter_for_back_branch_event(method); + return NULL; + } + } + if (ReplayCompiles) { + // Don't trigger other compiles in testing mode + if (bci == InvocationEntryBci) { + reset_counter_for_invocation_event(method); + } else { + reset_counter_for_back_branch_event(method); + } + return NULL; + } + + if (bci == InvocationEntryBci) { + // when code cache is full, compilation gets switched off, UseCompiler + // is set to false + if (!method->has_compiled_code() && UseCompiler) { + method_invocation_event(method, thread); + } else { + // Force counter overflow on method entry, even if no compilation + // happened. (The method_invocation_event call does this also.) + reset_counter_for_invocation_event(method); + } + // compilation at an invocation overflow no longer goes and retries test for + // compiled method. We always run the loser of the race as interpreted. + // so return NULL + return NULL; + } else { + // counter overflow in a loop => try to do on-stack-replacement + nmethod* osr_nm = method->lookup_osr_nmethod_for(bci, CompLevel_highest_tier, true); + NOT_PRODUCT(trace_osr_request(method, osr_nm, bci)); + // when code cache is full, we should not compile any more... + if (osr_nm == NULL && UseCompiler) { + method_back_branch_event(method, bci, thread); + osr_nm = method->lookup_osr_nmethod_for(bci, CompLevel_highest_tier, true); + } + if (osr_nm == NULL) { + reset_counter_for_back_branch_event(method); + return NULL; + } + return osr_nm; + } + return NULL; +} + +#ifndef PRODUCT +void SimpleCompPolicy::trace_frequency_counter_overflow(const methodHandle& m, int branch_bci, int bci) { + if (TraceInvocationCounterOverflow) { + MethodCounters* mcs = m->method_counters(); + assert(mcs != NULL, "MethodCounters cannot be NULL for profiling"); + InvocationCounter* ic = mcs->invocation_counter(); + InvocationCounter* bc = mcs->backedge_counter(); + ResourceMark rm; + if (bci == InvocationEntryBci) { + tty->print("comp-policy cntr ovfl @ %d in entry of ", bci); + } else { + tty->print("comp-policy cntr ovfl @ %d in loop of ", bci); + } + m->print_value(); + tty->cr(); + ic->print(); + bc->print(); + if (ProfileInterpreter) { + if (bci != InvocationEntryBci) { + MethodData* mdo = m->method_data(); + if (mdo != NULL) { + ProfileData *pd = mdo->bci_to_data(branch_bci); + if (pd == NULL) { + tty->print_cr("back branch count = N/A (missing ProfileData)"); + } else { + tty->print_cr("back branch count = %d", pd->as_JumpData()->taken()); + } + } + } + } + } +} + +void SimpleCompPolicy::trace_osr_request(const methodHandle& method, nmethod* osr, int bci) { + if (TraceOnStackReplacement) { + ResourceMark rm; + tty->print(osr != NULL ? "Reused OSR entry for " : "Requesting OSR entry for "); + method->print_short_name(tty); + tty->print_cr(" at bci %d", bci); + } +} +#endif // !PRODUCT + +void SimpleCompPolicy::method_invocation_event(const methodHandle& m, JavaThread* thread) { + const int comp_level = CompLevel_highest_tier; + const int hot_count = m->invocation_count(); + reset_counter_for_invocation_event(m); + + if (is_compilation_enabled() && can_be_compiled(m, comp_level)) { + CompiledMethod* nm = m->code(); + if (nm == NULL ) { + CompileBroker::compile_method(m, InvocationEntryBci, comp_level, m, hot_count, CompileTask::Reason_InvocationCount, thread); + } + } +} + +void SimpleCompPolicy::method_back_branch_event(const methodHandle& m, int bci, JavaThread* thread) { + const int comp_level = CompLevel_highest_tier; + const int hot_count = m->backedge_count(); + + if (is_compilation_enabled() && can_be_osr_compiled(m, comp_level)) { + CompileBroker::compile_method(m, bci, comp_level, m, hot_count, CompileTask::Reason_BackedgeCount, thread); + NOT_PRODUCT(trace_osr_completion(m->lookup_osr_nmethod_for(bci, comp_level, true));) + } +} diff -r 496bbf554c5c -r 38176d1c5ec2 src/hotspot/share/compiler/compilationPolicy.hpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/hotspot/share/compiler/compilationPolicy.hpp Wed Oct 16 11:23:46 2019 +0200 @@ -0,0 +1,113 @@ +/* + * Copyright (c) 2000, 2019, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +#ifndef SHARE_COMPILER_COMPILATIONPOLICY_HPP +#define SHARE_COMPILER_COMPILATIONPOLICY_HPP + +#include "code/nmethod.hpp" +#include "compiler/compileBroker.hpp" +#include "memory/allocation.hpp" +#include "runtime/vmOperations.hpp" +#include "utilities/growableArray.hpp" + +// The CompilationPolicy selects which method (if any) should be compiled. +// It also decides which methods must always be compiled (i.e., are never +// interpreted). +class CompileTask; +class CompileQueue; + +class CompilationPolicy : public CHeapObj { + static CompilationPolicy* _policy; + + // m must be compiled before executing it + static bool must_be_compiled(const methodHandle& m, int comp_level = CompLevel_all); + +public: + // If m must_be_compiled then request a compilation from the CompileBroker. + // This supports the -Xcomp option. + static void compile_if_required(const methodHandle& m, TRAPS); + + // m is allowed to be compiled + static bool can_be_compiled(const methodHandle& m, int comp_level = CompLevel_all); + // m is allowed to be osr compiled + static bool can_be_osr_compiled(const methodHandle& m, int comp_level = CompLevel_all); + static bool is_compilation_enabled(); + static void set_policy(CompilationPolicy* policy) { _policy = policy; } + static CompilationPolicy* policy() { return _policy; } + + static CompileTask* select_task_helper(CompileQueue* compile_queue); + + // Return initial compile level that is used with Xcomp + virtual CompLevel initial_compile_level() = 0; + virtual int compiler_count(CompLevel comp_level) = 0; + // main notification entry, return a pointer to an nmethod if the OSR is required, + // returns NULL otherwise. + virtual nmethod* event(const methodHandle& method, const methodHandle& inlinee, int branch_bci, int bci, CompLevel comp_level, CompiledMethod* nm, JavaThread* thread) = 0; + // safepoint() is called at the end of the safepoint + virtual void do_safepoint_work() = 0; + // reprofile request + virtual void reprofile(ScopeDesc* trap_scope, bool is_osr) = 0; + // delay_compilation(method) can be called by any component of the runtime to notify the policy + // that it's recommended to delay the compilation of this method. + virtual void delay_compilation(Method* method) = 0; + // disable_compilation() is called whenever the runtime decides to disable compilation of the + // specified method. + virtual void disable_compilation(Method* method) = 0; + // Select task is called by CompileBroker. The queue is guaranteed to have at least one + // element and is locked. The function should select one and return it. + virtual CompileTask* select_task(CompileQueue* compile_queue) = 0; + // Tell the runtime if we think a given method is adequately profiled. + virtual bool is_mature(Method* method) = 0; + // Do policy initialization + virtual void initialize() = 0; + virtual bool should_not_inline(ciEnv* env, ciMethod* method) { return false; } +}; + +// A simple compilation policy. +class SimpleCompPolicy : public CompilationPolicy { + int _compiler_count; + private: + static void trace_frequency_counter_overflow(const methodHandle& m, int branch_bci, int bci); + static void trace_osr_request(const methodHandle& method, nmethod* osr, int bci); + static void trace_osr_completion(nmethod* osr_nm); + void reset_counter_for_invocation_event(const methodHandle& method); + void reset_counter_for_back_branch_event(const methodHandle& method); + void method_invocation_event(const methodHandle& m, JavaThread* thread); + void method_back_branch_event(const methodHandle& m, int bci, JavaThread* thread); + public: + SimpleCompPolicy() : _compiler_count(0) { } + virtual CompLevel initial_compile_level() { return CompLevel_highest_tier; } + virtual int compiler_count(CompLevel comp_level); + virtual void do_safepoint_work(); + virtual void reprofile(ScopeDesc* trap_scope, bool is_osr); + virtual void delay_compilation(Method* method); + virtual void disable_compilation(Method* method); + virtual bool is_mature(Method* method); + virtual void initialize(); + virtual CompileTask* select_task(CompileQueue* compile_queue); + virtual nmethod* event(const methodHandle& method, const methodHandle& inlinee, int branch_bci, int bci, CompLevel comp_level, CompiledMethod* nm, JavaThread* thread); +}; + + +#endif // SHARE_COMPILER_COMPILATIONPOLICY_HPP diff -r 496bbf554c5c -r 38176d1c5ec2 src/hotspot/share/compiler/compileBroker.cpp --- a/src/hotspot/share/compiler/compileBroker.cpp Wed Oct 16 01:16:12 2019 +0200 +++ b/src/hotspot/share/compiler/compileBroker.cpp Wed Oct 16 11:23:46 2019 +0200 @@ -30,6 +30,7 @@ #include "code/codeCache.hpp" #include "code/codeHeapState.hpp" #include "code/dependencyContext.hpp" +#include "compiler/compilationPolicy.hpp" #include "compiler/compileBroker.hpp" #include "compiler/compileLog.hpp" #include "compiler/compilerOracle.hpp" @@ -48,7 +49,6 @@ #include "prims/whitebox.hpp" #include "runtime/arguments.hpp" #include "runtime/atomic.hpp" -#include "runtime/compilationPolicy.hpp" #include "runtime/handles.inline.hpp" #include "runtime/init.hpp" #include "runtime/interfaceSupport.inline.hpp" diff -r 496bbf554c5c -r 38176d1c5ec2 src/hotspot/share/compiler/oopMap.cpp --- a/src/hotspot/share/compiler/oopMap.cpp Wed Oct 16 01:16:12 2019 +0200 +++ b/src/hotspot/share/compiler/oopMap.cpp Wed Oct 16 11:23:46 2019 +0200 @@ -48,29 +48,25 @@ // OopMapStream -OopMapStream::OopMapStream(OopMap* oop_map, int oop_types_mask) { +OopMapStream::OopMapStream(OopMap* oop_map) { _stream = new CompressedReadStream(oop_map->write_stream()->buffer()); - _mask = oop_types_mask; _size = oop_map->omv_count(); _position = 0; _valid_omv = false; } -OopMapStream::OopMapStream(const ImmutableOopMap* oop_map, int oop_types_mask) { +OopMapStream::OopMapStream(const ImmutableOopMap* oop_map) { _stream = new CompressedReadStream(oop_map->data_addr()); - _mask = oop_types_mask; _size = oop_map->count(); _position = 0; _valid_omv = false; } void OopMapStream::find_next() { - while(_position++ < _size) { + if (_position++ < _size) { _omv.read_from(_stream); - if(((int)_omv.type() & _mask) > 0) { - _valid_omv = true; - return; - } + _valid_omv = true; + return; } _valid_omv = false; } @@ -140,16 +136,7 @@ assert( _locs_used[reg->value()] == OopMapValue::unused_value, "cannot insert twice" ); debug_only( _locs_used[reg->value()] = x; ) - OopMapValue o(reg, x); - - if(x == OopMapValue::callee_saved_value) { - // This can never be a stack location, so we don't need to transform it. - assert(optional->is_reg(), "Trying to callee save a stack location"); - o.set_content_reg(optional); - } else if(x == OopMapValue::derived_oop_value) { - o.set_content_reg(optional); - } - + OopMapValue o(reg, x, optional); o.write_on(write_stream()); increment_count(); } @@ -160,11 +147,6 @@ } -void OopMap::set_value(VMReg reg) { - // At this time, we don't need value entries in our OopMap. -} - - void OopMap::set_narrowoop(VMReg reg) { set_xxx(reg, OopMapValue::narrowoop_value, VMRegImpl::Bad()); } @@ -328,7 +310,7 @@ // changed before derived pointer offset has been collected) OopMapValue omv; { - OopMapStream oms(map,OopMapValue::derived_oop_value); + OopMapStream oms(map); if (!oms.is_done()) { #ifndef TIERED COMPILER1_PRESENT(ShouldNotReachHere();) @@ -340,27 +322,28 @@ #endif // !TIERED do { omv = oms.current(); - oop* loc = fr->oopmapreg_to_location(omv.reg(),reg_map); - guarantee(loc != NULL, "missing saved register"); - oop *derived_loc = loc; - oop *base_loc = fr->oopmapreg_to_location(omv.content_reg(), reg_map); - // Ignore NULL oops and decoded NULL narrow oops which - // equal to CompressedOops::base() when a narrow oop - // implicit null check is used in compiled code. - // The narrow_oop_base could be NULL or be the address - // of the page below heap depending on compressed oops mode. - if (base_loc != NULL && *base_loc != NULL && !CompressedOops::is_base(*base_loc)) { - derived_oop_fn(base_loc, derived_loc); + if (omv.type() == OopMapValue::derived_oop_value) { + oop* loc = fr->oopmapreg_to_location(omv.reg(),reg_map); + guarantee(loc != NULL, "missing saved register"); + oop *derived_loc = loc; + oop *base_loc = fr->oopmapreg_to_location(omv.content_reg(), reg_map); + // Ignore NULL oops and decoded NULL narrow oops which + // equal to CompressedOops::base() when a narrow oop + // implicit null check is used in compiled code. + // The narrow_oop_base could be NULL or be the address + // of the page below heap depending on compressed oops mode. + if (base_loc != NULL && *base_loc != NULL && !CompressedOops::is_base(*base_loc)) { + derived_oop_fn(base_loc, derived_loc); + } } oms.next(); } while (!oms.is_done()); } } - // We want coop and oop oop_types - int mask = OopMapValue::oop_value | OopMapValue::narrowoop_value; { - for (OopMapStream oms(map,mask); !oms.is_done(); oms.next()) { + // We want coop and oop oop_types + for (OopMapStream oms(map); !oms.is_done(); oms.next()) { omv = oms.current(); oop* loc = fr->oopmapreg_to_location(omv.reg(),reg_map); // It should be an error if no location can be found for a @@ -436,12 +419,14 @@ assert(map != NULL, "no ptr map found"); DEBUG_ONLY(int nof_callee = 0;) - for (OopMapStream oms(map, OopMapValue::callee_saved_value); !oms.is_done(); oms.next()) { + for (OopMapStream oms(map); !oms.is_done(); oms.next()) { OopMapValue omv = oms.current(); - VMReg reg = omv.content_reg(); - oop* loc = fr->oopmapreg_to_location(omv.reg(), reg_map); - reg_map->set_location(reg, (address) loc); - DEBUG_ONLY(nof_callee++;) + if (omv.type() == OopMapValue::callee_saved_value) { + VMReg reg = omv.content_reg(); + oop* loc = fr->oopmapreg_to_location(omv.reg(), reg_map); + reg_map->set_location(reg, (address) loc); + DEBUG_ONLY(nof_callee++;) + } } // Check that runtime stubs save all callee-saved registers @@ -452,25 +437,6 @@ #endif // COMPILER2 } -//============================================================================= -// Non-Product code - -#ifndef PRODUCT - -bool ImmutableOopMap::has_derived_pointer() const { -#if !defined(TIERED) && !INCLUDE_JVMCI - COMPILER1_PRESENT(return false); -#endif // !TIERED -#if COMPILER2_OR_JVMCI - OopMapStream oms(this,OopMapValue::derived_oop_value); - return oms.is_done(); -#else - return false; -#endif // COMPILER2_OR_JVMCI -} - -#endif //PRODUCT - // Printing code is present in product build for -XX:+PrintAssembly. static diff -r 496bbf554c5c -r 38176d1c5ec2 src/hotspot/share/compiler/oopMap.hpp --- a/src/hotspot/share/compiler/oopMap.hpp Wed Oct 16 01:16:12 2019 +0200 +++ b/src/hotspot/share/compiler/oopMap.hpp Wed Oct 16 11:23:46 2019 +0200 @@ -53,7 +53,7 @@ public: // Constants - enum { type_bits = 4, + enum { type_bits = 2, register_bits = BitsPerShort - type_bits }; enum { type_shift = 0, @@ -64,19 +64,41 @@ register_mask = right_n_bits(register_bits), register_mask_in_place = register_mask << register_shift }; - enum oop_types { // must fit in type_bits - unused_value =0, // powers of 2, for masking OopMapStream - oop_value = 1, - narrowoop_value = 2, - callee_saved_value = 4, - derived_oop_value= 8 }; + enum oop_types { + oop_value, + narrowoop_value, + callee_saved_value, + derived_oop_value, + unused_value = -1 // Only used as a sentinel value + }; // Constructors OopMapValue () { set_value(0); set_content_reg(VMRegImpl::Bad()); } - OopMapValue (VMReg reg, oop_types t) { set_reg_type(reg, t); set_content_reg(VMRegImpl::Bad()); } - OopMapValue (VMReg reg, oop_types t, VMReg reg2) { set_reg_type(reg, t); set_content_reg(reg2); } - OopMapValue (CompressedReadStream* stream) { read_from(stream); } + OopMapValue (VMReg reg, oop_types t, VMReg reg2) { + set_reg_type(reg, t); + set_content_reg(reg2); + } + + private: + void set_reg_type(VMReg p, oop_types t) { + set_value((p->value() << register_shift) | t); + assert(reg() == p, "sanity check" ); + assert(type() == t, "sanity check" ); + } + void set_content_reg(VMReg r) { + if (is_callee_saved()) { + // This can never be a stack location, so we don't need to transform it. + assert(r->is_reg(), "Trying to callee save a stack location"); + } else if (is_derived_oop()) { + assert (r->is_valid(), "must have a valid VMReg"); + } else { + assert (!r->is_valid(), "valid VMReg not allowed"); + } + _content_reg = r->value(); + } + + public: // Archiving void write_on(CompressedWriteStream* stream) { stream->write_int(value()); @@ -94,15 +116,10 @@ // Querying bool is_oop() { return mask_bits(value(), type_mask_in_place) == oop_value; } - bool is_narrowoop() { return mask_bits(value(), type_mask_in_place) == narrowoop_value; } + bool is_narrowoop() { return mask_bits(value(), type_mask_in_place) == narrowoop_value; } bool is_callee_saved() { return mask_bits(value(), type_mask_in_place) == callee_saved_value; } bool is_derived_oop() { return mask_bits(value(), type_mask_in_place) == derived_oop_value; } - void set_oop() { set_value((value() & register_mask_in_place) | oop_value); } - void set_narrowoop() { set_value((value() & register_mask_in_place) | narrowoop_value); } - void set_callee_saved() { set_value((value() & register_mask_in_place) | callee_saved_value); } - void set_derived_oop() { set_value((value() & register_mask_in_place) | derived_oop_value); } - VMReg reg() const { return VMRegImpl::as_VMReg(mask_bits(value(), register_mask_in_place) >> register_shift); } oop_types type() const { return (oop_types)mask_bits(value(), type_mask_in_place); } @@ -110,15 +127,7 @@ return (p->value() == (p->value() & register_mask)); } - void set_reg_type(VMReg p, oop_types t) { - set_value((p->value() << register_shift) | t); - assert(reg() == p, "sanity check" ); - assert(type() == t, "sanity check" ); - } - - VMReg content_reg() const { return VMRegImpl::as_VMReg(_content_reg, true); } - void set_content_reg(VMReg r) { _content_reg = r->value(); } // Physical location queries bool is_register_loc() { return reg()->is_reg(); } @@ -156,6 +165,8 @@ enum DeepCopyToken { _deep_copy_token }; OopMap(DeepCopyToken, OopMap* source); // used only by deep_copy + void set_xxx(VMReg reg, OopMapValue::oop_types x, VMReg optional); + public: OopMap(int frame_size, int arg_count); @@ -173,19 +184,14 @@ // frame_size units are stack-slots (4 bytes) NOT intptr_t; we can name odd // slots to hold 4-byte values like ints and floats in the LP64 build. void set_oop ( VMReg local); - void set_value( VMReg local); void set_narrowoop(VMReg local); - void set_dead ( VMReg local); void set_callee_saved( VMReg local, VMReg caller_machine_register ); void set_derived_oop ( VMReg local, VMReg derived_from_local_register ); - void set_xxx(VMReg reg, OopMapValue::oop_types x, VMReg optional); int heap_size() const; void copy_data_to(address addr) const; OopMap* deep_copy(); - bool has_derived_pointer() const PRODUCT_RETURN0; - bool legal_vm_reg_name(VMReg local) { return OopMapValue::legal_vm_reg_name(local); } @@ -269,7 +275,6 @@ public: ImmutableOopMap(const OopMap* oopmap); - bool has_derived_pointer() const PRODUCT_RETURN0; int count() const { return _count; } #ifdef ASSERT int nr_of_bytes() const; // this is an expensive operation, only used in debug builds @@ -334,7 +339,6 @@ class OopMapStream : public StackObj { private: CompressedReadStream* _stream; - int _mask; int _size; int _position; bool _valid_omv; @@ -342,8 +346,8 @@ void find_next(); public: - OopMapStream(OopMap* oop_map, int oop_types_mask = OopMapValue::type_mask_in_place); - OopMapStream(const ImmutableOopMap* oop_map, int oop_types_mask = OopMapValue::type_mask_in_place); + OopMapStream(OopMap* oop_map); + OopMapStream(const ImmutableOopMap* oop_map); bool is_done() { if(!_valid_omv) { find_next(); } return !_valid_omv; } void next() { find_next(); } OopMapValue current() { return _omv; } diff -r 496bbf554c5c -r 38176d1c5ec2 src/hotspot/share/compiler/tieredThresholdPolicy.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/hotspot/share/compiler/tieredThresholdPolicy.cpp Wed Oct 16 11:23:46 2019 +0200 @@ -0,0 +1,1005 @@ +/* + * Copyright (c) 2010, 2019, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * 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 "compiler/compileBroker.hpp" +#include "compiler/compilerOracle.hpp" +#include "compiler/tieredThresholdPolicy.hpp" +#include "memory/resourceArea.hpp" +#include "runtime/arguments.hpp" +#include "runtime/handles.inline.hpp" +#include "runtime/safepoint.hpp" +#include "runtime/safepointVerifiers.hpp" +#include "code/scopeDesc.hpp" +#include "oops/method.inline.hpp" +#if INCLUDE_JVMCI +#include "jvmci/jvmci.hpp" +#endif + +#ifdef TIERED + +#include "c1/c1_Compiler.hpp" +#include "opto/c2compiler.hpp" + +template +bool TieredThresholdPolicy::call_predicate_helper(int i, int b, double scale, Method* method) { + double threshold_scaling; + if (CompilerOracle::has_option_value(method, "CompileThresholdScaling", threshold_scaling)) { + scale *= threshold_scaling; + } + switch(level) { + case CompLevel_aot: + return (i >= Tier3AOTInvocationThreshold * scale) || + (i >= Tier3AOTMinInvocationThreshold * scale && i + b >= Tier3AOTCompileThreshold * scale); + case CompLevel_none: + case CompLevel_limited_profile: + return (i >= Tier3InvocationThreshold * scale) || + (i >= Tier3MinInvocationThreshold * scale && i + b >= Tier3CompileThreshold * scale); + case CompLevel_full_profile: + return (i >= Tier4InvocationThreshold * scale) || + (i >= Tier4MinInvocationThreshold * scale && i + b >= Tier4CompileThreshold * scale); + } + return true; +} + +template +bool TieredThresholdPolicy::loop_predicate_helper(int i, int b, double scale, Method* method) { + double threshold_scaling; + if (CompilerOracle::has_option_value(method, "CompileThresholdScaling", threshold_scaling)) { + scale *= threshold_scaling; + } + switch(level) { + case CompLevel_aot: + return b >= Tier3AOTBackEdgeThreshold * scale; + case CompLevel_none: + case CompLevel_limited_profile: + return b >= Tier3BackEdgeThreshold * scale; + case CompLevel_full_profile: + return b >= Tier4BackEdgeThreshold * scale; + } + return true; +} + +// Simple methods are as good being compiled with C1 as C2. +// Determine if a given method is such a case. +bool TieredThresholdPolicy::is_trivial(Method* method) { + if (method->is_accessor() || + method->is_constant_getter()) { + return true; + } + return false; +} + +bool TieredThresholdPolicy::should_compile_at_level_simple(Method* method) { + if (TieredThresholdPolicy::is_trivial(method)) { + return true; + } +#if INCLUDE_JVMCI + if (UseJVMCICompiler) { + AbstractCompiler* comp = CompileBroker::compiler(CompLevel_full_optimization); + if (comp != NULL && comp->is_jvmci() && ((JVMCICompiler*) comp)->force_comp_at_level_simple(method)) { + return true; + } + } +#endif + return false; +} + +CompLevel TieredThresholdPolicy::comp_level(Method* method) { + CompiledMethod *nm = method->code(); + if (nm != NULL && nm->is_in_use()) { + return (CompLevel)nm->comp_level(); + } + return CompLevel_none; +} + +void TieredThresholdPolicy::print_counters(const char* prefix, const methodHandle& mh) { + int invocation_count = mh->invocation_count(); + int backedge_count = mh->backedge_count(); + MethodData* mdh = mh->method_data(); + int mdo_invocations = 0, mdo_backedges = 0; + int mdo_invocations_start = 0, mdo_backedges_start = 0; + if (mdh != NULL) { + mdo_invocations = mdh->invocation_count(); + mdo_backedges = mdh->backedge_count(); + mdo_invocations_start = mdh->invocation_count_start(); + mdo_backedges_start = mdh->backedge_count_start(); + } + tty->print(" %stotal=%d,%d %smdo=%d(%d),%d(%d)", prefix, + invocation_count, backedge_count, prefix, + mdo_invocations, mdo_invocations_start, + mdo_backedges, mdo_backedges_start); + tty->print(" %smax levels=%d,%d", prefix, + mh->highest_comp_level(), mh->highest_osr_comp_level()); +} + +// Print an event. +void TieredThresholdPolicy::print_event(EventType type, const methodHandle& mh, const methodHandle& imh, + int bci, CompLevel level) { + bool inlinee_event = mh() != imh(); + + ttyLocker tty_lock; + tty->print("%lf: [", os::elapsedTime()); + + switch(type) { + case CALL: + tty->print("call"); + break; + case LOOP: + tty->print("loop"); + break; + case COMPILE: + tty->print("compile"); + break; + case REMOVE_FROM_QUEUE: + tty->print("remove-from-queue"); + break; + case UPDATE_IN_QUEUE: + tty->print("update-in-queue"); + break; + case REPROFILE: + tty->print("reprofile"); + break; + case MAKE_NOT_ENTRANT: + tty->print("make-not-entrant"); + break; + default: + tty->print("unknown"); + } + + tty->print(" level=%d ", level); + + ResourceMark rm; + char *method_name = mh->name_and_sig_as_C_string(); + tty->print("[%s", method_name); + if (inlinee_event) { + char *inlinee_name = imh->name_and_sig_as_C_string(); + tty->print(" [%s]] ", inlinee_name); + } + else tty->print("] "); + tty->print("@%d queues=%d,%d", bci, CompileBroker::queue_size(CompLevel_full_profile), + CompileBroker::queue_size(CompLevel_full_optimization)); + + print_specific(type, mh, imh, bci, level); + + if (type != COMPILE) { + print_counters("", mh); + if (inlinee_event) { + print_counters("inlinee ", imh); + } + tty->print(" compilable="); + bool need_comma = false; + if (!mh->is_not_compilable(CompLevel_full_profile)) { + tty->print("c1"); + need_comma = true; + } + if (!mh->is_not_osr_compilable(CompLevel_full_profile)) { + if (need_comma) tty->print(","); + tty->print("c1-osr"); + need_comma = true; + } + if (!mh->is_not_compilable(CompLevel_full_optimization)) { + if (need_comma) tty->print(","); + tty->print("c2"); + need_comma = true; + } + if (!mh->is_not_osr_compilable(CompLevel_full_optimization)) { + if (need_comma) tty->print(","); + tty->print("c2-osr"); + } + tty->print(" status="); + if (mh->queued_for_compilation()) { + tty->print("in-queue"); + } else tty->print("idle"); + } + tty->print_cr("]"); +} + +void TieredThresholdPolicy::initialize() { + int count = CICompilerCount; + bool c1_only = TieredStopAtLevel < CompLevel_full_optimization; +#ifdef _LP64 + // Turn on ergonomic compiler count selection + if (FLAG_IS_DEFAULT(CICompilerCountPerCPU) && FLAG_IS_DEFAULT(CICompilerCount)) { + FLAG_SET_DEFAULT(CICompilerCountPerCPU, true); + } + if (CICompilerCountPerCPU) { + // Simple log n seems to grow too slowly for tiered, try something faster: log n * log log n + int log_cpu = log2_int(os::active_processor_count()); + int loglog_cpu = log2_int(MAX2(log_cpu, 1)); + count = MAX2(log_cpu * loglog_cpu * 3 / 2, 2); + // Make sure there is enough space in the code cache to hold all the compiler buffers + size_t c1_size = Compiler::code_buffer_size(); + size_t c2_size = C2Compiler::initial_code_buffer_size(); + size_t buffer_size = c1_only ? c1_size : (c1_size/3 + 2*c2_size/3); + int max_count = (ReservedCodeCacheSize - (CodeCacheMinimumUseSpace DEBUG_ONLY(* 3))) / (int)buffer_size; + if (count > max_count) { + // Lower the compiler count such that all buffers fit into the code cache + count = MAX2(max_count, c1_only ? 1 : 2); + } + FLAG_SET_ERGO(CICompilerCount, count); + } +#else + // On 32-bit systems, the number of compiler threads is limited to 3. + // On these systems, the virtual address space available to the JVM + // is usually limited to 2-4 GB (the exact value depends on the platform). + // As the compilers (especially C2) can consume a large amount of + // memory, scaling the number of compiler threads with the number of + // available cores can result in the exhaustion of the address space + /// available to the VM and thus cause the VM to crash. + if (FLAG_IS_DEFAULT(CICompilerCount)) { + count = 3; + FLAG_SET_ERGO(CICompilerCount, count); + } +#endif + + if (c1_only) { + // No C2 compiler thread required + set_c1_count(count); + } else { + set_c1_count(MAX2(count / 3, 1)); + set_c2_count(MAX2(count - c1_count(), 1)); + } + assert(count == c1_count() + c2_count(), "inconsistent compiler thread count"); + + // Some inlining tuning +#ifdef X86 + if (FLAG_IS_DEFAULT(InlineSmallCode)) { + FLAG_SET_DEFAULT(InlineSmallCode, 2000); + } +#endif + +#if defined SPARC || defined AARCH64 + if (FLAG_IS_DEFAULT(InlineSmallCode)) { + FLAG_SET_DEFAULT(InlineSmallCode, 2500); + } +#endif + + set_increase_threshold_at_ratio(); + set_start_time(os::javaTimeMillis()); +} + +void TieredThresholdPolicy::set_carry_if_necessary(InvocationCounter *counter) { + if (!counter->carry() && counter->count() > InvocationCounter::count_limit / 2) { + counter->set_carry_flag(); + } +} + +// Set carry flags on the counters if necessary +void TieredThresholdPolicy::handle_counter_overflow(Method* method) { + MethodCounters *mcs = method->method_counters(); + if (mcs != NULL) { + set_carry_if_necessary(mcs->invocation_counter()); + set_carry_if_necessary(mcs->backedge_counter()); + } + MethodData* mdo = method->method_data(); + if (mdo != NULL) { + set_carry_if_necessary(mdo->invocation_counter()); + set_carry_if_necessary(mdo->backedge_counter()); + } +} + +// Called with the queue locked and with at least one element +CompileTask* TieredThresholdPolicy::select_task(CompileQueue* compile_queue) { + CompileTask *max_blocking_task = NULL; + CompileTask *max_task = NULL; + Method* max_method = NULL; + jlong t = os::javaTimeMillis(); + // Iterate through the queue and find a method with a maximum rate. + for (CompileTask* task = compile_queue->first(); task != NULL;) { + CompileTask* next_task = task->next(); + Method* method = task->method(); + // If a method was unloaded or has been stale for some time, remove it from the queue. + // Blocking tasks and tasks submitted from whitebox API don't become stale + if (task->is_unloaded() || (task->can_become_stale() && is_stale(t, TieredCompileTaskTimeout, method) && !is_old(method))) { + if (!task->is_unloaded()) { + if (PrintTieredEvents) { + print_event(REMOVE_FROM_QUEUE, method, method, task->osr_bci(), (CompLevel) task->comp_level()); + } + method->clear_queued_for_compilation(); + } + compile_queue->remove_and_mark_stale(task); + task = next_task; + continue; + } + update_rate(t, method); + if (max_task == NULL || compare_methods(method, max_method)) { + // Select a method with the highest rate + max_task = task; + max_method = method; + } + + if (task->is_blocking()) { + if (max_blocking_task == NULL || compare_methods(method, max_blocking_task->method())) { + max_blocking_task = task; + } + } + + task = next_task; + } + + if (max_blocking_task != NULL) { + // In blocking compilation mode, the CompileBroker will make + // compilations submitted by a JVMCI compiler thread non-blocking. These + // compilations should be scheduled after all blocking compilations + // to service non-compiler related compilations sooner and reduce the + // chance of such compilations timing out. + max_task = max_blocking_task; + max_method = max_task->method(); + } + + if (max_task != NULL && max_task->comp_level() == CompLevel_full_profile && + TieredStopAtLevel > CompLevel_full_profile && + max_method != NULL && is_method_profiled(max_method)) { + max_task->set_comp_level(CompLevel_limited_profile); + + if (CompileBroker::compilation_is_complete(max_method, max_task->osr_bci(), CompLevel_limited_profile)) { + if (PrintTieredEvents) { + print_event(REMOVE_FROM_QUEUE, max_method, max_method, max_task->osr_bci(), (CompLevel)max_task->comp_level()); + } + compile_queue->remove_and_mark_stale(max_task); + max_method->clear_queued_for_compilation(); + return NULL; + } + + if (PrintTieredEvents) { + print_event(UPDATE_IN_QUEUE, max_method, max_method, max_task->osr_bci(), (CompLevel)max_task->comp_level()); + } + } + + return max_task; +} + +void TieredThresholdPolicy::reprofile(ScopeDesc* trap_scope, bool is_osr) { + for (ScopeDesc* sd = trap_scope;; sd = sd->sender()) { + if (PrintTieredEvents) { + methodHandle mh(sd->method()); + print_event(REPROFILE, mh, mh, InvocationEntryBci, CompLevel_none); + } + MethodData* mdo = sd->method()->method_data(); + if (mdo != NULL) { + mdo->reset_start_counters(); + } + if (sd->is_top()) break; + } +} + +nmethod* TieredThresholdPolicy::event(const methodHandle& method, const methodHandle& inlinee, + int branch_bci, int bci, CompLevel comp_level, CompiledMethod* nm, JavaThread* thread) { + if (comp_level == CompLevel_none && + JvmtiExport::can_post_interpreter_events() && + thread->is_interp_only_mode()) { + return NULL; + } + if (ReplayCompiles) { + // Don't trigger other compiles in testing mode + return NULL; + } + + handle_counter_overflow(method()); + if (method() != inlinee()) { + handle_counter_overflow(inlinee()); + } + + if (PrintTieredEvents) { + print_event(bci == InvocationEntryBci ? CALL : LOOP, method, inlinee, bci, comp_level); + } + + if (bci == InvocationEntryBci) { + method_invocation_event(method, inlinee, comp_level, nm, thread); + } else { + // method == inlinee if the event originated in the main method + method_back_branch_event(method, inlinee, bci, comp_level, nm, thread); + // Check if event led to a higher level OSR compilation + CompLevel expected_comp_level = comp_level; + if (inlinee->is_not_osr_compilable(expected_comp_level)) { + // It's not possble to reach the expected level so fall back to simple. + expected_comp_level = CompLevel_simple; + } + nmethod* osr_nm = inlinee->lookup_osr_nmethod_for(bci, expected_comp_level, false); + assert(osr_nm == NULL || osr_nm->comp_level() >= expected_comp_level, "lookup_osr_nmethod_for is broken"); + if (osr_nm != NULL) { + // Perform OSR with new nmethod + return osr_nm; + } + } + return NULL; +} + +// Check if the method can be compiled, change level if necessary +void TieredThresholdPolicy::compile(const methodHandle& mh, int bci, CompLevel level, JavaThread* thread) { + assert(level <= TieredStopAtLevel, "Invalid compilation level"); + if (level == CompLevel_none) { + return; + } + if (level == CompLevel_aot) { + if (mh->has_aot_code()) { + if (PrintTieredEvents) { + print_event(COMPILE, mh, mh, bci, level); + } + MutexLocker ml(Compile_lock); + NoSafepointVerifier nsv; + if (mh->has_aot_code() && mh->code() != mh->aot_code()) { + mh->aot_code()->make_entrant(); + if (mh->has_compiled_code()) { + mh->code()->make_not_entrant(); + } + MutexLocker pl(CompiledMethod_lock, Mutex::_no_safepoint_check_flag); + Method::set_code(mh, mh->aot_code()); + } + } + return; + } + + // Check if the method can be compiled. If it cannot be compiled with C1, continue profiling + // in the interpreter and then compile with C2 (the transition function will request that, + // see common() ). If the method cannot be compiled with C2 but still can with C1, compile it with + // pure C1. + if ((bci == InvocationEntryBci && !can_be_compiled(mh, level))) { + if (level == CompLevel_full_optimization && can_be_compiled(mh, CompLevel_simple)) { + compile(mh, bci, CompLevel_simple, thread); + } + return; + } + if ((bci != InvocationEntryBci && !can_be_osr_compiled(mh, level))) { + if (level == CompLevel_full_optimization && can_be_osr_compiled(mh, CompLevel_simple)) { + nmethod* osr_nm = mh->lookup_osr_nmethod_for(bci, CompLevel_simple, false); + if (osr_nm != NULL && osr_nm->comp_level() > CompLevel_simple) { + // Invalidate the existing OSR nmethod so that a compile at CompLevel_simple is permitted. + osr_nm->make_not_entrant(); + } + compile(mh, bci, CompLevel_simple, thread); + } + return; + } + if (bci != InvocationEntryBci && mh->is_not_osr_compilable(level)) { + return; + } + if (!CompileBroker::compilation_is_in_queue(mh)) { + if (PrintTieredEvents) { + print_event(COMPILE, mh, mh, bci, level); + } + submit_compile(mh, bci, level, thread); + } +} + +// Update the rate and submit compile +void TieredThresholdPolicy::submit_compile(const methodHandle& mh, int bci, CompLevel level, JavaThread* thread) { + int hot_count = (bci == InvocationEntryBci) ? mh->invocation_count() : mh->backedge_count(); + update_rate(os::javaTimeMillis(), mh()); + CompileBroker::compile_method(mh, bci, level, mh, hot_count, CompileTask::Reason_Tiered, thread); +} + +// Print an event. +void TieredThresholdPolicy::print_specific(EventType type, const methodHandle& mh, const methodHandle& imh, + int bci, CompLevel level) { + tty->print(" rate="); + if (mh->prev_time() == 0) tty->print("n/a"); + else tty->print("%f", mh->rate()); + + tty->print(" k=%.2lf,%.2lf", threshold_scale(CompLevel_full_profile, Tier3LoadFeedback), + threshold_scale(CompLevel_full_optimization, Tier4LoadFeedback)); + +} + +// update_rate() is called from select_task() while holding a compile queue lock. +void TieredThresholdPolicy::update_rate(jlong t, Method* m) { + // Skip update if counters are absent. + // Can't allocate them since we are holding compile queue lock. + if (m->method_counters() == NULL) return; + + if (is_old(m)) { + // We don't remove old methods from the queue, + // so we can just zero the rate. + m->set_rate(0); + return; + } + + // We don't update the rate if we've just came out of a safepoint. + // delta_s is the time since last safepoint in milliseconds. + jlong delta_s = t - SafepointTracing::end_of_last_safepoint_epoch_ms(); + jlong delta_t = t - (m->prev_time() != 0 ? m->prev_time() : start_time()); // milliseconds since the last measurement + // How many events were there since the last time? + int event_count = m->invocation_count() + m->backedge_count(); + int delta_e = event_count - m->prev_event_count(); + + // We should be running for at least 1ms. + if (delta_s >= TieredRateUpdateMinTime) { + // And we must've taken the previous point at least 1ms before. + if (delta_t >= TieredRateUpdateMinTime && delta_e > 0) { + m->set_prev_time(t); + m->set_prev_event_count(event_count); + m->set_rate((float)delta_e / (float)delta_t); // Rate is events per millisecond + } else { + if (delta_t > TieredRateUpdateMaxTime && delta_e == 0) { + // If nothing happened for 25ms, zero the rate. Don't modify prev values. + m->set_rate(0); + } + } + } +} + +// Check if this method has been stale for a given number of milliseconds. +// See select_task(). +bool TieredThresholdPolicy::is_stale(jlong t, jlong timeout, Method* m) { + jlong delta_s = t - SafepointTracing::end_of_last_safepoint_epoch_ms(); + jlong delta_t = t - m->prev_time(); + if (delta_t > timeout && delta_s > timeout) { + int event_count = m->invocation_count() + m->backedge_count(); + int delta_e = event_count - m->prev_event_count(); + // Return true if there were no events. + return delta_e == 0; + } + return false; +} + +// We don't remove old methods from the compile queue even if they have +// very low activity. See select_task(). +bool TieredThresholdPolicy::is_old(Method* method) { + return method->invocation_count() > 50000 || method->backedge_count() > 500000; +} + +double TieredThresholdPolicy::weight(Method* method) { + return (double)(method->rate() + 1) * + (method->invocation_count() + 1) * (method->backedge_count() + 1); +} + +// Apply heuristics and return true if x should be compiled before y +bool TieredThresholdPolicy::compare_methods(Method* x, Method* y) { + if (x->highest_comp_level() > y->highest_comp_level()) { + // recompilation after deopt + return true; + } else + if (x->highest_comp_level() == y->highest_comp_level()) { + if (weight(x) > weight(y)) { + return true; + } + } + return false; +} + +// Is method profiled enough? +bool TieredThresholdPolicy::is_method_profiled(Method* method) { + MethodData* mdo = method->method_data(); + if (mdo != NULL) { + int i = mdo->invocation_count_delta(); + int b = mdo->backedge_count_delta(); + return call_predicate_helper(i, b, 1, method); + } + return false; +} + +double TieredThresholdPolicy::threshold_scale(CompLevel level, int feedback_k) { + double queue_size = CompileBroker::queue_size(level); + int comp_count = compiler_count(level); + double k = queue_size / (feedback_k * comp_count) + 1; + + // Increase C1 compile threshold when the code cache is filled more + // than specified by IncreaseFirstTierCompileThresholdAt percentage. + // The main intention is to keep enough free space for C2 compiled code + // to achieve peak performance if the code cache is under stress. + if ((TieredStopAtLevel == CompLevel_full_optimization) && (level != CompLevel_full_optimization)) { + double current_reverse_free_ratio = CodeCache::reverse_free_ratio(CodeCache::get_code_blob_type(level)); + if (current_reverse_free_ratio > _increase_threshold_at_ratio) { + k *= exp(current_reverse_free_ratio - _increase_threshold_at_ratio); + } + } + return k; +} + +// Call and loop predicates determine whether a transition to a higher +// compilation level should be performed (pointers to predicate functions +// are passed to common()). +// Tier?LoadFeedback is basically a coefficient that determines of +// how many methods per compiler thread can be in the queue before +// the threshold values double. +bool TieredThresholdPolicy::loop_predicate(int i, int b, CompLevel cur_level, Method* method) { + switch(cur_level) { + case CompLevel_aot: { + double k = threshold_scale(CompLevel_full_profile, Tier3LoadFeedback); + return loop_predicate_helper(i, b, k, method); + } + case CompLevel_none: + case CompLevel_limited_profile: { + double k = threshold_scale(CompLevel_full_profile, Tier3LoadFeedback); + return loop_predicate_helper(i, b, k, method); + } + case CompLevel_full_profile: { + double k = threshold_scale(CompLevel_full_optimization, Tier4LoadFeedback); + return loop_predicate_helper(i, b, k, method); + } + default: + return true; + } +} + +bool TieredThresholdPolicy::call_predicate(int i, int b, CompLevel cur_level, Method* method) { + switch(cur_level) { + case CompLevel_aot: { + double k = threshold_scale(CompLevel_full_profile, Tier3LoadFeedback); + return call_predicate_helper(i, b, k, method); + } + case CompLevel_none: + case CompLevel_limited_profile: { + double k = threshold_scale(CompLevel_full_profile, Tier3LoadFeedback); + return call_predicate_helper(i, b, k, method); + } + case CompLevel_full_profile: { + double k = threshold_scale(CompLevel_full_optimization, Tier4LoadFeedback); + return call_predicate_helper(i, b, k, method); + } + default: + return true; + } +} + +// Determine is a method is mature. +bool TieredThresholdPolicy::is_mature(Method* method) { + if (should_compile_at_level_simple(method)) return true; + MethodData* mdo = method->method_data(); + if (mdo != NULL) { + int i = mdo->invocation_count(); + int b = mdo->backedge_count(); + double k = ProfileMaturityPercentage / 100.0; + return call_predicate_helper(i, b, k, method) || + loop_predicate_helper(i, b, k, method); + } + return false; +} + +// If a method is old enough and is still in the interpreter we would want to +// start profiling without waiting for the compiled method to arrive. +// We also take the load on compilers into the account. +bool TieredThresholdPolicy::should_create_mdo(Method* method, CompLevel cur_level) { + if (cur_level == CompLevel_none && + CompileBroker::queue_size(CompLevel_full_optimization) <= + Tier3DelayOn * compiler_count(CompLevel_full_optimization)) { + int i = method->invocation_count(); + int b = method->backedge_count(); + double k = Tier0ProfilingStartPercentage / 100.0; + return call_predicate_helper(i, b, k, method) || loop_predicate_helper(i, b, k, method); + } + return false; +} + +// Inlining control: if we're compiling a profiled method with C1 and the callee +// is known to have OSRed in a C2 version, don't inline it. +bool TieredThresholdPolicy::should_not_inline(ciEnv* env, ciMethod* callee) { + CompLevel comp_level = (CompLevel)env->comp_level(); + if (comp_level == CompLevel_full_profile || + comp_level == CompLevel_limited_profile) { + return callee->highest_osr_comp_level() == CompLevel_full_optimization; + } + return false; +} + +// Create MDO if necessary. +void TieredThresholdPolicy::create_mdo(const methodHandle& mh, JavaThread* THREAD) { + if (mh->is_native() || + mh->is_abstract() || + mh->is_accessor() || + mh->is_constant_getter()) { + return; + } + if (mh->method_data() == NULL) { + Method::build_interpreter_method_data(mh, CHECK_AND_CLEAR); + } +} + + +/* + * Method states: + * 0 - interpreter (CompLevel_none) + * 1 - pure C1 (CompLevel_simple) + * 2 - C1 with invocation and backedge counting (CompLevel_limited_profile) + * 3 - C1 with full profiling (CompLevel_full_profile) + * 4 - C2 (CompLevel_full_optimization) + * + * Common state transition patterns: + * a. 0 -> 3 -> 4. + * The most common path. But note that even in this straightforward case + * profiling can start at level 0 and finish at level 3. + * + * b. 0 -> 2 -> 3 -> 4. + * This case occurs when the load on C2 is deemed too high. So, instead of transitioning + * into state 3 directly and over-profiling while a method is in the C2 queue we transition to + * level 2 and wait until the load on C2 decreases. This path is disabled for OSRs. + * + * c. 0 -> (3->2) -> 4. + * In this case we enqueue a method for compilation at level 3, but the C1 queue is long enough + * to enable the profiling to fully occur at level 0. In this case we change the compilation level + * of the method to 2 while the request is still in-queue, because it'll allow it to run much faster + * without full profiling while c2 is compiling. + * + * d. 0 -> 3 -> 1 or 0 -> 2 -> 1. + * After a method was once compiled with C1 it can be identified as trivial and be compiled to + * level 1. These transition can also occur if a method can't be compiled with C2 but can with C1. + * + * e. 0 -> 4. + * This can happen if a method fails C1 compilation (it will still be profiled in the interpreter) + * or because of a deopt that didn't require reprofiling (compilation won't happen in this case because + * the compiled version already exists). + * + * Note that since state 0 can be reached from any other state via deoptimization different loops + * are possible. + * + */ + +// Common transition function. Given a predicate determines if a method should transition to another level. +CompLevel TieredThresholdPolicy::common(Predicate p, Method* method, CompLevel cur_level, bool disable_feedback) { + CompLevel next_level = cur_level; + int i = method->invocation_count(); + int b = method->backedge_count(); + + if (should_compile_at_level_simple(method)) { + next_level = CompLevel_simple; + } else { + switch(cur_level) { + default: break; + case CompLevel_aot: { + // If we were at full profile level, would we switch to full opt? + if (common(p, method, CompLevel_full_profile, disable_feedback) == CompLevel_full_optimization) { + next_level = CompLevel_full_optimization; + } else if (disable_feedback || (CompileBroker::queue_size(CompLevel_full_optimization) <= + Tier3DelayOff * compiler_count(CompLevel_full_optimization) && + (this->*p)(i, b, cur_level, method))) { + next_level = CompLevel_full_profile; + } + } + break; + case CompLevel_none: + // If we were at full profile level, would we switch to full opt? + if (common(p, method, CompLevel_full_profile, disable_feedback) == CompLevel_full_optimization) { + next_level = CompLevel_full_optimization; + } else if ((this->*p)(i, b, cur_level, method)) { +#if INCLUDE_JVMCI + if (EnableJVMCI && UseJVMCICompiler) { + // Since JVMCI takes a while to warm up, its queue inevitably backs up during + // early VM execution. As of 2014-06-13, JVMCI's inliner assumes that the root + // compilation method and all potential inlinees have mature profiles (which + // includes type profiling). If it sees immature profiles, JVMCI's inliner + // can perform pathologically bad (e.g., causing OutOfMemoryErrors due to + // exploring/inlining too many graphs). Since a rewrite of the inliner is + // in progress, we simply disable the dialing back heuristic for now and will + // revisit this decision once the new inliner is completed. + next_level = CompLevel_full_profile; + } else +#endif + { + // C1-generated fully profiled code is about 30% slower than the limited profile + // code that has only invocation and backedge counters. The observation is that + // if C2 queue is large enough we can spend too much time in the fully profiled code + // while waiting for C2 to pick the method from the queue. To alleviate this problem + // we introduce a feedback on the C2 queue size. If the C2 queue is sufficiently long + // we choose to compile a limited profiled version and then recompile with full profiling + // when the load on C2 goes down. + if (!disable_feedback && CompileBroker::queue_size(CompLevel_full_optimization) > + Tier3DelayOn * compiler_count(CompLevel_full_optimization)) { + next_level = CompLevel_limited_profile; + } else { + next_level = CompLevel_full_profile; + } + } + } + break; + case CompLevel_limited_profile: + if (is_method_profiled(method)) { + // Special case: we got here because this method was fully profiled in the interpreter. + next_level = CompLevel_full_optimization; + } else { + MethodData* mdo = method->method_data(); + if (mdo != NULL) { + if (mdo->would_profile()) { + if (disable_feedback || (CompileBroker::queue_size(CompLevel_full_optimization) <= + Tier3DelayOff * compiler_count(CompLevel_full_optimization) && + (this->*p)(i, b, cur_level, method))) { + next_level = CompLevel_full_profile; + } + } else { + next_level = CompLevel_full_optimization; + } + } else { + // If there is no MDO we need to profile + if (disable_feedback || (CompileBroker::queue_size(CompLevel_full_optimization) <= + Tier3DelayOff * compiler_count(CompLevel_full_optimization) && + (this->*p)(i, b, cur_level, method))) { + next_level = CompLevel_full_profile; + } + } + } + break; + case CompLevel_full_profile: + { + MethodData* mdo = method->method_data(); + if (mdo != NULL) { + if (mdo->would_profile()) { + int mdo_i = mdo->invocation_count_delta(); + int mdo_b = mdo->backedge_count_delta(); + if ((this->*p)(mdo_i, mdo_b, cur_level, method)) { + next_level = CompLevel_full_optimization; + } + } else { + next_level = CompLevel_full_optimization; + } + } + } + break; + } + } + return MIN2(next_level, (CompLevel)TieredStopAtLevel); +} + +// Determine if a method should be compiled with a normal entry point at a different level. +CompLevel TieredThresholdPolicy::call_event(Method* method, CompLevel cur_level, JavaThread * thread) { + CompLevel osr_level = MIN2((CompLevel) method->highest_osr_comp_level(), + common(&TieredThresholdPolicy::loop_predicate, method, cur_level, true)); + CompLevel next_level = common(&TieredThresholdPolicy::call_predicate, method, cur_level); + + // If OSR method level is greater than the regular method level, the levels should be + // equalized by raising the regular method level in order to avoid OSRs during each + // invocation of the method. + if (osr_level == CompLevel_full_optimization && cur_level == CompLevel_full_profile) { + MethodData* mdo = method->method_data(); + guarantee(mdo != NULL, "MDO should not be NULL"); + if (mdo->invocation_count() >= 1) { + next_level = CompLevel_full_optimization; + } + } else { + next_level = MAX2(osr_level, next_level); + } + return next_level; +} + +// Determine if we should do an OSR compilation of a given method. +CompLevel TieredThresholdPolicy::loop_event(Method* method, CompLevel cur_level, JavaThread* thread) { + CompLevel next_level = common(&TieredThresholdPolicy::loop_predicate, method, cur_level, true); + if (cur_level == CompLevel_none) { + // If there is a live OSR method that means that we deopted to the interpreter + // for the transition. + CompLevel osr_level = MIN2((CompLevel)method->highest_osr_comp_level(), next_level); + if (osr_level > CompLevel_none) { + return osr_level; + } + } + return next_level; +} + +bool TieredThresholdPolicy::maybe_switch_to_aot(const methodHandle& mh, CompLevel cur_level, CompLevel next_level, JavaThread* thread) { + if (UseAOT) { + if (cur_level == CompLevel_full_profile || cur_level == CompLevel_none) { + // If the current level is full profile or interpreter and we're switching to any other level, + // activate the AOT code back first so that we won't waste time overprofiling. + compile(mh, InvocationEntryBci, CompLevel_aot, thread); + // Fall through for JIT compilation. + } + if (next_level == CompLevel_limited_profile && cur_level != CompLevel_aot && mh->has_aot_code()) { + // If the next level is limited profile, use the aot code (if there is any), + // since it's essentially the same thing. + compile(mh, InvocationEntryBci, CompLevel_aot, thread); + // Not need to JIT, we're done. + return true; + } + } + return false; +} + + +// Handle the invocation event. +void TieredThresholdPolicy::method_invocation_event(const methodHandle& mh, const methodHandle& imh, + CompLevel level, CompiledMethod* nm, JavaThread* thread) { + if (should_create_mdo(mh(), level)) { + create_mdo(mh, thread); + } + CompLevel next_level = call_event(mh(), level, thread); + if (next_level != level) { + if (maybe_switch_to_aot(mh, level, next_level, thread)) { + // No JITting necessary + return; + } + if (is_compilation_enabled() && !CompileBroker::compilation_is_in_queue(mh)) { + compile(mh, InvocationEntryBci, next_level, thread); + } + } +} + +// Handle the back branch event. Notice that we can compile the method +// with a regular entry from here. +void TieredThresholdPolicy::method_back_branch_event(const methodHandle& mh, const methodHandle& imh, + int bci, CompLevel level, CompiledMethod* nm, JavaThread* thread) { + if (should_create_mdo(mh(), level)) { + create_mdo(mh, thread); + } + // Check if MDO should be created for the inlined method + if (should_create_mdo(imh(), level)) { + create_mdo(imh, thread); + } + + if (is_compilation_enabled()) { + CompLevel next_osr_level = loop_event(imh(), level, thread); + CompLevel max_osr_level = (CompLevel)imh->highest_osr_comp_level(); + // At the very least compile the OSR version + if (!CompileBroker::compilation_is_in_queue(imh) && (next_osr_level != level)) { + compile(imh, bci, next_osr_level, thread); + } + + // Use loop event as an opportunity to also check if there's been + // enough calls. + CompLevel cur_level, next_level; + if (mh() != imh()) { // If there is an enclosing method + if (level == CompLevel_aot) { + // Recompile the enclosing method to prevent infinite OSRs. Stay at AOT level while it's compiling. + if (max_osr_level != CompLevel_none && !CompileBroker::compilation_is_in_queue(mh)) { + compile(mh, InvocationEntryBci, MIN2((CompLevel)TieredStopAtLevel, CompLevel_full_profile), thread); + } + } else { + // Current loop event level is not AOT + guarantee(nm != NULL, "Should have nmethod here"); + cur_level = comp_level(mh()); + next_level = call_event(mh(), cur_level, thread); + + if (max_osr_level == CompLevel_full_optimization) { + // The inlinee OSRed to full opt, we need to modify the enclosing method to avoid deopts + bool make_not_entrant = false; + if (nm->is_osr_method()) { + // This is an osr method, just make it not entrant and recompile later if needed + make_not_entrant = true; + } else { + if (next_level != CompLevel_full_optimization) { + // next_level is not full opt, so we need to recompile the + // enclosing method without the inlinee + cur_level = CompLevel_none; + make_not_entrant = true; + } + } + if (make_not_entrant) { + if (PrintTieredEvents) { + int osr_bci = nm->is_osr_method() ? nm->osr_entry_bci() : InvocationEntryBci; + print_event(MAKE_NOT_ENTRANT, mh(), mh(), osr_bci, level); + } + nm->make_not_entrant(); + } + } + // Fix up next_level if necessary to avoid deopts + if (next_level == CompLevel_limited_profile && max_osr_level == CompLevel_full_profile) { + next_level = CompLevel_full_profile; + } + if (cur_level != next_level) { + if (!maybe_switch_to_aot(mh, cur_level, next_level, thread) && !CompileBroker::compilation_is_in_queue(mh)) { + compile(mh, InvocationEntryBci, next_level, thread); + } + } + } + } else { + cur_level = comp_level(mh()); + next_level = call_event(mh(), cur_level, thread); + if (next_level != cur_level) { + if (!maybe_switch_to_aot(mh, cur_level, next_level, thread) && !CompileBroker::compilation_is_in_queue(mh)) { + compile(mh, InvocationEntryBci, next_level, thread); + } + } + } + } +} + +#endif diff -r 496bbf554c5c -r 38176d1c5ec2 src/hotspot/share/compiler/tieredThresholdPolicy.hpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/hotspot/share/compiler/tieredThresholdPolicy.hpp Wed Oct 16 11:23:46 2019 +0200 @@ -0,0 +1,278 @@ +/* + * Copyright (c) 2010, 2019, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +#ifndef SHARE_COMPILER_TIEREDTHRESHOLDPOLICY_HPP +#define SHARE_COMPILER_TIEREDTHRESHOLDPOLICY_HPP + +#include "code/nmethod.hpp" +#include "compiler/compilationPolicy.hpp" +#include "oops/methodData.hpp" +#include "utilities/globalDefinitions.hpp" + +#ifdef TIERED + +class CompileTask; +class CompileQueue; +/* + * The system supports 5 execution levels: + * * level 0 - interpreter + * * level 1 - C1 with full optimization (no profiling) + * * level 2 - C1 with invocation and backedge counters + * * level 3 - C1 with full profiling (level 2 + MDO) + * * level 4 - C2 + * + * Levels 0, 2 and 3 periodically notify the runtime about the current value of the counters + * (invocation counters and backedge counters). The frequency of these notifications is + * different at each level. These notifications are used by the policy to decide what transition + * to make. + * + * Execution starts at level 0 (interpreter), then the policy can decide either to compile the + * method at level 3 or level 2. The decision is based on the following factors: + * 1. The length of the C2 queue determines the next level. The observation is that level 2 + * is generally faster than level 3 by about 30%, therefore we would want to minimize the time + * a method spends at level 3. We should only spend the time at level 3 that is necessary to get + * adequate profiling. So, if the C2 queue is long enough it is more beneficial to go first to + * level 2, because if we transitioned to level 3 we would be stuck there until our C2 compile + * request makes its way through the long queue. When the load on C2 recedes we are going to + * recompile at level 3 and start gathering profiling information. + * 2. The length of C1 queue is used to dynamically adjust the thresholds, so as to introduce + * additional filtering if the compiler is overloaded. The rationale is that by the time a + * method gets compiled it can become unused, so it doesn't make sense to put too much onto the + * queue. + * + * After profiling is completed at level 3 the transition is made to level 4. Again, the length + * of the C2 queue is used as a feedback to adjust the thresholds. + * + * After the first C1 compile some basic information is determined about the code like the number + * of the blocks and the number of the loops. Based on that it can be decided that a method + * is trivial and compiling it with C1 will yield the same code. In this case the method is + * compiled at level 1 instead of 4. + * + * We also support profiling at level 0. If C1 is slow enough to produce the level 3 version of + * the code and the C2 queue is sufficiently small we can decide to start profiling in the + * interpreter (and continue profiling in the compiled code once the level 3 version arrives). + * If the profiling at level 0 is fully completed before level 3 version is produced, a level 2 + * version is compiled instead in order to run faster waiting for a level 4 version. + * + * Compile queues are implemented as priority queues - for each method in the queue we compute + * the event rate (the number of invocation and backedge counter increments per unit of time). + * When getting an element off the queue we pick the one with the largest rate. Maintaining the + * rate also allows us to remove stale methods (the ones that got on the queue but stopped + * being used shortly after that). +*/ + +/* Command line options: + * - Tier?InvokeNotifyFreqLog and Tier?BackedgeNotifyFreqLog control the frequency of method + * invocation and backedge notifications. Basically every n-th invocation or backedge a mutator thread + * makes a call into the runtime. + * + * - Tier?InvocationThreshold, Tier?CompileThreshold, Tier?BackEdgeThreshold, Tier?MinInvocationThreshold control + * compilation thresholds. + * Level 2 thresholds are not used and are provided for option-compatibility and potential future use. + * Other thresholds work as follows: + * + * Transition from interpreter (level 0) to C1 with full profiling (level 3) happens when + * the following predicate is true (X is the level): + * + * i > TierXInvocationThreshold * s || (i > TierXMinInvocationThreshold * s && i + b > TierXCompileThreshold * s), + * + * where $i$ is the number of method invocations, $b$ number of backedges and $s$ is the scaling + * coefficient that will be discussed further. + * The intuition is to equalize the time that is spend profiling each method. + * The same predicate is used to control the transition from level 3 to level 4 (C2). It should be + * noted though that the thresholds are relative. Moreover i and b for the 0->3 transition come + * from Method* and for 3->4 transition they come from MDO (since profiled invocations are + * counted separately). Finally, if a method does not contain anything worth profiling, a transition + * from level 3 to level 4 occurs without considering thresholds (e.g., with fewer invocations than + * what is specified by Tier4InvocationThreshold). + * + * OSR transitions are controlled simply with b > TierXBackEdgeThreshold * s predicates. + * + * - Tier?LoadFeedback options are used to automatically scale the predicates described above depending + * on the compiler load. The scaling coefficients are computed as follows: + * + * s = queue_size_X / (TierXLoadFeedback * compiler_count_X) + 1, + * + * where queue_size_X is the current size of the compiler queue of level X, and compiler_count_X + * is the number of level X compiler threads. + * + * Basically these parameters describe how many methods should be in the compile queue + * per compiler thread before the scaling coefficient increases by one. + * + * This feedback provides the mechanism to automatically control the flow of compilation requests + * depending on the machine speed, mutator load and other external factors. + * + * - Tier3DelayOn and Tier3DelayOff parameters control another important feedback loop. + * Consider the following observation: a method compiled with full profiling (level 3) + * is about 30% slower than a method at level 2 (just invocation and backedge counters, no MDO). + * Normally, the following transitions will occur: 0->3->4. The problem arises when the C2 queue + * gets congested and the 3->4 transition is delayed. While the method is the C2 queue it continues + * executing at level 3 for much longer time than is required by the predicate and at suboptimal speed. + * The idea is to dynamically change the behavior of the system in such a way that if a substantial + * load on C2 is detected we would first do the 0->2 transition allowing a method to run faster. + * And then when the load decreases to allow 2->3 transitions. + * + * Tier3Delay* parameters control this switching mechanism. + * Tier3DelayOn is the number of methods in the C2 queue per compiler thread after which the policy + * no longer does 0->3 transitions but does 0->2 transitions instead. + * Tier3DelayOff switches the original behavior back when the number of methods in the C2 queue + * per compiler thread falls below the specified amount. + * The hysteresis is necessary to avoid jitter. + * + * - TieredCompileTaskTimeout is the amount of time an idle method can spend in the compile queue. + * Basically, since we use the event rate d(i + b)/dt as a value of priority when selecting a method to + * compile from the compile queue, we also can detect stale methods for which the rate has been + * 0 for some time in the same iteration. Stale methods can appear in the queue when an application + * abruptly changes its behavior. + * + * - TieredStopAtLevel, is used mostly for testing. It allows to bypass the policy logic and stick + * to a given level. For example it's useful to set TieredStopAtLevel = 1 in order to compile everything + * with pure c1. + * + * - Tier0ProfilingStartPercentage allows the interpreter to start profiling when the inequalities in the + * 0->3 predicate are already exceeded by the given percentage but the level 3 version of the + * method is still not ready. We can even go directly from level 0 to 4 if c1 doesn't produce a compiled + * version in time. This reduces the overall transition to level 4 and decreases the startup time. + * Note that this behavior is also guarded by the Tier3Delay mechanism: when the c2 queue is too long + * these is not reason to start profiling prematurely. + * + * - TieredRateUpdateMinTime and TieredRateUpdateMaxTime are parameters of the rate computation. + * Basically, the rate is not computed more frequently than TieredRateUpdateMinTime and is considered + * to be zero if no events occurred in TieredRateUpdateMaxTime. + */ + +class TieredThresholdPolicy : public CompilationPolicy { + jlong _start_time; + int _c1_count, _c2_count; + + // Check if the counter is big enough and set carry (effectively infinity). + inline void set_carry_if_necessary(InvocationCounter *counter); + // Set carry flags in the counters (in Method* and MDO). + inline void handle_counter_overflow(Method* method); + // Call and loop predicates determine whether a transition to a higher compilation + // level should be performed (pointers to predicate functions are passed to common_TF(). + // Predicates also take compiler load into account. + typedef bool (TieredThresholdPolicy::*Predicate)(int i, int b, CompLevel cur_level, Method* method); + bool call_predicate(int i, int b, CompLevel cur_level, Method* method); + bool loop_predicate(int i, int b, CompLevel cur_level, Method* method); + // Common transition function. Given a predicate determines if a method should transition to another level. + CompLevel common(Predicate p, Method* method, CompLevel cur_level, bool disable_feedback = false); + // Transition functions. + // call_event determines if a method should be compiled at a different + // level with a regular invocation entry. + CompLevel call_event(Method* method, CompLevel cur_level, JavaThread* thread); + // loop_event checks if a method should be OSR compiled at a different + // level. + CompLevel loop_event(Method* method, CompLevel cur_level, JavaThread* thread); + void print_counters(const char* prefix, const methodHandle& mh); + // Has a method been long around? + // We don't remove old methods from the compile queue even if they have + // very low activity (see select_task()). + inline bool is_old(Method* method); + // Was a given method inactive for a given number of milliseconds. + // If it is, we would remove it from the queue (see select_task()). + inline bool is_stale(jlong t, jlong timeout, Method* m); + // Compute the weight of the method for the compilation scheduling + inline double weight(Method* method); + // Apply heuristics and return true if x should be compiled before y + inline bool compare_methods(Method* x, Method* y); + // Compute event rate for a given method. The rate is the number of event (invocations + backedges) + // per millisecond. + inline void update_rate(jlong t, Method* m); + // Compute threshold scaling coefficient + inline double threshold_scale(CompLevel level, int feedback_k); + // If a method is old enough and is still in the interpreter we would want to + // start profiling without waiting for the compiled method to arrive. This function + // determines whether we should do that. + inline bool should_create_mdo(Method* method, CompLevel cur_level); + // Create MDO if necessary. + void create_mdo(const methodHandle& mh, JavaThread* thread); + // Is method profiled enough? + bool is_method_profiled(Method* method); + + double _increase_threshold_at_ratio; + + bool maybe_switch_to_aot(const methodHandle& mh, CompLevel cur_level, CompLevel next_level, JavaThread* thread); + + int c1_count() const { return _c1_count; } + int c2_count() const { return _c2_count; } + void set_c1_count(int x) { _c1_count = x; } + void set_c2_count(int x) { _c2_count = x; } + + enum EventType { CALL, LOOP, COMPILE, REMOVE_FROM_QUEUE, UPDATE_IN_QUEUE, REPROFILE, MAKE_NOT_ENTRANT }; + void print_event(EventType type, const methodHandle& mh, const methodHandle& imh, int bci, CompLevel level); + // Print policy-specific information if necessary + void print_specific(EventType type, const methodHandle& mh, const methodHandle& imh, int bci, CompLevel level); + // Check if the method can be compiled, change level if necessary + void compile(const methodHandle& mh, int bci, CompLevel level, JavaThread* thread); + // Submit a given method for compilation + void submit_compile(const methodHandle& mh, int bci, CompLevel level, JavaThread* thread); + // Simple methods are as good being compiled with C1 as C2. + // This function tells if it's such a function. + inline static bool is_trivial(Method* method); + // Force method to be compiled at CompLevel_simple? + inline static bool should_compile_at_level_simple(Method* method); + + // Predicate helpers are used by .*_predicate() methods as well as others. + // They check the given counter values, multiplied by the scale against the thresholds. + template static inline bool call_predicate_helper(int i, int b, double scale, Method* method); + template static inline bool loop_predicate_helper(int i, int b, double scale, Method* method); + + // Get a compilation level for a given method. + static CompLevel comp_level(Method* method); + void method_invocation_event(const methodHandle& method, const methodHandle& inlinee, + CompLevel level, CompiledMethod* nm, JavaThread* thread); + void method_back_branch_event(const methodHandle& method, const methodHandle& inlinee, + int bci, CompLevel level, CompiledMethod* nm, JavaThread* thread); + + void set_increase_threshold_at_ratio() { _increase_threshold_at_ratio = 100 / (100 - (double)IncreaseFirstTierCompileThresholdAt); } + void set_start_time(jlong t) { _start_time = t; } + jlong start_time() const { return _start_time; } + +public: + TieredThresholdPolicy() : _start_time(0), _c1_count(0), _c2_count(0) { } + virtual int compiler_count(CompLevel comp_level) { + if (is_c1_compile(comp_level)) return c1_count(); + if (is_c2_compile(comp_level)) return c2_count(); + return 0; + } + virtual CompLevel initial_compile_level() { return MIN2((CompLevel)TieredStopAtLevel, CompLevel_initial_compile); } + virtual void do_safepoint_work() { } + virtual void delay_compilation(Method* method) { } + virtual void disable_compilation(Method* method) { } + virtual void reprofile(ScopeDesc* trap_scope, bool is_osr); + virtual nmethod* event(const methodHandle& method, const methodHandle& inlinee, + int branch_bci, int bci, CompLevel comp_level, CompiledMethod* nm, JavaThread* thread); + // Select task is called by CompileBroker. We should return a task or NULL. + virtual CompileTask* select_task(CompileQueue* compile_queue); + // Tell the runtime if we think a given method is adequately profiled. + virtual bool is_mature(Method* method); + // Initialize: set compiler thread count + virtual void initialize(); + virtual bool should_not_inline(ciEnv* env, ciMethod* callee); +}; + +#endif // TIERED + +#endif // SHARE_COMPILER_TIEREDTHRESHOLDPOLICY_HPP diff -r 496bbf554c5c -r 38176d1c5ec2 src/hotspot/share/gc/epsilon/epsilonArguments.cpp --- a/src/hotspot/share/gc/epsilon/epsilonArguments.cpp Wed Oct 16 01:16:12 2019 +0200 +++ b/src/hotspot/share/gc/epsilon/epsilonArguments.cpp Wed Oct 16 11:23:46 2019 +0200 @@ -45,13 +45,25 @@ FLAG_SET_DEFAULT(ExitOnOutOfMemoryError, true); } + // Warn users that non-resizable heap might be better for some configurations. + // We are not adjusting the heap size by ourselves, because it affects startup time. + if (InitialHeapSize != MaxHeapSize) { + log_warning(gc)("Consider setting -Xms equal to -Xmx to avoid resizing hiccups"); + } + + // Warn users that AlwaysPreTouch might be better for some configurations. + // We are not turning this on by ourselves, because it affects startup time. + if (FLAG_IS_DEFAULT(AlwaysPreTouch) && !AlwaysPreTouch) { + log_warning(gc)("Consider enabling -XX:+AlwaysPreTouch to avoid memory commit hiccups"); + } + if (EpsilonMaxTLABSize < MinTLABSize) { - warning("EpsilonMaxTLABSize < MinTLABSize, adjusting it to " SIZE_FORMAT, MinTLABSize); + log_warning(gc)("EpsilonMaxTLABSize < MinTLABSize, adjusting it to " SIZE_FORMAT, MinTLABSize); EpsilonMaxTLABSize = MinTLABSize; } if (!EpsilonElasticTLAB && EpsilonElasticTLABDecay) { - warning("Disabling EpsilonElasticTLABDecay because EpsilonElasticTLAB is disabled"); + log_warning(gc)("Disabling EpsilonElasticTLABDecay because EpsilonElasticTLAB is disabled"); FLAG_SET_DEFAULT(EpsilonElasticTLABDecay, false); } diff -r 496bbf554c5c -r 38176d1c5ec2 src/hotspot/share/gc/g1/heapRegionRemSet.hpp --- a/src/hotspot/share/gc/g1/heapRegionRemSet.hpp Wed Oct 16 01:16:12 2019 +0200 +++ b/src/hotspot/share/gc/g1/heapRegionRemSet.hpp Wed Oct 16 11:23:46 2019 +0200 @@ -186,10 +186,6 @@ _collision_list_next(NULL) {} - inline void add_card_work(CardIdx_t from_card, bool par); - - inline void add_reference_work(OopOrNarrowOopStar from, bool par); - public: // We need access in order to union things into the base table. BitMap* bm() { return &_bm; } @@ -206,12 +202,8 @@ inline void add_reference(OopOrNarrowOopStar from); - inline void seq_add_reference(OopOrNarrowOopStar from); - inline void add_card(CardIdx_t from_card_index); - void seq_add_card(CardIdx_t from_card_index); - // (Destructively) union the bitmap of the current table into the given // bitmap (which is assumed to be of the same size.) void union_bitmap_into(BitMap* bm) { @@ -381,12 +373,6 @@ _state = Complete; } - // Used in the sequential case. - void add_reference(OopOrNarrowOopStar from) { - add_reference(from, 0); - } - - // Used in the parallel case. void add_reference(OopOrNarrowOopStar from, uint tid) { RemSetState state = _state; if (state == Untracked) { diff -r 496bbf554c5c -r 38176d1c5ec2 src/hotspot/share/gc/g1/heapRegionRemSet.inline.hpp --- a/src/hotspot/share/gc/g1/heapRegionRemSet.inline.hpp Wed Oct 16 01:16:12 2019 +0200 +++ b/src/hotspot/share/gc/g1/heapRegionRemSet.inline.hpp Wed Oct 16 11:23:46 2019 +0200 @@ -35,20 +35,13 @@ _other_regions.iterate(cl); } -inline void PerRegionTable::add_card_work(CardIdx_t from_card, bool par) { - if (!_bm.at(from_card)) { - if (par) { - if (_bm.par_set_bit(from_card)) { - Atomic::inc(&_occupied); - } - } else { - _bm.set_bit(from_card); - _occupied++; - } +inline void PerRegionTable::add_card(CardIdx_t from_card_index) { + if (_bm.par_set_bit(from_card_index)) { + Atomic::inc(&_occupied); } } -inline void PerRegionTable::add_reference_work(OopOrNarrowOopStar from, bool par) { +inline void PerRegionTable::add_reference(OopOrNarrowOopStar from) { // Must make this robust in case "from" is not in "_hr", because of // concurrency. @@ -58,26 +51,10 @@ // and adding a bit to the new table is never incorrect. if (loc_hr->is_in_reserved(from)) { CardIdx_t from_card = OtherRegionsTable::card_within_region(from, loc_hr); - add_card_work(from_card, par); + add_card(from_card); } } -inline void PerRegionTable::add_card(CardIdx_t from_card_index) { - add_card_work(from_card_index, /*parallel*/ true); -} - -inline void PerRegionTable::seq_add_card(CardIdx_t from_card_index) { - add_card_work(from_card_index, /*parallel*/ false); -} - -inline void PerRegionTable::add_reference(OopOrNarrowOopStar from) { - add_reference_work(from, /*parallel*/ true); -} - -inline void PerRegionTable::seq_add_reference(OopOrNarrowOopStar from) { - add_reference_work(from, /*parallel*/ false); -} - inline void PerRegionTable::init(HeapRegion* hr, bool clear_links_to_all_list) { if (clear_links_to_all_list) { set_next(NULL); diff -r 496bbf554c5c -r 38176d1c5ec2 src/hotspot/share/gc/shenandoah/heuristics/shenandoahAdaptiveHeuristics.cpp --- a/src/hotspot/share/gc/shenandoah/heuristics/shenandoahAdaptiveHeuristics.cpp Wed Oct 16 01:16:12 2019 +0200 +++ b/src/hotspot/share/gc/shenandoah/heuristics/shenandoahAdaptiveHeuristics.cpp Wed Oct 16 11:23:46 2019 +0200 @@ -66,9 +66,12 @@ size_t min_garbage = free_target > actual_free ? (free_target - actual_free) : 0; size_t max_cset = (size_t)((1.0 * capacity / 100 * ShenandoahEvacReserve) / ShenandoahEvacWaste); - log_info(gc, ergo)("Adaptive CSet Selection. Target Free: " SIZE_FORMAT "M, Actual Free: " - SIZE_FORMAT "M, Max CSet: " SIZE_FORMAT "M, Min Garbage: " SIZE_FORMAT "M", - free_target / M, actual_free / M, max_cset / M, min_garbage / M); + log_info(gc, ergo)("Adaptive CSet Selection. Target Free: " SIZE_FORMAT "%s, Actual Free: " + SIZE_FORMAT "%s, Max CSet: " SIZE_FORMAT "%s, Min Garbage: " SIZE_FORMAT "%s", + byte_size_in_proper_unit(free_target), proper_unit_for_byte_size(free_target), + byte_size_in_proper_unit(actual_free), proper_unit_for_byte_size(actual_free), + byte_size_in_proper_unit(max_cset), proper_unit_for_byte_size(max_cset), + byte_size_in_proper_unit(min_garbage), proper_unit_for_byte_size(min_garbage)); // Better select garbage-first regions QuickSort::sort(data, (int)size, compare_by_garbage, false); @@ -119,8 +122,9 @@ // anything else. size_t min_threshold = capacity / 100 * ShenandoahMinFreeThreshold; if (available < min_threshold) { - log_info(gc)("Trigger: Free (" SIZE_FORMAT "M) is below minimum threshold (" SIZE_FORMAT "M)", - available / M, min_threshold / M); + log_info(gc)("Trigger: Free (" SIZE_FORMAT "%s) is below minimum threshold (" SIZE_FORMAT "%s)", + byte_size_in_proper_unit(available), proper_unit_for_byte_size(available), + byte_size_in_proper_unit(min_threshold), proper_unit_for_byte_size(min_threshold)); return true; } @@ -129,8 +133,10 @@ if (_gc_times_learned < max_learn) { size_t init_threshold = capacity / 100 * ShenandoahInitFreeThreshold; if (available < init_threshold) { - log_info(gc)("Trigger: Learning " SIZE_FORMAT " of " SIZE_FORMAT ". Free (" SIZE_FORMAT "M) is below initial threshold (" SIZE_FORMAT "M)", - _gc_times_learned + 1, max_learn, available / M, init_threshold / M); + log_info(gc)("Trigger: Learning " SIZE_FORMAT " of " SIZE_FORMAT ". Free (" SIZE_FORMAT "%s) is below initial threshold (" SIZE_FORMAT "%s)", + _gc_times_learned + 1, max_learn, + byte_size_in_proper_unit(available), proper_unit_for_byte_size(available), + byte_size_in_proper_unit(init_threshold), proper_unit_for_byte_size(init_threshold)); return true; } } @@ -154,10 +160,15 @@ double allocation_rate = heap->bytes_allocated_since_gc_start() / time_since_last; if (average_gc > allocation_headroom / allocation_rate) { - log_info(gc)("Trigger: Average GC time (%.2f ms) is above the time for allocation rate (%.2f MB/s) to deplete free headroom (" SIZE_FORMAT "M)", - average_gc * 1000, allocation_rate / M, allocation_headroom / M); - log_info(gc, ergo)("Free headroom: " SIZE_FORMAT "M (free) - " SIZE_FORMAT "M (spike) - " SIZE_FORMAT "M (penalties) = " SIZE_FORMAT "M", - available / M, spike_headroom / M, penalties / M, allocation_headroom / M); + log_info(gc)("Trigger: Average GC time (%.2f ms) is above the time for allocation rate (%.0f %sB/s) to deplete free headroom (" SIZE_FORMAT "%s)", + average_gc * 1000, + byte_size_in_proper_unit(allocation_rate), proper_unit_for_byte_size(allocation_rate), + byte_size_in_proper_unit(allocation_headroom), proper_unit_for_byte_size(allocation_headroom)); + log_info(gc, ergo)("Free headroom: " SIZE_FORMAT "%s (free) - " SIZE_FORMAT "%s (spike) - " SIZE_FORMAT "%s (penalties) = " SIZE_FORMAT "%s", + byte_size_in_proper_unit(available), proper_unit_for_byte_size(available), + byte_size_in_proper_unit(spike_headroom), proper_unit_for_byte_size(spike_headroom), + byte_size_in_proper_unit(penalties), proper_unit_for_byte_size(penalties), + byte_size_in_proper_unit(allocation_headroom), proper_unit_for_byte_size(allocation_headroom)); return true; } diff -r 496bbf554c5c -r 38176d1c5ec2 src/hotspot/share/gc/shenandoah/heuristics/shenandoahCompactHeuristics.cpp --- a/src/hotspot/share/gc/shenandoah/heuristics/shenandoahCompactHeuristics.cpp Wed Oct 16 01:16:12 2019 +0200 +++ b/src/hotspot/share/gc/shenandoah/heuristics/shenandoahCompactHeuristics.cpp Wed Oct 16 11:23:46 2019 +0200 @@ -59,21 +59,24 @@ size_t min_threshold = capacity / 100 * ShenandoahMinFreeThreshold; if (available < min_threshold) { - log_info(gc)("Trigger: Free (" SIZE_FORMAT "M) is below minimum threshold (" SIZE_FORMAT "M)", - available / M, min_threshold / M); + log_info(gc)("Trigger: Free (" SIZE_FORMAT "%s) is below minimum threshold (" SIZE_FORMAT "%s)", + byte_size_in_proper_unit(available), proper_unit_for_byte_size(available), + byte_size_in_proper_unit(min_threshold), proper_unit_for_byte_size(min_threshold)); return true; } if (available < threshold_bytes_allocated) { - log_info(gc)("Trigger: Free (" SIZE_FORMAT "M) is lower than allocated recently (" SIZE_FORMAT "M)", - available / M, threshold_bytes_allocated / M); + log_info(gc)("Trigger: Free (" SIZE_FORMAT "%s) is lower than allocated recently (" SIZE_FORMAT "%s)", + byte_size_in_proper_unit(available), proper_unit_for_byte_size(available), + byte_size_in_proper_unit(threshold_bytes_allocated), proper_unit_for_byte_size(threshold_bytes_allocated)); return true; } size_t bytes_allocated = heap->bytes_allocated_since_gc_start(); if (bytes_allocated > threshold_bytes_allocated) { - log_info(gc)("Trigger: Allocated since last cycle (" SIZE_FORMAT "M) is larger than allocation threshold (" SIZE_FORMAT "M)", - bytes_allocated / M, threshold_bytes_allocated / M); + log_info(gc)("Trigger: Allocated since last cycle (" SIZE_FORMAT "%s) is larger than allocation threshold (" SIZE_FORMAT "%s)", + byte_size_in_proper_unit(bytes_allocated), proper_unit_for_byte_size(bytes_allocated), + byte_size_in_proper_unit(threshold_bytes_allocated), proper_unit_for_byte_size(threshold_bytes_allocated)); return true; } @@ -86,8 +89,9 @@ // Do not select too large CSet that would overflow the available free space size_t max_cset = actual_free * 3 / 4; - log_info(gc, ergo)("CSet Selection. Actual Free: " SIZE_FORMAT "M, Max CSet: " SIZE_FORMAT "M", - actual_free / M, max_cset / M); + log_info(gc, ergo)("CSet Selection. Actual Free: " SIZE_FORMAT "%s, Max CSet: " SIZE_FORMAT "%s", + byte_size_in_proper_unit(actual_free), proper_unit_for_byte_size(actual_free), + byte_size_in_proper_unit(max_cset), proper_unit_for_byte_size(max_cset)); size_t threshold = ShenandoahHeapRegion::region_size_bytes() * ShenandoahGarbageThreshold / 100; diff -r 496bbf554c5c -r 38176d1c5ec2 src/hotspot/share/gc/shenandoah/heuristics/shenandoahPassiveHeuristics.cpp --- a/src/hotspot/share/gc/shenandoah/heuristics/shenandoahPassiveHeuristics.cpp Wed Oct 16 01:16:12 2019 +0200 +++ b/src/hotspot/share/gc/shenandoah/heuristics/shenandoahPassiveHeuristics.cpp Wed Oct 16 11:23:46 2019 +0200 @@ -60,8 +60,9 @@ size_t available = MAX2(capacity / 100 * ShenandoahEvacReserve, actual_free); size_t max_cset = (size_t)(available / ShenandoahEvacWaste); - log_info(gc, ergo)("CSet Selection. Actual Free: " SIZE_FORMAT "M, Max CSet: " SIZE_FORMAT "M", - actual_free / M, max_cset / M); + log_info(gc, ergo)("CSet Selection. Actual Free: " SIZE_FORMAT "%s, Max CSet: " SIZE_FORMAT "%s", + byte_size_in_proper_unit(actual_free), proper_unit_for_byte_size(actual_free), + byte_size_in_proper_unit(max_cset), proper_unit_for_byte_size(max_cset)); size_t threshold = ShenandoahHeapRegion::region_size_bytes() * ShenandoahGarbageThreshold / 100; diff -r 496bbf554c5c -r 38176d1c5ec2 src/hotspot/share/gc/shenandoah/heuristics/shenandoahStaticHeuristics.cpp --- a/src/hotspot/share/gc/shenandoah/heuristics/shenandoahStaticHeuristics.cpp Wed Oct 16 01:16:12 2019 +0200 +++ b/src/hotspot/share/gc/shenandoah/heuristics/shenandoahStaticHeuristics.cpp Wed Oct 16 11:23:46 2019 +0200 @@ -57,8 +57,9 @@ size_t threshold_available = capacity / 100 * ShenandoahFreeThreshold; if (available < threshold_available) { - log_info(gc)("Trigger: Free (" SIZE_FORMAT "M) is below free threshold (" SIZE_FORMAT "M)", - available / M, threshold_available / M); + log_info(gc)("Trigger: Free (" SIZE_FORMAT "%s) is below free threshold (" SIZE_FORMAT "%s)", + byte_size_in_proper_unit(available), proper_unit_for_byte_size(available), + byte_size_in_proper_unit(threshold_available), proper_unit_for_byte_size(threshold_available)); return true; } return ShenandoahHeuristics::should_start_gc(); diff -r 496bbf554c5c -r 38176d1c5ec2 src/hotspot/share/gc/shenandoah/heuristics/shenandoahTraversalHeuristics.cpp --- a/src/hotspot/share/gc/shenandoah/heuristics/shenandoahTraversalHeuristics.cpp Wed Oct 16 01:16:12 2019 +0200 +++ b/src/hotspot/share/gc/shenandoah/heuristics/shenandoahTraversalHeuristics.cpp Wed Oct 16 11:23:46 2019 +0200 @@ -100,9 +100,12 @@ size_t min_garbage = free_target > actual_free ? (free_target - actual_free) : 0; size_t max_cset = (size_t)((1.0 * capacity / 100 * ShenandoahEvacReserve) / ShenandoahEvacWaste); - log_info(gc, ergo)("Adaptive CSet Selection. Target Free: " SIZE_FORMAT "M, Actual Free: " - SIZE_FORMAT "M, Max CSet: " SIZE_FORMAT "M, Min Garbage: " SIZE_FORMAT "M", - free_target / M, actual_free / M, max_cset / M, min_garbage / M); + log_info(gc, ergo)("Adaptive CSet Selection. Target Free: " SIZE_FORMAT "%s, Actual Free: " + SIZE_FORMAT "%s, Max CSet: " SIZE_FORMAT "%s, Min Garbage: " SIZE_FORMAT "%s", + byte_size_in_proper_unit(free_target), proper_unit_for_byte_size(free_target), + byte_size_in_proper_unit(actual_free), proper_unit_for_byte_size(actual_free), + byte_size_in_proper_unit(max_cset), proper_unit_for_byte_size(max_cset), + byte_size_in_proper_unit(min_garbage), proper_unit_for_byte_size(min_garbage)); // Better select garbage-first regions, and then older ones QuickSort::sort(data, (int) cnt, compare_by_garbage_then_alloc_seq_ascending, false); @@ -190,8 +193,9 @@ // anything else. size_t min_threshold = capacity / 100 * ShenandoahMinFreeThreshold; if (available < min_threshold) { - log_info(gc)("Trigger: Free (" SIZE_FORMAT "M) is below minimum threshold (" SIZE_FORMAT "M)", - available / M, min_threshold / M); + log_info(gc)("Trigger: Free (" SIZE_FORMAT "%s) is below minimum threshold (" SIZE_FORMAT "%s)", + byte_size_in_proper_unit(available), proper_unit_for_byte_size(available), + byte_size_in_proper_unit(min_threshold), proper_unit_for_byte_size(min_threshold)); return true; } @@ -200,8 +204,10 @@ if (_gc_times_learned < max_learn) { size_t init_threshold = capacity / 100 * ShenandoahInitFreeThreshold; if (available < init_threshold) { - log_info(gc)("Trigger: Learning " SIZE_FORMAT " of " SIZE_FORMAT ". Free (" SIZE_FORMAT "M) is below initial threshold (" SIZE_FORMAT "M)", - _gc_times_learned + 1, max_learn, available / M, init_threshold / M); + log_info(gc)("Trigger: Learning " SIZE_FORMAT " of " SIZE_FORMAT ". Free (" SIZE_FORMAT "%s) is below initial threshold (" SIZE_FORMAT "%s)", + _gc_times_learned + 1, max_learn, + byte_size_in_proper_unit(available), proper_unit_for_byte_size(available), + byte_size_in_proper_unit(init_threshold), proper_unit_for_byte_size(init_threshold)); return true; } } @@ -223,10 +229,15 @@ double allocation_rate = heap->bytes_allocated_since_gc_start() / time_since_last; if (average_gc > allocation_headroom / allocation_rate) { - log_info(gc)("Trigger: Average GC time (%.2f ms) is above the time for allocation rate (%.2f MB/s) to deplete free headroom (" SIZE_FORMAT "M)", - average_gc * 1000, allocation_rate / M, allocation_headroom / M); - log_info(gc, ergo)("Free headroom: " SIZE_FORMAT "M (free) - " SIZE_FORMAT "M (spike) - " SIZE_FORMAT "M (penalties) = " SIZE_FORMAT "M", - available / M, spike_headroom / M, penalties / M, allocation_headroom / M); + log_info(gc)("Trigger: Average GC time (%.2f ms) is above the time for allocation rate (%.0f %sB/s) to deplete free headroom (" SIZE_FORMAT "%s)", + average_gc * 1000, + byte_size_in_proper_unit(allocation_rate), proper_unit_for_byte_size(allocation_rate), + byte_size_in_proper_unit(allocation_headroom), proper_unit_for_byte_size(allocation_headroom)); + log_info(gc, ergo)("Free headroom: " SIZE_FORMAT "%s (free) - " SIZE_FORMAT "%s (spike) - " SIZE_FORMAT "%s (penalties) = " SIZE_FORMAT "%s", + byte_size_in_proper_unit(available), proper_unit_for_byte_size(available), + byte_size_in_proper_unit(spike_headroom), proper_unit_for_byte_size(spike_headroom), + byte_size_in_proper_unit(penalties), proper_unit_for_byte_size(penalties), + byte_size_in_proper_unit(allocation_headroom), proper_unit_for_byte_size(allocation_headroom)); return true; } else if (ShenandoahHeuristics::should_start_gc()) { return true; diff -r 496bbf554c5c -r 38176d1c5ec2 src/hotspot/share/gc/shenandoah/shenandoahConcurrentMark.cpp --- a/src/hotspot/share/gc/shenandoah/shenandoahConcurrentMark.cpp Wed Oct 16 01:16:12 2019 +0200 +++ b/src/hotspot/share/gc/shenandoah/shenandoahConcurrentMark.cpp Wed Oct 16 11:23:46 2019 +0200 @@ -319,13 +319,20 @@ }; void ShenandoahConcurrentMark::update_thread_roots(ShenandoahPhaseTimings::Phase root_phase) { - WorkGang* workers = _heap->workers(); - bool is_par = workers->active_workers() > 1; + assert(ShenandoahSafepoint::is_at_shenandoah_safepoint(), "Must be at a safepoint"); + + ShenandoahGCPhase phase(root_phase); + #if COMPILER2_OR_JVMCI DerivedPointerTable::clear(); #endif + + WorkGang* workers = _heap->workers(); + bool is_par = workers->active_workers() > 1; + ShenandoahUpdateThreadRootsTask task(is_par, root_phase); workers->run_task(&task); + #if COMPILER2_OR_JVMCI DerivedPointerTable::update_pointers(); #endif diff -r 496bbf554c5c -r 38176d1c5ec2 src/hotspot/share/gc/shenandoah/shenandoahFreeSet.cpp --- a/src/hotspot/share/gc/shenandoah/shenandoahFreeSet.cpp Wed Oct 16 01:16:12 2019 +0200 +++ b/src/hotspot/share/gc/shenandoah/shenandoahFreeSet.cpp Wed Oct 16 11:23:46 2019 +0200 @@ -491,8 +491,12 @@ size_t max_humongous = max_contig * ShenandoahHeapRegion::region_size_bytes(); size_t free = capacity() - used(); - ls.print("Free: " SIZE_FORMAT "M (" SIZE_FORMAT " regions), Max regular: " SIZE_FORMAT "K, Max humongous: " SIZE_FORMAT "K, ", - total_free / M, mutator_count(), max / K, max_humongous / K); + ls.print("Free: " SIZE_FORMAT "%s (" SIZE_FORMAT " regions), Max regular: " SIZE_FORMAT "%s, Max humongous: " SIZE_FORMAT "%s, ", + byte_size_in_proper_unit(total_free), proper_unit_for_byte_size(total_free), + mutator_count(), + byte_size_in_proper_unit(max), proper_unit_for_byte_size(max), + byte_size_in_proper_unit(max_humongous), proper_unit_for_byte_size(max_humongous) + ); size_t frag_ext; if (free > 0) { @@ -525,8 +529,10 @@ } } - ls.print_cr("Evacuation Reserve: " SIZE_FORMAT "M (" SIZE_FORMAT " regions), Max regular: " SIZE_FORMAT "K", - total_free / M, collector_count(), max / K); + ls.print_cr("Evacuation Reserve: " SIZE_FORMAT "%s (" SIZE_FORMAT " regions), Max regular: " SIZE_FORMAT "%s", + byte_size_in_proper_unit(total_free), proper_unit_for_byte_size(total_free), + collector_count(), + byte_size_in_proper_unit(max), proper_unit_for_byte_size(max)); } } } diff -r 496bbf554c5c -r 38176d1c5ec2 src/hotspot/share/gc/shenandoah/shenandoahHeap.cpp --- a/src/hotspot/share/gc/shenandoah/shenandoahHeap.cpp Wed Oct 16 01:16:12 2019 +0200 +++ b/src/hotspot/share/gc/shenandoah/shenandoahHeap.cpp Wed Oct 16 11:23:46 2019 +0200 @@ -522,10 +522,14 @@ void ShenandoahHeap::print_on(outputStream* st) const { st->print_cr("Shenandoah Heap"); - st->print_cr(" " SIZE_FORMAT "K total, " SIZE_FORMAT "K committed, " SIZE_FORMAT "K used", - max_capacity() / K, committed() / K, used() / K); - st->print_cr(" " SIZE_FORMAT " x " SIZE_FORMAT"K regions", - num_regions(), ShenandoahHeapRegion::region_size_bytes() / K); + st->print_cr(" " SIZE_FORMAT "%s total, " SIZE_FORMAT "%s committed, " SIZE_FORMAT "%s used", + byte_size_in_proper_unit(max_capacity()), proper_unit_for_byte_size(max_capacity()), + byte_size_in_proper_unit(committed()), proper_unit_for_byte_size(committed()), + byte_size_in_proper_unit(used()), proper_unit_for_byte_size(used())); + st->print_cr(" " SIZE_FORMAT " x " SIZE_FORMAT"%s regions", + num_regions(), + byte_size_in_proper_unit(ShenandoahHeapRegion::region_size_bytes()), + proper_unit_for_byte_size(ShenandoahHeapRegion::region_size_bytes())); st->print("Status: "); if (has_forwarded_objects()) st->print("has forwarded objects, "); @@ -959,7 +963,7 @@ ShenandoahConcurrentEvacuateRegionObjectClosure cl(_sh); ShenandoahHeapRegion* r; while ((r =_cs->claim_next()) != NULL) { - assert(r->has_live(), "all-garbage regions are reclaimed early"); + assert(r->has_live(), "Region " SIZE_FORMAT " should have been reclaimed early", r->region_number()); _sh->marked_object_iterate(r, &cl); if (ShenandoahPacing) { diff -r 496bbf554c5c -r 38176d1c5ec2 src/hotspot/share/gc/shenandoah/shenandoahHeapRegion.cpp --- a/src/hotspot/share/gc/shenandoah/shenandoahHeapRegion.cpp Wed Oct 16 01:16:12 2019 +0200 +++ b/src/hotspot/share/gc/shenandoah/shenandoahHeapRegion.cpp Wed Oct 16 11:23:46 2019 +0200 @@ -527,29 +527,35 @@ size_t region_size; if (FLAG_IS_DEFAULT(ShenandoahHeapRegionSize)) { if (ShenandoahMinRegionSize > max_heap_size / MIN_NUM_REGIONS) { - err_msg message("Max heap size (" SIZE_FORMAT "K) is too low to afford the minimum number " - "of regions (" SIZE_FORMAT ") of minimum region size (" SIZE_FORMAT "K).", - max_heap_size/K, MIN_NUM_REGIONS, ShenandoahMinRegionSize/K); + err_msg message("Max heap size (" SIZE_FORMAT "%s) is too low to afford the minimum number " + "of regions (" SIZE_FORMAT ") of minimum region size (" SIZE_FORMAT "%s).", + byte_size_in_proper_unit(max_heap_size), proper_unit_for_byte_size(max_heap_size), + MIN_NUM_REGIONS, + byte_size_in_proper_unit(ShenandoahMinRegionSize), proper_unit_for_byte_size(ShenandoahMinRegionSize)); vm_exit_during_initialization("Invalid -XX:ShenandoahMinRegionSize option", message); } if (ShenandoahMinRegionSize < MIN_REGION_SIZE) { - err_msg message("" SIZE_FORMAT "K should not be lower than minimum region size (" SIZE_FORMAT "K).", - ShenandoahMinRegionSize/K, MIN_REGION_SIZE/K); + err_msg message("" SIZE_FORMAT "%s should not be lower than minimum region size (" SIZE_FORMAT "%s).", + byte_size_in_proper_unit(ShenandoahMinRegionSize), proper_unit_for_byte_size(ShenandoahMinRegionSize), + byte_size_in_proper_unit(MIN_REGION_SIZE), proper_unit_for_byte_size(MIN_REGION_SIZE)); vm_exit_during_initialization("Invalid -XX:ShenandoahMinRegionSize option", message); } if (ShenandoahMinRegionSize < MinTLABSize) { - err_msg message("" SIZE_FORMAT "K should not be lower than TLAB size size (" SIZE_FORMAT "K).", - ShenandoahMinRegionSize/K, MinTLABSize/K); + err_msg message("" SIZE_FORMAT "%s should not be lower than TLAB size size (" SIZE_FORMAT "%s).", + byte_size_in_proper_unit(ShenandoahMinRegionSize), proper_unit_for_byte_size(ShenandoahMinRegionSize), + byte_size_in_proper_unit(MinTLABSize), proper_unit_for_byte_size(MinTLABSize)); vm_exit_during_initialization("Invalid -XX:ShenandoahMinRegionSize option", message); } if (ShenandoahMaxRegionSize < MIN_REGION_SIZE) { - err_msg message("" SIZE_FORMAT "K should not be lower than min region size (" SIZE_FORMAT "K).", - ShenandoahMaxRegionSize/K, MIN_REGION_SIZE/K); + err_msg message("" SIZE_FORMAT "%s should not be lower than min region size (" SIZE_FORMAT "%s).", + byte_size_in_proper_unit(ShenandoahMaxRegionSize), proper_unit_for_byte_size(ShenandoahMaxRegionSize), + byte_size_in_proper_unit(MIN_REGION_SIZE), proper_unit_for_byte_size(MIN_REGION_SIZE)); vm_exit_during_initialization("Invalid -XX:ShenandoahMaxRegionSize option", message); } if (ShenandoahMinRegionSize > ShenandoahMaxRegionSize) { - err_msg message("Minimum (" SIZE_FORMAT "K) should be larger than maximum (" SIZE_FORMAT "K).", - ShenandoahMinRegionSize/K, ShenandoahMaxRegionSize/K); + err_msg message("Minimum (" SIZE_FORMAT "%s) should be larger than maximum (" SIZE_FORMAT "%s).", + byte_size_in_proper_unit(ShenandoahMinRegionSize), proper_unit_for_byte_size(ShenandoahMinRegionSize), + byte_size_in_proper_unit(ShenandoahMaxRegionSize), proper_unit_for_byte_size(ShenandoahMaxRegionSize)); vm_exit_during_initialization("Invalid -XX:ShenandoahMinRegionSize or -XX:ShenandoahMaxRegionSize", message); } @@ -563,19 +569,23 @@ } else { if (ShenandoahHeapRegionSize > max_heap_size / MIN_NUM_REGIONS) { - err_msg message("Max heap size (" SIZE_FORMAT "K) is too low to afford the minimum number " - "of regions (" SIZE_FORMAT ") of requested size (" SIZE_FORMAT "K).", - max_heap_size/K, MIN_NUM_REGIONS, ShenandoahHeapRegionSize/K); + err_msg message("Max heap size (" SIZE_FORMAT "%s) is too low to afford the minimum number " + "of regions (" SIZE_FORMAT ") of requested size (" SIZE_FORMAT "%s).", + byte_size_in_proper_unit(max_heap_size), proper_unit_for_byte_size(max_heap_size), + MIN_NUM_REGIONS, + byte_size_in_proper_unit(ShenandoahHeapRegionSize), proper_unit_for_byte_size(ShenandoahHeapRegionSize)); vm_exit_during_initialization("Invalid -XX:ShenandoahHeapRegionSize option", message); } if (ShenandoahHeapRegionSize < ShenandoahMinRegionSize) { - err_msg message("Heap region size (" SIZE_FORMAT "K) should be larger than min region size (" SIZE_FORMAT "K).", - ShenandoahHeapRegionSize/K, ShenandoahMinRegionSize/K); + err_msg message("Heap region size (" SIZE_FORMAT "%s) should be larger than min region size (" SIZE_FORMAT "%s).", + byte_size_in_proper_unit(ShenandoahHeapRegionSize), proper_unit_for_byte_size(ShenandoahHeapRegionSize), + byte_size_in_proper_unit(ShenandoahMinRegionSize), proper_unit_for_byte_size(ShenandoahMinRegionSize)); vm_exit_during_initialization("Invalid -XX:ShenandoahHeapRegionSize option", message); } if (ShenandoahHeapRegionSize > ShenandoahMaxRegionSize) { - err_msg message("Heap region size (" SIZE_FORMAT "K) should be lower than max region size (" SIZE_FORMAT "K).", - ShenandoahHeapRegionSize/K, ShenandoahMaxRegionSize/K); + err_msg message("Heap region size (" SIZE_FORMAT "%s) should be lower than max region size (" SIZE_FORMAT "%s).", + byte_size_in_proper_unit(ShenandoahHeapRegionSize), proper_unit_for_byte_size(ShenandoahHeapRegionSize), + byte_size_in_proper_unit(ShenandoahMaxRegionSize), proper_unit_for_byte_size(ShenandoahMaxRegionSize)); vm_exit_during_initialization("Invalid -XX:ShenandoahHeapRegionSize option", message); } region_size = ShenandoahHeapRegionSize; diff -r 496bbf554c5c -r 38176d1c5ec2 src/hotspot/share/gc/shenandoah/shenandoahHeapRegion.hpp --- a/src/hotspot/share/gc/shenandoah/shenandoahHeapRegion.hpp Wed Oct 16 01:16:12 2019 +0200 +++ b/src/hotspot/share/gc/shenandoah/shenandoahHeapRegion.hpp Wed Oct 16 11:23:46 2019 +0200 @@ -198,7 +198,7 @@ // Macro-properties: bool is_alloc_allowed() const { return is_empty() || is_regular() || _state == _pinned; } - bool is_move_allowed() const { return is_regular() || _state == _cset || (ShenandoahHumongousMoves && _state == _humongous_start); } + bool is_stw_move_allowed() const { return is_regular() || _state == _cset || (ShenandoahHumongousMoves && _state == _humongous_start); } RegionState state() const { return _state; } int state_ordinal() const { return region_state_to_ordinal(_state); } diff -r 496bbf554c5c -r 38176d1c5ec2 src/hotspot/share/gc/shenandoah/shenandoahHeuristics.cpp --- a/src/hotspot/share/gc/shenandoah/shenandoahHeuristics.cpp Wed Oct 16 01:16:12 2019 +0200 +++ b/src/hotspot/share/gc/shenandoah/shenandoahHeuristics.cpp Wed Oct 16 11:23:46 2019 +0200 @@ -186,8 +186,9 @@ // given the amount of immediately reclaimable garbage. If we do, figure out the collection set. assert (immediate_garbage <= total_garbage, - "Cannot have more immediate garbage than total garbage: " SIZE_FORMAT "M vs " SIZE_FORMAT "M", - immediate_garbage / M, total_garbage / M); + "Cannot have more immediate garbage than total garbage: " SIZE_FORMAT "%s vs " SIZE_FORMAT "%s", + byte_size_in_proper_unit(immediate_garbage), proper_unit_for_byte_size(immediate_garbage), + byte_size_in_proper_unit(total_garbage), proper_unit_for_byte_size(total_garbage)); size_t immediate_percent = total_garbage == 0 ? 0 : (immediate_garbage * 100 / total_garbage); @@ -196,12 +197,16 @@ collection_set->update_region_status(); size_t cset_percent = total_garbage == 0 ? 0 : (collection_set->garbage() * 100 / total_garbage); - log_info(gc, ergo)("Collectable Garbage: " SIZE_FORMAT "M (" SIZE_FORMAT "%% of total), " SIZE_FORMAT "M CSet, " SIZE_FORMAT " CSet regions", - collection_set->garbage() / M, cset_percent, collection_set->live_data() / M, collection_set->count()); + log_info(gc, ergo)("Collectable Garbage: " SIZE_FORMAT "%s (" SIZE_FORMAT "%% of total), " SIZE_FORMAT "%s CSet, " SIZE_FORMAT " CSet regions", + byte_size_in_proper_unit(collection_set->garbage()), proper_unit_for_byte_size(collection_set->garbage()), + cset_percent, + byte_size_in_proper_unit(collection_set->live_data()), proper_unit_for_byte_size(collection_set->live_data()), + collection_set->count()); } - log_info(gc, ergo)("Immediate Garbage: " SIZE_FORMAT "M (" SIZE_FORMAT "%% of total), " SIZE_FORMAT " regions", - immediate_garbage / M, immediate_percent, immediate_regions); + log_info(gc, ergo)("Immediate Garbage: " SIZE_FORMAT "%s (" SIZE_FORMAT "%% of total), " SIZE_FORMAT " regions", + byte_size_in_proper_unit(immediate_garbage), proper_unit_for_byte_size(immediate_garbage), + immediate_percent, immediate_regions); } void ShenandoahHeuristics::record_gc_start() { diff -r 496bbf554c5c -r 38176d1c5ec2 src/hotspot/share/gc/shenandoah/shenandoahMarkCompact.cpp --- a/src/hotspot/share/gc/shenandoah/shenandoahMarkCompact.cpp Wed Oct 16 01:16:12 2019 +0200 +++ b/src/hotspot/share/gc/shenandoah/shenandoahMarkCompact.cpp Wed Oct 16 11:23:46 2019 +0200 @@ -337,7 +337,7 @@ // Can move the region, and this is not the humongous region. Humongous // moves are special cased here, because their moves are handled separately. - if (from_region->is_move_allowed() && !from_region->is_humongous()) break; + if (from_region->is_stw_move_allowed() && !from_region->is_humongous()) break; from_region = _heap_regions.next(); } @@ -345,7 +345,7 @@ if (from_region != NULL) { assert(slice != NULL, "sanity"); assert(!from_region->is_humongous(), "this path cannot handle humongous regions"); - assert(from_region->is_empty() || from_region->is_move_allowed(), "only regions that can be moved in mark-compact"); + assert(from_region->is_empty() || from_region->is_stw_move_allowed(), "only regions that can be moved in mark-compact"); slice->add_region(from_region); } @@ -419,7 +419,7 @@ continue; } - if (r->is_humongous_start() && r->is_move_allowed()) { + if (r->is_humongous_start() && r->is_stw_move_allowed()) { // From-region candidate: movable humongous region oop old_obj = oop(r->bottom()); size_t words_size = old_obj->size(); @@ -761,7 +761,7 @@ size_t new_start = heap->heap_region_index_containing(old_obj->forwardee()); size_t new_end = new_start + num_regions - 1; assert(old_start != new_start, "must be real move"); - assert (r->is_move_allowed(), "should be movable"); + assert(r->is_stw_move_allowed(), "Region " SIZE_FORMAT " should be movable", r->region_number()); Copy::aligned_conjoint_words(heap->get_region(old_start)->bottom(), heap->get_region(new_start)->bottom(), diff -r 496bbf554c5c -r 38176d1c5ec2 src/hotspot/share/gc/shenandoah/shenandoahPacer.cpp --- a/src/hotspot/share/gc/shenandoah/shenandoahPacer.cpp Wed Oct 16 01:16:12 2019 +0200 +++ b/src/hotspot/share/gc/shenandoah/shenandoahPacer.cpp Wed Oct 16 11:23:46 2019 +0200 @@ -70,9 +70,12 @@ restart_with(non_taxable, tax); - log_info(gc, ergo)("Pacer for Mark. Expected Live: " SIZE_FORMAT "M, Free: " SIZE_FORMAT - "M, Non-Taxable: " SIZE_FORMAT "M, Alloc Tax Rate: %.1fx", - live / M, free / M, non_taxable / M, tax); + log_info(gc, ergo)("Pacer for Mark. Expected Live: " SIZE_FORMAT "%s, Free: " SIZE_FORMAT "%s, " + "Non-Taxable: " SIZE_FORMAT "%s, Alloc Tax Rate: %.1fx", + byte_size_in_proper_unit(live), proper_unit_for_byte_size(live), + byte_size_in_proper_unit(free), proper_unit_for_byte_size(free), + byte_size_in_proper_unit(non_taxable), proper_unit_for_byte_size(non_taxable), + tax); } void ShenandoahPacer::setup_for_evac() { @@ -91,9 +94,12 @@ restart_with(non_taxable, tax); - log_info(gc, ergo)("Pacer for Evacuation. Used CSet: " SIZE_FORMAT "M, Free: " SIZE_FORMAT - "M, Non-Taxable: " SIZE_FORMAT "M, Alloc Tax Rate: %.1fx", - used / M, free / M, non_taxable / M, tax); + log_info(gc, ergo)("Pacer for Evacuation. Used CSet: " SIZE_FORMAT "%s, Free: " SIZE_FORMAT "%s, " + "Non-Taxable: " SIZE_FORMAT "%s, Alloc Tax Rate: %.1fx", + byte_size_in_proper_unit(used), proper_unit_for_byte_size(used), + byte_size_in_proper_unit(free), proper_unit_for_byte_size(free), + byte_size_in_proper_unit(non_taxable), proper_unit_for_byte_size(non_taxable), + tax); } void ShenandoahPacer::setup_for_updaterefs() { @@ -112,9 +118,12 @@ restart_with(non_taxable, tax); - log_info(gc, ergo)("Pacer for Update Refs. Used: " SIZE_FORMAT "M, Free: " SIZE_FORMAT - "M, Non-Taxable: " SIZE_FORMAT "M, Alloc Tax Rate: %.1fx", - used / M, free / M, non_taxable / M, tax); + log_info(gc, ergo)("Pacer for Update Refs. Used: " SIZE_FORMAT "%s, Free: " SIZE_FORMAT "%s, " + "Non-Taxable: " SIZE_FORMAT "%s, Alloc Tax Rate: %.1fx", + byte_size_in_proper_unit(used), proper_unit_for_byte_size(used), + byte_size_in_proper_unit(free), proper_unit_for_byte_size(free), + byte_size_in_proper_unit(non_taxable), proper_unit_for_byte_size(non_taxable), + tax); } /* @@ -136,9 +145,12 @@ restart_with(non_taxable, tax); - log_info(gc, ergo)("Pacer for Traversal. Expected Live: " SIZE_FORMAT "M, Free: " SIZE_FORMAT - "M, Non-Taxable: " SIZE_FORMAT "M, Alloc Tax Rate: %.1fx", - live / M, free / M, non_taxable / M, tax); + log_info(gc, ergo)("Pacer for Traversal. Expected Live: " SIZE_FORMAT "%s, Free: " SIZE_FORMAT "%s, " + "Non-Taxable: " SIZE_FORMAT "%s, Alloc Tax Rate: %.1fx", + byte_size_in_proper_unit(live), proper_unit_for_byte_size(live), + byte_size_in_proper_unit(free), proper_unit_for_byte_size(free), + byte_size_in_proper_unit(non_taxable), proper_unit_for_byte_size(non_taxable), + tax); } /* @@ -158,8 +170,9 @@ restart_with(initial, tax); - log_info(gc, ergo)("Pacer for Idle. Initial: " SIZE_FORMAT "M, Alloc Tax Rate: %.1fx", - initial / M, tax); + log_info(gc, ergo)("Pacer for Idle. Initial: " SIZE_FORMAT "%s, Alloc Tax Rate: %.1fx", + byte_size_in_proper_unit(initial), proper_unit_for_byte_size(initial), + tax); } size_t ShenandoahPacer::update_and_get_progress_history() { diff -r 496bbf554c5c -r 38176d1c5ec2 src/hotspot/share/gc/shenandoah/shenandoahStrDedupQueue.cpp --- a/src/hotspot/share/gc/shenandoah/shenandoahStrDedupQueue.cpp Wed Oct 16 01:16:12 2019 +0200 +++ b/src/hotspot/share/gc/shenandoah/shenandoahStrDedupQueue.cpp Wed Oct 16 11:23:46 2019 +0200 @@ -205,8 +205,11 @@ void ShenandoahStrDedupQueue::print_statistics_impl() { Log(gc, stringdedup) log; log.debug(" Queue:"); - log.debug(" Total buffers: " SIZE_FORMAT " (" SIZE_FORMAT " K). " SIZE_FORMAT " buffers are on free list", - _total_buffers, (_total_buffers * sizeof(ShenandoahQueueBuffer) / K), _num_free_buffer); + log.debug(" Total buffers: " SIZE_FORMAT " (" SIZE_FORMAT " %s). " SIZE_FORMAT " buffers are on free list", + _total_buffers, + byte_size_in_proper_unit(_total_buffers * sizeof(ShenandoahQueueBuffer)), + proper_unit_for_byte_size(_total_buffers * sizeof(ShenandoahQueueBuffer)), + _num_free_buffer); } class VerifyQueueClosure : public OopClosure { diff -r 496bbf554c5c -r 38176d1c5ec2 src/hotspot/share/gc/shenandoah/shenandoahTraversalGC.cpp --- a/src/hotspot/share/gc/shenandoah/shenandoahTraversalGC.cpp Wed Oct 16 01:16:12 2019 +0200 +++ b/src/hotspot/share/gc/shenandoah/shenandoahTraversalGC.cpp Wed Oct 16 11:23:46 2019 +0200 @@ -366,8 +366,10 @@ // Rebuild free set free_set->rebuild(); - log_info(gc, ergo)("Collectable Garbage: " SIZE_FORMAT "M, " SIZE_FORMAT "M CSet, " SIZE_FORMAT " CSet regions", - collection_set->garbage() / M, collection_set->live_data() / M, collection_set->count()); + log_info(gc, ergo)("Collectable Garbage: " SIZE_FORMAT "%s, " SIZE_FORMAT "%s CSet, " SIZE_FORMAT " CSet regions", + byte_size_in_proper_unit(collection_set->garbage()), proper_unit_for_byte_size(collection_set->garbage()), + byte_size_in_proper_unit(collection_set->live_data()), proper_unit_for_byte_size(collection_set->live_data()), + collection_set->count()); } void ShenandoahTraversalGC::init_traversal_collection() { diff -r 496bbf554c5c -r 38176d1c5ec2 src/hotspot/share/gc/shenandoah/shenandoahVerifier.cpp --- a/src/hotspot/share/gc/shenandoah/shenandoahVerifier.cpp Wed Oct 16 01:16:12 2019 +0200 +++ b/src/hotspot/share/gc/shenandoah/shenandoahVerifier.cpp Wed Oct 16 11:23:46 2019 +0200 @@ -686,13 +686,17 @@ _heap->heap_region_iterate(&cl); size_t heap_used = _heap->used(); guarantee(cl.used() == heap_used, - "%s: heap used size must be consistent: heap-used = " SIZE_FORMAT "K, regions-used = " SIZE_FORMAT "K", - label, heap_used/K, cl.used()/K); + "%s: heap used size must be consistent: heap-used = " SIZE_FORMAT "%s, regions-used = " SIZE_FORMAT "%s", + label, + byte_size_in_proper_unit(heap_used), proper_unit_for_byte_size(heap_used), + byte_size_in_proper_unit(cl.used()), proper_unit_for_byte_size(cl.used())); size_t heap_committed = _heap->committed(); guarantee(cl.committed() == heap_committed, - "%s: heap committed size must be consistent: heap-committed = " SIZE_FORMAT "K, regions-committed = " SIZE_FORMAT "K", - label, heap_committed/K, cl.committed()/K); + "%s: heap committed size must be consistent: heap-committed = " SIZE_FORMAT "%s, regions-committed = " SIZE_FORMAT "%s", + label, + byte_size_in_exact_unit(heap_committed), proper_unit_for_byte_size(heap_committed), + byte_size_in_exact_unit(cl.committed()), proper_unit_for_byte_size(cl.committed())); } // Internal heap region checks diff -r 496bbf554c5c -r 38176d1c5ec2 src/hotspot/share/gc/shenandoah/shenandoah_globals.hpp --- a/src/hotspot/share/gc/shenandoah/shenandoah_globals.hpp Wed Oct 16 01:16:12 2019 +0200 +++ b/src/hotspot/share/gc/shenandoah/shenandoah_globals.hpp Wed Oct 16 11:23:46 2019 +0200 @@ -299,11 +299,11 @@ "Should internally-caused GCs invoke concurrent cycles, or go to" \ "stop-the-world (degenerated/full)?") \ \ - experimental(bool, ShenandoahHumongousMoves, true, \ + diagnostic(bool, ShenandoahHumongousMoves, true, \ "Allow moving humongous regions. This makes GC more resistant " \ "to external fragmentation that may otherwise fail other " \ "humongous allocations, at the expense of higher GC copying " \ - "costs.") \ + "costs. Currently affects stop-the-world (full) cycle only.") \ \ diagnostic(bool, ShenandoahOOMDuringEvacALot, false, \ "Simulate OOM during evacuation frequently.") \ diff -r 496bbf554c5c -r 38176d1c5ec2 src/hotspot/share/gc/z/zLock.inline.hpp --- a/src/hotspot/share/gc/z/zLock.inline.hpp Wed Oct 16 01:16:12 2019 +0200 +++ b/src/hotspot/share/gc/z/zLock.inline.hpp Wed Oct 16 11:23:46 2019 +0200 @@ -80,12 +80,16 @@ template inline ZLocker::ZLocker(T* lock) : _lock(lock) { - _lock->lock(); + if (_lock != NULL) { + _lock->lock(); + } } template inline ZLocker::~ZLocker() { - _lock->unlock(); + if (_lock != NULL) { + _lock->unlock(); + } } #endif // SHARE_GC_Z_ZLOCK_INLINE_HPP diff -r 496bbf554c5c -r 38176d1c5ec2 src/hotspot/share/gc/z/zNMethodTable.cpp --- a/src/hotspot/share/gc/z/zNMethodTable.cpp Wed Oct 16 01:16:12 2019 +0200 +++ b/src/hotspot/share/gc/z/zNMethodTable.cpp Wed Oct 16 11:23:46 2019 +0200 @@ -51,7 +51,7 @@ size_t ZNMethodTable::_nregistered = 0; size_t ZNMethodTable::_nunregistered = 0; ZNMethodTableIteration ZNMethodTable::_iteration; -ZSafeDelete ZNMethodTable::_safe_delete; +ZSafeDeleteNoLock ZNMethodTable::_safe_delete; size_t ZNMethodTable::first_index(const nmethod* nm, size_t size) { assert(is_power_of_2(size), "Invalid size"); diff -r 496bbf554c5c -r 38176d1c5ec2 src/hotspot/share/gc/z/zNMethodTable.hpp --- a/src/hotspot/share/gc/z/zNMethodTable.hpp Wed Oct 16 01:16:12 2019 +0200 +++ b/src/hotspot/share/gc/z/zNMethodTable.hpp Wed Oct 16 11:23:46 2019 +0200 @@ -35,12 +35,12 @@ class ZNMethodTable : public AllStatic { private: - static ZNMethodTableEntry* _table; - static size_t _size; - static size_t _nregistered; - static size_t _nunregistered; - static ZNMethodTableIteration _iteration; - static ZSafeDelete _safe_delete; + static ZNMethodTableEntry* _table; + static size_t _size; + static size_t _nregistered; + static size_t _nunregistered; + static ZNMethodTableIteration _iteration; + static ZSafeDeleteNoLock _safe_delete; static ZNMethodTableEntry* create(size_t size); static void destroy(ZNMethodTableEntry* table); diff -r 496bbf554c5c -r 38176d1c5ec2 src/hotspot/share/gc/z/zSafeDelete.hpp --- a/src/hotspot/share/gc/z/zSafeDelete.hpp Wed Oct 16 01:16:12 2019 +0200 +++ b/src/hotspot/share/gc/z/zSafeDelete.hpp Wed Oct 16 11:23:46 2019 +0200 @@ -29,11 +29,11 @@ #include "metaprogramming/removeExtent.hpp" template -class ZSafeDelete { +class ZSafeDeleteImpl { private: typedef typename RemoveExtent::type ItemT; - ZLock _lock; + ZLock* _lock; uint64_t _enabled; ZArray _deferred; @@ -41,7 +41,7 @@ void immediate_delete(ItemT* item); public: - ZSafeDelete(); + ZSafeDeleteImpl(ZLock* lock); void enable_deferred_delete(); void disable_deferred_delete(); @@ -49,4 +49,19 @@ void operator()(ItemT* item); }; +template +class ZSafeDelete : public ZSafeDeleteImpl { +private: + ZLock _lock; + +public: + ZSafeDelete(); +}; + +template +class ZSafeDeleteNoLock : public ZSafeDeleteImpl { +public: + ZSafeDeleteNoLock(); +}; + #endif // SHARE_GC_Z_ZSAFEDELETE_HPP diff -r 496bbf554c5c -r 38176d1c5ec2 src/hotspot/share/gc/z/zSafeDelete.inline.hpp --- a/src/hotspot/share/gc/z/zSafeDelete.inline.hpp Wed Oct 16 01:16:12 2019 +0200 +++ b/src/hotspot/share/gc/z/zSafeDelete.inline.hpp Wed Oct 16 11:23:46 2019 +0200 @@ -30,14 +30,14 @@ #include "utilities/debug.hpp" template -ZSafeDelete::ZSafeDelete() : - _lock(), +ZSafeDeleteImpl::ZSafeDeleteImpl(ZLock* lock) : + _lock(lock), _enabled(0), _deferred() {} template -bool ZSafeDelete::deferred_delete(ItemT* item) { - ZLocker locker(&_lock); +bool ZSafeDeleteImpl::deferred_delete(ItemT* item) { + ZLocker locker(_lock); if (_enabled > 0) { _deferred.add(item); return true; @@ -47,7 +47,7 @@ } template -void ZSafeDelete::immediate_delete(ItemT* item) { +void ZSafeDeleteImpl::immediate_delete(ItemT* item) { if (IsArray::value) { delete [] item; } else { @@ -56,17 +56,17 @@ } template -void ZSafeDelete::enable_deferred_delete() { - ZLocker locker(&_lock); +void ZSafeDeleteImpl::enable_deferred_delete() { + ZLocker locker(_lock); _enabled++; } template -void ZSafeDelete::disable_deferred_delete() { +void ZSafeDeleteImpl::disable_deferred_delete() { ZArray deferred; { - ZLocker locker(&_lock); + ZLocker locker(_lock); assert(_enabled > 0, "Invalid state"); if (--_enabled == 0) { deferred.transfer(&_deferred); @@ -80,10 +80,19 @@ } template -void ZSafeDelete::operator()(ItemT* item) { +void ZSafeDeleteImpl::operator()(ItemT* item) { if (!deferred_delete(item)) { immediate_delete(item); } } +template +ZSafeDelete::ZSafeDelete() : + ZSafeDeleteImpl(&_lock), + _lock() {} + +template +ZSafeDeleteNoLock::ZSafeDeleteNoLock() : + ZSafeDeleteImpl(NULL) {} + #endif // SHARE_GC_Z_ZSAFEDELETE_INLINE_HPP diff -r 496bbf554c5c -r 38176d1c5ec2 src/hotspot/share/gc/z/z_globals.hpp --- a/src/hotspot/share/gc/z/z_globals.hpp Wed Oct 16 01:16:12 2019 +0200 +++ b/src/hotspot/share/gc/z/z_globals.hpp Wed Oct 16 11:23:46 2019 +0200 @@ -86,9 +86,6 @@ "Verify marking stacks") \ \ diagnostic(bool, ZVerifyForwarding, false, \ - "Verify forwarding tables") \ - \ - develop(bool, ZVerifyLoadBarriers, false, \ - "Verify that reference loads are followed by barriers") + "Verify forwarding tables") #endif // SHARE_GC_Z_Z_GLOBALS_HPP diff -r 496bbf554c5c -r 38176d1c5ec2 src/hotspot/share/interpreter/interpreterRuntime.cpp --- a/src/hotspot/share/interpreter/interpreterRuntime.cpp Wed Oct 16 01:16:12 2019 +0200 +++ b/src/hotspot/share/interpreter/interpreterRuntime.cpp Wed Oct 16 11:23:46 2019 +0200 @@ -28,6 +28,7 @@ #include "classfile/systemDictionary.hpp" #include "classfile/vmSymbols.hpp" #include "code/codeCache.hpp" +#include "compiler/compilationPolicy.hpp" #include "compiler/compileBroker.hpp" #include "compiler/disassembler.hpp" #include "gc/shared/barrierSetNMethod.hpp" @@ -52,7 +53,6 @@ #include "prims/nativeLookup.hpp" #include "runtime/atomic.hpp" #include "runtime/biasedLocking.hpp" -#include "runtime/compilationPolicy.hpp" #include "runtime/deoptimization.hpp" #include "runtime/fieldDescriptor.inline.hpp" #include "runtime/frame.inline.hpp" diff -r 496bbf554c5c -r 38176d1c5ec2 src/hotspot/share/interpreter/linkResolver.cpp --- a/src/hotspot/share/interpreter/linkResolver.cpp Wed Oct 16 01:16:12 2019 +0200 +++ b/src/hotspot/share/interpreter/linkResolver.cpp Wed Oct 16 11:23:46 2019 +0200 @@ -30,6 +30,7 @@ #include "classfile/symbolTable.hpp" #include "classfile/systemDictionary.hpp" #include "classfile/vmSymbols.hpp" +#include "compiler/compilationPolicy.hpp" #include "compiler/compileBroker.hpp" #include "gc/shared/collectedHeap.inline.hpp" #include "interpreter/bootstrapInfo.hpp" @@ -48,7 +49,6 @@ #include "oops/oop.inline.hpp" #include "prims/methodHandles.hpp" #include "prims/nativeLookup.hpp" -#include "runtime/compilationPolicy.hpp" #include "runtime/fieldDescriptor.inline.hpp" #include "runtime/frame.inline.hpp" #include "runtime/handles.inline.hpp" diff -r 496bbf554c5c -r 38176d1c5ec2 src/hotspot/share/jvmci/compilerRuntime.cpp --- a/src/hotspot/share/jvmci/compilerRuntime.cpp Wed Oct 16 01:16:12 2019 +0200 +++ b/src/hotspot/share/jvmci/compilerRuntime.cpp Wed Oct 16 11:23:46 2019 +0200 @@ -25,11 +25,11 @@ #include "aot/aotLoader.hpp" #include "classfile/stringTable.hpp" #include "classfile/symbolTable.hpp" +#include "compiler/compilationPolicy.hpp" #include "interpreter/linkResolver.hpp" #include "jvmci/compilerRuntime.hpp" #include "oops/cpCache.inline.hpp" #include "oops/oop.inline.hpp" -#include "runtime/compilationPolicy.hpp" #include "runtime/deoptimization.hpp" #include "runtime/frame.inline.hpp" #include "runtime/handles.inline.hpp" diff -r 496bbf554c5c -r 38176d1c5ec2 src/hotspot/share/jvmci/jvmciCodeInstaller.cpp --- a/src/hotspot/share/jvmci/jvmciCodeInstaller.cpp Wed Oct 16 01:16:12 2019 +0200 +++ b/src/hotspot/share/jvmci/jvmciCodeInstaller.cpp Wed Oct 16 11:23:46 2019 +0200 @@ -642,11 +642,9 @@ failed_speculations, speculations, speculations_len); cb = nm->as_codeblob_or_null(); if (nm != NULL && compile_state == NULL) { + // This compile didn't come through the CompileBroker so perform the printing here DirectiveSet* directive = DirectivesStack::getMatchingDirective(method, compiler); - bool printnmethods = directive->PrintAssemblyOption || directive->PrintNMethodsOption; - if (!printnmethods && (PrintDebugInfo || PrintRelocations || PrintDependencies || PrintExceptionHandlers)) { - nm->print_nmethod(printnmethods); - } + nm->maybe_print_nmethod(directive); DirectivesStack::release(directive); } } diff -r 496bbf554c5c -r 38176d1c5ec2 src/hotspot/share/jvmci/jvmciCompilerToVMInit.cpp --- a/src/hotspot/share/jvmci/jvmciCompilerToVMInit.cpp Wed Oct 16 01:16:12 2019 +0200 +++ b/src/hotspot/share/jvmci/jvmciCompilerToVMInit.cpp Wed Oct 16 11:23:46 2019 +0200 @@ -31,6 +31,7 @@ #include "jvmci/vmStructs_jvmci.hpp" #include "memory/universe.hpp" #include "oops/compressedOops.hpp" +#include "oops/klass.inline.hpp" #include "runtime/sharedRuntime.hpp" #include "utilities/resourceHash.hpp" diff -r 496bbf554c5c -r 38176d1c5ec2 src/hotspot/share/oops/instanceKlass.hpp --- a/src/hotspot/share/oops/instanceKlass.hpp Wed Oct 16 01:16:12 2019 +0200 +++ b/src/hotspot/share/oops/instanceKlass.hpp Wed Oct 16 11:23:46 2019 +0200 @@ -992,7 +992,6 @@ void process_interfaces(Thread *thread); // virtual operations from Klass - bool is_leaf_class() const { return _subklass == NULL; } GrowableArray* compute_secondary_supers(int num_extra_slots, Array* transitive_interfaces); bool can_be_primary_super_slow() const; diff -r 496bbf554c5c -r 38176d1c5ec2 src/hotspot/share/oops/klass.cpp --- a/src/hotspot/share/oops/klass.cpp Wed Oct 16 01:16:12 2019 +0200 +++ b/src/hotspot/share/oops/klass.cpp Wed Oct 16 11:23:46 2019 +0200 @@ -57,10 +57,6 @@ _java_mirror = class_loader_data()->add_handle(m); } -oop Klass::java_mirror() const { - return _java_mirror.resolve(); -} - oop Klass::java_mirror_no_keepalive() const { return _java_mirror.peek(); } @@ -681,8 +677,6 @@ } } -oop Klass::class_loader() const { return class_loader_data()->class_loader(); } - // In product mode, this function doesn't have virtual function calls so // there might be some performance advantage to handling InstanceKlass here. const char* Klass::external_name() const { @@ -826,14 +820,6 @@ return ClassLoaderDataGraph::is_valid(k->class_loader_data()); } -klassVtable Klass::vtable() const { - return klassVtable(const_cast(this), start_of_vtable(), vtable_length() / vtableEntry::size()); -} - -vtableEntry* Klass::start_of_vtable() const { - return (vtableEntry*) ((address)this + in_bytes(vtable_start_offset())); -} - Method* Klass::method_at_vtable(int index) { #ifndef PRODUCT assert(index >= 0, "valid vtable index"); @@ -844,9 +830,6 @@ return start_of_vtable()[index].method(); } -ByteSize Klass::vtable_start_offset() { - return in_ByteSize(InstanceKlass::header_size() * wordSize); -} #ifndef PRODUCT diff -r 496bbf554c5c -r 38176d1c5ec2 src/hotspot/share/oops/klass.hpp --- a/src/hotspot/share/oops/klass.hpp Wed Oct 16 01:16:12 2019 +0200 +++ b/src/hotspot/share/oops/klass.hpp Wed Oct 16 11:23:46 2019 +0200 @@ -469,8 +469,6 @@ virtual bool should_be_initialized() const { return false; } // initializes the klass virtual void initialize(TRAPS); - // lookup operation for MethodLookupCache - friend class MethodLookupCache; virtual Klass* find_field(Symbol* name, Symbol* signature, fieldDescriptor* fd) const; virtual Method* uncached_lookup_method(const Symbol* name, const Symbol* signature, OverpassLookupMode overpass_mode, @@ -537,9 +535,6 @@ } public: - // subclass accessor (here for convenience; undefined for non-klass objects) - virtual bool is_leaf_class() const { fatal("not a class"); return false; } - public: // ALL FUNCTIONS BELOW THIS POINT ARE DISPATCHED FROM AN OOP // These functions describe behavior for the oop not the KLASS. diff -r 496bbf554c5c -r 38176d1c5ec2 src/hotspot/share/oops/klass.inline.hpp --- a/src/hotspot/share/oops/klass.inline.hpp Wed Oct 16 01:16:12 2019 +0200 +++ b/src/hotspot/share/oops/klass.inline.hpp Wed Oct 16 11:23:46 2019 +0200 @@ -25,13 +25,35 @@ #ifndef SHARE_OOPS_KLASS_INLINE_HPP #define SHARE_OOPS_KLASS_INLINE_HPP +#include "classfile/classLoaderData.inline.hpp" #include "oops/compressedOops.hpp" #include "oops/klass.hpp" #include "oops/markWord.hpp" +#include "oops/oopHandle.inline.hpp" inline void Klass::set_prototype_header(markWord header) { assert(!header.has_bias_pattern() || is_instance_klass(), "biased locking currently only supported for Java instances"); _prototype_header = header; } +inline oop Klass::java_mirror() const { + return _java_mirror.resolve(); +} + +inline klassVtable Klass::vtable() const { + return klassVtable(const_cast(this), start_of_vtable(), vtable_length() / vtableEntry::size()); +} + +inline oop Klass::class_loader() const { + return class_loader_data()->class_loader(); +} + +inline vtableEntry* Klass::start_of_vtable() const { + return (vtableEntry*) ((address)this + in_bytes(vtable_start_offset())); +} + +inline ByteSize Klass::vtable_start_offset() { + return in_ByteSize(InstanceKlass::header_size() * wordSize); +} + #endif // SHARE_OOPS_KLASS_INLINE_HPP diff -r 496bbf554c5c -r 38176d1c5ec2 src/hotspot/share/oops/klassVtable.cpp --- a/src/hotspot/share/oops/klassVtable.cpp Wed Oct 16 01:16:12 2019 +0200 +++ b/src/hotspot/share/oops/klassVtable.cpp Wed Oct 16 11:23:46 2019 +0200 @@ -1501,7 +1501,6 @@ #endif void vtableEntry::verify(klassVtable* vt, outputStream* st) { - NOT_PRODUCT(FlagSetting fs(IgnoreLockingAssertions, true)); Klass* vtklass = vt->klass(); if (vtklass->is_instance_klass() && (InstanceKlass::cast(vtklass)->major_version() >= klassVtable::VTABLE_TRANSITIVE_OVERRIDE_VERSION)) { diff -r 496bbf554c5c -r 38176d1c5ec2 src/hotspot/share/oops/method.cpp --- a/src/hotspot/share/oops/method.cpp Wed Oct 16 01:16:12 2019 +0200 +++ b/src/hotspot/share/oops/method.cpp Wed Oct 16 11:23:46 2019 +0200 @@ -28,6 +28,7 @@ #include "classfile/systemDictionary.hpp" #include "code/codeCache.hpp" #include "code/debugInfoRec.hpp" +#include "compiler/compilationPolicy.hpp" #include "gc/shared/collectedHeap.inline.hpp" #include "interpreter/bytecodeStream.hpp" #include "interpreter/bytecodeTracer.hpp" @@ -54,7 +55,6 @@ #include "prims/methodHandles.hpp" #include "prims/nativeLookup.hpp" #include "runtime/arguments.hpp" -#include "runtime/compilationPolicy.hpp" #include "runtime/frame.inline.hpp" #include "runtime/handles.inline.hpp" #include "runtime/init.hpp" diff -r 496bbf554c5c -r 38176d1c5ec2 src/hotspot/share/oops/methodData.cpp --- a/src/hotspot/share/oops/methodData.cpp Wed Oct 16 01:16:12 2019 +0200 +++ b/src/hotspot/share/oops/methodData.cpp Wed Oct 16 11:23:46 2019 +0200 @@ -24,6 +24,7 @@ #include "precompiled.hpp" #include "classfile/systemDictionary.hpp" +#include "compiler/compilationPolicy.hpp" #include "compiler/compilerOracle.hpp" #include "interpreter/bytecode.hpp" #include "interpreter/bytecodeStream.hpp" @@ -34,7 +35,6 @@ #include "oops/methodData.inline.hpp" #include "prims/jvmtiRedefineClasses.hpp" #include "runtime/arguments.hpp" -#include "runtime/compilationPolicy.hpp" #include "runtime/deoptimization.hpp" #include "runtime/handles.inline.hpp" #include "runtime/orderAccess.hpp" diff -r 496bbf554c5c -r 38176d1c5ec2 src/hotspot/share/opto/buildOopMap.cpp --- a/src/hotspot/share/opto/buildOopMap.cpp Wed Oct 16 01:16:12 2019 +0200 +++ b/src/hotspot/share/opto/buildOopMap.cpp Wed Oct 16 11:23:46 2019 +0200 @@ -352,7 +352,6 @@ } else { // Other - some reaching non-oop value - omap->set_value( r); #ifdef ASSERT if( t->isa_rawptr() && C->cfg()->_raw_oops.member(def) ) { def->dump(); @@ -377,11 +376,18 @@ #endif #ifdef ASSERT - for( OopMapStream oms1(omap, OopMapValue::derived_oop_value); !oms1.is_done(); oms1.next()) { + for( OopMapStream oms1(omap); !oms1.is_done(); oms1.next()) { OopMapValue omv1 = oms1.current(); + if (omv1.type() != OopMapValue::derived_oop_value) { + continue; + } bool found = false; - for( OopMapStream oms2(omap,OopMapValue::oop_value); !oms2.is_done(); oms2.next()) { - if( omv1.content_reg() == oms2.current().reg() ) { + for( OopMapStream oms2(omap); !oms2.is_done(); oms2.next()) { + OopMapValue omv2 = oms2.current(); + if (omv2.type() != OopMapValue::oop_value) { + continue; + } + if( omv1.content_reg() == omv2.reg() ) { found = true; break; } diff -r 496bbf554c5c -r 38176d1c5ec2 src/hotspot/share/opto/library_call.cpp --- a/src/hotspot/share/opto/library_call.cpp Wed Oct 16 01:16:12 2019 +0200 +++ b/src/hotspot/share/opto/library_call.cpp Wed Oct 16 11:23:46 2019 +0200 @@ -32,6 +32,7 @@ #include "gc/shared/barrierSet.hpp" #include "jfr/support/jfrIntrinsics.hpp" #include "memory/resourceArea.hpp" +#include "oops/klass.inline.hpp" #include "oops/objArrayKlass.hpp" #include "opto/addnode.hpp" #include "opto/arraycopynode.hpp" diff -r 496bbf554c5c -r 38176d1c5ec2 src/hotspot/share/opto/loopTransform.cpp --- a/src/hotspot/share/opto/loopTransform.cpp Wed Oct 16 01:16:12 2019 +0200 +++ b/src/hotspot/share/opto/loopTransform.cpp Wed Oct 16 11:23:46 2019 +0200 @@ -3129,6 +3129,13 @@ // We also need to replace the original limit to collapse loop exit. Node* cmp = cl->loopexit()->cmp_node(); assert(cl->limit() == cmp->in(2), "sanity"); + // Duplicate cmp node if it has other users + if (cmp->outcnt() > 1) { + cmp = cmp->clone(); + cmp = phase->_igvn.register_new_node_with_optimizer(cmp); + BoolNode *bol = cl->loopexit()->in(CountedLoopEndNode::TestValue)->as_Bool(); + phase->_igvn.replace_input_of(bol, 1, cmp); // put bol on worklist + } phase->_igvn._worklist.push(cmp->in(2)); // put limit on worklist phase->_igvn.replace_input_of(cmp, 2, exact_limit); // put cmp on worklist } diff -r 496bbf554c5c -r 38176d1c5ec2 src/hotspot/share/prims/jni.cpp --- a/src/hotspot/share/prims/jni.cpp Wed Oct 16 01:16:12 2019 +0200 +++ b/src/hotspot/share/prims/jni.cpp Wed Oct 16 11:23:46 2019 +0200 @@ -65,7 +65,6 @@ #include "prims/jvmtiExport.hpp" #include "prims/jvmtiThreadState.hpp" #include "runtime/atomic.hpp" -#include "runtime/compilationPolicy.hpp" #include "runtime/fieldDescriptor.inline.hpp" #include "runtime/handles.inline.hpp" #include "runtime/interfaceSupport.inline.hpp" @@ -88,6 +87,9 @@ #include "utilities/histogram.hpp" #include "utilities/macros.hpp" #include "utilities/vmError.hpp" +#if INCLUDE_JVMCI +#include "jvmci/jvmciCompiler.hpp" +#endif static jint CurrentVersion = JNI_VERSION_10; diff -r 496bbf554c5c -r 38176d1c5ec2 src/hotspot/share/prims/jniCheck.cpp --- a/src/hotspot/share/prims/jniCheck.cpp Wed Oct 16 01:16:12 2019 +0200 +++ b/src/hotspot/share/prims/jniCheck.cpp Wed Oct 16 11:23:46 2019 +0200 @@ -534,10 +534,10 @@ if (obj != NULL) { oop recv = jniCheck::validate_object(thr, obj); assert(recv != NULL, "validate_object checks that"); - Klass* ik = recv->klass(); + Klass* rk = recv->klass(); // Check that the object is a subtype of method holder too. - if (!InstanceKlass::cast(ik)->is_subtype_of(holder)) { + if (!rk->is_subtype_of(holder)) { ReportJNIFatalError(thr, fatal_wrong_class_or_method); } } diff -r 496bbf554c5c -r 38176d1c5ec2 src/hotspot/share/prims/methodHandles.cpp --- a/src/hotspot/share/prims/methodHandles.cpp Wed Oct 16 01:16:12 2019 +0200 +++ b/src/hotspot/share/prims/methodHandles.cpp Wed Oct 16 11:23:46 2019 +0200 @@ -41,7 +41,6 @@ #include "oops/oop.inline.hpp" #include "oops/typeArrayOop.inline.hpp" #include "prims/methodHandles.hpp" -#include "runtime/compilationPolicy.hpp" #include "runtime/deoptimization.hpp" #include "runtime/fieldDescriptor.inline.hpp" #include "runtime/handles.inline.hpp" diff -r 496bbf554c5c -r 38176d1c5ec2 src/hotspot/share/prims/whitebox.cpp --- a/src/hotspot/share/prims/whitebox.cpp Wed Oct 16 01:16:12 2019 +0200 +++ b/src/hotspot/share/prims/whitebox.cpp Wed Oct 16 11:23:46 2019 +0200 @@ -32,6 +32,7 @@ #include "classfile/stringTable.hpp" #include "classfile/symbolTable.hpp" #include "code/codeCache.hpp" +#include "compiler/compilationPolicy.hpp" #include "compiler/methodMatcher.hpp" #include "compiler/directivesParser.hpp" #include "gc/shared/gcConfig.hpp" @@ -58,7 +59,6 @@ #include "prims/wbtestmethods/parserTests.hpp" #include "prims/whitebox.inline.hpp" #include "runtime/arguments.hpp" -#include "runtime/compilationPolicy.hpp" #include "runtime/deoptimization.hpp" #include "runtime/fieldDescriptor.inline.hpp" #include "runtime/flags/jvmFlag.hpp" diff -r 496bbf554c5c -r 38176d1c5ec2 src/hotspot/share/runtime/compilationPolicy.cpp --- a/src/hotspot/share/runtime/compilationPolicy.cpp Wed Oct 16 01:16:12 2019 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,506 +0,0 @@ -/* - * Copyright (c) 2000, 2019, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * 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.inline.hpp" -#include "code/compiledIC.hpp" -#include "code/nmethod.hpp" -#include "code/scopeDesc.hpp" -#include "interpreter/interpreter.hpp" -#include "memory/resourceArea.hpp" -#include "oops/methodData.hpp" -#include "oops/method.inline.hpp" -#include "oops/oop.inline.hpp" -#include "prims/nativeLookup.hpp" -#include "runtime/compilationPolicy.hpp" -#include "runtime/frame.hpp" -#include "runtime/handles.inline.hpp" -#include "runtime/stubRoutines.hpp" -#include "runtime/thread.hpp" -#include "runtime/tieredThresholdPolicy.hpp" -#include "runtime/vframe.hpp" -#include "runtime/vmOperations.hpp" -#include "utilities/events.hpp" -#include "utilities/globalDefinitions.hpp" - -#ifdef COMPILER1 -#include "c1/c1_Compiler.hpp" -#endif -#ifdef COMPILER2 -#include "opto/c2compiler.hpp" -#endif - -CompilationPolicy* CompilationPolicy::_policy; - -// Determine compilation policy based on command line argument -void compilationPolicy_init() { - #ifdef TIERED - if (TieredCompilation) { - CompilationPolicy::set_policy(new TieredThresholdPolicy()); - } else { - CompilationPolicy::set_policy(new SimpleCompPolicy()); - } - #else - CompilationPolicy::set_policy(new SimpleCompPolicy()); - #endif - - CompilationPolicy::policy()->initialize(); -} - -// Returns true if m must be compiled before executing it -// This is intended to force compiles for methods (usually for -// debugging) that would otherwise be interpreted for some reason. -bool CompilationPolicy::must_be_compiled(const methodHandle& m, int comp_level) { - // Don't allow Xcomp to cause compiles in replay mode - if (ReplayCompiles) return false; - - if (m->has_compiled_code()) return false; // already compiled - if (!can_be_compiled(m, comp_level)) return false; - - return !UseInterpreter || // must compile all methods - (UseCompiler && AlwaysCompileLoopMethods && m->has_loops() && CompileBroker::should_compile_new_jobs()); // eagerly compile loop methods -} - -void CompilationPolicy::compile_if_required(const methodHandle& selected_method, TRAPS) { - if (must_be_compiled(selected_method)) { - // This path is unusual, mostly used by the '-Xcomp' stress test mode. - - // Note: with several active threads, the must_be_compiled may be true - // while can_be_compiled is false; remove assert - // assert(CompilationPolicy::can_be_compiled(selected_method), "cannot compile"); - if (!THREAD->can_call_java() || THREAD->is_Compiler_thread()) { - // don't force compilation, resolve was on behalf of compiler - return; - } - if (selected_method->method_holder()->is_not_initialized()) { - // 'is_not_initialized' means not only '!is_initialized', but also that - // initialization has not been started yet ('!being_initialized') - // Do not force compilation of methods in uninitialized classes. - // Note that doing this would throw an assert later, - // in CompileBroker::compile_method. - // We sometimes use the link resolver to do reflective lookups - // even before classes are initialized. - return; - } - CompileBroker::compile_method(selected_method, InvocationEntryBci, - CompilationPolicy::policy()->initial_compile_level(), - methodHandle(), 0, CompileTask::Reason_MustBeCompiled, CHECK); - } -} - -// Returns true if m is allowed to be compiled -bool CompilationPolicy::can_be_compiled(const methodHandle& m, int comp_level) { - // allow any levels for WhiteBox - assert(WhiteBoxAPI || comp_level == CompLevel_all || is_compile(comp_level), "illegal compilation level"); - - if (m->is_abstract()) return false; - if (DontCompileHugeMethods && m->code_size() > HugeMethodLimit) return false; - - // Math intrinsics should never be compiled as this can lead to - // monotonicity problems because the interpreter will prefer the - // compiled code to the intrinsic version. This can't happen in - // production because the invocation counter can't be incremented - // but we shouldn't expose the system to this problem in testing - // modes. - if (!AbstractInterpreter::can_be_compiled(m)) { - return false; - } - if (comp_level == CompLevel_all) { - if (TieredCompilation) { - // enough to be compilable at any level for tiered - return !m->is_not_compilable(CompLevel_simple) || !m->is_not_compilable(CompLevel_full_optimization); - } else { - // must be compilable at available level for non-tiered - return !m->is_not_compilable(CompLevel_highest_tier); - } - } else if (is_compile(comp_level)) { - return !m->is_not_compilable(comp_level); - } - return false; -} - -// Returns true if m is allowed to be osr compiled -bool CompilationPolicy::can_be_osr_compiled(const methodHandle& m, int comp_level) { - bool result = false; - if (comp_level == CompLevel_all) { - if (TieredCompilation) { - // enough to be osr compilable at any level for tiered - result = !m->is_not_osr_compilable(CompLevel_simple) || !m->is_not_osr_compilable(CompLevel_full_optimization); - } else { - // must be osr compilable at available level for non-tiered - result = !m->is_not_osr_compilable(CompLevel_highest_tier); - } - } else if (is_compile(comp_level)) { - result = !m->is_not_osr_compilable(comp_level); - } - return (result && can_be_compiled(m, comp_level)); -} - -bool CompilationPolicy::is_compilation_enabled() { - // NOTE: CompileBroker::should_compile_new_jobs() checks for UseCompiler - return CompileBroker::should_compile_new_jobs(); -} - -CompileTask* CompilationPolicy::select_task_helper(CompileQueue* compile_queue) { - // Remove unloaded methods from the queue - for (CompileTask* task = compile_queue->first(); task != NULL; ) { - CompileTask* next = task->next(); - if (task->is_unloaded()) { - compile_queue->remove_and_mark_stale(task); - } - task = next; - } -#if INCLUDE_JVMCI - if (UseJVMCICompiler && !BackgroundCompilation) { - /* - * In blocking compilation mode, the CompileBroker will make - * compilations submitted by a JVMCI compiler thread non-blocking. These - * compilations should be scheduled after all blocking compilations - * to service non-compiler related compilations sooner and reduce the - * chance of such compilations timing out. - */ - for (CompileTask* task = compile_queue->first(); task != NULL; task = task->next()) { - if (task->is_blocking()) { - return task; - } - } - } -#endif - return compile_queue->first(); -} - -#ifndef PRODUCT -void SimpleCompPolicy::trace_osr_completion(nmethod* osr_nm) { - if (TraceOnStackReplacement) { - if (osr_nm == NULL) tty->print_cr("compilation failed"); - else tty->print_cr("nmethod " INTPTR_FORMAT, p2i(osr_nm)); - } -} -#endif // !PRODUCT - -void SimpleCompPolicy::initialize() { - // Setup the compiler thread numbers - if (CICompilerCountPerCPU) { - // Example: if CICompilerCountPerCPU is true, then we get - // max(log2(8)-1,1) = 2 compiler threads on an 8-way machine. - // May help big-app startup time. - _compiler_count = MAX2(log2_int(os::active_processor_count())-1,1); - // Make sure there is enough space in the code cache to hold all the compiler buffers - size_t buffer_size = 1; -#ifdef COMPILER1 - buffer_size = is_client_compilation_mode_vm() ? Compiler::code_buffer_size() : buffer_size; -#endif -#ifdef COMPILER2 - buffer_size = is_server_compilation_mode_vm() ? C2Compiler::initial_code_buffer_size() : buffer_size; -#endif - int max_count = (ReservedCodeCacheSize - (CodeCacheMinimumUseSpace DEBUG_ONLY(* 3))) / (int)buffer_size; - if (_compiler_count > max_count) { - // Lower the compiler count such that all buffers fit into the code cache - _compiler_count = MAX2(max_count, 1); - } - FLAG_SET_ERGO(CICompilerCount, _compiler_count); - } else { - _compiler_count = CICompilerCount; - } -} - -// Note: this policy is used ONLY if TieredCompilation is off. -// compiler_count() behaves the following way: -// - with TIERED build (with both COMPILER1 and COMPILER2 defined) it should return -// zero for the c1 compilation levels in server compilation mode runs -// and c2 compilation levels in client compilation mode runs. -// - with COMPILER2 not defined it should return zero for c2 compilation levels. -// - with COMPILER1 not defined it should return zero for c1 compilation levels. -// - if neither is defined - always return zero. -int SimpleCompPolicy::compiler_count(CompLevel comp_level) { - assert(!TieredCompilation, "This policy should not be used with TieredCompilation"); - if (COMPILER2_PRESENT(is_server_compilation_mode_vm() && is_c2_compile(comp_level) ||) - is_client_compilation_mode_vm() && is_c1_compile(comp_level)) { - return _compiler_count; - } - return 0; -} - -void SimpleCompPolicy::reset_counter_for_invocation_event(const methodHandle& m) { - // Make sure invocation and backedge counter doesn't overflow again right away - // as would be the case for native methods. - - // BUT also make sure the method doesn't look like it was never executed. - // Set carry bit and reduce counter's value to min(count, CompileThreshold/2). - MethodCounters* mcs = m->method_counters(); - assert(mcs != NULL, "MethodCounters cannot be NULL for profiling"); - mcs->invocation_counter()->set_carry(); - mcs->backedge_counter()->set_carry(); - - assert(!m->was_never_executed(), "don't reset to 0 -- could be mistaken for never-executed"); -} - -void SimpleCompPolicy::reset_counter_for_back_branch_event(const methodHandle& m) { - // Delay next back-branch event but pump up invocation counter to trigger - // whole method compilation. - MethodCounters* mcs = m->method_counters(); - assert(mcs != NULL, "MethodCounters cannot be NULL for profiling"); - InvocationCounter* i = mcs->invocation_counter(); - InvocationCounter* b = mcs->backedge_counter(); - - // Don't set invocation_counter's value too low otherwise the method will - // look like immature (ic < ~5300) which prevents the inlining based on - // the type profiling. - i->set(i->state(), CompileThreshold); - // Don't reset counter too low - it is used to check if OSR method is ready. - b->set(b->state(), CompileThreshold / 2); -} - -// -// CounterDecay -// -// Iterates through invocation counters and decrements them. This -// is done at each safepoint. -// -class CounterDecay : public AllStatic { - static jlong _last_timestamp; - static void do_method(Method* m) { - MethodCounters* mcs = m->method_counters(); - if (mcs != NULL) { - mcs->invocation_counter()->decay(); - } - } -public: - static void decay(); - static bool is_decay_needed() { - return (os::javaTimeMillis() - _last_timestamp) > CounterDecayMinIntervalLength; - } -}; - -jlong CounterDecay::_last_timestamp = 0; - -void CounterDecay::decay() { - _last_timestamp = os::javaTimeMillis(); - - // This operation is going to be performed only at the end of a safepoint - // and hence GC's will not be going on, all Java mutators are suspended - // at this point and hence SystemDictionary_lock is also not needed. - assert(SafepointSynchronize::is_at_safepoint(), "can only be executed at a safepoint"); - size_t nclasses = ClassLoaderDataGraph::num_instance_classes(); - size_t classes_per_tick = nclasses * (CounterDecayMinIntervalLength * 1e-3 / - CounterHalfLifeTime); - for (size_t i = 0; i < classes_per_tick; i++) { - InstanceKlass* k = ClassLoaderDataGraph::try_get_next_class(); - if (k != NULL) { - k->methods_do(do_method); - } - } -} - -// Called at the end of the safepoint -void SimpleCompPolicy::do_safepoint_work() { - if(UseCounterDecay && CounterDecay::is_decay_needed()) { - CounterDecay::decay(); - } -} - -void SimpleCompPolicy::reprofile(ScopeDesc* trap_scope, bool is_osr) { - ScopeDesc* sd = trap_scope; - MethodCounters* mcs; - InvocationCounter* c; - for (; !sd->is_top(); sd = sd->sender()) { - mcs = sd->method()->method_counters(); - if (mcs != NULL) { - // Reset ICs of inlined methods, since they can trigger compilations also. - mcs->invocation_counter()->reset(); - } - } - mcs = sd->method()->method_counters(); - if (mcs != NULL) { - c = mcs->invocation_counter(); - if (is_osr) { - // It was an OSR method, so bump the count higher. - c->set(c->state(), CompileThreshold); - } else { - c->reset(); - } - mcs->backedge_counter()->reset(); - } -} - -// This method can be called by any component of the runtime to notify the policy -// that it's recommended to delay the compilation of this method. -void SimpleCompPolicy::delay_compilation(Method* method) { - MethodCounters* mcs = method->method_counters(); - if (mcs != NULL) { - mcs->invocation_counter()->decay(); - mcs->backedge_counter()->decay(); - } -} - -void SimpleCompPolicy::disable_compilation(Method* method) { - MethodCounters* mcs = method->method_counters(); - if (mcs != NULL) { - mcs->invocation_counter()->set_state(InvocationCounter::wait_for_nothing); - mcs->backedge_counter()->set_state(InvocationCounter::wait_for_nothing); - } -} - -CompileTask* SimpleCompPolicy::select_task(CompileQueue* compile_queue) { - return select_task_helper(compile_queue); -} - -bool SimpleCompPolicy::is_mature(Method* method) { - MethodData* mdo = method->method_data(); - assert(mdo != NULL, "Should be"); - uint current = mdo->mileage_of(method); - uint initial = mdo->creation_mileage(); - if (current < initial) - return true; // some sort of overflow - uint target; - if (ProfileMaturityPercentage <= 0) - target = (uint) -ProfileMaturityPercentage; // absolute value - else - target = (uint)( (ProfileMaturityPercentage * CompileThreshold) / 100 ); - return (current >= initial + target); -} - -nmethod* SimpleCompPolicy::event(const methodHandle& method, const methodHandle& inlinee, int branch_bci, - int bci, CompLevel comp_level, CompiledMethod* nm, JavaThread* thread) { - assert(comp_level == CompLevel_none, "This should be only called from the interpreter"); - NOT_PRODUCT(trace_frequency_counter_overflow(method, branch_bci, bci)); - if (JvmtiExport::can_post_interpreter_events() && thread->is_interp_only_mode()) { - // If certain JVMTI events (e.g. frame pop event) are requested then the - // thread is forced to remain in interpreted code. This is - // implemented partly by a check in the run_compiled_code - // section of the interpreter whether we should skip running - // compiled code, and partly by skipping OSR compiles for - // interpreted-only threads. - if (bci != InvocationEntryBci) { - reset_counter_for_back_branch_event(method); - return NULL; - } - } - if (ReplayCompiles) { - // Don't trigger other compiles in testing mode - if (bci == InvocationEntryBci) { - reset_counter_for_invocation_event(method); - } else { - reset_counter_for_back_branch_event(method); - } - return NULL; - } - - if (bci == InvocationEntryBci) { - // when code cache is full, compilation gets switched off, UseCompiler - // is set to false - if (!method->has_compiled_code() && UseCompiler) { - method_invocation_event(method, thread); - } else { - // Force counter overflow on method entry, even if no compilation - // happened. (The method_invocation_event call does this also.) - reset_counter_for_invocation_event(method); - } - // compilation at an invocation overflow no longer goes and retries test for - // compiled method. We always run the loser of the race as interpreted. - // so return NULL - return NULL; - } else { - // counter overflow in a loop => try to do on-stack-replacement - nmethod* osr_nm = method->lookup_osr_nmethod_for(bci, CompLevel_highest_tier, true); - NOT_PRODUCT(trace_osr_request(method, osr_nm, bci)); - // when code cache is full, we should not compile any more... - if (osr_nm == NULL && UseCompiler) { - method_back_branch_event(method, bci, thread); - osr_nm = method->lookup_osr_nmethod_for(bci, CompLevel_highest_tier, true); - } - if (osr_nm == NULL) { - reset_counter_for_back_branch_event(method); - return NULL; - } - return osr_nm; - } - return NULL; -} - -#ifndef PRODUCT -void SimpleCompPolicy::trace_frequency_counter_overflow(const methodHandle& m, int branch_bci, int bci) { - if (TraceInvocationCounterOverflow) { - MethodCounters* mcs = m->method_counters(); - assert(mcs != NULL, "MethodCounters cannot be NULL for profiling"); - InvocationCounter* ic = mcs->invocation_counter(); - InvocationCounter* bc = mcs->backedge_counter(); - ResourceMark rm; - if (bci == InvocationEntryBci) { - tty->print("comp-policy cntr ovfl @ %d in entry of ", bci); - } else { - tty->print("comp-policy cntr ovfl @ %d in loop of ", bci); - } - m->print_value(); - tty->cr(); - ic->print(); - bc->print(); - if (ProfileInterpreter) { - if (bci != InvocationEntryBci) { - MethodData* mdo = m->method_data(); - if (mdo != NULL) { - ProfileData *pd = mdo->bci_to_data(branch_bci); - if (pd == NULL) { - tty->print_cr("back branch count = N/A (missing ProfileData)"); - } else { - tty->print_cr("back branch count = %d", pd->as_JumpData()->taken()); - } - } - } - } - } -} - -void SimpleCompPolicy::trace_osr_request(const methodHandle& method, nmethod* osr, int bci) { - if (TraceOnStackReplacement) { - ResourceMark rm; - tty->print(osr != NULL ? "Reused OSR entry for " : "Requesting OSR entry for "); - method->print_short_name(tty); - tty->print_cr(" at bci %d", bci); - } -} -#endif // !PRODUCT - -void SimpleCompPolicy::method_invocation_event(const methodHandle& m, JavaThread* thread) { - const int comp_level = CompLevel_highest_tier; - const int hot_count = m->invocation_count(); - reset_counter_for_invocation_event(m); - - if (is_compilation_enabled() && can_be_compiled(m, comp_level)) { - CompiledMethod* nm = m->code(); - if (nm == NULL ) { - CompileBroker::compile_method(m, InvocationEntryBci, comp_level, m, hot_count, CompileTask::Reason_InvocationCount, thread); - } - } -} - -void SimpleCompPolicy::method_back_branch_event(const methodHandle& m, int bci, JavaThread* thread) { - const int comp_level = CompLevel_highest_tier; - const int hot_count = m->backedge_count(); - - if (is_compilation_enabled() && can_be_osr_compiled(m, comp_level)) { - CompileBroker::compile_method(m, bci, comp_level, m, hot_count, CompileTask::Reason_BackedgeCount, thread); - NOT_PRODUCT(trace_osr_completion(m->lookup_osr_nmethod_for(bci, comp_level, true));) - } -} diff -r 496bbf554c5c -r 38176d1c5ec2 src/hotspot/share/runtime/compilationPolicy.hpp --- a/src/hotspot/share/runtime/compilationPolicy.hpp Wed Oct 16 01:16:12 2019 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,113 +0,0 @@ -/* - * Copyright (c) 2000, 2019, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - * - */ - -#ifndef SHARE_RUNTIME_COMPILATIONPOLICY_HPP -#define SHARE_RUNTIME_COMPILATIONPOLICY_HPP - -#include "code/nmethod.hpp" -#include "compiler/compileBroker.hpp" -#include "memory/allocation.hpp" -#include "runtime/vmOperations.hpp" -#include "utilities/growableArray.hpp" - -// The CompilationPolicy selects which method (if any) should be compiled. -// It also decides which methods must always be compiled (i.e., are never -// interpreted). -class CompileTask; -class CompileQueue; - -class CompilationPolicy : public CHeapObj { - static CompilationPolicy* _policy; - - // m must be compiled before executing it - static bool must_be_compiled(const methodHandle& m, int comp_level = CompLevel_all); - -public: - // If m must_be_compiled then request a compilation from the CompileBroker. - // This supports the -Xcomp option. - static void compile_if_required(const methodHandle& m, TRAPS); - - // m is allowed to be compiled - static bool can_be_compiled(const methodHandle& m, int comp_level = CompLevel_all); - // m is allowed to be osr compiled - static bool can_be_osr_compiled(const methodHandle& m, int comp_level = CompLevel_all); - static bool is_compilation_enabled(); - static void set_policy(CompilationPolicy* policy) { _policy = policy; } - static CompilationPolicy* policy() { return _policy; } - - static CompileTask* select_task_helper(CompileQueue* compile_queue); - - // Return initial compile level that is used with Xcomp - virtual CompLevel initial_compile_level() = 0; - virtual int compiler_count(CompLevel comp_level) = 0; - // main notification entry, return a pointer to an nmethod if the OSR is required, - // returns NULL otherwise. - virtual nmethod* event(const methodHandle& method, const methodHandle& inlinee, int branch_bci, int bci, CompLevel comp_level, CompiledMethod* nm, JavaThread* thread) = 0; - // safepoint() is called at the end of the safepoint - virtual void do_safepoint_work() = 0; - // reprofile request - virtual void reprofile(ScopeDesc* trap_scope, bool is_osr) = 0; - // delay_compilation(method) can be called by any component of the runtime to notify the policy - // that it's recommended to delay the compilation of this method. - virtual void delay_compilation(Method* method) = 0; - // disable_compilation() is called whenever the runtime decides to disable compilation of the - // specified method. - virtual void disable_compilation(Method* method) = 0; - // Select task is called by CompileBroker. The queue is guaranteed to have at least one - // element and is locked. The function should select one and return it. - virtual CompileTask* select_task(CompileQueue* compile_queue) = 0; - // Tell the runtime if we think a given method is adequately profiled. - virtual bool is_mature(Method* method) = 0; - // Do policy initialization - virtual void initialize() = 0; - virtual bool should_not_inline(ciEnv* env, ciMethod* method) { return false; } -}; - -// A simple compilation policy. -class SimpleCompPolicy : public CompilationPolicy { - int _compiler_count; - private: - static void trace_frequency_counter_overflow(const methodHandle& m, int branch_bci, int bci); - static void trace_osr_request(const methodHandle& method, nmethod* osr, int bci); - static void trace_osr_completion(nmethod* osr_nm); - void reset_counter_for_invocation_event(const methodHandle& method); - void reset_counter_for_back_branch_event(const methodHandle& method); - void method_invocation_event(const methodHandle& m, JavaThread* thread); - void method_back_branch_event(const methodHandle& m, int bci, JavaThread* thread); - public: - SimpleCompPolicy() : _compiler_count(0) { } - virtual CompLevel initial_compile_level() { return CompLevel_highest_tier; } - virtual int compiler_count(CompLevel comp_level); - virtual void do_safepoint_work(); - virtual void reprofile(ScopeDesc* trap_scope, bool is_osr); - virtual void delay_compilation(Method* method); - virtual void disable_compilation(Method* method); - virtual bool is_mature(Method* method); - virtual void initialize(); - virtual CompileTask* select_task(CompileQueue* compile_queue); - virtual nmethod* event(const methodHandle& method, const methodHandle& inlinee, int branch_bci, int bci, CompLevel comp_level, CompiledMethod* nm, JavaThread* thread); -}; - - -#endif // SHARE_RUNTIME_COMPILATIONPOLICY_HPP diff -r 496bbf554c5c -r 38176d1c5ec2 src/hotspot/share/runtime/deoptimization.cpp --- a/src/hotspot/share/runtime/deoptimization.cpp Wed Oct 16 01:16:12 2019 +0200 +++ b/src/hotspot/share/runtime/deoptimization.cpp Wed Oct 16 11:23:46 2019 +0200 @@ -31,6 +31,7 @@ #include "code/nmethod.hpp" #include "code/pcDesc.hpp" #include "code/scopeDesc.hpp" +#include "compiler/compilationPolicy.hpp" #include "interpreter/bytecode.hpp" #include "interpreter/interpreter.hpp" #include "interpreter/oopMapCache.hpp" @@ -48,7 +49,6 @@ #include "oops/verifyOopClosure.hpp" #include "prims/jvmtiThreadState.hpp" #include "runtime/biasedLocking.hpp" -#include "runtime/compilationPolicy.hpp" #include "runtime/deoptimization.hpp" #include "runtime/fieldDescriptor.hpp" #include "runtime/fieldDescriptor.inline.hpp" diff -r 496bbf554c5c -r 38176d1c5ec2 src/hotspot/share/runtime/globals.hpp --- a/src/hotspot/share/runtime/globals.hpp Wed Oct 16 01:16:12 2019 +0200 +++ b/src/hotspot/share/runtime/globals.hpp Wed Oct 16 11:23:46 2019 +0200 @@ -1197,9 +1197,6 @@ develop(bool, TraceCreateZombies, false, \ "trace creation of zombie nmethods") \ \ - notproduct(bool, IgnoreLockingAssertions, false, \ - "disable locking assertions (for speed)") \ - \ product(bool, RangeCheckElimination, true, \ "Eliminate range checks") \ \ diff -r 496bbf554c5c -r 38176d1c5ec2 src/hotspot/share/runtime/interfaceSupport.cpp --- a/src/hotspot/share/runtime/interfaceSupport.cpp Wed Oct 16 01:16:12 2019 +0200 +++ b/src/hotspot/share/runtime/interfaceSupport.cpp Wed Oct 16 11:23:46 2019 +0200 @@ -55,12 +55,6 @@ if (WalkStackALot) { InterfaceSupport::walk_stack(); } -#ifdef COMPILER2 - // This option is not used by Compiler 1 - if (StressDerivedPointers) { - InterfaceSupport::stress_derived_pointers(); - } -#endif if (DeoptimizeALot || DeoptimizeRandom) { InterfaceSupport::deoptimizeAll(); } @@ -234,31 +228,6 @@ } -void InterfaceSupport::stress_derived_pointers() { -#ifdef COMPILER2 - JavaThread *thread = JavaThread::current(); - if (!is_init_completed()) return; - ResourceMark rm(thread); - bool found = false; - for (StackFrameStream sfs(thread); !sfs.is_done() && !found; sfs.next()) { - CodeBlob* cb = sfs.current()->cb(); - if (cb != NULL && cb->oop_maps() ) { - // Find oopmap for current method - const ImmutableOopMap* map = cb->oop_map_for_return_address(sfs.current()->pc()); - assert(map != NULL, "no oopmap found for pc"); - found = map->has_derived_pointer(); - } - } - if (found) { - // $$$ Not sure what to do here. - /* - Scavenge::invoke(0); - */ - } -#endif -} - - void InterfaceSupport::verify_stack() { JavaThread* thread = JavaThread::current(); ResourceMark rm(thread); diff -r 496bbf554c5c -r 38176d1c5ec2 src/hotspot/share/runtime/interfaceSupport.inline.hpp --- a/src/hotspot/share/runtime/interfaceSupport.inline.hpp Wed Oct 16 01:16:12 2019 +0200 +++ b/src/hotspot/share/runtime/interfaceSupport.inline.hpp Wed Oct 16 11:23:46 2019 +0200 @@ -62,7 +62,6 @@ static void zombieAll(); static void deoptimizeAll(); - static void stress_derived_pointers(); static void verify_stack(); static void verify_last_frame(); # endif diff -r 496bbf554c5c -r 38176d1c5ec2 src/hotspot/share/runtime/java.cpp --- a/src/hotspot/share/runtime/java.cpp Wed Oct 16 01:16:12 2019 +0200 +++ b/src/hotspot/share/runtime/java.cpp Wed Oct 16 11:23:46 2019 +0200 @@ -56,7 +56,6 @@ #include "prims/jvmtiExport.hpp" #include "runtime/arguments.hpp" #include "runtime/biasedLocking.hpp" -#include "runtime/compilationPolicy.hpp" #include "runtime/deoptimization.hpp" #include "runtime/flags/flagSetting.hpp" #include "runtime/handles.inline.hpp" diff -r 496bbf554c5c -r 38176d1c5ec2 src/hotspot/share/runtime/javaCalls.cpp --- a/src/hotspot/share/runtime/javaCalls.cpp Wed Oct 16 01:16:12 2019 +0200 +++ b/src/hotspot/share/runtime/javaCalls.cpp Wed Oct 16 11:23:46 2019 +0200 @@ -26,6 +26,7 @@ #include "classfile/systemDictionary.hpp" #include "classfile/vmSymbols.hpp" #include "code/nmethod.hpp" +#include "compiler/compilationPolicy.hpp" #include "compiler/compileBroker.hpp" #include "interpreter/interpreter.hpp" #include "interpreter/linkResolver.hpp" @@ -33,7 +34,6 @@ #include "oops/method.inline.hpp" #include "oops/oop.inline.hpp" #include "prims/jniCheck.hpp" -#include "runtime/compilationPolicy.hpp" #include "runtime/handles.inline.hpp" #include "runtime/interfaceSupport.inline.hpp" #include "runtime/javaCalls.hpp" diff -r 496bbf554c5c -r 38176d1c5ec2 src/hotspot/share/runtime/mutexLocker.cpp --- a/src/hotspot/share/runtime/mutexLocker.cpp Wed Oct 16 01:16:12 2019 +0200 +++ b/src/hotspot/share/runtime/mutexLocker.cpp Wed Oct 16 11:23:46 2019 +0200 @@ -161,7 +161,6 @@ #ifdef ASSERT void assert_locked_or_safepoint(const Mutex* lock) { // check if this thread owns the lock (common case) - if (IgnoreLockingAssertions) return; assert(lock != NULL, "Need non-NULL lock"); if (lock->owned_by_self()) return; if (SafepointSynchronize::is_at_safepoint()) return; @@ -174,7 +173,6 @@ // a weaker assertion than the above void assert_locked_or_safepoint_weak(const Mutex* lock) { - if (IgnoreLockingAssertions) return; assert(lock != NULL, "Need non-NULL lock"); if (lock->is_locked()) return; if (SafepointSynchronize::is_at_safepoint()) return; @@ -184,7 +182,6 @@ // a stronger assertion than the above void assert_lock_strong(const Mutex* lock) { - if (IgnoreLockingAssertions) return; assert(lock != NULL, "Need non-NULL lock"); if (lock->owned_by_self()) return; fatal("must own lock %s", lock->name()); diff -r 496bbf554c5c -r 38176d1c5ec2 src/hotspot/share/runtime/safepoint.cpp --- a/src/hotspot/share/runtime/safepoint.cpp Wed Oct 16 01:16:12 2019 +0200 +++ b/src/hotspot/share/runtime/safepoint.cpp Wed Oct 16 11:23:46 2019 +0200 @@ -33,6 +33,7 @@ #include "code/nmethod.hpp" #include "code/pcDesc.hpp" #include "code/scopeDesc.hpp" +#include "compiler/compilationPolicy.hpp" #include "gc/shared/collectedHeap.hpp" #include "gc/shared/gcLocker.hpp" #include "gc/shared/oopStorage.hpp" @@ -47,7 +48,6 @@ #include "oops/oop.inline.hpp" #include "oops/symbol.hpp" #include "runtime/atomic.hpp" -#include "runtime/compilationPolicy.hpp" #include "runtime/deoptimization.hpp" #include "runtime/frame.inline.hpp" #include "runtime/handles.inline.hpp" diff -r 496bbf554c5c -r 38176d1c5ec2 src/hotspot/share/runtime/sharedRuntime.cpp --- a/src/hotspot/share/runtime/sharedRuntime.cpp Wed Oct 16 01:16:12 2019 +0200 +++ b/src/hotspot/share/runtime/sharedRuntime.cpp Wed Oct 16 11:23:46 2019 +0200 @@ -57,7 +57,6 @@ #include "runtime/arguments.hpp" #include "runtime/atomic.hpp" #include "runtime/biasedLocking.hpp" -#include "runtime/compilationPolicy.hpp" #include "runtime/frame.inline.hpp" #include "runtime/handles.inline.hpp" #include "runtime/init.hpp" diff -r 496bbf554c5c -r 38176d1c5ec2 src/hotspot/share/runtime/sweeper.cpp --- a/src/hotspot/share/runtime/sweeper.cpp Wed Oct 16 01:16:12 2019 +0200 +++ b/src/hotspot/share/runtime/sweeper.cpp Wed Oct 16 11:23:46 2019 +0200 @@ -38,7 +38,6 @@ #include "memory/universe.hpp" #include "oops/method.hpp" #include "runtime/atomic.hpp" -#include "runtime/compilationPolicy.hpp" #include "runtime/interfaceSupport.inline.hpp" #include "runtime/handshake.hpp" #include "runtime/mutexLocker.hpp" diff -r 496bbf554c5c -r 38176d1c5ec2 src/hotspot/share/runtime/threadSMR.cpp --- a/src/hotspot/share/runtime/threadSMR.cpp Wed Oct 16 01:16:12 2019 +0200 +++ b/src/hotspot/share/runtime/threadSMR.cpp Wed Oct 16 11:23:46 2019 +0200 @@ -528,6 +528,22 @@ return; } + if ( _thread == VM_Exit::shutdown_thread()) { + // The shutdown thread has removed itself from the Threads + // list and is safe to have a waiver from this check because + // VM_Exit::_shutdown_thread is not set until after the VMThread + // has started the final safepoint which holds the Threads_lock + // for the remainder of the VM's life. + return; + } + + if (VMError::is_error_reported() && + VMError::get_first_error_tid() == os::current_thread_id()) { + // If there is an error reported by this thread it may use ThreadsList even + // if it's unsafe. + return; + } + // The closure will attempt to verify that the calling thread can // be found by threads_do() on the specified ThreadsList. If it // is successful, then the specified ThreadsList was acquired as @@ -540,12 +556,6 @@ // ThreadsList is not a stable hazard ptr and can be freed by // another thread from the to-be-deleted list at any time. // - // Note: The shutdown thread has removed itself from the Threads - // list and is safe to have a waiver from this check because - // VM_Exit::_shutdown_thread is not set until after the VMThread - // has started the final safepoint which holds the Threads_lock - // for the remainder of the VM's life. - // VerifyHazardPtrThreadClosure cl(_thread); ThreadsSMRSupport::threads_do(&cl, _list); @@ -555,7 +565,7 @@ // In either case, we won't get past this point with a badly placed // ThreadsListHandle. - assert(cl.found() || _thread == VM_Exit::shutdown_thread(), "Acquired a ThreadsList snapshot from a thread not recognized by the Thread-SMR protocol."); + assert(cl.found(), "Acquired a ThreadsList snapshot from a thread not recognized by the Thread-SMR protocol."); #endif } diff -r 496bbf554c5c -r 38176d1c5ec2 src/hotspot/share/runtime/tieredThresholdPolicy.cpp --- a/src/hotspot/share/runtime/tieredThresholdPolicy.cpp Wed Oct 16 01:16:12 2019 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,1005 +0,0 @@ -/* - * Copyright (c) 2010, 2019, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * 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 "compiler/compileBroker.hpp" -#include "compiler/compilerOracle.hpp" -#include "memory/resourceArea.hpp" -#include "runtime/arguments.hpp" -#include "runtime/handles.inline.hpp" -#include "runtime/safepoint.hpp" -#include "runtime/safepointVerifiers.hpp" -#include "runtime/tieredThresholdPolicy.hpp" -#include "code/scopeDesc.hpp" -#include "oops/method.inline.hpp" -#if INCLUDE_JVMCI -#include "jvmci/jvmci.hpp" -#endif - -#ifdef TIERED - -#include "c1/c1_Compiler.hpp" -#include "opto/c2compiler.hpp" - -template -bool TieredThresholdPolicy::call_predicate_helper(int i, int b, double scale, Method* method) { - double threshold_scaling; - if (CompilerOracle::has_option_value(method, "CompileThresholdScaling", threshold_scaling)) { - scale *= threshold_scaling; - } - switch(level) { - case CompLevel_aot: - return (i >= Tier3AOTInvocationThreshold * scale) || - (i >= Tier3AOTMinInvocationThreshold * scale && i + b >= Tier3AOTCompileThreshold * scale); - case CompLevel_none: - case CompLevel_limited_profile: - return (i >= Tier3InvocationThreshold * scale) || - (i >= Tier3MinInvocationThreshold * scale && i + b >= Tier3CompileThreshold * scale); - case CompLevel_full_profile: - return (i >= Tier4InvocationThreshold * scale) || - (i >= Tier4MinInvocationThreshold * scale && i + b >= Tier4CompileThreshold * scale); - } - return true; -} - -template -bool TieredThresholdPolicy::loop_predicate_helper(int i, int b, double scale, Method* method) { - double threshold_scaling; - if (CompilerOracle::has_option_value(method, "CompileThresholdScaling", threshold_scaling)) { - scale *= threshold_scaling; - } - switch(level) { - case CompLevel_aot: - return b >= Tier3AOTBackEdgeThreshold * scale; - case CompLevel_none: - case CompLevel_limited_profile: - return b >= Tier3BackEdgeThreshold * scale; - case CompLevel_full_profile: - return b >= Tier4BackEdgeThreshold * scale; - } - return true; -} - -// Simple methods are as good being compiled with C1 as C2. -// Determine if a given method is such a case. -bool TieredThresholdPolicy::is_trivial(Method* method) { - if (method->is_accessor() || - method->is_constant_getter()) { - return true; - } - return false; -} - -bool TieredThresholdPolicy::should_compile_at_level_simple(Method* method) { - if (TieredThresholdPolicy::is_trivial(method)) { - return true; - } -#if INCLUDE_JVMCI - if (UseJVMCICompiler) { - AbstractCompiler* comp = CompileBroker::compiler(CompLevel_full_optimization); - if (comp != NULL && comp->is_jvmci() && ((JVMCICompiler*) comp)->force_comp_at_level_simple(method)) { - return true; - } - } -#endif - return false; -} - -CompLevel TieredThresholdPolicy::comp_level(Method* method) { - CompiledMethod *nm = method->code(); - if (nm != NULL && nm->is_in_use()) { - return (CompLevel)nm->comp_level(); - } - return CompLevel_none; -} - -void TieredThresholdPolicy::print_counters(const char* prefix, const methodHandle& mh) { - int invocation_count = mh->invocation_count(); - int backedge_count = mh->backedge_count(); - MethodData* mdh = mh->method_data(); - int mdo_invocations = 0, mdo_backedges = 0; - int mdo_invocations_start = 0, mdo_backedges_start = 0; - if (mdh != NULL) { - mdo_invocations = mdh->invocation_count(); - mdo_backedges = mdh->backedge_count(); - mdo_invocations_start = mdh->invocation_count_start(); - mdo_backedges_start = mdh->backedge_count_start(); - } - tty->print(" %stotal=%d,%d %smdo=%d(%d),%d(%d)", prefix, - invocation_count, backedge_count, prefix, - mdo_invocations, mdo_invocations_start, - mdo_backedges, mdo_backedges_start); - tty->print(" %smax levels=%d,%d", prefix, - mh->highest_comp_level(), mh->highest_osr_comp_level()); -} - -// Print an event. -void TieredThresholdPolicy::print_event(EventType type, const methodHandle& mh, const methodHandle& imh, - int bci, CompLevel level) { - bool inlinee_event = mh() != imh(); - - ttyLocker tty_lock; - tty->print("%lf: [", os::elapsedTime()); - - switch(type) { - case CALL: - tty->print("call"); - break; - case LOOP: - tty->print("loop"); - break; - case COMPILE: - tty->print("compile"); - break; - case REMOVE_FROM_QUEUE: - tty->print("remove-from-queue"); - break; - case UPDATE_IN_QUEUE: - tty->print("update-in-queue"); - break; - case REPROFILE: - tty->print("reprofile"); - break; - case MAKE_NOT_ENTRANT: - tty->print("make-not-entrant"); - break; - default: - tty->print("unknown"); - } - - tty->print(" level=%d ", level); - - ResourceMark rm; - char *method_name = mh->name_and_sig_as_C_string(); - tty->print("[%s", method_name); - if (inlinee_event) { - char *inlinee_name = imh->name_and_sig_as_C_string(); - tty->print(" [%s]] ", inlinee_name); - } - else tty->print("] "); - tty->print("@%d queues=%d,%d", bci, CompileBroker::queue_size(CompLevel_full_profile), - CompileBroker::queue_size(CompLevel_full_optimization)); - - print_specific(type, mh, imh, bci, level); - - if (type != COMPILE) { - print_counters("", mh); - if (inlinee_event) { - print_counters("inlinee ", imh); - } - tty->print(" compilable="); - bool need_comma = false; - if (!mh->is_not_compilable(CompLevel_full_profile)) { - tty->print("c1"); - need_comma = true; - } - if (!mh->is_not_osr_compilable(CompLevel_full_profile)) { - if (need_comma) tty->print(","); - tty->print("c1-osr"); - need_comma = true; - } - if (!mh->is_not_compilable(CompLevel_full_optimization)) { - if (need_comma) tty->print(","); - tty->print("c2"); - need_comma = true; - } - if (!mh->is_not_osr_compilable(CompLevel_full_optimization)) { - if (need_comma) tty->print(","); - tty->print("c2-osr"); - } - tty->print(" status="); - if (mh->queued_for_compilation()) { - tty->print("in-queue"); - } else tty->print("idle"); - } - tty->print_cr("]"); -} - -void TieredThresholdPolicy::initialize() { - int count = CICompilerCount; - bool c1_only = TieredStopAtLevel < CompLevel_full_optimization; -#ifdef _LP64 - // Turn on ergonomic compiler count selection - if (FLAG_IS_DEFAULT(CICompilerCountPerCPU) && FLAG_IS_DEFAULT(CICompilerCount)) { - FLAG_SET_DEFAULT(CICompilerCountPerCPU, true); - } - if (CICompilerCountPerCPU) { - // Simple log n seems to grow too slowly for tiered, try something faster: log n * log log n - int log_cpu = log2_int(os::active_processor_count()); - int loglog_cpu = log2_int(MAX2(log_cpu, 1)); - count = MAX2(log_cpu * loglog_cpu * 3 / 2, 2); - // Make sure there is enough space in the code cache to hold all the compiler buffers - size_t c1_size = Compiler::code_buffer_size(); - size_t c2_size = C2Compiler::initial_code_buffer_size(); - size_t buffer_size = c1_only ? c1_size : (c1_size/3 + 2*c2_size/3); - int max_count = (ReservedCodeCacheSize - (CodeCacheMinimumUseSpace DEBUG_ONLY(* 3))) / (int)buffer_size; - if (count > max_count) { - // Lower the compiler count such that all buffers fit into the code cache - count = MAX2(max_count, c1_only ? 1 : 2); - } - FLAG_SET_ERGO(CICompilerCount, count); - } -#else - // On 32-bit systems, the number of compiler threads is limited to 3. - // On these systems, the virtual address space available to the JVM - // is usually limited to 2-4 GB (the exact value depends on the platform). - // As the compilers (especially C2) can consume a large amount of - // memory, scaling the number of compiler threads with the number of - // available cores can result in the exhaustion of the address space - /// available to the VM and thus cause the VM to crash. - if (FLAG_IS_DEFAULT(CICompilerCount)) { - count = 3; - FLAG_SET_ERGO(CICompilerCount, count); - } -#endif - - if (c1_only) { - // No C2 compiler thread required - set_c1_count(count); - } else { - set_c1_count(MAX2(count / 3, 1)); - set_c2_count(MAX2(count - c1_count(), 1)); - } - assert(count == c1_count() + c2_count(), "inconsistent compiler thread count"); - - // Some inlining tuning -#ifdef X86 - if (FLAG_IS_DEFAULT(InlineSmallCode)) { - FLAG_SET_DEFAULT(InlineSmallCode, 2000); - } -#endif - -#if defined SPARC || defined AARCH64 - if (FLAG_IS_DEFAULT(InlineSmallCode)) { - FLAG_SET_DEFAULT(InlineSmallCode, 2500); - } -#endif - - set_increase_threshold_at_ratio(); - set_start_time(os::javaTimeMillis()); -} - -void TieredThresholdPolicy::set_carry_if_necessary(InvocationCounter *counter) { - if (!counter->carry() && counter->count() > InvocationCounter::count_limit / 2) { - counter->set_carry_flag(); - } -} - -// Set carry flags on the counters if necessary -void TieredThresholdPolicy::handle_counter_overflow(Method* method) { - MethodCounters *mcs = method->method_counters(); - if (mcs != NULL) { - set_carry_if_necessary(mcs->invocation_counter()); - set_carry_if_necessary(mcs->backedge_counter()); - } - MethodData* mdo = method->method_data(); - if (mdo != NULL) { - set_carry_if_necessary(mdo->invocation_counter()); - set_carry_if_necessary(mdo->backedge_counter()); - } -} - -// Called with the queue locked and with at least one element -CompileTask* TieredThresholdPolicy::select_task(CompileQueue* compile_queue) { - CompileTask *max_blocking_task = NULL; - CompileTask *max_task = NULL; - Method* max_method = NULL; - jlong t = os::javaTimeMillis(); - // Iterate through the queue and find a method with a maximum rate. - for (CompileTask* task = compile_queue->first(); task != NULL;) { - CompileTask* next_task = task->next(); - Method* method = task->method(); - // If a method was unloaded or has been stale for some time, remove it from the queue. - // Blocking tasks and tasks submitted from whitebox API don't become stale - if (task->is_unloaded() || (task->can_become_stale() && is_stale(t, TieredCompileTaskTimeout, method) && !is_old(method))) { - if (!task->is_unloaded()) { - if (PrintTieredEvents) { - print_event(REMOVE_FROM_QUEUE, method, method, task->osr_bci(), (CompLevel) task->comp_level()); - } - method->clear_queued_for_compilation(); - } - compile_queue->remove_and_mark_stale(task); - task = next_task; - continue; - } - update_rate(t, method); - if (max_task == NULL || compare_methods(method, max_method)) { - // Select a method with the highest rate - max_task = task; - max_method = method; - } - - if (task->is_blocking()) { - if (max_blocking_task == NULL || compare_methods(method, max_blocking_task->method())) { - max_blocking_task = task; - } - } - - task = next_task; - } - - if (max_blocking_task != NULL) { - // In blocking compilation mode, the CompileBroker will make - // compilations submitted by a JVMCI compiler thread non-blocking. These - // compilations should be scheduled after all blocking compilations - // to service non-compiler related compilations sooner and reduce the - // chance of such compilations timing out. - max_task = max_blocking_task; - max_method = max_task->method(); - } - - if (max_task != NULL && max_task->comp_level() == CompLevel_full_profile && - TieredStopAtLevel > CompLevel_full_profile && - max_method != NULL && is_method_profiled(max_method)) { - max_task->set_comp_level(CompLevel_limited_profile); - - if (CompileBroker::compilation_is_complete(max_method, max_task->osr_bci(), CompLevel_limited_profile)) { - if (PrintTieredEvents) { - print_event(REMOVE_FROM_QUEUE, max_method, max_method, max_task->osr_bci(), (CompLevel)max_task->comp_level()); - } - compile_queue->remove_and_mark_stale(max_task); - max_method->clear_queued_for_compilation(); - return NULL; - } - - if (PrintTieredEvents) { - print_event(UPDATE_IN_QUEUE, max_method, max_method, max_task->osr_bci(), (CompLevel)max_task->comp_level()); - } - } - - return max_task; -} - -void TieredThresholdPolicy::reprofile(ScopeDesc* trap_scope, bool is_osr) { - for (ScopeDesc* sd = trap_scope;; sd = sd->sender()) { - if (PrintTieredEvents) { - methodHandle mh(sd->method()); - print_event(REPROFILE, mh, mh, InvocationEntryBci, CompLevel_none); - } - MethodData* mdo = sd->method()->method_data(); - if (mdo != NULL) { - mdo->reset_start_counters(); - } - if (sd->is_top()) break; - } -} - -nmethod* TieredThresholdPolicy::event(const methodHandle& method, const methodHandle& inlinee, - int branch_bci, int bci, CompLevel comp_level, CompiledMethod* nm, JavaThread* thread) { - if (comp_level == CompLevel_none && - JvmtiExport::can_post_interpreter_events() && - thread->is_interp_only_mode()) { - return NULL; - } - if (ReplayCompiles) { - // Don't trigger other compiles in testing mode - return NULL; - } - - handle_counter_overflow(method()); - if (method() != inlinee()) { - handle_counter_overflow(inlinee()); - } - - if (PrintTieredEvents) { - print_event(bci == InvocationEntryBci ? CALL : LOOP, method, inlinee, bci, comp_level); - } - - if (bci == InvocationEntryBci) { - method_invocation_event(method, inlinee, comp_level, nm, thread); - } else { - // method == inlinee if the event originated in the main method - method_back_branch_event(method, inlinee, bci, comp_level, nm, thread); - // Check if event led to a higher level OSR compilation - CompLevel expected_comp_level = comp_level; - if (inlinee->is_not_osr_compilable(expected_comp_level)) { - // It's not possble to reach the expected level so fall back to simple. - expected_comp_level = CompLevel_simple; - } - nmethod* osr_nm = inlinee->lookup_osr_nmethod_for(bci, expected_comp_level, false); - assert(osr_nm == NULL || osr_nm->comp_level() >= expected_comp_level, "lookup_osr_nmethod_for is broken"); - if (osr_nm != NULL) { - // Perform OSR with new nmethod - return osr_nm; - } - } - return NULL; -} - -// Check if the method can be compiled, change level if necessary -void TieredThresholdPolicy::compile(const methodHandle& mh, int bci, CompLevel level, JavaThread* thread) { - assert(level <= TieredStopAtLevel, "Invalid compilation level"); - if (level == CompLevel_none) { - return; - } - if (level == CompLevel_aot) { - if (mh->has_aot_code()) { - if (PrintTieredEvents) { - print_event(COMPILE, mh, mh, bci, level); - } - MutexLocker ml(Compile_lock); - NoSafepointVerifier nsv; - if (mh->has_aot_code() && mh->code() != mh->aot_code()) { - mh->aot_code()->make_entrant(); - if (mh->has_compiled_code()) { - mh->code()->make_not_entrant(); - } - MutexLocker pl(CompiledMethod_lock, Mutex::_no_safepoint_check_flag); - Method::set_code(mh, mh->aot_code()); - } - } - return; - } - - // Check if the method can be compiled. If it cannot be compiled with C1, continue profiling - // in the interpreter and then compile with C2 (the transition function will request that, - // see common() ). If the method cannot be compiled with C2 but still can with C1, compile it with - // pure C1. - if ((bci == InvocationEntryBci && !can_be_compiled(mh, level))) { - if (level == CompLevel_full_optimization && can_be_compiled(mh, CompLevel_simple)) { - compile(mh, bci, CompLevel_simple, thread); - } - return; - } - if ((bci != InvocationEntryBci && !can_be_osr_compiled(mh, level))) { - if (level == CompLevel_full_optimization && can_be_osr_compiled(mh, CompLevel_simple)) { - nmethod* osr_nm = mh->lookup_osr_nmethod_for(bci, CompLevel_simple, false); - if (osr_nm != NULL && osr_nm->comp_level() > CompLevel_simple) { - // Invalidate the existing OSR nmethod so that a compile at CompLevel_simple is permitted. - osr_nm->make_not_entrant(); - } - compile(mh, bci, CompLevel_simple, thread); - } - return; - } - if (bci != InvocationEntryBci && mh->is_not_osr_compilable(level)) { - return; - } - if (!CompileBroker::compilation_is_in_queue(mh)) { - if (PrintTieredEvents) { - print_event(COMPILE, mh, mh, bci, level); - } - submit_compile(mh, bci, level, thread); - } -} - -// Update the rate and submit compile -void TieredThresholdPolicy::submit_compile(const methodHandle& mh, int bci, CompLevel level, JavaThread* thread) { - int hot_count = (bci == InvocationEntryBci) ? mh->invocation_count() : mh->backedge_count(); - update_rate(os::javaTimeMillis(), mh()); - CompileBroker::compile_method(mh, bci, level, mh, hot_count, CompileTask::Reason_Tiered, thread); -} - -// Print an event. -void TieredThresholdPolicy::print_specific(EventType type, const methodHandle& mh, const methodHandle& imh, - int bci, CompLevel level) { - tty->print(" rate="); - if (mh->prev_time() == 0) tty->print("n/a"); - else tty->print("%f", mh->rate()); - - tty->print(" k=%.2lf,%.2lf", threshold_scale(CompLevel_full_profile, Tier3LoadFeedback), - threshold_scale(CompLevel_full_optimization, Tier4LoadFeedback)); - -} - -// update_rate() is called from select_task() while holding a compile queue lock. -void TieredThresholdPolicy::update_rate(jlong t, Method* m) { - // Skip update if counters are absent. - // Can't allocate them since we are holding compile queue lock. - if (m->method_counters() == NULL) return; - - if (is_old(m)) { - // We don't remove old methods from the queue, - // so we can just zero the rate. - m->set_rate(0); - return; - } - - // We don't update the rate if we've just came out of a safepoint. - // delta_s is the time since last safepoint in milliseconds. - jlong delta_s = t - SafepointTracing::end_of_last_safepoint_epoch_ms(); - jlong delta_t = t - (m->prev_time() != 0 ? m->prev_time() : start_time()); // milliseconds since the last measurement - // How many events were there since the last time? - int event_count = m->invocation_count() + m->backedge_count(); - int delta_e = event_count - m->prev_event_count(); - - // We should be running for at least 1ms. - if (delta_s >= TieredRateUpdateMinTime) { - // And we must've taken the previous point at least 1ms before. - if (delta_t >= TieredRateUpdateMinTime && delta_e > 0) { - m->set_prev_time(t); - m->set_prev_event_count(event_count); - m->set_rate((float)delta_e / (float)delta_t); // Rate is events per millisecond - } else { - if (delta_t > TieredRateUpdateMaxTime && delta_e == 0) { - // If nothing happened for 25ms, zero the rate. Don't modify prev values. - m->set_rate(0); - } - } - } -} - -// Check if this method has been stale for a given number of milliseconds. -// See select_task(). -bool TieredThresholdPolicy::is_stale(jlong t, jlong timeout, Method* m) { - jlong delta_s = t - SafepointTracing::end_of_last_safepoint_epoch_ms(); - jlong delta_t = t - m->prev_time(); - if (delta_t > timeout && delta_s > timeout) { - int event_count = m->invocation_count() + m->backedge_count(); - int delta_e = event_count - m->prev_event_count(); - // Return true if there were no events. - return delta_e == 0; - } - return false; -} - -// We don't remove old methods from the compile queue even if they have -// very low activity. See select_task(). -bool TieredThresholdPolicy::is_old(Method* method) { - return method->invocation_count() > 50000 || method->backedge_count() > 500000; -} - -double TieredThresholdPolicy::weight(Method* method) { - return (double)(method->rate() + 1) * - (method->invocation_count() + 1) * (method->backedge_count() + 1); -} - -// Apply heuristics and return true if x should be compiled before y -bool TieredThresholdPolicy::compare_methods(Method* x, Method* y) { - if (x->highest_comp_level() > y->highest_comp_level()) { - // recompilation after deopt - return true; - } else - if (x->highest_comp_level() == y->highest_comp_level()) { - if (weight(x) > weight(y)) { - return true; - } - } - return false; -} - -// Is method profiled enough? -bool TieredThresholdPolicy::is_method_profiled(Method* method) { - MethodData* mdo = method->method_data(); - if (mdo != NULL) { - int i = mdo->invocation_count_delta(); - int b = mdo->backedge_count_delta(); - return call_predicate_helper(i, b, 1, method); - } - return false; -} - -double TieredThresholdPolicy::threshold_scale(CompLevel level, int feedback_k) { - double queue_size = CompileBroker::queue_size(level); - int comp_count = compiler_count(level); - double k = queue_size / (feedback_k * comp_count) + 1; - - // Increase C1 compile threshold when the code cache is filled more - // than specified by IncreaseFirstTierCompileThresholdAt percentage. - // The main intention is to keep enough free space for C2 compiled code - // to achieve peak performance if the code cache is under stress. - if ((TieredStopAtLevel == CompLevel_full_optimization) && (level != CompLevel_full_optimization)) { - double current_reverse_free_ratio = CodeCache::reverse_free_ratio(CodeCache::get_code_blob_type(level)); - if (current_reverse_free_ratio > _increase_threshold_at_ratio) { - k *= exp(current_reverse_free_ratio - _increase_threshold_at_ratio); - } - } - return k; -} - -// Call and loop predicates determine whether a transition to a higher -// compilation level should be performed (pointers to predicate functions -// are passed to common()). -// Tier?LoadFeedback is basically a coefficient that determines of -// how many methods per compiler thread can be in the queue before -// the threshold values double. -bool TieredThresholdPolicy::loop_predicate(int i, int b, CompLevel cur_level, Method* method) { - switch(cur_level) { - case CompLevel_aot: { - double k = threshold_scale(CompLevel_full_profile, Tier3LoadFeedback); - return loop_predicate_helper(i, b, k, method); - } - case CompLevel_none: - case CompLevel_limited_profile: { - double k = threshold_scale(CompLevel_full_profile, Tier3LoadFeedback); - return loop_predicate_helper(i, b, k, method); - } - case CompLevel_full_profile: { - double k = threshold_scale(CompLevel_full_optimization, Tier4LoadFeedback); - return loop_predicate_helper(i, b, k, method); - } - default: - return true; - } -} - -bool TieredThresholdPolicy::call_predicate(int i, int b, CompLevel cur_level, Method* method) { - switch(cur_level) { - case CompLevel_aot: { - double k = threshold_scale(CompLevel_full_profile, Tier3LoadFeedback); - return call_predicate_helper(i, b, k, method); - } - case CompLevel_none: - case CompLevel_limited_profile: { - double k = threshold_scale(CompLevel_full_profile, Tier3LoadFeedback); - return call_predicate_helper(i, b, k, method); - } - case CompLevel_full_profile: { - double k = threshold_scale(CompLevel_full_optimization, Tier4LoadFeedback); - return call_predicate_helper(i, b, k, method); - } - default: - return true; - } -} - -// Determine is a method is mature. -bool TieredThresholdPolicy::is_mature(Method* method) { - if (should_compile_at_level_simple(method)) return true; - MethodData* mdo = method->method_data(); - if (mdo != NULL) { - int i = mdo->invocation_count(); - int b = mdo->backedge_count(); - double k = ProfileMaturityPercentage / 100.0; - return call_predicate_helper(i, b, k, method) || - loop_predicate_helper(i, b, k, method); - } - return false; -} - -// If a method is old enough and is still in the interpreter we would want to -// start profiling without waiting for the compiled method to arrive. -// We also take the load on compilers into the account. -bool TieredThresholdPolicy::should_create_mdo(Method* method, CompLevel cur_level) { - if (cur_level == CompLevel_none && - CompileBroker::queue_size(CompLevel_full_optimization) <= - Tier3DelayOn * compiler_count(CompLevel_full_optimization)) { - int i = method->invocation_count(); - int b = method->backedge_count(); - double k = Tier0ProfilingStartPercentage / 100.0; - return call_predicate_helper(i, b, k, method) || loop_predicate_helper(i, b, k, method); - } - return false; -} - -// Inlining control: if we're compiling a profiled method with C1 and the callee -// is known to have OSRed in a C2 version, don't inline it. -bool TieredThresholdPolicy::should_not_inline(ciEnv* env, ciMethod* callee) { - CompLevel comp_level = (CompLevel)env->comp_level(); - if (comp_level == CompLevel_full_profile || - comp_level == CompLevel_limited_profile) { - return callee->highest_osr_comp_level() == CompLevel_full_optimization; - } - return false; -} - -// Create MDO if necessary. -void TieredThresholdPolicy::create_mdo(const methodHandle& mh, JavaThread* THREAD) { - if (mh->is_native() || - mh->is_abstract() || - mh->is_accessor() || - mh->is_constant_getter()) { - return; - } - if (mh->method_data() == NULL) { - Method::build_interpreter_method_data(mh, CHECK_AND_CLEAR); - } -} - - -/* - * Method states: - * 0 - interpreter (CompLevel_none) - * 1 - pure C1 (CompLevel_simple) - * 2 - C1 with invocation and backedge counting (CompLevel_limited_profile) - * 3 - C1 with full profiling (CompLevel_full_profile) - * 4 - C2 (CompLevel_full_optimization) - * - * Common state transition patterns: - * a. 0 -> 3 -> 4. - * The most common path. But note that even in this straightforward case - * profiling can start at level 0 and finish at level 3. - * - * b. 0 -> 2 -> 3 -> 4. - * This case occurs when the load on C2 is deemed too high. So, instead of transitioning - * into state 3 directly and over-profiling while a method is in the C2 queue we transition to - * level 2 and wait until the load on C2 decreases. This path is disabled for OSRs. - * - * c. 0 -> (3->2) -> 4. - * In this case we enqueue a method for compilation at level 3, but the C1 queue is long enough - * to enable the profiling to fully occur at level 0. In this case we change the compilation level - * of the method to 2 while the request is still in-queue, because it'll allow it to run much faster - * without full profiling while c2 is compiling. - * - * d. 0 -> 3 -> 1 or 0 -> 2 -> 1. - * After a method was once compiled with C1 it can be identified as trivial and be compiled to - * level 1. These transition can also occur if a method can't be compiled with C2 but can with C1. - * - * e. 0 -> 4. - * This can happen if a method fails C1 compilation (it will still be profiled in the interpreter) - * or because of a deopt that didn't require reprofiling (compilation won't happen in this case because - * the compiled version already exists). - * - * Note that since state 0 can be reached from any other state via deoptimization different loops - * are possible. - * - */ - -// Common transition function. Given a predicate determines if a method should transition to another level. -CompLevel TieredThresholdPolicy::common(Predicate p, Method* method, CompLevel cur_level, bool disable_feedback) { - CompLevel next_level = cur_level; - int i = method->invocation_count(); - int b = method->backedge_count(); - - if (should_compile_at_level_simple(method)) { - next_level = CompLevel_simple; - } else { - switch(cur_level) { - default: break; - case CompLevel_aot: { - // If we were at full profile level, would we switch to full opt? - if (common(p, method, CompLevel_full_profile, disable_feedback) == CompLevel_full_optimization) { - next_level = CompLevel_full_optimization; - } else if (disable_feedback || (CompileBroker::queue_size(CompLevel_full_optimization) <= - Tier3DelayOff * compiler_count(CompLevel_full_optimization) && - (this->*p)(i, b, cur_level, method))) { - next_level = CompLevel_full_profile; - } - } - break; - case CompLevel_none: - // If we were at full profile level, would we switch to full opt? - if (common(p, method, CompLevel_full_profile, disable_feedback) == CompLevel_full_optimization) { - next_level = CompLevel_full_optimization; - } else if ((this->*p)(i, b, cur_level, method)) { -#if INCLUDE_JVMCI - if (EnableJVMCI && UseJVMCICompiler) { - // Since JVMCI takes a while to warm up, its queue inevitably backs up during - // early VM execution. As of 2014-06-13, JVMCI's inliner assumes that the root - // compilation method and all potential inlinees have mature profiles (which - // includes type profiling). If it sees immature profiles, JVMCI's inliner - // can perform pathologically bad (e.g., causing OutOfMemoryErrors due to - // exploring/inlining too many graphs). Since a rewrite of the inliner is - // in progress, we simply disable the dialing back heuristic for now and will - // revisit this decision once the new inliner is completed. - next_level = CompLevel_full_profile; - } else -#endif - { - // C1-generated fully profiled code is about 30% slower than the limited profile - // code that has only invocation and backedge counters. The observation is that - // if C2 queue is large enough we can spend too much time in the fully profiled code - // while waiting for C2 to pick the method from the queue. To alleviate this problem - // we introduce a feedback on the C2 queue size. If the C2 queue is sufficiently long - // we choose to compile a limited profiled version and then recompile with full profiling - // when the load on C2 goes down. - if (!disable_feedback && CompileBroker::queue_size(CompLevel_full_optimization) > - Tier3DelayOn * compiler_count(CompLevel_full_optimization)) { - next_level = CompLevel_limited_profile; - } else { - next_level = CompLevel_full_profile; - } - } - } - break; - case CompLevel_limited_profile: - if (is_method_profiled(method)) { - // Special case: we got here because this method was fully profiled in the interpreter. - next_level = CompLevel_full_optimization; - } else { - MethodData* mdo = method->method_data(); - if (mdo != NULL) { - if (mdo->would_profile()) { - if (disable_feedback || (CompileBroker::queue_size(CompLevel_full_optimization) <= - Tier3DelayOff * compiler_count(CompLevel_full_optimization) && - (this->*p)(i, b, cur_level, method))) { - next_level = CompLevel_full_profile; - } - } else { - next_level = CompLevel_full_optimization; - } - } else { - // If there is no MDO we need to profile - if (disable_feedback || (CompileBroker::queue_size(CompLevel_full_optimization) <= - Tier3DelayOff * compiler_count(CompLevel_full_optimization) && - (this->*p)(i, b, cur_level, method))) { - next_level = CompLevel_full_profile; - } - } - } - break; - case CompLevel_full_profile: - { - MethodData* mdo = method->method_data(); - if (mdo != NULL) { - if (mdo->would_profile()) { - int mdo_i = mdo->invocation_count_delta(); - int mdo_b = mdo->backedge_count_delta(); - if ((this->*p)(mdo_i, mdo_b, cur_level, method)) { - next_level = CompLevel_full_optimization; - } - } else { - next_level = CompLevel_full_optimization; - } - } - } - break; - } - } - return MIN2(next_level, (CompLevel)TieredStopAtLevel); -} - -// Determine if a method should be compiled with a normal entry point at a different level. -CompLevel TieredThresholdPolicy::call_event(Method* method, CompLevel cur_level, JavaThread * thread) { - CompLevel osr_level = MIN2((CompLevel) method->highest_osr_comp_level(), - common(&TieredThresholdPolicy::loop_predicate, method, cur_level, true)); - CompLevel next_level = common(&TieredThresholdPolicy::call_predicate, method, cur_level); - - // If OSR method level is greater than the regular method level, the levels should be - // equalized by raising the regular method level in order to avoid OSRs during each - // invocation of the method. - if (osr_level == CompLevel_full_optimization && cur_level == CompLevel_full_profile) { - MethodData* mdo = method->method_data(); - guarantee(mdo != NULL, "MDO should not be NULL"); - if (mdo->invocation_count() >= 1) { - next_level = CompLevel_full_optimization; - } - } else { - next_level = MAX2(osr_level, next_level); - } - return next_level; -} - -// Determine if we should do an OSR compilation of a given method. -CompLevel TieredThresholdPolicy::loop_event(Method* method, CompLevel cur_level, JavaThread* thread) { - CompLevel next_level = common(&TieredThresholdPolicy::loop_predicate, method, cur_level, true); - if (cur_level == CompLevel_none) { - // If there is a live OSR method that means that we deopted to the interpreter - // for the transition. - CompLevel osr_level = MIN2((CompLevel)method->highest_osr_comp_level(), next_level); - if (osr_level > CompLevel_none) { - return osr_level; - } - } - return next_level; -} - -bool TieredThresholdPolicy::maybe_switch_to_aot(const methodHandle& mh, CompLevel cur_level, CompLevel next_level, JavaThread* thread) { - if (UseAOT) { - if (cur_level == CompLevel_full_profile || cur_level == CompLevel_none) { - // If the current level is full profile or interpreter and we're switching to any other level, - // activate the AOT code back first so that we won't waste time overprofiling. - compile(mh, InvocationEntryBci, CompLevel_aot, thread); - // Fall through for JIT compilation. - } - if (next_level == CompLevel_limited_profile && cur_level != CompLevel_aot && mh->has_aot_code()) { - // If the next level is limited profile, use the aot code (if there is any), - // since it's essentially the same thing. - compile(mh, InvocationEntryBci, CompLevel_aot, thread); - // Not need to JIT, we're done. - return true; - } - } - return false; -} - - -// Handle the invocation event. -void TieredThresholdPolicy::method_invocation_event(const methodHandle& mh, const methodHandle& imh, - CompLevel level, CompiledMethod* nm, JavaThread* thread) { - if (should_create_mdo(mh(), level)) { - create_mdo(mh, thread); - } - CompLevel next_level = call_event(mh(), level, thread); - if (next_level != level) { - if (maybe_switch_to_aot(mh, level, next_level, thread)) { - // No JITting necessary - return; - } - if (is_compilation_enabled() && !CompileBroker::compilation_is_in_queue(mh)) { - compile(mh, InvocationEntryBci, next_level, thread); - } - } -} - -// Handle the back branch event. Notice that we can compile the method -// with a regular entry from here. -void TieredThresholdPolicy::method_back_branch_event(const methodHandle& mh, const methodHandle& imh, - int bci, CompLevel level, CompiledMethod* nm, JavaThread* thread) { - if (should_create_mdo(mh(), level)) { - create_mdo(mh, thread); - } - // Check if MDO should be created for the inlined method - if (should_create_mdo(imh(), level)) { - create_mdo(imh, thread); - } - - if (is_compilation_enabled()) { - CompLevel next_osr_level = loop_event(imh(), level, thread); - CompLevel max_osr_level = (CompLevel)imh->highest_osr_comp_level(); - // At the very least compile the OSR version - if (!CompileBroker::compilation_is_in_queue(imh) && (next_osr_level != level)) { - compile(imh, bci, next_osr_level, thread); - } - - // Use loop event as an opportunity to also check if there's been - // enough calls. - CompLevel cur_level, next_level; - if (mh() != imh()) { // If there is an enclosing method - if (level == CompLevel_aot) { - // Recompile the enclosing method to prevent infinite OSRs. Stay at AOT level while it's compiling. - if (max_osr_level != CompLevel_none && !CompileBroker::compilation_is_in_queue(mh)) { - compile(mh, InvocationEntryBci, MIN2((CompLevel)TieredStopAtLevel, CompLevel_full_profile), thread); - } - } else { - // Current loop event level is not AOT - guarantee(nm != NULL, "Should have nmethod here"); - cur_level = comp_level(mh()); - next_level = call_event(mh(), cur_level, thread); - - if (max_osr_level == CompLevel_full_optimization) { - // The inlinee OSRed to full opt, we need to modify the enclosing method to avoid deopts - bool make_not_entrant = false; - if (nm->is_osr_method()) { - // This is an osr method, just make it not entrant and recompile later if needed - make_not_entrant = true; - } else { - if (next_level != CompLevel_full_optimization) { - // next_level is not full opt, so we need to recompile the - // enclosing method without the inlinee - cur_level = CompLevel_none; - make_not_entrant = true; - } - } - if (make_not_entrant) { - if (PrintTieredEvents) { - int osr_bci = nm->is_osr_method() ? nm->osr_entry_bci() : InvocationEntryBci; - print_event(MAKE_NOT_ENTRANT, mh(), mh(), osr_bci, level); - } - nm->make_not_entrant(); - } - } - // Fix up next_level if necessary to avoid deopts - if (next_level == CompLevel_limited_profile && max_osr_level == CompLevel_full_profile) { - next_level = CompLevel_full_profile; - } - if (cur_level != next_level) { - if (!maybe_switch_to_aot(mh, cur_level, next_level, thread) && !CompileBroker::compilation_is_in_queue(mh)) { - compile(mh, InvocationEntryBci, next_level, thread); - } - } - } - } else { - cur_level = comp_level(mh()); - next_level = call_event(mh(), cur_level, thread); - if (next_level != cur_level) { - if (!maybe_switch_to_aot(mh, cur_level, next_level, thread) && !CompileBroker::compilation_is_in_queue(mh)) { - compile(mh, InvocationEntryBci, next_level, thread); - } - } - } - } -} - -#endif diff -r 496bbf554c5c -r 38176d1c5ec2 src/hotspot/share/runtime/tieredThresholdPolicy.hpp --- a/src/hotspot/share/runtime/tieredThresholdPolicy.hpp Wed Oct 16 01:16:12 2019 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,278 +0,0 @@ -/* - * Copyright (c) 2010, 2019, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - * - */ - -#ifndef SHARE_RUNTIME_TIEREDTHRESHOLDPOLICY_HPP -#define SHARE_RUNTIME_TIEREDTHRESHOLDPOLICY_HPP - -#include "code/nmethod.hpp" -#include "oops/methodData.hpp" -#include "runtime/compilationPolicy.hpp" -#include "utilities/globalDefinitions.hpp" - -#ifdef TIERED - -class CompileTask; -class CompileQueue; -/* - * The system supports 5 execution levels: - * * level 0 - interpreter - * * level 1 - C1 with full optimization (no profiling) - * * level 2 - C1 with invocation and backedge counters - * * level 3 - C1 with full profiling (level 2 + MDO) - * * level 4 - C2 - * - * Levels 0, 2 and 3 periodically notify the runtime about the current value of the counters - * (invocation counters and backedge counters). The frequency of these notifications is - * different at each level. These notifications are used by the policy to decide what transition - * to make. - * - * Execution starts at level 0 (interpreter), then the policy can decide either to compile the - * method at level 3 or level 2. The decision is based on the following factors: - * 1. The length of the C2 queue determines the next level. The observation is that level 2 - * is generally faster than level 3 by about 30%, therefore we would want to minimize the time - * a method spends at level 3. We should only spend the time at level 3 that is necessary to get - * adequate profiling. So, if the C2 queue is long enough it is more beneficial to go first to - * level 2, because if we transitioned to level 3 we would be stuck there until our C2 compile - * request makes its way through the long queue. When the load on C2 recedes we are going to - * recompile at level 3 and start gathering profiling information. - * 2. The length of C1 queue is used to dynamically adjust the thresholds, so as to introduce - * additional filtering if the compiler is overloaded. The rationale is that by the time a - * method gets compiled it can become unused, so it doesn't make sense to put too much onto the - * queue. - * - * After profiling is completed at level 3 the transition is made to level 4. Again, the length - * of the C2 queue is used as a feedback to adjust the thresholds. - * - * After the first C1 compile some basic information is determined about the code like the number - * of the blocks and the number of the loops. Based on that it can be decided that a method - * is trivial and compiling it with C1 will yield the same code. In this case the method is - * compiled at level 1 instead of 4. - * - * We also support profiling at level 0. If C1 is slow enough to produce the level 3 version of - * the code and the C2 queue is sufficiently small we can decide to start profiling in the - * interpreter (and continue profiling in the compiled code once the level 3 version arrives). - * If the profiling at level 0 is fully completed before level 3 version is produced, a level 2 - * version is compiled instead in order to run faster waiting for a level 4 version. - * - * Compile queues are implemented as priority queues - for each method in the queue we compute - * the event rate (the number of invocation and backedge counter increments per unit of time). - * When getting an element off the queue we pick the one with the largest rate. Maintaining the - * rate also allows us to remove stale methods (the ones that got on the queue but stopped - * being used shortly after that). -*/ - -/* Command line options: - * - Tier?InvokeNotifyFreqLog and Tier?BackedgeNotifyFreqLog control the frequency of method - * invocation and backedge notifications. Basically every n-th invocation or backedge a mutator thread - * makes a call into the runtime. - * - * - Tier?InvocationThreshold, Tier?CompileThreshold, Tier?BackEdgeThreshold, Tier?MinInvocationThreshold control - * compilation thresholds. - * Level 2 thresholds are not used and are provided for option-compatibility and potential future use. - * Other thresholds work as follows: - * - * Transition from interpreter (level 0) to C1 with full profiling (level 3) happens when - * the following predicate is true (X is the level): - * - * i > TierXInvocationThreshold * s || (i > TierXMinInvocationThreshold * s && i + b > TierXCompileThreshold * s), - * - * where $i$ is the number of method invocations, $b$ number of backedges and $s$ is the scaling - * coefficient that will be discussed further. - * The intuition is to equalize the time that is spend profiling each method. - * The same predicate is used to control the transition from level 3 to level 4 (C2). It should be - * noted though that the thresholds are relative. Moreover i and b for the 0->3 transition come - * from Method* and for 3->4 transition they come from MDO (since profiled invocations are - * counted separately). Finally, if a method does not contain anything worth profiling, a transition - * from level 3 to level 4 occurs without considering thresholds (e.g., with fewer invocations than - * what is specified by Tier4InvocationThreshold). - * - * OSR transitions are controlled simply with b > TierXBackEdgeThreshold * s predicates. - * - * - Tier?LoadFeedback options are used to automatically scale the predicates described above depending - * on the compiler load. The scaling coefficients are computed as follows: - * - * s = queue_size_X / (TierXLoadFeedback * compiler_count_X) + 1, - * - * where queue_size_X is the current size of the compiler queue of level X, and compiler_count_X - * is the number of level X compiler threads. - * - * Basically these parameters describe how many methods should be in the compile queue - * per compiler thread before the scaling coefficient increases by one. - * - * This feedback provides the mechanism to automatically control the flow of compilation requests - * depending on the machine speed, mutator load and other external factors. - * - * - Tier3DelayOn and Tier3DelayOff parameters control another important feedback loop. - * Consider the following observation: a method compiled with full profiling (level 3) - * is about 30% slower than a method at level 2 (just invocation and backedge counters, no MDO). - * Normally, the following transitions will occur: 0->3->4. The problem arises when the C2 queue - * gets congested and the 3->4 transition is delayed. While the method is the C2 queue it continues - * executing at level 3 for much longer time than is required by the predicate and at suboptimal speed. - * The idea is to dynamically change the behavior of the system in such a way that if a substantial - * load on C2 is detected we would first do the 0->2 transition allowing a method to run faster. - * And then when the load decreases to allow 2->3 transitions. - * - * Tier3Delay* parameters control this switching mechanism. - * Tier3DelayOn is the number of methods in the C2 queue per compiler thread after which the policy - * no longer does 0->3 transitions but does 0->2 transitions instead. - * Tier3DelayOff switches the original behavior back when the number of methods in the C2 queue - * per compiler thread falls below the specified amount. - * The hysteresis is necessary to avoid jitter. - * - * - TieredCompileTaskTimeout is the amount of time an idle method can spend in the compile queue. - * Basically, since we use the event rate d(i + b)/dt as a value of priority when selecting a method to - * compile from the compile queue, we also can detect stale methods for which the rate has been - * 0 for some time in the same iteration. Stale methods can appear in the queue when an application - * abruptly changes its behavior. - * - * - TieredStopAtLevel, is used mostly for testing. It allows to bypass the policy logic and stick - * to a given level. For example it's useful to set TieredStopAtLevel = 1 in order to compile everything - * with pure c1. - * - * - Tier0ProfilingStartPercentage allows the interpreter to start profiling when the inequalities in the - * 0->3 predicate are already exceeded by the given percentage but the level 3 version of the - * method is still not ready. We can even go directly from level 0 to 4 if c1 doesn't produce a compiled - * version in time. This reduces the overall transition to level 4 and decreases the startup time. - * Note that this behavior is also guarded by the Tier3Delay mechanism: when the c2 queue is too long - * these is not reason to start profiling prematurely. - * - * - TieredRateUpdateMinTime and TieredRateUpdateMaxTime are parameters of the rate computation. - * Basically, the rate is not computed more frequently than TieredRateUpdateMinTime and is considered - * to be zero if no events occurred in TieredRateUpdateMaxTime. - */ - -class TieredThresholdPolicy : public CompilationPolicy { - jlong _start_time; - int _c1_count, _c2_count; - - // Check if the counter is big enough and set carry (effectively infinity). - inline void set_carry_if_necessary(InvocationCounter *counter); - // Set carry flags in the counters (in Method* and MDO). - inline void handle_counter_overflow(Method* method); - // Call and loop predicates determine whether a transition to a higher compilation - // level should be performed (pointers to predicate functions are passed to common_TF(). - // Predicates also take compiler load into account. - typedef bool (TieredThresholdPolicy::*Predicate)(int i, int b, CompLevel cur_level, Method* method); - bool call_predicate(int i, int b, CompLevel cur_level, Method* method); - bool loop_predicate(int i, int b, CompLevel cur_level, Method* method); - // Common transition function. Given a predicate determines if a method should transition to another level. - CompLevel common(Predicate p, Method* method, CompLevel cur_level, bool disable_feedback = false); - // Transition functions. - // call_event determines if a method should be compiled at a different - // level with a regular invocation entry. - CompLevel call_event(Method* method, CompLevel cur_level, JavaThread* thread); - // loop_event checks if a method should be OSR compiled at a different - // level. - CompLevel loop_event(Method* method, CompLevel cur_level, JavaThread* thread); - void print_counters(const char* prefix, const methodHandle& mh); - // Has a method been long around? - // We don't remove old methods from the compile queue even if they have - // very low activity (see select_task()). - inline bool is_old(Method* method); - // Was a given method inactive for a given number of milliseconds. - // If it is, we would remove it from the queue (see select_task()). - inline bool is_stale(jlong t, jlong timeout, Method* m); - // Compute the weight of the method for the compilation scheduling - inline double weight(Method* method); - // Apply heuristics and return true if x should be compiled before y - inline bool compare_methods(Method* x, Method* y); - // Compute event rate for a given method. The rate is the number of event (invocations + backedges) - // per millisecond. - inline void update_rate(jlong t, Method* m); - // Compute threshold scaling coefficient - inline double threshold_scale(CompLevel level, int feedback_k); - // If a method is old enough and is still in the interpreter we would want to - // start profiling without waiting for the compiled method to arrive. This function - // determines whether we should do that. - inline bool should_create_mdo(Method* method, CompLevel cur_level); - // Create MDO if necessary. - void create_mdo(const methodHandle& mh, JavaThread* thread); - // Is method profiled enough? - bool is_method_profiled(Method* method); - - double _increase_threshold_at_ratio; - - bool maybe_switch_to_aot(const methodHandle& mh, CompLevel cur_level, CompLevel next_level, JavaThread* thread); - - int c1_count() const { return _c1_count; } - int c2_count() const { return _c2_count; } - void set_c1_count(int x) { _c1_count = x; } - void set_c2_count(int x) { _c2_count = x; } - - enum EventType { CALL, LOOP, COMPILE, REMOVE_FROM_QUEUE, UPDATE_IN_QUEUE, REPROFILE, MAKE_NOT_ENTRANT }; - void print_event(EventType type, const methodHandle& mh, const methodHandle& imh, int bci, CompLevel level); - // Print policy-specific information if necessary - void print_specific(EventType type, const methodHandle& mh, const methodHandle& imh, int bci, CompLevel level); - // Check if the method can be compiled, change level if necessary - void compile(const methodHandle& mh, int bci, CompLevel level, JavaThread* thread); - // Submit a given method for compilation - void submit_compile(const methodHandle& mh, int bci, CompLevel level, JavaThread* thread); - // Simple methods are as good being compiled with C1 as C2. - // This function tells if it's such a function. - inline static bool is_trivial(Method* method); - // Force method to be compiled at CompLevel_simple? - inline static bool should_compile_at_level_simple(Method* method); - - // Predicate helpers are used by .*_predicate() methods as well as others. - // They check the given counter values, multiplied by the scale against the thresholds. - template static inline bool call_predicate_helper(int i, int b, double scale, Method* method); - template static inline bool loop_predicate_helper(int i, int b, double scale, Method* method); - - // Get a compilation level for a given method. - static CompLevel comp_level(Method* method); - void method_invocation_event(const methodHandle& method, const methodHandle& inlinee, - CompLevel level, CompiledMethod* nm, JavaThread* thread); - void method_back_branch_event(const methodHandle& method, const methodHandle& inlinee, - int bci, CompLevel level, CompiledMethod* nm, JavaThread* thread); - - void set_increase_threshold_at_ratio() { _increase_threshold_at_ratio = 100 / (100 - (double)IncreaseFirstTierCompileThresholdAt); } - void set_start_time(jlong t) { _start_time = t; } - jlong start_time() const { return _start_time; } - -public: - TieredThresholdPolicy() : _start_time(0), _c1_count(0), _c2_count(0) { } - virtual int compiler_count(CompLevel comp_level) { - if (is_c1_compile(comp_level)) return c1_count(); - if (is_c2_compile(comp_level)) return c2_count(); - return 0; - } - virtual CompLevel initial_compile_level() { return MIN2((CompLevel)TieredStopAtLevel, CompLevel_initial_compile); } - virtual void do_safepoint_work() { } - virtual void delay_compilation(Method* method) { } - virtual void disable_compilation(Method* method) { } - virtual void reprofile(ScopeDesc* trap_scope, bool is_osr); - virtual nmethod* event(const methodHandle& method, const methodHandle& inlinee, - int branch_bci, int bci, CompLevel comp_level, CompiledMethod* nm, JavaThread* thread); - // Select task is called by CompileBroker. We should return a task or NULL. - virtual CompileTask* select_task(CompileQueue* compile_queue); - // Tell the runtime if we think a given method is adequately profiled. - virtual bool is_mature(Method* method); - // Initialize: set compiler thread count - virtual void initialize(); - virtual bool should_not_inline(ciEnv* env, ciMethod* callee); -}; - -#endif // TIERED - -#endif // SHARE_RUNTIME_TIEREDTHRESHOLDPOLICY_HPP diff -r 496bbf554c5c -r 38176d1c5ec2 src/hotspot/share/utilities/decoder.cpp --- a/src/hotspot/share/utilities/decoder.cpp Wed Oct 16 01:16:12 2019 +0200 +++ b/src/hotspot/share/utilities/decoder.cpp Wed Oct 16 11:23:46 2019 +0200 @@ -84,7 +84,7 @@ } bool Decoder::decode(address addr, char* buf, int buflen, int* offset, const char* modulepath, bool demangle) { - bool error_handling_thread = os::current_thread_id() == VMError::first_error_tid; + bool error_handling_thread = os::current_thread_id() == VMError::get_first_error_tid(); if (error_handling_thread) { return get_error_handler_instance()->decode(addr, buf, buflen, offset, modulepath, demangle); } else { @@ -95,7 +95,7 @@ } bool Decoder::decode(address addr, char* buf, int buflen, int* offset, const void* base) { - bool error_handling_thread = os::current_thread_id() == VMError::first_error_tid; + bool error_handling_thread = os::current_thread_id() == VMError::get_first_error_tid(); if (error_handling_thread) { return get_error_handler_instance()->decode(addr, buf, buflen, offset, base); } else { @@ -106,7 +106,7 @@ bool Decoder::demangle(const char* symbol, char* buf, int buflen) { - bool error_handling_thread = os::current_thread_id() == VMError::first_error_tid; + bool error_handling_thread = os::current_thread_id() == VMError::get_first_error_tid(); if (error_handling_thread) { return get_error_handler_instance()->demangle(symbol, buf, buflen); } else { diff -r 496bbf554c5c -r 38176d1c5ec2 src/hotspot/share/utilities/vmError.cpp --- a/src/hotspot/share/utilities/vmError.cpp Wed Oct 16 01:16:12 2019 +0200 +++ b/src/hotspot/share/utilities/vmError.cpp Wed Oct 16 11:23:46 2019 +0200 @@ -1205,7 +1205,7 @@ st->print_cr("END."); } -volatile intptr_t VMError::first_error_tid = -1; +volatile intptr_t VMError::_first_error_tid = -1; /** Expand a pattern into a buffer starting at pos and open a file using constructed path */ static int expand_and_open(const char* pattern, bool overwrite_existing, char* buf, size_t buflen, size_t pos) { @@ -1355,8 +1355,8 @@ os::abort(CreateCoredumpOnCrash); } intptr_t mytid = os::current_thread_id(); - if (first_error_tid == -1 && - Atomic::cmpxchg(mytid, &first_error_tid, (intptr_t)-1) == -1) { + if (_first_error_tid == -1 && + Atomic::cmpxchg(mytid, &_first_error_tid, (intptr_t)-1) == -1) { // Initialize time stamps to use the same base. out.time_stamp().update_to(1); @@ -1416,7 +1416,7 @@ // This is not the first error, see if it happened in a different thread // or in the same thread during error reporting. - if (first_error_tid != mytid) { + if (_first_error_tid != mytid) { char msgbuf[64]; jio_snprintf(msgbuf, sizeof(msgbuf), "[thread " INTX_FORMAT " also had an error]", diff -r 496bbf554c5c -r 38176d1c5ec2 src/hotspot/share/utilities/vmError.hpp --- a/src/hotspot/share/utilities/vmError.hpp Wed Oct 16 01:16:12 2019 +0200 +++ b/src/hotspot/share/utilities/vmError.hpp Wed Oct 16 11:23:46 2019 +0200 @@ -32,8 +32,6 @@ class VM_ReportJavaOutOfMemory; class VMError : public AllStatic { - friend class VM_ReportJavaOutOfMemory; - friend class Decoder; friend class VMStructs; static int _id; // Solaris/Linux signals: 0 - SIGRTMAX @@ -65,7 +63,7 @@ // Thread id of the first error. We must be able to handle native thread, // so use thread id instead of Thread* to identify thread. - static volatile intptr_t first_error_tid; + static volatile intptr_t _first_error_tid; // Core dump status, false if we have been unable to write a core/minidump for some reason static bool coredump_status; @@ -177,9 +175,9 @@ static address get_resetted_sighandler(int sig); // check to see if fatal error reporting is in progress - static bool fatal_error_in_progress() { return first_error_tid != -1; } + static bool fatal_error_in_progress() { return _first_error_tid != -1; } - static intptr_t get_first_error_tid() { return first_error_tid; } + static intptr_t get_first_error_tid() { return _first_error_tid; } // Called by the WatcherThread to check if error reporting has timed-out. // Returns true if error reporting has not completed within the ErrorLogTimeout limit. diff -r 496bbf554c5c -r 38176d1c5ec2 src/java.base/share/classes/java/io/FilePermission.java --- a/src/java.base/share/classes/java/io/FilePermission.java Wed Oct 16 01:16:12 2019 +0200 +++ b/src/java.base/share/classes/java/io/FilePermission.java Wed Oct 16 11:23:46 2019 +0200 @@ -367,12 +367,22 @@ this.mask = mask; if (cpath.equals("<>")) { + allFiles = true; directory = true; recursive = true; cpath = ""; return; } + // Validate path by platform's default file system + try { + String name = cpath.endsWith("*") ? cpath.substring(0, cpath.length() - 1) + "-" : cpath; + builtInFS.getPath(new File(name).getPath()); + } catch (InvalidPathException ipe) { + invalid = true; + return; + } + // store only the canonical cpath if possible cpath = AccessController.doPrivileged(new PrivilegedAction<>() { public String run() { @@ -463,6 +473,9 @@ *

* The default value of the {@code jdk.io.permissionsUseCanonicalPath} * system property is {@code false} in this implementation. + *

+ * The value can also be set with a security property using the same name, + * but setting a system property will override the security property value. * * @param path the pathname of the file/directory. * @param actions the action string. @@ -573,19 +586,19 @@ * @return the effective mask */ boolean impliesIgnoreMask(FilePermission that) { + if (this == that) { + return true; + } + if (allFiles) { + return true; + } + if (this.invalid || that.invalid) { + return false; + } + if (that.allFiles) { + return false; + } if (FilePermCompat.nb) { - if (this == that) { - return true; - } - if (allFiles) { - return true; - } - if (this.invalid || that.invalid) { - return false; - } - if (that.allFiles) { - return false; - } // Left at least same level of wildness as right if ((this.recursive && that.recursive) != that.recursive || (this.directory && that.directory) != that.directory) { @@ -783,10 +796,10 @@ FilePermission that = (FilePermission) obj; + if (this.invalid || that.invalid) { + return false; + } if (FilePermCompat.nb) { - if (this.invalid || that.invalid) { - return false; - } return (this.mask == that.mask) && (this.allFiles == that.allFiles) && this.npath.equals(that.npath) && @@ -795,6 +808,7 @@ (this.recursive == that.recursive); } else { return (this.mask == that.mask) && + (this.allFiles == that.allFiles) && this.cpath.equals(that.cpath) && (this.directory == that.directory) && (this.recursive == that.recursive); diff -r 496bbf554c5c -r 38176d1c5ec2 src/java.base/share/classes/java/lang/ClassLoader.java --- a/src/java.base/share/classes/java/lang/ClassLoader.java Wed Oct 16 01:16:12 2019 +0200 +++ b/src/java.base/share/classes/java/lang/ClassLoader.java Wed Oct 16 11:23:46 2019 +0200 @@ -1,5 +1,6 @@ /* * Copyright (c) 2013, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, Azul Systems, Inc. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -2004,6 +2005,17 @@ return scl; } + /* + * Initialize default paths for native libraries search. + * Must be done early as JDK may load libraries during bootstrap. + * + * @see java.lang.System#initPhase1 + */ + static void initLibraryPaths() { + usr_paths = initializePath("java.library.path"); + sys_paths = initializePath("sun.boot.library.path"); + } + // Returns true if the specified class loader can be found in this class // loader's delegation chain. boolean isAncestor(ClassLoader cl) { @@ -2473,8 +2485,7 @@ * * We use a static stack to hold the list of libraries we are * loading because this can happen only when called by the - * same thread because Runtime.load and Runtime.loadLibrary - * are synchronous. + * same thread because this block is synchronous. * * If there is a pending load operation for the library, we * immediately return success; otherwise, we raise @@ -2619,10 +2630,9 @@ boolean isAbsolute) { ClassLoader loader = (fromClass == null) ? null : fromClass.getClassLoader(); - if (sys_paths == null) { - usr_paths = initializePath("java.library.path"); - sys_paths = initializePath("sun.boot.library.path"); - } + assert sys_paths != null : "should be initialized at this point"; + assert usr_paths != null : "should be initialized at this point"; + if (isAbsolute) { if (loadLibrary0(fromClass, new File(name))) { return; diff -r 496bbf554c5c -r 38176d1c5ec2 src/java.base/share/classes/java/lang/Runtime.java --- a/src/java.base/share/classes/java/lang/Runtime.java Wed Oct 16 01:16:12 2019 +0200 +++ b/src/java.base/share/classes/java/lang/Runtime.java Wed Oct 16 11:23:46 2019 +0200 @@ -1,5 +1,6 @@ /* * Copyright (c) 1995, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, Azul Systems, Inc. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -732,7 +733,7 @@ load0(Reflection.getCallerClass(), filename); } - synchronized void load0(Class fromClass, String filename) { + void load0(Class fromClass, String filename) { SecurityManager security = System.getSecurityManager(); if (security != null) { security.checkLink(filename); @@ -794,14 +795,14 @@ loadLibrary0(Reflection.getCallerClass(), libname); } - synchronized void loadLibrary0(Class fromClass, String libname) { + void loadLibrary0(Class fromClass, String libname) { SecurityManager security = System.getSecurityManager(); if (security != null) { security.checkLink(libname); } if (libname.indexOf((int)File.separatorChar) != -1) { throw new UnsatisfiedLinkError( - "Directory separator should not appear in library name: " + libname); + "Directory separator should not appear in library name: " + libname); } ClassLoader.loadLibrary(fromClass, libname, false); } diff -r 496bbf554c5c -r 38176d1c5ec2 src/java.base/share/classes/java/lang/StringCoding.java --- a/src/java.base/share/classes/java/lang/StringCoding.java Wed Oct 16 01:16:12 2019 +0200 +++ b/src/java.base/share/classes/java/lang/StringCoding.java Wed Oct 16 11:23:46 2019 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2019, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -191,6 +191,12 @@ return result.with(StringLatin1.inflate(ba, off, len), UTF16); } } + // fastpath for always Latin1 decodable single byte + if (COMPACT_STRINGS && cd instanceof ArrayDecoder && ((ArrayDecoder)cd).isLatin1Decodable()) { + byte[] dst = new byte[len]; + ((ArrayDecoder)cd).decodeToLatin1(ba, off, len, dst); + return result.with(dst, LATIN1); + } int en = scale(len, cd.maxCharsPerByte()); char[] ca = new char[en]; if (cd instanceof ArrayDecoder) { @@ -278,6 +284,13 @@ ((ArrayDecoder)cd).isASCIICompatible() && !hasNegatives(ba, off, len)) { return decodeLatin1(ba, off, len); } + // fastpath for always Latin1 decodable single byte + if (COMPACT_STRINGS && cd instanceof ArrayDecoder && ((ArrayDecoder)cd).isLatin1Decodable()) { + byte[] dst = new byte[len]; + ((ArrayDecoder)cd).decodeToLatin1(ba, off, len, dst); + return new Result().with(dst, LATIN1); + } + int en = scale(len, cd.maxCharsPerByte()); if (len == 0) { return new Result().with(); diff -r 496bbf554c5c -r 38176d1c5ec2 src/java.base/share/classes/java/lang/System.java --- a/src/java.base/share/classes/java/lang/System.java Wed Oct 16 01:16:12 2019 +0200 +++ b/src/java.base/share/classes/java/lang/System.java Wed Oct 16 11:23:46 2019 +0200 @@ -2045,6 +2045,8 @@ // register shared secrets setJavaLangAccess(); + ClassLoader.initLibraryPaths(); + // Subsystems that are invoked during initialization can invoke // VM.isBooted() in order to avoid doing things that should // wait until the VM is fully initialized. The initialization level diff -r 496bbf554c5c -r 38176d1c5ec2 src/java.base/share/classes/java/net/NetPermission.java --- a/src/java.base/share/classes/java/net/NetPermission.java Wed Oct 16 01:16:12 2019 +0200 +++ b/src/java.base/share/classes/java/net/NetPermission.java Wed Oct 16 11:23:46 2019 +0200 @@ -145,6 +145,15 @@ * * * + * setSocketImpl + * The ability to create a sub-class of Socket or ServerSocket with a + * user specified SocketImpl. + * Malicious user-defined SocketImpls can change the behavior of + * Socket and ServerSocket in surprising ways, by virtue of their + * ability to access the protected fields of SocketImpl. + * + * + * * specifyStreamHandler * The ability * to specify a stream handler when constructing a URL diff -r 496bbf554c5c -r 38176d1c5ec2 src/java.base/share/classes/java/net/ServerSocket.java --- a/src/java.base/share/classes/java/net/ServerSocket.java Wed Oct 16 01:16:12 2019 +0200 +++ b/src/java.base/share/classes/java/net/ServerSocket.java Wed Oct 16 11:23:46 2019 +0200 @@ -32,6 +32,7 @@ import java.util.Set; import java.util.Collections; +import sun.security.util.SecurityConstants; import sun.net.PlatformSocketImpl; /** @@ -73,13 +74,25 @@ * * @throws NullPointerException if impl is {@code null}. * + * @throws SecurityException if a security manager is set and + * its {@code checkPermission} method doesn't allow + * {@code NetPermission("setSocketImpl")}. * @since 12 */ protected ServerSocket(SocketImpl impl) { Objects.requireNonNull(impl); + checkPermission(); this.impl = impl; } + private static Void checkPermission() { + SecurityManager sm = System.getSecurityManager(); + if (sm != null) { + sm.checkPermission(SecurityConstants.SET_SOCKETIMPL_PERMISSION); + } + return null; + } + /** * Creates an unbound server socket. * diff -r 496bbf554c5c -r 38176d1c5ec2 src/java.base/share/classes/java/net/Socket.java --- a/src/java.base/share/classes/java/net/Socket.java Wed Oct 16 01:16:12 2019 +0200 +++ b/src/java.base/share/classes/java/net/Socket.java Wed Oct 16 11:23:46 2019 +0200 @@ -25,6 +25,8 @@ package java.net; +import sun.security.util.SecurityConstants; + import java.io.InputStream; import java.io.OutputStream; import java.io.IOException; @@ -182,12 +184,28 @@ * * @throws SocketException if there is an error in the underlying protocol, * such as a TCP error. + * + * @throws SecurityException if {@code impl} is non-null and a security manager is set + * and its {@code checkPermission} method doesn't allow {@code NetPermission("setSocketImpl")}. + * * @since 1.1 */ protected Socket(SocketImpl impl) throws SocketException { + checkPermission(impl); this.impl = impl; } + private static Void checkPermission(SocketImpl impl) { + if (impl == null) { + return null; + } + SecurityManager sm = System.getSecurityManager(); + if (sm != null) { + sm.checkPermission(SecurityConstants.SET_SOCKETIMPL_PERMISSION); + } + return null; + } + /** * Creates a stream socket and connects it to the specified port * number on the named host. diff -r 496bbf554c5c -r 38176d1c5ec2 src/java.base/share/classes/java/net/URL.java --- a/src/java.base/share/classes/java/net/URL.java Wed Oct 16 01:16:12 2019 +0200 +++ b/src/java.base/share/classes/java/net/URL.java Wed Oct 16 11:23:46 2019 +0200 @@ -484,6 +484,16 @@ throw new MalformedURLException(s); } } + if ("jar".equalsIgnoreCase(protocol)) { + if (handler instanceof sun.net.www.protocol.jar.Handler) { + // URL.openConnection() would throw a confusing exception + // so generate a better exception here instead. + String s = ((sun.net.www.protocol.jar.Handler) handler).checkNestedProtocol(file); + if (s != null) { + throw new MalformedURLException(s); + } + } + } } /** diff -r 496bbf554c5c -r 38176d1c5ec2 src/java.base/share/classes/java/text/DecimalFormat.java --- a/src/java.base/share/classes/java/text/DecimalFormat.java Wed Oct 16 01:16:12 2019 +0200 +++ b/src/java.base/share/classes/java/text/DecimalFormat.java Wed Oct 16 11:23:46 2019 +0200 @@ -2756,7 +2756,10 @@ /** * Return the grouping size. Grouping size is the number of digits between * grouping separators in the integer portion of a number. For example, - * in the number "123,456.78", the grouping size is 3. + * in the number "123,456.78", the grouping size is 3. Grouping size of + * zero designates that grouping is not used, which provides the same + * formatting as if calling {@link #setGroupingUsed(boolean) + * setGroupingUsed(false)}. * * @return the grouping size * @see #setGroupingSize @@ -2770,16 +2773,28 @@ /** * Set the grouping size. Grouping size is the number of digits between * grouping separators in the integer portion of a number. For example, - * in the number "123,456.78", the grouping size is 3. - *
+ * in the number "123,456.78", the grouping size is 3. Grouping size of + * zero designates that grouping is not used, which provides the same + * formatting as if calling {@link #setGroupingUsed(boolean) + * setGroupingUsed(false)}. + *

* The value passed in is converted to a byte, which may lose information. + * Values that are negative or greater than + * {@link java.lang.Byte#MAX_VALUE Byte.MAX_VALUE}, will throw an + * {@code IllegalArgumentException}. * * @param newValue the new grouping size * @see #getGroupingSize * @see java.text.NumberFormat#setGroupingUsed * @see java.text.DecimalFormatSymbols#setGroupingSeparator + * @throws IllegalArgumentException if {@code newValue} is negative or + * greater than {@link java.lang.Byte#MAX_VALUE Byte.MAX_VALUE} */ public void setGroupingSize (int newValue) { + if (newValue < 0 || newValue > Byte.MAX_VALUE) { + throw new IllegalArgumentException( + "newValue is out of valid range. value: " + newValue); + } groupingSize = (byte)newValue; fastPathCheckNeeded = true; } @@ -3906,6 +3921,12 @@ // Didn't have exponential fields useExponentialNotation = false; } + + // Restore the invariant value if groupingSize is invalid. + if (groupingSize < 0) { + groupingSize = 3; + } + serialVersionOnStream = currentSerialVersion; } @@ -4009,14 +4030,15 @@ /** * The number of digits between grouping separators in the integer - * portion of a number. Must be greater than 0 if + * portion of a number. Must be non-negative and less than or equal to + * {@link java.lang.Byte#MAX_VALUE Byte.MAX_VALUE} if * {@code NumberFormat.groupingUsed} is true. * * @serial * @see #getGroupingSize * @see java.text.NumberFormat#isGroupingUsed */ - private byte groupingSize = 3; // invariant, > 0 if useThousands + private byte groupingSize = 3; // invariant, 0 - 127, if groupingUsed /** * If true, forces the decimal separator to always appear in a formatted diff -r 496bbf554c5c -r 38176d1c5ec2 src/java.base/share/classes/java/util/regex/Pattern.java --- a/src/java.base/share/classes/java/util/regex/Pattern.java Wed Oct 16 01:16:12 2019 +0200 +++ b/src/java.base/share/classes/java/util/regex/Pattern.java Wed Oct 16 11:23:46 2019 +0200 @@ -1427,7 +1427,11 @@ localTCNCount = 0; if (!pattern.isEmpty()) { - compile(); + try { + compile(); + } catch (StackOverflowError soe) { + throw error("Stack overflow during pattern compilation"); + } } else { root = new Start(lastAccept); matchRoot = lastAccept; @@ -1965,6 +1969,10 @@ int ch = temp[cursor++]; while (ch != 0 && !isLineSeparator(ch)) ch = temp[cursor++]; + if (ch == 0 && cursor > patternLength) { + cursor = patternLength; + ch = temp[cursor++]; + } return ch; } @@ -1975,6 +1983,10 @@ int ch = temp[++cursor]; while (ch != 0 && !isLineSeparator(ch)) ch = temp[++cursor]; + if (ch == 0 && cursor > patternLength) { + cursor = patternLength; + ch = temp[cursor]; + } return ch; } @@ -3415,9 +3427,10 @@ private int N() { if (read() == '{') { int i = cursor; - while (cursor < patternLength && read() != '}') {} - if (cursor > patternLength) - throw error("Unclosed character name escape sequence"); + while (read() != '}') { + if (cursor >= patternLength) + throw error("Unclosed character name escape sequence"); + } String name = new String(temp, i, cursor - i - 1); try { return Character.codePointOf(name); diff -r 496bbf554c5c -r 38176d1c5ec2 src/java.base/share/classes/sun/net/www/protocol/http/HttpURLConnection.java --- a/src/java.base/share/classes/sun/net/www/protocol/http/HttpURLConnection.java Wed Oct 16 01:16:12 2019 +0200 +++ b/src/java.base/share/classes/sun/net/www/protocol/http/HttpURLConnection.java Wed Oct 16 11:23:46 2019 +0200 @@ -2171,6 +2171,10 @@ } while (retryTunnel < maxRedirects); if (retryTunnel >= maxRedirects || (respCode != HTTP_OK)) { + if (respCode != HTTP_PROXY_AUTH) { + // remove all but authenticate responses + responses.reset(); + } throw new IOException("Unable to tunnel through proxy."+ " Proxy returns \"" + statusLine + "\""); diff -r 496bbf554c5c -r 38176d1c5ec2 src/java.base/share/classes/sun/net/www/protocol/jar/Handler.java --- a/src/java.base/share/classes/sun/net/www/protocol/jar/Handler.java Wed Oct 16 01:16:12 2019 +0200 +++ b/src/java.base/share/classes/sun/net/www/protocol/jar/Handler.java Wed Oct 16 11:23:46 2019 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2011, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2019, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -121,6 +121,13 @@ return h; } + public String checkNestedProtocol(String spec) { + if (spec.regionMatches(true, 0, "jar:", 0, 4)) { + return "Nested JAR URLs are not supported"; + } else { + return null; + } + } @Override @SuppressWarnings("deprecation") @@ -146,6 +153,12 @@ : false; spec = spec.substring(start, limit); + String exceptionMessage = checkNestedProtocol(spec); + if (exceptionMessage != null) { + // NPE will be transformed into MalformedURLException by the caller + throw new NullPointerException(exceptionMessage); + } + if (absoluteSpec) { file = parseAbsoluteSpec(spec); } else if (!refOnly) { diff -r 496bbf554c5c -r 38176d1c5ec2 src/java.base/share/classes/sun/nio/ch/ServerSocketAdaptor.java --- a/src/java.base/share/classes/sun/nio/ch/ServerSocketAdaptor.java Wed Oct 16 01:16:12 2019 +0200 +++ b/src/java.base/share/classes/sun/nio/ch/ServerSocketAdaptor.java Wed Oct 16 11:23:46 2019 +0200 @@ -37,6 +37,9 @@ import java.nio.channels.IllegalBlockingModeException; import java.nio.channels.ServerSocketChannel; import java.nio.channels.SocketChannel; +import java.security.AccessController; +import java.security.PrivilegedActionException; +import java.security.PrivilegedExceptionAction; import java.util.Set; import static java.util.concurrent.TimeUnit.MILLISECONDS; @@ -59,7 +62,12 @@ private volatile int timeout; static ServerSocket create(ServerSocketChannelImpl ssc) { - return new ServerSocketAdaptor(ssc); + PrivilegedExceptionAction pa = () -> new ServerSocketAdaptor(ssc); + try { + return AccessController.doPrivileged(pa); + } catch (PrivilegedActionException pae) { + throw new InternalError("Should not reach here", pae); + } } private ServerSocketAdaptor(ServerSocketChannelImpl ssc) { diff -r 496bbf554c5c -r 38176d1c5ec2 src/java.base/share/classes/sun/nio/ch/SocketAdaptor.java --- a/src/java.base/share/classes/sun/nio/ch/SocketAdaptor.java Wed Oct 16 01:16:12 2019 +0200 +++ b/src/java.base/share/classes/sun/nio/ch/SocketAdaptor.java Wed Oct 16 11:23:46 2019 +0200 @@ -36,6 +36,9 @@ import java.net.SocketOption; import java.net.StandardSocketOptions; import java.nio.channels.SocketChannel; +import java.security.AccessController; +import java.security.PrivilegedActionException; +import java.security.PrivilegedExceptionAction; import java.util.Set; import static java.util.concurrent.TimeUnit.MILLISECONDS; @@ -61,10 +64,11 @@ } static Socket create(SocketChannelImpl sc) { + PrivilegedExceptionAction pa = () -> new SocketAdaptor(sc); try { - return new SocketAdaptor(sc); - } catch (SocketException e) { - throw new InternalError("Should not reach here"); + return AccessController.doPrivileged(pa); + } catch (PrivilegedActionException pae) { + throw new InternalError("Should not reach here", pae); } } diff -r 496bbf554c5c -r 38176d1c5ec2 src/java.base/share/classes/sun/nio/cs/ArrayDecoder.java --- a/src/java.base/share/classes/sun/nio/cs/ArrayDecoder.java Wed Oct 16 01:16:12 2019 +0200 +++ b/src/java.base/share/classes/sun/nio/cs/ArrayDecoder.java Wed Oct 16 11:23:46 2019 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2009, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2009, 2019, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -28,6 +28,9 @@ /* * FastPath byte[]->char[] decoder, REPLACE on malformed or * unmappable input. + * + * FastPath encoded byte[]-> "String Latin1 coding" byte[] decoder for use when + * charset is always decodable to the internal String Latin1 coding byte[], ie. all mappings <=0xff */ public interface ArrayDecoder { @@ -36,4 +39,14 @@ default boolean isASCIICompatible() { return false; } + + // Is always decodable to internal String Latin1 coding, ie. all mappings <= 0xff + default boolean isLatin1Decodable() { + return false; + } + + // Decode to internal String Latin1 coding byte[] fastpath for when isLatin1Decodable == true + default int decodeToLatin1(byte[] src, int sp, int len, byte[] dst) { + return 0; + } } diff -r 496bbf554c5c -r 38176d1c5ec2 src/java.base/share/classes/sun/nio/cs/SingleByte.java --- a/src/java.base/share/classes/sun/nio/cs/SingleByte.java Wed Oct 16 01:16:12 2019 +0200 +++ b/src/java.base/share/classes/sun/nio/cs/SingleByte.java Wed Oct 16 11:23:46 2019 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2008, 2019, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -50,17 +50,27 @@ implements ArrayDecoder { private final char[] b2c; private final boolean isASCIICompatible; + private final boolean isLatin1Decodable; public Decoder(Charset cs, char[] b2c) { super(cs, 1.0f, 1.0f); this.b2c = b2c; this.isASCIICompatible = false; + this.isLatin1Decodable = false; } public Decoder(Charset cs, char[] b2c, boolean isASCIICompatible) { super(cs, 1.0f, 1.0f); this.b2c = b2c; this.isASCIICompatible = isASCIICompatible; + this.isLatin1Decodable = false; + } + + public Decoder(Charset cs, char[] b2c, boolean isASCIICompatible, boolean isLatin1Decodable) { + super(cs, 1.0f, 1.0f); + this.b2c = b2c; + this.isASCIICompatible = isASCIICompatible; + this.isLatin1Decodable = isLatin1Decodable; } private CoderResult decodeArrayLoop(ByteBuffer src, CharBuffer dst) { @@ -125,6 +135,18 @@ } @Override + public int decodeToLatin1(byte[] src, int sp, int len, byte[] dst) { + if (len > dst.length) + len = dst.length; + + int dp = 0; + while (dp < len) { + dst[dp++] = (byte)decode(src[sp++]); + } + return dp; + } + + @Override public int decode(byte[] src, int sp, int len, char[] dst) { if (len > dst.length) len = dst.length; @@ -143,6 +165,11 @@ public boolean isASCIICompatible() { return isASCIICompatible; } + + @Override + public boolean isLatin1Decodable() { + return isLatin1Decodable; + } } public static final class Encoder extends CharsetEncoder diff -r 496bbf554c5c -r 38176d1c5ec2 src/java.base/share/classes/sun/security/ssl/SupportedGroupsExtension.java --- a/src/java.base/share/classes/sun/security/ssl/SupportedGroupsExtension.java Wed Oct 16 01:16:12 2019 +0200 +++ b/src/java.base/share/classes/sun/security/ssl/SupportedGroupsExtension.java Wed Oct 16 11:23:46 2019 +0200 @@ -201,7 +201,7 @@ // Primary XDH (RFC 7748) curves NamedGroup.X25519, - // Primary NIST curves (e.g. used in TLSv1.3) + // Primary NIST Suite B curves NamedGroup.SECP256_R1, NamedGroup.SECP384_R1, NamedGroup.SECP521_R1, @@ -209,17 +209,6 @@ // Secondary XDH curves NamedGroup.X448, - // Secondary NIST curves - NamedGroup.SECT283_K1, - NamedGroup.SECT283_R1, - NamedGroup.SECT409_K1, - NamedGroup.SECT409_R1, - NamedGroup.SECT571_K1, - NamedGroup.SECT571_R1, - - // non-NIST curves - NamedGroup.SECP256_K1, - // FFDHE (RFC 7919) NamedGroup.FFDHE_2048, NamedGroup.FFDHE_3072, diff -r 496bbf554c5c -r 38176d1c5ec2 src/java.base/share/classes/sun/security/util/FilePermCompat.java --- a/src/java.base/share/classes/sun/security/util/FilePermCompat.java Wed Oct 16 01:16:12 2019 +0200 +++ b/src/java.base/share/classes/sun/security/util/FilePermCompat.java Wed Oct 16 11:23:46 2019 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2019, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -42,8 +42,11 @@ public static final boolean compat; static { - String flag = GetPropertyAction.privilegedGetProperty( - "jdk.io.permissionsUseCanonicalPath", "false"); + String flag = SecurityProperties.privilegedGetOverridable( + "jdk.io.permissionsUseCanonicalPath"); + if (flag == null) { + flag = "false"; + } switch (flag) { case "true": nb = false; diff -r 496bbf554c5c -r 38176d1c5ec2 src/java.base/share/classes/sun/security/util/SecurityConstants.java --- a/src/java.base/share/classes/sun/security/util/SecurityConstants.java Wed Oct 16 01:16:12 2019 +0200 +++ b/src/java.base/share/classes/sun/security/util/SecurityConstants.java Wed Oct 16 11:23:46 2019 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2019, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -97,6 +97,10 @@ public static final NetPermission GET_RESPONSECACHE_PERMISSION = new NetPermission("getResponseCache"); + // java.net.ServerSocket, java.net.Socket + public static final NetPermission SET_SOCKETIMPL_PERMISSION = + new NetPermission("setSocketImpl"); + // java.lang.SecurityManager, sun.applet.AppletPanel public static final RuntimePermission CREATE_CLASSLOADER_PERMISSION = new RuntimePermission("createClassLoader"); diff -r 496bbf554c5c -r 38176d1c5ec2 src/java.base/share/conf/security/java.security --- a/src/java.base/share/conf/security/java.security Wed Oct 16 01:16:12 2019 +0200 +++ b/src/java.base/share/conf/security/java.security Wed Oct 16 11:23:46 2019 +0200 @@ -1213,3 +1213,51 @@ # if this property is not enabled. # jdk.security.caDistrustPolicies=SYMANTEC_TLS + +# +# FilePermission path canonicalization +# +# This security property dictates how the path argument is processed and stored +# while constructing a FilePermission object. If the value is set to true, the +# path argument is canonicalized and FilePermission methods (such as implies, +# equals, and hashCode) are implemented based on this canonicalized result. +# Otherwise, the path argument is not canonicalized and FilePermission methods are +# implemented based on the original input. See the implementation note of the +# FilePermission class for more details. +# +# If a system property of the same name is also specified, it supersedes the +# security property value defined here. +# +# The default value for this property is false. +# +jdk.io.permissionsUseCanonicalPath=false + + +# +# Policies for the proxy_impersonator Kerberos ccache configuration entry +# +# The proxy_impersonator ccache configuration entry indicates that the ccache +# is a synthetic delegated credential for use with S4U2Proxy by an intermediate +# server. The ccache file should also contain the TGT of this server and +# an evidence ticket from the default principal of the ccache to this server. +# +# This security property determines how Java uses this configuration entry. +# There are 3 possible values: +# +# no-impersonate - Ignore this configuration entry, and always act as +# the owner of the TGT (if it exists). +# +# try-impersonate - Try impersonation when this configuration entry exists. +# If no matching TGT or evidence ticket is found, +# fallback to no-impersonate. +# +# always-impersonate - Always impersonate when this configuration entry exists. +# If no matching TGT or evidence ticket is found, +# no initial credential is read from the ccache. +# +# The default value is "always-impersonate". +# +# If a system property of the same name is also specified, it supersedes the +# security property value defined here. +# +#jdk.security.krb5.default.initiate.credential=always-impersonate diff -r 496bbf554c5c -r 38176d1c5ec2 src/java.base/unix/native/libnio/ch/Net.c --- a/src/java.base/unix/native/libnio/ch/Net.c Wed Oct 16 01:16:12 2019 +0200 +++ b/src/java.base/unix/native/libnio/ch/Net.c Wed Oct 16 11:23:46 2019 +0200 @@ -66,34 +66,6 @@ #endif #endif -#if defined(_AIX) - #ifndef IP_BLOCK_SOURCE - #define IP_BLOCK_SOURCE 58 /* Block data from a given source to a given group */ - #define IP_UNBLOCK_SOURCE 59 /* Unblock data from a given source to a given group */ - #define IP_ADD_SOURCE_MEMBERSHIP 60 /* Join a source-specific group */ - #define IP_DROP_SOURCE_MEMBERSHIP 61 /* Leave a source-specific group */ - #endif - - #ifndef MCAST_BLOCK_SOURCE - #define MCAST_BLOCK_SOURCE 64 - #define MCAST_UNBLOCK_SOURCE 65 - #define MCAST_JOIN_SOURCE_GROUP 66 - #define MCAST_LEAVE_SOURCE_GROUP 67 - - /* This means we're on AIX 5.3 and 'group_source_req' and 'ip_mreq_source' aren't defined as well */ - struct group_source_req { - uint32_t gsr_interface; - struct sockaddr_storage gsr_group; - struct sockaddr_storage gsr_source; - }; - struct ip_mreq_source { - struct in_addr imr_multiaddr; /* IP multicast address of group */ - struct in_addr imr_sourceaddr; /* IP address of source */ - struct in_addr imr_interface; /* local IP address of interface */ - }; - #endif -#endif /* _AIX */ - #define COPY_INET6_ADDRESS(env, source, target) \ (*env)->GetByteArrayRegion(env, source, 0, 16, target) diff -r 496bbf554c5c -r 38176d1c5ec2 src/java.base/windows/classes/java/lang/ProcessImpl.java --- a/src/java.base/windows/classes/java/lang/ProcessImpl.java Wed Oct 16 01:16:12 2019 +0200 +++ b/src/java.base/windows/classes/java/lang/ProcessImpl.java Wed Oct 16 11:23:46 2019 +0200 @@ -38,6 +38,7 @@ import java.security.AccessController; import java.security.PrivilegedAction; import java.util.ArrayList; +import java.util.Locale; import java.util.concurrent.CompletableFuture; import java.util.concurrent.TimeUnit; import java.util.regex.Matcher; @@ -46,6 +47,8 @@ import jdk.internal.access.JavaIOFileDescriptorAccess; import jdk.internal.access.SharedSecrets; import jdk.internal.ref.CleanerFactory; +import sun.security.action.GetBooleanAction; +import sun.security.action.GetPropertyAction; /* This class is for the exclusive use of ProcessBuilder.start() to * create new processes. @@ -209,12 +212,15 @@ private static final int VERIFICATION_CMD_BAT = 0; private static final int VERIFICATION_WIN32 = 1; - private static final int VERIFICATION_LEGACY = 2; + private static final int VERIFICATION_WIN32_SAFE = 2; // inside quotes not allowed + private static final int VERIFICATION_LEGACY = 3; + // See Command shell overview for documentation of special characters. + // https://docs.microsoft.com/en-us/previous-versions/windows/it-pro/windows-xp/bb490954(v=technet.10) private static final char ESCAPE_VERIFICATION[][] = { // We guarantee the only command file execution for implicit [cmd.exe] run. // http://technet.microsoft.com/en-us/library/bb490954.aspx {' ', '\t', '<', '>', '&', '|', '^'}, - + {' ', '\t', '<', '>'}, {' ', '\t', '<', '>'}, {' ', '\t'} }; @@ -231,8 +237,25 @@ cmdbuf.append(' '); String s = cmd[i]; if (needsEscaping(verificationType, s)) { - cmdbuf.append('"').append(s); + cmdbuf.append('"'); + if (verificationType == VERIFICATION_WIN32_SAFE) { + // Insert the argument, adding '\' to quote any interior quotes + int length = s.length(); + for (int j = 0; j < length; j++) { + char c = s.charAt(j); + if (c == DOUBLEQUOTE) { + int count = countLeadingBackslash(verificationType, s, j); + while (count-- > 0) { + cmdbuf.append(BACKSLASH); // double the number of backslashes + } + cmdbuf.append(BACKSLASH); // backslash to quote the quote + } + cmdbuf.append(c); + } + } else { + cmdbuf.append(s); + } // The code protects the [java.exe] and console command line // parser, that interprets the [\"] combination as an escape // sequence for the ["] char. @@ -245,8 +268,9 @@ // command line parser. The case of the [""] tail escape // sequence could not be realized due to the argument validation // procedure. - if ((verificationType != VERIFICATION_CMD_BAT) && s.endsWith("\\")) { - cmdbuf.append('\\'); + int count = countLeadingBackslash(verificationType, s, s.length()); + while (count-- > 0) { + cmdbuf.append(BACKSLASH); // double the number of backslashes } cmdbuf.append('"'); } else { @@ -256,26 +280,16 @@ return cmdbuf.toString(); } - private static boolean isQuoted(boolean noQuotesInside, String arg, - String errorMessage) { - int lastPos = arg.length() - 1; - if (lastPos >=1 && arg.charAt(0) == '"' && arg.charAt(lastPos) == '"') { - // The argument has already been quoted. - if (noQuotesInside) { - if (arg.indexOf('"', 1) != lastPos) { - // There is ["] inside. - throw new IllegalArgumentException(errorMessage); - } - } - return true; - } - if (noQuotesInside) { - if (arg.indexOf('"') >= 0) { - // There is ["] inside. - throw new IllegalArgumentException(errorMessage); - } - } - return false; + /** + * Return the argument without quotes (1st and last) if present, else the arg. + * @param str a string + * @return the string without 1st and last quotes + */ + private static String unQuote(String str) { + int len = str.length(); + return (len >= 2 && str.charAt(0) == DOUBLEQUOTE && str.charAt(len - 1) == DOUBLEQUOTE) + ? str.substring(1, len - 1) + : str; } private static boolean needsEscaping(int verificationType, String arg) { @@ -286,9 +300,26 @@ // For [.exe] or [.com] file the unpaired/internal ["] // in the argument is not a problem. - boolean argIsQuoted = isQuoted( - (verificationType == VERIFICATION_CMD_BAT), - arg, "Argument has embedded quote, use the explicit CMD.EXE call."); + String unquotedArg = unQuote(arg); + boolean argIsQuoted = !arg.equals(unquotedArg); + boolean embeddedQuote = unquotedArg.indexOf(DOUBLEQUOTE) >= 0; + + switch (verificationType) { + case VERIFICATION_CMD_BAT: + if (embeddedQuote) { + throw new IllegalArgumentException("Argument has embedded quote, " + + "use the explicit CMD.EXE call."); + } + break; // break determine whether to quote + case VERIFICATION_WIN32_SAFE: + if (argIsQuoted && embeddedQuote) { + throw new IllegalArgumentException("Malformed argument has embedded quote: " + + unquotedArg); + } + break; + default: + break; + } if (!argIsQuoted) { char testEscape[] = ESCAPE_VERIFICATION[verificationType]; @@ -304,13 +335,13 @@ private static String getExecutablePath(String path) throws IOException { - boolean pathIsQuoted = isQuoted(true, path, - "Executable name has embedded quote, split the arguments"); - + String name = unQuote(path); + if (name.indexOf(DOUBLEQUOTE) >= 0) { + throw new IllegalArgumentException("Executable name has embedded quote, " + + "split the arguments: " + name); + } // Win32 CreateProcess requires path to be normalized - File fileToRun = new File(pathIsQuoted - ? path.substring(1, path.length() - 1) - : path); + File fileToRun = new File(name); // From the [CreateProcess] function documentation: // @@ -325,13 +356,26 @@ // sequence:..." // // In practice ANY non-existent path is extended by [.exe] extension - // in the [CreateProcess] funcion with the only exception: + // in the [CreateProcess] function with the only exception: // the path ends by (.) return fileToRun.getPath(); } + /** + * An executable is any program that is an EXE or does not have an extension + * and the Windows createProcess will be looking for .exe. + * The comparison is case insensitive based on the name. + * @param executablePath the executable file + * @return true if the path ends in .exe or does not have an extension. + */ + private boolean isExe(String executablePath) { + File file = new File(executablePath); + String upName = file.getName().toUpperCase(Locale.ROOT); + return (upName.endsWith(".EXE") || upName.indexOf('.') < 0); + } + // Old version that can be bypassed private boolean isShellFile(String executablePath) { String upPath = executablePath.toUpperCase(); return (upPath.endsWith(".CMD") || upPath.endsWith(".BAT")); @@ -342,6 +386,21 @@ return argbuf.append('"').append(arg).append('"').toString(); } + // Count backslashes before start index of string. + // .bat files don't include backslashes as part of the quote + private static int countLeadingBackslash(int verificationType, + CharSequence input, int start) { + if (verificationType == VERIFICATION_CMD_BAT) + return 0; + int j; + for (j = start - 1; j >= 0 && input.charAt(j) == BACKSLASH; j--) { + // just scanning backwards + } + return (start - 1) - j; // number of BACKSLASHES + } + + private static final char DOUBLEQUOTE = '\"'; + private static final char BACKSLASH = '\\'; private final long handle; private final ProcessHandle processHandle; @@ -358,15 +417,13 @@ throws IOException { String cmdstr; - SecurityManager security = System.getSecurityManager(); - boolean allowAmbiguousCommands = false; - if (security == null) { - allowAmbiguousCommands = true; - String value = System.getProperty("jdk.lang.Process.allowAmbiguousCommands"); - if (value != null) - allowAmbiguousCommands = !"false".equalsIgnoreCase(value); - } - if (allowAmbiguousCommands) { + final SecurityManager security = System.getSecurityManager(); + final String value = GetPropertyAction. + privilegedGetProperty("jdk.lang.Process.allowAmbiguousCommands", + (security == null ? "true" : "false")); + final boolean allowAmbiguousCommands = !"false".equalsIgnoreCase(value); + + if (allowAmbiguousCommands && security == null) { // Legacy mode. // Normalize path if possible. @@ -413,11 +470,12 @@ // Quotation protects from interpretation of the [path] argument as // start of longer path with spaces. Quotation has no influence to // [.exe] extension heuristic. + boolean isShell = allowAmbiguousCommands ? isShellFile(executablePath) + : !isExe(executablePath); cmdstr = createCommandLine( - // We need the extended verification procedure for CMD files. - isShellFile(executablePath) - ? VERIFICATION_CMD_BAT - : VERIFICATION_WIN32, + // We need the extended verification procedures + isShell ? VERIFICATION_CMD_BAT + : (allowAmbiguousCommands ? VERIFICATION_WIN32 : VERIFICATION_WIN32_SAFE), quoteString(executablePath), cmd); } diff -r 496bbf554c5c -r 38176d1c5ec2 src/java.datatransfer/share/classes/java/awt/datatransfer/MimeType.java --- a/src/java.datatransfer/share/classes/java/awt/datatransfer/MimeType.java Wed Oct 16 01:16:12 2019 +0200 +++ b/src/java.datatransfer/share/classes/java/awt/datatransfer/MimeType.java Wed Oct 16 11:23:46 2019 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2019, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -346,9 +346,9 @@ return newObj; } - private String primaryType; - private String subType; - private MimeTypeParameterList parameters; + private transient String primaryType; + private transient String subType; + private transient MimeTypeParameterList parameters; // below here be scary parsing related things diff -r 496bbf554c5c -r 38176d1c5ec2 src/java.desktop/macosx/classes/sun/awt/CGraphicsDevice.java --- a/src/java.desktop/macosx/classes/sun/awt/CGraphicsDevice.java Wed Oct 16 01:16:12 2019 +0200 +++ b/src/java.desktop/macosx/classes/sun/awt/CGraphicsDevice.java Wed Oct 16 11:23:46 2019 +0200 @@ -61,6 +61,10 @@ public CGraphicsDevice(final int displayID) { this.displayID = displayID; config = CGLGraphicsConfig.getConfig(this, displayID, 0); + // initializes default device state, might be redundant step since we + // call "displayChanged()" later anyway, but we do not want to leave the + // device in an inconsistent state after construction + displayChanged(); } /** diff -r 496bbf554c5c -r 38176d1c5ec2 src/java.desktop/macosx/classes/sun/java2d/opengl/CGLSurfaceData.java --- a/src/java.desktop/macosx/classes/sun/java2d/opengl/CGLSurfaceData.java Wed Oct 16 01:16:12 2019 +0200 +++ b/src/java.desktop/macosx/classes/sun/java2d/opengl/CGLSurfaceData.java Wed Oct 16 11:23:46 2019 +0200 @@ -25,7 +25,6 @@ package sun.java2d.opengl; -import java.awt.Graphics; import java.awt.GraphicsConfiguration; import java.awt.GraphicsDevice; import java.awt.GraphicsEnvironment; @@ -33,9 +32,7 @@ import java.awt.Rectangle; import java.awt.image.ColorModel; -import sun.java2d.SunGraphics2D; import sun.java2d.SurfaceData; - import sun.lwawt.macosx.CPlatformView; public abstract class CGLSurfaceData extends OGLSurfaceData { @@ -342,43 +339,4 @@ return offscreenImage; } } - - // Mac OS X specific APIs for JOGL/Java2D bridge... - - // given a surface create and attach GL context, then return it - private static native long createCGLContextOnSurface(CGLSurfaceData sd, - long sharedContext); - - public static long createOGLContextOnSurface(Graphics g, long sharedContext) { - SurfaceData sd = ((SunGraphics2D) g).surfaceData; - if ((sd instanceof CGLSurfaceData) == true) { - CGLSurfaceData cglsd = (CGLSurfaceData) sd; - return createCGLContextOnSurface(cglsd, sharedContext); - } else { - return 0L; - } - } - - // returns whether or not the makeCurrent operation succeeded - static native boolean makeCGLContextCurrentOnSurface(CGLSurfaceData sd, - long ctx); - - public static boolean makeOGLContextCurrentOnSurface(Graphics g, long ctx) { - SurfaceData sd = ((SunGraphics2D) g).surfaceData; - if ((ctx != 0L) && ((sd instanceof CGLSurfaceData) == true)) { - CGLSurfaceData cglsd = (CGLSurfaceData) sd; - return makeCGLContextCurrentOnSurface(cglsd, ctx); - } else { - return false; - } - } - - // additional cleanup - private static native void destroyCGLContext(long ctx); - - public static void destroyOGLContext(long ctx) { - if (ctx != 0L) { - destroyCGLContext(ctx); - } - } } diff -r 496bbf554c5c -r 38176d1c5ec2 src/java.desktop/macosx/classes/sun/lwawt/macosx/LWCToolkit.java --- a/src/java.desktop/macosx/classes/sun/lwawt/macosx/LWCToolkit.java Wed Oct 16 01:16:12 2019 +0200 +++ b/src/java.desktop/macosx/classes/sun/lwawt/macosx/LWCToolkit.java Wed Oct 16 11:23:46 2019 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 2019, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -444,6 +444,7 @@ fontHints.put(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_LCD_HRGB); desktopProperties.put(SunToolkit.DESKTOPFONTHINTS, fontHints); desktopProperties.put("awt.mouse.numButtons", BUTTONS); + desktopProperties.put("awt.multiClickInterval", getMultiClickTime()); // These DnD properties must be set, otherwise Swing ends up spewing NPEs // all over the place. The values came straight off of MToolkit. @@ -538,6 +539,11 @@ return BUTTONS; } + /** + * Returns the double-click time interval in ms. + */ + private static native int getMultiClickTime(); + @Override public boolean isTraySupported() { return true; diff -r 496bbf554c5c -r 38176d1c5ec2 src/java.desktop/macosx/native/libawt_lwawt/awt/LWCToolkit.m --- a/src/java.desktop/macosx/native/libawt_lwawt/awt/LWCToolkit.m Wed Oct 16 01:16:12 2019 +0200 +++ b/src/java.desktop/macosx/native/libawt_lwawt/awt/LWCToolkit.m Wed Oct 16 11:23:46 2019 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 2019, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -831,3 +831,19 @@ } return JNI_FALSE; } + +/* + * Class: sun_lwawt_macosx_LWCToolkit + * Method: getMultiClickTime + * Signature: ()I + */ +JNIEXPORT jint JNICALL +Java_sun_lwawt_macosx_LWCToolkit_getMultiClickTime(JNIEnv *env, jclass klass) { + __block jint multiClickTime = 0; + JNF_COCOA_ENTER(env); + [JNFRunLoop performOnMainThreadWaiting:YES withBlock:^(){ + multiClickTime = (jint)([NSEvent doubleClickInterval] * 1000); + }]; + JNF_COCOA_EXIT(env); + return multiClickTime; +} diff -r 496bbf554c5c -r 38176d1c5ec2 src/java.desktop/macosx/native/libawt_lwawt/java2d/opengl/CGLGraphicsConfig.m --- a/src/java.desktop/macosx/native/libawt_lwawt/java2d/opengl/CGLGraphicsConfig.m Wed Oct 16 01:16:12 2019 +0200 +++ b/src/java.desktop/macosx/native/libawt_lwawt/java2d/opengl/CGLGraphicsConfig.m Wed Oct 16 11:23:46 2019 +0200 @@ -152,7 +152,6 @@ AWT_ASSERT_APPKIT_THREAD; jint displayID = (jint)[(NSNumber *)[argValue objectAtIndex: 0] intValue]; - jint pixfmt = (jint)[(NSNumber *)[argValue objectAtIndex: 1] intValue]; jint swapInterval = (jint)[(NSNumber *)[argValue objectAtIndex: 2] intValue]; JNIEnv *env = [ThreadUtilities getJNIEnvUncached]; [argValue removeAllObjects]; @@ -161,11 +160,7 @@ NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; - CGOpenGLDisplayMask glMask = (CGOpenGLDisplayMask)pixfmt; if (sharedContext == NULL) { - if (glMask == 0) { - glMask = CGDisplayIDToOpenGLDisplayMask(displayID); - } NSOpenGLPixelFormatAttribute attrs[] = { NSOpenGLPFAAllowOfflineRenderers, @@ -176,16 +171,17 @@ NSOpenGLPFAColorSize, 32, NSOpenGLPFAAlphaSize, 8, NSOpenGLPFADepthSize, 16, - NSOpenGLPFAScreenMask, glMask, 0 }; sharedPixelFormat = [[NSOpenGLPixelFormat alloc] initWithAttributes:attrs]; if (sharedPixelFormat == nil) { - J2dRlsTraceLn(J2D_TRACE_ERROR, "CGLGraphicsConfig_getCGLConfigInfo: shared NSOpenGLPixelFormat is NULL"); - [argValue addObject: [NSNumber numberWithLong: 0L]]; - return; + J2dRlsTraceLn(J2D_TRACE_ERROR, + "CGLGraphicsConfig_getCGLConfigInfo: shared NSOpenGLPixelFormat is NULL"); + + [argValue addObject: [NSNumber numberWithLong: 0L]]; + return; } sharedContext = diff -r 496bbf554c5c -r 38176d1c5ec2 src/java.desktop/share/classes/java/awt/Font.java --- a/src/java.desktop/share/classes/java/awt/Font.java Wed Oct 16 01:16:12 2019 +0200 +++ b/src/java.desktop/share/classes/java/awt/Font.java Wed Oct 16 11:23:46 2019 +0200 @@ -1929,6 +1929,7 @@ // value is the default. if (fRequestedAttributes != null) { + try { values = getAttributeValues(); // init AttributeValues extras = AttributeValues.fromSerializableHashtable(fRequestedAttributes); @@ -1938,10 +1939,13 @@ values = getAttributeValues().merge(extras); this.nonIdentityTx = values.anyNonDefault(EXTRA_MASK); this.hasLayoutAttributes = values.anyNonDefault(LAYOUT_MASK); - + } catch (Throwable t) { + throw new IOException(t); + } finally { fRequestedAttributes = null; // don't need it any more } } + } /** * Returns the number of glyphs in this {@code Font}. Glyph codes diff -r 496bbf554c5c -r 38176d1c5ec2 src/java.desktop/share/classes/java/awt/doc-files/AWTThreadIssues.html --- a/src/java.desktop/share/classes/java/awt/doc-files/AWTThreadIssues.html Wed Oct 16 01:16:12 2019 +0200 +++ b/src/java.desktop/share/classes/java/awt/doc-files/AWTThreadIssues.html Wed Oct 16 11:23:46 2019 +0200 @@ -5,7 +5,7 @@ AWT Threading Issues