Mercurial > hg > aarch64-jdk8u51-b16-hotspot
changeset 8068:4f902e26d7e3
Merge up to jdk8u40-b23
line wrap: on
line diff
--- a/.hgtags Thu Jan 08 12:47:32 2015 +0000 +++ b/.hgtags Tue Feb 03 16:48:05 2015 +0000 @@ -509,6 +509,8 @@ 00cf2b6f51b9560b01030e8f4c28c466f0b21fe3 hs25.20-b23 19408d5fd31c25ce60c43dd33e92b96e8df4a4ea jdk8u20-b25 eaa4074a7e3975cd33ec55e6b584586e2ac681bd jdk8u20-b26 +7c9925f21c2529a88eb64b8039cc080f60b85e01 jdk8u20-b31 +7edb04063a423e278fe34a0006d25fee198f495e jdk8u20-b32 4828415ebbf11e205dcc08e97ad5ae7dd03522f9 jdk8u40-b00 d952af8cf67dd1e7ab5fec9a299c6c6dafd1863e hs25.40-b01 f0afba33c928ddaa2d5f003b90d683c143f78ea3 hs25.40-b02 @@ -552,6 +554,21 @@ 6467bdd4d22d8b140844dc847c43b9ba7cb0bbd1 jdk8u25-b16 28b50d07f6f8c5a567b6a25e95a423948114a004 jdk8u25-b17 639abc668bfe995dba811dd35411b9ea8a9041cd jdk8u25-b18 +c3528699fb33fe3eb1d117504184ae7ab2507aa1 jdk8u25-b31 +5bb683bbe2c74876d585b5c3232fc3aab7b23e97 jdk8u31-b00 +5bb686ae3b89f8aa1c74331b2d24e2a5ebd43448 jdk8u31-b01 +087678da96603c9705b38b6cc4a6569ac7b4420a jdk8u31-b02 +401cbaa475b4efe53153119ab87a82b217980a7f jdk8u31-b03 +060cdf93040c1bfa5fdf580da5e9999042632cc8 jdk8u31-b04 +6e56d7f1634f6c4cd4196e699c06e6ca2e6d6efb jdk8u31-b05 +271a32147391d08b0f338d9353330e2b5584d580 jdk8u31-b06 +e9f815c3f21cf2febd8e3c185917c1519aa52d9a jdk8u31-b07 +cc74ca22516644867be3b8db6c1f8d05ab4f6c27 jdk8u31-b08 +245d29ed5db5ad6914eb0c9fe78b9ba26122c478 jdk8u31-b09 +d7b6bdd51abe68b16411d5b292fb830a43c5bc09 jdk8u31-b10 +9906d432d6dbd2cda242e3f3cfde7cf6c90245bf jdk8u31-b11 +e13839545238d1ecf17f0489bb6fb765de46719a jdk8u31-b12 +4206e725d584be942c25ff46ff23d8e299ca4a4c jdk8u31-b13 1b3abbeee961dee49780c0e4af5337feb918c555 jdk8u40-b10 f10fe402dfb1543723b4b117a7cba3ea3d4159f1 hs25.40-b15 99372b2fee0eb8b3452f47230e84aa6e97003184 jdk8u40-b11 @@ -559,3 +576,20 @@ b280f4f4f11916e202aaa4d458630d4c26b59e2a jdk8u40-b12-aarch64 26fc60dd5da8d3f1554fb8f2553f050839a539c6 jdk8u40-b12-aarch64-1262 d7c03eb8b2c2bc4d34438699f07609ba4c4bca5c jdk8u40-b12-aarch64-1263 +4d5dc0d0f8799fafa1135d51d85edd4edd566501 hs25.40-b18 +b8ca8ec1daea70f7c0d519e866f9f147ec247055 jdk8u40-b14 +eb16b24e2eba9bdf04a9b377bebc2db9f713ff5e jdk8u40-b15 +3a8a0fd171c5876023112941b1c7254262f9adfc hs25.40-b19 +aa2442f89230dc46147c721812f3b3bd4c612e83 hs25.40-b20 +5ea68fb91139081304357f9b937f32c5fdfeca6d jdk8u40-b16 +6bf89bfe8185747a57193efb6cec1f17ccc80414 hs25.40-b21 +fc1f9b67fd8c5d5cd94ecc03569d93e7ce7fb574 jdk8u40-b17 +bc5a90a4db47f1c497d7894434c42325f595cd02 hs25.40-b22 +31d3306aad29e39929418ed43f28212a5f5306a3 jdk8u40-b18 +f8fc5cbe082ce0fb0c6c1dcd39493a16ed916353 hs25.40-b23 +d9349fa8822336e0244da0a8448f3e6b2d62741d jdk8u40-b19 +c3933f52eeb33f70ee562464edddfe9f01d944fd jdk8u40-b20 +d2e9a6bec4f2eec8506eed16f7324992a85d8480 hs25.40-b24 +25ec4a67433744bbe3406e5069e7fd1876ebbf2f jdk8u40-b21 +0f0cb4eeab2d871274f4ffdcd6017d2fdfa89238 hs25.40-b25 +0ee548a1cda08c884eccd563e2d5fdb6ee769b5a jdk8u40-b22
--- a/THIRD_PARTY_README Thu Jan 08 12:47:32 2015 +0000 +++ b/THIRD_PARTY_README Tue Feb 03 16:48:05 2015 +0000 @@ -3385,7 +3385,7 @@ included with JRE 8, JDK 8, and OpenJDK 8. Apache Commons Math 3.2 - Apache Derby 10.10.1.3 + Apache Derby 10.11.1.2 Apache Jakarta BCEL 5.1 Apache Jakarta Regexp 1.4 Apache Santuario XML Security for Java 1.5.4
--- a/make/aix/makefiles/adjust-mflags.sh Thu Jan 08 12:47:32 2015 +0000 +++ b/make/aix/makefiles/adjust-mflags.sh Tue Feb 03 16:48:05 2015 +0000 @@ -1,6 +1,6 @@ #! /bin/sh # -# Copyright (c) 1999, 2013, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 1999, 2014, Oracle and/or its affiliates. All rights reserved. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. # # This code is free software; you can redistribute it and/or modify it @@ -64,7 +64,7 @@ echo "$MFLAGS" \ | sed ' s/^-/ -/ - s/ -\([^ ][^ ]*\)j/ -\1 -j/ + s/ -\([^ I][^ I]*\)j/ -\1 -j/ s/ -j[0-9][0-9]*/ -j/ s/ -j\([^ ]\)/ -j -\1/ s/ -j/ -j'${HOTSPOT_BUILD_JOBS:-${default_build_jobs}}'/
--- a/make/bsd/makefiles/adjust-mflags.sh Thu Jan 08 12:47:32 2015 +0000 +++ b/make/bsd/makefiles/adjust-mflags.sh Tue Feb 03 16:48:05 2015 +0000 @@ -64,7 +64,7 @@ echo "$MFLAGS" \ | sed ' s/^-/ -/ - s/ -\([^ ][^ ]*\)j/ -\1 -j/ + s/ -\([^ I][^ I]*\)j/ -\1 -j/ s/ -j[0-9][0-9]*/ -j/ s/ -j\([^ ]\)/ -j -\1/ s/ -j/ -j'${HOTSPOT_BUILD_JOBS:-${default_build_jobs}}'/
--- a/make/bsd/makefiles/mapfile-vers-debug Thu Jan 08 12:47:32 2015 +0000 +++ b/make/bsd/makefiles/mapfile-vers-debug Tue Feb 03 16:48:05 2015 +0000 @@ -187,6 +187,9 @@ _JVM_IsSupportedJNIVersion _JVM_IsThreadAlive _JVM_IsVMGeneratedMethodIx + _JVM_KnownToNotExist + _JVM_GetResourceLookupCacheURLs + _JVM_GetResourceLookupCache _JVM_LatestUserDefinedLoader _JVM_Listen _JVM_LoadClass0
--- a/make/bsd/makefiles/mapfile-vers-product Thu Jan 08 12:47:32 2015 +0000 +++ b/make/bsd/makefiles/mapfile-vers-product Tue Feb 03 16:48:05 2015 +0000 @@ -187,6 +187,9 @@ _JVM_IsSupportedJNIVersion _JVM_IsThreadAlive _JVM_IsVMGeneratedMethodIx + _JVM_KnownToNotExist + _JVM_GetResourceLookupCacheURLs + _JVM_GetResourceLookupCache _JVM_LatestUserDefinedLoader _JVM_Listen _JVM_LoadClass0
--- a/make/hotspot_version Thu Jan 08 12:47:32 2015 +0000 +++ b/make/hotspot_version Tue Feb 03 16:48:05 2015 +0000 @@ -1,5 +1,5 @@ # -# Copyright (c) 2006, 2014, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2006, 2015, Oracle and/or its affiliates. All rights reserved. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. # # This code is free software; you can redistribute it and/or modify it @@ -31,11 +31,11 @@ # # Don't put quotes (fail windows build). -HOTSPOT_VM_COPYRIGHT=Copyright 2014 +HOTSPOT_VM_COPYRIGHT=Copyright 2015 HS_MAJOR_VER=25 HS_MINOR_VER=40 -HS_BUILD_NUMBER=16 +HS_BUILD_NUMBER=25 JDK_MAJOR_VER=1 JDK_MINOR_VER=8
--- a/make/jprt.properties Thu Jan 08 12:47:32 2015 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,407 +0,0 @@ -# -# Copyright (c) 2006, 2013, Oracle and/or its affiliates. All rights reserved. -# 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. -# -# - -# Properties for jprt - -# All build result bundles are full jdks. -jprt.need.sibling.build=false - -# At submit time, the release supplied will be in jprt.submit.release -# and will be one of the official release names defined in jprt. -# jprt supports property value expansion using ${property.name} syntax. - -# This tells jprt what default release we want to build - -jprt.hotspot.default.release=jdk8u40 - -jprt.tools.default.release=${jprt.submit.option.release?${jprt.submit.option.release}:${jprt.hotspot.default.release}} - -# Disable syncing the source after builds and tests are done. - -jprt.sync.push=false - -# Note: we want both embedded releases and regular releases to build and test -# all platforms so that regressions are not introduced (eg. change to -# common code by SE breaks PPC/ARM; change to common code by SE-E breaks -# sparc etc. - -# Define the Solaris platforms we want for the various releases -jprt.my.solaris.sparcv9.jdk8u40=solaris_sparcv9_5.10 -jprt.my.solaris.sparcv9.jdk7=solaris_sparcv9_5.10 -jprt.my.solaris.sparcv9.jdk7u8=${jprt.my.solaris.sparcv9.jdk7} -jprt.my.solaris.sparcv9=${jprt.my.solaris.sparcv9.${jprt.tools.default.release}} - -jprt.my.solaris.x64.jdk8u40=solaris_x64_5.10 -jprt.my.solaris.x64.jdk7=solaris_x64_5.10 -jprt.my.solaris.x64.jdk7u8=${jprt.my.solaris.x64.jdk7} -jprt.my.solaris.x64=${jprt.my.solaris.x64.${jprt.tools.default.release}} - -jprt.my.linux.i586.jdk8u40=linux_i586_2.6 -jprt.my.linux.i586.jdk7=linux_i586_2.6 -jprt.my.linux.i586.jdk7u8=${jprt.my.linux.i586.jdk7} -jprt.my.linux.i586=${jprt.my.linux.i586.${jprt.tools.default.release}} - -jprt.my.linux.x64.jdk8u40=linux_x64_2.6 -jprt.my.linux.x64.jdk7=linux_x64_2.6 -jprt.my.linux.x64.jdk7u8=${jprt.my.linux.x64.jdk7} -jprt.my.linux.x64=${jprt.my.linux.x64.${jprt.tools.default.release}} - -jprt.my.linux.ppc.jdk8u40=linux_ppc_2.6 -jprt.my.linux.ppc.jdk7=linux_ppc_2.6 -jprt.my.linux.ppc.jdk7u8=${jprt.my.linux.ppc.jdk7} -jprt.my.linux.ppc=${jprt.my.linux.ppc.${jprt.tools.default.release}} - -jprt.my.linux.ppcv2.jdk8u40=linux_ppcv2_2.6 -jprt.my.linux.ppcv2.jdk7=linux_ppcv2_2.6 -jprt.my.linux.ppcv2.jdk7u8=${jprt.my.linux.ppcv2.jdk7} -jprt.my.linux.ppcv2=${jprt.my.linux.ppcv2.${jprt.tools.default.release}} - -jprt.my.linux.armvfpsflt.jdk8u40=linux_armvfpsflt_2.6 -jprt.my.linux.armvfpsflt=${jprt.my.linux.armvfpsflt.${jprt.tools.default.release}} - -jprt.my.linux.armvfphflt.jdk8u40=linux_armvfphflt_2.6 -jprt.my.linux.armvfphflt=${jprt.my.linux.armvfphflt.${jprt.tools.default.release}} - -# The ARM GP vfp-sflt build is not currently supported -#jprt.my.linux.armvs.jdk8u40=linux_armvs_2.6 -#jprt.my.linux.armvs=${jprt.my.linux.armvs.${jprt.tools.default.release}} - -jprt.my.linux.armvh.jdk8u40=linux_armvh_2.6 -jprt.my.linux.armvh=${jprt.my.linux.armvh.${jprt.tools.default.release}} - -jprt.my.linux.armsflt.jdk8u40=linux_armsflt_2.6 -jprt.my.linux.armsflt.jdk7=linux_armsflt_2.6 -jprt.my.linux.armsflt.jdk7u8=${jprt.my.linux.armsflt.jdk7} -jprt.my.linux.armsflt=${jprt.my.linux.armsflt.${jprt.tools.default.release}} - -jprt.my.macosx.x64.jdk8u40=macosx_x64_10.7 -jprt.my.macosx.x64.jdk7=macosx_x64_10.7 -jprt.my.macosx.x64.jdk7u8=${jprt.my.macosx.x64.jdk7} -jprt.my.macosx.x64=${jprt.my.macosx.x64.${jprt.tools.default.release}} - -jprt.my.windows.i586.jdk8u40=windows_i586_6.1 -jprt.my.windows.i586.jdk7=windows_i586_6.1 -jprt.my.windows.i586.jdk7u8=${jprt.my.windows.i586.jdk7} -jprt.my.windows.i586=${jprt.my.windows.i586.${jprt.tools.default.release}} - -jprt.my.windows.x64.jdk8u40=windows_x64_6.1 -jprt.my.windows.x64.jdk7=windows_x64_6.1 -jprt.my.windows.x64.jdk7u8=${jprt.my.windows.x64.jdk7} -jprt.my.windows.x64=${jprt.my.windows.x64.${jprt.tools.default.release}} - -# Standard list of jprt build targets for this source tree - -jprt.build.targets.standard= \ - ${jprt.my.solaris.sparcv9}-{product|fastdebug}, \ - ${jprt.my.solaris.x64}-{product|fastdebug}, \ - ${jprt.my.linux.i586}-{product|fastdebug}, \ - ${jprt.my.linux.x64}-{product|fastdebug}, \ - ${jprt.my.macosx.x64}-{product|fastdebug}, \ - ${jprt.my.windows.i586}-{product|fastdebug}, \ - ${jprt.my.windows.x64}-{product|fastdebug}, \ - ${jprt.my.linux.armvh}-{product|fastdebug} - -jprt.build.targets.open= \ - ${jprt.my.solaris.x64}-{debugOpen}, \ - ${jprt.my.linux.x64}-{productOpen} - -jprt.build.targets.embedded= \ - ${jprt.my.linux.i586}-{productEmb|fastdebugEmb}, \ - ${jprt.my.linux.ppc}-{productEmb|fastdebugEmb}, \ - ${jprt.my.linux.ppcv2}-{productEmb|fastdebugEmb}, \ - ${jprt.my.linux.armvfpsflt}-{productEmb|fastdebugEmb}, \ - ${jprt.my.linux.armvfphflt}-{productEmb|fastdebugEmb}, \ - ${jprt.my.linux.armsflt}-{productEmb|fastdebugEmb} - -jprt.build.targets.all=${jprt.build.targets.standard}, \ - ${jprt.build.targets.embedded}, ${jprt.build.targets.open} - -jprt.build.targets.jdk8u40=${jprt.build.targets.all} -jprt.build.targets.jdk7=${jprt.build.targets.all} -jprt.build.targets.jdk7u8=${jprt.build.targets.all} -jprt.build.targets=${jprt.build.targets.${jprt.tools.default.release}} - -# Subset lists of test targets for this source tree - -jprt.my.solaris.sparcv9.test.targets= \ - ${jprt.my.solaris.sparcv9}-{product|fastdebug}-c2-jvm98, \ - ${jprt.my.solaris.sparcv9}-{product|fastdebug}-c2-jvm98_nontiered, \ - ${jprt.my.solaris.sparcv9}-{product|fastdebug}-c2-scimark, \ - ${jprt.my.solaris.sparcv9}-product-c2-runThese, \ - ${jprt.my.solaris.sparcv9}-{product|fastdebug}-c2-GCBasher_SerialGC, \ - ${jprt.my.solaris.sparcv9}-{product|fastdebug}-c2-GCBasher_ParallelGC, \ - ${jprt.my.solaris.sparcv9}-{product|fastdebug}-c2-GCBasher_ParNewGC, \ - ${jprt.my.solaris.sparcv9}-{product|fastdebug}-c2-GCBasher_CMS, \ - ${jprt.my.solaris.sparcv9}-{product|fastdebug}-c2-GCBasher_G1, \ - ${jprt.my.solaris.sparcv9}-{product|fastdebug}-c2-GCBasher_ParOldGC, \ - ${jprt.my.solaris.sparcv9}-{product|fastdebug}-c2-GCOld_SerialGC, \ - ${jprt.my.solaris.sparcv9}-{product|fastdebug}-c2-GCOld_ParallelGC, \ - ${jprt.my.solaris.sparcv9}-{product|fastdebug}-c2-GCOld_ParNewGC, \ - ${jprt.my.solaris.sparcv9}-{product|fastdebug}-c2-GCOld_CMS, \ - ${jprt.my.solaris.sparcv9}-{product|fastdebug}-c2-GCOld_G1, \ - ${jprt.my.solaris.sparcv9}-{product|fastdebug}-c2-GCOld_ParOldGC, \ - ${jprt.my.solaris.sparcv9}-{product|fastdebug}-c2-jbb_default_nontiered, \ - ${jprt.my.solaris.sparcv9}-{product|fastdebug}-c2-jbb_SerialGC, \ - ${jprt.my.solaris.sparcv9}-{product|fastdebug}-c2-jbb_ParallelGC, \ - ${jprt.my.solaris.sparcv9}-{product|fastdebug}-c2-jbb_CMS, \ - ${jprt.my.solaris.sparcv9}-{product|fastdebug}-c2-jbb_G1, \ - ${jprt.my.solaris.sparcv9}-{product|fastdebug}-c2-jbb_ParOldGC - -jprt.my.solaris.x64.test.targets= \ - ${jprt.my.solaris.x64}-{product|fastdebug}-c2-jvm98, \ - ${jprt.my.solaris.x64}-{product|fastdebug}-c2-jvm98_nontiered, \ - ${jprt.my.solaris.x64}-{product|fastdebug}-c2-scimark, \ - ${jprt.my.solaris.x64}-product-c2-runThese, \ - ${jprt.my.solaris.x64}-product-c2-runThese_Xcomp, \ - ${jprt.my.solaris.x64}-{product|fastdebug}-c2-GCBasher_SerialGC, \ - ${jprt.my.solaris.x64}-{product|fastdebug}-c2-GCBasher_ParallelGC, \ - ${jprt.my.solaris.x64}-{product|fastdebug}-c2-GCBasher_ParNewGC, \ - ${jprt.my.solaris.x64}-{product|fastdebug}-c2-GCBasher_CMS, \ - ${jprt.my.solaris.x64}-{product|fastdebug}-c2-GCBasher_G1, \ - ${jprt.my.solaris.x64}-{product|fastdebug}-c2-GCBasher_ParOldGC, \ - ${jprt.my.solaris.x64}-{product|fastdebug}-c2-GCOld_SerialGC, \ - ${jprt.my.solaris.x64}-{product|fastdebug}-c2-GCOld_ParallelGC, \ - ${jprt.my.solaris.x64}-{product|fastdebug}-c2-GCOld_ParNewGC, \ - ${jprt.my.solaris.x64}-{product|fastdebug}-c2-GCOld_CMS, \ - ${jprt.my.solaris.x64}-{product|fastdebug}-c2-GCOld_G1, \ - ${jprt.my.solaris.x64}-{product|fastdebug}-c2-GCOld_ParOldGC, \ - ${jprt.my.solaris.x64}-{product|fastdebug}-c2-jbb_default_nontiered, \ - ${jprt.my.solaris.x64}-{product|fastdebug}-c2-jbb_SerialGC, \ - ${jprt.my.solaris.x64}-{product|fastdebug}-c2-jbb_ParallelGC, \ - ${jprt.my.solaris.x64}-{product|fastdebug}-c2-GCOld_CMS, \ - ${jprt.my.solaris.x64}-{product|fastdebug}-c2-GCOld_G1, \ - ${jprt.my.solaris.x64}-{product|fastdebug}-c2-GCOld_ParOldGC - -jprt.my.linux.i586.test.targets = \ - ${jprt.my.linux.i586}-{product|fastdebug}-{c1|c2}-jvm98, \ - ${jprt.my.linux.i586}-{product|fastdebug}-c2-jvm98_nontiered, \ - ${jprt.my.linux.i586}-{product|fastdebug}-{c1|c2}-scimark, \ - ${jprt.my.linux.i586}-product-c1-runThese_Xcomp, \ - ${jprt.my.linux.i586}-fastdebug-c1-runThese_Xshare, \ - ${jprt.my.linux.i586}-fastdebug-c2-runThese_Xcomp, \ - ${jprt.my.linux.i586}-{product|fastdebug}-{c1|c2}-GCBasher_SerialGC, \ - ${jprt.my.linux.i586}-{product|fastdebug}-{c1|c2}-GCBasher_ParallelGC, \ - ${jprt.my.linux.i586}-{product|fastdebug}-{c1|c2}-GCBasher_ParNewGC, \ - ${jprt.my.linux.i586}-{product|fastdebug}-{c1|c2}-GCBasher_CMS, \ - ${jprt.my.linux.i586}-{product|fastdebug}-{c1|c2}-GCBasher_G1, \ - ${jprt.my.linux.i586}-{product|fastdebug}-{c1|c2}-GCBasher_ParOldGC, \ - ${jprt.my.linux.i586}-product-{c1|c2}-GCOld_SerialGC, \ - ${jprt.my.linux.i586}-product-{c1|c2}-GCOld_ParallelGC, \ - ${jprt.my.linux.i586}-product-{c1|c2}-GCOld_ParNewGC, \ - ${jprt.my.linux.i586}-product-{c1|c2}-GCOld_CMS, \ - ${jprt.my.linux.i586}-product-{c1|c2}-GCOld_G1, \ - ${jprt.my.linux.i586}-product-{c1|c2}-GCOld_ParOldGC, \ - ${jprt.my.linux.i586}-{product|fastdebug}-c1-jbb_SerialGC, \ - ${jprt.my.linux.i586}-{product|fastdebug}-c2-jbb_default_nontiered, \ - ${jprt.my.linux.i586}-{product|fastdebug}-c1-jbb_ParallelGC, \ - ${jprt.my.linux.i586}-{product|fastdebug}-c1-jbb_CMS, \ - ${jprt.my.linux.i586}-{product|fastdebug}-c1-jbb_G1, \ - ${jprt.my.linux.i586}-{product|fastdebug}-c1-jbb_ParOldGC - -jprt.my.linux.x64.test.targets = \ - ${jprt.my.linux.x64}-{product|fastdebug}-c2-jvm98, \ - ${jprt.my.linux.x64}-{product|fastdebug}-c2-jvm98_nontiered, \ - ${jprt.my.linux.x64}-{product|fastdebug}-c2-scimark, \ - ${jprt.my.linux.x64}-{product|fastdebug}-c2-GCBasher_SerialGC, \ - ${jprt.my.linux.x64}-{product|fastdebug}-c2-GCBasher_ParallelGC, \ - ${jprt.my.linux.x64}-{product|fastdebug}-c2-GCBasher_ParNewGC, \ - ${jprt.my.linux.x64}-{product|fastdebug}-c2-GCBasher_CMS, \ - ${jprt.my.linux.x64}-{product|fastdebug}-c2-GCBasher_G1, \ - ${jprt.my.linux.x64}-{product|fastdebug}-c2-GCBasher_ParOldGC, \ - ${jprt.my.linux.x64}-{product|fastdebug}-c2-GCOld_SerialGC, \ - ${jprt.my.linux.x64}-{product|fastdebug}-c2-GCOld_ParallelGC, \ - ${jprt.my.linux.x64}-{product|fastdebug}-c2-GCOld_ParNewGC, \ - ${jprt.my.linux.x64}-{product|fastdebug}-c2-GCOld_CMS, \ - ${jprt.my.linux.x64}-{product|fastdebug}-c2-GCOld_G1, \ - ${jprt.my.linux.x64}-{product|fastdebug}-c2-GCOld_ParOldGC, \ - ${jprt.my.linux.x64}-{product|fastdebug}-c2-jbb_default_nontiered, \ - ${jprt.my.linux.x64}-{product|fastdebug}-c2-jbb_ParallelGC, \ - ${jprt.my.linux.x64}-{product|fastdebug}-c2-jbb_G1, \ - ${jprt.my.linux.x64}-{product|fastdebug}-c2-jbb_ParOldGC - -jprt.my.macosx.x64.test.targets = \ - ${jprt.my.macosx.x64}-{product|fastdebug}-c2-jvm98, \ - ${jprt.my.macosx.x64}-{product|fastdebug}-c2-jvm98_nontiered, \ - ${jprt.my.macosx.x64}-{product|fastdebug}-c2-scimark, \ - ${jprt.my.macosx.x64}-{product|fastdebug}-c2-GCBasher_SerialGC, \ - ${jprt.my.macosx.x64}-{product|fastdebug}-c2-GCBasher_ParallelGC, \ - ${jprt.my.macosx.x64}-{product|fastdebug}-c2-GCBasher_ParNewGC, \ - ${jprt.my.macosx.x64}-{product|fastdebug}-c2-GCBasher_CMS, \ - ${jprt.my.macosx.x64}-{product|fastdebug}-c2-GCBasher_G1, \ - ${jprt.my.macosx.x64}-{product|fastdebug}-c2-GCBasher_ParOldGC, \ - ${jprt.my.macosx.x64}-{product|fastdebug}-c2-GCOld_SerialGC, \ - ${jprt.my.macosx.x64}-{product|fastdebug}-c2-GCOld_ParallelGC, \ - ${jprt.my.macosx.x64}-{product|fastdebug}-c2-GCOld_ParNewGC, \ - ${jprt.my.macosx.x64}-{product|fastdebug}-c2-GCOld_CMS, \ - ${jprt.my.macosx.x64}-{product|fastdebug}-c2-GCOld_G1, \ - ${jprt.my.macosx.x64}-{product|fastdebug}-c2-GCOld_ParOldGC, \ - ${jprt.my.macosx.x64}-{product|fastdebug}-c2-jbb_default_nontiered, \ - ${jprt.my.macosx.x64}-{product|fastdebug}-c2-jbb_ParallelGC, \ - ${jprt.my.macosx.x64}-{product|fastdebug}-c2-jbb_G1, \ - ${jprt.my.macosx.x64}-{product|fastdebug}-c2-jbb_ParOldGC - -jprt.my.windows.i586.test.targets = \ - ${jprt.my.windows.i586}-{product|fastdebug}-{c1|c2}-jvm98, \ - ${jprt.my.windows.i586}-{product|fastdebug}-c2-jvm98_nontiered, \ - ${jprt.my.windows.i586}-{product|fastdebug}-{c1|c2}-scimark, \ - ${jprt.my.windows.i586}-product-{c1|c2}-runThese, \ - ${jprt.my.windows.i586}-product-{c1|c2}-runThese_Xcomp, \ - ${jprt.my.windows.i586}-fastdebug-c1-runThese_Xshare, \ - ${jprt.my.windows.i586}-{product|fastdebug}-{c1|c2}-GCBasher_SerialGC, \ - ${jprt.my.windows.i586}-{product|fastdebug}-{c1|c2}-GCBasher_ParallelGC, \ - ${jprt.my.windows.i586}-{product|fastdebug}-{c1|c2}-GCBasher_ParNewGC, \ - ${jprt.my.windows.i586}-{product|fastdebug}-{c1|c2}-GCBasher_CMS, \ - ${jprt.my.windows.i586}-{product|fastdebug}-{c1|c2}-GCBasher_G1, \ - ${jprt.my.windows.i586}-{product|fastdebug}-{c1|c2}-GCBasher_ParOldGC, \ - ${jprt.my.windows.i586}-product-{c1|c2}-GCOld_SerialGC, \ - ${jprt.my.windows.i586}-product-{c1|c2}-GCOld_ParallelGC, \ - ${jprt.my.windows.i586}-product-{c1|c2}-GCOld_ParNewGC, \ - ${jprt.my.windows.i586}-product-{c1|c2}-GCOld_CMS, \ - ${jprt.my.windows.i586}-product-{c1|c2}-GCOld_G1, \ - ${jprt.my.windows.i586}-product-{c1|c2}-GCOld_ParOldGC, \ - ${jprt.my.windows.i586}-{product|fastdebug}-{c1|c2}-jbb_default, \ - ${jprt.my.windows.i586}-{product|fastdebug}-c2-jbb_default_nontiered, \ - ${jprt.my.windows.i586}-product-{c1|c2}-jbb_ParallelGC, \ - ${jprt.my.windows.i586}-product-{c1|c2}-jbb_CMS, \ - ${jprt.my.windows.i586}-product-{c1|c2}-jbb_G1, \ - ${jprt.my.windows.i586}-product-{c1|c2}-jbb_ParOldGC - -jprt.my.windows.x64.test.targets = \ - ${jprt.my.windows.x64}-{product|fastdebug}-c2-jvm98, \ - ${jprt.my.windows.x64}-{product|fastdebug}-c2-jvm98_nontiered, \ - ${jprt.my.windows.x64}-{product|fastdebug}-c2-scimark, \ - ${jprt.my.windows.x64}-product-c2-runThese, \ - ${jprt.my.windows.x64}-product-c2-runThese_Xcomp, \ - ${jprt.my.windows.x64}-{product|fastdebug}-c2-GCBasher_SerialGC, \ - ${jprt.my.windows.x64}-{product|fastdebug}-c2-GCBasher_ParallelGC, \ - ${jprt.my.windows.x64}-{product|fastdebug}-c2-GCBasher_ParNewGC, \ - ${jprt.my.windows.x64}-{product|fastdebug}-c2-GCBasher_CMS, \ - ${jprt.my.windows.x64}-{product|fastdebug}-c2-GCBasher_G1, \ - ${jprt.my.windows.x64}-{product|fastdebug}-c2-GCBasher_ParOldGC, \ - ${jprt.my.windows.x64}-{product|fastdebug}-c2-GCOld_SerialGC, \ - ${jprt.my.windows.x64}-{product|fastdebug}-c2-GCOld_ParallelGC, \ - ${jprt.my.windows.x64}-{product|fastdebug}-c2-GCOld_ParNewGC, \ - ${jprt.my.windows.x64}-{product|fastdebug}-c2-GCOld_CMS, \ - ${jprt.my.windows.x64}-{product|fastdebug}-c2-GCOld_G1, \ - ${jprt.my.windows.x64}-{product|fastdebug}-c2-GCOld_ParOldGC, \ - ${jprt.my.windows.x64}-{product|fastdebug}-c2-jbb_default, \ - ${jprt.my.windows.x64}-{product|fastdebug}-c2-jbb_default_nontiered, \ - ${jprt.my.windows.x64}-product-c2-jbb_CMS, \ - ${jprt.my.windows.x64}-product-c2-jbb_ParallelGC, \ - ${jprt.my.windows.x64}-product-c2-jbb_G1, \ - ${jprt.my.windows.x64}-product-c2-jbb_ParOldGC - -# Some basic "smoke" tests for OpenJDK builds -jprt.test.targets.open = \ - ${jprt.my.solaris.x64}-{productOpen|fastdebugOpen}-c2-jvm98, \ - ${jprt.my.linux.x64}-{productOpen|fastdebugOpen}-c2-jvm98 - -# Testing for actual embedded builds is different to standard -jprt.my.linux.i586.test.targets.embedded = \ - linux_i586_2.6-product-c1-scimark - -# The complete list of test targets for jprt -# Note: no PPC or ARM tests at this stage - -jprt.test.targets.standard = \ - ${jprt.my.linux.i586.test.targets.embedded}, \ - ${jprt.my.solaris.sparcv9.test.targets}, \ - ${jprt.my.solaris.x64.test.targets}, \ - ${jprt.my.linux.i586.test.targets}, \ - ${jprt.my.linux.x64.test.targets}, \ - ${jprt.my.macosx.x64.test.targets}, \ - ${jprt.my.windows.i586.test.targets}, \ - ${jprt.my.windows.x64.test.targets}, \ - ${jprt.test.targets.open} - -jprt.test.targets.embedded= \ - ${jprt.my.linux.i586.test.targets.embedded}, \ - ${jprt.my.solaris.sparcv9.test.targets}, \ - ${jprt.my.solaris.x64.test.targets}, \ - ${jprt.my.linux.x64.test.targets}, \ - ${jprt.my.windows.i586.test.targets}, \ - ${jprt.my.windows.x64.test.targets} - -jprt.test.targets.jdk8u40=${jprt.test.targets.standard} -jprt.test.targets.jdk7=${jprt.test.targets.standard} -jprt.test.targets.jdk7u8=${jprt.test.targets.jdk7} -jprt.test.targets=${jprt.test.targets.${jprt.tools.default.release}} - -# The default test/Makefile targets that should be run - -#jprt.make.rule.test.targets=*-product-*-packtest - -jprt.make.rule.test.targets.standard.client = \ - ${jprt.my.linux.i586}-*-c1-clienttest, \ - ${jprt.my.windows.i586}-*-c1-clienttest - -jprt.make.rule.test.targets.standard.server = \ - ${jprt.my.solaris.sparcv9}-*-c2-servertest, \ - ${jprt.my.solaris.x64}-*-c2-servertest, \ - ${jprt.my.linux.i586}-*-c2-servertest, \ - ${jprt.my.linux.x64}-*-c2-servertest, \ - ${jprt.my.macosx.x64}-*-c2-servertest, \ - ${jprt.my.windows.i586}-*-c2-servertest, \ - ${jprt.my.windows.x64}-*-c2-servertest - -jprt.make.rule.test.targets.standard.internalvmtests = \ - ${jprt.my.solaris.sparcv9}-fastdebug-c2-internalvmtests, \ - ${jprt.my.solaris.x64}-fastdebug-c2-internalvmtests, \ - ${jprt.my.linux.i586}-fastdebug-c2-internalvmtests, \ - ${jprt.my.linux.x64}-fastdebug-c2-internalvmtests, \ - ${jprt.my.macosx.x64}-fastdebug-c2-internalvmtests, \ - ${jprt.my.windows.i586}-fastdebug-c2-internalvmtests, \ - ${jprt.my.windows.x64}-fastdebug-c2-internalvmtests - -jprt.make.rule.test.targets.standard.reg.group = \ - ${jprt.my.solaris.sparcv9}-{product|fastdebug}-c2-GROUP, \ - ${jprt.my.solaris.x64}-{product|fastdebug}-c2-GROUP, \ - ${jprt.my.linux.i586}-{product|fastdebug}-c2-GROUP, \ - ${jprt.my.linux.x64}-{product|fastdebug}-c2-GROUP, \ - ${jprt.my.windows.i586}-{product|fastdebug}-c2-GROUP, \ - ${jprt.my.windows.x64}-{product|fastdebug}-c2-GROUP, \ - ${jprt.my.linux.i586}-{product|fastdebug}-c1-GROUP, \ - ${jprt.my.windows.i586}-{product|fastdebug}-c1-GROUP - -jprt.make.rule.test.targets.standard = \ - ${jprt.make.rule.test.targets.standard.client}, \ - ${jprt.make.rule.test.targets.standard.server}, \ - ${jprt.make.rule.test.targets.standard.internalvmtests}, \ - ${jprt.make.rule.test.targets.standard.reg.group:GROUP=hotspot_wbapitest}, \ - ${jprt.make.rule.test.targets.standard.reg.group:GROUP=hotspot_compiler}, \ - ${jprt.make.rule.test.targets.standard.reg.group:GROUP=hotspot_gc}, \ - ${jprt.make.rule.test.targets.standard.reg.group:GROUP=hotspot_runtime}, \ - ${jprt.make.rule.test.targets.standard.reg.group:GROUP=hotspot_serviceability} - -jprt.make.rule.test.targets.embedded = \ - ${jprt.make.rule.test.targets.standard.client} - -jprt.make.rule.test.targets.jdk8u40=${jprt.make.rule.test.targets.standard} -jprt.make.rule.test.targets.jdk7=${jprt.make.rule.test.targets.standard} -jprt.make.rule.test.targets.jdk7u8=${jprt.make.rule.test.targets.jdk7} -jprt.make.rule.test.targets=${jprt.make.rule.test.targets.${jprt.tools.default.release}} - -# 7155453: Work-around to prevent popups on OSX from blocking test completion -# but the work-around is added to all platforms to be consistent -jprt.jbb.options=-Djava.awt.headless=true
--- a/make/linux/makefiles/adjust-mflags.sh Thu Jan 08 12:47:32 2015 +0000 +++ b/make/linux/makefiles/adjust-mflags.sh Tue Feb 03 16:48:05 2015 +0000 @@ -64,7 +64,7 @@ echo "$MFLAGS" \ | sed ' s/^-/ -/ - s/ -\([^ ][^ ]*\)j/ -\1 -j/ + s/ -\([^ I][^ I]*\)j/ -\1 -j/ s/ -j[0-9][0-9]*/ -j/ s/ -j\([^ ]\)/ -j -\1/ s/ -j/ -j'${HOTSPOT_BUILD_JOBS:-${default_build_jobs}}'/
--- a/make/linux/makefiles/mapfile-vers-debug Thu Jan 08 12:47:32 2015 +0000 +++ b/make/linux/makefiles/mapfile-vers-debug Tue Feb 03 16:48:05 2015 +0000 @@ -217,6 +217,9 @@ JVM_RegisterSignal; JVM_ReleaseUTF; JVM_ResolveClass; + JVM_KnownToNotExist; + JVM_GetResourceLookupCacheURLs; + JVM_GetResourceLookupCache; JVM_ResumeThread; JVM_Send; JVM_SendTo;
--- a/make/linux/makefiles/mapfile-vers-product Thu Jan 08 12:47:32 2015 +0000 +++ b/make/linux/makefiles/mapfile-vers-product Tue Feb 03 16:48:05 2015 +0000 @@ -217,6 +217,9 @@ JVM_RegisterSignal; JVM_ReleaseUTF; JVM_ResolveClass; + JVM_KnownToNotExist; + JVM_GetResourceLookupCacheURLs; + JVM_GetResourceLookupCache; JVM_ResumeThread; JVM_Send; JVM_SendTo;
--- a/make/solaris/makefiles/add_gnu_debuglink.make Thu Jan 08 12:47:32 2015 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,54 +0,0 @@ -# -# Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. -# 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. -# -# - -# Rules to build add_gnu_debuglink, used by vm.make on Solaris - -# Allow $(ADD_GNU_DEBUGLINK) to be called from any directory. -# We don't set or use the GENERATED macro to avoid affecting -# other HotSpot Makefiles. -TOPDIR = $(shell echo `pwd`) -ADD_GNU_DEBUGLINK = $(TOPDIR)/../generated/add_gnu_debuglink - -ADD_GNU_DEBUGLINK_DIR = $(GAMMADIR)/src/os/solaris/add_gnu_debuglink -ADD_GNU_DEBUGLINK_SRC = $(ADD_GNU_DEBUGLINK_DIR)/add_gnu_debuglink.c -ADD_GNU_DEBUGLINK_FLAGS = -LIBS_ADD_GNU_DEBUGLINK += -lelf - -ifeq ("${Platform_compiler}", "sparcWorks") -# Enable the following ADD_GNU_DEBUGLINK_FLAGS addition if you need to -# compare the built ELF objects. -# -# The -g option makes static data global and the "-W0,-noglobal" -# option tells the compiler to not globalize static data using a unique -# globalization prefix. Instead force the use of a static globalization -# prefix based on the source filepath so the objects from two identical -# compilations are the same. -# -# Note: The blog says to use "-W0,-xglobalstatic", but that doesn't -# seem to work. I got "-W0,-noglobal" from Kelly and that works. -#ADD_GNU_DEBUGLINK_FLAGS += -W0,-noglobal -endif # Platform_compiler == sparcWorks - -$(ADD_GNU_DEBUGLINK): $(ADD_GNU_DEBUGLINK_SRC) - $(CC) -g -o $@ $< $(ADD_GNU_DEBUGLINK_FLAGS) $(LIBS_ADD_GNU_DEBUGLINK)
--- a/make/solaris/makefiles/adjust-mflags.sh Thu Jan 08 12:47:32 2015 +0000 +++ b/make/solaris/makefiles/adjust-mflags.sh Tue Feb 03 16:48:05 2015 +0000 @@ -64,7 +64,7 @@ echo "$MFLAGS" \ | sed ' s/^-/ -/ - s/ -\([^ ][^ ]*\)j/ -\1 -j/ + s/ -\([^ I][^ I]*\)j/ -\1 -j/ s/ -j[0-9][0-9]*/ -j/ s/ -j\([^ ]\)/ -j -\1/ s/ -j/ -j'${HOTSPOT_BUILD_JOBS:-${default_build_jobs}}'/
--- a/make/solaris/makefiles/defs.make Thu Jan 08 12:47:32 2015 +0000 +++ b/make/solaris/makefiles/defs.make Tue Feb 03 16:48:05 2015 +0000 @@ -1,5 +1,5 @@ # -# Copyright (c) 2006, 2013, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2006, 2014, Oracle and/or its affiliates. All rights reserved. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. # # This code is free software; you can redistribute it and/or modify it @@ -133,6 +133,55 @@ OBJCOPY=$(shell test -x $(ALT_OBJCOPY) && echo $(ALT_OBJCOPY)) endif + ifneq ($(OBJCOPY),) + # OBJCOPY version check: + # - version number is last blank separate word on first line + # - version number formats that have been seen: + # - <major>.<minor> + # - <major>.<minor>.<micro> + # + # Full Debug Symbols on Solaris needs version 2.21.1 or newer. + # + OBJCOPY_VERS_CHK := $(shell \ + $(OBJCOPY) --version \ + | sed -n \ + -e 's/.* //' \ + -e '/^[01]\./b bad' \ + -e '/^2\./{' \ + -e ' s/^2\.//' \ + -e ' /^[0-9]$$/b bad' \ + -e ' /^[0-9]\./b bad' \ + -e ' /^1[0-9]$$/b bad' \ + -e ' /^1[0-9]\./b bad' \ + -e ' /^20\./b bad' \ + -e ' /^21\.0$$/b bad' \ + -e ' /^21\.0\./b bad' \ + -e '}' \ + -e ':good' \ + -e 's/.*/VALID_VERSION/p' \ + -e 'q' \ + -e ':bad' \ + -e 's/.*/BAD_VERSION/p' \ + -e 'q' \ + ) + ifeq ($(OBJCOPY_VERS_CHK),BAD_VERSION) + _JUNK_ := $(shell \ + echo >&2 "WARNING: $(OBJCOPY) --version info:"; \ + $(OBJCOPY) --version | sed -n -e 's/^/WARNING: /p' -e 'q' >&2; \ + echo >&2 "WARNING: an objcopy version of 2.21.1 or newer" \ + "is needed to create valid .debuginfo files."; \ + echo >&2 "WARNING: ignoring above objcopy command."; \ + echo >&2 "WARNING: patch 149063-01 or newer contains the" \ + "correct Solaris 10 SPARC version."; \ + echo >&2 "WARNING: patch 149064-01 or newer contains the" \ + "correct Solaris 10 X86 version."; \ + echo >&2 "WARNING: Solaris 11 Update 1 contains the" \ + "correct version."; \ + ) + OBJCOPY= + endif + endif + ifeq ($(OBJCOPY),) _JUNK_ := $(shell \ echo >&2 "INFO: no objcopy cmd found so cannot create .debuginfo files.")
--- a/make/solaris/makefiles/dtrace.make Thu Jan 08 12:47:32 2015 +0000 +++ b/make/solaris/makefiles/dtrace.make Tue Feb 03 16:48:05 2015 +0000 @@ -1,5 +1,5 @@ # -# Copyright (c) 2005, 2013, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2005, 2014, Oracle and/or its affiliates. All rights reserved. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. # # This code is free software; you can redistribute it and/or modify it @@ -96,25 +96,16 @@ XLIBJVM_DTRACE_DEBUGINFO = $(XLIBJVM_DIR)/$(LIBJVM_DTRACE_DEBUGINFO) XLIBJVM_DTRACE_DIZ = $(XLIBJVM_DIR)/$(LIBJVM_DTRACE_DIZ) -$(XLIBJVM_DB): $(ADD_GNU_DEBUGLINK) $(FIX_EMPTY_SEC_HDR_FLAGS) $(DTRACE_SRCDIR)/$(JVM_DB).c $(JVMOFFS).h $(LIBJVM_DB_MAPFILE) +$(XLIBJVM_DB): $(DTRACE_SRCDIR)/$(JVM_DB).c $(JVMOFFS).h $(LIBJVM_DB_MAPFILE) @echo Making $@ $(QUIETLY) mkdir -p $(XLIBJVM_DIR) ; \ $(CC) $(SYMFLAG) $(ARCHFLAG/$(ISA)) -D$(TYPE) -I. -I$(GENERATED) \ $(SHARED_FLAG) $(LFLAGS_JVM_DB) -o $@ $(DTRACE_SRCDIR)/$(JVM_DB).c -lc ifeq ($(ENABLE_FULL_DEBUG_SYMBOLS),1) -# gobjcopy crashes on "empty" section headers with the SHF_ALLOC flag set. -# Clear the SHF_ALLOC flag (if set) from empty section headers. -# An empty section header has sh_addr == 0 and sh_size == 0. -# This problem has only been seen on Solaris X64, but we call this tool -# on all Solaris builds just in case. - $(QUIETLY) $(FIX_EMPTY_SEC_HDR_FLAGS) $@ $(QUIETLY) $(OBJCOPY) --only-keep-debug $@ $(XLIBJVM_DB_DEBUGINFO) -# $(OBJCOPY) --add-gnu-debuglink=... corrupts SUNW_* sections. -# Use $(ADD_GNU_DEBUGLINK) until a fixed $(OBJCOPY) is available. -# $(OBJCOPY) --add-gnu-debuglink=$(LIBJVM_DB_DEBUGINFO) $(LIBJVM_DB) ; # Do this part in the $(XLIBJVM_DIR) subdir so $(XLIBJVM_DIR) is not # in the link name: - ( cd $(XLIBJVM_DIR) && $(ADD_GNU_DEBUGLINK) $(LIBJVM_DB_DEBUGINFO) $(LIBJVM_DB) ) + ( cd $(XLIBJVM_DIR) && $(OBJCOPY) --add-gnu-debuglink=$(LIBJVM_DB_DEBUGINFO) $(LIBJVM_DB) ) ifeq ($(STRIP_POLICY),all_strip) $(QUIETLY) $(STRIP) $@ else @@ -131,20 +122,16 @@ endif endif -$(XLIBJVM_DTRACE): $(ADD_GNU_DEBUGLINK) $(FIX_EMPTY_SEC_HDR_FLAGS) $(DTRACE_SRCDIR)/$(JVM_DTRACE).c $(DTRACE_SRCDIR)/$(JVM_DTRACE).h $(LIBJVM_DTRACE_MAPFILE) +$(XLIBJVM_DTRACE): $(DTRACE_SRCDIR)/$(JVM_DTRACE).c $(DTRACE_SRCDIR)/$(JVM_DTRACE).h $(LIBJVM_DTRACE_MAPFILE) @echo Making $@ $(QUIETLY) mkdir -p $(XLIBJVM_DIR) ; \ $(CC) $(SYMFLAG) $(ARCHFLAG/$(ISA)) -D$(TYPE) -I. \ $(SHARED_FLAG) $(LFLAGS_JVM_DTRACE) -o $@ $(DTRACE_SRCDIR)/$(JVM_DTRACE).c -lc -lthread -ldoor ifeq ($(ENABLE_FULL_DEBUG_SYMBOLS),1) -# Clear the SHF_ALLOC flag (if set) from empty section headers. - $(QUIETLY) $(FIX_EMPTY_SEC_HDR_FLAGS) $@ $(QUIETLY) $(OBJCOPY) --only-keep-debug $@ $(XLIBJVM_DTRACE_DEBUGINFO) -# $(OBJCOPY) --add-gnu-debuglink=... corrupts SUNW_* sections. -# $(OBJCOPY) --add-gnu-debuglink=$(LIBJVM_DTRACE_DEBUGINFO) $(LIBJVM_DTRACE) ; # Do this part in the $(XLIBJVM_DIR) subdir so $(XLIBJVM_DIR) is not # in the link name: - ( cd $(XLIBJVM_DIR) && $(ADD_GNU_DEBUGLINK) $(LIBJVM_DTRACE_DEBUGINFO) $(LIBJVM_DTRACE) ) + ( cd $(XLIBJVM_DIR) && $(OBJCOPY) --add-gnu-debuglink=$(LIBJVM_DTRACE_DEBUGINFO) $(LIBJVM_DTRACE) ) ifeq ($(STRIP_POLICY),all_strip) $(QUIETLY) $(STRIP) $@ else @@ -201,17 +188,13 @@ $(JVMOFFS.o): $(JVMOFFS).h $(JVMOFFS).cpp $(QUIETLY) $(CXX) -c -I. -o $@ $(ARCHFLAG) -D$(TYPE) $(JVMOFFS).cpp -$(LIBJVM_DB): $(ADD_GNU_DEBUGLINK) $(FIX_EMPTY_SEC_HDR_FLAGS) $(DTRACE_SRCDIR)/$(JVM_DB).c $(JVMOFFS.o) $(XLIBJVM_DB) $(LIBJVM_DB_MAPFILE) +$(LIBJVM_DB): $(DTRACE_SRCDIR)/$(JVM_DB).c $(JVMOFFS.o) $(XLIBJVM_DB) $(LIBJVM_DB_MAPFILE) @echo Making $@ $(QUIETLY) $(CC) $(SYMFLAG) $(ARCHFLAG) -D$(TYPE) -I. -I$(GENERATED) \ $(SHARED_FLAG) $(LFLAGS_JVM_DB) -o $@ $(DTRACE_SRCDIR)/$(JVM_DB).c -lc ifeq ($(ENABLE_FULL_DEBUG_SYMBOLS),1) -# Clear the SHF_ALLOC flag (if set) from empty section headers. - $(QUIETLY) $(FIX_EMPTY_SEC_HDR_FLAGS) $@ $(QUIETLY) $(OBJCOPY) --only-keep-debug $@ $(LIBJVM_DB_DEBUGINFO) -# $(OBJCOPY) --add-gnu-debuglink=... corrupts SUNW_* sections. -# $(QUIETLY) $(OBJCOPY) --add-gnu-debuglink=$(LIBJVM_DB_DEBUGINFO) $@ - $(QUIETLY) $(ADD_GNU_DEBUGLINK) $(LIBJVM_DB_DEBUGINFO) $@ + $(QUIETLY) $(OBJCOPY) --add-gnu-debuglink=$(LIBJVM_DB_DEBUGINFO) $@ ifeq ($(STRIP_POLICY),all_strip) $(QUIETLY) $(STRIP) $@ else @@ -226,17 +209,13 @@ endif endif -$(LIBJVM_DTRACE): $(ADD_GNU_DEBUGLINK) $(FIX_EMPTY_SEC_HDR_FLAGS) $(DTRACE_SRCDIR)/$(JVM_DTRACE).c $(XLIBJVM_DTRACE) $(DTRACE_SRCDIR)/$(JVM_DTRACE).h $(LIBJVM_DTRACE_MAPFILE) +$(LIBJVM_DTRACE): $(DTRACE_SRCDIR)/$(JVM_DTRACE).c $(XLIBJVM_DTRACE) $(DTRACE_SRCDIR)/$(JVM_DTRACE).h $(LIBJVM_DTRACE_MAPFILE) @echo Making $@ $(QUIETLY) $(CC) $(SYMFLAG) $(ARCHFLAG) -D$(TYPE) -I. \ $(SHARED_FLAG) $(LFLAGS_JVM_DTRACE) -o $@ $(DTRACE_SRCDIR)/$(JVM_DTRACE).c -lc -lthread -ldoor ifeq ($(ENABLE_FULL_DEBUG_SYMBOLS),1) -# Clear the SHF_ALLOC flag (if set) from empty section headers. - $(QUIETLY) $(FIX_EMPTY_SEC_HDR_FLAGS) $@ $(QUIETLY) $(OBJCOPY) --only-keep-debug $@ $(LIBJVM_DTRACE_DEBUGINFO) -# $(OBJCOPY) --add-gnu-debuglink=... corrupts SUNW_* sections. -# $(QUIETLY) $(OBJCOPY) --add-gnu-debuglink=$(LIBJVM_DTRACE_DEBUGINFO) $@ - $(QUIETLY) $(ADD_GNU_DEBUGLINK) $(LIBJVM_DTRACE_DEBUGINFO) $@ + $(QUIETLY) $(OBJCOPY) --add-gnu-debuglink=$(LIBJVM_DTRACE_DEBUGINFO) $@ ifeq ($(STRIP_POLICY),all_strip) $(QUIETLY) $(STRIP) $@ else
--- a/make/solaris/makefiles/fix_empty_sec_hdr_flags.make Thu Jan 08 12:47:32 2015 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,54 +0,0 @@ -# -# Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. -# 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. -# -# - -# Rules to build fix_empty_sec_hdr_flags, used by vm.make on Solaris - -# Allow $(FIX_EMPTY_SEC_HDR_FLAGS) to be called from any directory. -# We don't set or use the GENERATED macro to avoid affecting -# other HotSpot Makefiles. -TOPDIR = $(shell echo `pwd`) -FIX_EMPTY_SEC_HDR_FLAGS = $(TOPDIR)/../generated/fix_empty_sec_hdr_flags - -FIX_EMPTY_SEC_HDR_FLAGS_DIR = $(GAMMADIR)/src/os/solaris/fix_empty_sec_hdr_flags -FIX_EMPTY_SEC_HDR_FLAGS_SRC = $(FIX_EMPTY_SEC_HDR_FLAGS_DIR)/fix_empty_sec_hdr_flags.c -FIX_EMPTY_SEC_HDR_FLAGS_FLAGS = -LIBS_FIX_EMPTY_SEC_HDR_FLAGS += -lelf - -ifeq ("${Platform_compiler}", "sparcWorks") -# Enable the following FIX_EMPTY_SEC_HDR_FLAGS_FLAGS addition if you need to -# compare the built ELF objects. -# -# The -g option makes static data global and the "-W0,-noglobal" -# option tells the compiler to not globalize static data using a unique -# globalization prefix. Instead force the use of a static globalization -# prefix based on the source filepath so the objects from two identical -# compilations are the same. -# -# Note: The blog says to use "-W0,-xglobalstatic", but that doesn't -# seem to work. I got "-W0,-noglobal" from Kelly and that works. -#FIX_EMPTY_SEC_HDR_FLAGS_FLAGS += -W0,-noglobal -endif # Platform_compiler == sparcWorks - -$(FIX_EMPTY_SEC_HDR_FLAGS): $(FIX_EMPTY_SEC_HDR_FLAGS_SRC) - $(CC) -g -o $@ $< $(FIX_EMPTY_SEC_HDR_FLAGS_FLAGS) $(LIBS_FIX_EMPTY_SEC_HDR_FLAGS)
--- a/make/solaris/makefiles/jsig.make Thu Jan 08 12:47:32 2015 +0000 +++ b/make/solaris/makefiles/jsig.make Tue Feb 03 16:48:05 2015 +0000 @@ -1,5 +1,5 @@ # -# Copyright (c) 2005, 2012, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2005, 2014, Oracle and/or its affiliates. All rights reserved. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. # # This code is free software; you can redistribute it and/or modify it @@ -47,22 +47,13 @@ LFLAGS_JSIG += -mt -xnolib endif -$(LIBJSIG): $(ADD_GNU_DEBUGLINK) $(FIX_EMPTY_SEC_HDR_FLAGS) $(JSIGSRCDIR)/jsig.c $(LIBJSIG_MAPFILE) +$(LIBJSIG): $(JSIGSRCDIR)/jsig.c $(LIBJSIG_MAPFILE) @echo Making signal interposition lib... $(QUIETLY) $(CC) $(SYMFLAG) $(ARCHFLAG) $(SHARED_FLAG) $(PICFLAG) \ $(LFLAGS_JSIG) -o $@ $(JSIGSRCDIR)/jsig.c -ldl ifeq ($(ENABLE_FULL_DEBUG_SYMBOLS),1) -# gobjcopy crashes on "empty" section headers with the SHF_ALLOC flag set. -# Clear the SHF_ALLOC flag (if set) from empty section headers. -# An empty section header has sh_addr == 0 and sh_size == 0. -# This problem has only been seen on Solaris X64, but we call this tool -# on all Solaris builds just in case. - $(QUIETLY) $(FIX_EMPTY_SEC_HDR_FLAGS) $@ $(QUIETLY) $(OBJCOPY) --only-keep-debug $@ $(LIBJSIG_DEBUGINFO) -# $(OBJCOPY) --add-gnu-debuglink=... corrupts SUNW_* sections. -# Use $(ADD_GNU_DEBUGLINK) until a fixed $(OBJCOPY) is available. -# $(QUIETLY) $(OBJCOPY) --add-gnu-debuglink=$(LIBJSIG_DEBUGINFO) $@ - $(QUIETLY) $(ADD_GNU_DEBUGLINK) $(LIBJSIG_DEBUGINFO) $@ + $(QUIETLY) $(OBJCOPY) --add-gnu-debuglink=$(LIBJSIG_DEBUGINFO) $@ ifeq ($(STRIP_POLICY),all_strip) $(QUIETLY) $(STRIP) $@ else
--- a/make/solaris/makefiles/mapfile-vers Thu Jan 08 12:47:32 2015 +0000 +++ b/make/solaris/makefiles/mapfile-vers Tue Feb 03 16:48:05 2015 +0000 @@ -189,6 +189,9 @@ JVM_IsSupportedJNIVersion; JVM_IsThreadAlive; JVM_IsVMGeneratedMethodIx; + JVM_KnownToNotExist; + JVM_GetResourceLookupCacheURLs; + JVM_GetResourceLookupCache; JVM_LatestUserDefinedLoader; JVM_Listen; JVM_LoadClass0;
--- a/make/solaris/makefiles/saproc.make Thu Jan 08 12:47:32 2015 +0000 +++ b/make/solaris/makefiles/saproc.make Tue Feb 03 16:48:05 2015 +0000 @@ -1,5 +1,5 @@ # -# Copyright (c) 2005, 2012, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2005, 2014, Oracle and/or its affiliates. All rights reserved. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. # # This code is free software; you can redistribute it and/or modify it @@ -90,7 +90,7 @@ #SOLARIS_11_B159_OR_LATER=-DSOLARIS_11_B159_OR_LATER -$(LIBSAPROC): $(ADD_GNU_DEBUGLINK) $(FIX_EMPTY_SEC_HDR_FLAGS) $(SASRCFILES) $(SADISOBJ) $(SAMAPFILE) +$(LIBSAPROC): $(SASRCFILES) $(SADISOBJ) $(SAMAPFILE) $(QUIETLY) if [ "$(BOOT_JAVA_HOME)" = "" ]; then \ echo "ALT_BOOTDIR, BOOTDIR or JAVA_HOME needs to be defined to build SA"; \ exit 1; \ @@ -121,17 +121,8 @@ -c -o $(SADISOBJ) ifeq ($(ENABLE_FULL_DEBUG_SYMBOLS),1) -# gobjcopy crashes on "empty" section headers with the SHF_ALLOC flag set. -# Clear the SHF_ALLOC flag (if set) from empty section headers. -# An empty section header has sh_addr == 0 and sh_size == 0. -# This problem has only been seen on Solaris X64, but we call this tool -# on all Solaris builds just in case. - $(QUIETLY) $(FIX_EMPTY_SEC_HDR_FLAGS) $@ $(QUIETLY) $(OBJCOPY) --only-keep-debug $@ $(LIBSAPROC_DEBUGINFO) -# $(OBJCOPY) --add-gnu-debuglink=... corrupts SUNW_* sections. -# Use $(ADD_GNU_DEBUGLINK) until a fixed $(OBJCOPY) is available. -# $(QUIETLY) $(OBJCOPY) --add-gnu-debuglink=$(LIBSAPROC_DEBUGINFO) $@ - $(QUIETLY) $(ADD_GNU_DEBUGLINK) $(LIBSAPROC_DEBUGINFO) $@ + $(QUIETLY) $(OBJCOPY) --add-gnu-debuglink=$(LIBSAPROC_DEBUGINFO) $@ ifeq ($(STRIP_POLICY),all_strip) $(QUIETLY) $(STRIP) $@ else
--- a/make/solaris/makefiles/vm.make Thu Jan 08 12:47:32 2015 +0000 +++ b/make/solaris/makefiles/vm.make Tue Feb 03 16:48:05 2015 +0000 @@ -1,5 +1,5 @@ # -# Copyright (c) 1998, 2013, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 1998, 2014, Oracle and/or its affiliates. All rights reserved. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. # # This code is free software; you can redistribute it and/or modify it @@ -141,7 +141,7 @@ LIBS += -lsocket -lsched -ldl $(LIBM) -lthread -lc -ldemangle endif # sparcWorks -LIBS += -lkstat -lpicl +LIBS += -lkstat # By default, link the *.o into the library, not the executable. LINK_INTO$(LINK_INTO) = LIBJVM @@ -153,14 +153,6 @@ include $(MAKEFILES_DIR)/dtrace.make #---------------------------------------------------------------------- -# add_gnu_debuglink tool -include $(MAKEFILES_DIR)/add_gnu_debuglink.make - -#---------------------------------------------------------------------- -# fix_empty_sec_hdr_flags tool -include $(MAKEFILES_DIR)/fix_empty_sec_hdr_flags.make - -#---------------------------------------------------------------------- # JVM JVM = jvm @@ -299,7 +291,7 @@ LINK_VM = $(LINK_LIB.CXX) endif # making the library: -$(LIBJVM): $(ADD_GNU_DEBUGLINK) $(FIX_EMPTY_SEC_HDR_FLAGS) $(LIBJVM.o) $(LIBJVM_MAPFILE) +$(LIBJVM): $(LIBJVM.o) $(LIBJVM_MAPFILE) ifeq ($(filter -sbfast -xsbfast, $(CFLAGS_BROWSE)),) @echo Linking vm... $(QUIETLY) $(LINK_LIB.CXX/PRE_HOOK) @@ -307,17 +299,8 @@ $(QUIETLY) $(LINK_LIB.CXX/POST_HOOK) $(QUIETLY) rm -f $@.1 && ln -s $@ $@.1 ifeq ($(ENABLE_FULL_DEBUG_SYMBOLS),1) -# gobjcopy crashes on "empty" section headers with the SHF_ALLOC flag set. -# Clear the SHF_ALLOC flag (if set) from empty section headers. -# An empty section header has sh_addr == 0 and sh_size == 0. -# This problem has only been seen on Solaris X64, but we call this tool -# on all Solaris builds just in case. - $(QUIETLY) $(FIX_EMPTY_SEC_HDR_FLAGS) $@ $(QUIETLY) $(OBJCOPY) --only-keep-debug $@ $(LIBJVM_DEBUGINFO) -# $(OBJCOPY) --add-gnu-debuglink=... corrupts SUNW_* sections. -# Use $(ADD_GNU_DEBUGLINK) until a fixed $(OBJCOPY) is available. -# $(QUIETLY) $(OBJCOPY) --add-gnu-debuglink=$(LIBJVM_DEBUGINFO) $@ - $(QUIETLY) $(ADD_GNU_DEBUGLINK) $(LIBJVM_DEBUGINFO) $@ + $(QUIETLY) $(OBJCOPY) --add-gnu-debuglink=$(LIBJVM_DEBUGINFO) $@ ifeq ($(STRIP_POLICY),all_strip) $(QUIETLY) $(STRIP) $@ else
--- a/make/windows/makefiles/compile.make Thu Jan 08 12:47:32 2015 +0000 +++ b/make/windows/makefiles/compile.make Tue Feb 03 16:48:05 2015 +0000 @@ -268,7 +268,7 @@ !endif LD_FLAGS= $(LD_FLAGS) kernel32.lib user32.lib gdi32.lib winspool.lib \ comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib \ - uuid.lib Wsock32.lib winmm.lib /nologo /machine:$(MACHINE) /opt:REF \ + uuid.lib Wsock32.lib winmm.lib version.lib /nologo /machine:$(MACHINE) /opt:REF \ /opt:ICF,8 !if "$(ENABLE_FULL_DEBUG_SYMBOLS)" == "1" LD_FLAGS= $(LD_FLAGS) /map /debug
--- a/make/windows/makefiles/sa.make Thu Jan 08 12:47:32 2015 +0000 +++ b/make/windows/makefiles/sa.make Tue Feb 03 16:48:05 2015 +0000 @@ -111,7 +111,7 @@ SA_LFLAGS = $(SA_LFLAGS) -map -debug !endif !if "$(BUILDARCH)" == "i486" -SA_LFLAGS = $(SAFESEH_FLAG) $(SA_LFLAGS) +SA_LFLAGS = /SAFESEH $(SA_LFLAGS) !endif SA_CFLAGS = $(SA_CFLAGS) $(MP_FLAG)
--- a/src/cpu/ppc/vm/assembler_ppc.cpp Thu Jan 08 12:47:32 2015 +0000 +++ b/src/cpu/ppc/vm/assembler_ppc.cpp Tue Feb 03 16:48:05 2015 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2014, Oracle and/or its affiliates. All rights reserved. * Copyright 2012, 2014 SAP AG. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -693,7 +693,7 @@ // PPC 1, section 4.6.7 Floating-Point Compare Instructions fcmpu( CCR7, F24, F25); - tty->print_cr("\ntest_asm disassembly (0x%lx 0x%lx):", code()->insts_begin(), code()->insts_end()); + tty->print_cr("\ntest_asm disassembly (0x%lx 0x%lx):", p2i(code()->insts_begin()), p2i(code()->insts_end())); code()->decode(); }
--- a/src/cpu/ppc/vm/compiledIC_ppc.cpp Thu Jan 08 12:47:32 2015 +0000 +++ b/src/cpu/ppc/vm/compiledIC_ppc.cpp Tue Feb 03 16:48:05 2015 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2014, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -175,7 +175,7 @@ if (TraceICs) { ResourceMark rm; tty->print_cr("CompiledStaticCall@" INTPTR_FORMAT ": set_to_interpreted %s", - instruction_address(), + p2i(instruction_address()), callee->name_and_sig_as_C_string()); }
--- a/src/cpu/ppc/vm/frame_ppc.cpp Thu Jan 08 12:47:32 2015 +0000 +++ b/src/cpu/ppc/vm/frame_ppc.cpp Tue Feb 03 16:48:05 2015 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2014, Oracle and/or its affiliates. All rights reserved. * Copyright 2012, 2014 SAP AG. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -140,7 +140,7 @@ void frame::patch_pc(Thread* thread, address pc) { if (TracePcPatching) { tty->print_cr("patch_pc at address " PTR_FORMAT " [" PTR_FORMAT " -> " PTR_FORMAT "]", - &((address*) _sp)[-1], ((address*) _sp)[-1], pc); + p2i(&((address*) _sp)[-1]), p2i(((address*) _sp)[-1]), p2i(pc)); } own_abi()->lr = (uint64_t)pc; _cb = CodeCache::find_blob(pc);
--- a/src/cpu/ppc/vm/interp_masm_ppc_64.cpp Thu Jan 08 12:47:32 2015 +0000 +++ b/src/cpu/ppc/vm/interp_masm_ppc_64.cpp Tue Feb 03 16:48:05 2015 +0000 @@ -545,6 +545,9 @@ cmplw(CCR0, Rindex, Rlength); sldi(RsxtIndex, RsxtIndex, index_shift); blt(CCR0, LnotOOR); + // Index should be in R17_tos, array should be in R4_ARG2. + mr(R17_tos, Rindex); + mr(R4_ARG2, Rarray); load_dispatch_table(Rtmp, (address*)Interpreter::_throw_ArrayIndexOutOfBoundsException_entry); mtctr(Rtmp); bctr(); @@ -1679,6 +1682,228 @@ } } +// Argument and return type profilig. +// kills: tmp, tmp2, R0, CR0, CR1 +void InterpreterMacroAssembler::profile_obj_type(Register obj, Register mdo_addr_base, + RegisterOrConstant mdo_addr_offs, Register tmp, Register tmp2) { + Label do_nothing, do_update; + + // tmp2 = obj is allowed + assert_different_registers(obj, mdo_addr_base, tmp, R0); + assert_different_registers(tmp2, mdo_addr_base, tmp, R0); + const Register klass = tmp2; + + verify_oop(obj); + + ld(tmp, mdo_addr_offs, mdo_addr_base); + + // Set null_seen if obj is 0. + cmpdi(CCR0, obj, 0); + ori(R0, tmp, TypeEntries::null_seen); + beq(CCR0, do_update); + + load_klass(klass, obj); + + clrrdi(R0, tmp, exact_log2(-TypeEntries::type_klass_mask)); + // Basically same as andi(R0, tmp, TypeEntries::type_klass_mask); + cmpd(CCR1, R0, klass); + // Klass seen before, nothing to do (regardless of unknown bit). + //beq(CCR1, do_nothing); + + andi_(R0, klass, TypeEntries::type_unknown); + // Already unknown. Nothing to do anymore. + //bne(CCR0, do_nothing); + crorc(/*CCR0 eq*/2, /*CCR1 eq*/4+2, /*CCR0 eq*/2); // cr0 eq = cr1 eq or cr0 ne + beq(CCR0, do_nothing); + + clrrdi_(R0, tmp, exact_log2(-TypeEntries::type_mask)); + orr(R0, klass, tmp); // Combine klass and null_seen bit (only used if (tmp & type_mask)==0). + beq(CCR0, do_update); // First time here. Set profile type. + + // Different than before. Cannot keep accurate profile. + ori(R0, tmp, TypeEntries::type_unknown); + + bind(do_update); + // update profile + std(R0, mdo_addr_offs, mdo_addr_base); + + align(32, 12); + bind(do_nothing); +} + +void InterpreterMacroAssembler::profile_arguments_type(Register callee, Register tmp1, Register tmp2, bool is_virtual) { + if (!ProfileInterpreter) { + return; + } + + assert_different_registers(callee, tmp1, tmp2, R28_mdx); + + if (MethodData::profile_arguments() || MethodData::profile_return()) { + Label profile_continue; + + test_method_data_pointer(profile_continue); + + int off_to_start = is_virtual ? in_bytes(VirtualCallData::virtual_call_data_size()) : in_bytes(CounterData::counter_data_size()); + + lbz(tmp1, in_bytes(DataLayout::tag_offset()) - off_to_start, R28_mdx); + cmpwi(CCR0, tmp1, is_virtual ? DataLayout::virtual_call_type_data_tag : DataLayout::call_type_data_tag); + bne(CCR0, profile_continue); + + if (MethodData::profile_arguments()) { + Label done; + int off_to_args = in_bytes(TypeEntriesAtCall::args_data_offset()); + add(R28_mdx, off_to_args, R28_mdx); + + for (int i = 0; i < TypeProfileArgsLimit; i++) { + if (i > 0 || MethodData::profile_return()) { + // If return value type is profiled we may have no argument to profile. + ld(tmp1, in_bytes(TypeEntriesAtCall::cell_count_offset())-off_to_args, R28_mdx); + cmpdi(CCR0, tmp1, (i+1)*TypeStackSlotEntries::per_arg_count()); + addi(tmp1, tmp1, -i*TypeStackSlotEntries::per_arg_count()); + blt(CCR0, done); + } + ld(tmp1, in_bytes(Method::const_offset()), callee); + lhz(tmp1, in_bytes(ConstMethod::size_of_parameters_offset()), tmp1); + // Stack offset o (zero based) from the start of the argument + // list, for n arguments translates into offset n - o - 1 from + // the end of the argument list. But there's an extra slot at + // the top of the stack. So the offset is n - o from Lesp. + ld(tmp2, in_bytes(TypeEntriesAtCall::stack_slot_offset(i))-off_to_args, R28_mdx); + subf(tmp1, tmp2, tmp1); + + sldi(tmp1, tmp1, Interpreter::logStackElementSize); + ldx(tmp1, tmp1, R15_esp); + + profile_obj_type(tmp1, R28_mdx, in_bytes(TypeEntriesAtCall::argument_type_offset(i))-off_to_args, tmp2, tmp1); + + int to_add = in_bytes(TypeStackSlotEntries::per_arg_size()); + addi(R28_mdx, R28_mdx, to_add); + off_to_args += to_add; + } + + if (MethodData::profile_return()) { + ld(tmp1, in_bytes(TypeEntriesAtCall::cell_count_offset())-off_to_args, R28_mdx); + addi(tmp1, tmp1, -TypeProfileArgsLimit*TypeStackSlotEntries::per_arg_count()); + } + + bind(done); + + if (MethodData::profile_return()) { + // We're right after the type profile for the last + // argument. tmp1 is the number of cells left in the + // CallTypeData/VirtualCallTypeData to reach its end. Non null + // if there's a return to profile. + assert(ReturnTypeEntry::static_cell_count() < TypeStackSlotEntries::per_arg_count(), "can't move past ret type"); + sldi(tmp1, tmp1, exact_log2(DataLayout::cell_size)); + add(R28_mdx, tmp1, R28_mdx); + } + } else { + assert(MethodData::profile_return(), "either profile call args or call ret"); + update_mdp_by_constant(in_bytes(TypeEntriesAtCall::return_only_size())); + } + + // Mdp points right after the end of the + // CallTypeData/VirtualCallTypeData, right after the cells for the + // return value type if there's one. + align(32, 12); + bind(profile_continue); + } +} + +void InterpreterMacroAssembler::profile_return_type(Register ret, Register tmp1, Register tmp2) { + assert_different_registers(ret, tmp1, tmp2); + if (ProfileInterpreter && MethodData::profile_return()) { + Label profile_continue; + + test_method_data_pointer(profile_continue); + + if (MethodData::profile_return_jsr292_only()) { + // If we don't profile all invoke bytecodes we must make sure + // it's a bytecode we indeed profile. We can't go back to the + // begining of the ProfileData we intend to update to check its + // type because we're right after it and we don't known its + // length. + lbz(tmp1, 0, R14_bcp); + lbz(tmp2, Method::intrinsic_id_offset_in_bytes(), R19_method); + cmpwi(CCR0, tmp1, Bytecodes::_invokedynamic); + cmpwi(CCR1, tmp1, Bytecodes::_invokehandle); + cror(/*CR0 eq*/2, /*CR1 eq*/4+2, /*CR0 eq*/2); + cmpwi(CCR1, tmp2, vmIntrinsics::_compiledLambdaForm); + cror(/*CR0 eq*/2, /*CR1 eq*/4+2, /*CR0 eq*/2); + bne(CCR0, profile_continue); + } + + profile_obj_type(ret, R28_mdx, -in_bytes(ReturnTypeEntry::size()), tmp1, tmp2); + + align(32, 12); + bind(profile_continue); + } +} + +void InterpreterMacroAssembler::profile_parameters_type(Register tmp1, Register tmp2, Register tmp3, Register tmp4) { + if (ProfileInterpreter && MethodData::profile_parameters()) { + Label profile_continue, done; + + test_method_data_pointer(profile_continue); + + // Load the offset of the area within the MDO used for + // parameters. If it's negative we're not profiling any parameters. + lwz(tmp1, in_bytes(MethodData::parameters_type_data_di_offset()) - in_bytes(MethodData::data_offset()), R28_mdx); + cmpwi(CCR0, tmp1, 0); + blt(CCR0, profile_continue); + + // Compute a pointer to the area for parameters from the offset + // and move the pointer to the slot for the last + // parameters. Collect profiling from last parameter down. + // mdo start + parameters offset + array length - 1 + + // Pointer to the parameter area in the MDO. + const Register mdp = tmp1; + add(mdp, tmp1, R28_mdx); + + // Pffset of the current profile entry to update. + const Register entry_offset = tmp2; + // entry_offset = array len in number of cells + ld(entry_offset, in_bytes(ArrayData::array_len_offset()), mdp); + + int off_base = in_bytes(ParametersTypeData::stack_slot_offset(0)); + assert(off_base % DataLayout::cell_size == 0, "should be a number of cells"); + + // entry_offset (number of cells) = array len - size of 1 entry + offset of the stack slot field + addi(entry_offset, entry_offset, -TypeStackSlotEntries::per_arg_count() + (off_base / DataLayout::cell_size)); + // entry_offset in bytes + sldi(entry_offset, entry_offset, exact_log2(DataLayout::cell_size)); + + Label loop; + align(32, 12); + bind(loop); + + // Load offset on the stack from the slot for this parameter. + ld(tmp3, entry_offset, mdp); + sldi(tmp3, tmp3, Interpreter::logStackElementSize); + neg(tmp3, tmp3); + // Read the parameter from the local area. + ldx(tmp3, tmp3, R18_locals); + + // Make entry_offset now point to the type field for this parameter. + int type_base = in_bytes(ParametersTypeData::type_offset(0)); + assert(type_base > off_base, "unexpected"); + addi(entry_offset, entry_offset, type_base - off_base); + + // Profile the parameter. + profile_obj_type(tmp3, mdp, entry_offset, tmp4, tmp3); + + // Go to next parameter. + int delta = TypeStackSlotEntries::per_arg_count() * DataLayout::cell_size + (type_base - off_base); + cmpdi(CCR0, entry_offset, off_base + delta); + addi(entry_offset, entry_offset, -delta); + bge(CCR0, loop); + + align(32, 12); + bind(profile_continue); + } +} + // Add a InterpMonitorElem to stack (see frame_sparc.hpp). void InterpreterMacroAssembler::add_monitor_to_stack(bool stack_is_empty, Register Rtemp1, Register Rtemp2) { @@ -2040,20 +2265,19 @@ bne(CCR0, test); address fd = CAST_FROM_FN_PTR(address, verify_return_address); - unsigned int nbytes_save = 10*8; // 10 volatile gprs - - save_LR_CR(Rtmp); + const int nbytes_save = 11*8; // volatile gprs except R0 + save_volatile_gprs(R1_SP, -nbytes_save); // except R0 + save_LR_CR(Rtmp); // Save in old frame. push_frame_reg_args(nbytes_save, Rtmp); - save_volatile_gprs(R1_SP, 112); // except R0 load_const_optimized(Rtmp, fd, R0); mr_if_needed(R4_ARG2, reg); mr(R3_ARG1, R19_method); call_c(Rtmp); // call C - restore_volatile_gprs(R1_SP, 112); // except R0 pop_frame(); restore_LR_CR(Rtmp); + restore_volatile_gprs(R1_SP, -nbytes_save); // except R0 b(skip); // Perform a more elaborate out-of-line call.
--- a/src/cpu/ppc/vm/interp_masm_ppc_64.hpp Thu Jan 08 12:47:32 2015 +0000 +++ b/src/cpu/ppc/vm/interp_masm_ppc_64.hpp Tue Feb 03 16:48:05 2015 +0000 @@ -255,6 +255,12 @@ void record_klass_in_profile(Register receiver, Register scratch1, Register scratch2, bool is_virtual_call); void record_klass_in_profile_helper(Register receiver, Register scratch1, Register scratch2, int start_row, Label& done, bool is_virtual_call); + // Argument and return type profiling. + void profile_obj_type(Register obj, Register mdo_addr_base, RegisterOrConstant mdo_addr_offs, Register tmp, Register tmp2); + void profile_arguments_type(Register callee, Register tmp1, Register tmp2, bool is_virtual); + void profile_return_type(Register ret, Register tmp1, Register tmp2); + void profile_parameters_type(Register tmp1, Register tmp2, Register tmp3, Register tmp4); + #endif // !CC_INTERP // Debugging
--- a/src/cpu/ppc/vm/macroAssembler_ppc.cpp Thu Jan 08 12:47:32 2015 +0000 +++ b/src/cpu/ppc/vm/macroAssembler_ppc.cpp Tue Feb 03 16:48:05 2015 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2014, Oracle and/or its affiliates. All rights reserved. * Copyright 2012, 2014 SAP AG. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -806,6 +806,7 @@ // For verify_oops. void MacroAssembler::save_volatile_gprs(Register dst, int offset) { + std(R2, offset, dst); offset += 8; std(R3, offset, dst); offset += 8; std(R4, offset, dst); offset += 8; std(R5, offset, dst); offset += 8; @@ -820,6 +821,7 @@ // For verify_oops. void MacroAssembler::restore_volatile_gprs(Register src, int offset) { + ld(R2, offset, src); offset += 8; ld(R3, offset, src); offset += 8; ld(R4, offset, src); offset += 8; ld(R5, offset, src); offset += 8; @@ -1186,6 +1188,16 @@ call_VM(oop_result, entry_point, check_exceptions); } +void MacroAssembler::call_VM(Register oop_result, address entry_point, Register arg_1, Register arg_2, Register arg_3, + bool check_exceptions) { + // R3_ARG1 is reserved for the thread + mr_if_needed(R4_ARG2, arg_1); + assert(arg_2 != R4_ARG2, "smashed argument"); + mr_if_needed(R5_ARG3, arg_2); + mr_if_needed(R6_ARG4, arg_3); + call_VM(oop_result, entry_point, check_exceptions); +} + void MacroAssembler::call_VM_leaf(address entry_point) { call_VM_leaf_base(entry_point); } @@ -3058,35 +3070,27 @@ if (!VerifyOops) { return; } - // Will be preserved. - Register tmp = R11; - assert(oop != tmp, "precondition"); - unsigned int nbytes_save = 10*8; // 10 volatile gprs + address/* FunctionDescriptor** */fd = StubRoutines::verify_oop_subroutine_entry_address(); - // save tmp - mr(R0, tmp); - // kill tmp - save_LR_CR(tmp); + const Register tmp = R11; // Will be preserved. + const int nbytes_save = 11*8; // Volatile gprs except R0. + save_volatile_gprs(R1_SP, -nbytes_save); // except R0 + + if (oop == tmp) mr(R4_ARG2, oop); + save_LR_CR(tmp); // save in old frame push_frame_reg_args(nbytes_save, tmp); - // restore tmp - mr(tmp, R0); - save_volatile_gprs(R1_SP, 112); // except R0 // load FunctionDescriptor** / entry_address * - load_const(tmp, fd); + load_const_optimized(tmp, fd, R0); // load FunctionDescriptor* / entry_address ld(tmp, 0, tmp); - mr(R4_ARG2, oop); - load_const(R3_ARG1, (address)msg); - // call destination for its side effect + if (oop != tmp) mr_if_needed(R4_ARG2, oop); + load_const_optimized(R3_ARG1, (address)msg, R0); + // Call destination for its side effect. call_c(tmp); - restore_volatile_gprs(R1_SP, 112); // except R0 + pop_frame(); - // save tmp - mr(R0, tmp); - // kill tmp restore_LR_CR(tmp); - // restore tmp - mr(tmp, R0); + restore_volatile_gprs(R1_SP, -nbytes_save); // except R0 } const char* stop_types[] = { @@ -3097,7 +3101,7 @@ }; static void stop_on_request(int tp, const char* msg) { - tty->print("PPC assembly code requires stop: (%s) %s\n", (void *)stop_types[tp%/*stop_end*/4], msg); + tty->print("PPC assembly code requires stop: (%s) %s\n", stop_types[tp%/*stop_end*/4], msg); guarantee(false, err_msg("PPC assembly code requires stop: %s", msg)); }
--- a/src/cpu/ppc/vm/macroAssembler_ppc.hpp Thu Jan 08 12:47:32 2015 +0000 +++ b/src/cpu/ppc/vm/macroAssembler_ppc.hpp Tue Feb 03 16:48:05 2015 +0000 @@ -368,6 +368,7 @@ void call_VM(Register oop_result, address entry_point, bool check_exceptions = true); void call_VM(Register oop_result, address entry_point, Register arg_1, bool check_exceptions = true); void call_VM(Register oop_result, address entry_point, Register arg_1, Register arg_2, bool check_exceptions = true); + void call_VM(Register oop_result, address entry_point, Register arg_1, Register arg_2, Register arg3, bool check_exceptions = true); void call_VM_leaf(address entry_point); void call_VM_leaf(address entry_point, Register arg_1); void call_VM_leaf(address entry_point, Register arg_1, Register arg_2);
--- a/src/cpu/ppc/vm/methodHandles_ppc.cpp Thu Jan 08 12:47:32 2015 +0000 +++ b/src/cpu/ppc/vm/methodHandles_ppc.cpp Tue Feb 03 16:48:05 2015 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2014, Oracle and/or its affiliates. All rights reserved. * Copyright 2012, 2014 SAP AG. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -464,7 +464,7 @@ strstr(adaptername, "linkTo") == NULL); // static linkers don't have MH const char* mh_reg_name = has_mh ? "R23_method_handle" : "G23"; tty->print_cr("MH %s %s="INTPTR_FORMAT " sp=" INTPTR_FORMAT, - adaptername, mh_reg_name, (intptr_t) mh, entry_sp); + adaptername, mh_reg_name, (intptr_t) mh, (intptr_t) entry_sp); if (Verbose) { tty->print_cr("Registers:");
--- a/src/cpu/ppc/vm/nativeInst_ppc.cpp Thu Jan 08 12:47:32 2015 +0000 +++ b/src/cpu/ppc/vm/nativeInst_ppc.cpp Tue Feb 03 16:48:05 2015 +0000 @@ -1,6 +1,6 @@ /* - * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. - * Copyright 2012, 2013 SAP AG. All rights reserved. + * Copyright (c) 1997, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright 2012, 2014 SAP AG. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -100,10 +100,7 @@ MacroAssembler* a = new MacroAssembler(&cb); // Patch the call. - if (ReoptimizeCallSequences && - a->is_within_range_of_b(dest, addr_call)) { - a->bl(dest); - } else { + if (!ReoptimizeCallSequences || !a->is_within_range_of_b(dest, addr_call)) { address trampoline_stub_addr = get_trampoline(); // We did not find a trampoline stub because the current codeblob @@ -115,9 +112,12 @@ // Patch the constant in the call's trampoline stub. NativeCallTrampolineStub_at(trampoline_stub_addr)->set_destination(dest); + dest = trampoline_stub_addr; + } - a->bl(trampoline_stub_addr); - } + OrderAccess::release(); + a->bl(dest); + ICache::ppc64_flush_icache_bytes(addr_call, code_size); } @@ -147,9 +147,9 @@ address addr = addr_at(0); if (!NativeCall::is_call_at(addr)) { - tty->print_cr("not a NativeCall at " PTR_FORMAT, addr); + tty->print_cr("not a NativeCall at " PTR_FORMAT, p2i(addr)); // TODO: PPC port: Disassembler::decode(addr - 20, addr + 20, tty); - fatal(err_msg("not a NativeCall at " PTR_FORMAT, addr)); + fatal(err_msg("not a NativeCall at " PTR_FORMAT, p2i(addr))); } } #endif // ASSERT @@ -160,9 +160,9 @@ NativeInstruction::verify(); if (!NativeFarCall::is_far_call_at(addr)) { - tty->print_cr("not a NativeFarCall at " PTR_FORMAT, addr); + tty->print_cr("not a NativeFarCall at " PTR_FORMAT, p2i(addr)); // TODO: PPC port: Disassembler::decode(addr, 20, 20, tty); - fatal(err_msg("not a NativeFarCall at " PTR_FORMAT, addr)); + fatal(err_msg("not a NativeFarCall at " PTR_FORMAT, p2i(addr))); } } #endif // ASSERT @@ -306,9 +306,9 @@ if (! (cb != NULL && MacroAssembler::is_calculate_address_from_global_toc_at(addr, cb->content_begin())) && ! (cb != NULL && MacroAssembler::is_set_narrow_oop(addr, cb->content_begin())) && ! MacroAssembler::is_bl(*((int*) addr))) { - tty->print_cr("not a NativeMovConstReg at " PTR_FORMAT, addr); + tty->print_cr("not a NativeMovConstReg at " PTR_FORMAT, p2i(addr)); // TODO: PPC port: Disassembler::decode(addr, 20, 20, tty); - fatal(err_msg("not a NativeMovConstReg at " PTR_FORMAT, addr)); + fatal(err_msg("not a NativeMovConstReg at " PTR_FORMAT, p2i(addr))); } } } @@ -344,9 +344,9 @@ NativeInstruction::verify(); if (!NativeJump::is_jump_at(addr)) { - tty->print_cr("not a NativeJump at " PTR_FORMAT, addr); + tty->print_cr("not a NativeJump at " PTR_FORMAT, p2i(addr)); // TODO: PPC port: Disassembler::decode(addr, 20, 20, tty); - fatal(err_msg("not a NativeJump at " PTR_FORMAT, addr)); + fatal(err_msg("not a NativeJump at " PTR_FORMAT, p2i(addr))); } } #endif // ASSERT
--- a/src/cpu/ppc/vm/ppc.ad Thu Jan 08 12:47:32 2015 +0000 +++ b/src/cpu/ppc/vm/ppc.ad Tue Feb 03 16:48:05 2015 +0000 @@ -1330,7 +1330,7 @@ if (!false /* TODO: PPC port C->is_frameless_method()*/) { st->print("save return pc\n\t"); - st->print("push frame %d\n\t", -framesize); + st->print("push frame %ld\n\t", -framesize); } } #endif @@ -1938,8 +1938,9 @@ // -------------------------------------------------------------------- // Check for hi bits still needing moving. Only happens for misaligned // arguments to native calls. - if (src_hi == dst_hi) + if (src_hi == dst_hi) { return ppc64Opcode_none; // Self copy; no move. + } ShouldNotReachHere(); return ppc64Opcode_undefined; @@ -1961,14 +1962,15 @@ } uint MachNopNode::size(PhaseRegAlloc *ra_) const { - return _count * 4; + return _count * 4; } #ifndef PRODUCT void BoxLockNode::format(PhaseRegAlloc *ra_, outputStream *st) const { int offset = ra_->reg2offset(in_RegMask(0).find_first_elem()); - int reg = ra_->get_reg_first(this); - st->print("ADDI %s, SP, %d \t// box node", Matcher::regName[reg], offset); + char reg_str[128]; + ra_->dump_register(this, reg_str); + st->print("ADDI %s, SP, %d \t// box node", reg_str, offset); } #endif
--- a/src/cpu/ppc/vm/templateInterpreter_ppc.cpp Thu Jan 08 12:47:32 2015 +0000 +++ b/src/cpu/ppc/vm/templateInterpreter_ppc.cpp Tue Feb 03 16:48:05 2015 +0000 @@ -90,7 +90,7 @@ // Thread will be loaded to R3_ARG1. // Target class oop is in register R5_ARG3 by convention! - __ call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::throw_ClassCastException_verbose, R17_tos, R5_ARG3)); + __ call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::throw_ClassCastException_verbose), R17_tos, R5_ARG3); // Above call must not return here since exception pending. DEBUG_ONLY(__ should_not_reach_here();) return entry; @@ -171,6 +171,10 @@ // Compiled code destroys templateTableBase, reload. __ load_const_optimized(R25_templateTableBase, (address)Interpreter::dispatch_table((TosState)0), R12_scratch2); + if (state == atos) { + __ profile_return_type(R3_RET, R11_scratch1, R12_scratch2); + } + const Register cache = R11_scratch1; const Register size = R12_scratch2; __ get_cache_and_index_at_bcp(cache, 1, index_size); @@ -1230,6 +1234,10 @@ __ li(R0, 1); __ stb(R0, in_bytes(JavaThread::do_not_unlock_if_synchronized_offset()), R16_thread); } + + // Argument and return type profiling. + __ profile_parameters_type(R3_ARG1, R4_ARG2, R5_ARG3, R6_ARG4); + // Increment invocation counter and check for overflow. if (inc_counter) { generate_counter_incr(&invocation_counter_overflow, &profile_method, &profile_method_continue); @@ -1549,6 +1557,8 @@ __ resize_frame_absolute(R12_scratch2, R11_scratch1, R0); if (ProfileInterpreter) { __ set_method_data_pointer_for_bcp(); + __ ld(R11_scratch1, 0, R1_SP); + __ std(R28_mdx, _ijava_state_neg(mdx), R11_scratch1); } #if INCLUDE_JVMTI Label L_done; @@ -1560,13 +1570,11 @@ // The member name argument must be restored if _invokestatic is re-executed after a PopFrame call. // Detect such a case in the InterpreterRuntime function and return the member name argument, or NULL. __ ld(R4_ARG2, 0, R18_locals); - __ call_VM(R11_scratch1, CAST_FROM_FN_PTR(address, InterpreterRuntime::member_name_arg_or_null), - R4_ARG2, R19_method, R14_bcp); - - __ cmpdi(CCR0, R11_scratch1, 0); + __ MacroAssembler::call_VM(R4_ARG2, CAST_FROM_FN_PTR(address, InterpreterRuntime::member_name_arg_or_null), R4_ARG2, R19_method, R14_bcp, false); + __ restore_interpreter_state(R11_scratch1, /*bcp_and_mdx_only*/ true); + __ cmpdi(CCR0, R4_ARG2, 0); __ beq(CCR0, L_done); - - __ std(R11_scratch1, wordSize, R15_esp); + __ std(R4_ARG2, wordSize, R15_esp); __ bind(L_done); #endif // INCLUDE_JVMTI __ dispatch_next(vtos);
--- a/src/cpu/ppc/vm/templateTable_ppc_64.cpp Thu Jan 08 12:47:32 2015 +0000 +++ b/src/cpu/ppc/vm/templateTable_ppc_64.cpp Tue Feb 03 16:48:05 2015 +0000 @@ -3234,6 +3234,8 @@ // Load target. __ addi(Rrecv_klass, Rrecv_klass, base + vtableEntry::method_offset_in_bytes()); __ ldx(Rtarget_method, Rindex, Rrecv_klass); + // Argument and return type profiling. + __ profile_arguments_type(Rtarget_method, Rrecv_klass /* scratch1 */, Rtemp /* scratch2 */, true); __ call_from_interpreter(Rtarget_method, Rret, Rrecv_klass /* scratch1 */, Rtemp /* scratch2 */); } @@ -3317,6 +3319,8 @@ __ null_check_throw(Rrecv, -1, Rscratch1); __ profile_final_call(Rrecv, Rscratch1); + // Argument and return type profiling. + __ profile_arguments_type(Rmethod, Rscratch1, Rscratch2, true); // Do the call. __ call_from_interpreter(Rmethod, Rret_addr, Rscratch1, Rscratch2); @@ -3338,6 +3342,8 @@ __ null_check_throw(Rreceiver, -1, R11_scratch1); __ profile_call(R11_scratch1, R12_scratch2); + // Argument and return type profiling. + __ profile_arguments_type(Rmethod, R11_scratch1, R12_scratch2, false); __ call_from_interpreter(Rmethod, Rret_addr, R11_scratch1, R12_scratch2); } @@ -3352,6 +3358,8 @@ prepare_invoke(byte_no, R19_method, Rret_addr, noreg, noreg, Rflags, R11_scratch1); __ profile_call(R11_scratch1, R12_scratch2); + // Argument and return type profiling. + __ profile_arguments_type(R19_method, R11_scratch1, R12_scratch2, false); __ call_from_interpreter(R19_method, Rret_addr, R11_scratch1, R12_scratch2); } @@ -3373,6 +3381,8 @@ // Final call case. __ profile_final_call(Rtemp1, Rscratch); + // Argument and return type profiling. + __ profile_arguments_type(Rindex, Rscratch, Rrecv_klass /* scratch */, true); // Do the final call - the index (f2) contains the method. __ call_from_interpreter(Rindex, Rret, Rscratch, Rrecv_klass /* scratch */); @@ -3424,6 +3434,8 @@ __ cmpdi(CCR0, Rindex, 0); __ beq(CCR0, Lthrow_ame); // Found entry. Jump off! + // Argument and return type profiling. + __ profile_arguments_type(Rindex, Rscratch1, Rscratch2, true); __ call_from_interpreter(Rindex, Rret_addr, Rscratch1, Rscratch2); // Vtable entry was NULL => Throw abstract method error. @@ -3477,6 +3489,8 @@ // to be the callsite object the bootstrap method returned. This is passed to a // "link" method which does the dispatch (Most likely just grabs the MH stored // inside the callsite and does an invokehandle). + // Argument and return type profiling. + __ profile_arguments_type(Rmethod, Rscratch1, Rscratch2, false); __ call_from_interpreter(Rmethod, Rret_addr, Rscratch1 /* scratch1 */, Rscratch2 /* scratch2 */); } @@ -3503,6 +3517,8 @@ __ profile_final_call(Rrecv, Rscratch1); // Still no call from handle => We call the method handle interpreter here. + // Argument and return type profiling. + __ profile_arguments_type(Rmethod, Rscratch1, Rscratch2, true); __ call_from_interpreter(Rmethod, Rret_addr, Rscratch1 /* scratch1 */, Rscratch2 /* scratch2 */); }
--- a/src/cpu/ppc/vm/vm_version_ppc.cpp Thu Jan 08 12:47:32 2015 +0000 +++ b/src/cpu/ppc/vm/vm_version_ppc.cpp Tue Feb 03 16:48:05 2015 +0000 @@ -139,13 +139,44 @@ } assert(AllocatePrefetchLines > 0, "invalid value"); - if (AllocatePrefetchLines < 1) // Set valid value in product VM. + if (AllocatePrefetchLines < 1) { // Set valid value in product VM. AllocatePrefetchLines = 1; // Conservative value. + } - if (AllocatePrefetchStyle == 3 && AllocatePrefetchDistance < cache_line_size) + if (AllocatePrefetchStyle == 3 && AllocatePrefetchDistance < cache_line_size) { AllocatePrefetchStyle = 1; // Fall back if inappropriate. + } assert(AllocatePrefetchStyle >= 0, "AllocatePrefetchStyle should be positive"); + + if (UseCRC32Intrinsics) { + if (!FLAG_IS_DEFAULT(UseCRC32Intrinsics)) + warning("CRC32 intrinsics are not available on this CPU"); + FLAG_SET_DEFAULT(UseCRC32Intrinsics, false); + } + + // The AES intrinsic stubs require AES instruction support. + if (UseAES) { + warning("AES instructions are not available on this CPU"); + FLAG_SET_DEFAULT(UseAES, false); + } + if (UseAESIntrinsics) { + if (!FLAG_IS_DEFAULT(UseAESIntrinsics)) + warning("AES intrinsics are not available on this CPU"); + FLAG_SET_DEFAULT(UseAESIntrinsics, false); + } + + if (UseSHA) { + warning("SHA instructions are not available on this CPU"); + FLAG_SET_DEFAULT(UseSHA, false); + } + if (UseSHA1Intrinsics || UseSHA256Intrinsics || UseSHA512Intrinsics) { + warning("SHA intrinsics are not available on this CPU"); + FLAG_SET_DEFAULT(UseSHA1Intrinsics, false); + FLAG_SET_DEFAULT(UseSHA256Intrinsics, false); + FLAG_SET_DEFAULT(UseSHA512Intrinsics, false); + } + } void VM_Version::print_features() { @@ -352,7 +383,7 @@ if (PrintAssembly) { ttyLocker ttyl; - tty->print_cr("Decoding section size detection stub at " INTPTR_FORMAT " before execution:", code); + tty->print_cr("Decoding section size detection stub at " INTPTR_FORMAT " before execution:", p2i(code)); Disassembler::decode((u_char*)code, (u_char*)code_end, tty); tty->print_cr("Time loop1 :%f", loop1_seconds); tty->print_cr("Time loop2 :%f", loop2_seconds); @@ -435,7 +466,7 @@ // Print the detection code. if (PrintAssembly) { ttyLocker ttyl; - tty->print_cr("Decoding cpu-feature detection stub at " INTPTR_FORMAT " before execution:", code); + tty->print_cr("Decoding cpu-feature detection stub at " INTPTR_FORMAT " before execution:", p2i(code)); Disassembler::decode((u_char*)code, (u_char*)code_end, tty); } @@ -468,7 +499,7 @@ // Print the detection code. if (PrintAssembly) { ttyLocker ttyl; - tty->print_cr("Decoding cpu-feature detection stub at " INTPTR_FORMAT " after execution:", code); + tty->print_cr("Decoding cpu-feature detection stub at " INTPTR_FORMAT " after execution:", p2i(code)); Disassembler::decode((u_char*)code, (u_char*)code_end, tty); }
--- a/src/cpu/x86/vm/c1_Runtime1_x86.cpp Thu Jan 08 12:47:32 2015 +0000 +++ b/src/cpu/x86/vm/c1_Runtime1_x86.cpp Tue Feb 03 16:48:05 2015 +0000 @@ -675,7 +675,7 @@ case handle_exception_nofpu_id: case handle_exception_id: // At this point all registers MAY be live. - oop_map = save_live_registers(sasm, 1 /*thread*/, id == handle_exception_nofpu_id); + oop_map = save_live_registers(sasm, 1 /*thread*/, id != handle_exception_nofpu_id); break; case handle_exception_from_callee_id: { // At this point all registers except exception oop (RAX) and @@ -748,7 +748,7 @@ case handle_exception_nofpu_id: case handle_exception_id: // Restore the registers that were saved at the beginning. - restore_live_registers(sasm, id == handle_exception_nofpu_id); + restore_live_registers(sasm, id != handle_exception_nofpu_id); break; case handle_exception_from_callee_id: // WIN64_ONLY: No need to add frame::arg_reg_save_area_bytes to SP
--- a/src/cpu/x86/vm/macroAssembler_x86.cpp Thu Jan 08 12:47:32 2015 +0000 +++ b/src/cpu/x86/vm/macroAssembler_x86.cpp Tue Feb 03 16:48:05 2015 +0000 @@ -1769,7 +1769,7 @@ // at [FETCH], below, will never observe a biased encoding (*101b). // If this invariant is not held we risk exclusion (safety) failure. if (UseBiasedLocking && !UseOptoBiasInlining) { - biased_locking_enter(boxReg, objReg, tmpReg, scrReg, true, DONE_LABEL, NULL, counters); + biased_locking_enter(boxReg, objReg, tmpReg, scrReg, false, DONE_LABEL, NULL, counters); } #if INCLUDE_RTM_OPT
--- a/src/os/aix/vm/os_aix.cpp Thu Jan 08 12:47:32 2015 +0000 +++ b/src/os/aix/vm/os_aix.cpp Tue Feb 03 16:48:05 2015 +0000 @@ -114,12 +114,6 @@ } #endif -// Excerpts from systemcfg.h definitions newer than AIX 5.3 -#ifndef PV_7 -# define PV_7 0x200000 // Power PC 7 -# define PV_7_Compat 0x208000 // Power PC 7 -#endif - #define MAX_PATH (2 * K) // for timer info max values which include all bits @@ -130,17 +124,40 @@ #define ERROR_MP_VMGETINFO_FAILED 102 #define ERROR_MP_VMGETINFO_CLAIMS_NO_SUPPORT_FOR_64K 103 -// the semantics in this file are thus that codeptr_t is a *real code ptr* +// The semantics in this file are thus that codeptr_t is a *real code ptr*. // This means that any function taking codeptr_t as arguments will assume // a real codeptr and won't handle function descriptors (eg getFuncName), // whereas functions taking address as args will deal with function -// descriptors (eg os::dll_address_to_library_name) +// descriptors (eg os::dll_address_to_library_name). typedef unsigned int* codeptr_t; -// typedefs for stackslots, stack pointers, pointers to op codes +// Typedefs for stackslots, stack pointers, pointers to op codes. typedef unsigned long stackslot_t; typedef stackslot_t* stackptr_t; +// Excerpts from systemcfg.h definitions newer than AIX 5.3. +#ifndef PV_7 +#define PV_7 0x200000 /* Power PC 7 */ +#define PV_7_Compat 0x208000 /* Power PC 7 */ +#endif +#ifndef PV_8 +#define PV_8 0x300000 /* Power PC 8 */ +#define PV_8_Compat 0x308000 /* Power PC 8 */ +#endif + +#define trcVerbose(fmt, ...) { /* PPC port */ \ + if (Verbose) { \ + fprintf(stderr, fmt, ##__VA_ARGS__); \ + fputc('\n', stderr); fflush(stderr); \ + } \ +} +#define trc(fmt, ...) /* PPC port */ + +#define ERRBYE(s) { \ + trcVerbose(s); \ + return -1; \ +} + // query dimensions of the stack of the calling thread static void query_stack_dimensions(address* p_stack_base, size_t* p_stack_size); @@ -172,12 +189,12 @@ return true; } -// macro to check a given stack pointer against given stack limits and to die if test fails +// Macro to check a given stack pointer against given stack limits and to die if test fails. #define CHECK_STACK_PTR(sp, stack_base, stack_size) { \ guarantee(is_valid_stackpointer((stackptr_t)(sp), (stackptr_t)(stack_base), stack_size), "Stack Pointer Invalid"); \ } -// macro to check the current stack pointer against given stacklimits +// Macro to check the current stack pointer against given stacklimits. #define CHECK_CURRENT_STACK_PTR(stack_base, stack_size) { \ address sp; \ sp = os::current_stack_pointer(); \ @@ -211,7 +228,7 @@ static pid_t _initial_pid = 0; static int SR_signum = SIGUSR2; // Signal used to suspend/resume a thread (must be > SIGSEGV, see 4355769) static sigset_t SR_sigset; -static pthread_mutex_t dl_mutex; // Used to protect dlsym() calls */ +static pthread_mutex_t dl_mutex; // Used to protect dlsym() calls. julong os::available_memory() { return Aix::available_memory(); @@ -243,7 +260,6 @@ return false; } - // Return true if user is running as root. bool os::have_special_privileges() { @@ -274,8 +290,7 @@ for (int i = 0; i < numFullDisclaimsNeeded; i ++) { if (::disclaim(p, maxDisclaimSize, DISCLAIM_ZEROMEM) != 0) { - //if (Verbose) - fprintf(stderr, "Cannot disclaim %p - %p (errno %d)\n", p, p + maxDisclaimSize, errno); + trc("Cannot disclaim %p - %p (errno %d)\n", p, p + maxDisclaimSize, errno); return false; } p += maxDisclaimSize; @@ -283,8 +298,7 @@ if (lastDisclaimSize > 0) { if (::disclaim(p, lastDisclaimSize, DISCLAIM_ZEROMEM) != 0) { - //if (Verbose) - fprintf(stderr, "Cannot disclaim %p - %p (errno %d)\n", p, p + lastDisclaimSize, errno); + trc("Cannot disclaim %p - %p (errno %d)\n", p, p + lastDisclaimSize, errno); return false; } } @@ -324,11 +338,11 @@ void os::Aix::initialize_system_info() { - // get the number of online(logical) cpus instead of configured + // Get the number of online(logical) cpus instead of configured. os::_processor_count = sysconf(_SC_NPROCESSORS_ONLN); assert(_processor_count > 0, "_processor_count must be > 0"); - // retrieve total physical storage + // Retrieve total physical storage. os::Aix::meminfo_t mi; if (!os::Aix::get_meminfo(&mi)) { fprintf(stderr, "os::Aix::get_meminfo failed.\n"); fflush(stderr); @@ -503,7 +517,6 @@ } // end os::Aix::query_multipage_support() -// The code for this method was initially derived from the version in os_linux.cpp. void os::init_system_properties_values() { #define DEFAULT_LIBPATH "/usr/lib:/lib" @@ -600,10 +613,11 @@ sigaction(sig, (struct sigaction*)NULL, &oact); void* ohlr = oact.sa_sigaction ? CAST_FROM_FN_PTR(void*, oact.sa_sigaction) : CAST_FROM_FN_PTR(void*, oact.sa_handler); - if (ohlr == CAST_FROM_FN_PTR(void*, SIG_IGN)) + if (ohlr == CAST_FROM_FN_PTR(void*, SIG_IGN)) { return true; - else + } else { return false; + } } void os::Aix::signal_sets_init() { @@ -777,6 +791,9 @@ // get the processor version from _system_configuration switch (_system_configuration.version) { + case PV_8: + strcpy(pci->version, "Power PC 8"); + break; case PV_7: strcpy(pci->version, "Power PC 7"); break; @@ -804,6 +821,9 @@ case PV_7_Compat: strcpy(pci->version, "PV_7_Compat"); break; + case PV_8_Compat: + strcpy(pci->version, "PV_8_Compat"); + break; default: strcpy(pci->version, "unknown"); } @@ -939,7 +959,9 @@ pthread_attr_destroy(&attr); - if (ret != 0) { + if (ret == 0) { + // PPC port traceOsMisc(("Created New Thread : pthread-id %u", tid)); + } else { if (PrintMiscellaneous && (Verbose || WizardMode)) { perror("pthread_create()"); } @@ -1096,8 +1118,7 @@ if (os::Aix::on_pase()) { Unimplemented(); return 0; - } - else { + } else { // On AIX use the precision of processors real time clock // or time base registers. timebasestruct_t time; @@ -1150,7 +1171,6 @@ } } - char * os::local_time_string(char *buf, size_t buflen) { struct tm t; time_t long_time; @@ -1188,7 +1208,6 @@ if (abort_hook != NULL) { abort_hook(); } - } // Note: os::abort() might be called very early during initialization, or @@ -1220,8 +1239,7 @@ // from src/solaris/hpi/src/system_md.c size_t os::lasterror(char *buf, size_t len) { - - if (errno == 0) return 0; + if (errno == 0) return 0; const char *s = ::strerror(errno); size_t n = ::strlen(s); @@ -1234,6 +1252,7 @@ } intx os::current_thread_id() { return (intx)pthread_self(); } + int os::current_process_id() { // This implementation returns a unique pid, the pid of the @@ -1370,9 +1389,9 @@ if (offset) { *offset = -1; } - if (buf) { - buf[0] = '\0'; - } + // Buf is not optional, but offset is optional. + assert(buf != NULL, "sanity check"); + buf[0] = '\0'; // Resolve function ptr literals first. addr = resolve_function_descriptor_to_code_pointer(addr); @@ -1405,12 +1424,9 @@ return 0; } - if (Verbose) { - fprintf(stderr, "pc outside any module"); - } + trcVerbose("pc outside any module"); return -1; - } bool os::dll_address_to_library_name(address addr, char* buf, @@ -1418,9 +1434,9 @@ if (offset) { *offset = -1; } - if (buf) { - buf[0] = '\0'; - } + // Buf is not optional, but offset is optional. + assert(buf != NULL, "sanity check"); + buf[0] = '\0'; // Resolve function ptr literals first. addr = resolve_function_descriptor_to_code_pointer(addr); @@ -1435,7 +1451,7 @@ } // Loads .dll/.so and in case of error it checks if .dll/.so was built -// for the same architecture as Hotspot is running on +// for the same architecture as Hotspot is running on. void *os::dll_load(const char *filename, char *ebuf, int ebuflen) { if (ebuf && ebuflen > 0) { @@ -1598,7 +1614,6 @@ st->cr(); } - static void print_signal_handler(outputStream* st, int sig, char* buf, size_t buflen); @@ -1622,7 +1637,7 @@ static char saved_jvm_path[MAXPATHLEN] = {0}; -// Find the full path to the current module, libjvm.so or libjvm_g.so +// Find the full path to the current module, libjvm.so. void os::jvm_path(char *buf, jint buflen) { // Error checking. if (buflen < MAXPATHLEN) { @@ -1692,7 +1707,7 @@ // Do not block out synchronous signals in the signal handler. // Blocking synchronous signals only makes sense if you can really // be sure that those signals won't happen during signal handling, - // when the blocking applies. Normal signal handlers are lean and + // when the blocking applies. Normal signal handlers are lean and // do not cause signals. But our signal handlers tend to be "risky" // - secondary SIGSEGV, SIGILL, SIGBUS' may and do happen. // On AIX, PASE there was a case where a SIGSEGV happened, followed @@ -2967,13 +2982,9 @@ param.sched_priority = newpri; int ret = pthread_setschedparam(thr, policy, ¶m); - if (Verbose) { - if (ret == 0) { - fprintf(stderr, "changed priority of thread %d to %d\n", (int)thr, newpri); - } else { - fprintf(stderr, "Could not changed priority for thread %d to %d (error %d, %s)\n", - (int)thr, newpri, ret, strerror(ret)); - } + if (ret != 0) { + trcVerbose("Could not change priority for thread %d to %d (error %d, %s)", + (int)thr, newpri, ret, strerror(ret)); } return (ret == 0) ? OS_OK : OS_ERR; } @@ -3094,7 +3105,6 @@ errno = old_errno; } - static int SR_initialize() { struct sigaction act; char *s; @@ -3337,7 +3347,6 @@ JVM_handle_aix_signal(sig, info, uc, true); } - // This boolean allows users to forward their own non-matching signals // to JVM_handle_aix_signal, harmlessly. bool os::Aix::signal_handlers_are_installed = false; @@ -3531,7 +3540,7 @@ set_signal_handler(SIGDANGER, true); if (libjsig_is_loaded) { - // Tell libjsig jvm finishes setting signal handlers + // Tell libjsig jvm finishes setting signal handlers. (*end_signal_setting)(); } @@ -3547,7 +3556,7 @@ tty->print_cr("Info: AllowUserSignalHandlers is activated, all active signal checking is disabled"); check_signals = false; } - // need to initialize check_signal_done + // Need to initialize check_signal_done. ::sigemptyset(&check_signal_done); } } @@ -3621,7 +3630,6 @@ st->cr(); } - #define DO_SIGNAL_CHECK(sig) \ if (!sigismember(&check_signal_done, sig)) \ os::Aix::check_signal_handler(sig) @@ -3682,7 +3690,6 @@ ? CAST_FROM_FN_PTR(address, act.sa_sigaction) : CAST_FROM_FN_PTR(address, act.sa_handler); - switch(sig) { case SIGSEGV: case SIGBUS: @@ -3830,15 +3837,13 @@ pthread_mutex_init(&dl_mutex, NULL); } -// this is called _after_ the global arguments have been parsed +// This is called _after_ the global arguments have been parsed. jint os::init_2(void) { - if (Verbose) { - fprintf(stderr, "processor count: %d\n", os::_processor_count); - fprintf(stderr, "physical memory: %lu\n", Aix::_physical_memory); - } - - // initially build up the loaded dll map + trcVerbose("processor count: %d", os::_processor_count); + trcVerbose("physical memory: %lu", Aix::_physical_memory); + + // Initially build up the loaded dll map. LoadedLibraries::reload(); const int page_size = Aix::page_size(); @@ -3888,7 +3893,7 @@ } if (map_address != (address) MAP_FAILED) { - // map succeeded, but polling_page is not at wished address, unmap and continue. + // Map succeeded, but polling_page is not at wished address, unmap and continue. ::munmap(map_address, map_size); map_address = (address) MAP_FAILED; } @@ -3942,7 +3947,7 @@ // Make the stack size a multiple of the page size so that // the yellow/red zones can be guarded. - // note that this can be 0, if no default stacksize was set + // Note that this can be 0, if no default stacksize was set. JavaThread::set_stack_size_at_create(round_to(threadStackSizeInBytes, vm_page_size())); Aix::libpthread_init(); @@ -4255,7 +4260,6 @@ return fd; } - // create binary file, rewriting existing file if required int os::create_binary_file(const char* path, bool rewrite_existing) { int oflags = O_WRONLY | O_CREAT; @@ -4324,7 +4328,6 @@ return NULL; } - // Remap a block of memory. char* os::pd_remap_memory(int fd, const char* file_name, size_t file_offset, char *addr, size_t bytes, bool read_only, @@ -4372,14 +4375,14 @@ jlong sys_time = 0; jlong user_time = 0; - // reimplemented using getthrds64(). + // Reimplemented using getthrds64(). // - // goes like this: + // Works like this: // For the thread in question, get the kernel thread id. Then get the // kernel thread statistics using that id. // // This only works of course when no pthread scheduling is used, - // ie there is a 1:1 relationship to kernel threads. + // i.e. there is a 1:1 relationship to kernel threads. // On AIX, see AIXTHREAD_SCOPE variable. pthread_t pthtid = thread->osthread()->pthread_id(); @@ -4526,14 +4529,12 @@ memset(&uts, 0, sizeof(uts)); strcpy(uts.sysname, "?"); if (::uname(&uts) == -1) { - fprintf(stderr, "uname failed (%d)\n", errno); + trc("uname failed (%d)", errno); guarantee(0, "Could not determine whether we run on AIX or PASE"); } else { - if (Verbose) { - fprintf(stderr,"uname says: sysname \"%s\" version \"%s\" release \"%s\" " - "node \"%s\" machine \"%s\"\n", - uts.sysname, uts.version, uts.release, uts.nodename, uts.machine); - } + trcVerbose("uname says: sysname \"%s\" version \"%s\" release \"%s\" " + "node \"%s\" machine \"%s\"\n", + uts.sysname, uts.version, uts.release, uts.nodename, uts.machine); const int major = atoi(uts.version); assert(major > 0, "invalid OS version"); const int minor = atoi(uts.release); @@ -4545,12 +4546,10 @@ // We run on AIX. We do not support versions older than AIX 5.3. _on_pase = 0; if (_os_version < 0x0503) { - fprintf(stderr, "AIX release older than AIX 5.3 not supported.\n"); + trc("AIX release older than AIX 5.3 not supported."); assert(false, "AIX release too old."); } else { - if (Verbose) { - fprintf(stderr, "We run on AIX %d.%d\n", major, minor); - } + trcVerbose("We run on AIX %d.%d\n", major, minor); } } else { assert(false, "unknown OS"); @@ -4558,7 +4557,6 @@ } guarantee(_on_pase != -1 && _os_version, "Could not determine AIX/OS400 release"); - } // end: os::Aix::initialize_os_info() // Scan environment for important settings which might effect the VM. @@ -4596,12 +4594,10 @@ // Note: Setting XPG_SUS_ENV in the process is too late. Must be set earlier (before // exec() ? before loading the libjvm ? ....) p = ::getenv("XPG_SUS_ENV"); - if (Verbose) { - fprintf(stderr, "XPG_SUS_ENV=%s.\n", p ? p : "<unset>"); - } + trcVerbose("XPG_SUS_ENV=%s.", p ? p : "<unset>"); if (p && strcmp(p, "ON") == 0) { _xpg_sus_mode = 1; - fprintf(stderr, "Unsupported setting: XPG_SUS_ENV=ON\n"); + trc("Unsupported setting: XPG_SUS_ENV=ON"); // This is not supported. Worst of all, it changes behaviour of mmap MAP_FIXED to // clobber address ranges. If we ever want to support that, we have to do some // testing first. @@ -4613,10 +4609,7 @@ // Switch off AIX internal (pthread) guard pages. This has // immediate effect for any pthread_create calls which follow. p = ::getenv("AIXTHREAD_GUARDPAGES"); - if (Verbose) { - fprintf(stderr, "AIXTHREAD_GUARDPAGES=%s.\n", p ? p : "<unset>"); - fprintf(stderr, "setting AIXTHREAD_GUARDPAGES=0.\n"); - } + trcVerbose("AIXTHREAD_GUARDPAGES=%s.", p ? p : "<unset>"); rc = ::putenv("AIXTHREAD_GUARDPAGES=0"); guarantee(rc == 0, ""); @@ -4634,7 +4627,7 @@ assert(os::Aix::on_aix(), "AIX only"); if (!libperfstat::init()) { - fprintf(stderr, "libperfstat initialization failed.\n"); + trc("libperfstat initialization failed."); assert(false, "libperfstat initialization failed"); } else { if (Verbose) { @@ -4806,7 +4799,6 @@ return abstime; } - // Test-and-clear _Event, always leaves _Event set to 0, returns immediately. // Conceptually TryPark() should be equivalent to park(0). @@ -4889,7 +4881,7 @@ while (_Event < 0) { status = pthread_cond_timedwait(_cond, _mutex, &abst); assert_status(status == 0 || status == ETIMEDOUT, - status, "cond_timedwait"); + status, "cond_timedwait"); if (!FilterSpuriousWakeups) break; // previous semantics if (status == ETIMEDOUT) break; // We consume and ignore EINTR and spurious wakeups. @@ -5023,9 +5015,9 @@ // Optional fast-path check: // Return immediately if a permit is available. if (_counter > 0) { - _counter = 0; - OrderAccess::fence(); - return; + _counter = 0; + OrderAccess::fence(); + return; } Thread* thread = Thread::current(); @@ -5047,7 +5039,6 @@ unpackTime(&absTime, isAbsolute, time); } - // Enter safepoint region // Beware of deadlocks such as 6317397. // The per-thread Parker:: mutex is a classic leaf-lock. @@ -5135,7 +5126,6 @@ } } - extern char** environ; // Run the specified command in a separate process. Return its exit value, @@ -5154,44 +5144,43 @@ } else if (pid == 0) { // child process - // try to be consistent with system(), which uses "/usr/bin/sh" on AIX + // Try to be consistent with system(), which uses "/usr/bin/sh" on AIX. execve("/usr/bin/sh", argv, environ); // execve failed _exit(-1); - } else { + } else { // copied from J2SE ..._waitForProcessExit() in UNIXProcess_md.c; we don't // care about the actual exit code, for now. int status; - // Wait for the child process to exit. This returns immediately if + // Wait for the child process to exit. This returns immediately if // the child has already exited. */ while (waitpid(pid, &status, 0) < 0) { - switch (errno) { + switch (errno) { case ECHILD: return 0; case EINTR: break; default: return -1; - } + } } if (WIFEXITED(status)) { - // The child exited normally; get its exit code. - return WEXITSTATUS(status); + // The child exited normally; get its exit code. + return WEXITSTATUS(status); } else if (WIFSIGNALED(status)) { - // The child exited because of a signal - // The best value to return is 0x80 + signal number, - // because that is what all Unix shells do, and because - // it allows callers to distinguish between process exit and - // process death by signal. - return 0x80 + WTERMSIG(status); + // The child exited because of a signal. + // The best value to return is 0x80 + signal number, + // because that is what all Unix shells do, and because + // it allows callers to distinguish between process exit and + // process death by signal. + return 0x80 + WTERMSIG(status); } else { - // Unknown exit code; pass it through - return status; + // Unknown exit code; pass it through. + return status; } } - // Remove warning. return -1; } @@ -5206,7 +5195,7 @@ struct stat statbuf; char buf[MAXPATHLEN]; char libmawtpath[MAXPATHLEN]; - const char *xawtstr = "/xawt/libmawt.so"; + const char *xawtstr = "/xawt/libmawt.so"; const char *new_xawtstr = "/libawt_xawt.so"; char *p;
--- a/src/os/aix/vm/os_aix.hpp Thu Jan 08 12:47:32 2015 +0000 +++ b/src/os/aix/vm/os_aix.hpp Tue Feb 03 16:48:05 2015 +0000 @@ -209,7 +209,7 @@ return _can_use_16M_pages == 1 ? true : false; } - static address ucontext_get_pc(ucontext_t* uc); + static address ucontext_get_pc(const ucontext_t* uc); static intptr_t* ucontext_get_sp(ucontext_t* uc); static intptr_t* ucontext_get_fp(ucontext_t* uc); // Set PC into context. Needed for continuation after signal.
--- a/src/os/bsd/vm/perfMemory_bsd.cpp Thu Jan 08 12:47:32 2015 +0000 +++ b/src/os/bsd/vm/perfMemory_bsd.cpp Tue Feb 03 16:48:05 2015 +0000 @@ -197,7 +197,38 @@ } -// check if the given path is considered a secure directory for +// Check if the given statbuf is considered a secure directory for +// the backing store files. Returns true if the directory is considered +// a secure location. Returns false if the statbuf is a symbolic link or +// if an error occurred. +// +static bool is_statbuf_secure(struct stat *statp) { + if (S_ISLNK(statp->st_mode) || !S_ISDIR(statp->st_mode)) { + // The path represents a link or some non-directory file type, + // which is not what we expected. Declare it insecure. + // + return false; + } + // We have an existing directory, check if the permissions are safe. + // + if ((statp->st_mode & (S_IWGRP|S_IWOTH)) != 0) { + // The directory is open for writing and could be subjected + // to a symlink or a hard link attack. Declare it insecure. + // + return false; + } + // See if the uid of the directory matches the effective uid of the process. + // + if (statp->st_uid != geteuid()) { + // The directory was not created by this user, declare it insecure. + // + return false; + } + return true; +} + + +// Check if the given path is considered a secure directory for // the backing store files. Returns true if the directory exists // and is considered a secure location. Returns false if the path // is a symbolic link or if an error occurred. @@ -211,27 +242,185 @@ return false; } - // the path exists, now check it's mode - if (S_ISLNK(statbuf.st_mode) || !S_ISDIR(statbuf.st_mode)) { - // the path represents a link or some non-directory file type, - // which is not what we expected. declare it insecure. - // + // The path exists, see if it is secure. + return is_statbuf_secure(&statbuf); +} + + +// Check if the given directory file descriptor is considered a secure +// directory for the backing store files. Returns true if the directory +// exists and is considered a secure location. Returns false if the path +// is a symbolic link or if an error occurred. +// +static bool is_dirfd_secure(int dir_fd) { + struct stat statbuf; + int result = 0; + + RESTARTABLE(::fstat(dir_fd, &statbuf), result); + if (result == OS_ERR) { + return false; + } + + // The path exists, now check its mode. + return is_statbuf_secure(&statbuf); +} + + +// Check to make sure fd1 and fd2 are referencing the same file system object. +// +static bool is_same_fsobject(int fd1, int fd2) { + struct stat statbuf1; + struct stat statbuf2; + int result = 0; + + RESTARTABLE(::fstat(fd1, &statbuf1), result); + if (result == OS_ERR) { + return false; + } + RESTARTABLE(::fstat(fd2, &statbuf2), result); + if (result == OS_ERR) { + return false; + } + + if ((statbuf1.st_ino == statbuf2.st_ino) && + (statbuf1.st_dev == statbuf2.st_dev)) { + return true; + } else { return false; } - else { - // we have an existing directory, check if the permissions are safe. - // - if ((statbuf.st_mode & (S_IWGRP|S_IWOTH)) != 0) { - // the directory is open for writing and could be subjected - // to a symlnk attack. declare it insecure. - // - return false; +} + + +// Open the directory of the given path and validate it. +// Return a DIR * of the open directory. +// +static DIR *open_directory_secure(const char* dirname) { + // Open the directory using open() so that it can be verified + // to be secure by calling is_dirfd_secure(), opendir() and then check + // to see if they are the same file system object. This method does not + // introduce a window of opportunity for the directory to be attacked that + // calling opendir() and is_directory_secure() does. + int result; + DIR *dirp = NULL; + RESTARTABLE(::open(dirname, O_RDONLY|O_NOFOLLOW), result); + if (result == OS_ERR) { + // Directory doesn't exist or is a symlink, so there is nothing to cleanup. + if (PrintMiscellaneous && Verbose) { + if (errno == ELOOP) { + warning("directory %s is a symlink and is not secure\n", dirname); + } else { + warning("could not open directory %s: %s\n", dirname, strerror(errno)); + } } + return dirp; + } + int fd = result; + + // Determine if the open directory is secure. + if (!is_dirfd_secure(fd)) { + // The directory is not a secure directory. + os::close(fd); + return dirp; + } + + // Open the directory. + dirp = ::opendir(dirname); + if (dirp == NULL) { + // The directory doesn't exist, close fd and return. + os::close(fd); + return dirp; + } + + // Check to make sure fd and dirp are referencing the same file system object. + if (!is_same_fsobject(fd, dirfd(dirp))) { + // The directory is not secure. + os::close(fd); + os::closedir(dirp); + dirp = NULL; + return dirp; + } + + // Close initial open now that we know directory is secure + os::close(fd); + + return dirp; +} + +// NOTE: The code below uses fchdir(), open() and unlink() because +// fdopendir(), openat() and unlinkat() are not supported on all +// versions. Once the support for fdopendir(), openat() and unlinkat() +// is available on all supported versions the code can be changed +// to use these functions. + +// Open the directory of the given path, validate it and set the +// current working directory to it. +// Return a DIR * of the open directory and the saved cwd fd. +// +static DIR *open_directory_secure_cwd(const char* dirname, int *saved_cwd_fd) { + + // Open the directory. + DIR* dirp = open_directory_secure(dirname); + if (dirp == NULL) { + // Directory doesn't exist or is insecure, so there is nothing to cleanup. + return dirp; + } + int fd = dirfd(dirp); + + // Open a fd to the cwd and save it off. + int result; + RESTARTABLE(::open(".", O_RDONLY), result); + if (result == OS_ERR) { + *saved_cwd_fd = -1; + } else { + *saved_cwd_fd = result; + } + + // Set the current directory to dirname by using the fd of the directory. + result = fchdir(fd); + + return dirp; +} + +// Close the directory and restore the current working directory. +// +static void close_directory_secure_cwd(DIR* dirp, int saved_cwd_fd) { + + int result; + // If we have a saved cwd change back to it and close the fd. + if (saved_cwd_fd != -1) { + result = fchdir(saved_cwd_fd); + ::close(saved_cwd_fd); + } + + // Close the directory. + os::closedir(dirp); +} + +// Check if the given file descriptor is considered a secure. +// +static bool is_file_secure(int fd, const char *filename) { + + int result; + struct stat statbuf; + + // Determine if the file is secure. + RESTARTABLE(::fstat(fd, &statbuf), result); + if (result == OS_ERR) { + if (PrintMiscellaneous && Verbose) { + warning("fstat failed on %s: %s\n", filename, strerror(errno)); + } + return false; + } + if (statbuf.st_nlink > 1) { + // A file with multiple links is not expected. + if (PrintMiscellaneous && Verbose) { + warning("file %s has multiple links\n", filename); + } + return false; } return true; } - // return the user name for the given user id // // the caller is expected to free the allocated memory. @@ -317,9 +506,11 @@ const char* tmpdirname = os::get_temp_directory(); + // open the temp directory DIR* tmpdirp = os::opendir(tmpdirname); if (tmpdirp == NULL) { + // Cannot open the directory to get the user name, return. return NULL; } @@ -344,25 +535,14 @@ strcat(usrdir_name, "/"); strcat(usrdir_name, dentry->d_name); - DIR* subdirp = os::opendir(usrdir_name); + // open the user directory + DIR* subdirp = open_directory_secure(usrdir_name); if (subdirp == NULL) { FREE_C_HEAP_ARRAY(char, usrdir_name, mtInternal); continue; } - // Since we don't create the backing store files in directories - // pointed to by symbolic links, we also don't follow them when - // looking for the files. We check for a symbolic link after the - // call to opendir in order to eliminate a small window where the - // symlink can be exploited. - // - if (!is_directory_secure(usrdir_name)) { - FREE_C_HEAP_ARRAY(char, usrdir_name, mtInternal); - os::closedir(subdirp); - continue; - } - struct dirent* udentry; char* udbuf = NEW_C_HEAP_ARRAY(char, os::readdir_buf_size(usrdir_name), mtInternal); errno = 0; @@ -465,26 +645,6 @@ } -// remove file -// -// this method removes the file with the given file name in the -// named directory. -// -static void remove_file(const char* dirname, const char* filename) { - - size_t nbytes = strlen(dirname) + strlen(filename) + 2; - char* path = NEW_C_HEAP_ARRAY(char, nbytes, mtInternal); - - strcpy(path, dirname); - strcat(path, "/"); - strcat(path, filename); - - remove_file(path); - - FREE_C_HEAP_ARRAY(char, path, mtInternal); -} - - // cleanup stale shared memory resources // // This method attempts to remove all stale shared memory files in @@ -496,16 +656,11 @@ // static void cleanup_sharedmem_resources(const char* dirname) { - // open the user temp directory - DIR* dirp = os::opendir(dirname); - + int saved_cwd_fd; + // open the directory and set the current working directory to it + DIR* dirp = open_directory_secure_cwd(dirname, &saved_cwd_fd); if (dirp == NULL) { - // directory doesn't exist, so there is nothing to cleanup - return; - } - - if (!is_directory_secure(dirname)) { - // the directory is not a secure directory + // directory doesn't exist or is insecure, so there is nothing to cleanup return; } @@ -519,6 +674,7 @@ // struct dirent* entry; char* dbuf = NEW_C_HEAP_ARRAY(char, os::readdir_buf_size(dirname), mtInternal); + errno = 0; while ((entry = os::readdir(dirp, (struct dirent *)dbuf)) != NULL) { @@ -529,7 +685,7 @@ if (strcmp(entry->d_name, ".") != 0 && strcmp(entry->d_name, "..") != 0) { // attempt to remove all unexpected files, except "." and ".." - remove_file(dirname, entry->d_name); + unlink(entry->d_name); } errno = 0; @@ -552,11 +708,14 @@ if ((pid == os::current_process_id()) || (kill(pid, 0) == OS_ERR && (errno == ESRCH || errno == EPERM))) { - remove_file(dirname, entry->d_name); + unlink(entry->d_name); } errno = 0; } - os::closedir(dirp); + + // close the directory and reset the current working directory + close_directory_secure_cwd(dirp, saved_cwd_fd); + FREE_C_HEAP_ARRAY(char, dbuf, mtInternal); } @@ -613,19 +772,54 @@ return -1; } - int result; + int saved_cwd_fd; + // open the directory and set the current working directory to it + DIR* dirp = open_directory_secure_cwd(dirname, &saved_cwd_fd); + if (dirp == NULL) { + // Directory doesn't exist or is insecure, so cannot create shared + // memory file. + return -1; + } - RESTARTABLE(::open(filename, O_RDWR|O_CREAT|O_TRUNC, S_IREAD|S_IWRITE), result); + // Open the filename in the current directory. + // Cannot use O_TRUNC here; truncation of an existing file has to happen + // after the is_file_secure() check below. + int result; + RESTARTABLE(::open(filename, O_RDWR|O_CREAT|O_NOFOLLOW, S_IREAD|S_IWRITE), result); if (result == OS_ERR) { if (PrintMiscellaneous && Verbose) { - warning("could not create file %s: %s\n", filename, strerror(errno)); + if (errno == ELOOP) { + warning("file %s is a symlink and is not secure\n", filename); + } else { + warning("could not create file %s: %s\n", filename, strerror(errno)); + } } + // close the directory and reset the current working directory + close_directory_secure_cwd(dirp, saved_cwd_fd); + return -1; } + // close the directory and reset the current working directory + close_directory_secure_cwd(dirp, saved_cwd_fd); // save the file descriptor int fd = result; + // check to see if the file is secure + if (!is_file_secure(fd, filename)) { + ::close(fd); + return -1; + } + + // truncate the file to get rid of any existing data + RESTARTABLE(::ftruncate(fd, (off_t)0), result); + if (result == OS_ERR) { + if (PrintMiscellaneous && Verbose) { + warning("could not truncate shared memory file: %s\n", strerror(errno)); + } + ::close(fd); + return -1; + } // set the file size RESTARTABLE(::ftruncate(fd, (off_t)size), result); if (result == OS_ERR) { @@ -683,8 +877,15 @@ THROW_MSG_(vmSymbols::java_io_IOException(), strerror(errno), OS_ERR); } } + int fd = result; - return result; + // check to see if the file is secure + if (!is_file_secure(fd, filename)) { + ::close(fd); + return -1; + } + + return fd; } // create a named shared memory region. returns the address of the @@ -716,13 +917,21 @@ char* dirname = get_user_tmp_dir(user_name); char* filename = get_sharedmem_filename(dirname, vmid); + // get the short filename + char* short_filename = strrchr(filename, '/'); + if (short_filename == NULL) { + short_filename = filename; + } else { + short_filename++; + } + // cleanup any stale shared memory files cleanup_sharedmem_resources(dirname); assert(((size > 0) && (size % os::vm_page_size() == 0)), "unexpected PerfMemory region size"); - fd = create_sharedmem_resources(dirname, filename, size); + fd = create_sharedmem_resources(dirname, short_filename, size); FREE_C_HEAP_ARRAY(char, user_name, mtInternal); FREE_C_HEAP_ARRAY(char, dirname, mtInternal); @@ -837,12 +1046,12 @@ // constructs for the file and the shared memory mapping. if (mode == PerfMemory::PERF_MODE_RO) { mmap_prot = PROT_READ; - file_flags = O_RDONLY; + file_flags = O_RDONLY | O_NOFOLLOW; } else if (mode == PerfMemory::PERF_MODE_RW) { #ifdef LATER mmap_prot = PROT_READ | PROT_WRITE; - file_flags = O_RDWR; + file_flags = O_RDWR | O_NOFOLLOW; #else THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(), "Unsupported access mode");
--- a/src/os/linux/vm/perfMemory_linux.cpp Thu Jan 08 12:47:32 2015 +0000 +++ b/src/os/linux/vm/perfMemory_linux.cpp Tue Feb 03 16:48:05 2015 +0000 @@ -197,7 +197,38 @@ } -// check if the given path is considered a secure directory for +// Check if the given statbuf is considered a secure directory for +// the backing store files. Returns true if the directory is considered +// a secure location. Returns false if the statbuf is a symbolic link or +// if an error occurred. +// +static bool is_statbuf_secure(struct stat *statp) { + if (S_ISLNK(statp->st_mode) || !S_ISDIR(statp->st_mode)) { + // The path represents a link or some non-directory file type, + // which is not what we expected. Declare it insecure. + // + return false; + } + // We have an existing directory, check if the permissions are safe. + // + if ((statp->st_mode & (S_IWGRP|S_IWOTH)) != 0) { + // The directory is open for writing and could be subjected + // to a symlink or a hard link attack. Declare it insecure. + // + return false; + } + // See if the uid of the directory matches the effective uid of the process. + // + if (statp->st_uid != geteuid()) { + // The directory was not created by this user, declare it insecure. + // + return false; + } + return true; +} + + +// Check if the given path is considered a secure directory for // the backing store files. Returns true if the directory exists // and is considered a secure location. Returns false if the path // is a symbolic link or if an error occurred. @@ -211,22 +242,180 @@ return false; } - // the path exists, now check it's mode - if (S_ISLNK(statbuf.st_mode) || !S_ISDIR(statbuf.st_mode)) { - // the path represents a link or some non-directory file type, - // which is not what we expected. declare it insecure. - // + // The path exists, see if it is secure. + return is_statbuf_secure(&statbuf); +} + + +// Check if the given directory file descriptor is considered a secure +// directory for the backing store files. Returns true if the directory +// exists and is considered a secure location. Returns false if the path +// is a symbolic link or if an error occurred. +// +static bool is_dirfd_secure(int dir_fd) { + struct stat statbuf; + int result = 0; + + RESTARTABLE(::fstat(dir_fd, &statbuf), result); + if (result == OS_ERR) { + return false; + } + + // The path exists, now check its mode. + return is_statbuf_secure(&statbuf); +} + + +// Check to make sure fd1 and fd2 are referencing the same file system object. +// +static bool is_same_fsobject(int fd1, int fd2) { + struct stat statbuf1; + struct stat statbuf2; + int result = 0; + + RESTARTABLE(::fstat(fd1, &statbuf1), result); + if (result == OS_ERR) { + return false; + } + RESTARTABLE(::fstat(fd2, &statbuf2), result); + if (result == OS_ERR) { + return false; + } + + if ((statbuf1.st_ino == statbuf2.st_ino) && + (statbuf1.st_dev == statbuf2.st_dev)) { + return true; + } else { return false; } - else { - // we have an existing directory, check if the permissions are safe. - // - if ((statbuf.st_mode & (S_IWGRP|S_IWOTH)) != 0) { - // the directory is open for writing and could be subjected - // to a symlnk attack. declare it insecure. - // - return false; +} + + +// Open the directory of the given path and validate it. +// Return a DIR * of the open directory. +// +static DIR *open_directory_secure(const char* dirname) { + // Open the directory using open() so that it can be verified + // to be secure by calling is_dirfd_secure(), opendir() and then check + // to see if they are the same file system object. This method does not + // introduce a window of opportunity for the directory to be attacked that + // calling opendir() and is_directory_secure() does. + int result; + DIR *dirp = NULL; + RESTARTABLE(::open(dirname, O_RDONLY|O_NOFOLLOW), result); + if (result == OS_ERR) { + if (PrintMiscellaneous && Verbose) { + if (errno == ELOOP) { + warning("directory %s is a symlink and is not secure\n", dirname); + } else { + warning("could not open directory %s: %s\n", dirname, strerror(errno)); + } } + return dirp; + } + int fd = result; + + // Determine if the open directory is secure. + if (!is_dirfd_secure(fd)) { + // The directory is not a secure directory. + os::close(fd); + return dirp; + } + + // Open the directory. + dirp = ::opendir(dirname); + if (dirp == NULL) { + // The directory doesn't exist, close fd and return. + os::close(fd); + return dirp; + } + + // Check to make sure fd and dirp are referencing the same file system object. + if (!is_same_fsobject(fd, dirfd(dirp))) { + // The directory is not secure. + os::close(fd); + os::closedir(dirp); + dirp = NULL; + return dirp; + } + + // Close initial open now that we know directory is secure + os::close(fd); + + return dirp; +} + +// NOTE: The code below uses fchdir(), open() and unlink() because +// fdopendir(), openat() and unlinkat() are not supported on all +// versions. Once the support for fdopendir(), openat() and unlinkat() +// is available on all supported versions the code can be changed +// to use these functions. + +// Open the directory of the given path, validate it and set the +// current working directory to it. +// Return a DIR * of the open directory and the saved cwd fd. +// +static DIR *open_directory_secure_cwd(const char* dirname, int *saved_cwd_fd) { + + // Open the directory. + DIR* dirp = open_directory_secure(dirname); + if (dirp == NULL) { + // Directory doesn't exist or is insecure, so there is nothing to cleanup. + return dirp; + } + int fd = dirfd(dirp); + + // Open a fd to the cwd and save it off. + int result; + RESTARTABLE(::open(".", O_RDONLY), result); + if (result == OS_ERR) { + *saved_cwd_fd = -1; + } else { + *saved_cwd_fd = result; + } + + // Set the current directory to dirname by using the fd of the directory. + result = fchdir(fd); + + return dirp; +} + +// Close the directory and restore the current working directory. +// +static void close_directory_secure_cwd(DIR* dirp, int saved_cwd_fd) { + + int result; + // If we have a saved cwd change back to it and close the fd. + if (saved_cwd_fd != -1) { + result = fchdir(saved_cwd_fd); + ::close(saved_cwd_fd); + } + + // Close the directory. + os::closedir(dirp); +} + +// Check if the given file descriptor is considered a secure. +// +static bool is_file_secure(int fd, const char *filename) { + + int result; + struct stat statbuf; + + // Determine if the file is secure. + RESTARTABLE(::fstat(fd, &statbuf), result); + if (result == OS_ERR) { + if (PrintMiscellaneous && Verbose) { + warning("fstat failed on %s: %s\n", filename, strerror(errno)); + } + return false; + } + if (statbuf.st_nlink > 1) { + // A file with multiple links is not expected. + if (PrintMiscellaneous && Verbose) { + warning("file %s has multiple links\n", filename); + } + return false; } return true; } @@ -317,9 +506,11 @@ const char* tmpdirname = os::get_temp_directory(); + // open the temp directory DIR* tmpdirp = os::opendir(tmpdirname); if (tmpdirp == NULL) { + // Cannot open the directory to get the user name, return. return NULL; } @@ -344,7 +535,8 @@ strcat(usrdir_name, "/"); strcat(usrdir_name, dentry->d_name); - DIR* subdirp = os::opendir(usrdir_name); + // open the user directory + DIR* subdirp = open_directory_secure(usrdir_name); if (subdirp == NULL) { FREE_C_HEAP_ARRAY(char, usrdir_name, mtInternal); @@ -465,26 +657,6 @@ } -// remove file -// -// this method removes the file with the given file name in the -// named directory. -// -static void remove_file(const char* dirname, const char* filename) { - - size_t nbytes = strlen(dirname) + strlen(filename) + 2; - char* path = NEW_C_HEAP_ARRAY(char, nbytes, mtInternal); - - strcpy(path, dirname); - strcat(path, "/"); - strcat(path, filename); - - remove_file(path); - - FREE_C_HEAP_ARRAY(char, path, mtInternal); -} - - // cleanup stale shared memory resources // // This method attempts to remove all stale shared memory files in @@ -496,16 +668,11 @@ // static void cleanup_sharedmem_resources(const char* dirname) { - // open the user temp directory - DIR* dirp = os::opendir(dirname); - + int saved_cwd_fd; + // open the directory + DIR* dirp = open_directory_secure_cwd(dirname, &saved_cwd_fd); if (dirp == NULL) { - // directory doesn't exist, so there is nothing to cleanup - return; - } - - if (!is_directory_secure(dirname)) { - // the directory is not a secure directory + // directory doesn't exist or is insecure, so there is nothing to cleanup return; } @@ -519,6 +686,7 @@ // struct dirent* entry; char* dbuf = NEW_C_HEAP_ARRAY(char, os::readdir_buf_size(dirname), mtInternal); + errno = 0; while ((entry = os::readdir(dirp, (struct dirent *)dbuf)) != NULL) { @@ -527,9 +695,8 @@ if (pid == 0) { if (strcmp(entry->d_name, ".") != 0 && strcmp(entry->d_name, "..") != 0) { - // attempt to remove all unexpected files, except "." and ".." - remove_file(dirname, entry->d_name); + unlink(entry->d_name); } errno = 0; @@ -551,12 +718,14 @@ // if ((pid == os::current_process_id()) || (kill(pid, 0) == OS_ERR && (errno == ESRCH || errno == EPERM))) { - - remove_file(dirname, entry->d_name); + unlink(entry->d_name); } errno = 0; } - os::closedir(dirp); + + // close the directory and reset the current working directory + close_directory_secure_cwd(dirp, saved_cwd_fd); + FREE_C_HEAP_ARRAY(char, dbuf, mtInternal); } @@ -613,19 +782,54 @@ return -1; } - int result; + int saved_cwd_fd; + // open the directory and set the current working directory to it + DIR* dirp = open_directory_secure_cwd(dirname, &saved_cwd_fd); + if (dirp == NULL) { + // Directory doesn't exist or is insecure, so cannot create shared + // memory file. + return -1; + } - RESTARTABLE(::open(filename, O_RDWR|O_CREAT|O_TRUNC, S_IREAD|S_IWRITE), result); + // Open the filename in the current directory. + // Cannot use O_TRUNC here; truncation of an existing file has to happen + // after the is_file_secure() check below. + int result; + RESTARTABLE(::open(filename, O_RDWR|O_CREAT|O_NOFOLLOW, S_IREAD|S_IWRITE), result); if (result == OS_ERR) { if (PrintMiscellaneous && Verbose) { - warning("could not create file %s: %s\n", filename, strerror(errno)); + if (errno == ELOOP) { + warning("file %s is a symlink and is not secure\n", filename); + } else { + warning("could not create file %s: %s\n", filename, strerror(errno)); + } } + // close the directory and reset the current working directory + close_directory_secure_cwd(dirp, saved_cwd_fd); + return -1; } + // close the directory and reset the current working directory + close_directory_secure_cwd(dirp, saved_cwd_fd); // save the file descriptor int fd = result; + // check to see if the file is secure + if (!is_file_secure(fd, filename)) { + ::close(fd); + return -1; + } + + // truncate the file to get rid of any existing data + RESTARTABLE(::ftruncate(fd, (off_t)0), result); + if (result == OS_ERR) { + if (PrintMiscellaneous && Verbose) { + warning("could not truncate shared memory file: %s\n", strerror(errno)); + } + ::close(fd); + return -1; + } // set the file size RESTARTABLE(::ftruncate(fd, (off_t)size), result); if (result == OS_ERR) { @@ -683,8 +887,15 @@ THROW_MSG_(vmSymbols::java_io_IOException(), strerror(errno), OS_ERR); } } + int fd = result; - return result; + // check to see if the file is secure + if (!is_file_secure(fd, filename)) { + ::close(fd); + return -1; + } + + return fd; } // create a named shared memory region. returns the address of the @@ -715,6 +926,13 @@ char* dirname = get_user_tmp_dir(user_name); char* filename = get_sharedmem_filename(dirname, vmid); + // get the short filename + char* short_filename = strrchr(filename, '/'); + if (short_filename == NULL) { + short_filename = filename; + } else { + short_filename++; + } // cleanup any stale shared memory files cleanup_sharedmem_resources(dirname); @@ -722,7 +940,7 @@ assert(((size > 0) && (size % os::vm_page_size() == 0)), "unexpected PerfMemory region size"); - fd = create_sharedmem_resources(dirname, filename, size); + fd = create_sharedmem_resources(dirname, short_filename, size); FREE_C_HEAP_ARRAY(char, user_name, mtInternal); FREE_C_HEAP_ARRAY(char, dirname, mtInternal); @@ -837,12 +1055,12 @@ // constructs for the file and the shared memory mapping. if (mode == PerfMemory::PERF_MODE_RO) { mmap_prot = PROT_READ; - file_flags = O_RDONLY; + file_flags = O_RDONLY | O_NOFOLLOW; } else if (mode == PerfMemory::PERF_MODE_RW) { #ifdef LATER mmap_prot = PROT_READ | PROT_WRITE; - file_flags = O_RDWR; + file_flags = O_RDWR | O_NOFOLLOW; #else THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(), "Unsupported access mode");
--- a/src/os/solaris/add_gnu_debuglink/add_gnu_debuglink.c Thu Jan 08 12:47:32 2015 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,285 +0,0 @@ -/* - * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. - * 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. - * - */ - -/* - * Name: add_gnu_debuglink.c - * - * Description: Add a ".gnu_debuglink" section that refers to the specified - * debug_info_path to the specified ELF object. - * - * This program is adapted from the example program shown on the - * elf(3elf) man page and from code from the Solaris compiler - * driver. - */ - -/* - * needed to define SHF_EXCLUDE - */ -#define ELF_TARGET_ALL - -#include <fcntl.h> -#include <stdio.h> -#include <libelf.h> -#include <stdlib.h> -#include <string.h> -#include <unistd.h> - -static void failure(void); -static unsigned int gnu_debuglink_crc32(unsigned int crc, unsigned char *buf, - size_t len); - -void -main(int argc, char ** argv) { - /* new ELF section name */ - static char SEC_NAME[] = ".gnu_debuglink"; - - unsigned char buffer[8 * 1024]; /* I/O buffer */ - int buffer_len; /* buffer length */ - char * debug_info_path; /* debug info path */ - void * ehdr; /* ELF header */ - Elf * elf; /* ELF descriptor */ - char * elf_ident; /* ELF identity string */ - char * elf_obj; /* elf_obj file */ - int fd; /* descriptor for files */ - unsigned int file_crc = 0; /* CRC for debug info file */ - int is_elfclass64; /* is an ELFCLASS64 file? */ - Elf_Data * link_dat; /* ELF data for new debug info link */ - Elf_Data * name_dat; /* ELF data for new section name */ - Elf_Scn * new_scn; /* new ELF section descriptor */ - void * new_shdr; /* new ELF section header */ - Elf_Scn * scn; /* ELF section descriptor */ - void * shdr; /* ELF section header */ - - if (argc != 3) { - (void) fprintf(stderr, "Usage: %s debug_info_path elf_obj\n", argv[0]); - exit(2); - } - - debug_info_path = argv[1]; /* save for later */ - if ((fd = open(debug_info_path, O_RDONLY)) == -1) { - (void) fprintf(stderr, "%s: cannot open file.\n", debug_info_path); - exit(3); - } - - (void) printf("Computing CRC for '%s'\n", debug_info_path); - (void) fflush(stdout); - /* compute CRC for the debug info file */ - for (;;) { - int len = read(fd, buffer, sizeof buffer); - if (len <= 0) { - break; - } - file_crc = gnu_debuglink_crc32(file_crc, buffer, len); - } - (void) close(fd); - - /* open the elf_obj */ - elf_obj = argv[2]; - if ((fd = open(elf_obj, O_RDWR)) == -1) { - (void) fprintf(stderr, "%s: cannot open file.\n", elf_obj); - exit(4); - } - - (void) printf("Opening '%s' for update\n", elf_obj); - (void) fflush(stdout); - (void) elf_version(EV_CURRENT); /* coordinate ELF versions */ - - /* obtain the ELF descriptors from the input file */ - if ((elf = elf_begin(fd, ELF_C_RDWR, NULL)) == NULL) { - failure(); - } - - /* determine if ELFCLASS64 or not? */ - elf_ident = elf_getident(elf, NULL); - is_elfclass64 = (elf_ident[EI_CLASS] == ELFCLASS64); - - /* get the ELF header */ - if (is_elfclass64) { - ehdr = elf64_getehdr(elf); - } else { - ehdr = elf32_getehdr(elf); - } - if (ehdr == NULL) { - failure(); - } - - /* get the ELF section descriptor */ - if (is_elfclass64) { - scn = elf_getscn(elf, ((Elf64_Ehdr *) ehdr)->e_shstrndx); - } else { - scn = elf_getscn(elf, ((Elf32_Ehdr *) ehdr)->e_shstrndx); - } - if (scn == NULL) { - failure(); - } - - /* get the section header */ - if (is_elfclass64) { - shdr = elf64_getshdr(scn); - } else { - shdr = elf32_getshdr(scn); - } - if (shdr == NULL) { - failure(); - } - - (void) printf("Adding ELF data for new section name\n"); - (void) fflush(stdout); - name_dat = elf_newdata(scn); - name_dat->d_buf = (void *) SEC_NAME; - if (is_elfclass64) { - name_dat->d_off = ((Elf64_Shdr *) shdr)->sh_size + 1; - } else { - name_dat->d_off = ((Elf32_Shdr *) shdr)->sh_size + 1; - } - name_dat->d_align = 1; - name_dat->d_size = strlen(SEC_NAME) + 1; - - new_scn = elf_newscn(elf); - - if (is_elfclass64) { - new_shdr = elf64_getshdr(new_scn); - ((Elf64_Shdr *) new_shdr)->sh_flags = SHF_EXCLUDE; - ((Elf64_Shdr *) new_shdr)->sh_type = SHT_PROGBITS; - ((Elf64_Shdr *) new_shdr)->sh_name = ((Elf64_Shdr *) shdr)->sh_size; - ((Elf64_Shdr *) new_shdr)->sh_addralign = 1; - ((Elf64_Shdr *) shdr)->sh_size += (strlen(SEC_NAME) + 1); - } else { - new_shdr = elf32_getshdr(new_scn); - ((Elf32_Shdr *) new_shdr)->sh_flags = SHF_EXCLUDE; - ((Elf32_Shdr *) new_shdr)->sh_type = SHT_PROGBITS; - ((Elf32_Shdr *) new_shdr)->sh_name = ((Elf32_Shdr *) shdr)->sh_size; - ((Elf32_Shdr *) new_shdr)->sh_addralign = 1; - ((Elf32_Shdr *) shdr)->sh_size += (strlen(SEC_NAME) + 1); - } - - (void) printf("Adding ELF data for debug_info_path value\n"); - (void) fflush(stdout); - (void) memset(buffer, 0, sizeof buffer); - buffer_len = strlen(debug_info_path) + 1; /* +1 for NUL */ - (void) strncpy((char *) buffer, debug_info_path, buffer_len); - if (buffer_len % 4 != 0) { - /* not on a 4 byte boundary so pad to the next one */ - buffer_len += (4 - buffer_len % 4); - } - /* save the CRC */ - (void) memcpy(&buffer[buffer_len], &file_crc, sizeof file_crc); - buffer_len += sizeof file_crc; - - link_dat = elf_newdata(new_scn); - link_dat->d_type = ELF_T_BYTE; - link_dat->d_size = buffer_len; - link_dat->d_buf = buffer; - link_dat->d_align = 1; - - (void) printf("Saving updates to '%s'\n", elf_obj); - (void) fflush(stdout); - (void) elf_update(elf, ELF_C_NULL); /* recalc ELF memory structures */ - (void) elf_update(elf, ELF_C_WRITE); /* write out changes to ELF obj */ - (void) elf_end(elf); /* done with ELF obj */ - (void) close(fd); - - (void) printf("Done updating '%s'\n", elf_obj); - (void) fflush(stdout); - exit(0); -} /* end main */ - - -static void -failure() { - (void) fprintf(stderr, "%s\n", elf_errmsg(elf_errno())); - exit(5); -} - - -/* - * The CRC used in gnu_debuglink, retrieved from - * http://sourceware.org/gdb/current/onlinedocs/gdb/Separate-Debug-Files.html#Separate-Debug-Files. - */ - -static unsigned int -gnu_debuglink_crc32(unsigned int crc, unsigned char *buf, size_t len) { - static const unsigned int crc32_table[256] = { - 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, - 0x706af48f, 0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4, - 0xe0d5e91e, 0x97d2d988, 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, - 0x90bf1d91, 0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de, - 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7, 0x136c9856, - 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9, - 0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4, - 0xa2677172, 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, - 0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, - 0x45df5c75, 0xdcd60dcf, 0xabd13d59, 0x26d930ac, 0x51de003a, - 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423, 0xcfba9599, - 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924, - 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190, - 0x01db7106, 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, - 0x9fbfe4a5, 0xe8b8d433, 0x7807c9a2, 0x0f00f934, 0x9609a88e, - 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01, - 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, 0x6c0695ed, - 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950, - 0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, - 0xfbd44c65, 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, - 0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a, - 0x346ed9fc, 0xad678846, 0xda60b8d0, 0x44042d73, 0x33031de5, - 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa, 0xbe0b1010, - 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f, - 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, - 0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6, - 0x03b6e20c, 0x74b1d29a, 0xead54739, 0x9dd277af, 0x04db2615, - 0x73dc1683, 0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8, - 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1, 0xf00f9344, - 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb, - 0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a, - 0x67dd4acc, 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, - 0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, - 0xa6bc5767, 0x3fb506dd, 0x48b2364b, 0xd80d2bda, 0xaf0a1b4c, - 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55, 0x316e8eef, - 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236, - 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe, - 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, - 0x2cd99e8b, 0x5bdeae1d, 0x9b64c2b0, 0xec63f226, 0x756aa39c, - 0x026d930a, 0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713, - 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, 0x92d28e9b, - 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242, - 0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, - 0x18b74777, 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, - 0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45, 0xa00ae278, - 0xd70dd2ee, 0x4e048354, 0x3903b3c2, 0xa7672661, 0xd06016f7, - 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc, 0x40df0b66, - 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9, - 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, - 0xcdd70693, 0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, - 0x5d681b02, 0x2a6f2b94, 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, - 0x2d02ef8d - }; - - unsigned char *end; - - crc = ~crc & 0xffffffff; - for (end = buf + len; buf < end; ++buf) { - crc = crc32_table[(crc ^ *buf) & 0xff] ^ (crc >> 8); - } - return ~crc & 0xffffffff; -}
--- a/src/os/solaris/fix_empty_sec_hdr_flags/fix_empty_sec_hdr_flags.c Thu Jan 08 12:47:32 2015 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,181 +0,0 @@ -/* - * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. - * 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. - * - */ - -/* - * Name: fix_empty_sec_hdr_flags.c - * - * Description: Remove the SHF_ALLOC flag from "empty" section headers. - * An "empty" section header has sh_addr == 0 and sh_size == 0. - * - * This program is adapted from the example program shown on the - * elf(3elf) man page and from code from the Solaris compiler - * driver. - */ - -#include <fcntl.h> -#include <stdio.h> -#include <libelf.h> -#include <stdlib.h> -#include <string.h> -#include <unistd.h> - -static void failure(void); - -void -main(int argc, char ** argv) { - void * ehdr; /* ELF header */ - unsigned int i; /* section counter */ - int fd; /* descriptor for file */ - Elf * elf; /* ELF descriptor */ - char * elf_ident; /* ELF identity string */ - char * elf_obj; /* elf_obj file */ - int fix_count; /* number of flags fixed */ - int is_elfclass64; /* is an ELFCLASS64 file? */ - Elf_Scn * scn; /* ELF section descriptor */ - void * shdr; /* ELF section header */ - Elf_Data * shstrtab; /* ELF section header string table */ - - if (argc != 2) { - (void) fprintf(stderr, "Usage: %s elf_obj\n", argv[0]); - exit(2); - } - - /* open the elf_obj */ - elf_obj = argv[1]; - if ((fd = open(elf_obj, O_RDWR)) == -1) { - (void) fprintf(stderr, "%s: cannot open file.\n", elf_obj); - exit(3); - } - - (void) printf("Opening '%s' for update\n", elf_obj); - (void) fflush(stdout); - (void) elf_version(EV_CURRENT); /* coordinate ELF versions */ - - /* obtain the ELF descriptors from the input file */ - if ((elf = elf_begin(fd, ELF_C_RDWR, NULL)) == NULL) { - failure(); - } - - /* determine if ELFCLASS64 or not? */ - elf_ident = elf_getident(elf, NULL); - is_elfclass64 = (elf_ident[EI_CLASS] == ELFCLASS64); - - /* get the ELF header */ - if (is_elfclass64) { - ehdr = elf64_getehdr(elf); - } else { - ehdr = elf32_getehdr(elf); - } - if (ehdr == NULL) { - failure(); - } - - /* get the ELF section descriptor */ - if (is_elfclass64) { - scn = elf_getscn(elf, ((Elf64_Ehdr *) ehdr)->e_shstrndx); - } else { - scn = elf_getscn(elf, ((Elf32_Ehdr *) ehdr)->e_shstrndx); - } - if (scn == NULL) { - failure(); - } - - /* get the section header string table */ - shstrtab = elf_getdata(scn, NULL); - if (shstrtab == NULL) { - failure(); - } - - fix_count = 0; - - /* traverse the sections of the input file */ - for (i = 1, scn = NULL; scn = elf_nextscn(elf, scn); i++) { - int has_flag_set; /* is SHF_ALLOC flag set? */ - int is_empty; /* is section empty? */ - char * name; /* short hand pointer */ - - /* get the section header */ - if (is_elfclass64) { - shdr = elf64_getshdr(scn); - } else { - shdr = elf32_getshdr(scn); - } - if (shdr == NULL) { - failure(); - } - - if (is_elfclass64) { - name = (char *)shstrtab->d_buf + ((Elf64_Shdr *) shdr)->sh_name; - } else { - name = (char *)shstrtab->d_buf + ((Elf32_Shdr *) shdr)->sh_name; - } - - if (is_elfclass64) { - has_flag_set = ((Elf64_Shdr *) shdr)->sh_flags & SHF_ALLOC; - is_empty = ((Elf64_Shdr *) shdr)->sh_addr == 0 && - ((Elf64_Shdr *) shdr)->sh_size == 0; - } else { - has_flag_set = ((Elf32_Shdr *) shdr)->sh_flags & SHF_ALLOC; - is_empty = ((Elf32_Shdr *) shdr)->sh_addr == 0 && - ((Elf32_Shdr *) shdr)->sh_size == 0; - } - - if (is_empty && has_flag_set) { - (void) printf("section[%u] '%s' is empty, " - "but SHF_ALLOC flag is set.\n", i, name); - (void) printf("Clearing the SHF_ALLOC flag.\n"); - - if (is_elfclass64) { - ((Elf64_Shdr *) shdr)->sh_flags &= ~SHF_ALLOC; - } else { - ((Elf32_Shdr *) shdr)->sh_flags &= ~SHF_ALLOC; - } - fix_count++; - } - } /* end for each ELF section */ - - if (fix_count > 0) { - (void) printf("Saving %d updates to '%s'\n", fix_count, elf_obj); - (void) fflush(stdout); - (void) elf_update(elf, ELF_C_NULL); /* recalc ELF memory structures */ - (void) elf_update(elf, ELF_C_WRITE); /* write out changes to ELF obj */ - } else { - (void) printf("No SHF_ALLOC flags needed to be cleared.\n"); - } - - (void) elf_end(elf); /* done with ELF obj */ - (void) close(fd); - - (void) printf("Done %s '%s'\n", - (fix_count > 0) ? "updating" : "with", elf_obj); - (void) fflush(stdout); - exit(0); -} /* end main */ - - -static void -failure() { - (void) fprintf(stderr, "%s\n", elf_errmsg(elf_errno())); - exit(6); -}
--- a/src/os/solaris/vm/perfMemory_solaris.cpp Thu Jan 08 12:47:32 2015 +0000 +++ b/src/os/solaris/vm/perfMemory_solaris.cpp Tue Feb 03 16:48:05 2015 +0000 @@ -199,7 +199,38 @@ } -// check if the given path is considered a secure directory for +// Check if the given statbuf is considered a secure directory for +// the backing store files. Returns true if the directory is considered +// a secure location. Returns false if the statbuf is a symbolic link or +// if an error occurred. +// +static bool is_statbuf_secure(struct stat *statp) { + if (S_ISLNK(statp->st_mode) || !S_ISDIR(statp->st_mode)) { + // The path represents a link or some non-directory file type, + // which is not what we expected. Declare it insecure. + // + return false; + } + // We have an existing directory, check if the permissions are safe. + // + if ((statp->st_mode & (S_IWGRP|S_IWOTH)) != 0) { + // The directory is open for writing and could be subjected + // to a symlink or a hard link attack. Declare it insecure. + // + return false; + } + // See if the uid of the directory matches the effective uid of the process. + // + if (statp->st_uid != geteuid()) { + // The directory was not created by this user, declare it insecure. + // + return false; + } + return true; +} + + +// Check if the given path is considered a secure directory for // the backing store files. Returns true if the directory exists // and is considered a secure location. Returns false if the path // is a symbolic link or if an error occurred. @@ -213,27 +244,185 @@ return false; } - // the path exists, now check it's mode - if (S_ISLNK(statbuf.st_mode) || !S_ISDIR(statbuf.st_mode)) { - // the path represents a link or some non-directory file type, - // which is not what we expected. declare it insecure. - // + // The path exists, see if it is secure. + return is_statbuf_secure(&statbuf); +} + + +// Check if the given directory file descriptor is considered a secure +// directory for the backing store files. Returns true if the directory +// exists and is considered a secure location. Returns false if the path +// is a symbolic link or if an error occurred. +// +static bool is_dirfd_secure(int dir_fd) { + struct stat statbuf; + int result = 0; + + RESTARTABLE(::fstat(dir_fd, &statbuf), result); + if (result == OS_ERR) { + return false; + } + + // The path exists, now check its mode. + return is_statbuf_secure(&statbuf); +} + + +// Check to make sure fd1 and fd2 are referencing the same file system object. +// +static bool is_same_fsobject(int fd1, int fd2) { + struct stat statbuf1; + struct stat statbuf2; + int result = 0; + + RESTARTABLE(::fstat(fd1, &statbuf1), result); + if (result == OS_ERR) { + return false; + } + RESTARTABLE(::fstat(fd2, &statbuf2), result); + if (result == OS_ERR) { + return false; + } + + if ((statbuf1.st_ino == statbuf2.st_ino) && + (statbuf1.st_dev == statbuf2.st_dev)) { + return true; + } else { return false; } - else { - // we have an existing directory, check if the permissions are safe. - // - if ((statbuf.st_mode & (S_IWGRP|S_IWOTH)) != 0) { - // the directory is open for writing and could be subjected - // to a symlnk attack. declare it insecure. - // - return false; +} + + +// Open the directory of the given path and validate it. +// Return a DIR * of the open directory. +// +static DIR *open_directory_secure(const char* dirname) { + // Open the directory using open() so that it can be verified + // to be secure by calling is_dirfd_secure(), opendir() and then check + // to see if they are the same file system object. This method does not + // introduce a window of opportunity for the directory to be attacked that + // calling opendir() and is_directory_secure() does. + int result; + DIR *dirp = NULL; + RESTARTABLE(::open(dirname, O_RDONLY|O_NOFOLLOW), result); + if (result == OS_ERR) { + // Directory doesn't exist or is a symlink, so there is nothing to cleanup. + if (PrintMiscellaneous && Verbose) { + if (errno == ELOOP) { + warning("directory %s is a symlink and is not secure\n", dirname); + } else { + warning("could not open directory %s: %s\n", dirname, strerror(errno)); + } } + return dirp; + } + int fd = result; + + // Determine if the open directory is secure. + if (!is_dirfd_secure(fd)) { + // The directory is not a secure directory. + os::close(fd); + return dirp; + } + + // Open the directory. + dirp = ::opendir(dirname); + if (dirp == NULL) { + // The directory doesn't exist, close fd and return. + os::close(fd); + return dirp; + } + + // Check to make sure fd and dirp are referencing the same file system object. + if (!is_same_fsobject(fd, dirp->dd_fd)) { + // The directory is not secure. + os::close(fd); + os::closedir(dirp); + dirp = NULL; + return dirp; + } + + // Close initial open now that we know directory is secure + os::close(fd); + + return dirp; +} + +// NOTE: The code below uses fchdir(), open() and unlink() because +// fdopendir(), openat() and unlinkat() are not supported on all +// versions. Once the support for fdopendir(), openat() and unlinkat() +// is available on all supported versions the code can be changed +// to use these functions. + +// Open the directory of the given path, validate it and set the +// current working directory to it. +// Return a DIR * of the open directory and the saved cwd fd. +// +static DIR *open_directory_secure_cwd(const char* dirname, int *saved_cwd_fd) { + + // Open the directory. + DIR* dirp = open_directory_secure(dirname); + if (dirp == NULL) { + // Directory doesn't exist or is insecure, so there is nothing to cleanup. + return dirp; + } + int fd = dirp->dd_fd; + + // Open a fd to the cwd and save it off. + int result; + RESTARTABLE(::open(".", O_RDONLY), result); + if (result == OS_ERR) { + *saved_cwd_fd = -1; + } else { + *saved_cwd_fd = result; + } + + // Set the current directory to dirname by using the fd of the directory. + result = fchdir(fd); + + return dirp; +} + +// Close the directory and restore the current working directory. +// +static void close_directory_secure_cwd(DIR* dirp, int saved_cwd_fd) { + + int result; + // If we have a saved cwd change back to it and close the fd. + if (saved_cwd_fd != -1) { + result = fchdir(saved_cwd_fd); + ::close(saved_cwd_fd); + } + + // Close the directory. + os::closedir(dirp); +} + +// Check if the given file descriptor is considered a secure. +// +static bool is_file_secure(int fd, const char *filename) { + + int result; + struct stat statbuf; + + // Determine if the file is secure. + RESTARTABLE(::fstat(fd, &statbuf), result); + if (result == OS_ERR) { + if (PrintMiscellaneous && Verbose) { + warning("fstat failed on %s: %s\n", filename, strerror(errno)); + } + return false; + } + if (statbuf.st_nlink > 1) { + // A file with multiple links is not expected. + if (PrintMiscellaneous && Verbose) { + warning("file %s has multiple links\n", filename); + } + return false; } return true; } - // return the user name for the given user id // // the caller is expected to free the allocated memory. @@ -308,9 +497,11 @@ const char* tmpdirname = os::get_temp_directory(); + // open the temp directory DIR* tmpdirp = os::opendir(tmpdirname); if (tmpdirp == NULL) { + // Cannot open the directory to get the user name, return. return NULL; } @@ -335,7 +526,8 @@ strcat(usrdir_name, "/"); strcat(usrdir_name, dentry->d_name); - DIR* subdirp = os::opendir(usrdir_name); + // open the user directory + DIR* subdirp = open_directory_secure(usrdir_name); if (subdirp == NULL) { FREE_C_HEAP_ARRAY(char, usrdir_name, mtInternal); @@ -504,26 +696,6 @@ } -// remove file -// -// this method removes the file with the given file name in the -// named directory. -// -static void remove_file(const char* dirname, const char* filename) { - - size_t nbytes = strlen(dirname) + strlen(filename) + 2; - char* path = NEW_C_HEAP_ARRAY(char, nbytes, mtInternal); - - strcpy(path, dirname); - strcat(path, "/"); - strcat(path, filename); - - remove_file(path); - - FREE_C_HEAP_ARRAY(char, path, mtInternal); -} - - // cleanup stale shared memory resources // // This method attempts to remove all stale shared memory files in @@ -535,16 +707,11 @@ // static void cleanup_sharedmem_resources(const char* dirname) { - // open the user temp directory - DIR* dirp = os::opendir(dirname); - + int saved_cwd_fd; + // open the directory + DIR* dirp = open_directory_secure_cwd(dirname, &saved_cwd_fd); if (dirp == NULL) { - // directory doesn't exist, so there is nothing to cleanup - return; - } - - if (!is_directory_secure(dirname)) { - // the directory is not a secure directory + // directory doesn't exist or is insecure, so there is nothing to cleanup return; } @@ -558,6 +725,7 @@ // struct dirent* entry; char* dbuf = NEW_C_HEAP_ARRAY(char, os::readdir_buf_size(dirname), mtInternal); + errno = 0; while ((entry = os::readdir(dirp, (struct dirent *)dbuf)) != NULL) { @@ -568,7 +736,7 @@ if (strcmp(entry->d_name, ".") != 0 && strcmp(entry->d_name, "..") != 0) { // attempt to remove all unexpected files, except "." and ".." - remove_file(dirname, entry->d_name); + unlink(entry->d_name); } errno = 0; @@ -591,11 +759,14 @@ if ((pid == os::current_process_id()) || (kill(pid, 0) == OS_ERR && (errno == ESRCH || errno == EPERM))) { - remove_file(dirname, entry->d_name); + unlink(entry->d_name); } errno = 0; } - os::closedir(dirp); + + // close the directory and reset the current working directory + close_directory_secure_cwd(dirp, saved_cwd_fd); + FREE_C_HEAP_ARRAY(char, dbuf, mtInternal); } @@ -652,19 +823,54 @@ return -1; } - int result; + int saved_cwd_fd; + // open the directory and set the current working directory to it + DIR* dirp = open_directory_secure_cwd(dirname, &saved_cwd_fd); + if (dirp == NULL) { + // Directory doesn't exist or is insecure, so cannot create shared + // memory file. + return -1; + } - RESTARTABLE(::open(filename, O_RDWR|O_CREAT|O_TRUNC, S_IREAD|S_IWRITE), result); + // Open the filename in the current directory. + // Cannot use O_TRUNC here; truncation of an existing file has to happen + // after the is_file_secure() check below. + int result; + RESTARTABLE(::open(filename, O_RDWR|O_CREAT|O_NOFOLLOW, S_IREAD|S_IWRITE), result); if (result == OS_ERR) { if (PrintMiscellaneous && Verbose) { - warning("could not create file %s: %s\n", filename, strerror(errno)); + if (errno == ELOOP) { + warning("file %s is a symlink and is not secure\n", filename); + } else { + warning("could not create file %s: %s\n", filename, strerror(errno)); + } } + // close the directory and reset the current working directory + close_directory_secure_cwd(dirp, saved_cwd_fd); + return -1; } + // close the directory and reset the current working directory + close_directory_secure_cwd(dirp, saved_cwd_fd); // save the file descriptor int fd = result; + // check to see if the file is secure + if (!is_file_secure(fd, filename)) { + ::close(fd); + return -1; + } + + // truncate the file to get rid of any existing data + RESTARTABLE(::ftruncate(fd, (off_t)0), result); + if (result == OS_ERR) { + if (PrintMiscellaneous && Verbose) { + warning("could not truncate shared memory file: %s\n", strerror(errno)); + } + ::close(fd); + return -1; + } // set the file size RESTARTABLE(::ftruncate(fd, (off_t)size), result); if (result == OS_ERR) { @@ -700,8 +906,15 @@ THROW_MSG_(vmSymbols::java_io_IOException(), strerror(errno), OS_ERR); } } + int fd = result; - return result; + // check to see if the file is secure + if (!is_file_secure(fd, filename)) { + ::close(fd); + return -1; + } + + return fd; } // create a named shared memory region. returns the address of the @@ -733,13 +946,21 @@ char* dirname = get_user_tmp_dir(user_name); char* filename = get_sharedmem_filename(dirname, vmid); + // get the short filename + char* short_filename = strrchr(filename, '/'); + if (short_filename == NULL) { + short_filename = filename; + } else { + short_filename++; + } + // cleanup any stale shared memory files cleanup_sharedmem_resources(dirname); assert(((size > 0) && (size % os::vm_page_size() == 0)), "unexpected PerfMemory region size"); - fd = create_sharedmem_resources(dirname, filename, size); + fd = create_sharedmem_resources(dirname, short_filename, size); FREE_C_HEAP_ARRAY(char, user_name, mtInternal); FREE_C_HEAP_ARRAY(char, dirname, mtInternal); @@ -855,12 +1076,12 @@ // constructs for the file and the shared memory mapping. if (mode == PerfMemory::PERF_MODE_RO) { mmap_prot = PROT_READ; - file_flags = O_RDONLY; + file_flags = O_RDONLY | O_NOFOLLOW; } else if (mode == PerfMemory::PERF_MODE_RW) { #ifdef LATER mmap_prot = PROT_READ | PROT_WRITE; - file_flags = O_RDWR; + file_flags = O_RDWR | O_NOFOLLOW; #else THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(), "Unsupported access mode");
--- a/src/os/windows/vm/os_windows.cpp Thu Jan 08 12:47:32 2015 +0000 +++ b/src/os/windows/vm/os_windows.cpp Tue Feb 03 16:48:05 2015 +0000 @@ -1650,96 +1650,123 @@ void os::win32::print_windows_version(outputStream* st) { OSVERSIONINFOEX osvi; - SYSTEM_INFO si; - + VS_FIXEDFILEINFO *file_info; + TCHAR kernel32_path[MAX_PATH]; + UINT len, ret; + + // Use the GetVersionEx information to see if we're on a server or + // workstation edition of Windows. Starting with Windows 8.1 we can't + // trust the OS version information returned by this API. ZeroMemory(&osvi, sizeof(OSVERSIONINFOEX)); osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX); - if (!GetVersionEx((OSVERSIONINFO *)&osvi)) { - st->print_cr("N/A"); + st->print_cr("Call to GetVersionEx failed"); + return; + } + bool is_workstation = (osvi.wProductType == VER_NT_WORKSTATION); + + // Get the full path to \Windows\System32\kernel32.dll and use that for + // determining what version of Windows we're running on. + len = MAX_PATH - (UINT)strlen("\\kernel32.dll") - 1; + ret = GetSystemDirectory(kernel32_path, len); + if (ret == 0 || ret > len) { + st->print_cr("Call to GetSystemDirectory failed"); + return; + } + strncat(kernel32_path, "\\kernel32.dll", MAX_PATH - ret); + + DWORD version_size = GetFileVersionInfoSize(kernel32_path, NULL); + if (version_size == 0) { + st->print_cr("Call to GetFileVersionInfoSize failed"); + return; + } + + LPTSTR version_info = (LPTSTR)os::malloc(version_size, mtInternal); + if (version_info == NULL) { + st->print_cr("Failed to allocate version_info"); return; } - int os_vers = osvi.dwMajorVersion * 1000 + osvi.dwMinorVersion; - - ZeroMemory(&si, sizeof(SYSTEM_INFO)); - if (os_vers >= 5002) { - // Retrieve SYSTEM_INFO from GetNativeSystemInfo call so that we could - // find out whether we are running on 64 bit processor or not. - if (os::Kernel32Dll::GetNativeSystemInfoAvailable()) { - os::Kernel32Dll::GetNativeSystemInfo(&si); + if (!GetFileVersionInfo(kernel32_path, NULL, version_size, version_info)) { + os::free(version_info); + st->print_cr("Call to GetFileVersionInfo failed"); + return; + } + + if (!VerQueryValue(version_info, TEXT("\\"), (LPVOID*)&file_info, &len)) { + os::free(version_info); + st->print_cr("Call to VerQueryValue failed"); + return; + } + + int major_version = HIWORD(file_info->dwProductVersionMS); + int minor_version = LOWORD(file_info->dwProductVersionMS); + int build_number = HIWORD(file_info->dwProductVersionLS); + int build_minor = LOWORD(file_info->dwProductVersionLS); + int os_vers = major_version * 1000 + minor_version; + os::free(version_info); + + st->print(" Windows "); + switch (os_vers) { + + case 6000: + if (is_workstation) { + st->print("Vista"); } else { - GetSystemInfo(&si); + st->print("Server 2008"); } - } - - if (osvi.dwPlatformId == VER_PLATFORM_WIN32_NT) { - switch (os_vers) { - case 3051: st->print(" Windows NT 3.51"); break; - case 4000: st->print(" Windows NT 4.0"); break; - case 5000: st->print(" Windows 2000"); break; - case 5001: st->print(" Windows XP"); break; - case 5002: - if (osvi.wProductType == VER_NT_WORKSTATION && - si.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_AMD64) { - st->print(" Windows XP x64 Edition"); - } else { - st->print(" Windows Server 2003 family"); - } - break; - - case 6000: - if (osvi.wProductType == VER_NT_WORKSTATION) { - st->print(" Windows Vista"); - } else { - st->print(" Windows Server 2008"); - } - break; - - case 6001: - if (osvi.wProductType == VER_NT_WORKSTATION) { - st->print(" Windows 7"); - } else { - st->print(" Windows Server 2008 R2"); - } - break; - - case 6002: - if (osvi.wProductType == VER_NT_WORKSTATION) { - st->print(" Windows 8"); - } else { - st->print(" Windows Server 2012"); - } - break; - - case 6003: - if (osvi.wProductType == VER_NT_WORKSTATION) { - st->print(" Windows 8.1"); - } else { - st->print(" Windows Server 2012 R2"); - } - break; - - default: // future os - // Unrecognized windows, print out its major and minor versions - st->print(" Windows NT %d.%d", osvi.dwMajorVersion, osvi.dwMinorVersion); + break; + + case 6001: + if (is_workstation) { + st->print("7"); + } else { + st->print("Server 2008 R2"); + } + break; + + case 6002: + if (is_workstation) { + st->print("8"); + } else { + st->print("Server 2012"); + } + break; + + case 6003: + if (is_workstation) { + st->print("8.1"); + } else { + st->print("Server 2012 R2"); } - } else { - switch (os_vers) { - case 4000: st->print(" Windows 95"); break; - case 4010: st->print(" Windows 98"); break; - case 4090: st->print(" Windows Me"); break; - default: // future windows, print out its major and minor versions - st->print(" Windows %d.%d", osvi.dwMajorVersion, osvi.dwMinorVersion); + break; + + case 6004: + if (is_workstation) { + st->print("10"); + } else { + // The server version name of Windows 10 is not known at this time + st->print("%d.%d", major_version, minor_version); } - } - - if (os_vers >= 6000 && si.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_AMD64) { + break; + + default: + // Unrecognized windows, print out its major and minor versions + st->print("%d.%d", major_version, minor_version); + break; + } + + // Retrieve SYSTEM_INFO from GetNativeSystemInfo call so that we could + // find out whether we are running on 64 bit processor or not + SYSTEM_INFO si; + ZeroMemory(&si, sizeof(SYSTEM_INFO)); + os::Kernel32Dll::GetNativeSystemInfo(&si); + if (si.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_AMD64) { st->print(" , 64 bit"); } - st->print(" Build %d", osvi.dwBuildNumber); - st->print(" %s", osvi.szCSDVersion); // service pack + st->print(" Build %d", build_number); + st->print(" (%d.%d.%d.%d)", major_version, minor_version, build_number, build_minor); st->cr(); } @@ -5350,11 +5377,6 @@ return ::Module32Next(hSnapshot, lpme); } - -inline BOOL os::Kernel32Dll::GetNativeSystemInfoAvailable() { - return true; -} - inline void os::Kernel32Dll::GetNativeSystemInfo(LPSYSTEM_INFO lpSystemInfo) { ::GetNativeSystemInfo(lpSystemInfo); }
--- a/src/os/windows/vm/os_windows.hpp Thu Jan 08 12:47:32 2015 +0000 +++ b/src/os/windows/vm/os_windows.hpp Tue Feb 03 16:48:05 2015 +0000 @@ -192,7 +192,6 @@ static BOOL Module32First(HANDLE,LPMODULEENTRY32); static BOOL Module32Next(HANDLE,LPMODULEENTRY32); - static BOOL GetNativeSystemInfoAvailable(); static void GetNativeSystemInfo(LPSYSTEM_INFO); // NUMA calls
--- a/src/os_cpu/aix_ppc/vm/os_aix_ppc.cpp Thu Jan 08 12:47:32 2015 +0000 +++ b/src/os_cpu/aix_ppc/vm/os_aix_ppc.cpp Tue Feb 03 16:48:05 2015 +0000 @@ -91,8 +91,9 @@ // Frame information (pc, sp, fp) retrieved via ucontext // always looks like a C-frame according to the frame -// conventions in frame_ppc64.hpp. -address os::Aix::ucontext_get_pc(ucontext_t * uc) { +// conventions in frame_ppc.hpp. + +address os::Aix::ucontext_get_pc(const ucontext_t * uc) { return (address)uc->uc_mcontext.jmp_context.iar; } @@ -486,7 +487,7 @@ //////////////////////////////////////////////////////////////////////////////// // thread stack -size_t os::Aix::min_stack_allowed = 768*K; +size_t os::Aix::min_stack_allowed = 128*K; // Aix is always in floating stack mode. The stack size for a new // thread can be set via pthread_attr_setstacksize(). @@ -499,7 +500,7 @@ // because of the strange 'fallback logic' in os::create_thread(). // Better set CompilerThreadStackSize in globals_<os_cpu>.hpp if you want to // specify a different stack size for compiler threads! - size_t s = (thr_type == os::compiler_thread ? 4 * M : 1024 * K); + size_t s = (thr_type == os::compiler_thread ? 4 * M : 1 * M); return s; }
--- a/src/os_cpu/aix_ppc/vm/os_aix_ppc.hpp Thu Jan 08 12:47:32 2015 +0000 +++ b/src/os_cpu/aix_ppc/vm/os_aix_ppc.hpp Tue Feb 03 16:48:05 2015 +0000 @@ -23,8 +23,8 @@ * */ -#ifndef OS_CPU_AIX_OJDKPPC_VM_OS_AIX_PPC_HPP -#define OS_CPU_AIX_OJDKPPC_VM_OS_AIX_PPC_HPP +#ifndef OS_CPU_AIX_PPC_VM_OS_AIX_PPC_HPP +#define OS_CPU_AIX_PPC_VM_OS_AIX_PPC_HPP static void setup_fpu() {} @@ -32,4 +32,4 @@ // Note: Currently only used in 64 bit Windows implementations static bool register_code_area(char *low, char *high) { return true; } -#endif // OS_CPU_AIX_OJDKPPC_VM_OS_AIX_PPC_HPP +#endif // OS_CPU_AIX_PPC_VM_OS_AIX_PPC_HPP
--- a/src/os_cpu/aix_ppc/vm/prefetch_aix_ppc.inline.hpp Thu Jan 08 12:47:32 2015 +0000 +++ b/src/os_cpu/aix_ppc/vm/prefetch_aix_ppc.inline.hpp Tue Feb 03 16:48:05 2015 +0000 @@ -23,8 +23,8 @@ * */ -#ifndef OS_CPU_AIX_PPC_64_VM_PREFETCH_AIX_PPC_64_INLINE_HPP -#define OS_CPU_AIX_PPC_64_VM_PREFETCH_AIX_PPC_64_INLINE_HPP +#ifndef OS_CPU_AIX_PPC_VM_PREFETCH_AIX_PPC_INLINE_HPP +#define OS_CPU_AIX_PPC_VM_PREFETCH_AIX_PPC_INLINE_HPP #include "runtime/prefetch.hpp" @@ -55,4 +55,4 @@ #endif } -#endif // OS_CPU_AIX_PPC_64_VM_PREFETCH_AIX_PPC_64_INLINE_HPP +#endif // OS_CPU_AIX_PPC_VM_PREFETCH_AIX_PPC_INLINE_HPP
--- a/src/os_cpu/aix_ppc/vm/threadLS_aix_ppc.hpp Thu Jan 08 12:47:32 2015 +0000 +++ b/src/os_cpu/aix_ppc/vm/threadLS_aix_ppc.hpp Tue Feb 03 16:48:05 2015 +0000 @@ -23,8 +23,8 @@ * */ -#ifndef OS_CPU_AIX_OJDKPPC_VM_THREADLS_AIX_PPC_HPP -#define OS_CPU_AIX_OJDKPPC_VM_THREADLS_AIX_PPC_HPP +#ifndef OS_CPU_AIX_PPC_VM_THREADLS_AIX_PPC_HPP +#define OS_CPU_AIX_PPC_VM_THREADLS_AIX_PPC_HPP // Processor dependent parts of ThreadLocalStorage @@ -33,4 +33,4 @@ return (Thread *) os::thread_local_storage_at(thread_index()); } -#endif // OS_CPU_AIX_OJDKPPC_VM_THREADLS_AIX_PPC_HPP +#endif // OS_CPU_AIX_PPC_VM_THREADLS_AIX_PPC_HPP
--- a/src/os_cpu/aix_ppc/vm/thread_aix_ppc.hpp Thu Jan 08 12:47:32 2015 +0000 +++ b/src/os_cpu/aix_ppc/vm/thread_aix_ppc.hpp Tue Feb 03 16:48:05 2015 +0000 @@ -23,8 +23,8 @@ * */ -#ifndef OS_CPU_AIX_OJDKPPC_VM_THREAD_AIX_PPC_HPP -#define OS_CPU_AIX_OJDKPPC_VM_THREAD_AIX_PPC_HPP +#ifndef OS_CPU_AIX_PPC_VM_THREAD_AIX_PPC_HPP +#define OS_CPU_AIX_PPC_VM_THREAD_AIX_PPC_HPP private: void pd_initialize() { @@ -76,4 +76,4 @@ intptr_t* last_interpreter_fp() { return _last_interpreter_fp; } -#endif // OS_CPU_AIX_OJDKPPC_VM_THREAD_AIX_PPC_HPP +#endif // OS_CPU_AIX_PPC_VM_THREAD_AIX_PPC_HPP
--- a/src/os_cpu/linux_ppc/vm/os_linux_ppc.cpp Thu Jan 08 12:47:32 2015 +0000 +++ b/src/os_cpu/linux_ppc/vm/os_linux_ppc.cpp Tue Feb 03 16:48:05 2015 +0000 @@ -1,6 +1,6 @@ /* - * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. - * Copyright 2012, 2013 SAP AG. All rights reserved. + * Copyright (c) 1997, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright 2012, 2014 SAP AG. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -307,7 +307,7 @@ // doesn't work for us. We use: ((NativeInstruction*)pc)->is_safepoint_poll()) { if (TraceTraps) { - tty->print_cr("trap: safepoint_poll at " INTPTR_FORMAT " (SIGSEGV)", pc); + tty->print_cr("trap: safepoint_poll at " INTPTR_FORMAT " (SIGSEGV)", p2i(pc)); } stub = SharedRuntime::get_poll_stub(pc); } @@ -316,7 +316,7 @@ else if (sig == SIGTRAP && TrapBasedICMissChecks && nativeInstruction_at(pc)->is_sigtrap_ic_miss_check()) { if (TraceTraps) { - tty->print_cr("trap: ic_miss_check at " INTPTR_FORMAT " (SIGTRAP)", pc); + tty->print_cr("trap: ic_miss_check at " INTPTR_FORMAT " (SIGTRAP)", p2i(pc)); } stub = SharedRuntime::get_ic_miss_stub(); } @@ -325,7 +325,7 @@ else if (sig == SIGTRAP && TrapBasedNullChecks && nativeInstruction_at(pc)->is_sigtrap_null_check()) { if (TraceTraps) { - tty->print_cr("trap: null_check at " INTPTR_FORMAT " (SIGTRAP)", pc); + tty->print_cr("trap: null_check at " INTPTR_FORMAT " (SIGTRAP)", p2i(pc)); } stub = SharedRuntime::continuation_for_implicit_exception(thread, pc, SharedRuntime::IMPLICIT_NULL); } @@ -335,7 +335,7 @@ CodeCache::contains((void*) pc) && !MacroAssembler::needs_explicit_null_check((intptr_t) info->si_addr)) { if (TraceTraps) { - tty->print_cr("trap: null_check at " INTPTR_FORMAT " (SIGSEGV)", pc); + tty->print_cr("trap: null_check at " INTPTR_FORMAT " (SIGSEGV)", p2i(pc)); } stub = SharedRuntime::continuation_for_implicit_exception(thread, pc, SharedRuntime::IMPLICIT_NULL); } @@ -345,7 +345,7 @@ else if (sig == SIGTRAP && TrapBasedRangeChecks && nativeInstruction_at(pc)->is_sigtrap_range_check()) { if (TraceTraps) { - tty->print_cr("trap: range_check at " INTPTR_FORMAT " (SIGTRAP)", pc); + tty->print_cr("trap: range_check at " INTPTR_FORMAT " (SIGTRAP)", p2i(pc)); } stub = SharedRuntime::continuation_for_implicit_exception(thread, pc, SharedRuntime::IMPLICIT_NULL); } @@ -453,7 +453,7 @@ //////////////////////////////////////////////////////////////////////////////// // thread stack -size_t os::Linux::min_stack_allowed = 768*K; +size_t os::Linux::min_stack_allowed = 128*K; bool os::Linux::supports_variable_stack_size() { return true; } @@ -572,7 +572,7 @@ st->cr(); intptr_t *sp = (intptr_t *)os::Linux::ucontext_get_sp(uc); - st->print_cr("Top of Stack: (sp=" PTR_FORMAT ")", sp); + st->print_cr("Top of Stack: (sp=" PTR_FORMAT ")", p2i(sp)); print_hex_dump(st, (address)sp, (address)(sp + 128), sizeof(intptr_t)); st->cr(); @@ -580,7 +580,7 @@ // point to garbage if entry point in an nmethod is corrupted. Leave // this at the end, and hope for the best. address pc = os::Linux::ucontext_get_pc(uc); - st->print_cr("Instructions: (pc=" PTR_FORMAT ")", pc); + st->print_cr("Instructions: (pc=" PTR_FORMAT ")", p2i(pc)); print_hex_dump(st, pc - 64, pc + 64, /*instrsize=*/4); st->cr(); }
--- a/src/os_cpu/linux_x86/vm/os_linux_x86.cpp Thu Jan 08 12:47:32 2015 +0000 +++ b/src/os_cpu/linux_x86/vm/os_linux_x86.cpp Tue Feb 03 16:48:05 2015 +0000 @@ -909,7 +909,7 @@ */ char* hint = (char*) (Linux::initial_thread_stack_bottom() - ((StackYellowPages + StackRedPages + 1) * page_size)); - char* codebuf = os::reserve_memory(page_size, hint); + char* codebuf = os::attempt_reserve_memory_at(page_size, hint); if ( (codebuf == NULL) || (!os::commit_memory(codebuf, page_size, true)) ) { return; // No matter, we tried, best effort. }
--- a/src/os_cpu/solaris_sparc/vm/vm_version_solaris_sparc.cpp Thu Jan 08 12:47:32 2015 +0000 +++ b/src/os_cpu/solaris_sparc/vm/vm_version_solaris_sparc.cpp Tue Feb 03 16:48:05 2015 +0000 @@ -31,18 +31,51 @@ #include <sys/systeminfo.h> #include <kstat.h> #include <picl.h> +#include <dlfcn.h> +#include <link.h> extern "C" static int PICL_get_l1_data_cache_line_size_helper(picl_nodehdl_t nodeh, void *result); extern "C" static int PICL_get_l2_cache_line_size_helper(picl_nodehdl_t nodeh, void *result); +// Functions from the library we need (signatures should match those in picl.h) +extern "C" { + typedef int (*picl_initialize_func_t)(void); + typedef int (*picl_shutdown_func_t)(void); + typedef int (*picl_get_root_func_t)(picl_nodehdl_t *nodehandle); + typedef int (*picl_walk_tree_by_class_func_t)(picl_nodehdl_t rooth, + const char *classname, void *c_args, + int (*callback_fn)(picl_nodehdl_t hdl, void *args)); + typedef int (*picl_get_prop_by_name_func_t)(picl_nodehdl_t nodeh, const char *nm, + picl_prophdl_t *ph); + typedef int (*picl_get_propval_func_t)(picl_prophdl_t proph, void *valbuf, size_t sz); + typedef int (*picl_get_propinfo_func_t)(picl_prophdl_t proph, picl_propinfo_t *pi); +} + class PICL { + // Pointers to functions in the library + picl_initialize_func_t _picl_initialize; + picl_shutdown_func_t _picl_shutdown; + picl_get_root_func_t _picl_get_root; + picl_walk_tree_by_class_func_t _picl_walk_tree_by_class; + picl_get_prop_by_name_func_t _picl_get_prop_by_name; + picl_get_propval_func_t _picl_get_propval; + picl_get_propinfo_func_t _picl_get_propinfo; + // Handle to the library that is returned by dlopen + void *_dl_handle; + + bool open_library(); + void close_library(); + + template<typename FuncType> bool bind(FuncType& func, const char* name); + bool bind_library_functions(); + // Get a value of the integer property. The value in the tree can be either 32 or 64 bit // depending on the platform. The result is converted to int. - static int get_int_property(picl_nodehdl_t nodeh, const char* name, int* result) { + int get_int_property(picl_nodehdl_t nodeh, const char* name, int* result) { picl_propinfo_t pinfo; picl_prophdl_t proph; - if (picl_get_prop_by_name(nodeh, name, &proph) != PICL_SUCCESS || - picl_get_propinfo(proph, &pinfo) != PICL_SUCCESS) { + if (_picl_get_prop_by_name(nodeh, name, &proph) != PICL_SUCCESS || + _picl_get_propinfo(proph, &pinfo) != PICL_SUCCESS) { return PICL_FAILURE; } @@ -52,13 +85,13 @@ } if (pinfo.size == sizeof(int64_t)) { int64_t val; - if (picl_get_propval(proph, &val, sizeof(int64_t)) != PICL_SUCCESS) { + if (_picl_get_propval(proph, &val, sizeof(int64_t)) != PICL_SUCCESS) { return PICL_FAILURE; } *result = static_cast<int>(val); } else if (pinfo.size == sizeof(int32_t)) { int32_t val; - if (picl_get_propval(proph, &val, sizeof(int32_t)) != PICL_SUCCESS) { + if (_picl_get_propval(proph, &val, sizeof(int32_t)) != PICL_SUCCESS) { return PICL_FAILURE; } *result = static_cast<int>(val); @@ -72,6 +105,7 @@ // Visitor and a state machine that visits integer properties and verifies that the // values are the same. Stores the unique value observed. class UniqueValueVisitor { + PICL *_picl; enum { INITIAL, // Start state, no assignments happened ASSIGNED, // Assigned a value @@ -79,7 +113,7 @@ } _state; int _value; public: - UniqueValueVisitor() : _state(INITIAL) { } + UniqueValueVisitor(PICL* picl) : _picl(picl), _state(INITIAL) { } int value() { assert(_state == ASSIGNED, "Precondition"); return _value; @@ -96,9 +130,10 @@ static int visit(picl_nodehdl_t nodeh, const char* name, void *arg) { UniqueValueVisitor *state = static_cast<UniqueValueVisitor*>(arg); + PICL* picl = state->_picl; assert(!state->is_inconsistent(), "Precondition"); int curr; - if (PICL::get_int_property(nodeh, name, &curr) == PICL_SUCCESS) { + if (picl->get_int_property(nodeh, name, &curr) == PICL_SUCCESS) { if (!state->is_assigned()) { // first iteration state->set_value(curr); } else if (curr != state->value()) { // following iterations @@ -122,32 +157,36 @@ return UniqueValueVisitor::visit(nodeh, "l2-cache-line-size", state); } - PICL() : _L1_data_cache_line_size(0), _L2_cache_line_size(0) { - if (picl_initialize() == PICL_SUCCESS) { + PICL() : _L1_data_cache_line_size(0), _L2_cache_line_size(0), _dl_handle(NULL) { + if (!open_library()) { + return; + } + if (_picl_initialize() == PICL_SUCCESS) { picl_nodehdl_t rooth; - if (picl_get_root(&rooth) == PICL_SUCCESS) { - UniqueValueVisitor L1_state; + if (_picl_get_root(&rooth) == PICL_SUCCESS) { + UniqueValueVisitor L1_state(this); // Visit all "cpu" class instances - picl_walk_tree_by_class(rooth, "cpu", &L1_state, PICL_get_l1_data_cache_line_size_helper); + _picl_walk_tree_by_class(rooth, "cpu", &L1_state, PICL_get_l1_data_cache_line_size_helper); if (L1_state.is_initial()) { // Still initial, iteration found no values // Try walk all "core" class instances, it might be a Fujitsu machine - picl_walk_tree_by_class(rooth, "core", &L1_state, PICL_get_l1_data_cache_line_size_helper); + _picl_walk_tree_by_class(rooth, "core", &L1_state, PICL_get_l1_data_cache_line_size_helper); } if (L1_state.is_assigned()) { // Is there a value? _L1_data_cache_line_size = L1_state.value(); } - UniqueValueVisitor L2_state; - picl_walk_tree_by_class(rooth, "cpu", &L2_state, PICL_get_l2_cache_line_size_helper); + UniqueValueVisitor L2_state(this); + _picl_walk_tree_by_class(rooth, "cpu", &L2_state, PICL_get_l2_cache_line_size_helper); if (L2_state.is_initial()) { - picl_walk_tree_by_class(rooth, "core", &L2_state, PICL_get_l2_cache_line_size_helper); + _picl_walk_tree_by_class(rooth, "core", &L2_state, PICL_get_l2_cache_line_size_helper); } if (L2_state.is_assigned()) { _L2_cache_line_size = L2_state.value(); } } - picl_shutdown(); + _picl_shutdown(); } + close_library(); } unsigned int L1_data_cache_line_size() const { return _L1_data_cache_line_size; } @@ -161,6 +200,43 @@ return PICL::get_l2_cache_line_size(nodeh, result); } +template<typename FuncType> +bool PICL::bind(FuncType& func, const char* name) { + func = reinterpret_cast<FuncType>(dlsym(_dl_handle, name)); + return func != NULL; +} + +bool PICL::bind_library_functions() { + assert(_dl_handle != NULL, "library should be open"); + return bind(_picl_initialize, "picl_initialize" ) && + bind(_picl_shutdown, "picl_shutdown" ) && + bind(_picl_get_root, "picl_get_root" ) && + bind(_picl_walk_tree_by_class, "picl_walk_tree_by_class") && + bind(_picl_get_prop_by_name, "picl_get_prop_by_name" ) && + bind(_picl_get_propval, "picl_get_propval" ) && + bind(_picl_get_propinfo, "picl_get_propinfo" ); +} + +bool PICL::open_library() { + _dl_handle = dlopen("libpicl.so.1", RTLD_LAZY); + if (_dl_handle == NULL) { + warning("PICL (libpicl.so.1) is missing. Performance will not be optimal."); + return false; + } + if (!bind_library_functions()) { + assert(false, "unexpected PICL API change"); + close_library(); + return false; + } + return true; +} + +void PICL::close_library() { + assert(_dl_handle != NULL, "library should be open"); + dlclose(_dl_handle); + _dl_handle = NULL; +} + // We need to keep these here as long as we have to build on Solaris // versions before 10. #ifndef SI_ARCHITECTURE_32
--- a/src/os_cpu/windows_x86/vm/os_windows_x86.cpp Thu Jan 08 12:47:32 2015 +0000 +++ b/src/os_cpu/windows_x86/vm/os_windows_x86.cpp Tue Feb 03 16:48:05 2015 +0000 @@ -635,7 +635,11 @@ #ifndef PRODUCT void os::verify_stack_alignment() { #ifdef AMD64 - assert(((intptr_t)os::current_stack_pointer() & (StackAlignmentInBytes-1)) == 0, "incorrect stack alignment"); + // The current_stack_pointer() calls generated get_previous_sp stub routine. + // Only enable the assert after the routine becomes available. + if (StubRoutines::code1() != NULL) { + assert(((intptr_t)os::current_stack_pointer() & (StackAlignmentInBytes-1)) == 0, "incorrect stack alignment"); + } #endif } #endif
--- a/src/share/tools/ProjectCreator/WinGammaPlatformVC10.java Thu Jan 08 12:47:32 2015 +0000 +++ b/src/share/tools/ProjectCreator/WinGammaPlatformVC10.java Tue Feb 03 16:48:05 2015 +0000 @@ -398,7 +398,7 @@ "/export:JVM_GetThreadStateNames "+ "/export:JVM_GetThreadStateValues "+ "/export:JVM_InitAgentProperties"); - addAttr(rv, "AdditionalDependencies", "kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;Wsock32.lib;winmm.lib;psapi.lib"); + addAttr(rv, "AdditionalDependencies", "kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;Wsock32.lib;winmm.lib;psapi.lib;version.lib"); addAttr(rv, "OutputFile", outDll); addAttr(rv, "SuppressStartupBanner", "true"); addAttr(rv, "ModuleDefinitionFile", outDir+Util.sep+"vm.def");
--- a/src/share/vm/c1/c1_globals.hpp Thu Jan 08 12:47:32 2015 +0000 +++ b/src/share/vm/c1/c1_globals.hpp Tue Feb 03 16:48:05 2015 +0000 @@ -290,9 +290,6 @@ develop(bool, InstallMethods, true, \ "Install methods at the end of successful compilations") \ \ - product(intx, CompilationRepeat, 0, \ - "Number of times to recompile method before returning result") \ - \ develop(intx, NMethodSizeLimit, (64*K)*wordSize, \ "Maximum size of a compiled method.") \ \
--- a/src/share/vm/ci/bcEscapeAnalyzer.cpp Thu Jan 08 12:47:32 2015 +0000 +++ b/src/share/vm/ci/bcEscapeAnalyzer.cpp Tue Feb 03 16:48:05 2015 +0000 @@ -89,8 +89,8 @@ public: ArgumentMap *_vars; ArgumentMap *_stack; - short _stack_height; - short _max_stack; + int _stack_height; + int _max_stack; bool _initialized; ArgumentMap empty_map;
--- a/src/share/vm/ci/ciEnv.cpp Thu Jan 08 12:47:32 2015 +0000 +++ b/src/share/vm/ci/ciEnv.cpp Tue Feb 03 16:48:05 2015 +0000 @@ -559,7 +559,12 @@ oop obj = cpool->resolved_references()->obj_at(cache_index); if (obj != NULL) { ciObject* ciobj = get_object(obj); - return ciConstant(T_OBJECT, ciobj); + if (ciobj->is_array()) { + return ciConstant(T_ARRAY, ciobj); + } else { + assert(ciobj->is_instance(), "should be an instance"); + return ciConstant(T_OBJECT, ciobj); + } } index = cpool->object_to_cp_index(cache_index); } @@ -586,8 +591,12 @@ } } ciObject* constant = get_object(string); - assert (constant->is_instance(), "must be an instance, or not? "); - return ciConstant(T_OBJECT, constant); + if (constant->is_array()) { + return ciConstant(T_ARRAY, constant); + } else { + assert (constant->is_instance(), "must be an instance, or not? "); + return ciConstant(T_OBJECT, constant); + } } else if (tag.is_klass() || tag.is_unresolved_klass()) { // 4881222: allow ldc to take a class type ciKlass* klass = get_klass_by_index_impl(cpool, index, ignore_will_link, accessor);
--- a/src/share/vm/ci/ciMethod.cpp Thu Jan 08 12:47:32 2015 +0000 +++ b/src/share/vm/ci/ciMethod.cpp Tue Feb 03 16:48:05 2015 +0000 @@ -68,7 +68,10 @@ // ciMethod::ciMethod // // Loaded method. -ciMethod::ciMethod(methodHandle h_m) : ciMetadata(h_m()) { +ciMethod::ciMethod(methodHandle h_m, ciInstanceKlass* holder) : + ciMetadata(h_m()), + _holder(holder) +{ assert(h_m() != NULL, "no null method"); // These fields are always filled in in loaded methods. @@ -124,7 +127,6 @@ // generating _signature may allow GC and therefore move m. // These fields are always filled in. _name = env->get_symbol(h_m()->name()); - _holder = env->get_instance_klass(h_m()->method_holder()); ciSymbol* sig_symbol = env->get_symbol(h_m()->signature()); constantPoolHandle cpool = h_m()->constants(); _signature = new (env->arena()) ciSignature(_holder, cpool, sig_symbol);
--- a/src/share/vm/ci/ciMethod.hpp Thu Jan 08 12:47:32 2015 +0000 +++ b/src/share/vm/ci/ciMethod.hpp Tue Feb 03 16:48:05 2015 +0000 @@ -90,7 +90,7 @@ BCEscapeAnalyzer* _bcea; #endif - ciMethod(methodHandle h_m); + ciMethod(methodHandle h_m, ciInstanceKlass* holder); ciMethod(ciInstanceKlass* holder, ciSymbol* name, ciSymbol* signature, ciInstanceKlass* accessor); Method* get_Method() const {
--- a/src/share/vm/ci/ciObjectFactory.cpp Thu Jan 08 12:47:32 2015 +0000 +++ b/src/share/vm/ci/ciObjectFactory.cpp Tue Feb 03 16:48:05 2015 +0000 @@ -239,7 +239,7 @@ ciObject* ciObjectFactory::get(oop key) { ASSERT_IN_VM; - assert(key == NULL || Universe::heap()->is_in_reserved(key), "must be"); + assert(Universe::heap()->is_in_reserved(key), "must be"); NonPermObject* &bucket = find_non_perm(key); if (bucket != NULL) { @@ -260,10 +260,10 @@ } // ------------------------------------------------------------------ -// ciObjectFactory::get +// ciObjectFactory::get_metadata // -// Get the ciObject corresponding to some oop. If the ciObject has -// already been created, it is returned. Otherwise, a new ciObject +// Get the ciMetadata corresponding to some Metadata. If the ciMetadata has +// already been created, it is returned. Otherwise, a new ciMetadata // is created. ciMetadata* ciObjectFactory::get_metadata(Metadata* key) { ASSERT_IN_VM; @@ -290,9 +290,9 @@ } #endif if (!is_found_at(index, key, _ci_metadata)) { - // The ciObject does not yet exist. Create it and insert it + // The ciMetadata does not yet exist. Create it and insert it // into the cache. - ciMetadata* new_object = create_new_object(key); + ciMetadata* new_object = create_new_metadata(key); init_ident_of(new_object); assert(new_object->is_metadata(), "must be"); @@ -344,15 +344,28 @@ } // ------------------------------------------------------------------ -// ciObjectFactory::create_new_object +// ciObjectFactory::create_new_metadata // -// Create a new ciObject from a Metadata*. +// Create a new ciMetadata from a Metadata*. // -// Implementation note: this functionality could be virtual behavior -// of the oop itself. For now, we explicitly marshal the object. -ciMetadata* ciObjectFactory::create_new_object(Metadata* o) { +// Implementation note: in order to keep Metadata live, an auxiliary ciObject +// is used, which points to it's holder. +ciMetadata* ciObjectFactory::create_new_metadata(Metadata* o) { EXCEPTION_CONTEXT; + // Hold metadata from unloading by keeping it's holder alive. + if (_initialized && o->is_klass()) { + Klass* holder = ((Klass*)o); + if (holder->oop_is_instance() && InstanceKlass::cast(holder)->is_anonymous()) { + // Though ciInstanceKlass records class loader oop, it's not enough to keep + // VM anonymous classes alive (loader == NULL). Klass holder should be used instead. + // It is enough to record a ciObject, since cached elements are never removed + // during ciObjectFactory lifetime. ciObjectFactory itself is created for + // every compilation and lives for the whole duration of the compilation. + ciObject* h = get(holder->klass_holder()); + } + } + if (o->is_klass()) { KlassHandle h_k(THREAD, (Klass*)o); Klass* k = (Klass*)o; @@ -365,14 +378,16 @@ } } else if (o->is_method()) { methodHandle h_m(THREAD, (Method*)o); - return new (arena()) ciMethod(h_m); + ciEnv *env = CURRENT_THREAD_ENV; + ciInstanceKlass* holder = env->get_instance_klass(h_m()->method_holder()); + return new (arena()) ciMethod(h_m, holder); } else if (o->is_methodData()) { // Hold methodHandle alive - might not be necessary ??? methodHandle h_m(THREAD, ((MethodData*)o)->method()); return new (arena()) ciMethodData((MethodData*)o); } - // The oop is of some type not supported by the compiler interface. + // The Metadata* is of some type not supported by the compiler interface. ShouldNotReachHere(); return NULL; } @@ -701,7 +716,7 @@ // If there is no entry in the cache corresponding to this oop, return // the null tail of the bucket into which the oop should be inserted. ciObjectFactory::NonPermObject* &ciObjectFactory::find_non_perm(oop key) { - assert(Universe::heap()->is_in_reserved_or_null(key), "must be"); + assert(Universe::heap()->is_in_reserved(key), "must be"); ciMetadata* klass = get_metadata(key->klass()); NonPermObject* *bp = &_non_perm_bucket[(unsigned) klass->hash() % NON_PERM_BUCKETS]; for (NonPermObject* p; (p = (*bp)) != NULL; bp = &p->next()) {
--- a/src/share/vm/ci/ciObjectFactory.hpp Thu Jan 08 12:47:32 2015 +0000 +++ b/src/share/vm/ci/ciObjectFactory.hpp Tue Feb 03 16:48:05 2015 +0000 @@ -73,7 +73,7 @@ void insert(int index, ciMetadata* obj, GrowableArray<ciMetadata*>* objects); ciObject* create_new_object(oop o); - ciMetadata* create_new_object(Metadata* o); + ciMetadata* create_new_metadata(Metadata* o); void ensure_metadata_alive(ciMetadata* m);
--- a/src/share/vm/ci/ciTypeFlow.cpp Thu Jan 08 12:47:32 2015 +0000 +++ b/src/share/vm/ci/ciTypeFlow.cpp Tue Feb 03 16:48:05 2015 +0000 @@ -35,6 +35,7 @@ #include "interpreter/bytecode.hpp" #include "interpreter/bytecodes.hpp" #include "memory/allocation.inline.hpp" +#include "opto/compile.hpp" #include "runtime/deoptimization.hpp" #include "utilities/growableArray.hpp" @@ -730,7 +731,7 @@ if (obj->is_null_object()) { push_null(); } else { - assert(obj->is_instance(), "must be java_mirror of klass"); + assert(obj->is_instance() || obj->is_array(), "must be java_mirror of klass"); push_object(obj->klass()); } } else { @@ -2646,7 +2647,7 @@ assert (!blk->has_pre_order(), ""); blk->set_next_pre_order(); - if (_next_pre_order >= MaxNodeLimit / 2) { + if (_next_pre_order >= (int)Compile::current()->max_node_limit() / 2) { // Too many basic blocks. Bail out. // This can happen when try/finally constructs are nested to depth N, // and there is O(2**N) cloning of jsr bodies. See bug 4697245!
--- a/src/share/vm/classfile/classFileParser.cpp Thu Jan 08 12:47:32 2015 +0000 +++ b/src/share/vm/classfile/classFileParser.cpp Tue Feb 03 16:48:05 2015 +0000 @@ -2529,7 +2529,7 @@ Array<Method*>* ClassFileParser::parse_methods(bool is_interface, AccessFlags* promoted_flags, bool* has_final_method, - bool* has_default_methods, + bool* declares_default_methods, TRAPS) { ClassFileStream* cfs = stream(); cfs->guarantee_more(2, CHECK_NULL); // length @@ -2548,11 +2548,11 @@ if (method->is_final()) { *has_final_method = true; } - if (is_interface && !(*has_default_methods) - && !method->is_abstract() && !method->is_static() - && !method->is_private()) { - // default method - *has_default_methods = true; + // declares_default_methods: declares concrete instance methods, any access flags + // used for interface initialization, and default method inheritance analysis + if (is_interface && !(*declares_default_methods) + && !method->is_abstract() && !method->is_static()) { + *declares_default_methods = true; } _methods->at_put(index, method()); } @@ -3058,21 +3058,39 @@ } } -// Transfer ownership of metadata allocated to the InstanceKlass. -void ClassFileParser::apply_parsed_class_metadata( - instanceKlassHandle this_klass, - int java_fields_count, TRAPS) { - // Assign annotations if needed - if (_annotations != NULL || _type_annotations != NULL || - _fields_annotations != NULL || _fields_type_annotations != NULL) { +// Create the Annotations object that will +// hold the annotations array for the Klass. +void ClassFileParser::create_combined_annotations(TRAPS) { + if (_annotations == NULL && + _type_annotations == NULL && + _fields_annotations == NULL && + _fields_type_annotations == NULL) { + // Don't create the Annotations object unnecessarily. + return; + } + Annotations* annotations = Annotations::allocate(_loader_data, CHECK); annotations->set_class_annotations(_annotations); annotations->set_class_type_annotations(_type_annotations); annotations->set_fields_annotations(_fields_annotations); annotations->set_fields_type_annotations(_fields_type_annotations); - this_klass->set_annotations(annotations); - } - + + // This is the Annotations object that will be + // assigned to InstanceKlass being constructed. + _combined_annotations = annotations; + + // The annotations arrays below has been transfered the + // _combined_annotations so these fields can now be cleared. + _annotations = NULL; + _type_annotations = NULL; + _fields_annotations = NULL; + _fields_type_annotations = NULL; +} + +// Transfer ownership of metadata allocated to the InstanceKlass. +void ClassFileParser::apply_parsed_class_metadata( + instanceKlassHandle this_klass, + int java_fields_count, TRAPS) { _cp->set_pool_holder(this_klass()); this_klass->set_constants(_cp); this_klass->set_fields(_fields, java_fields_count); @@ -3080,6 +3098,7 @@ this_klass->set_inner_classes(_inner_classes); this_klass->set_local_interfaces(_local_interfaces); this_klass->set_transitive_interfaces(_transitive_interfaces); + this_klass->set_annotations(_combined_annotations); // Clear out these fields so they don't get deallocated by the destructor clear_class_metadata(); @@ -3691,6 +3710,7 @@ JvmtiCachedClassFileData *cached_class_file = NULL; Handle class_loader(THREAD, loader_data->class_loader()); bool has_default_methods = false; + bool declares_default_methods = false; ResourceMark rm(THREAD); ClassFileStream* cfs = stream(); @@ -3928,13 +3948,20 @@ Array<Method*>* methods = parse_methods(access_flags.is_interface(), &promoted_flags, &has_final_method, - &has_default_methods, + &declares_default_methods, CHECK_(nullHandle)); + if (declares_default_methods) { + has_default_methods = true; + } // Additional attributes ClassAnnotationCollector parsed_annotations; parse_classfile_attributes(&parsed_annotations, CHECK_(nullHandle)); + // Finalize the Annotations metadata object, + // now that all annotation arrays have been created. + create_combined_annotations(CHECK_(nullHandle)); + // Make sure this is the end of class file stream guarantee_property(cfs->at_eos(), "Extra bytes at the end of class file %s", CHECK_(nullHandle)); @@ -4072,6 +4099,7 @@ this_klass->set_minor_version(minor_version); this_klass->set_major_version(major_version); this_klass->set_has_default_methods(has_default_methods); + this_klass->set_declares_default_methods(declares_default_methods); if (!host_klass.is_null()) { assert (this_klass->is_anonymous(), "should be the same"); @@ -4234,10 +4262,27 @@ InstanceKlass::deallocate_interfaces(_loader_data, _super_klass(), _local_interfaces, _transitive_interfaces); - MetadataFactory::free_array<u1>(_loader_data, _annotations); - MetadataFactory::free_array<u1>(_loader_data, _type_annotations); - Annotations::free_contents(_loader_data, _fields_annotations); - Annotations::free_contents(_loader_data, _fields_type_annotations); + if (_combined_annotations != NULL) { + // After all annotations arrays have been created, they are installed into the + // Annotations object that will be assigned to the InstanceKlass being created. + + // Deallocate the Annotations object and the installed annotations arrays. + _combined_annotations->deallocate_contents(_loader_data); + + // If the _combined_annotations pointer is non-NULL, + // then the other annotations fields should have been cleared. + assert(_annotations == NULL, "Should have been cleared"); + assert(_type_annotations == NULL, "Should have been cleared"); + assert(_fields_annotations == NULL, "Should have been cleared"); + assert(_fields_type_annotations == NULL, "Should have been cleared"); + } else { + // If the annotations arrays were not installed into the Annotations object, + // then they have to be deallocated explicitly. + MetadataFactory::free_array<u1>(_loader_data, _annotations); + MetadataFactory::free_array<u1>(_loader_data, _type_annotations); + Annotations::free_contents(_loader_data, _fields_annotations); + Annotations::free_contents(_loader_data, _fields_type_annotations); + } clear_class_metadata();
--- a/src/share/vm/classfile/classFileParser.hpp Thu Jan 08 12:47:32 2015 +0000 +++ b/src/share/vm/classfile/classFileParser.hpp Tue Feb 03 16:48:05 2015 +0000 @@ -75,6 +75,7 @@ Array<u2>* _inner_classes; Array<Klass*>* _local_interfaces; Array<Klass*>* _transitive_interfaces; + Annotations* _combined_annotations; AnnotationArray* _annotations; AnnotationArray* _type_annotations; Array<AnnotationArray*>* _fields_annotations; @@ -86,6 +87,8 @@ void set_class_generic_signature_index(u2 x) { _generic_signature_index = x; } void set_class_sde_buffer(char* x, int len) { _sde_buffer = x; _sde_length = len; } + void create_combined_annotations(TRAPS); + void init_parsed_class_attributes(ClassLoaderData* loader_data) { _loader_data = loader_data; _synthetic_flag = false; @@ -110,6 +113,7 @@ _inner_classes = NULL; _local_interfaces = NULL; _transitive_interfaces = NULL; + _combined_annotations = NULL; _annotations = _type_annotations = NULL; _fields_annotations = _fields_type_annotations = NULL; } @@ -247,7 +251,7 @@ Array<Method*>* parse_methods(bool is_interface, AccessFlags* promoted_flags, bool* has_final_method, - bool* has_default_method, + bool* declares_default_methods, TRAPS); intArray* sort_methods(Array<Method*>* methods);
--- a/src/share/vm/classfile/classLoader.cpp Thu Jan 08 12:47:32 2015 +0000 +++ b/src/share/vm/classfile/classLoader.cpp Tue Feb 03 16:48:05 2015 +0000 @@ -610,7 +610,7 @@ } #endif -void ClassLoader::setup_search_path(const char *class_path) { +void ClassLoader::setup_search_path(const char *class_path, bool canonicalize) { int offset = 0; int len = (int)strlen(class_path); int end = 0; @@ -625,7 +625,13 @@ char* path = NEW_RESOURCE_ARRAY(char, end - start + 1); strncpy(path, &class_path[start], end - start); path[end - start] = '\0'; - update_class_path_entry_list(path, false); + if (canonicalize) { + char* canonical_path = NEW_RESOURCE_ARRAY(char, JVM_MAXPATHLEN + 1); + if (get_canonical_path(path, canonical_path, JVM_MAXPATHLEN)) { + path = canonical_path; + } + } + update_class_path_entry_list(path, /*check_for_duplicates=*/canonicalize); #if INCLUDE_CDS if (DumpSharedSpaces) { check_shared_classpath(path); @@ -1131,7 +1137,7 @@ h = context.record_result(classpath_index, e, result, THREAD); } else { if (DumpSharedSpaces) { - tty->print_cr("Preload Error: Cannot find %s", class_name); + tty->print_cr("Preload Warning: Cannot find %s", class_name); } }
--- a/src/share/vm/classfile/classLoader.hpp Thu Jan 08 12:47:32 2015 +0000 +++ b/src/share/vm/classfile/classLoader.hpp Tue Feb 03 16:48:05 2015 +0000 @@ -129,8 +129,8 @@ bool _has_error; bool _throw_exception; volatile ClassPathEntry* _resolved_entry; + public: ClassPathEntry* resolve_entry(TRAPS); - public: bool is_jar_file(); const char* name() { return _path; } LazyClassPathEntry(const char* path, const struct stat* st, bool throw_exception); @@ -218,7 +218,7 @@ static void setup_meta_index(const char* meta_index_path, const char* meta_index_dir, int start_index); static void setup_bootstrap_search_path(); - static void setup_search_path(const char *class_path); + static void setup_search_path(const char *class_path, bool canonicalize=false); static void load_zip_library(); static ClassPathEntry* create_class_path_entry(const char *path, const struct stat* st, @@ -329,6 +329,10 @@ return e; } + static int num_classpath_entries() { + return _num_entries; + } + #if INCLUDE_CDS // Sharing dump and restore static void copy_package_info_buckets(char** top, char* end);
--- a/src/share/vm/classfile/classLoaderData.cpp Thu Jan 08 12:47:32 2015 +0000 +++ b/src/share/vm/classfile/classLoaderData.cpp Tue Feb 03 16:48:05 2015 +0000 @@ -64,9 +64,8 @@ #include "utilities/growableArray.hpp" #include "utilities/macros.hpp" #include "utilities/ostream.hpp" - #if INCLUDE_TRACE - #include "trace/tracing.hpp" +#include "trace/tracing.hpp" #endif ClassLoaderData * ClassLoaderData::_the_null_class_loader_data = NULL; @@ -747,7 +746,7 @@ // Move class loader data from main list to the unloaded list for unloading // and deallocation later. -bool ClassLoaderDataGraph::do_unloading(BoolObjectClosure* is_alive_closure) { +bool ClassLoaderDataGraph::do_unloading(BoolObjectClosure* is_alive_closure, bool clean_alive) { ClassLoaderData* data = _head; ClassLoaderData* prev = NULL; bool seen_dead_loader = false; @@ -756,16 +755,8 @@ // purging and we don't want to rewalk the previously unloaded class loader data. _saved_unloading = _unloading; - // mark metadata seen on the stack and code cache so we can delete - // unneeded entries. - bool has_redefined_a_class = JvmtiExport::has_redefined_a_class(); - MetadataOnStackMark md_on_stack; while (data != NULL) { if (data->is_alive(is_alive_closure)) { - if (has_redefined_a_class) { - data->classes_do(InstanceKlass::purge_previous_versions); - } - data->free_deallocate_list(); prev = data; data = data->next(); continue; @@ -787,6 +778,11 @@ _unloading = dead; } + if (clean_alive) { + // Clean previous versions and the deallocate list. + ClassLoaderDataGraph::clean_metaspaces(); + } + if (seen_dead_loader) { post_class_unload_events(); } @@ -794,6 +790,26 @@ return seen_dead_loader; } +void ClassLoaderDataGraph::clean_metaspaces() { + // mark metadata seen on the stack and code cache so we can delete unneeded entries. + bool has_redefined_a_class = JvmtiExport::has_redefined_a_class(); + MetadataOnStackMark md_on_stack(has_redefined_a_class); + + if (has_redefined_a_class) { + // purge_previous_versions also cleans weak method links. Because + // one method's MDO can reference another method from another + // class loader, we need to first clean weak method links for all + // class loaders here. Below, we can then free redefined methods + // for all class loaders. + for (ClassLoaderData* data = _head; data != NULL; data = data->next()) { + data->classes_do(InstanceKlass::purge_previous_versions); + } + } + + // Need to purge the previous version before deallocating. + free_deallocate_lists(); +} + void ClassLoaderDataGraph::purge() { assert(SafepointSynchronize::is_at_safepoint(), "must be at safepoint!"); ClassLoaderData* list = _unloading; @@ -821,6 +837,14 @@ #endif } +void ClassLoaderDataGraph::free_deallocate_lists() { + for (ClassLoaderData* cld = _head; cld != NULL; cld = cld->next()) { + // We need to keep this data until InstanceKlass::purge_previous_version has been + // called on all alive classes. See the comment in ClassLoaderDataGraph::clean_metaspaces. + cld->free_deallocate_list(); + } +} + // CDS support // Global metaspaces for writing information to the shared archive. When @@ -959,4 +983,4 @@ event.commit(); } -#endif /* INCLUDE_TRACE */ +#endif // INCLUDE_TRACE
--- a/src/share/vm/classfile/classLoaderData.hpp Thu Jan 08 12:47:32 2015 +0000 +++ b/src/share/vm/classfile/classLoaderData.hpp Tue Feb 03 16:48:05 2015 +0000 @@ -31,8 +31,9 @@ #include "memory/metaspaceCounters.hpp" #include "runtime/mutex.hpp" #include "utilities/growableArray.hpp" +#include "utilities/macros.hpp" #if INCLUDE_TRACE -# include "utilities/ticks.hpp" +#include "utilities/ticks.hpp" #endif // @@ -71,6 +72,7 @@ static ClassLoaderData* add(Handle class_loader, bool anonymous, TRAPS); static void post_class_unload_events(void); + static void clean_metaspaces(); public: static ClassLoaderData* find_or_create(Handle class_loader, TRAPS); static void purge(); @@ -89,7 +91,7 @@ static void classes_do(void f(Klass* const)); static void loaded_classes_do(KlassClosure* klass_closure); static void classes_unloading_do(void f(Klass* const)); - static bool do_unloading(BoolObjectClosure* is_alive); + static bool do_unloading(BoolObjectClosure* is_alive, bool clean_alive); // CMS support. static void remember_new_clds(bool remember) { _saved_head = (remember ? _head : NULL); } @@ -105,6 +107,8 @@ } } + static void free_deallocate_lists(); + static void dump_on(outputStream * const out) PRODUCT_RETURN; static void dump() { dump_on(tty); } static void verify();
--- a/src/share/vm/classfile/classLoaderExt.hpp Thu Jan 08 12:47:32 2015 +0000 +++ b/src/share/vm/classfile/classLoaderExt.hpp Tue Feb 03 16:48:05 2015 +0000 @@ -63,7 +63,19 @@ ClassPathEntry* new_entry) { ClassLoader::add_to_list(new_entry); } + static void append_boot_classpath(ClassPathEntry* new_entry) { + ClassLoader::add_to_list(new_entry); + } static void setup_search_paths() {} + + static void init_lookup_cache(TRAPS) {} + static void copy_lookup_cache_to_archive(char** top, char* end) {} + static char* restore_lookup_cache_from_archive(char* buffer) {return buffer;} + static inline bool is_lookup_cache_enabled() {return false;} + + static bool known_to_not_exist(JNIEnv *env, jobject loader, const char *classname, TRAPS) {return false;} + static jobjectArray get_lookup_cache_urls(JNIEnv *env, jobject loader, TRAPS) {return NULL;} + static jintArray get_lookup_cache(JNIEnv *env, jobject loader, const char *pkgname, TRAPS) {return NULL;} }; #endif // SHARE_VM_CLASSFILE_CLASSLOADEREXT_HPP
--- a/src/share/vm/classfile/dictionary.cpp Thu Jan 08 12:47:32 2015 +0000 +++ b/src/share/vm/classfile/dictionary.cpp Tue Feb 03 16:48:05 2015 +0000 @@ -223,7 +223,7 @@ } free_entry(probe); ResourceMark rm; - tty->print_cr("Removed error class: %s", ik->external_name()); + tty->print_cr("Preload Warning: Removed error class: %s", ik->external_name()); continue; }
--- a/src/share/vm/classfile/javaClasses.cpp Thu Jan 08 12:47:32 2015 +0000 +++ b/src/share/vm/classfile/javaClasses.cpp Tue Feb 03 16:48:05 2015 +0000 @@ -41,6 +41,7 @@ #include "oops/method.hpp" #include "oops/symbol.hpp" #include "oops/typeArrayOop.hpp" +#include "prims/jvmtiRedefineClassesTrace.hpp" #include "runtime/fieldDescriptor.hpp" #include "runtime/handles.inline.hpp" #include "runtime/interfaceSupport.hpp" @@ -2775,12 +2776,35 @@ return (Metadata*)mname->address_field(_vmtarget_offset); } +bool java_lang_invoke_MemberName::is_method(oop mname) { + assert(is_instance(mname), "must be MemberName"); + return (flags(mname) & (MN_IS_METHOD | MN_IS_CONSTRUCTOR)) > 0; +} + #if INCLUDE_JVMTI // Can be executed on VM thread only -void java_lang_invoke_MemberName::adjust_vmtarget(oop mname, Metadata* ref) { - assert((is_instance(mname) && (flags(mname) & (MN_IS_METHOD | MN_IS_CONSTRUCTOR)) > 0), "wrong type"); +void java_lang_invoke_MemberName::adjust_vmtarget(oop mname, Method* old_method, + Method* new_method, bool* trace_name_printed) { + assert(is_method(mname), "wrong type"); assert(Thread::current()->is_VM_thread(), "not VM thread"); - mname->address_field_put(_vmtarget_offset, (address)ref); + + Method* target = (Method*)mname->address_field(_vmtarget_offset); + if (target == old_method) { + mname->address_field_put(_vmtarget_offset, (address)new_method); + + if (RC_TRACE_IN_RANGE(0x00100000, 0x00400000)) { + if (!(*trace_name_printed)) { + // RC_TRACE_MESG macro has an embedded ResourceMark + RC_TRACE_MESG(("adjust: name=%s", + old_method->method_holder()->external_name())); + *trace_name_printed = true; + } + // RC_TRACE macro has an embedded ResourceMark + RC_TRACE(0x00400000, ("MemberName method update: %s(%s)", + new_method->name()->as_C_string(), + new_method->signature()->as_C_string())); + } + } } #endif // INCLUDE_JVMTI
--- a/src/share/vm/classfile/javaClasses.hpp Thu Jan 08 12:47:32 2015 +0000 +++ b/src/share/vm/classfile/javaClasses.hpp Tue Feb 03 16:48:05 2015 +0000 @@ -1096,7 +1096,8 @@ static Metadata* vmtarget(oop mname); static void set_vmtarget(oop mname, Metadata* target); #if INCLUDE_JVMTI - static void adjust_vmtarget(oop mname, Metadata* target); + static void adjust_vmtarget(oop mname, Method* old_method, Method* new_method, + bool* trace_name_printed); #endif // INCLUDE_JVMTI static intptr_t vmindex(oop mname); @@ -1110,6 +1111,8 @@ return obj != NULL && is_subclass(obj->klass()); } + static bool is_method(oop obj); + // Relevant integer codes (keep these in synch. with MethodHandleNatives.Constants): enum { MN_IS_METHOD = 0x00010000, // method (not constructor)
--- a/src/share/vm/classfile/metadataOnStackMark.cpp Thu Jan 08 12:47:32 2015 +0000 +++ b/src/share/vm/classfile/metadataOnStackMark.cpp Tue Feb 03 16:48:05 2015 +0000 @@ -31,25 +31,23 @@ #include "runtime/synchronizer.hpp" #include "runtime/thread.hpp" #include "services/threadService.hpp" -#include "utilities/growableArray.hpp" - +#include "utilities/chunkedList.hpp" -// Keep track of marked on-stack metadata so it can be cleared. -GrowableArray<Metadata*>* _marked_objects = NULL; +volatile MetadataOnStackBuffer* MetadataOnStackMark::_used_buffers = NULL; +volatile MetadataOnStackBuffer* MetadataOnStackMark::_free_buffers = NULL; + NOT_PRODUCT(bool MetadataOnStackMark::_is_active = false;) // Walk metadata on the stack and mark it so that redefinition doesn't delete // it. Class unloading also walks the previous versions and might try to // delete it, so this class is used by class unloading also. -MetadataOnStackMark::MetadataOnStackMark() { +MetadataOnStackMark::MetadataOnStackMark(bool visit_code_cache) { assert(SafepointSynchronize::is_at_safepoint(), "sanity check"); + assert(_used_buffers == NULL, "sanity check"); NOT_PRODUCT(_is_active = true;) - if (_marked_objects == NULL) { - _marked_objects = new (ResourceObj::C_HEAP, mtClass) GrowableArray<Metadata*>(1000, true); - } Threads::metadata_do(Metadata::mark_on_stack); - if (JvmtiExport::has_redefined_a_class()) { + if (visit_code_cache) { CodeCache::alive_nmethods_do(nmethod::mark_on_stack); } CompileBroker::mark_on_stack(); @@ -62,15 +60,93 @@ // Unmark everything that was marked. Can't do the same walk because // redefine classes messes up the code cache so the set of methods // might not be the same. - for (int i = 0; i< _marked_objects->length(); i++) { - _marked_objects->at(i)->set_on_stack(false); + + retire_buffer_for_thread(Thread::current()); + + MetadataOnStackBuffer* buffer = const_cast<MetadataOnStackBuffer* >(_used_buffers); + while (buffer != NULL) { + // Clear on stack state for all metadata. + size_t size = buffer->size(); + for (size_t i = 0; i < size; i++) { + Metadata* md = buffer->at(i); + md->set_on_stack(false); + } + + MetadataOnStackBuffer* next = buffer->next_used(); + + // Move the buffer to the free list. + buffer->clear(); + buffer->set_next_used(NULL); + buffer->set_next_free(const_cast<MetadataOnStackBuffer*>(_free_buffers)); + _free_buffers = buffer; + + // Step to next used buffer. + buffer = next; } - _marked_objects->clear(); // reuse growable array for next time. + + _used_buffers = NULL; + NOT_PRODUCT(_is_active = false;) } +void MetadataOnStackMark::retire_buffer(MetadataOnStackBuffer* buffer) { + if (buffer == NULL) { + return; + } + + MetadataOnStackBuffer* old_head; + + do { + old_head = const_cast<MetadataOnStackBuffer*>(_used_buffers); + buffer->set_next_used(old_head); + } while (Atomic::cmpxchg_ptr(buffer, &_used_buffers, old_head) != old_head); +} + +void MetadataOnStackMark::retire_buffer_for_thread(Thread* thread) { + retire_buffer(thread->metadata_on_stack_buffer()); + thread->set_metadata_on_stack_buffer(NULL); +} + +bool MetadataOnStackMark::has_buffer_for_thread(Thread* thread) { + return thread->metadata_on_stack_buffer() != NULL; +} + +MetadataOnStackBuffer* MetadataOnStackMark::allocate_buffer() { + MetadataOnStackBuffer* allocated; + MetadataOnStackBuffer* new_head; + + do { + allocated = const_cast<MetadataOnStackBuffer*>(_free_buffers); + if (allocated == NULL) { + break; + } + new_head = allocated->next_free(); + } while (Atomic::cmpxchg_ptr(new_head, &_free_buffers, allocated) != allocated); + + if (allocated == NULL) { + allocated = new MetadataOnStackBuffer(); + } + + assert(!allocated->is_full(), err_msg("Should not be full: " PTR_FORMAT, p2i(allocated))); + + return allocated; +} + // Record which objects are marked so we can unmark the same objects. -void MetadataOnStackMark::record(Metadata* m) { +void MetadataOnStackMark::record(Metadata* m, Thread* thread) { assert(_is_active, "metadata on stack marking is active"); - _marked_objects->push(m); + + MetadataOnStackBuffer* buffer = thread->metadata_on_stack_buffer(); + + if (buffer != NULL && buffer->is_full()) { + retire_buffer(buffer); + buffer = NULL; + } + + if (buffer == NULL) { + buffer = allocate_buffer(); + thread->set_metadata_on_stack_buffer(buffer); + } + + buffer->push(m); }
--- a/src/share/vm/classfile/metadataOnStackMark.hpp Thu Jan 08 12:47:32 2015 +0000 +++ b/src/share/vm/classfile/metadataOnStackMark.hpp Tue Feb 03 16:48:05 2015 +0000 @@ -26,9 +26,12 @@ #define SHARE_VM_CLASSFILE_METADATAONSTACKMARK_HPP #include "memory/allocation.hpp" +#include "utilities/chunkedList.hpp" class Metadata; +typedef ChunkedList<Metadata*, mtInternal> MetadataOnStackBuffer; + // Helper class to mark and unmark metadata used on the stack as either handles // or executing methods, so that it can't be deleted during class redefinition // and class unloading. @@ -36,10 +39,20 @@ // metadata during parsing, relocated methods, and methods in backtraces. class MetadataOnStackMark : public StackObj { NOT_PRODUCT(static bool _is_active;) + + static volatile MetadataOnStackBuffer* _used_buffers; + static volatile MetadataOnStackBuffer* _free_buffers; + + static MetadataOnStackBuffer* allocate_buffer(); + static void retire_buffer(MetadataOnStackBuffer* buffer); + public: - MetadataOnStackMark(); - ~MetadataOnStackMark(); - static void record(Metadata* m); + MetadataOnStackMark(bool visit_code_cache); + ~MetadataOnStackMark(); + + static void record(Metadata* m, Thread* thread); + static void retire_buffer_for_thread(Thread* thread); + static bool has_buffer_for_thread(Thread* thread); }; #endif // SHARE_VM_CLASSFILE_METADATAONSTACKMARK_HPP
--- a/src/share/vm/classfile/systemDictionary.cpp Thu Jan 08 12:47:32 2015 +0000 +++ b/src/share/vm/classfile/systemDictionary.cpp Tue Feb 03 16:48:05 2015 +0000 @@ -64,9 +64,8 @@ #include "services/threadService.hpp" #include "utilities/macros.hpp" #include "utilities/ticks.hpp" - #if INCLUDE_TRACE - #include "trace/tracing.hpp" +#include "trace/tracing.hpp" #endif Dictionary* SystemDictionary::_dictionary = NULL; @@ -1691,9 +1690,9 @@ // Assumes classes in the SystemDictionary are only unloaded at a safepoint // Note: anonymous classes are not in the SD. -bool SystemDictionary::do_unloading(BoolObjectClosure* is_alive) { +bool SystemDictionary::do_unloading(BoolObjectClosure* is_alive, bool clean_alive) { // First, mark for unload all ClassLoaderData referencing a dead class loader. - bool unloading_occurred = ClassLoaderDataGraph::do_unloading(is_alive); + bool unloading_occurred = ClassLoaderDataGraph::do_unloading(is_alive, clean_alive); if (unloading_occurred) { dictionary()->do_unloading(); constraints()->purge_loader_constraints(); @@ -1908,11 +1907,12 @@ InstanceKlass::cast(WK_KLASS(Reference_klass))->set_reference_type(REF_OTHER); InstanceRefKlass::update_nonstatic_oop_maps(WK_KLASS(Reference_klass)); - initialize_wk_klasses_through(WK_KLASS_ENUM_NAME(PhantomReference_klass), scan, CHECK); + initialize_wk_klasses_through(WK_KLASS_ENUM_NAME(Cleaner_klass), scan, CHECK); InstanceKlass::cast(WK_KLASS(SoftReference_klass))->set_reference_type(REF_SOFT); InstanceKlass::cast(WK_KLASS(WeakReference_klass))->set_reference_type(REF_WEAK); InstanceKlass::cast(WK_KLASS(FinalReference_klass))->set_reference_type(REF_FINAL); InstanceKlass::cast(WK_KLASS(PhantomReference_klass))->set_reference_type(REF_PHANTOM); + InstanceKlass::cast(WK_KLASS(Cleaner_klass))->set_reference_type(REF_CLEANER); // JSR 292 classes WKID jsr292_group_start = WK_KLASS_ENUM_NAME(MethodHandle_klass); @@ -2664,7 +2664,7 @@ class_loader->klass() : (Klass*)NULL); event.commit(); } -#endif /* INCLUDE_TRACE */ +#endif // INCLUDE_TRACE } #ifndef PRODUCT
--- a/src/share/vm/classfile/systemDictionary.hpp Thu Jan 08 12:47:32 2015 +0000 +++ b/src/share/vm/classfile/systemDictionary.hpp Tue Feb 03 16:48:05 2015 +0000 @@ -128,6 +128,7 @@ do_klass(WeakReference_klass, java_lang_ref_WeakReference, Pre ) \ do_klass(FinalReference_klass, java_lang_ref_FinalReference, Pre ) \ do_klass(PhantomReference_klass, java_lang_ref_PhantomReference, Pre ) \ + do_klass(Cleaner_klass, sun_misc_Cleaner, Pre ) \ do_klass(Finalizer_klass, java_lang_ref_Finalizer, Pre ) \ \ do_klass(Thread_klass, java_lang_Thread, Pre ) \ @@ -175,6 +176,8 @@ do_klass(URL_klass, java_net_URL, Pre ) \ do_klass(Jar_Manifest_klass, java_util_jar_Manifest, Pre ) \ do_klass(sun_misc_Launcher_klass, sun_misc_Launcher, Pre ) \ + do_klass(sun_misc_Launcher_AppClassLoader_klass, sun_misc_Launcher_AppClassLoader, Pre ) \ + do_klass(sun_misc_Launcher_ExtClassLoader_klass, sun_misc_Launcher_ExtClassLoader, Pre ) \ do_klass(CodeSource_klass, java_security_CodeSource, Pre ) \ \ /* It's NULL in non-1.4 JDKs. */ \ @@ -339,7 +342,7 @@ // Unload (that is, break root links to) all unmarked classes and // loaders. Returns "true" iff something was unloaded. - static bool do_unloading(BoolObjectClosure* is_alive); + static bool do_unloading(BoolObjectClosure* is_alive, bool clean_alive = true); // Used by DumpSharedSpaces only to remove classes that failed verification static void remove_classes_in_error_state();
--- a/src/share/vm/classfile/verifier.cpp Thu Jan 08 12:47:32 2015 +0000 +++ b/src/share/vm/classfile/verifier.cpp Tue Feb 03 16:48:05 2015 +0000 @@ -1556,14 +1556,14 @@ case Bytecodes::_invokespecial : case Bytecodes::_invokestatic : verify_invoke_instructions( - &bcs, code_length, ¤t_frame, - &this_uninit, return_type, cp, CHECK_VERIFY(this)); + &bcs, code_length, ¤t_frame, (bci >= ex_min && bci < ex_max), + &this_uninit, return_type, cp, &stackmap_table, CHECK_VERIFY(this)); no_control_flow = false; break; case Bytecodes::_invokeinterface : case Bytecodes::_invokedynamic : verify_invoke_instructions( - &bcs, code_length, ¤t_frame, - &this_uninit, return_type, cp, CHECK_VERIFY(this)); + &bcs, code_length, ¤t_frame, (bci >= ex_min && bci < ex_max), + &this_uninit, return_type, cp, &stackmap_table, CHECK_VERIFY(this)); no_control_flow = false; break; case Bytecodes::_new : { @@ -2411,8 +2411,9 @@ void ClassVerifier::verify_invoke_init( RawBytecodeStream* bcs, u2 ref_class_index, VerificationType ref_class_type, - StackMapFrame* current_frame, u4 code_length, bool *this_uninit, - constantPoolHandle cp, TRAPS) { + StackMapFrame* current_frame, u4 code_length, bool in_try_block, + bool *this_uninit, constantPoolHandle cp, StackMapTable* stackmap_table, + TRAPS) { u2 bci = bcs->bci(); VerificationType type = current_frame->pop_stack( VerificationType::reference_check(), CHECK_VERIFY(this)); @@ -2428,28 +2429,36 @@ return; } - // Check if this call is done from inside of a TRY block. If so, make - // sure that all catch clause paths end in a throw. Otherwise, this - // can result in returning an incomplete object. - ExceptionTable exhandlers(_method()); - int exlength = exhandlers.length(); - for(int i = 0; i < exlength; i++) { - u2 start_pc = exhandlers.start_pc(i); - u2 end_pc = exhandlers.end_pc(i); + // If this invokespecial call is done from inside of a TRY block then make + // sure that all catch clause paths end in a throw. Otherwise, this can + // result in returning an incomplete object. + if (in_try_block) { + ExceptionTable exhandlers(_method()); + int exlength = exhandlers.length(); + for(int i = 0; i < exlength; i++) { + u2 start_pc = exhandlers.start_pc(i); + u2 end_pc = exhandlers.end_pc(i); - if (bci >= start_pc && bci < end_pc) { - if (!ends_in_athrow(exhandlers.handler_pc(i))) { - verify_error(ErrorContext::bad_code(bci), - "Bad <init> method call from after the start of a try block"); - return; - } else if (VerboseVerification) { - ResourceMark rm; - tty->print_cr( - "Survived call to ends_in_athrow(): %s", - current_class()->name()->as_C_string()); + if (bci >= start_pc && bci < end_pc) { + if (!ends_in_athrow(exhandlers.handler_pc(i))) { + verify_error(ErrorContext::bad_code(bci), + "Bad <init> method call from after the start of a try block"); + return; + } else if (VerboseVerification) { + ResourceMark rm; + tty->print_cr( + "Survived call to ends_in_athrow(): %s", + current_class()->name()->as_C_string()); + } } } - } + + // Check the exception handler target stackmaps with the locals from the + // incoming stackmap (before initialize_object() changes them to outgoing + // state). + verify_exception_handler_targets(bci, true, current_frame, + stackmap_table, CHECK_VERIFY(this)); + } // in_try_block current_frame->initialize_object(type, current_type()); *this_uninit = true; @@ -2503,6 +2512,13 @@ } } } + // Check the exception handler target stackmaps with the locals from the + // incoming stackmap (before initialize_object() changes them to outgoing + // state). + if (in_try_block) { + verify_exception_handler_targets(bci, *this_uninit, current_frame, + stackmap_table, CHECK_VERIFY(this)); + } current_frame->initialize_object(type, new_class_type); } else { verify_error(ErrorContext::bad_type(bci, current_frame->stack_top_ctx()), @@ -2531,8 +2547,8 @@ void ClassVerifier::verify_invoke_instructions( RawBytecodeStream* bcs, u4 code_length, StackMapFrame* current_frame, - bool *this_uninit, VerificationType return_type, - constantPoolHandle cp, TRAPS) { + bool in_try_block, bool *this_uninit, VerificationType return_type, + constantPoolHandle cp, StackMapTable* stackmap_table, TRAPS) { // Make sure the constant pool item is the right type u2 index = bcs->get_index_u2(); Bytecodes::Code opcode = bcs->raw_code(); @@ -2702,7 +2718,8 @@ opcode != Bytecodes::_invokedynamic) { if (method_name == vmSymbols::object_initializer_name()) { // <init> method verify_invoke_init(bcs, index, ref_class_type, current_frame, - code_length, this_uninit, cp, CHECK_VERIFY(this)); + code_length, in_try_block, this_uninit, cp, stackmap_table, + CHECK_VERIFY(this)); } else { // other methods // Ensures that target class is assignable to method class. if (opcode == Bytecodes::_invokespecial) {
--- a/src/share/vm/classfile/verifier.hpp Thu Jan 08 12:47:32 2015 +0000 +++ b/src/share/vm/classfile/verifier.hpp Tue Feb 03 16:48:05 2015 +0000 @@ -301,8 +301,9 @@ void verify_invoke_init( RawBytecodeStream* bcs, u2 ref_index, VerificationType ref_class_type, - StackMapFrame* current_frame, u4 code_length, bool* this_uninit, - constantPoolHandle cp, TRAPS); + StackMapFrame* current_frame, u4 code_length, bool in_try_block, + bool* this_uninit, constantPoolHandle cp, StackMapTable* stackmap_table, + TRAPS); // Used by ends_in_athrow() to push all handlers that contain bci onto // the handler_stack, if the handler is not already on the stack. @@ -316,8 +317,8 @@ void verify_invoke_instructions( RawBytecodeStream* bcs, u4 code_length, StackMapFrame* current_frame, - bool* this_uninit, VerificationType return_type, - constantPoolHandle cp, TRAPS); + bool in_try_block, bool* this_uninit, VerificationType return_type, + constantPoolHandle cp, StackMapTable* stackmap_table, TRAPS); VerificationType get_newarray_type(u2 index, u2 bci, TRAPS); void verify_anewarray(u2 bci, u2 index, constantPoolHandle cp,
--- a/src/share/vm/classfile/vmSymbols.hpp Thu Jan 08 12:47:32 2015 +0000 +++ b/src/share/vm/classfile/vmSymbols.hpp Tue Feb 03 16:48:05 2015 +0000 @@ -79,6 +79,7 @@ template(java_lang_ref_WeakReference, "java/lang/ref/WeakReference") \ template(java_lang_ref_FinalReference, "java/lang/ref/FinalReference") \ template(java_lang_ref_PhantomReference, "java/lang/ref/PhantomReference") \ + template(sun_misc_Cleaner, "sun/misc/Cleaner") \ template(java_lang_ref_Finalizer, "java/lang/ref/Finalizer") \ template(java_lang_reflect_AccessibleObject, "java/lang/reflect/AccessibleObject") \ template(java_lang_reflect_Method, "java/lang/reflect/Method") \ @@ -116,6 +117,7 @@ template(java_lang_AssertionStatusDirectives, "java/lang/AssertionStatusDirectives") \ template(getBootClassPathEntryForClass_name, "getBootClassPathEntryForClass") \ template(sun_misc_PostVMInitHook, "sun/misc/PostVMInitHook") \ + template(sun_misc_Launcher_AppClassLoader, "sun/misc/Launcher$AppClassLoader") \ template(sun_misc_Launcher_ExtClassLoader, "sun/misc/Launcher$ExtClassLoader") \ \ /* Java runtime version access */ \
--- a/src/share/vm/code/dependencies.cpp Thu Jan 08 12:47:32 2015 +0000 +++ b/src/share/vm/code/dependencies.cpp Tue Feb 03 16:48:05 2015 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2014, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -560,7 +560,7 @@ put_star = !Dependencies::is_concrete_klass((Klass*)arg.metadata_value()); } else if (arg.is_method()) { what = "method "; - put_star = !Dependencies::is_concrete_method((Method*)arg.metadata_value()); + put_star = !Dependencies::is_concrete_method((Method*)arg.metadata_value(), NULL); } else if (arg.is_klass()) { what = "class "; } else { @@ -845,8 +845,8 @@ // Static methods don't override non-static so punt return true; } - if ( !Dependencies::is_concrete_method(lm) - && !Dependencies::is_concrete_method(m) + if ( !Dependencies::is_concrete_method(lm, k) + && !Dependencies::is_concrete_method(m, ctxk) && lm->method_holder()->is_subtype_of(m->method_holder())) // Method m is overridden by lm, but both are non-concrete. return true; @@ -879,9 +879,20 @@ bool is_witness(Klass* k) { if (doing_subtype_search()) { return Dependencies::is_concrete_klass(k); + } else if (!k->oop_is_instance()) { + return false; // no methods to find in an array type } else { - Method* m = InstanceKlass::cast(k)->find_method(_name, _signature); - if (m == NULL || !Dependencies::is_concrete_method(m)) return false; + // Search class hierarchy first. + Method* m = InstanceKlass::cast(k)->find_instance_method(_name, _signature); + if (!Dependencies::is_concrete_method(m, k)) { + // Check interface defaults also, if any exist. + Array<Method*>* default_methods = InstanceKlass::cast(k)->default_methods(); + if (default_methods == NULL) + return false; + m = InstanceKlass::cast(k)->find_method(default_methods, _name, _signature); + if (!Dependencies::is_concrete_method(m, NULL)) + return false; + } _found_methods[_num_participants] = m; // Note: If add_participant(k) is called, // the method m will already be memoized for it. @@ -1085,7 +1096,7 @@ Klass* chain; // scratch variable #define ADD_SUBCLASS_CHAIN(k) { \ assert(chaini < CHAINMAX, "oob"); \ - chain = InstanceKlass::cast(k)->subklass(); \ + chain = k->subklass(); \ if (chain != NULL) chains[chaini++] = chain; } // Look for non-abstract subclasses. @@ -1096,35 +1107,37 @@ // (Their subclasses are additional indirect implementors. // See InstanceKlass::add_implementor.) // (Note: nof_implementors is always zero for non-interfaces.) - int nof_impls = InstanceKlass::cast(context_type)->nof_implementors(); - if (nof_impls > 1) { - // Avoid this case: *I.m > { A.m, C }; B.m > C - // Here, I.m has 2 concrete implementations, but m appears unique - // as A.m, because the search misses B.m when checking C. - // The inherited method B.m was getting missed by the walker - // when interface 'I' was the starting point. - // %%% Until this is fixed more systematically, bail out. - // (Old CHA had the same limitation.) - return context_type; - } - if (nof_impls > 0) { - Klass* impl = InstanceKlass::cast(context_type)->implementor(); - assert(impl != NULL, "just checking"); - // If impl is the same as the context_type, then more than one - // implementor has seen. No exact info in this case. - if (impl == context_type) { - return context_type; // report an inexact witness to this sad affair + if (top_level_call) { + int nof_impls = InstanceKlass::cast(context_type)->nof_implementors(); + if (nof_impls > 1) { + // Avoid this case: *I.m > { A.m, C }; B.m > C + // Here, I.m has 2 concrete implementations, but m appears unique + // as A.m, because the search misses B.m when checking C. + // The inherited method B.m was getting missed by the walker + // when interface 'I' was the starting point. + // %%% Until this is fixed more systematically, bail out. + // (Old CHA had the same limitation.) + return context_type; } - if (do_counts) - { NOT_PRODUCT(deps_find_witness_steps++); } - if (is_participant(impl)) { - if (!participants_hide_witnesses) { + if (nof_impls > 0) { + Klass* impl = InstanceKlass::cast(context_type)->implementor(); + assert(impl != NULL, "just checking"); + // If impl is the same as the context_type, then more than one + // implementor has seen. No exact info in this case. + if (impl == context_type) { + return context_type; // report an inexact witness to this sad affair + } + if (do_counts) + { NOT_PRODUCT(deps_find_witness_steps++); } + if (is_participant(impl)) { + if (!participants_hide_witnesses) { + ADD_SUBCLASS_CHAIN(impl); + } + } else if (is_witness(impl) && !ignore_witness(impl)) { + return impl; + } else { ADD_SUBCLASS_CHAIN(impl); } - } else if (is_witness(impl) && !ignore_witness(impl)) { - return impl; - } else { - ADD_SUBCLASS_CHAIN(impl); } } @@ -1172,15 +1185,17 @@ return true; } -bool Dependencies::is_concrete_method(Method* m) { - // Statics are irrelevant to virtual call sites. - if (m->is_static()) return false; - - // We could also return false if m does not yet appear to be - // executed, if the VM version supports this distinction also. - // Default methods are considered "concrete" as well. - return !m->is_abstract() && - !m->is_overpass(); // error functions aren't concrete +bool Dependencies::is_concrete_method(Method* m, Klass * k) { + // NULL is not a concrete method, + // statics are irrelevant to virtual call sites, + // abstract methods are not concrete, + // overpass (error) methods are not concrete if k is abstract + // + // note "true" is conservative answer -- + // overpass clause is false if k == NULL, implies return true if + // answer depends on overpass clause. + return ! ( m == NULL || m -> is_static() || m -> is_abstract() || + m->is_overpass() && k != NULL && k -> is_abstract() ); } @@ -1205,16 +1220,6 @@ return true; } -bool Dependencies::is_concrete_method(ciMethod* m) { - // Statics are irrelevant to virtual call sites. - if (m->is_static()) return false; - - // We could also return false if m does not yet appear to be - // executed, if the VM version supports this distinction also. - return !m->is_abstract(); -} - - bool Dependencies::has_finalizable_subclass(ciInstanceKlass* k) { return k->has_finalizable_subclass(); } @@ -1428,7 +1433,7 @@ Klass* wit = wf.find_witness_definer(ctxk); if (wit != NULL) return NULL; // Too many witnesses. Method* fm = wf.found_method(0); // Will be NULL if num_parts == 0. - if (Dependencies::is_concrete_method(m)) { + if (Dependencies::is_concrete_method(m, ctxk)) { if (fm == NULL) { // It turns out that m was always the only implementation. fm = m; @@ -1458,61 +1463,6 @@ return wf.find_witness_definer(ctxk, changes); } -// Find the set of all non-abstract methods under ctxk that match m[0]. -// (The method m[0] must be defined or inherited in ctxk.) -// Include m itself in the set, unless it is abstract. -// Fill the given array m[0..(mlen-1)] with this set, and return the length. -// (The length may be zero if no concrete methods are found anywhere.) -// If there are too many concrete methods to fit in marray, return -1. -int Dependencies::find_exclusive_concrete_methods(Klass* ctxk, - int mlen, - Method* marray[]) { - Method* m0 = marray[0]; - ClassHierarchyWalker wf(m0); - assert(wf.check_method_context(ctxk, m0), "proper context"); - wf.record_witnesses(mlen); - bool participants_hide_witnesses = true; - Klass* wit = wf.find_witness_definer(ctxk); - if (wit != NULL) return -1; // Too many witnesses. - int num = wf.num_participants(); - assert(num <= mlen, "oob"); - // Keep track of whether m is also part of the result set. - int mfill = 0; - assert(marray[mfill] == m0, "sanity"); - if (Dependencies::is_concrete_method(m0)) - mfill++; // keep m0 as marray[0], the first result - for (int i = 0; i < num; i++) { - Method* fm = wf.found_method(i); - if (fm == m0) continue; // Already put this guy in the list. - if (mfill == mlen) { - return -1; // Oops. Too many methods after all! - } - marray[mfill++] = fm; - } -#ifndef PRODUCT - // Make sure the dependency mechanism will pass this discovery: - if (VerifyDependencies) { - // Turn off dependency tracing while actually testing deps. - FlagSetting fs(TraceDependencies, false); - switch (mfill) { - case 1: - guarantee(NULL == (void *)check_unique_concrete_method(ctxk, marray[0]), - "verify dep."); - break; - case 2: - guarantee(NULL == (void *) - check_exclusive_concrete_methods(ctxk, marray[0], marray[1]), - "verify dep."); - break; - default: - ShouldNotReachHere(); // mlen > 2 yet supported - } - } -#endif //PRODUCT - return mfill; -} - - Klass* Dependencies::check_has_no_finalizable_subclasses(Klass* ctxk, KlassDepChange* changes) { Klass* search_at = ctxk; if (changes != NULL) @@ -1520,7 +1470,6 @@ return find_finalizable_subclass(search_at); } - Klass* Dependencies::check_call_site_target_value(oop call_site, oop method_handle, CallSiteDepChange* changes) { assert(call_site ->is_a(SystemDictionary::CallSite_klass()), "sanity"); assert(method_handle->is_a(SystemDictionary::MethodHandle_klass()), "sanity");
--- a/src/share/vm/code/dependencies.hpp Thu Jan 08 12:47:32 2015 +0000 +++ b/src/share/vm/code/dependencies.hpp Tue Feb 03 16:48:05 2015 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2014, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -287,7 +287,7 @@ // In that case, there would be a middle ground between concrete // and abstract (as defined by the Java language and VM). static bool is_concrete_klass(Klass* k); // k is instantiable - static bool is_concrete_method(Method* m); // m is invocable + static bool is_concrete_method(Method* m, Klass* k); // m is invocable static Klass* find_finalizable_subclass(Klass* k); // These versions of the concreteness queries work through the CI. @@ -301,7 +301,6 @@ // not go back into the VM to get their value; they must cache the // bit in the CI, either eagerly or lazily.) static bool is_concrete_klass(ciInstanceKlass* k); // k appears instantiable - static bool is_concrete_method(ciMethod* m); // m appears invocable static bool has_finalizable_subclass(ciInstanceKlass* k); // As a general rule, it is OK to compile under the assumption that @@ -348,7 +347,6 @@ static Klass* find_unique_concrete_subtype(Klass* ctxk); static Method* find_unique_concrete_method(Klass* ctxk, Method* m); static int find_exclusive_concrete_subtypes(Klass* ctxk, int klen, Klass* k[]); - static int find_exclusive_concrete_methods(Klass* ctxk, int mlen, Method* m[]); // Create the encoding which will be stored in an nmethod. void encode_content_bytes();
--- a/src/share/vm/code/nmethod.cpp Thu Jan 08 12:47:32 2015 +0000 +++ b/src/share/vm/code/nmethod.cpp Tue Feb 03 16:48:05 2015 +0000 @@ -1741,11 +1741,17 @@ set_unload_reported(); } -void static clean_ic_if_metadata_is_dead(CompiledIC *ic, BoolObjectClosure *is_alive) { +void static clean_ic_if_metadata_is_dead(CompiledIC *ic, BoolObjectClosure *is_alive, bool mark_on_stack) { if (ic->is_icholder_call()) { // The only exception is compiledICHolder oops which may // yet be marked below. (We check this further below). CompiledICHolder* cichk_oop = ic->cached_icholder(); + + if (mark_on_stack) { + Metadata::mark_on_stack(cichk_oop->holder_method()); + Metadata::mark_on_stack(cichk_oop->holder_klass()); + } + if (cichk_oop->holder_method()->method_holder()->is_loader_alive(is_alive) && cichk_oop->holder_klass()->is_loader_alive(is_alive)) { return; @@ -1753,6 +1759,10 @@ } else { Metadata* ic_oop = ic->cached_metadata(); if (ic_oop != NULL) { + if (mark_on_stack) { + Metadata::mark_on_stack(ic_oop); + } + if (ic_oop->is_klass()) { if (((Klass*)ic_oop)->is_loader_alive(is_alive)) { return; @@ -1813,7 +1823,7 @@ while(iter.next()) { if (iter.type() == relocInfo::virtual_call_type) { CompiledIC *ic = CompiledIC_at(&iter); - clean_ic_if_metadata_is_dead(ic, is_alive); + clean_ic_if_metadata_is_dead(ic, is_alive, false); } } } @@ -1881,6 +1891,53 @@ return clean_if_nmethod_is_unloaded(csc, csc->destination(), is_alive, from); } +bool nmethod::unload_if_dead_at(RelocIterator* iter_at_oop, BoolObjectClosure *is_alive, bool unloading_occurred) { + assert(iter_at_oop->type() == relocInfo::oop_type, "Wrong relocation type"); + + oop_Relocation* r = iter_at_oop->oop_reloc(); + // Traverse those oops directly embedded in the code. + // Other oops (oop_index>0) are seen as part of scopes_oops. + assert(1 == (r->oop_is_immediate()) + + (r->oop_addr() >= oops_begin() && r->oop_addr() < oops_end()), + "oop must be found in exactly one place"); + if (r->oop_is_immediate() && r->oop_value() != NULL) { + // Unload this nmethod if the oop is dead. + if (can_unload(is_alive, r->oop_addr(), unloading_occurred)) { + return true;; + } + } + + return false; +} + +void nmethod::mark_metadata_on_stack_at(RelocIterator* iter_at_metadata) { + assert(iter_at_metadata->type() == relocInfo::metadata_type, "Wrong relocation type"); + + metadata_Relocation* r = iter_at_metadata->metadata_reloc(); + // In this metadata, we must only follow those metadatas directly embedded in + // the code. Other metadatas (oop_index>0) are seen as part of + // the metadata section below. + assert(1 == (r->metadata_is_immediate()) + + (r->metadata_addr() >= metadata_begin() && r->metadata_addr() < metadata_end()), + "metadata must be found in exactly one place"); + if (r->metadata_is_immediate() && r->metadata_value() != NULL) { + Metadata* md = r->metadata_value(); + if (md != _method) Metadata::mark_on_stack(md); + } +} + +void nmethod::mark_metadata_on_stack_non_relocs() { + // Visit the metadata section + for (Metadata** p = metadata_begin(); p < metadata_end(); p++) { + if (*p == Universe::non_oop_word() || *p == NULL) continue; // skip non-oops + Metadata* md = *p; + Metadata::mark_on_stack(md); + } + + // Visit metadata not embedded in the other places. + if (_method != NULL) Metadata::mark_on_stack(_method); +} + bool nmethod::do_unloading_parallel(BoolObjectClosure* is_alive, bool unloading_occurred) { ResourceMark rm; @@ -1910,6 +1967,11 @@ unloading_occurred = true; } + // When class redefinition is used all metadata in the CodeCache has to be recorded, + // so that unused "previous versions" can be purged. Since walking the CodeCache can + // be expensive, the "mark on stack" is piggy-backed on this parallel unloading code. + bool mark_metadata_on_stack = a_class_was_redefined; + // Exception cache clean_exception_cache(is_alive); @@ -1925,7 +1987,7 @@ if (unloading_occurred) { // If class unloading occurred we first iterate over all inline caches and // clear ICs where the cached oop is referring to an unloaded klass or method. - clean_ic_if_metadata_is_dead(CompiledIC_at(&iter), is_alive); + clean_ic_if_metadata_is_dead(CompiledIC_at(&iter), is_alive, mark_metadata_on_stack); } postponed |= clean_if_nmethod_is_unloaded(CompiledIC_at(&iter), is_alive, this); @@ -1941,24 +2003,21 @@ case relocInfo::oop_type: if (!is_unloaded) { - // Unload check - oop_Relocation* r = iter.oop_reloc(); - // Traverse those oops directly embedded in the code. - // Other oops (oop_index>0) are seen as part of scopes_oops. - assert(1 == (r->oop_is_immediate()) + - (r->oop_addr() >= oops_begin() && r->oop_addr() < oops_end()), - "oop must be found in exactly one place"); - if (r->oop_is_immediate() && r->oop_value() != NULL) { - if (can_unload(is_alive, r->oop_addr(), unloading_occurred)) { - is_unloaded = true; - } - } + is_unloaded = unload_if_dead_at(&iter, is_alive, unloading_occurred); } break; + case relocInfo::metadata_type: + if (mark_metadata_on_stack) { + mark_metadata_on_stack_at(&iter); + } } } + if (mark_metadata_on_stack) { + mark_metadata_on_stack_non_relocs(); + } + if (is_unloaded) { return postponed; } @@ -2106,7 +2165,7 @@ while (iter.next()) { if (iter.type() == relocInfo::metadata_type ) { metadata_Relocation* r = iter.metadata_reloc(); - // In this lmetadata, we must only follow those metadatas directly embedded in + // In this metadata, we must only follow those metadatas directly embedded in // the code. Other metadatas (oop_index>0) are seen as part of // the metadata section below. assert(1 == (r->metadata_is_immediate()) + @@ -2140,7 +2199,7 @@ f(md); } - // Call function Method*, not embedded in these other places. + // Visit metadata not embedded in the other places. if (_method != NULL) f(_method); }
--- a/src/share/vm/code/nmethod.hpp Thu Jan 08 12:47:32 2015 +0000 +++ b/src/share/vm/code/nmethod.hpp Tue Feb 03 16:48:05 2015 +0000 @@ -614,9 +614,16 @@ // The parallel versions are used by G1. bool do_unloading_parallel(BoolObjectClosure* is_alive, bool unloading_occurred); void do_unloading_parallel_postponed(BoolObjectClosure* is_alive, bool unloading_occurred); + + private: // Unload a nmethod if the *root object is dead. bool can_unload(BoolObjectClosure* is_alive, oop* root, bool unloading_occurred); + bool unload_if_dead_at(RelocIterator *iter_at_oop, BoolObjectClosure* is_alive, bool unloading_occurred); + void mark_metadata_on_stack_at(RelocIterator* iter_at_metadata); + void mark_metadata_on_stack_non_relocs(); + + public: void preserve_callee_argument_oops(frame fr, const RegisterMap *reg_map, OopClosure* f); void oops_do(OopClosure* f) { oops_do(f, false); }
--- a/src/share/vm/compiler/compileBroker.cpp Thu Jan 08 12:47:32 2015 +0000 +++ b/src/share/vm/compiler/compileBroker.cpp Tue Feb 03 16:48:05 2015 +0000 @@ -183,9 +183,8 @@ long CompileBroker::_peak_compilation_time = 0; -CompileQueue* CompileBroker::_c2_method_queue = NULL; -CompileQueue* CompileBroker::_c1_method_queue = NULL; -CompileTask* CompileBroker::_task_free_list = NULL; +CompileQueue* CompileBroker::_c2_compile_queue = NULL; +CompileQueue* CompileBroker::_c1_compile_queue = NULL; GrowableArray<CompilerThread*>* CompileBroker::_compiler_threads = NULL; @@ -253,13 +252,56 @@ // By convention, the compiling thread is responsible for // recycling a non-blocking CompileTask. - CompileBroker::free_task(task); + CompileTask::free(task); } } -// ------------------------------------------------------------------ -// CompileTask::initialize +CompileTask* CompileTask::_task_free_list = NULL; +#ifdef ASSERT +int CompileTask::_num_allocated_tasks = 0; +#endif +/** + * Allocate a CompileTask, from the free list if possible. + */ +CompileTask* CompileTask::allocate() { + MutexLocker locker(CompileTaskAlloc_lock); + CompileTask* task = NULL; + + if (_task_free_list != NULL) { + task = _task_free_list; + _task_free_list = task->next(); + task->set_next(NULL); + } else { + task = new CompileTask(); + DEBUG_ONLY(_num_allocated_tasks++;) + assert (_num_allocated_tasks < 10000, "Leaking compilation tasks?"); + task->set_next(NULL); + task->set_is_free(true); + } + assert(task->is_free(), "Task must be free."); + task->set_is_free(false); + return task; +} + + +/** + * Add a task to the free list. + */ +void CompileTask::free(CompileTask* task) { + MutexLocker locker(CompileTaskAlloc_lock); + if (!task->is_free()) { + task->set_code(NULL); + assert(!task->lock()->is_locked(), "Should not be locked when freed"); + JNIHandles::destroy_global(task->_method_holder); + JNIHandles::destroy_global(task->_hot_method_holder); + + task->set_is_free(true); + task->set_next(_task_free_list); + _task_free_list = task; + } +} + void CompileTask::initialize(int compile_id, methodHandle method, int osr_bci, @@ -318,15 +360,6 @@ if (nm == NULL) _code_handle = NULL; // drop the handle also } -// ------------------------------------------------------------------ -// CompileTask::free -void CompileTask::free() { - set_code(NULL); - assert(!_lock->is_locked(), "Should not be locked when freed"); - JNIHandles::destroy_global(_method_holder); - JNIHandles::destroy_global(_hot_method_holder); -} - void CompileTask::mark_on_stack() { // Mark these methods as something redefine classes cannot remove. @@ -594,9 +627,12 @@ -// Add a CompileTask to a CompileQueue +/** + * Add a CompileTask to a CompileQueue + */ void CompileQueue::add(CompileTask* task) { assert(lock()->owned_by_self(), "must own lock"); + assert(!CompileBroker::is_compilation_disabled_forever(), "Do not add task if compilation is turned off forever"); task->set_next(NULL); task->set_prev(NULL); @@ -618,9 +654,7 @@ // Mark the method as being in the compile queue. task->method()->set_queued_for_compilation(); - if (CIPrintCompileQueue) { - print(); - } + NOT_PRODUCT(print();) if (LogCompilation && xtty != NULL) { task->log_task_queued(); @@ -630,14 +664,32 @@ lock()->notify_all(); } -void CompileQueue::delete_all() { - assert(lock()->owned_by_self(), "must own lock"); - if (_first != NULL) { - for (CompileTask* task = _first; task != NULL; task = task->next()) { - delete task; +/** + * Empties compilation queue by putting all compilation tasks onto + * a freelist. Furthermore, the method wakes up all threads that are + * waiting on a compilation task to finish. This can happen if background + * compilation is disabled. + */ +void CompileQueue::free_all() { + MutexLocker mu(lock()); + CompileTask* next = _first; + + // Iterate over all tasks in the compile queue + while (next != NULL) { + CompileTask* current = next; + next = current->next(); + { + // Wake up thread that blocks on the compile task. + MutexLocker ct_lock(current->lock()); + current->lock()->notify(); } - _first = NULL; + // Put the task back on the freelist. + CompileTask::free(current); } + _first = NULL; + + // Wake up all threads that block on the queue. + lock()->notify_all(); } // ------------------------------------------------------------------ @@ -767,18 +819,24 @@ } } -// ------------------------------------------------------------------ -// CompileQueue::print +#ifndef PRODUCT +/** + * Print entire compilation queue. + */ void CompileQueue::print() { - tty->print_cr("Contents of %s", name()); - tty->print_cr("----------------------"); - CompileTask* task = _first; - while (task != NULL) { - task->print_line(); - task = task->next(); + if (CIPrintCompileQueue) { + ttyLocker ttyl; + tty->print_cr("Contents of %s", name()); + tty->print_cr("----------------------"); + CompileTask* task = _first; + while (task != NULL) { + task->print_line(); + task = task->next(); + } + tty->print_cr("----------------------"); } - tty->print_cr("----------------------"); } +#endif // PRODUCT CompilerCounters::CompilerCounters(const char* thread_name, int instance, TRAPS) { @@ -851,9 +909,6 @@ _compilers[1] = new SharkCompiler(); #endif // SHARK - // Initialize the CompileTask free list - _task_free_list = NULL; - // Start the CompilerThreads init_compiler_threads(c1_count, c2_count); // totalTime performance counter is always created as it is required @@ -1046,11 +1101,11 @@ #endif // !ZERO && !SHARK // Initialize the compilation queue if (c2_compiler_count > 0) { - _c2_method_queue = new CompileQueue("C2MethodQueue", MethodCompileQueue_lock); + _c2_compile_queue = new CompileQueue("C2 CompileQueue", MethodCompileQueue_lock); _compilers[1]->set_num_compiler_threads(c2_compiler_count); } if (c1_compiler_count > 0) { - _c1_method_queue = new CompileQueue("C1MethodQueue", MethodCompileQueue_lock); + _c1_compile_queue = new CompileQueue("C1 CompileQueue", MethodCompileQueue_lock); _compilers[0]->set_num_compiler_threads(c1_compiler_count); } @@ -1065,7 +1120,7 @@ sprintf(name_buffer, "C2 CompilerThread%d", i); CompilerCounters* counters = new CompilerCounters("compilerThread", i, CHECK); // Shark and C2 - CompilerThread* new_thread = make_compiler_thread(name_buffer, _c2_method_queue, counters, _compilers[1], CHECK); + CompilerThread* new_thread = make_compiler_thread(name_buffer, _c2_compile_queue, counters, _compilers[1], CHECK); _compiler_threads->append(new_thread); } @@ -1074,7 +1129,7 @@ sprintf(name_buffer, "C1 CompilerThread%d", i); CompilerCounters* counters = new CompilerCounters("compilerThread", i, CHECK); // C1 - CompilerThread* new_thread = make_compiler_thread(name_buffer, _c1_method_queue, counters, _compilers[0], CHECK); + CompilerThread* new_thread = make_compiler_thread(name_buffer, _c1_compile_queue, counters, _compilers[0], CHECK); _compiler_threads->append(new_thread); } @@ -1084,14 +1139,19 @@ } -// Set the methods on the stack as on_stack so that redefine classes doesn't -// reclaim them +/** + * Set the methods on the stack as on_stack so that redefine classes doesn't + * reclaim them. This method is executed at a safepoint. + */ void CompileBroker::mark_on_stack() { - if (_c2_method_queue != NULL) { - _c2_method_queue->mark_on_stack(); + assert(SafepointSynchronize::is_at_safepoint(), "sanity check"); + // Since we are at a safepoint, we do not need a lock to access + // the compile queues. + if (_c2_compile_queue != NULL) { + _c2_compile_queue->mark_on_stack(); } - if (_c1_method_queue != NULL) { - _c1_method_queue->mark_on_stack(); + if (_c1_compile_queue != NULL) { + _c1_compile_queue->mark_on_stack(); } } @@ -1107,7 +1167,7 @@ const char* comment, Thread* thread) { // do nothing if compiler thread(s) is not available - if (!_initialized ) { + if (!_initialized) { return; } @@ -1154,7 +1214,7 @@ // If this method is already in the compile queue, then // we do not block the current thread. - if (compilation_is_in_queue(method, osr_bci)) { + if (compilation_is_in_queue(method)) { // We may want to decay our counter a bit here to prevent // multiple denied requests for compilation. This is an // open compilation policy issue. Note: The other possibility, @@ -1193,7 +1253,7 @@ // Make sure the method has not slipped into the queues since // last we checked; note that those checks were "fast bail-outs". // Here we need to be more careful, see 14012000 below. - if (compilation_is_in_queue(method, osr_bci)) { + if (compilation_is_in_queue(method)) { return; } @@ -1214,7 +1274,7 @@ } // Should this thread wait for completion of the compile? - blocking = is_compile_blocking(method, osr_bci); + blocking = is_compile_blocking(); // We will enter the compilation in the queue. // 14012000: Note that this sets the queued_for_compile bits in @@ -1406,19 +1466,17 @@ } -// ------------------------------------------------------------------ -// CompileBroker::compilation_is_in_queue -// -// See if this compilation is already requested. -// -// Implementation note: there is only a single "is in queue" bit -// for each method. This means that the check below is overly -// conservative in the sense that an osr compilation in the queue -// will block a normal compilation from entering the queue (and vice -// versa). This can be remedied by a full queue search to disambiguate -// cases. If it is deemed profitible, this may be done. -bool CompileBroker::compilation_is_in_queue(methodHandle method, - int osr_bci) { +/** + * See if this compilation is already requested. + * + * Implementation note: there is only a single "is in queue" bit + * for each method. This means that the check below is overly + * conservative in the sense that an osr compilation in the queue + * will block a normal compilation from entering the queue (and vice + * versa). This can be remedied by a full queue search to disambiguate + * cases. If it is deemed profitable, this may be done. + */ +bool CompileBroker::compilation_is_in_queue(methodHandle method) { return method->queued_for_compilation(); } @@ -1498,13 +1556,11 @@ #endif } - -// ------------------------------------------------------------------ -// CompileBroker::is_compile_blocking -// -// Should the current thread be blocked until this compilation request -// has been fulfilled? -bool CompileBroker::is_compile_blocking(methodHandle method, int osr_bci) { +/** + * Should the current thread block until this compilation request + * has been fulfilled? + */ +bool CompileBroker::is_compile_blocking() { assert(!InstanceRefKlass::owns_pending_list_lock(JavaThread::current()), "possible deadlock"); return !BackgroundCompilation; } @@ -1532,7 +1588,7 @@ int hot_count, const char* comment, bool blocking) { - CompileTask* new_task = allocate_task(); + CompileTask* new_task = CompileTask::allocate(); new_task->initialize(compile_id, method, osr_bci, comp_level, hot_method, hot_count, comment, blocking); @@ -1541,75 +1597,52 @@ } -// ------------------------------------------------------------------ -// CompileBroker::allocate_task -// -// Allocate a CompileTask, from the free list if possible. -CompileTask* CompileBroker::allocate_task() { - MutexLocker locker(CompileTaskAlloc_lock); - CompileTask* task = NULL; - if (_task_free_list != NULL) { - task = _task_free_list; - _task_free_list = task->next(); - task->set_next(NULL); - } else { - task = new CompileTask(); - task->set_next(NULL); - } - return task; -} - - -// ------------------------------------------------------------------ -// CompileBroker::free_task -// -// Add a task to the free list. -void CompileBroker::free_task(CompileTask* task) { - MutexLocker locker(CompileTaskAlloc_lock); - task->free(); - task->set_next(_task_free_list); - _task_free_list = task; -} - - -// ------------------------------------------------------------------ -// CompileBroker::wait_for_completion -// -// Wait for the given method CompileTask to complete. +/** + * Wait for the compilation task to complete. + */ void CompileBroker::wait_for_completion(CompileTask* task) { if (CIPrintCompileQueue) { + ttyLocker ttyl; tty->print_cr("BLOCKING FOR COMPILE"); } assert(task->is_blocking(), "can only wait on blocking task"); - JavaThread *thread = JavaThread::current(); + JavaThread* thread = JavaThread::current(); thread->set_blocked_on_compilation(true); methodHandle method(thread, task->method()); { MutexLocker waiter(task->lock(), thread); - while (!task->is_complete()) + while (!task->is_complete() && !is_compilation_disabled_forever()) { task->lock()->wait(); + } } + + thread->set_blocked_on_compilation(false); + if (is_compilation_disabled_forever()) { + CompileTask::free(task); + return; + } + // It is harmless to check this status without the lock, because // completion is a stable property (until the task object is recycled). assert(task->is_complete(), "Compilation should have completed"); assert(task->code_handle() == NULL, "must be reset"); - thread->set_blocked_on_compilation(false); - // By convention, the waiter is responsible for recycling a // blocking CompileTask. Since there is only one waiter ever // waiting on a CompileTask, we know that no one else will // be using this CompileTask; we can free it. - free_task(task); + CompileTask::free(task); } -// Initialize compiler thread(s) + compiler object(s). The postcondition -// of this function is that the compiler runtimes are initialized and that -//compiler threads can start compiling. +/** + * Initialize compiler thread(s) + compiler object(s). The postcondition + * of this function is that the compiler runtimes are initialized and that + * compiler threads can start compiling. + */ bool CompileBroker::init_compiler_runtime() { CompilerThread* thread = CompilerThread::current(); AbstractCompiler* comp = thread->compiler(); @@ -1646,7 +1679,6 @@ disable_compilation_forever(); // If compiler initialization failed, no compiler thread that is specific to a // particular compiler runtime will ever start to compile methods. - shutdown_compiler_runtime(comp, thread); return false; } @@ -1660,9 +1692,11 @@ return true; } -// If C1 and/or C2 initialization failed, we shut down all compilation. -// We do this to keep things simple. This can be changed if it ever turns out to be -// a problem. +/** + * If C1 and/or C2 initialization failed, we shut down all compilation. + * We do this to keep things simple. This can be changed if it ever turns + * out to be a problem. + */ void CompileBroker::shutdown_compiler_runtime(AbstractCompiler* comp, CompilerThread* thread) { // Free buffer blob, if allocated if (thread->get_buffer_blob() != NULL) { @@ -1674,28 +1708,25 @@ // There are two reasons for shutting down the compiler // 1) compiler runtime initialization failed // 2) The code cache is full and the following flag is set: -XX:-UseCodeCacheFlushing - warning("Shutting down compiler %s (no space to run compilers)", comp->name()); + warning("%s initialization failed. Shutting down all compilers", comp->name()); // Only one thread per compiler runtime object enters here // Set state to shut down comp->set_shut_down(); - MutexLocker mu(MethodCompileQueue_lock, thread); - CompileQueue* queue; - if (_c1_method_queue != NULL) { - _c1_method_queue->delete_all(); - queue = _c1_method_queue; - _c1_method_queue = NULL; - delete _c1_method_queue; + // Delete all queued compilation tasks to make compiler threads exit faster. + if (_c1_compile_queue != NULL) { + _c1_compile_queue->free_all(); } - if (_c2_method_queue != NULL) { - _c2_method_queue->delete_all(); - queue = _c2_method_queue; - _c2_method_queue = NULL; - delete _c2_method_queue; + if (_c2_compile_queue != NULL) { + _c2_compile_queue->free_all(); } + // Set flags so that we continue execution with using interpreter only. + UseCompiler = false; + UseInterpreter = true; + // We could delete compiler runtimes also. However, there are references to // the compiler runtime(s) (e.g., nmethod::is_compiled_by_c1()) which then // fail. This can be done later if necessary. @@ -1781,22 +1812,6 @@ if (method()->number_of_breakpoints() == 0) { // Compile the method. if ((UseCompiler || AlwaysCompileLoopMethods) && CompileBroker::should_compile_new_jobs()) { -#ifdef COMPILER1 - // Allow repeating compilations for the purpose of benchmarking - // compile speed. This is not useful for customers. - if (CompilationRepeat != 0) { - int compile_count = CompilationRepeat; - while (compile_count > 0) { - invoke_compiler_on_method(task); - nmethod* nm = method->code(); - if (nm != NULL) { - nm->make_zombie(); - method->clear_code(); - } - compile_count--; - } - } -#endif /* COMPILER1 */ invoke_compiler_on_method(task); } else { // After compilation is disabled, remove remaining methods from queue @@ -1830,7 +1845,7 @@ os::file_separator(), thread_id, os::current_process_id()); } - fp = fopen(file_name, "at"); + fp = fopen(file_name, "wt"); if (fp != NULL) { if (LogCompilation && Verbose) { tty->print_cr("Opening compilation log %s", file_name);
--- a/src/share/vm/compiler/compileBroker.hpp Thu Jan 08 12:47:32 2015 +0000 +++ b/src/share/vm/compiler/compileBroker.hpp Tue Feb 03 16:48:05 2015 +0000 @@ -40,6 +40,11 @@ friend class VMStructs; private: + static CompileTask* _task_free_list; +#ifdef ASSERT + static int _num_allocated_tasks; +#endif + Monitor* _lock; uint _compile_id; Method* _method; @@ -52,7 +57,7 @@ int _num_inlined_bytecodes; nmethodLocker* _code_handle; // holder of eventual result CompileTask* _next, *_prev; - + bool _is_free; // Fields used for logging why the compilation was initiated: jlong _time_queued; // in units of os::elapsed_counter() Method* _hot_method; // which method actually triggered this task @@ -70,7 +75,8 @@ methodHandle hot_method, int hot_count, const char* comment, bool is_blocking); - void free(); + static CompileTask* allocate(); + static void free(CompileTask* task); int compile_id() const { return _compile_id; } Method* method() const { return _method; } @@ -99,6 +105,8 @@ void set_next(CompileTask* next) { _next = next; } CompileTask* prev() const { return _prev; } void set_prev(CompileTask* prev) { _prev = prev; } + bool is_free() const { return _is_free; } + void set_is_free(bool val) { _is_free = val; } private: static void print_compilation_impl(outputStream* st, Method* method, int compile_id, int comp_level, @@ -225,8 +233,8 @@ // Redefine Classes support void mark_on_stack(); - void delete_all(); - void print(); + void free_all(); + NOT_PRODUCT (void print();) ~CompileQueue() { assert (is_empty(), " Compile Queue must be empty"); @@ -279,9 +287,8 @@ static int _last_compile_level; static char _last_method_compiled[name_buffer_length]; - static CompileQueue* _c2_method_queue; - static CompileQueue* _c1_method_queue; - static CompileTask* _task_free_list; + static CompileQueue* _c2_compile_queue; + static CompileQueue* _c1_compile_queue; static GrowableArray<CompilerThread*>* _compiler_threads; @@ -334,7 +341,7 @@ static void init_compiler_threads(int c1_compiler_count, int c2_compiler_count); static bool compilation_is_complete (methodHandle method, int osr_bci, int comp_level); static bool compilation_is_prohibited(methodHandle method, int osr_bci, int comp_level); - static bool is_compile_blocking (methodHandle method, int osr_bci); + static bool is_compile_blocking (); static void preload_classes (methodHandle method, TRAPS); static CompileTask* create_compile_task(CompileQueue* queue, @@ -346,8 +353,6 @@ int hot_count, const char* comment, bool blocking); - static CompileTask* allocate_task(); - static void free_task(CompileTask* task); static void wait_for_completion(CompileTask* task); static void invoke_compiler_on_method(CompileTask* task); @@ -365,8 +370,8 @@ const char* comment, Thread* thread); static CompileQueue* compile_queue(int comp_level) { - if (is_c2_compile(comp_level)) return _c2_method_queue; - if (is_c1_compile(comp_level)) return _c1_method_queue; + if (is_c2_compile(comp_level)) return _c2_compile_queue; + if (is_c1_compile(comp_level)) return _c1_compile_queue; return NULL; } static bool init_compiler_runtime(); @@ -384,7 +389,7 @@ return NULL; } - static bool compilation_is_in_queue(methodHandle method, int osr_bci); + static bool compilation_is_in_queue(methodHandle method); static int queue_size(int comp_level) { CompileQueue *q = compile_queue(comp_level); return q != NULL ? q->size() : 0;
--- a/src/share/vm/compiler/compileLog.cpp Thu Jan 08 12:47:32 2015 +0000 +++ b/src/share/vm/compiler/compileLog.cpp Tue Feb 03 16:48:05 2015 +0000 @@ -55,8 +55,10 @@ } CompileLog::~CompileLog() { - delete _out; + delete _out; // Close fd in fileStream::~fileStream() _out = NULL; + // Remove partial file after merging in CompileLog::finish_log_on_error + unlink(_file); FREE_C_HEAP_ARRAY(char, _identities, mtCompiler); FREE_C_HEAP_ARRAY(char, _file, mtCompiler); } @@ -268,10 +270,9 @@ } file->print_raw_cr("</compilation_log>"); close(partial_fd); - unlink(partial_file); } CompileLog* next_log = log->_next; - delete log; + delete log; // Removes partial file log = next_log; } _first = NULL;
--- a/src/share/vm/gc_implementation/concurrentMarkSweep/compactibleFreeListSpace.cpp Thu Jan 08 12:47:32 2015 +0000 +++ b/src/share/vm/gc_implementation/concurrentMarkSweep/compactibleFreeListSpace.cpp Tue Feb 03 16:48:05 2015 +0000 @@ -2641,7 +2641,7 @@ // Get the #blocks we want to claim size_t n_blks = (size_t)_blocks_to_claim[word_sz].average(); assert(n_blks > 0, "Error"); - assert(ResizePLAB || n_blks == OldPLABSize, "Error"); + assert(ResizeOldPLAB || n_blks == OldPLABSize, "Error"); // In some cases, when the application has a phase change, // there may be a sudden and sharp shift in the object survival // profile, and updating the counts at the end of a scavenge
--- a/src/share/vm/gc_implementation/concurrentMarkSweep/concurrentMarkSweepGeneration.cpp Thu Jan 08 12:47:32 2015 +0000 +++ b/src/share/vm/gc_implementation/concurrentMarkSweep/concurrentMarkSweepGeneration.cpp Tue Feb 03 16:48:05 2015 +0000 @@ -738,7 +738,7 @@ // Support for parallelizing survivor space rescan if ((CMSParallelRemarkEnabled && CMSParallelSurvivorRemarkEnabled) || CMSParallelInitialMarkEnabled) { const size_t max_plab_samples = - ((DefNewGeneration*)_young_gen)->max_survivor_size()/MinTLABSize; + ((DefNewGeneration*)_young_gen)->max_survivor_size() / plab_sample_minimum_size(); _survivor_plab_array = NEW_C_HEAP_ARRAY(ChunkArray, ParallelGCThreads, mtGC); _survivor_chunk_array = NEW_C_HEAP_ARRAY(HeapWord*, 2*max_plab_samples, mtGC); @@ -796,6 +796,12 @@ _inter_sweep_timer.start(); // start of time } +size_t CMSCollector::plab_sample_minimum_size() { + // The default value of MinTLABSize is 2k, but there is + // no way to get the default value if the flag has been overridden. + return MAX2(ThreadLocalAllocBuffer::min_size() * HeapWordSize, 2 * K); +} + const char* ConcurrentMarkSweepGeneration::name() const { return "concurrent mark-sweep generation"; }
--- a/src/share/vm/gc_implementation/concurrentMarkSweep/concurrentMarkSweepGeneration.hpp Thu Jan 08 12:47:32 2015 +0000 +++ b/src/share/vm/gc_implementation/concurrentMarkSweep/concurrentMarkSweepGeneration.hpp Tue Feb 03 16:48:05 2015 +0000 @@ -764,6 +764,10 @@ size_t* _cursor; ChunkArray* _survivor_plab_array; + // A bounded minimum size of PLABs, should not return too small values since + // this will affect the size of the data structures used for parallel young gen rescan + size_t plab_sample_minimum_size(); + // Support for marking stack overflow handling bool take_from_overflow_list(size_t num, CMSMarkStack* to_stack); bool par_take_from_overflow_list(size_t num,
--- a/src/share/vm/gc_implementation/concurrentMarkSweep/vmCMSOperations.cpp Thu Jan 08 12:47:32 2015 +0000 +++ b/src/share/vm/gc_implementation/concurrentMarkSweep/vmCMSOperations.cpp Tue Feb 03 16:48:05 2015 +0000 @@ -50,8 +50,12 @@ void VM_CMS_Operation::acquire_pending_list_lock() { // The caller may block while communicating // with the SLT thread in order to acquire/release the PLL. - ConcurrentMarkSweepThread::slt()-> - manipulatePLL(SurrogateLockerThread::acquirePLL); + SurrogateLockerThread* slt = ConcurrentMarkSweepThread::slt(); + if (slt != NULL) { + slt->manipulatePLL(SurrogateLockerThread::acquirePLL); + } else { + SurrogateLockerThread::report_missing_slt(); + } } void VM_CMS_Operation::release_and_notify_pending_list_lock() {
--- a/src/share/vm/gc_implementation/g1/concurrentMark.cpp Thu Jan 08 12:47:32 2015 +0000 +++ b/src/share/vm/gc_implementation/g1/concurrentMark.cpp Tue Feb 03 16:48:05 2015 +0000 @@ -23,6 +23,7 @@ */ #include "precompiled.hpp" +#include "classfile/metadataOnStackMark.hpp" #include "classfile/symbolTable.hpp" #include "code/codeCache.hpp" #include "gc_implementation/g1/concurrentMark.inline.hpp" @@ -2174,6 +2175,7 @@ // We reclaimed old regions so we should calculate the sizes to make // sure we update the old gen/space data. g1h->g1mm()->update_sizes(); + g1h->allocation_context_stats().update_after_mark(); g1h->trace_heap_after_concurrent_cycle(); } @@ -2602,17 +2604,27 @@ G1RemarkGCTraceTime trace("Unloading", G1Log::finer()); if (ClassUnloadingWithConcurrentMark) { + // Cleaning of klasses depends on correct information from MetadataMarkOnStack. The CodeCache::mark_on_stack + // part is too slow to be done serially, so it is handled during the weakRefsWorkParallelPart phase. + // Defer the cleaning until we have complete on_stack data. + MetadataOnStackMark md_on_stack(false /* Don't visit the code cache at this point */); + bool purged_classes; { G1RemarkGCTraceTime trace("System Dictionary Unloading", G1Log::finest()); - purged_classes = SystemDictionary::do_unloading(&g1_is_alive); + purged_classes = SystemDictionary::do_unloading(&g1_is_alive, false /* Defer klass cleaning */); } { G1RemarkGCTraceTime trace("Parallel Unloading", G1Log::finest()); weakRefsWorkParallelPart(&g1_is_alive, purged_classes); } + + { + G1RemarkGCTraceTime trace("Deallocate Metadata", G1Log::finest()); + ClassLoaderDataGraph::free_deallocate_lists(); + } } if (G1StringDedup::is_enabled()) { @@ -3335,7 +3347,6 @@ } else { g1_par_agg_task.work(0); } - _g1h->allocation_context_stats().update_at_remark(); } // Clear the per-worker arrays used to store the per-region counting data
--- a/src/share/vm/gc_implementation/g1/dirtyCardQueue.hpp Thu Jan 08 12:47:32 2015 +0000 +++ b/src/share/vm/gc_implementation/g1/dirtyCardQueue.hpp Tue Feb 03 16:48:05 2015 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2014, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -47,6 +47,13 @@ // active field set to true. PtrQueue(qset_, perm, true /* active */) { } + // Flush before destroying; queue may be used to capture pending work while + // doing something else, with auto-flush on completion. + ~DirtyCardQueue() { if (!is_permanent()) flush(); } + + // Process queue entries and release resources. + void flush() { flush_impl(); } + // Apply the closure to all elements, and reset the index to make the // buffer empty. If a closure application returns "false", return // "false" immediately, halting the iteration. If "consume" is true,
--- a/src/share/vm/gc_implementation/g1/g1AllocationContext.hpp Thu Jan 08 12:47:32 2015 +0000 +++ b/src/share/vm/gc_implementation/g1/g1AllocationContext.hpp Tue Feb 03 16:48:05 2015 +0000 @@ -45,7 +45,7 @@ public: inline void clear() { } inline void update(bool full_gc) { } - inline void update_at_remark() { } + inline void update_after_mark() { } inline bool available() { return false; } };
--- a/src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp Thu Jan 08 12:47:32 2015 +0000 +++ b/src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp Tue Feb 03 16:48:05 2015 +0000 @@ -27,6 +27,7 @@ #endif #include "precompiled.hpp" +#include "classfile/metadataOnStackMark.hpp" #include "code/codeCache.hpp" #include "code/icBuffer.hpp" #include "gc_implementation/g1/bufferingOopClosure.hpp" @@ -2478,6 +2479,7 @@ unsigned int gc_count_before; unsigned int old_marking_count_before; + unsigned int full_gc_count_before; bool retry_gc; do { @@ -2488,6 +2490,7 @@ // Read the GC count while holding the Heap_lock gc_count_before = total_collections(); + full_gc_count_before = total_full_collections(); old_marking_count_before = _old_marking_cycles_started; } @@ -2532,7 +2535,7 @@ VMThread::execute(&op); } else { // Schedule a Full GC. - VM_G1CollectFull op(gc_count_before, old_marking_count_before, cause); + VM_G1CollectFull op(gc_count_before, full_gc_count_before, cause); VMThread::execute(&op); } } @@ -5131,6 +5134,10 @@ clean_nmethod(claimed_nmethods[i]); } } + + // The nmethod cleaning helps out and does the CodeCache part of MetadataOnStackMark. + // Need to retire the buffers now that this thread has stopped cleaning nmethods. + MetadataOnStackMark::retire_buffer_for_thread(Thread::current()); } void work_second_pass(uint worker_id) { @@ -5183,6 +5190,9 @@ // G1 specific cleanup work that has // been moved here to be done in parallel. ik->clean_dependent_nmethods(); + if (JvmtiExport::has_redefined_a_class()) { + InstanceKlass::purge_previous_versions(ik); + } } void work() { @@ -5217,8 +5227,20 @@ _klass_cleaning_task(is_alive) { } + void pre_work_verification() { + // The VM Thread will have registered Metadata during the single-threaded phase of MetadataStackOnMark. + assert(Thread::current()->is_VM_thread() + || !MetadataOnStackMark::has_buffer_for_thread(Thread::current()), "Should be empty"); + } + + void post_work_verification() { + assert(!MetadataOnStackMark::has_buffer_for_thread(Thread::current()), "Should be empty"); + } + // The parallel work done by all worker threads. void work(uint worker_id) { + pre_work_verification(); + // Do first pass of code cache cleaning. _code_cache_task.work_first_pass(worker_id); @@ -5237,6 +5259,8 @@ // Clean all klasses that were not unloaded. _klass_cleaning_task.work(); + + post_work_verification(); } };
--- a/src/share/vm/gc_implementation/g1/g1CollectedHeap.hpp Thu Jan 08 12:47:32 2015 +0000 +++ b/src/share/vm/gc_implementation/g1/g1CollectedHeap.hpp Tue Feb 03 16:48:05 2015 +0000 @@ -1249,7 +1249,7 @@ // The same as above but assume that the caller holds the Heap_lock. void collect_locked(GCCause::Cause cause); - virtual void copy_allocation_context_stats(const jint* contexts, + virtual bool copy_allocation_context_stats(const jint* contexts, jlong* totals, jbyte* accuracy, jint len);
--- a/src/share/vm/gc_implementation/g1/g1CollectedHeap_ext.cpp Thu Jan 08 12:47:32 2015 +0000 +++ b/src/share/vm/gc_implementation/g1/g1CollectedHeap_ext.cpp Tue Feb 03 16:48:05 2015 +0000 @@ -25,8 +25,9 @@ #include "precompiled.hpp" #include "gc_implementation/g1/g1CollectedHeap.hpp" -void G1CollectedHeap::copy_allocation_context_stats(const jint* contexts, +bool G1CollectedHeap::copy_allocation_context_stats(const jint* contexts, jlong* totals, jbyte* accuracy, jint len) { + return false; }
--- a/src/share/vm/gc_implementation/g1/g1CollectorPolicy.cpp Thu Jan 08 12:47:32 2015 +0000 +++ b/src/share/vm/gc_implementation/g1/g1CollectorPolicy.cpp Tue Feb 03 16:48:05 2015 +0000 @@ -1425,6 +1425,18 @@ #endif // PRODUCT } +bool G1CollectorPolicy::is_young_list_full() { + uint young_list_length = _g1->young_list()->length(); + uint young_list_target_length = _young_list_target_length; + return young_list_length >= young_list_target_length; +} + +bool G1CollectorPolicy::can_expand_young_list() { + uint young_list_length = _g1->young_list()->length(); + uint young_list_max_length = _young_list_max_length; + return young_list_length < young_list_max_length; +} + uint G1CollectorPolicy::max_regions(int purpose) { switch (purpose) { case GCAllocForSurvived:
--- a/src/share/vm/gc_implementation/g1/g1CollectorPolicy.hpp Thu Jan 08 12:47:32 2015 +0000 +++ b/src/share/vm/gc_implementation/g1/g1CollectorPolicy.hpp Tue Feb 03 16:48:05 2015 +0000 @@ -26,6 +26,7 @@ #define SHARE_VM_GC_IMPLEMENTATION_G1_G1COLLECTORPOLICY_HPP #include "gc_implementation/g1/collectionSetChooser.hpp" +#include "gc_implementation/g1/g1Allocator.hpp" #include "gc_implementation/g1/g1MMUTracker.hpp" #include "memory/collectorPolicy.hpp" @@ -803,7 +804,7 @@ // If an expansion would be appropriate, because recent GC overhead had // exceeded the desired limit, return an amount to expand by. - size_t expansion_amount(); + virtual size_t expansion_amount(); // Print tracing information. void print_tracing_info() const; @@ -822,17 +823,9 @@ size_t young_list_target_length() const { return _young_list_target_length; } - bool is_young_list_full() { - uint young_list_length = _g1->young_list()->length(); - uint young_list_target_length = _young_list_target_length; - return young_list_length >= young_list_target_length; - } + bool is_young_list_full(); - bool can_expand_young_list() { - uint young_list_length = _g1->young_list()->length(); - uint young_list_max_length = _young_list_max_length; - return young_list_length < young_list_max_length; - } + bool can_expand_young_list(); uint young_list_max_length() { return _young_list_max_length;
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/share/vm/gc_implementation/g1/g1CollectorPolicy_ext.hpp Tue Feb 03 16:48:05 2015 +0000 @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +#ifndef SHARE_VM_GC_IMPLEMENTATION_G1_G1COLLECTORPOLICY_EXT_HPP +#define SHARE_VM_GC_IMPLEMENTATION_G1_G1COLLECTORPOLICY_EXT_HPP + +#include "gc_implementation/g1/g1CollectorPolicy.hpp" + +class G1CollectorPolicyExt : public G1CollectorPolicy { }; + +#endif // SHARE_VM_GC_IMPLEMENTATION_G1_G1COLLECTORPOLICY_EXT_HPP
--- a/src/share/vm/gc_implementation/g1/g1PageBasedVirtualSpace.cpp Thu Jan 08 12:47:32 2015 +0000 +++ b/src/share/vm/gc_implementation/g1/g1PageBasedVirtualSpace.cpp Tue Feb 03 16:48:05 2015 +0000 @@ -45,7 +45,8 @@ #include "utilities/bitMap.inline.hpp" G1PageBasedVirtualSpace::G1PageBasedVirtualSpace() : _low_boundary(NULL), - _high_boundary(NULL), _committed(), _page_size(0), _special(false), _executable(false) { + _high_boundary(NULL), _committed(), _page_size(0), _special(false), + _dirty(), _executable(false) { } bool G1PageBasedVirtualSpace::initialize_with_granularity(ReservedSpace rs, size_t page_size) { @@ -66,6 +67,9 @@ assert(_committed.size() == 0, "virtual space initialized more than once"); uintx size_in_bits = rs.size() / page_size; _committed.resize(size_in_bits, /* in_resource_area */ false); + if (_special) { + _dirty.resize(size_in_bits, /* in_resource_area */ false); + } return true; } @@ -84,6 +88,7 @@ _executable = false; _page_size = 0; _committed.resize(0, false); + _dirty.resize(0, false); } size_t G1PageBasedVirtualSpace::committed_size() const { @@ -120,31 +125,40 @@ return num * _page_size; } -MemRegion G1PageBasedVirtualSpace::commit(uintptr_t start, size_t size_in_pages) { +bool G1PageBasedVirtualSpace::commit(uintptr_t start, size_t size_in_pages) { // We need to make sure to commit all pages covered by the given area. guarantee(is_area_uncommitted(start, size_in_pages), "Specified area is not uncommitted"); - if (!_special) { + bool zero_filled = true; + uintptr_t end = start + size_in_pages; + + if (_special) { + // Check for dirty pages and update zero_filled if any found. + if (_dirty.get_next_one_offset(start,end) < end) { + zero_filled = false; + _dirty.clear_range(start, end); + } + } else { os::commit_memory_or_exit(page_start(start), byte_size_for_pages(size_in_pages), _executable, err_msg("Failed to commit pages from "SIZE_FORMAT" of length "SIZE_FORMAT, start, size_in_pages)); } - _committed.set_range(start, start + size_in_pages); + _committed.set_range(start, end); - MemRegion result((HeapWord*)page_start(start), byte_size_for_pages(size_in_pages) / HeapWordSize); - return result; + return zero_filled; } -MemRegion G1PageBasedVirtualSpace::uncommit(uintptr_t start, size_t size_in_pages) { +void G1PageBasedVirtualSpace::uncommit(uintptr_t start, size_t size_in_pages) { guarantee(is_area_committed(start, size_in_pages), "checking"); - if (!_special) { + if (_special) { + // Mark that memory is dirty. If committed again the memory might + // need to be cleared explicitly. + _dirty.set_range(start, start + size_in_pages); + } else { os::uncommit_memory(page_start(start), byte_size_for_pages(size_in_pages)); } _committed.clear_range(start, start + size_in_pages); - - MemRegion result((HeapWord*)page_start(start), byte_size_for_pages(size_in_pages) / HeapWordSize); - return result; } bool G1PageBasedVirtualSpace::contains(const void* p) const { @@ -154,7 +168,7 @@ #ifndef PRODUCT void G1PageBasedVirtualSpace::print_on(outputStream* out) { out->print ("Virtual space:"); - if (special()) out->print(" (pinned in memory)"); + if (_special) out->print(" (pinned in memory)"); out->cr(); out->print_cr(" - committed: " SIZE_FORMAT, committed_size()); out->print_cr(" - reserved: " SIZE_FORMAT, reserved_size());
--- a/src/share/vm/gc_implementation/g1/g1PageBasedVirtualSpace.hpp Thu Jan 08 12:47:32 2015 +0000 +++ b/src/share/vm/gc_implementation/g1/g1PageBasedVirtualSpace.hpp Tue Feb 03 16:48:05 2015 +0000 @@ -49,6 +49,12 @@ // Bitmap used for verification of commit/uncommit operations. BitMap _committed; + // Bitmap used to keep track of which pages are dirty or not for _special + // spaces. This is needed because for those spaces the underlying memory + // will only be zero filled the first time it is committed. Calls to commit + // will use this bitmap and return whether or not the memory is zero filled. + BitMap _dirty; + // Indicates that the entire space has been committed and pinned in memory, // os::commit_memory() or os::uncommit_memory() have no function. bool _special; @@ -71,12 +77,11 @@ public: // Commit the given area of pages starting at start being size_in_pages large. - MemRegion commit(uintptr_t start, size_t size_in_pages); + // Returns true if the given area is zero filled upon completion. + bool commit(uintptr_t start, size_t size_in_pages); // Uncommit the given area of pages starting at start being size_in_pages large. - MemRegion uncommit(uintptr_t start, size_t size_in_pages); - - bool special() const { return _special; } + void uncommit(uintptr_t start, size_t size_in_pages); // Initialization G1PageBasedVirtualSpace();
--- a/src/share/vm/gc_implementation/g1/g1RegionToSpaceMapper.cpp Thu Jan 08 12:47:32 2015 +0000 +++ b/src/share/vm/gc_implementation/g1/g1RegionToSpaceMapper.cpp Tue Feb 03 16:48:05 2015 +0000 @@ -67,9 +67,9 @@ } virtual void commit_regions(uintptr_t start_idx, size_t num_regions) { - _storage.commit(start_idx * _pages_per_region, num_regions * _pages_per_region); + bool zero_filled = _storage.commit(start_idx * _pages_per_region, num_regions * _pages_per_region); _commit_map.set_range(start_idx, start_idx + num_regions); - fire_on_commit(start_idx, num_regions, true); + fire_on_commit(start_idx, num_regions, zero_filled); } virtual void uncommit_regions(uintptr_t start_idx, size_t num_regions) { @@ -117,8 +117,7 @@ uint old_refcount = _refcounts.get_by_index(idx); bool zero_filled = false; if (old_refcount == 0) { - _storage.commit(idx, 1); - zero_filled = true; + zero_filled = _storage.commit(idx, 1); } _refcounts.set_by_index(idx, old_refcount + 1); _commit_map.set_bit(i);
--- a/src/share/vm/gc_implementation/g1/heapRegion.cpp Thu Jan 08 12:47:32 2015 +0000 +++ b/src/share/vm/gc_implementation/g1/heapRegion.cpp Tue Feb 03 16:48:05 2015 +0000 @@ -1015,10 +1015,13 @@ HeapWord* G1OffsetTableContigSpace::saved_mark_word() const { G1CollectedHeap* g1h = G1CollectedHeap::heap(); assert( _gc_time_stamp <= g1h->get_gc_time_stamp(), "invariant" ); - if (_gc_time_stamp < g1h->get_gc_time_stamp()) - return top(); - else + HeapWord* local_top = top(); + OrderAccess::loadload(); + if (_gc_time_stamp < g1h->get_gc_time_stamp()) { + return local_top; + } else { return Space::saved_mark_word(); + } } void G1OffsetTableContigSpace::record_top_and_timestamp() {
--- a/src/share/vm/gc_implementation/g1/ptrQueue.cpp Thu Jan 08 12:47:32 2015 +0000 +++ b/src/share/vm/gc_implementation/g1/ptrQueue.cpp Tue Feb 03 16:48:05 2015 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2014, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -31,11 +31,15 @@ #include "runtime/thread.inline.hpp" PtrQueue::PtrQueue(PtrQueueSet* qset, bool perm, bool active) : - _qset(qset), _buf(NULL), _index(0), _active(active), + _qset(qset), _buf(NULL), _index(0), _sz(0), _active(active), _perm(perm), _lock(NULL) {} -void PtrQueue::flush() { +PtrQueue::~PtrQueue() { + assert(_perm || (_buf == NULL), "queue must be flushed before delete"); +} + +void PtrQueue::flush_impl() { if (!_perm && _buf != NULL) { if (_index == _sz) { // No work to do.
--- a/src/share/vm/gc_implementation/g1/ptrQueue.hpp Thu Jan 08 12:47:32 2015 +0000 +++ b/src/share/vm/gc_implementation/g1/ptrQueue.hpp Tue Feb 03 16:48:05 2015 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2014, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -65,15 +65,18 @@ Mutex* _lock; PtrQueueSet* qset() { return _qset; } + bool is_permanent() const { return _perm; } + + // Process queue entries and release resources, if not permanent. + void flush_impl(); public: // Initialize this queue to contain a null buffer, and be part of the // given PtrQueueSet. PtrQueue(PtrQueueSet* qset, bool perm = false, bool active = false); - // Release any contained resources. - virtual void flush(); - // Calls flush() when destroyed. - ~PtrQueue() { flush(); } + + // Requires queue flushed or permanent. + ~PtrQueue(); // Associate a lock with a ptr queue. void set_lock(Mutex* lock) { _lock = lock; }
--- a/src/share/vm/gc_implementation/g1/satbQueue.cpp Thu Jan 08 12:47:32 2015 +0000 +++ b/src/share/vm/gc_implementation/g1/satbQueue.cpp Tue Feb 03 16:48:05 2015 +0000 @@ -39,7 +39,7 @@ // first before we flush it, otherwise we might end up with an // enqueued buffer with refs into the CSet which breaks our invariants. filter(); - PtrQueue::flush(); + flush_impl(); } // This method removes entries from an SATB buffer that will not be
--- a/src/share/vm/gc_implementation/g1/satbQueue.hpp Thu Jan 08 12:47:32 2015 +0000 +++ b/src/share/vm/gc_implementation/g1/satbQueue.hpp Tue Feb 03 16:48:05 2015 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2014, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -60,9 +60,8 @@ // field to true. This is done in JavaThread::initialize_queues(). PtrQueue(qset, perm, false /* active */) { } - // Overrides PtrQueue::flush() so that it can filter the buffer - // before it is flushed. - virtual void flush(); + // Process queue entries and free resources. + void flush(); // Overrides PtrQueue::should_enqueue_buffer(). See the method's // definition for more information.
--- a/src/share/vm/gc_implementation/g1/vm_operations_g1.cpp Thu Jan 08 12:47:32 2015 +0000 +++ b/src/share/vm/gc_implementation/g1/vm_operations_g1.cpp Tue Feb 03 16:48:05 2015 +0000 @@ -213,8 +213,12 @@ assert(_needs_pll, "don't call this otherwise"); // The caller may block while communicating // with the SLT thread in order to acquire/release the PLL. - ConcurrentMarkThread::slt()-> - manipulatePLL(SurrogateLockerThread::acquirePLL); + SurrogateLockerThread* slt = ConcurrentMarkThread::slt(); + if (slt != NULL) { + slt->manipulatePLL(SurrogateLockerThread::acquirePLL); + } else { + SurrogateLockerThread::report_missing_slt(); + } } void VM_CGC_Operation::release_and_notify_pending_list_lock() {
--- a/src/share/vm/gc_implementation/g1/vm_operations_g1.hpp Thu Jan 08 12:47:32 2015 +0000 +++ b/src/share/vm/gc_implementation/g1/vm_operations_g1.hpp Tue Feb 03 16:48:05 2015 +0000 @@ -60,7 +60,7 @@ VM_G1CollectFull(unsigned int gc_count_before, unsigned int full_gc_count_before, GCCause::Cause cause) - : VM_GC_Operation(gc_count_before, cause, full_gc_count_before) { } + : VM_GC_Operation(gc_count_before, cause, full_gc_count_before, true) { } virtual VMOp_Type type() const { return VMOp_G1CollectFull; } virtual void doit(); virtual const char* name() const {
--- a/src/share/vm/gc_implementation/shared/concurrentGCThread.cpp Thu Jan 08 12:47:32 2015 +0000 +++ b/src/share/vm/gc_implementation/shared/concurrentGCThread.cpp Tue Feb 03 16:48:05 2015 +0000 @@ -137,6 +137,13 @@ return res; } +void SurrogateLockerThread::report_missing_slt() { + vm_exit_during_initialization( + "GC before GC support fully initialized: " + "SLT is needed but has not yet been created."); + ShouldNotReachHere(); +} + void SurrogateLockerThread::manipulatePLL(SLT_msg_type msg) { MutexLockerEx x(&_monitor, Mutex::_no_safepoint_check_flag); assert(_buffer == empty, "Should be empty");
--- a/src/share/vm/gc_implementation/shared/concurrentGCThread.hpp Thu Jan 08 12:47:32 2015 +0000 +++ b/src/share/vm/gc_implementation/shared/concurrentGCThread.hpp Tue Feb 03 16:48:05 2015 +0000 @@ -93,6 +93,9 @@ public: static SurrogateLockerThread* make(TRAPS); + // Terminate VM with error message that SLT needed but not yet created. + static void report_missing_slt(); + SurrogateLockerThread(); bool is_hidden_from_external_view() const { return true; }
--- a/src/share/vm/gc_implementation/shared/objectCountEventSender.cpp Thu Jan 08 12:47:32 2015 +0000 +++ b/src/share/vm/gc_implementation/shared/objectCountEventSender.cpp Tue Feb 03 16:48:05 2015 +0000 @@ -29,8 +29,8 @@ #include "memory/heapInspection.hpp" #include "trace/tracing.hpp" #include "utilities/globalDefinitions.hpp" +#include "utilities/macros.hpp" #include "utilities/ticks.hpp" - #if INCLUDE_SERVICES void ObjectCountEventSender::send(const KlassInfoEntry* entry, GCId gc_id, const Ticks& timestamp) {
--- a/src/share/vm/gc_implementation/shared/parGCAllocBuffer.hpp Thu Jan 08 12:47:32 2015 +0000 +++ b/src/share/vm/gc_implementation/shared/parGCAllocBuffer.hpp Tue Feb 03 16:48:05 2015 +0000 @@ -63,7 +63,8 @@ virtual ~ParGCAllocBuffer() {} static const size_t min_size() { - return ThreadLocalAllocBuffer::min_size(); + // Make sure that we return something that is larger than AlignmentReserve + return align_object_size(MAX2(MinTLABSize / HeapWordSize, (uintx)oopDesc::header_size())) + AlignmentReserve; } static const size_t max_size() {
--- a/src/share/vm/gc_interface/collectedHeap.hpp Thu Jan 08 12:47:32 2015 +0000 +++ b/src/share/vm/gc_interface/collectedHeap.hpp Tue Feb 03 16:48:05 2015 +0000 @@ -641,10 +641,13 @@ // For each context in contexts, set the corresponding entries in the totals // and accuracy arrays to the current values held by the statistics. Each // array should be of length len. - virtual void copy_allocation_context_stats(const jint* contexts, + // Returns true if there are more stats available. + virtual bool copy_allocation_context_stats(const jint* contexts, jlong* totals, jbyte* accuracy, - jint len) { } + jint len) { + return false; + } /////////////// Unit tests ///////////////
--- a/src/share/vm/interpreter/bytecodeInterpreter.cpp Thu Jan 08 12:47:32 2015 +0000 +++ b/src/share/vm/interpreter/bytecodeInterpreter.cpp Tue Feb 03 16:48:05 2015 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 2014, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -2813,11 +2813,11 @@ if (TraceExceptions) { ttyLocker ttyl; ResourceMark rm; - tty->print_cr("Exception <%s> (" INTPTR_FORMAT ")", except_oop->print_value_string(), (void*)except_oop()); + tty->print_cr("Exception <%s> (" INTPTR_FORMAT ")", except_oop->print_value_string(), p2i(except_oop())); tty->print_cr(" thrown in interpreter method <%s>", METHOD->print_value_string()); tty->print_cr(" at bci %d, continuing at %d for thread " INTPTR_FORMAT, - istate->bcp() - (intptr_t)METHOD->code_base(), - continuation_bci, THREAD); + (int)(istate->bcp() - METHOD->code_base()), + (int)continuation_bci, p2i(THREAD)); } // for AbortVMOnException flag NOT_PRODUCT(Exceptions::debug_check_abort(except_oop)); @@ -2829,11 +2829,11 @@ if (TraceExceptions) { ttyLocker ttyl; ResourceMark rm; - tty->print_cr("Exception <%s> (" INTPTR_FORMAT ")", except_oop->print_value_string(), (void*)except_oop()); + tty->print_cr("Exception <%s> (" INTPTR_FORMAT ")", except_oop->print_value_string(), p2i(except_oop())); tty->print_cr(" thrown in interpreter method <%s>", METHOD->print_value_string()); tty->print_cr(" at bci %d, unwinding for thread " INTPTR_FORMAT, - istate->bcp() - (intptr_t)METHOD->code_base(), - THREAD); + (int)(istate->bcp() - METHOD->code_base()), + p2i(THREAD)); } // for AbortVMOnException flag NOT_PRODUCT(Exceptions::debug_check_abort(except_oop)); @@ -3432,7 +3432,7 @@ tty->print_cr("osr._osr_buf: " INTPTR_FORMAT, (uintptr_t) this->_result._osr._osr_buf); tty->print_cr("osr._osr_entry: " INTPTR_FORMAT, (uintptr_t) this->_result._osr._osr_entry); tty->print_cr("prev_link: " INTPTR_FORMAT, (uintptr_t) this->_prev_link); - tty->print_cr("native_mirror: " INTPTR_FORMAT, (void*) this->_oop_temp); + tty->print_cr("native_mirror: " INTPTR_FORMAT, (uintptr_t) this->_oop_temp); tty->print_cr("stack_base: " INTPTR_FORMAT, (uintptr_t) this->_stack_base); tty->print_cr("stack_limit: " INTPTR_FORMAT, (uintptr_t) this->_stack_limit); tty->print_cr("monitor_base: " INTPTR_FORMAT, (uintptr_t) this->_monitor_base);
--- a/src/share/vm/interpreter/bytecodeInterpreterProfiling.hpp Thu Jan 08 12:47:32 2015 +0000 +++ b/src/share/vm/interpreter/bytecodeInterpreterProfiling.hpp Tue Feb 03 16:48:05 2015 +0000 @@ -1,6 +1,6 @@ /* - * Copyright (c) 2002, 2013, Oracle and/or its affiliates. All rights reserved. - * Copyright 2012, 2013 SAP AG. All rights reserved. + * Copyright (c) 2002, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright 2012, 2014 SAP AG. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -86,11 +86,11 @@ " \t-> " PTR_FORMAT "(%d)", \ (int) THREAD->osthread()->thread_id(), \ BCI(), \ - MDX(), \ + p2i(MDX()), \ (MDX() == NULL \ ? 0 \ : istate->method()->method_data()->dp_to_di((address)MDX())), \ - mdx, \ + p2i(mdx), \ istate->method()->method_data()->dp_to_di((address)mdx) \ ); \ }; \ @@ -107,7 +107,7 @@ MethodData *md = istate->method()->method_data(); \ tty->cr(); \ tty->print("method data at mdx " PTR_FORMAT "(0) for", \ - md->data_layout_at(md->bci_to_di(0))); \ + p2i(md->data_layout_at(md->bci_to_di(0)))); \ istate->method()->print_short_name(tty); \ tty->cr(); \ if (md != NULL) { \ @@ -115,7 +115,7 @@ address mdx = (address) MDX(); \ if (mdx != NULL) { \ tty->print_cr("current mdx " PTR_FORMAT "(%d)", \ - mdx, \ + p2i(mdx), \ istate->method()->method_data()->dp_to_di(mdx)); \ } \ } else { \
--- a/src/share/vm/interpreter/bytecodes.hpp Thu Jan 08 12:47:32 2015 +0000 +++ b/src/share/vm/interpreter/bytecodes.hpp Tue Feb 03 16:48:05 2015 +0000 @@ -423,8 +423,10 @@ static bool is_astore (Code code) { return (code == _astore || code == _astore_0 || code == _astore_1 || code == _astore_2 || code == _astore_3); } + static bool is_const (Code code) { return (_aconst_null <= code && code <= _ldc2_w); } static bool is_zero_const (Code code) { return (code == _aconst_null || code == _iconst_0 || code == _fconst_0 || code == _dconst_0); } + static bool is_return (Code code) { return (_ireturn <= code && code <= _return); } static bool is_invoke (Code code) { return (_invokevirtual <= code && code <= _invokedynamic); } static bool has_receiver (Code code) { assert(is_invoke(code), ""); return code == _invokevirtual || code == _invokespecial ||
--- a/src/share/vm/interpreter/interpreterRuntime.cpp Thu Jan 08 12:47:32 2015 +0000 +++ b/src/share/vm/interpreter/interpreterRuntime.cpp Tue Feb 03 16:48:05 2015 +0000 @@ -401,6 +401,18 @@ int handler_bci; int current_bci = bci(thread); + if (thread->frames_to_pop_failed_realloc() > 0) { + // Allocation of scalar replaced object used in this frame + // failed. Unconditionally pop the frame. + thread->dec_frames_to_pop_failed_realloc(); + thread->set_vm_result(h_exception()); + // If the method is synchronized we already unlocked the monitor + // during deoptimization so the interpreter needs to skip it when + // the frame is popped. + thread->set_do_not_unlock_if_synchronized(true); + return Interpreter::remove_activation_entry(); + } + // Need to do this check first since when _do_not_unlock_if_synchronized // is set, we don't want to trigger any classloading which may make calls // into java, or surprisingly find a matching exception handler for bci 0
--- a/src/share/vm/interpreter/linkResolver.cpp Thu Jan 08 12:47:32 2015 +0000 +++ b/src/share/vm/interpreter/linkResolver.cpp Tue Feb 03 16:48:05 2015 +0000 @@ -320,7 +320,7 @@ // First check in default method array if (!resolved_method->is_abstract() && (InstanceKlass::cast(klass())->default_methods() != NULL)) { - int index = InstanceKlass::find_method_index(InstanceKlass::cast(klass())->default_methods(), name, signature, false); + int index = InstanceKlass::find_method_index(InstanceKlass::cast(klass())->default_methods(), name, signature, false, false); if (index >= 0 ) { vtable_index = InstanceKlass::cast(klass())->default_vtable_indices()->at(index); }
--- a/src/share/vm/memory/collectorPolicy.cpp Thu Jan 08 12:47:32 2015 +0000 +++ b/src/share/vm/memory/collectorPolicy.cpp Tue Feb 03 16:48:05 2015 +0000 @@ -183,13 +183,9 @@ // Requirements of any new remembered set implementations must be added here. size_t alignment = GenRemSet::max_alignment_constraint(GenRemSet::CardTable); - // Parallel GC does its own alignment of the generations to avoid requiring a - // large page (256M on some platforms) for the permanent generation. The - // other collectors should also be updated to do their own alignment and then - // this use of lcm() should be removed. - if (UseLargePages && !UseParallelGC) { - // in presence of large pages we have to make sure that our - // alignment is large page aware + if (UseLargePages) { + // In presence of large pages we have to make sure that our + // alignment is large page aware. alignment = lcm(os::large_page_size(), alignment); }
--- a/src/share/vm/memory/filemap.cpp Thu Jan 08 12:47:32 2015 +0000 +++ b/src/share/vm/memory/filemap.cpp Tue Feb 03 16:48:05 2015 +0000 @@ -97,11 +97,11 @@ tty->print_cr("UseSharedSpaces: %s", msg); } } + UseSharedSpaces = false; + assert(current_info() != NULL, "singleton must be registered"); + current_info()->close(); } va_end(ap); - UseSharedSpaces = false; - assert(current_info() != NULL, "singleton must be registered"); - current_info()->close(); } // Fill in the fileMapInfo structure with data about this VM instance.
--- a/src/share/vm/memory/metadataFactory.hpp Thu Jan 08 12:47:32 2015 +0000 +++ b/src/share/vm/memory/metadataFactory.hpp Tue Feb 03 16:48:05 2015 +0000 @@ -64,6 +64,12 @@ template <typename T> static void free_array(ClassLoaderData* loader_data, Array<T>* data) { + if (DumpSharedSpaces) { + // FIXME: the freeing code is buggy, especially when PrintSharedSpaces is enabled. + // Disable for now -- this means if you specify bad classes in your classlist you + // may have wasted space inside the archive. + return; + } if (data != NULL) { assert(loader_data != NULL, "shouldn't pass null"); assert(!data->is_shared(), "cannot deallocate array in shared spaces");
--- a/src/share/vm/memory/metaspace.cpp Thu Jan 08 12:47:32 2015 +0000 +++ b/src/share/vm/memory/metaspace.cpp Tue Feb 03 16:48:05 2015 +0000 @@ -3181,7 +3181,7 @@ MetaspaceGC::initialize(); // Initialize the alignment for shared spaces. - int max_alignment = os::vm_page_size(); + int max_alignment = os::vm_allocation_granularity(); size_t cds_total = 0; MetaspaceShared::set_max_alignment(max_alignment); @@ -3195,6 +3195,16 @@ SharedMiscDataSize = align_size_up(SharedMiscDataSize, max_alignment); SharedMiscCodeSize = align_size_up(SharedMiscCodeSize, max_alignment); + // the min_misc_code_size estimate is based on MetaspaceShared::generate_vtable_methods() + uintx min_misc_code_size = align_size_up( + (MetaspaceShared::num_virtuals * MetaspaceShared::vtbl_list_size) * + (sizeof(void*) + MetaspaceShared::vtbl_method_size) + MetaspaceShared::vtbl_common_code_size, + max_alignment); + + if (SharedMiscCodeSize < min_misc_code_size) { + report_out_of_shared_space(SharedMiscCode); + } + // Initialize with the sum of the shared space sizes. The read-only // and read write metaspace chunks will be allocated out of this and the // remainder is the misc code and data chunks.
--- a/src/share/vm/memory/metaspaceShared.cpp Thu Jan 08 12:47:32 2015 +0000 +++ b/src/share/vm/memory/metaspaceShared.cpp Tue Feb 03 16:48:05 2015 +0000 @@ -24,6 +24,7 @@ #include "precompiled.hpp" #include "classfile/dictionary.hpp" +#include "classfile/classLoaderExt.hpp" #include "classfile/loaderConstraints.hpp" #include "classfile/placeholders.hpp" #include "classfile/sharedClassUtil.hpp" @@ -39,6 +40,7 @@ #include "runtime/signature.hpp" #include "runtime/vm_operations.hpp" #include "runtime/vmThread.hpp" +#include "utilities/hashtable.hpp" #include "utilities/hashtable.inline.hpp" PRAGMA_FORMAT_MUTE_WARNINGS_FOR_GCC @@ -533,6 +535,8 @@ ClassLoader::copy_package_info_table(&md_top, md_end); ClassLoader::verify(); + ClassLoaderExt::copy_lookup_cache_to_archive(&md_top, md_end); + // Write the other data to the output array. WriteClosure wc(md_top, md_end); MetaspaceShared::serialize(&wc); @@ -745,6 +749,8 @@ } tty->print_cr("Loading classes to share: done."); + ClassLoaderExt::init_lookup_cache(THREAD); + if (PrintSharedSpaces) { tty->print_cr("Shared spaces: preloaded %d classes", class_count); } @@ -845,7 +851,7 @@ ik->link_class(THREAD); if (HAS_PENDING_EXCEPTION) { ResourceMark rm; - tty->print_cr("Preload Error: Verification failed for %s", + tty->print_cr("Preload Warning: Verification failed for %s", ik->external_name()); CLEAR_PENDING_EXCEPTION; ik->set_in_error_state(); @@ -961,7 +967,7 @@ #endif // If -Xshare:on is specified, print out the error message and exit VM, // otherwise, set UseSharedSpaces to false and continue. - if (RequireSharedSpaces) { + if (RequireSharedSpaces || PrintSharedArchiveAndExit) { vm_exit_during_initialization("Unable to use shared archive.", "Failed map_region for using -Xshare:on."); } else { FLAG_SET_DEFAULT(UseSharedSpaces, false); @@ -1060,6 +1066,8 @@ buffer += sizeof(intptr_t); buffer += len; + buffer = ClassLoaderExt::restore_lookup_cache_from_archive(buffer); + intptr_t* array = (intptr_t*)buffer; ReadClosure rc(&array); serialize(&rc);
--- a/src/share/vm/memory/metaspaceShared.hpp Thu Jan 08 12:47:32 2015 +0000 +++ b/src/share/vm/memory/metaspaceShared.hpp Tue Feb 03 16:48:05 2015 +0000 @@ -32,9 +32,9 @@ #define LargeSharedArchiveSize (300*M) #define HugeSharedArchiveSize (800*M) -#define ReadOnlyRegionPercentage 0.4 -#define ReadWriteRegionPercentage 0.55 -#define MiscDataRegionPercentage 0.03 +#define ReadOnlyRegionPercentage 0.39 +#define ReadWriteRegionPercentage 0.50 +#define MiscDataRegionPercentage 0.09 #define MiscCodeRegionPercentage 0.02 #define LargeThresholdClassCount 5000 #define HugeThresholdClassCount 40000 @@ -57,11 +57,16 @@ static bool _archive_loading_failed; public: enum { - vtbl_list_size = 17, // number of entries in the shared space vtable list. - num_virtuals = 200 // maximum number of virtual functions - // If virtual functions are added to Metadata, - // this number needs to be increased. Also, - // SharedMiscCodeSize will need to be increased. + vtbl_list_size = 17, // number of entries in the shared space vtable list. + num_virtuals = 200, // maximum number of virtual functions + // If virtual functions are added to Metadata, + // this number needs to be increased. Also, + // SharedMiscCodeSize will need to be increased. + // The following 2 sizes were based on + // MetaspaceShared::generate_vtable_methods() + vtbl_method_size = 16, // conservative size of the mov1 and jmp instructions + // for the x64 platform + vtbl_common_code_size = (1*K) // conservative size of the "common_code" for the x64 platform }; enum {
--- a/src/share/vm/memory/referenceProcessor.cpp Thu Jan 08 12:47:32 2015 +0000 +++ b/src/share/vm/memory/referenceProcessor.cpp Tue Feb 03 16:48:05 2015 +0000 @@ -118,6 +118,7 @@ _discoveredWeakRefs = &_discoveredSoftRefs[_max_num_q]; _discoveredFinalRefs = &_discoveredWeakRefs[_max_num_q]; _discoveredPhantomRefs = &_discoveredFinalRefs[_max_num_q]; + _discoveredCleanerRefs = &_discoveredPhantomRefs[_max_num_q]; // Initialize all entries to NULL for (uint i = 0; i < _max_num_q * number_of_subclasses_of_ref(); i++) { @@ -246,6 +247,13 @@ phantom_count = process_discovered_reflist(_discoveredPhantomRefs, NULL, false, is_alive, keep_alive, complete_gc, task_executor); + + // Process cleaners, but include them in phantom statistics. We expect + // Cleaner references to be temporary, and don't want to deal with + // possible incompatibilities arising from making it more visible. + phantom_count += + process_discovered_reflist(_discoveredCleanerRefs, NULL, false, + is_alive, keep_alive, complete_gc, task_executor); } // Weak global JNI references. It would make more sense (semantically) to @@ -883,6 +891,7 @@ balance_queues(_discoveredWeakRefs); balance_queues(_discoveredFinalRefs); balance_queues(_discoveredPhantomRefs); + balance_queues(_discoveredCleanerRefs); } size_t @@ -1042,6 +1051,9 @@ case REF_PHANTOM: list = &_discoveredPhantomRefs[id]; break; + case REF_CLEANER: + list = &_discoveredCleanerRefs[id]; + break; case REF_NONE: // we should not reach here if we are an InstanceRefKlass default: @@ -1307,6 +1319,17 @@ preclean_discovered_reflist(_discoveredPhantomRefs[i], is_alive, keep_alive, complete_gc, yield); } + + // Cleaner references. Included in timing for phantom references. We + // expect Cleaner references to be temporary, and don't want to deal with + // possible incompatibilities arising from making it more visible. + for (uint i = 0; i < _max_num_q; i++) { + if (yield->should_return()) { + return; + } + preclean_discovered_reflist(_discoveredCleanerRefs[i], is_alive, + keep_alive, complete_gc, yield); + } } } @@ -1375,6 +1398,7 @@ case 1: return "WeakRef"; case 2: return "FinalRef"; case 3: return "PhantomRef"; + case 4: return "CleanerRef"; } ShouldNotReachHere(); return NULL;
--- a/src/share/vm/memory/referenceProcessor.hpp Thu Jan 08 12:47:32 2015 +0000 +++ b/src/share/vm/memory/referenceProcessor.hpp Tue Feb 03 16:48:05 2015 +0000 @@ -264,9 +264,10 @@ DiscoveredList* _discoveredWeakRefs; DiscoveredList* _discoveredFinalRefs; DiscoveredList* _discoveredPhantomRefs; + DiscoveredList* _discoveredCleanerRefs; public: - static int number_of_subclasses_of_ref() { return (REF_PHANTOM - REF_OTHER); } + static int number_of_subclasses_of_ref() { return (REF_CLEANER - REF_OTHER); } uint num_q() { return _num_q; } uint max_num_q() { return _max_num_q; }
--- a/src/share/vm/memory/referenceType.hpp Thu Jan 08 12:47:32 2015 +0000 +++ b/src/share/vm/memory/referenceType.hpp Tue Feb 03 16:48:05 2015 +0000 @@ -35,7 +35,8 @@ REF_SOFT, // Subclass of java/lang/ref/SoftReference REF_WEAK, // Subclass of java/lang/ref/WeakReference REF_FINAL, // Subclass of java/lang/ref/FinalReference - REF_PHANTOM // Subclass of java/lang/ref/PhantomReference + REF_PHANTOM, // Subclass of java/lang/ref/PhantomReference + REF_CLEANER // Subclass of sun/misc/Cleaner }; #endif // SHARE_VM_MEMORY_REFRERENCETYPE_HPP
--- a/src/share/vm/memory/threadLocalAllocBuffer.cpp Thu Jan 08 12:47:32 2015 +0000 +++ b/src/share/vm/memory/threadLocalAllocBuffer.cpp Tue Feb 03 16:48:05 2015 +0000 @@ -235,22 +235,19 @@ } size_t ThreadLocalAllocBuffer::initial_desired_size() { - size_t init_sz; + size_t init_sz = 0; if (TLABSize > 0) { - init_sz = MIN2(TLABSize / HeapWordSize, max_size()); - } else if (global_stats() == NULL) { - // Startup issue - main thread initialized before heap initialized. - init_sz = min_size(); - } else { + init_sz = TLABSize / HeapWordSize; + } else if (global_stats() != NULL) { // Initial size is a function of the average number of allocating threads. unsigned nof_threads = global_stats()->allocating_threads_avg(); init_sz = (Universe::heap()->tlab_capacity(myThread()) / HeapWordSize) / (nof_threads * target_refills()); init_sz = align_object_size(init_sz); - init_sz = MIN2(MAX2(init_sz, min_size()), max_size()); } + init_sz = MIN2(MAX2(init_sz, min_size()), max_size()); return init_sz; }
--- a/src/share/vm/memory/threadLocalAllocBuffer.hpp Thu Jan 08 12:47:32 2015 +0000 +++ b/src/share/vm/memory/threadLocalAllocBuffer.hpp Tue Feb 03 16:48:05 2015 +0000 @@ -105,7 +105,7 @@ // do nothing. tlabs must be inited by initialize() calls } - static const size_t min_size() { return align_object_size(MinTLABSize / HeapWordSize); } + static const size_t min_size() { return align_object_size(MinTLABSize / HeapWordSize) + alignment_reserve(); } static const size_t max_size() { assert(_max_size != 0, "max_size not set up"); return _max_size; } static void set_max_size(size_t max_size) { _max_size = max_size; }
--- a/src/share/vm/memory/universe.cpp Thu Jan 08 12:47:32 2015 +0000 +++ b/src/share/vm/memory/universe.cpp Tue Feb 03 16:48:05 2015 +0000 @@ -78,7 +78,7 @@ #include "gc_implementation/concurrentMarkSweep/cmsAdaptiveSizePolicy.hpp" #include "gc_implementation/concurrentMarkSweep/cmsCollectorPolicy.hpp" #include "gc_implementation/g1/g1CollectedHeap.inline.hpp" -#include "gc_implementation/g1/g1CollectorPolicy.hpp" +#include "gc_implementation/g1/g1CollectorPolicy_ext.hpp" #include "gc_implementation/parallelScavenge/parallelScavengeHeap.hpp" #endif // INCLUDE_ALL_GCS @@ -119,6 +119,7 @@ oop Universe::_out_of_memory_error_class_metaspace = NULL; oop Universe::_out_of_memory_error_array_size = NULL; oop Universe::_out_of_memory_error_gc_overhead_limit = NULL; +oop Universe::_out_of_memory_error_realloc_objects = NULL; objArrayOop Universe::_preallocated_out_of_memory_error_array = NULL; volatile jint Universe::_preallocated_out_of_memory_error_avail_count = 0; bool Universe::_verify_in_progress = false; @@ -190,6 +191,7 @@ f->do_oop((oop*)&_out_of_memory_error_class_metaspace); f->do_oop((oop*)&_out_of_memory_error_array_size); f->do_oop((oop*)&_out_of_memory_error_gc_overhead_limit); + f->do_oop((oop*)&_out_of_memory_error_realloc_objects); f->do_oop((oop*)&_preallocated_out_of_memory_error_array); f->do_oop((oop*)&_null_ptr_exception_instance); f->do_oop((oop*)&_arithmetic_exception_instance); @@ -574,7 +576,8 @@ (throwable() != Universe::_out_of_memory_error_metaspace) && (throwable() != Universe::_out_of_memory_error_class_metaspace) && (throwable() != Universe::_out_of_memory_error_array_size) && - (throwable() != Universe::_out_of_memory_error_gc_overhead_limit)); + (throwable() != Universe::_out_of_memory_error_gc_overhead_limit) && + (throwable() != Universe::_out_of_memory_error_realloc_objects)); } @@ -798,7 +801,7 @@ } else if (UseG1GC) { #if INCLUDE_ALL_GCS - G1CollectorPolicy* g1p = new G1CollectorPolicy(); + G1CollectorPolicyExt* g1p = new G1CollectorPolicyExt(); g1p->initialize_all(); G1CollectedHeap* g1h = new G1CollectedHeap(g1p); Universe::_collectedHeap = g1h; @@ -1044,6 +1047,7 @@ Universe::_out_of_memory_error_array_size = k_h->allocate_instance(CHECK_false); Universe::_out_of_memory_error_gc_overhead_limit = k_h->allocate_instance(CHECK_false); + Universe::_out_of_memory_error_realloc_objects = k_h->allocate_instance(CHECK_false); // Setup preallocated NullPointerException // (this is currently used for a cheap & dirty solution in compiler exception handling) @@ -1083,6 +1087,9 @@ msg = java_lang_String::create_from_str("GC overhead limit exceeded", CHECK_false); java_lang_Throwable::set_message(Universe::_out_of_memory_error_gc_overhead_limit, msg()); + msg = java_lang_String::create_from_str("Java heap space: failed reallocation of scalar replaced objects", CHECK_false); + java_lang_Throwable::set_message(Universe::_out_of_memory_error_realloc_objects, msg()); + msg = java_lang_String::create_from_str("/ by zero", CHECK_false); java_lang_Throwable::set_message(Universe::_arithmetic_exception_instance, msg());
--- a/src/share/vm/memory/universe.hpp Thu Jan 08 12:47:32 2015 +0000 +++ b/src/share/vm/memory/universe.hpp Tue Feb 03 16:48:05 2015 +0000 @@ -157,6 +157,7 @@ static oop _out_of_memory_error_class_metaspace; static oop _out_of_memory_error_array_size; static oop _out_of_memory_error_gc_overhead_limit; + static oop _out_of_memory_error_realloc_objects; static Array<int>* _the_empty_int_array; // Canonicalized int array static Array<u2>* _the_empty_short_array; // Canonicalized short array @@ -328,6 +329,7 @@ static oop out_of_memory_error_class_metaspace() { return gen_out_of_memory_error(_out_of_memory_error_class_metaspace); } static oop out_of_memory_error_array_size() { return gen_out_of_memory_error(_out_of_memory_error_array_size); } static oop out_of_memory_error_gc_overhead_limit() { return gen_out_of_memory_error(_out_of_memory_error_gc_overhead_limit); } + static oop out_of_memory_error_realloc_objects() { return gen_out_of_memory_error(_out_of_memory_error_realloc_objects); } // Accessors needed for fast allocation static Klass** boolArrayKlassObj_addr() { return &_boolArrayKlassObj; }
--- a/src/share/vm/oops/constantPool.cpp Thu Jan 08 12:47:32 2015 +0000 +++ b/src/share/vm/oops/constantPool.cpp Tue Feb 03 16:48:05 2015 +0000 @@ -1817,11 +1817,22 @@ void ConstantPool::set_on_stack(const bool value) { if (value) { - _flags |= _on_stack; + int old_flags = *const_cast<volatile int *>(&_flags); + while ((old_flags & _on_stack) == 0) { + int new_flags = old_flags | _on_stack; + int result = Atomic::cmpxchg(new_flags, &_flags, old_flags); + + if (result == old_flags) { + // Succeeded. + MetadataOnStackMark::record(this, Thread::current()); + return; + } + old_flags = result; + } } else { + // Clearing is done single-threadedly. _flags &= ~_on_stack; } - if (value) MetadataOnStackMark::record(this); } // JSR 292 support for patching constant pool oops after the class is linked and
--- a/src/share/vm/oops/instanceKlass.cpp Thu Jan 08 12:47:32 2015 +0000 +++ b/src/share/vm/oops/instanceKlass.cpp Tue Feb 03 16:48:05 2015 +0000 @@ -780,6 +780,41 @@ } } +// Eagerly initialize superinterfaces that declare default methods (concrete instance: any access) +void InstanceKlass::initialize_super_interfaces(instanceKlassHandle this_oop, TRAPS) { + if (this_oop->has_default_methods()) { + for (int i = 0; i < this_oop->local_interfaces()->length(); ++i) { + Klass* iface = this_oop->local_interfaces()->at(i); + InstanceKlass* ik = InstanceKlass::cast(iface); + if (ik->should_be_initialized()) { + if (ik->has_default_methods()) { + ik->initialize_super_interfaces(ik, THREAD); + } + // Only initialize() interfaces that "declare" concrete methods. + // has_default_methods drives searching superinterfaces since it + // means has_default_methods in its superinterface hierarchy + if (!HAS_PENDING_EXCEPTION && ik->declares_default_methods()) { + ik->initialize(THREAD); + } + if (HAS_PENDING_EXCEPTION) { + Handle e(THREAD, PENDING_EXCEPTION); + CLEAR_PENDING_EXCEPTION; + { + EXCEPTION_MARK; + // Locks object, set state, and notify all waiting threads + this_oop->set_initialization_state_and_notify( + initialization_error, THREAD); + + // ignore any exception thrown, superclass initialization error is + // thrown below + CLEAR_PENDING_EXCEPTION; + } + THROW_OOP(e()); + } + } + } + } +} void InstanceKlass::initialize_impl(instanceKlassHandle this_oop, TRAPS) { // Make sure klass is linked (verified) before initialization @@ -859,33 +894,11 @@ } } + // Recursively initialize any superinterfaces that declare default methods + // Only need to recurse if has_default_methods which includes declaring and + // inheriting default methods if (this_oop->has_default_methods()) { - // Step 7.5: initialize any interfaces which have default methods - for (int i = 0; i < this_oop->local_interfaces()->length(); ++i) { - Klass* iface = this_oop->local_interfaces()->at(i); - InstanceKlass* ik = InstanceKlass::cast(iface); - if (ik->has_default_methods() && ik->should_be_initialized()) { - ik->initialize(THREAD); - - if (HAS_PENDING_EXCEPTION) { - Handle e(THREAD, PENDING_EXCEPTION); - CLEAR_PENDING_EXCEPTION; - { - EXCEPTION_MARK; - // Locks object, set state, and notify all waiting threads - this_oop->set_initialization_state_and_notify( - initialization_error, THREAD); - - // ignore any exception thrown, superclass initialization error is - // thrown below - CLEAR_PENDING_EXCEPTION; - } - DTRACE_CLASSINIT_PROBE_WAIT( - super__failed, InstanceKlass::cast(this_oop()), -1, wait); - THROW_OOP(e()); - } - } - } + this_oop->initialize_super_interfaces(this_oop, CHECK); } // Step 8 @@ -1440,32 +1453,41 @@ } Method* InstanceKlass::find_method_impl(Symbol* name, Symbol* signature, bool skipping_overpass) const { - return InstanceKlass::find_method_impl(methods(), name, signature, skipping_overpass); + return InstanceKlass::find_method_impl(methods(), name, signature, skipping_overpass, false); } // find_instance_method looks up the name/signature in the local methods array // and skips over static methods Method* InstanceKlass::find_instance_method( Array<Method*>* methods, Symbol* name, Symbol* signature) { - Method* meth = InstanceKlass::find_method(methods, name, signature); - if (meth != NULL && meth->is_static()) { - meth = NULL; - } + Method* meth = InstanceKlass::find_method_impl(methods, name, signature, false, true); return meth; } +// find_instance_method looks up the name/signature in the local methods array +// and skips over static methods +Method* InstanceKlass::find_instance_method(Symbol* name, Symbol* signature) { + return InstanceKlass::find_instance_method(methods(), name, signature); +} + // find_method looks up the name/signature in the local methods array Method* InstanceKlass::find_method( Array<Method*>* methods, Symbol* name, Symbol* signature) { - return InstanceKlass::find_method_impl(methods, name, signature, false); + return InstanceKlass::find_method_impl(methods, name, signature, false, false); } Method* InstanceKlass::find_method_impl( - Array<Method*>* methods, Symbol* name, Symbol* signature, bool skipping_overpass) { - int hit = find_method_index(methods, name, signature, skipping_overpass); + Array<Method*>* methods, Symbol* name, Symbol* signature, bool skipping_overpass, bool skipping_static) { + int hit = find_method_index(methods, name, signature, skipping_overpass, skipping_static); return hit >= 0 ? methods->at(hit): NULL; } +bool InstanceKlass::method_matches(Method* m, Symbol* signature, bool skipping_overpass, bool skipping_static) { + return (m->signature() == signature) && + (!skipping_overpass || !m->is_overpass()) && + (!skipping_static || !m->is_static()); +} + // Used directly for default_methods to find the index into the // default_vtable_indices, and indirectly by find_method // find_method_index looks in the local methods array to return the index @@ -1474,13 +1496,14 @@ // is important during method resolution to prefer a static method, for example, // over an overpass method. int InstanceKlass::find_method_index( - Array<Method*>* methods, Symbol* name, Symbol* signature, bool skipping_overpass) { + Array<Method*>* methods, Symbol* name, Symbol* signature, bool skipping_overpass, bool skipping_static) { int hit = binary_search(methods, name); if (hit != -1) { Method* m = methods->at(hit); + // Do linear search to find matching signature. First, quick check // for common case, ignoring overpasses if requested. - if ((m->signature() == signature) && (!skipping_overpass || !m->is_overpass())) return hit; + if (method_matches(m, signature, skipping_overpass, skipping_static)) return hit; // search downwards through overloaded methods int i; @@ -1488,18 +1511,18 @@ Method* m = methods->at(i); assert(m->is_method(), "must be method"); if (m->name() != name) break; - if ((m->signature() == signature) && (!skipping_overpass || !m->is_overpass())) return i; + if (method_matches(m, signature, skipping_overpass, skipping_static)) return i; } // search upwards for (i = hit + 1; i < methods->length(); ++i) { Method* m = methods->at(i); assert(m->is_method(), "must be method"); if (m->name() != name) break; - if ((m->signature() == signature) && (!skipping_overpass || !m->is_overpass())) return i; + if (method_matches(m, signature, skipping_overpass, skipping_static)) return i; } // not found #ifdef ASSERT - int index = skipping_overpass ? -1 : linear_search(methods, name, signature); + int index = skipping_overpass || skipping_static ? -1 : linear_search(methods, name, signature); assert(index == -1, err_msg("binary search should have found entry %d", index)); #endif } @@ -2877,6 +2900,22 @@ OsrList_lock->unlock(); } +int InstanceKlass::mark_osr_nmethods(const Method* m) { + // This is a short non-blocking critical region, so the no safepoint check is ok. + MutexLockerEx ml(OsrList_lock, Mutex::_no_safepoint_check_flag); + nmethod* osr = osr_nmethods_head(); + int found = 0; + while (osr != NULL) { + assert(osr->is_osr_method(), "wrong kind of nmethod found in chain"); + if (osr->method() == m) { + osr->mark_for_deoptimization(); + found++; + } + osr = osr->osr_link(); + } + return found; +} + nmethod* InstanceKlass::lookup_osr_nmethod(const Method* m, int bci, int comp_level, bool match_level) const { // This is a short non-blocking critical region, so the no safepoint check is ok. OsrList_lock->lock_without_safepoint_check(); @@ -2918,28 +2957,27 @@ return NULL; } -void InstanceKlass::add_member_name(int index, Handle mem_name) { +bool InstanceKlass::add_member_name(Handle mem_name) { jweak mem_name_wref = JNIHandles::make_weak_global(mem_name); MutexLocker ml(MemberNameTable_lock); - assert(0 <= index && index < idnum_allocated_count(), "index is out of bounds"); DEBUG_ONLY(No_Safepoint_Verifier nsv); + // Check if method has been redefined while taking out MemberNameTable_lock, if so + // return false. We cannot cache obsolete methods. They will crash when the function + // is called! + Method* method = (Method*)java_lang_invoke_MemberName::vmtarget(mem_name()); + if (method->is_obsolete()) { + return false; + } else if (method->is_old()) { + // Replace method with redefined version + java_lang_invoke_MemberName::set_vmtarget(mem_name(), method_with_idnum(method->method_idnum())); + } + if (_member_names == NULL) { _member_names = new (ResourceObj::C_HEAP, mtClass) MemberNameTable(idnum_allocated_count()); } - _member_names->add_member_name(index, mem_name_wref); -} - -oop InstanceKlass::get_member_name(int index) { - MutexLocker ml(MemberNameTable_lock); - assert(0 <= index && index < idnum_allocated_count(), "index is out of bounds"); - DEBUG_ONLY(No_Safepoint_Verifier nsv); - - if (_member_names == NULL) { - return NULL; - } - oop mem_name =_member_names->get_member_name(index); - return mem_name; + _member_names->add_member_name(mem_name_wref); + return true; } // -----------------------------------------------------------------------------------------------------
--- a/src/share/vm/oops/instanceKlass.hpp Thu Jan 08 12:47:32 2015 +0000 +++ b/src/share/vm/oops/instanceKlass.hpp Tue Feb 03 16:48:05 2015 +0000 @@ -229,12 +229,13 @@ bool _has_unloaded_dependent; enum { - _misc_rewritten = 1 << 0, // methods rewritten. - _misc_has_nonstatic_fields = 1 << 1, // for sizing with UseCompressedOops - _misc_should_verify_class = 1 << 2, // allow caching of preverification - _misc_is_anonymous = 1 << 3, // has embedded _host_klass field - _misc_is_contended = 1 << 4, // marked with contended annotation - _misc_has_default_methods = 1 << 5 // class/superclass/implemented interfaces has default methods + _misc_rewritten = 1 << 0, // methods rewritten. + _misc_has_nonstatic_fields = 1 << 1, // for sizing with UseCompressedOops + _misc_should_verify_class = 1 << 2, // allow caching of preverification + _misc_is_anonymous = 1 << 3, // has embedded _host_klass field + _misc_is_contended = 1 << 4, // marked with contended annotation + _misc_has_default_methods = 1 << 5, // class/superclass/implemented interfaces has default methods + _misc_declares_default_methods = 1 << 6 // directly declares default methods (any access) }; u2 _misc_flags; u2 _minor_version; // minor version number of class file @@ -519,10 +520,16 @@ // find a local method (returns NULL if not found) Method* find_method(Symbol* name, Symbol* signature) const; static Method* find_method(Array<Method*>* methods, Symbol* name, Symbol* signature); + + // find a local method, but skip static methods + Method* find_instance_method(Symbol* name, Symbol* signature); static Method* find_instance_method(Array<Method*>* methods, Symbol* name, Symbol* signature); + // true if method matches signature and conforms to skipping_X conditions. + static bool method_matches(Method* m, Symbol* signature, bool skipping_overpass, bool skipping_static); + // find a local method index in default_methods (returns -1 if not found) - static int find_method_index(Array<Method*>* methods, Symbol* name, Symbol* signature, bool skipping_overpass); + static int find_method_index(Array<Method*>* methods, Symbol* name, Symbol* signature, bool skipping_overpass, bool skipping_static); // lookup operation (returns NULL if not found) Method* uncached_lookup_method(Symbol* name, Symbol* signature, MethodLookupMode mode) const; @@ -680,6 +687,17 @@ } } + bool declares_default_methods() const { + return (_misc_flags & _misc_declares_default_methods) != 0; + } + void set_declares_default_methods(bool b) { + if (b) { + _misc_flags |= _misc_declares_default_methods; + } else { + _misc_flags &= ~_misc_declares_default_methods; + } + } + // for adding methods, ConstMethod::UNSET_IDNUM means no more ids available inline u2 next_method_idnum(); void set_initial_method_idnum(u2 value) { _idnum_allocated_count = value; } @@ -771,6 +789,7 @@ void set_osr_nmethods_head(nmethod* h) { _osr_nmethods_head = h; }; void add_osr_nmethod(nmethod* n); void remove_osr_nmethod(nmethod* n); + int mark_osr_nmethods(const Method* m); nmethod* lookup_osr_nmethod(const Method* m, int bci, int level, bool match_level) const; // Breakpoint support (see methods on Method* for details) @@ -1046,6 +1065,7 @@ static bool link_class_impl (instanceKlassHandle this_oop, bool throw_verifyerror, TRAPS); static bool verify_code (instanceKlassHandle this_oop, bool throw_verifyerror, TRAPS); static void initialize_impl (instanceKlassHandle this_oop, TRAPS); + static void initialize_super_interfaces (instanceKlassHandle this_oop, TRAPS); static void eager_initialize_impl (instanceKlassHandle this_oop); static void set_initialization_state_and_notify_impl (instanceKlassHandle this_oop, ClassState state, TRAPS); static void call_class_initializer_impl (instanceKlassHandle this_oop, TRAPS); @@ -1062,7 +1082,7 @@ // find a local method (returns NULL if not found) Method* find_method_impl(Symbol* name, Symbol* signature, bool skipping_overpass) const; - static Method* find_method_impl(Array<Method*>* methods, Symbol* name, Symbol* signature, bool skipping_overpass); + static Method* find_method_impl(Array<Method*>* methods, Symbol* name, Symbol* signature, bool skipping_overpass, bool skipping_static); // Free CHeap allocated fields. void release_C_heap_structures(); @@ -1077,8 +1097,7 @@ // JSR-292 support MemberNameTable* member_names() { return _member_names; } void set_member_names(MemberNameTable* member_names) { _member_names = member_names; } - void add_member_name(int index, Handle member_name); - oop get_member_name(int index); + bool add_member_name(Handle member_name); public: // JVMTI support
--- a/src/share/vm/oops/method.cpp Thu Jan 08 12:47:32 2015 +0000 +++ b/src/share/vm/oops/method.cpp Tue Feb 03 16:48:05 2015 +0000 @@ -563,6 +563,15 @@ return true; } +bool Method::is_constant_getter() const { + int last_index = code_size() - 1; + // Check if the first 1-3 bytecodes are a constant push + // and the last bytecode is a return. + return (2 <= code_size() && code_size() <= 4 && + Bytecodes::is_const(java_code_at(0)) && + Bytecodes::length_for(java_code_at(0)) == last_index && + Bytecodes::is_return(java_code_at(last_index))); +} bool Method::is_initializer() const { return name() == vmSymbols::object_initializer_name() || is_static_initializer(); @@ -1880,9 +1889,12 @@ void Method::set_on_stack(const bool value) { // Set both the method itself and its constant pool. The constant pool // on stack means some method referring to it is also on the stack. - _access_flags.set_on_stack(value); constants()->set_on_stack(value); - if (value) MetadataOnStackMark::record(this); + + bool succeeded = _access_flags.set_on_stack(value); + if (value && succeeded) { + MetadataOnStackMark::record(this, Thread::current()); + } } // Called when the class loader is unloaded to make all methods weak.
--- a/src/share/vm/oops/method.hpp Thu Jan 08 12:47:32 2015 +0000 +++ b/src/share/vm/oops/method.hpp Tue Feb 03 16:48:05 2015 +0000 @@ -624,6 +624,9 @@ // returns true if the method is an accessor function (setter/getter). bool is_accessor() const; + // returns true if the method does nothing but return a constant of primitive type + bool is_constant_getter() const; + // returns true if the method is an initializer (<init> or <clinit>). bool is_initializer() const; @@ -798,6 +801,10 @@ return method_holder()->lookup_osr_nmethod(this, InvocationEntryBci, level, match_level) != NULL; } + int mark_osr_nmethods() { + return method_holder()->mark_osr_nmethods(this); + } + nmethod* lookup_osr_nmethod_for(int bci, int level, bool match_level) { return method_holder()->lookup_osr_nmethod(this, bci, level, match_level); }
--- a/src/share/vm/oops/methodData.cpp Thu Jan 08 12:47:32 2015 +0000 +++ b/src/share/vm/oops/methodData.cpp Tue Feb 03 16:48:05 2015 +0000 @@ -1153,7 +1153,7 @@ _backedge_counter_start = 0; _num_loops = 0; _num_blocks = 0; - _would_profile = true; + _would_profile = unknown; #if INCLUDE_RTM_OPT _rtm_state = NoRTM; // No RTM lock eliding by default
--- a/src/share/vm/oops/methodData.hpp Thu Jan 08 12:47:32 2015 +0000 +++ b/src/share/vm/oops/methodData.hpp Tue Feb 03 16:48:05 2015 +0000 @@ -2099,7 +2099,8 @@ short _num_loops; short _num_blocks; // Does this method contain anything worth profiling? - bool _would_profile; + enum WouldProfile {unknown, no_profile, profile}; + WouldProfile _would_profile; // Size of _data array in bytes. (Excludes header and extra_data fields.) int _data_size; @@ -2268,8 +2269,8 @@ } #endif - void set_would_profile(bool p) { _would_profile = p; } - bool would_profile() const { return _would_profile; } + void set_would_profile(bool p) { _would_profile = p ? profile : no_profile; } + bool would_profile() const { return _would_profile != no_profile; } int num_loops() const { return _num_loops; } void set_num_loops(int n) { _num_loops = n; }
--- a/src/share/vm/oops/objArrayOop.hpp Thu Jan 08 12:47:32 2015 +0000 +++ b/src/share/vm/oops/objArrayOop.hpp Tue Feb 03 16:48:05 2015 +0000 @@ -45,9 +45,10 @@ private: // Give size of objArrayOop in HeapWords minus the header static int array_size(int length) { - const int OopsPerHeapWord = HeapWordSize/heapOopSize; + const uint OopsPerHeapWord = HeapWordSize/heapOopSize; assert(OopsPerHeapWord >= 1 && (HeapWordSize % heapOopSize == 0), "Else the following (new) computation would be in error"); + uint res = ((uint)length + OopsPerHeapWord - 1)/OopsPerHeapWord; #ifdef ASSERT // The old code is left in for sanity-checking; it'll // go away pretty soon. XXX @@ -55,16 +56,15 @@ // oop->length() * HeapWordsPerOop; // With narrowOops, HeapWordsPerOop is 1/2 or equal 0 as an integer. // The oop elements are aligned up to wordSize - const int HeapWordsPerOop = heapOopSize/HeapWordSize; - int old_res; + const uint HeapWordsPerOop = heapOopSize/HeapWordSize; + uint old_res; if (HeapWordsPerOop > 0) { old_res = length * HeapWordsPerOop; } else { - old_res = align_size_up(length, OopsPerHeapWord)/OopsPerHeapWord; + old_res = align_size_up((uint)length, OopsPerHeapWord)/OopsPerHeapWord; } + assert(res == old_res, "Inconsistency between old and new."); #endif // ASSERT - int res = ((uint)length + OopsPerHeapWord - 1)/OopsPerHeapWord; - assert(res == old_res, "Inconsistency between old and new."); return res; }
--- a/src/share/vm/oops/typeArrayOop.hpp Thu Jan 08 12:47:32 2015 +0000 +++ b/src/share/vm/oops/typeArrayOop.hpp Tue Feb 03 16:48:05 2015 +0000 @@ -150,7 +150,7 @@ DEBUG_ONLY(BasicType etype = Klass::layout_helper_element_type(lh)); assert(length <= arrayOopDesc::max_array_length(etype), "no overflow"); - julong size_in_bytes = length; + julong size_in_bytes = (juint)length; size_in_bytes <<= element_shift; size_in_bytes += instance_header_size; julong size_in_words = ((size_in_bytes + (HeapWordSize-1)) >> LogHeapWordSize);
--- a/src/share/vm/opto/c2_globals.hpp Thu Jan 08 12:47:32 2015 +0000 +++ b/src/share/vm/opto/c2_globals.hpp Tue Feb 03 16:48:05 2015 +0000 @@ -476,6 +476,9 @@ product(bool, DoEscapeAnalysis, true, \ "Perform escape analysis") \ \ + product(double, EscapeAnalysisTimeout, 20. DEBUG_ONLY(+40.), \ + "Abort EA when it reaches time limit (in sec)") \ + \ develop(bool, ExitEscapeAnalysisOnTimeout, true, \ "Exit or throw assert in EA when it reaches time limit") \ \ @@ -647,7 +650,7 @@ develop(bool, AlwaysIncrementalInline, false, \ "do all inlining incrementally") \ \ - product(intx, LiveNodeCountInliningCutoff, 20000, \ + product(intx, LiveNodeCountInliningCutoff, 40000, \ "max number of live nodes in a method") \ \ diagnostic(bool, OptimizeExpensiveOps, true, \
--- a/src/share/vm/opto/callGenerator.cpp Thu Jan 08 12:47:32 2015 +0000 +++ b/src/share/vm/opto/callGenerator.cpp Tue Feb 03 16:48:05 2015 +0000 @@ -862,7 +862,7 @@ call_does_dispatch, vtable_index); // out-parameters // We lack profiling at this call but type speculation may // provide us with a type - speculative_receiver_type = receiver_type->speculative_type(); + speculative_receiver_type = (receiver_type != NULL) ? receiver_type->speculative_type() : NULL; } CallGenerator* cg = C->call_generator(target, vtable_index, call_does_dispatch, jvms, true, PROB_ALWAYS, speculative_receiver_type, true, true);
--- a/src/share/vm/opto/coalesce.cpp Thu Jan 08 12:47:32 2015 +0000 +++ b/src/share/vm/opto/coalesce.cpp Tue Feb 03 16:48:05 2015 +0000 @@ -281,9 +281,11 @@ Block *pred = _phc._cfg.get_block_for_node(b->pred(j)); Node *copy; assert(!m->is_Con() || m->is_Mach(), "all Con must be Mach"); - // Rematerialize constants instead of copying them - if( m->is_Mach() && m->as_Mach()->is_Con() && - m->as_Mach()->rematerialize() ) { + // Rematerialize constants instead of copying them. + // We do this only for immediate constants, we avoid constant table loads + // because that will unsafely extend the live range of the constant table base. + if (m->is_Mach() && m->as_Mach()->is_Con() && !m->as_Mach()->is_MachConstant() && + m->as_Mach()->rematerialize()) { copy = m->clone(); // Insert the copy in the predecessor basic block pred->add_inst(copy); @@ -317,8 +319,8 @@ assert(!m->is_Con() || m->is_Mach(), "all Con must be Mach"); // At this point it is unsafe to extend live ranges (6550579). // Rematerialize only constants as we do for Phi above. - if(m->is_Mach() && m->as_Mach()->is_Con() && - m->as_Mach()->rematerialize()) { + if (m->is_Mach() && m->as_Mach()->is_Con() && !m->as_Mach()->is_MachConstant() && + m->as_Mach()->rematerialize()) { copy = m->clone(); // Insert the copy in the basic block, just before us b->insert_node(copy, l++);
--- a/src/share/vm/opto/compile.cpp Thu Jan 08 12:47:32 2015 +0000 +++ b/src/share/vm/opto/compile.cpp Tue Feb 03 16:48:05 2015 +0000 @@ -685,7 +685,8 @@ _inlining_incrementally(false), _print_inlining_list(NULL), _print_inlining_idx(0), - _interpreter_frame_size(0) { + _interpreter_frame_size(0), + _max_node_limit(MaxNodeLimit) { C = this; CompileWrapper cw(this); @@ -1027,7 +1028,8 @@ _print_inlining_list(NULL), _print_inlining_idx(0), _allowed_reasons(0), - _interpreter_frame_size(0) { + _interpreter_frame_size(0), + _max_node_limit(MaxNodeLimit) { C = this; #ifndef PRODUCT @@ -1137,6 +1139,7 @@ set_do_count_invocations(false); set_do_method_data_update(false); set_rtm_state(NoRTM); // No RTM lock eliding by default + method_has_option_value("MaxNodeLimit", _max_node_limit); #if INCLUDE_RTM_OPT if (UseRTMLocking && has_method() && (method()->method_data_or_null() != NULL)) { int rtm_state = method()->method_data()->rtm_state();
--- a/src/share/vm/opto/compile.hpp Thu Jan 08 12:47:32 2015 +0000 +++ b/src/share/vm/opto/compile.hpp Tue Feb 03 16:48:05 2015 +0000 @@ -290,6 +290,7 @@ int _freq_inline_size; // Max hot method inline size for this compilation int _fixed_slots; // count of frame slots not allocated by the register // allocator i.e. locks, original deopt pc, etc. + uintx _max_node_limit; // Max unique node count during a single compilation. // For deopt int _orig_pc_slot; int _orig_pc_slot_offset_in_bytes; @@ -594,6 +595,9 @@ void set_rtm_state(RTMState s) { _rtm_state = s; } bool use_rtm() const { return (_rtm_state & NoRTM) == 0; } bool profile_rtm() const { return _rtm_state == ProfileRTM; } + uint max_node_limit() const { return (uint)_max_node_limit; } + void set_max_node_limit(uint n) { _max_node_limit = n; } + // check the CompilerOracle for special behaviours for this compile bool method_has_option(const char * option) { return method() != NULL && method()->has_option(option); @@ -723,7 +727,7 @@ record_method_not_compilable(reason, true); } bool check_node_count(uint margin, const char* reason) { - if (live_nodes() + margin > (uint)MaxNodeLimit) { + if (live_nodes() + margin > max_node_limit()) { record_method_not_compilable(reason); return true; } else {
--- a/src/share/vm/opto/connode.cpp Thu Jan 08 12:47:32 2015 +0000 +++ b/src/share/vm/opto/connode.cpp Tue Feb 03 16:48:05 2015 +0000 @@ -441,6 +441,102 @@ return this; } +uint CastIINode::size_of() const { + return sizeof(*this); +} + +uint CastIINode::cmp(const Node &n) const { + return TypeNode::cmp(n) && ((CastIINode&)n)._carry_dependency == _carry_dependency; +} + +Node *CastIINode::Identity(PhaseTransform *phase) { + if (_carry_dependency) { + return this; + } + return ConstraintCastNode::Identity(phase); +} + +const Type *CastIINode::Value(PhaseTransform *phase) const { + const Type *res = ConstraintCastNode::Value(phase); + + // Try to improve the type of the CastII if we recognize a CmpI/If + // pattern. + if (_carry_dependency) { + if (in(0) != NULL && in(0)->in(0) != NULL && in(0)->in(0)->is_If()) { + assert(in(0)->is_IfFalse() || in(0)->is_IfTrue(), "should be If proj"); + Node* proj = in(0); + if (proj->in(0)->in(1)->is_Bool()) { + Node* b = proj->in(0)->in(1); + if (b->in(1)->Opcode() == Op_CmpI) { + Node* cmp = b->in(1); + if (cmp->in(1) == in(1) && phase->type(cmp->in(2))->isa_int()) { + const TypeInt* in2_t = phase->type(cmp->in(2))->is_int(); + const Type* t = TypeInt::INT; + BoolTest test = b->as_Bool()->_test; + if (proj->is_IfFalse()) { + test = test.negate(); + } + BoolTest::mask m = test._test; + jlong lo_long = min_jint; + jlong hi_long = max_jint; + if (m == BoolTest::le || m == BoolTest::lt) { + hi_long = in2_t->_hi; + if (m == BoolTest::lt) { + hi_long -= 1; + } + } else if (m == BoolTest::ge || m == BoolTest::gt) { + lo_long = in2_t->_lo; + if (m == BoolTest::gt) { + lo_long += 1; + } + } else if (m == BoolTest::eq) { + lo_long = in2_t->_lo; + hi_long = in2_t->_hi; + } else if (m == BoolTest::ne) { + // can't do any better + } else { + stringStream ss; + test.dump_on(&ss); + fatal(err_msg_res("unexpected comparison %s", ss.as_string())); + } + int lo_int = (int)lo_long; + int hi_int = (int)hi_long; + + if (lo_long != (jlong)lo_int) { + lo_int = min_jint; + } + if (hi_long != (jlong)hi_int) { + hi_int = max_jint; + } + + t = TypeInt::make(lo_int, hi_int, Type::WidenMax); + + res = res->filter_speculative(t); + + return res; + } + } + } + } + } + return res; +} + +Node *CastIINode::Ideal_DU_postCCP(PhaseCCP *ccp) { + if (_carry_dependency) { + return NULL; + } + return ConstraintCastNode::Ideal_DU_postCCP(ccp); +} + +#ifndef PRODUCT +void CastIINode::dump_spec(outputStream *st) const { + TypeNode::dump_spec(st); + if (_carry_dependency) { + st->print(" carry dependency"); + } +} +#endif //=============================================================================
--- a/src/share/vm/opto/connode.hpp Thu Jan 08 12:47:32 2015 +0000 +++ b/src/share/vm/opto/connode.hpp Tue Feb 03 16:48:05 2015 +0000 @@ -241,10 +241,25 @@ //------------------------------CastIINode------------------------------------- // cast integer to integer (different range) class CastIINode: public ConstraintCastNode { + private: + // Can this node be removed post CCP or does it carry a required dependency? + const bool _carry_dependency; + + protected: + virtual uint cmp( const Node &n ) const; + virtual uint size_of() const; + public: - CastIINode (Node *n, const Type *t ): ConstraintCastNode(n,t) {} + CastIINode(Node *n, const Type *t, bool carry_dependency = false) + : ConstraintCastNode(n,t), _carry_dependency(carry_dependency) {} virtual int Opcode() const; virtual uint ideal_reg() const { return Op_RegI; } + virtual Node *Identity( PhaseTransform *phase ); + virtual const Type *Value( PhaseTransform *phase ) const; + virtual Node *Ideal_DU_postCCP( PhaseCCP * ); +#ifndef PRODUCT + virtual void dump_spec(outputStream *st) const; +#endif }; //------------------------------CastPPNode-------------------------------------
--- a/src/share/vm/opto/doCall.cpp Thu Jan 08 12:47:32 2015 +0000 +++ b/src/share/vm/opto/doCall.cpp Tue Feb 03 16:48:05 2015 +0000 @@ -410,6 +410,11 @@ ciInstanceKlass* klass = ciEnv::get_instance_klass_for_declared_method_holder(holder); assert(declared_signature != NULL, "cannot be null"); + // Bump max node limit for JSR292 users + if (bc() == Bytecodes::_invokedynamic || orig_callee->is_method_handle_intrinsic()) { + C->set_max_node_limit(3*MaxNodeLimit); + } + // uncommon-trap when callee is unloaded, uninitialized or will not link // bailout when too many arguments for register representation if (!will_link || can_not_compile_call_site(orig_callee, klass)) { @@ -791,7 +796,7 @@ Node* ex_klass_node = NULL; if (has_ex_handler() && !ex_type->klass_is_exact()) { Node* p = basic_plus_adr( ex_node, ex_node, oopDesc::klass_offset_in_bytes()); - ex_klass_node = _gvn.transform( LoadKlassNode::make(_gvn, immutable_memory(), p, TypeInstPtr::KLASS, TypeKlassPtr::OBJECT) ); + ex_klass_node = _gvn.transform(LoadKlassNode::make(_gvn, NULL, immutable_memory(), p, TypeInstPtr::KLASS, TypeKlassPtr::OBJECT)); // Compute the exception klass a little more cleverly. // Obvious solution is to simple do a LoadKlass from the 'ex_node'. @@ -809,7 +814,7 @@ continue; } Node* p = basic_plus_adr(ex_in, ex_in, oopDesc::klass_offset_in_bytes()); - Node* k = _gvn.transform( LoadKlassNode::make(_gvn, immutable_memory(), p, TypeInstPtr::KLASS, TypeKlassPtr::OBJECT) ); + Node* k = _gvn.transform(LoadKlassNode::make(_gvn, NULL, immutable_memory(), p, TypeInstPtr::KLASS, TypeKlassPtr::OBJECT)); ex_klass_node->init_req( i, k ); } _gvn.set_type(ex_klass_node, TypeKlassPtr::OBJECT);
--- a/src/share/vm/opto/escape.cpp Thu Jan 08 12:47:32 2015 +0000 +++ b/src/share/vm/opto/escape.cpp Tue Feb 03 16:48:05 2015 +0000 @@ -37,6 +37,8 @@ ConnectionGraph::ConnectionGraph(Compile * C, PhaseIterGVN *igvn) : _nodes(C->comp_arena(), C->unique(), C->unique(), NULL), + _in_worklist(C->comp_arena()), + _next_pidx(0), _collecting(true), _verify(false), _compile(C), @@ -124,13 +126,19 @@ if (C->root() != NULL) { ideal_nodes.push(C->root()); } + // Processed ideal nodes are unique on ideal_nodes list + // but several ideal nodes are mapped to the phantom_obj. + // To avoid duplicated entries on the following worklists + // add the phantom_obj only once to them. + ptnodes_worklist.append(phantom_obj); + java_objects_worklist.append(phantom_obj); for( uint next = 0; next < ideal_nodes.size(); ++next ) { Node* n = ideal_nodes.at(next); // Create PointsTo nodes and add them to Connection Graph. Called // only once per ideal node since ideal_nodes is Unique_Node list. add_node_to_connection_graph(n, &delayed_worklist); PointsToNode* ptn = ptnode_adr(n->_idx); - if (ptn != NULL) { + if (ptn != NULL && ptn != phantom_obj) { ptnodes_worklist.append(ptn); if (ptn->is_JavaObject()) { java_objects_worklist.append(ptn->as_JavaObject()); @@ -414,7 +422,7 @@ } case Op_CreateEx: { // assume that all exception objects globally escape - add_java_object(n, PointsToNode::GlobalEscape); + map_ideal_node(n, phantom_obj); break; } case Op_LoadKlass: @@ -1065,13 +1073,8 @@ // on graph complexity. Observed 8 passes in jvm2008 compiler.compiler. // Set limit to 20 to catch situation when something did go wrong and // bailout Escape Analysis. - // Also limit build time to 30 sec (60 in debug VM). + // Also limit build time to 20 sec (60 in debug VM), EscapeAnalysisTimeout flag. #define CG_BUILD_ITER_LIMIT 20 -#ifdef ASSERT -#define CG_BUILD_TIME_LIMIT 60.0 -#else -#define CG_BUILD_TIME_LIMIT 30.0 -#endif // Propagate GlobalEscape and ArgEscape escape states and check that // we still have non-escaping objects. The method pushs on _worklist @@ -1082,12 +1085,13 @@ // Now propagate references to all JavaObject nodes. int java_objects_length = java_objects_worklist.length(); elapsedTimer time; + bool timeout = false; int new_edges = 1; int iterations = 0; do { while ((new_edges > 0) && - (iterations++ < CG_BUILD_ITER_LIMIT) && - (time.seconds() < CG_BUILD_TIME_LIMIT)) { + (iterations++ < CG_BUILD_ITER_LIMIT)) { + double start_time = time.seconds(); time.start(); new_edges = 0; // Propagate references to phantom_object for nodes pushed on _worklist @@ -1096,7 +1100,29 @@ for (int next = 0; next < java_objects_length; ++next) { JavaObjectNode* ptn = java_objects_worklist.at(next); new_edges += add_java_object_edges(ptn, true); + +#define SAMPLE_SIZE 4 + if ((next % SAMPLE_SIZE) == 0) { + // Each 4 iterations calculate how much time it will take + // to complete graph construction. + time.stop(); + // Poll for requests from shutdown mechanism to quiesce compiler + // because Connection graph construction may take long time. + CompileBroker::maybe_block(); + double stop_time = time.seconds(); + double time_per_iter = (stop_time - start_time) / (double)SAMPLE_SIZE; + double time_until_end = time_per_iter * (double)(java_objects_length - next); + if ((start_time + time_until_end) >= EscapeAnalysisTimeout) { + timeout = true; + break; // Timeout + } + start_time = stop_time; + time.start(); + } +#undef SAMPLE_SIZE + } + if (timeout) break; if (new_edges > 0) { // Update escape states on each iteration if graph was updated. if (!find_non_escaped_objects(ptnodes_worklist, non_escaped_worklist)) { @@ -1104,9 +1130,12 @@ } } time.stop(); + if (time.seconds() >= EscapeAnalysisTimeout) { + timeout = true; + break; + } } - if ((iterations < CG_BUILD_ITER_LIMIT) && - (time.seconds() < CG_BUILD_TIME_LIMIT)) { + if ((iterations < CG_BUILD_ITER_LIMIT) && !timeout) { time.start(); // Find fields which have unknown value. int fields_length = oop_fields_worklist.length(); @@ -1119,18 +1148,21 @@ } } time.stop(); + if (time.seconds() >= EscapeAnalysisTimeout) { + timeout = true; + break; + } } else { new_edges = 0; // Bailout } } while (new_edges > 0); // Bailout if passed limits. - if ((iterations >= CG_BUILD_ITER_LIMIT) || - (time.seconds() >= CG_BUILD_TIME_LIMIT)) { + if ((iterations >= CG_BUILD_ITER_LIMIT) || timeout) { Compile* C = _compile; if (C->log() != NULL) { C->log()->begin_elem("connectionGraph_bailout reason='reached "); - C->log()->text("%s", (iterations >= CG_BUILD_ITER_LIMIT) ? "iterations" : "time"); + C->log()->text("%s", timeout ? "time" : "iterations"); C->log()->end_elem(" limit'"); } assert(ExitEscapeAnalysisOnTimeout, err_msg_res("infinite EA connection graph build (%f sec, %d iterations) with %d nodes and worklist size %d", @@ -1147,7 +1179,6 @@ #endif #undef CG_BUILD_ITER_LIMIT -#undef CG_BUILD_TIME_LIMIT // Find fields initialized by NULL for non-escaping Allocations. int non_escaped_length = non_escaped_worklist.length(); @@ -1271,8 +1302,8 @@ } } } - while(_worklist.length() > 0) { - PointsToNode* use = _worklist.pop(); + for (int l = 0; l < _worklist.length(); l++) { + PointsToNode* use = _worklist.at(l); if (PointsToNode::is_base_use(use)) { // Add reference from jobj to field and from field to jobj (field's base). use = PointsToNode::get_use_node(use)->as_Field(); @@ -1319,6 +1350,8 @@ add_field_uses_to_worklist(use->as_Field()); } } + _worklist.clear(); + _in_worklist.Reset(); return new_edges; } @@ -1898,7 +1931,7 @@ return; } Compile* C = _compile; - ptadr = new (C->comp_arena()) LocalVarNode(C, n, es); + ptadr = new (C->comp_arena()) LocalVarNode(this, n, es); _nodes.at_put(n->_idx, ptadr); } @@ -1909,7 +1942,7 @@ return; } Compile* C = _compile; - ptadr = new (C->comp_arena()) JavaObjectNode(C, n, es); + ptadr = new (C->comp_arena()) JavaObjectNode(this, n, es); _nodes.at_put(n->_idx, ptadr); } @@ -1925,7 +1958,7 @@ es = PointsToNode::GlobalEscape; } Compile* C = _compile; - FieldNode* field = new (C->comp_arena()) FieldNode(C, n, es, offset, is_oop); + FieldNode* field = new (C->comp_arena()) FieldNode(this, n, es, offset, is_oop); _nodes.at_put(n->_idx, field); } @@ -1939,7 +1972,7 @@ return; } Compile* C = _compile; - ptadr = new (C->comp_arena()) ArraycopyNode(C, n, es); + ptadr = new (C->comp_arena()) ArraycopyNode(this, n, es); _nodes.at_put(n->_idx, ptadr); // Add edge from arraycopy node to source object. (void)add_edge(ptadr, src); @@ -2379,7 +2412,7 @@ } } } - if ((int) (C->live_nodes() + 2*NodeLimitFudgeFactor) > MaxNodeLimit) { + if (C->live_nodes() + 2*NodeLimitFudgeFactor > C->max_node_limit()) { if (C->do_escape_analysis() == true && !C->failing()) { // Retry compilation without escape analysis. // If this is the first failure, the sentinel string will "stick" @@ -2839,6 +2872,13 @@ continue; } } + + const TypeOopPtr *t = igvn->type(n)->isa_oopptr(); + if (t == NULL) + continue; // not a TypeOopPtr + if (!t->klass_is_exact()) + continue; // not an unique type + if (alloc->is_Allocate()) { // Set the scalar_replaceable flag for allocation // so it could be eliminated. @@ -2857,10 +2897,7 @@ // - not determined to be ineligible by escape analysis set_map(alloc, n); set_map(n, alloc); - const TypeOopPtr *t = igvn->type(n)->isa_oopptr(); - if (t == NULL) - continue; // not a TypeOopPtr - const TypeOopPtr* tinst = t->cast_to_exactness(true)->is_oopptr()->cast_to_instance_id(ni); + const TypeOopPtr* tinst = t->cast_to_instance_id(ni); igvn->hash_delete(n); igvn->set_type(n, tinst); n->raise_bottom_type(tinst);
--- a/src/share/vm/opto/escape.hpp Thu Jan 08 12:47:32 2015 +0000 +++ b/src/share/vm/opto/escape.hpp Tue Feb 03 16:48:05 2015 +0000 @@ -125,6 +125,8 @@ class FieldNode; class ArraycopyNode; +class ConnectionGraph; + // ConnectionGraph nodes class PointsToNode : public ResourceObj { GrowableArray<PointsToNode*> _edges; // List of nodes this node points to @@ -137,6 +139,7 @@ Node* const _node; // Ideal node corresponding to this PointsTo node. const int _idx; // Cached ideal node's _idx + const uint _pidx; // Index of this node public: typedef enum { @@ -165,17 +168,9 @@ } NodeFlags; - PointsToNode(Compile *C, Node* n, EscapeState es, NodeType type): - _edges(C->comp_arena(), 2, 0, NULL), - _uses (C->comp_arena(), 2, 0, NULL), - _node(n), - _idx(n->_idx), - _type((u1)type), - _escape((u1)es), - _fields_escape((u1)es), - _flags(ScalarReplaceable) { - assert(n != NULL && es != UnknownEscape, "sanity"); - } + inline PointsToNode(ConnectionGraph* CG, Node* n, EscapeState es, NodeType type); + + uint pidx() const { return _pidx; } Node* ideal_node() const { return _node; } int idx() const { return _idx; } @@ -243,14 +238,14 @@ class LocalVarNode: public PointsToNode { public: - LocalVarNode(Compile *C, Node* n, EscapeState es): - PointsToNode(C, n, es, LocalVar) {} + LocalVarNode(ConnectionGraph *CG, Node* n, EscapeState es): + PointsToNode(CG, n, es, LocalVar) {} }; class JavaObjectNode: public PointsToNode { public: - JavaObjectNode(Compile *C, Node* n, EscapeState es): - PointsToNode(C, n, es, JavaObject) { + JavaObjectNode(ConnectionGraph *CG, Node* n, EscapeState es): + PointsToNode(CG, n, es, JavaObject) { if (es > NoEscape) set_scalar_replaceable(false); } @@ -262,8 +257,8 @@ const bool _is_oop; // Field points to object bool _has_unknown_base; // Has phantom_object base public: - FieldNode(Compile *C, Node* n, EscapeState es, int offs, bool is_oop): - PointsToNode(C, n, es, Field), + FieldNode(ConnectionGraph *CG, Node* n, EscapeState es, int offs, bool is_oop): + PointsToNode(CG, n, es, Field), _offset(offs), _is_oop(is_oop), _has_unknown_base(false) {} @@ -284,8 +279,8 @@ class ArraycopyNode: public PointsToNode { public: - ArraycopyNode(Compile *C, Node* n, EscapeState es): - PointsToNode(C, n, es, Arraycopy) {} + ArraycopyNode(ConnectionGraph *CG, Node* n, EscapeState es): + PointsToNode(CG, n, es, Arraycopy) {} }; // Iterators for PointsTo node's edges: @@ -323,11 +318,14 @@ class ConnectionGraph: public ResourceObj { + friend class PointsToNode; private: GrowableArray<PointsToNode*> _nodes; // Map from ideal nodes to // ConnectionGraph nodes. GrowableArray<PointsToNode*> _worklist; // Nodes to be processed + VectorSet _in_worklist; + uint _next_pidx; bool _collecting; // Indicates whether escape information // is still being collected. If false, @@ -353,6 +351,8 @@ } uint nodes_size() const { return _nodes.length(); } + uint next_pidx() { return _next_pidx++; } + // Add nodes to ConnectionGraph. void add_local_var(Node* n, PointsToNode::EscapeState es); void add_java_object(Node* n, PointsToNode::EscapeState es); @@ -396,15 +396,26 @@ int add_java_object_edges(JavaObjectNode* jobj, bool populate_worklist); // Put node on worklist if it is (or was) not there. - void add_to_worklist(PointsToNode* pt) { - _worklist.push(pt); - return; + inline void add_to_worklist(PointsToNode* pt) { + PointsToNode* ptf = pt; + uint pidx_bias = 0; + if (PointsToNode::is_base_use(pt)) { + // Create a separate entry in _in_worklist for a marked base edge + // because _worklist may have an entry for a normal edge pointing + // to the same node. To separate them use _next_pidx as bias. + ptf = PointsToNode::get_use_node(pt)->as_Field(); + pidx_bias = _next_pidx; + } + if (!_in_worklist.test_set(ptf->pidx() + pidx_bias)) { + _worklist.append(pt); + } } // Put on worklist all uses of this node. - void add_uses_to_worklist(PointsToNode* pt) { - for (UseIterator i(pt); i.has_next(); i.next()) - _worklist.push(i.get()); + inline void add_uses_to_worklist(PointsToNode* pt) { + for (UseIterator i(pt); i.has_next(); i.next()) { + add_to_worklist(i.get()); + } } // Put on worklist all field's uses and related field nodes. @@ -517,8 +528,8 @@ } // Helper functions bool is_oop_field(Node* n, int offset, bool* unsafe); - static Node* get_addp_base(Node *addp); - static Node* find_second_addp(Node* addp, Node* n); + static Node* get_addp_base(Node *addp); + static Node* find_second_addp(Node* addp, Node* n); // offset of a field reference int address_offset(Node* adr, PhaseTransform *phase); @@ -587,4 +598,17 @@ #endif }; +inline PointsToNode::PointsToNode(ConnectionGraph *CG, Node* n, EscapeState es, NodeType type): + _edges(CG->_compile->comp_arena(), 2, 0, NULL), + _uses (CG->_compile->comp_arena(), 2, 0, NULL), + _node(n), + _idx(n->_idx), + _pidx(CG->next_pidx()), + _type((u1)type), + _escape((u1)es), + _fields_escape((u1)es), + _flags(ScalarReplaceable) { + assert(n != NULL && es != UnknownEscape, "sanity"); +} + #endif // SHARE_VM_OPTO_ESCAPE_HPP
--- a/src/share/vm/opto/graphKit.cpp Thu Jan 08 12:47:32 2015 +0000 +++ b/src/share/vm/opto/graphKit.cpp Tue Feb 03 16:48:05 2015 +0000 @@ -1150,7 +1150,7 @@ Node* akls = AllocateNode::Ideal_klass(obj, &_gvn); if (akls != NULL) return akls; Node* k_adr = basic_plus_adr(obj, oopDesc::klass_offset_in_bytes()); - return _gvn.transform( LoadKlassNode::make(_gvn, immutable_memory(), k_adr, TypeInstPtr::KLASS) ); + return _gvn.transform(LoadKlassNode::make(_gvn, NULL, immutable_memory(), k_adr, TypeInstPtr::KLASS)); } //-------------------------load_array_length----------------------------------- @@ -2542,7 +2542,7 @@ // cache which is mutable so can't use immutable memory. Other // types load from the super-class display table which is immutable. Node *kmem = might_be_cache ? memory(p2) : immutable_memory(); - Node *nkls = _gvn.transform( LoadKlassNode::make( _gvn, kmem, p2, _gvn.type(p2)->is_ptr(), TypeKlassPtr::OBJECT_OR_NULL ) ); + Node* nkls = _gvn.transform(LoadKlassNode::make(_gvn, NULL, kmem, p2, _gvn.type(p2)->is_ptr(), TypeKlassPtr::OBJECT_OR_NULL)); // Compile speed common case: ARE a subtype and we canNOT fail if( superklass == nkls )
--- a/src/share/vm/opto/ifg.cpp Thu Jan 08 12:47:32 2015 +0000 +++ b/src/share/vm/opto/ifg.cpp Tue Feb 03 16:48:05 2015 +0000 @@ -541,17 +541,37 @@ if( !n->is_Proj() || // Could also be a flags-projection of a dead ADD or such. (_lrg_map.live_range_id(def) && !liveout.member(_lrg_map.live_range_id(def)))) { - block->remove_node(j - 1); - if (lrgs(r)._def == n) { - lrgs(r)._def = 0; + bool remove = true; + if (n->is_MachProj()) { + // Don't remove KILL projections if their "defining" nodes have + // memory effects (have SCMemProj projection node) - + // they are not dead even when their result is not used. + // For example, compareAndSwapL (and other CAS) and EncodeISOArray nodes. + // The method add_input_to_liveout() keeps such nodes alive (put them on liveout list) + // when it sees SCMemProj node in a block. Unfortunately SCMemProj node could be placed + // in block in such order that KILL MachProj nodes are processed first. + uint cnt = def->outcnt(); + for (uint i = 0; i < cnt; i++) { + Node* proj = def->raw_out(i); + if (proj->Opcode() == Op_SCMemProj) { + remove = false; + break; + } + } } - n->disconnect_inputs(NULL, C); - _cfg.unmap_node_from_block(n); - n->replace_by(C->top()); - // Since yanking a Node from block, high pressure moves up one - hrp_index[0]--; - hrp_index[1]--; - continue; + if (remove) { + block->remove_node(j - 1); + if (lrgs(r)._def == n) { + lrgs(r)._def = 0; + } + n->disconnect_inputs(NULL, C); + _cfg.unmap_node_from_block(n); + n->replace_by(C->top()); + // Since yanking a Node from block, high pressure moves up one + hrp_index[0]--; + hrp_index[1]--; + continue; + } } // Fat-projections kill many registers which cannot be used to
--- a/src/share/vm/opto/ifnode.cpp Thu Jan 08 12:47:32 2015 +0000 +++ b/src/share/vm/opto/ifnode.cpp Tue Feb 03 16:48:05 2015 +0000 @@ -820,6 +820,11 @@ static IfNode* idealize_test(PhaseGVN* phase, IfNode* iff); +struct RangeCheck { + Node* ctl; + jint off; +}; + //------------------------------Ideal------------------------------------------ // Return a node which is more "ideal" than the current node. Strip out // control copies @@ -861,83 +866,141 @@ jint offset1; int flip1 = is_range_check(range1, index1, offset1); if( flip1 ) { - Node *first_prev_dom = NULL; - // Try to remove extra range checks. All 'up_one_dom' gives up at merges // so all checks we inspect post-dominate the top-most check we find. // If we are going to fail the current check and we reach the top check // then we are guaranteed to fail, so just start interpreting there. - // We 'expand' the top 2 range checks to include all post-dominating + // We 'expand' the top 3 range checks to include all post-dominating // checks. - // The top 2 range checks seen - Node *prev_chk1 = NULL; - Node *prev_chk2 = NULL; + // The top 3 range checks seen + const int NRC =3; + RangeCheck prev_checks[NRC]; + int nb_checks = 0; + // Low and high offsets seen so far jint off_lo = offset1; jint off_hi = offset1; - // Scan for the top 2 checks and collect range of offsets - for( int dist = 0; dist < 999; dist++ ) { // Range-Check scan limit - if( dom->Opcode() == Op_If && // Not same opcode? - prev_dom->in(0) == dom ) { // One path of test does dominate? - if( dom == this ) return NULL; // dead loop + bool found_immediate_dominator = false; + + // Scan for the top checks and collect range of offsets + for (int dist = 0; dist < 999; dist++) { // Range-Check scan limit + if (dom->Opcode() == Op_If && // Not same opcode? + prev_dom->in(0) == dom) { // One path of test does dominate? + if (dom == this) return NULL; // dead loop // See if this is a range check Node *index2, *range2; jint offset2; int flip2 = dom->as_If()->is_range_check(range2, index2, offset2); // See if this is a _matching_ range check, checking against // the same array bounds. - if( flip2 == flip1 && range2 == range1 && index2 == index1 && - dom->outcnt() == 2 ) { + if (flip2 == flip1 && range2 == range1 && index2 == index1 && + dom->outcnt() == 2) { + if (nb_checks == 0 && dom->in(1) == in(1)) { + // Found an immediately dominating test at the same offset. + // This kind of back-to-back test can be eliminated locally, + // and there is no need to search further for dominating tests. + assert(offset2 == offset1, "Same test but different offsets"); + found_immediate_dominator = true; + break; + } // Gather expanded bounds off_lo = MIN2(off_lo,offset2); off_hi = MAX2(off_hi,offset2); - // Record top 2 range checks - prev_chk2 = prev_chk1; - prev_chk1 = prev_dom; - // If we match the test exactly, then the top test covers - // both our lower and upper bounds. - if( dom->in(1) == in(1) ) - prev_chk2 = prev_chk1; + // Record top NRC range checks + prev_checks[nb_checks%NRC].ctl = prev_dom; + prev_checks[nb_checks%NRC].off = offset2; + nb_checks++; } } prev_dom = dom; - dom = up_one_dom( dom ); - if( !dom ) break; + dom = up_one_dom(dom); + if (!dom) break; } - - // Attempt to widen the dominating range check to cover some later - // ones. Since range checks "fail" by uncommon-trapping to the - // interpreter, widening a check can make us speculative enter the - // interpreter. If we see range-check deopt's, do not widen! - if (!phase->C->allow_range_check_smearing()) return NULL; + if (!found_immediate_dominator) { + // Attempt to widen the dominating range check to cover some later + // ones. Since range checks "fail" by uncommon-trapping to the + // interpreter, widening a check can make us speculatively enter + // the interpreter. If we see range-check deopt's, do not widen! + if (!phase->C->allow_range_check_smearing()) return NULL; - // Constant indices only need to check the upper bound. - // Non-constance indices must check both low and high. - if( index1 ) { - // Didn't find 2 prior covering checks, so cannot remove anything. - if( !prev_chk2 ) return NULL; - // 'Widen' the offsets of the 1st and 2nd covering check - adjust_check( prev_chk1, range1, index1, flip1, off_lo, igvn ); - // Do not call adjust_check twice on the same projection - // as the first call may have transformed the BoolNode to a ConI - if( prev_chk1 != prev_chk2 ) { - adjust_check( prev_chk2, range1, index1, flip1, off_hi, igvn ); + // Didn't find prior covering check, so cannot remove anything. + if (nb_checks == 0) { + return NULL; } - // Test is now covered by prior checks, dominate it out - prev_dom = prev_chk2; - } else { - // Didn't find prior covering check, so cannot remove anything. - if( !prev_chk1 ) return NULL; - // 'Widen' the offset of the 1st and only covering check - adjust_check( prev_chk1, range1, index1, flip1, off_hi, igvn ); - // Test is now covered by prior checks, dominate it out - prev_dom = prev_chk1; + // Constant indices only need to check the upper bound. + // Non-constant indices must check both low and high. + int chk0 = (nb_checks - 1) % NRC; + if (index1) { + if (nb_checks == 1) { + return NULL; + } else { + // If the top range check's constant is the min or max of + // all constants we widen the next one to cover the whole + // range of constants. + RangeCheck rc0 = prev_checks[chk0]; + int chk1 = (nb_checks - 2) % NRC; + RangeCheck rc1 = prev_checks[chk1]; + if (rc0.off == off_lo) { + adjust_check(rc1.ctl, range1, index1, flip1, off_hi, igvn); + prev_dom = rc1.ctl; + } else if (rc0.off == off_hi) { + adjust_check(rc1.ctl, range1, index1, flip1, off_lo, igvn); + prev_dom = rc1.ctl; + } else { + // If the top test's constant is not the min or max of all + // constants, we need 3 range checks. We must leave the + // top test unchanged because widening it would allow the + // accesses it protects to successfully read/write out of + // bounds. + if (nb_checks == 2) { + return NULL; + } + int chk2 = (nb_checks - 3) % NRC; + RangeCheck rc2 = prev_checks[chk2]; + // The top range check a+i covers interval: -a <= i < length-a + // The second range check b+i covers interval: -b <= i < length-b + if (rc1.off <= rc0.off) { + // if b <= a, we change the second range check to: + // -min_of_all_constants <= i < length-min_of_all_constants + // Together top and second range checks now cover: + // -min_of_all_constants <= i < length-a + // which is more restrictive than -b <= i < length-b: + // -b <= -min_of_all_constants <= i < length-a <= length-b + // The third check is then changed to: + // -max_of_all_constants <= i < length-max_of_all_constants + // so 2nd and 3rd checks restrict allowed values of i to: + // -min_of_all_constants <= i < length-max_of_all_constants + adjust_check(rc1.ctl, range1, index1, flip1, off_lo, igvn); + adjust_check(rc2.ctl, range1, index1, flip1, off_hi, igvn); + } else { + // if b > a, we change the second range check to: + // -max_of_all_constants <= i < length-max_of_all_constants + // Together top and second range checks now cover: + // -a <= i < length-max_of_all_constants + // which is more restrictive than -b <= i < length-b: + // -b < -a <= i < length-max_of_all_constants <= length-b + // The third check is then changed to: + // -max_of_all_constants <= i < length-max_of_all_constants + // so 2nd and 3rd checks restrict allowed values of i to: + // -min_of_all_constants <= i < length-max_of_all_constants + adjust_check(rc1.ctl, range1, index1, flip1, off_hi, igvn); + adjust_check(rc2.ctl, range1, index1, flip1, off_lo, igvn); + } + prev_dom = rc2.ctl; + } + } + } else { + RangeCheck rc0 = prev_checks[chk0]; + // 'Widen' the offset of the 1st and only covering check + adjust_check(rc0.ctl, range1, index1, flip1, off_hi, igvn); + // Test is now covered by prior checks, dominate it out + prev_dom = rc0.ctl; + } } - } else { // Scan for an equivalent test Node *cmp; @@ -1019,7 +1082,7 @@ // for lower and upper bounds. ProjNode* unc_proj = proj_out(1 - prev_dom->as_Proj()->_con)->as_Proj(); if (unc_proj->is_uncommon_trap_proj(Deoptimization::Reason_predicate)) - prev_dom = idom; + prev_dom = idom; // Now walk the current IfNode's projections. // Loop ends when 'this' has no more uses.
--- a/src/share/vm/opto/lcm.cpp Thu Jan 08 12:47:32 2015 +0000 +++ b/src/share/vm/opto/lcm.cpp Tue Feb 03 16:48:05 2015 +0000 @@ -487,9 +487,7 @@ iop == Op_CreateEx || // Create-exception must start block iop == Op_CheckCastPP ) { - // select the node n - // remove n from worklist and retain the order of remaining nodes - worklist.remove((uint)i); + worklist.map(i,worklist.pop()); return n; } @@ -575,9 +573,7 @@ assert(idx >= 0, "index should be set"); Node *n = worklist[(uint)idx]; // Get the winner - // select the node n - // remove n from worklist and retain the order of remaining nodes - worklist.remove((uint)idx); + worklist.map((uint)idx, worklist.pop()); // Compress worklist return n; }
--- a/src/share/vm/opto/library_call.cpp Thu Jan 08 12:47:32 2015 +0000 +++ b/src/share/vm/opto/library_call.cpp Tue Feb 03 16:48:05 2015 +0000 @@ -3398,7 +3398,7 @@ if (region == NULL) never_see_null = true; Node* p = basic_plus_adr(mirror, offset); const TypeKlassPtr* kls_type = TypeKlassPtr::OBJECT_OR_NULL; - Node* kls = _gvn.transform( LoadKlassNode::make(_gvn, immutable_memory(), p, TypeRawPtr::BOTTOM, kls_type)); + Node* kls = _gvn.transform(LoadKlassNode::make(_gvn, NULL, immutable_memory(), p, TypeRawPtr::BOTTOM, kls_type)); Node* null_ctl = top(); kls = null_check_oop(kls, &null_ctl, never_see_null); if (region != NULL) { @@ -3574,7 +3574,7 @@ phi->add_req(makecon(TypeInstPtr::make(env()->Object_klass()->java_mirror()))); // If we fall through, it's a plain class. Get its _super. p = basic_plus_adr(kls, in_bytes(Klass::super_offset())); - kls = _gvn.transform( LoadKlassNode::make(_gvn, immutable_memory(), p, TypeRawPtr::BOTTOM, TypeKlassPtr::OBJECT_OR_NULL)); + kls = _gvn.transform(LoadKlassNode::make(_gvn, NULL, immutable_memory(), p, TypeRawPtr::BOTTOM, TypeKlassPtr::OBJECT_OR_NULL)); null_ctl = top(); kls = null_check_oop(kls, &null_ctl); if (null_ctl != top()) { @@ -3656,7 +3656,7 @@ args[which_arg] = arg; Node* p = basic_plus_adr(arg, class_klass_offset); - Node* kls = LoadKlassNode::make(_gvn, immutable_memory(), p, adr_type, kls_type); + Node* kls = LoadKlassNode::make(_gvn, NULL, immutable_memory(), p, adr_type, kls_type); klasses[which_arg] = _gvn.transform(kls); } @@ -5172,7 +5172,7 @@ // (At this point we can assume disjoint_bases, since types differ.) int ek_offset = in_bytes(ObjArrayKlass::element_klass_offset()); Node* p1 = basic_plus_adr(dest_klass, ek_offset); - Node* n1 = LoadKlassNode::make(_gvn, immutable_memory(), p1, TypeRawPtr::BOTTOM); + Node* n1 = LoadKlassNode::make(_gvn, NULL, immutable_memory(), p1, TypeRawPtr::BOTTOM); Node* dest_elem_klass = _gvn.transform(n1); Node* cv = generate_checkcast_arraycopy(adr_type, dest_elem_klass,
--- a/src/share/vm/opto/loopTransform.cpp Thu Jan 08 12:47:32 2015 +0000 +++ b/src/share/vm/opto/loopTransform.cpp Tue Feb 03 16:48:05 2015 +0000 @@ -269,10 +269,9 @@ bool IdealLoopTree::policy_peeling( PhaseIdealLoop *phase ) const { Node *test = ((IdealLoopTree*)this)->tail(); int body_size = ((IdealLoopTree*)this)->_body.size(); - int live_node_count = phase->C->live_nodes(); // Peeling does loop cloning which can result in O(N^2) node construction if( body_size > 255 /* Prevent overflow for large body_size */ - || (body_size * body_size + live_node_count > MaxNodeLimit) ) { + || (body_size * body_size + phase->C->live_nodes()) > phase->C->max_node_limit() ) { return false; // too large to safely clone } while( test != _head ) { // Scan till run off top of loop @@ -601,7 +600,7 @@ return false; if (new_body_size > unroll_limit || // Unrolling can result in a large amount of node construction - new_body_size >= MaxNodeLimit - (uint) phase->C->live_nodes()) { + new_body_size >= phase->C->max_node_limit() - phase->C->live_nodes()) { return false; } @@ -882,6 +881,20 @@ return n; } +bool PhaseIdealLoop::cast_incr_before_loop(Node* incr, Node* ctrl, Node* loop) { + Node* castii = new (C) CastIINode(incr, TypeInt::INT, true); + castii->set_req(0, ctrl); + register_new_node(castii, ctrl); + for (DUIterator_Fast imax, i = incr->fast_outs(imax); i < imax; i++) { + Node* n = incr->fast_out(i); + if (n->is_Phi() && n->in(0) == loop) { + int nrep = n->replace_edge(incr, castii); + return true; + } + } + return false; +} + //------------------------------insert_pre_post_loops-------------------------- // Insert pre and post loops. If peel_only is set, the pre-loop can not have // more iterations added. It acts as a 'peel' only, no lower-bound RCE, no @@ -1080,6 +1093,24 @@ } } + // Nodes inside the loop may be control dependent on a predicate + // that was moved before the preloop. If the back branch of the main + // or post loops becomes dead, those nodes won't be dependent on the + // test that guards that loop nest anymore which could lead to an + // incorrect array access because it executes independently of the + // test that was guarding the loop nest. We add a special CastII on + // the if branch that enters the loop, between the input induction + // variable value and the induction variable Phi to preserve correct + // dependencies. + + // CastII for the post loop: + bool inserted = cast_incr_before_loop(zer_opaq->in(1), zer_taken, post_head); + assert(inserted, "no castII inserted"); + + // CastII for the main loop: + inserted = cast_incr_before_loop(pre_incr, min_taken, main_head); + assert(inserted, "no castII inserted"); + // Step B4: Shorten the pre-loop to run only 1 iteration (for now). // RCE and alignment may change this later. Node *cmp_end = pre_end->cmp_node(); @@ -2287,8 +2318,8 @@ // Skip next optimizations if running low on nodes. Note that // policy_unswitching and policy_maximally_unroll have this check. - uint nodes_left = MaxNodeLimit - (uint) phase->C->live_nodes(); - if ((2 * _body.size()) > nodes_left) { + int nodes_left = phase->C->max_node_limit() - phase->C->live_nodes(); + if ((int)(2 * _body.size()) > nodes_left) { return true; }
--- a/src/share/vm/opto/loopUnswitch.cpp Thu Jan 08 12:47:32 2015 +0000 +++ b/src/share/vm/opto/loopUnswitch.cpp Tue Feb 03 16:48:05 2015 +0000 @@ -59,8 +59,8 @@ if (!_head->is_Loop()) { return false; } - uint nodes_left = MaxNodeLimit - phase->C->live_nodes(); - if (2 * _body.size() > nodes_left) { + int nodes_left = phase->C->max_node_limit() - phase->C->live_nodes(); + if ((int)(2 * _body.size()) > nodes_left) { return false; // Too speculative if running low on nodes. } LoopNode* head = _head->as_Loop();
--- a/src/share/vm/opto/loopnode.hpp Thu Jan 08 12:47:32 2015 +0000 +++ b/src/share/vm/opto/loopnode.hpp Tue Feb 03 16:48:05 2015 +0000 @@ -602,6 +602,8 @@ return ctrl; } + bool cast_incr_before_loop(Node* incr, Node* ctrl, Node* loop); + public: bool has_node( Node* n ) const { guarantee(n != NULL, "No Node.");
--- a/src/share/vm/opto/loopopts.cpp Thu Jan 08 12:47:32 2015 +0000 +++ b/src/share/vm/opto/loopopts.cpp Tue Feb 03 16:48:05 2015 +0000 @@ -239,8 +239,13 @@ ProjNode* dp_proj = dp->as_Proj(); ProjNode* unc_proj = iff->as_If()->proj_out(1 - dp_proj->_con)->as_Proj(); if (exclude_loop_predicate && - unc_proj->is_uncommon_trap_proj(Deoptimization::Reason_predicate)) + (unc_proj->is_uncommon_trap_proj(Deoptimization::Reason_predicate) || + unc_proj->is_uncommon_trap_proj(Deoptimization::Reason_range_check))) { + // If this is a range check (IfNode::is_range_check), do not + // reorder because Compile::allow_range_check_smearing might have + // changed the check. return; // Let IGVN transformation change control dependence. + } IdealLoopTree *old_loop = get_loop(dp); @@ -734,7 +739,7 @@ for (DUIterator_Fast imax, i = region->fast_outs(imax); i < imax; i++) { weight += region->fast_out(i)->outcnt(); } - int nodes_left = MaxNodeLimit - C->live_nodes(); + int nodes_left = C->max_node_limit() - C->live_nodes(); if (weight * 8 > nodes_left) { #ifndef PRODUCT if (PrintOpto) @@ -896,23 +901,23 @@ int n_op = n->Opcode(); // Check for an IF being dominated by another IF same test - if( n_op == Op_If ) { + if (n_op == Op_If) { Node *bol = n->in(1); uint max = bol->outcnt(); // Check for same test used more than once? - if( n_op == Op_If && max > 1 && bol->is_Bool() ) { + if (max > 1 && bol->is_Bool()) { // Search up IDOMs to see if this IF is dominated. Node *cutoff = get_ctrl(bol); // Now search up IDOMs till cutoff, looking for a dominating test Node *prevdom = n; Node *dom = idom(prevdom); - while( dom != cutoff ) { - if( dom->req() > 1 && dom->in(1) == bol && prevdom->in(0) == dom ) { + while (dom != cutoff) { + if (dom->req() > 1 && dom->in(1) == bol && prevdom->in(0) == dom) { // Replace the dominated test with an obvious true or false. // Place it on the IGVN worklist for later cleanup. C->set_major_progress(); - dominated_by( prevdom, n, false, true ); + dominated_by(prevdom, n, false, true); #ifndef PRODUCT if( VerifyLoopOptimizations ) verify(); #endif
--- a/src/share/vm/opto/macro.cpp Thu Jan 08 12:47:32 2015 +0000 +++ b/src/share/vm/opto/macro.cpp Tue Feb 03 16:48:05 2015 +0000 @@ -964,7 +964,11 @@ } bool PhaseMacroExpand::eliminate_allocate_node(AllocateNode *alloc) { - if (!EliminateAllocations || !alloc->_is_non_escaping) { + // Don't do scalar replacement if the frame can be popped by JVMTI: + // if reallocation fails during deoptimization we'll pop all + // interpreter frames for this compiled frame and that won't play + // nice with JVMTI popframe. + if (!EliminateAllocations || JvmtiExport::can_pop_frame() || !alloc->_is_non_escaping) { return false; } Node* klass = alloc->in(AllocateNode::KlassNode); @@ -2194,7 +2198,7 @@ Node* klass_node = AllocateNode::Ideal_klass(obj, &_igvn); if (klass_node == NULL) { Node* k_adr = basic_plus_adr(obj, oopDesc::klass_offset_in_bytes()); - klass_node = transform_later( LoadKlassNode::make(_igvn, mem, k_adr, _igvn.type(k_adr)->is_ptr()) ); + klass_node = transform_later(LoadKlassNode::make(_igvn, NULL, mem, k_adr, _igvn.type(k_adr)->is_ptr())); #ifdef _LP64 if (UseCompressedClassPointers && klass_node->is_DecodeNKlass()) { assert(klass_node->in(1)->Opcode() == Op_LoadNKlass, "sanity");
--- a/src/share/vm/opto/memnode.cpp Thu Jan 08 12:47:32 2015 +0000 +++ b/src/share/vm/opto/memnode.cpp Tue Feb 03 16:48:05 2015 +0000 @@ -870,6 +870,10 @@ //============================================================================= +// Should LoadNode::Ideal() attempt to remove control edges? +bool LoadNode::can_remove_control() const { + return true; +} uint LoadNode::size_of() const { return sizeof(*this); } uint LoadNode::cmp( const Node &n ) const { return !Type::cmp( _type, ((LoadNode&)n)._type ); } @@ -1262,6 +1266,16 @@ result = new (phase->C) ConvI2LNode(phase->transform(result)); } #endif + // Boxing/unboxing can be done from signed & unsigned loads (e.g. LoadUB -> ... -> LoadB pair). + // Need to preserve unboxing load type if it is unsigned. + switch(this->Opcode()) { + case Op_LoadUB: + result = new (phase->C) AndINode(phase->transform(result), phase->intcon(0xFF)); + break; + case Op_LoadUS: + result = new (phase->C) AndINode(phase->transform(result), phase->intcon(0xFFFF)); + break; + } return result; } } @@ -1466,7 +1480,7 @@ } //------------------------------Ideal------------------------------------------ -// If the load is from Field memory and the pointer is non-null, we can +// If the load is from Field memory and the pointer is non-null, it might be possible to // zero out the control input. // If the offset is constant and the base is an object allocation, // try to hook me up to the exact initializing store. @@ -1491,6 +1505,7 @@ && phase->C->get_alias_index(phase->type(address)->is_ptr()) != Compile::AliasIdxRaw) { // Check for useless control edge in some common special cases if (in(MemNode::Control) != NULL + && can_remove_control() && phase->type(base)->higher_equal(TypePtr::NOTNULL) && all_controls_dominate(base, phase->C->start())) { // A method-invariant, non-null address (constant or 'this' argument). @@ -2018,9 +2033,8 @@ //============================================================================= //----------------------------LoadKlassNode::make------------------------------ // Polymorphic factory method: -Node *LoadKlassNode::make( PhaseGVN& gvn, Node *mem, Node *adr, const TypePtr* at, const TypeKlassPtr *tk ) { +Node* LoadKlassNode::make(PhaseGVN& gvn, Node* ctl, Node *mem, Node *adr, const TypePtr* at, const TypeKlassPtr *tk) { Compile* C = gvn.C; - Node *ctl = NULL; // sanity check the alias category against the created node type const TypePtr *adr_type = adr->bottom_type()->isa_ptr(); assert(adr_type != NULL, "expecting TypeKlassPtr"); @@ -2040,6 +2054,12 @@ return klass_value_common(phase); } +// In most cases, LoadKlassNode does not have the control input set. If the control +// input is set, it must not be removed (by LoadNode::Ideal()). +bool LoadKlassNode::can_remove_control() const { + return false; +} + const Type *LoadNode::klass_value_common( PhaseTransform *phase ) const { // Either input is TOP ==> the result is TOP const Type *t1 = phase->type( in(MemNode::Memory) );
--- a/src/share/vm/opto/memnode.hpp Thu Jan 08 12:47:32 2015 +0000 +++ b/src/share/vm/opto/memnode.hpp Tue Feb 03 16:48:05 2015 +0000 @@ -151,6 +151,8 @@ protected: virtual uint cmp(const Node &n) const; virtual uint size_of() const; // Size is bigger + // Should LoadNode::Ideal() attempt to remove control edges? + virtual bool can_remove_control() const; const Type* const _type; // What kind of value is loaded? public: @@ -174,8 +176,10 @@ // we are equivalent to. We look for Load of a Store. virtual Node *Identity( PhaseTransform *phase ); - // If the load is from Field memory and the pointer is non-null, we can + // If the load is from Field memory and the pointer is non-null, it might be possible to // zero out the control input. + // If the offset is constant and the base is an object allocation, + // try to hook me up to the exact initializing store. virtual Node *Ideal(PhaseGVN *phase, bool can_reshape); // Split instance field load through Phi. @@ -416,6 +420,10 @@ //------------------------------LoadKlassNode---------------------------------- // Load a Klass from an object class LoadKlassNode : public LoadPNode { +protected: + // In most cases, LoadKlassNode does not have the control input set. If the control + // input is set, it must not be removed (by LoadNode::Ideal()). + virtual bool can_remove_control() const; public: LoadKlassNode(Node *c, Node *mem, Node *adr, const TypePtr *at, const TypeKlassPtr *tk, MemOrd mo) : LoadPNode(c, mem, adr, at, tk, mo) {} @@ -425,8 +433,8 @@ virtual bool depends_only_on_test() const { return true; } // Polymorphic factory method: - static Node* make( PhaseGVN& gvn, Node *mem, Node *adr, const TypePtr* at, - const TypeKlassPtr *tk = TypeKlassPtr::OBJECT ); + static Node* make(PhaseGVN& gvn, Node* ctl, Node* mem, Node* adr, const TypePtr* at, + const TypeKlassPtr* tk = TypeKlassPtr::OBJECT); }; //------------------------------LoadNKlassNode---------------------------------
--- a/src/share/vm/opto/node.cpp Thu Jan 08 12:47:32 2015 +0000 +++ b/src/share/vm/opto/node.cpp Tue Feb 03 16:48:05 2015 +0000 @@ -69,7 +69,7 @@ Compile::set_debug_idx(new_debug_idx); set_debug_idx( new_debug_idx ); assert(Compile::current()->unique() < (INT_MAX - 1), "Node limit exceeded INT_MAX"); - assert(Compile::current()->live_nodes() < (uint)MaxNodeLimit, "Live Node limit exceeded limit"); + assert(Compile::current()->live_nodes() < Compile::current()->max_node_limit(), "Live Node limit exceeded limit"); if (BreakAtNode != 0 && (_debug_idx == BreakAtNode || (int)_idx == BreakAtNode)) { tty->print_cr("BreakAtNode: _idx=%d _debug_idx=%d", _idx, _debug_idx); BREAKPOINT; @@ -326,7 +326,7 @@ Node::Node(uint req) : _idx(IDX_INIT(req)) { - assert( req < (uint)(MaxNodeLimit - NodeLimitFudgeFactor), "Input limit exceeded" ); + assert( req < Compile::current()->max_node_limit() - NodeLimitFudgeFactor, "Input limit exceeded" ); debug_only( verify_construction() ); NOT_PRODUCT(nodes_created++); if (req == 0) {
--- a/src/share/vm/opto/parse1.cpp Thu Jan 08 12:47:32 2015 +0000 +++ b/src/share/vm/opto/parse1.cpp Tue Feb 03 16:48:05 2015 +0000 @@ -1958,7 +1958,7 @@ // finalization. In general this will fold up since the concrete // class is often visible so the access flags are constant. Node* klass_addr = basic_plus_adr( receiver, receiver, oopDesc::klass_offset_in_bytes() ); - Node* klass = _gvn.transform( LoadKlassNode::make(_gvn, immutable_memory(), klass_addr, TypeInstPtr::KLASS) ); + Node* klass = _gvn.transform(LoadKlassNode::make(_gvn, NULL, immutable_memory(), klass_addr, TypeInstPtr::KLASS)); Node* access_flags_addr = basic_plus_adr(klass, klass, in_bytes(Klass::access_flags_offset())); Node* access_flags = make_load(NULL, access_flags_addr, TypeInt::INT, T_INT, MemNode::unordered);
--- a/src/share/vm/opto/parseHelper.cpp Thu Jan 08 12:47:32 2015 +0000 +++ b/src/share/vm/opto/parseHelper.cpp Tue Feb 03 16:48:05 2015 +0000 @@ -156,22 +156,43 @@ int klass_offset = oopDesc::klass_offset_in_bytes(); Node* p = basic_plus_adr( ary, ary, klass_offset ); // p's type is array-of-OOPS plus klass_offset - Node* array_klass = _gvn.transform( LoadKlassNode::make(_gvn, immutable_memory(), p, TypeInstPtr::KLASS) ); + Node* array_klass = _gvn.transform(LoadKlassNode::make(_gvn, NULL, immutable_memory(), p, TypeInstPtr::KLASS)); // Get the array klass const TypeKlassPtr *tak = _gvn.type(array_klass)->is_klassptr(); - // array_klass's type is generally INexact array-of-oop. Heroically - // cast the array klass to EXACT array and uncommon-trap if the cast - // fails. + // The type of array_klass is usually INexact array-of-oop. Heroically + // cast array_klass to EXACT array and uncommon-trap if the cast fails. + // Make constant out of the inexact array klass, but use it only if the cast + // succeeds. bool always_see_exact_class = false; if (MonomorphicArrayCheck - && !too_many_traps(Deoptimization::Reason_array_check)) { + && !too_many_traps(Deoptimization::Reason_array_check) + && !tak->klass_is_exact() + && tak != TypeKlassPtr::OBJECT) { + // Regarding the fourth condition in the if-statement from above: + // + // If the compiler has determined that the type of array 'ary' (represented + // by 'array_klass') is java/lang/Object, the compiler must not assume that + // the array 'ary' is monomorphic. + // + // If 'ary' were of type java/lang/Object, this arraystore would have to fail, + // because it is not possible to perform a arraystore into an object that is not + // a "proper" array. + // + // Therefore, let's obtain at runtime the type of 'ary' and check if we can still + // successfully perform the store. + // + // The implementation reasons for the condition are the following: + // + // java/lang/Object is the superclass of all arrays, but it is represented by the VM + // as an InstanceKlass. The checks generated by gen_checkcast() (see below) expect + // 'array_klass' to be ObjArrayKlass, which can result in invalid memory accesses. + // + // See issue JDK-8057622 for details. + always_see_exact_class = true; // (If no MDO at all, hope for the best, until a trap actually occurs.) - } - // Is the array klass is exactly its defined type? - if (always_see_exact_class && !tak->klass_is_exact()) { // Make a constant out of the inexact array klass const TypeKlassPtr *extak = tak->cast_to_exactness(true)->is_klassptr(); Node* con = makecon(extak); @@ -202,11 +223,15 @@ // Extract the array element class int element_klass_offset = in_bytes(ObjArrayKlass::element_klass_offset()); Node *p2 = basic_plus_adr(array_klass, array_klass, element_klass_offset); - Node *a_e_klass = _gvn.transform( LoadKlassNode::make(_gvn, immutable_memory(), p2, tak) ); + // We are allowed to use the constant type only if cast succeeded. If always_see_exact_class is true, + // we must set a control edge from the IfTrue node created by the uncommon_trap above to the + // LoadKlassNode. + Node* a_e_klass = _gvn.transform(LoadKlassNode::make(_gvn, always_see_exact_class ? control() : NULL, + immutable_memory(), p2, tak)); // Check (the hard way) and throw if not a subklass. // Result is ignored, we just need the CFG effects. - gen_checkcast( obj, a_e_klass ); + gen_checkcast(obj, a_e_klass); }
--- a/src/share/vm/opto/phaseX.cpp Thu Jan 08 12:47:32 2015 +0000 +++ b/src/share/vm/opto/phaseX.cpp Tue Feb 03 16:48:05 2015 +0000 @@ -1340,15 +1340,27 @@ } } - if( use->is_Cmp() ) { // Enable CMP/BOOL optimization + uint use_op = use->Opcode(); + if(use->is_Cmp()) { // Enable CMP/BOOL optimization add_users_to_worklist(use); // Put Bool on worklist - // Look for the 'is_x2logic' pattern: "x ? : 0 : 1" and put the - // phi merging either 0 or 1 onto the worklist if (use->outcnt() > 0) { Node* bol = use->raw_out(0); if (bol->outcnt() > 0) { Node* iff = bol->raw_out(0); - if (iff->outcnt() == 2) { + if (use_op == Op_CmpI && + iff->is_CountedLoopEnd()) { + CountedLoopEndNode* cle = iff->as_CountedLoopEnd(); + if (cle->limit() == n && cle->phi() != NULL) { + // If an opaque node feeds into the limit condition of a + // CountedLoop, we need to process the Phi node for the + // induction variable when the opaque node is removed: + // the range of values taken by the Phi is now known and + // so its type is also known. + _worklist.push(cle->phi()); + } + } else if (iff->outcnt() == 2) { + // Look for the 'is_x2logic' pattern: "x ? : 0 : 1" and put the + // phi merging either 0 or 1 onto the worklist Node* ifproj0 = iff->raw_out(0); Node* ifproj1 = iff->raw_out(1); if (ifproj0->outcnt() > 0 && ifproj1->outcnt() > 0) { @@ -1360,9 +1372,26 @@ } } } + if (use_op == Op_CmpI) { + Node* in1 = use->in(1); + for (uint i = 0; i < in1->outcnt(); i++) { + if (in1->raw_out(i)->Opcode() == Op_CastII) { + Node* castii = in1->raw_out(i); + if (castii->in(0) != NULL && castii->in(0)->in(0) != NULL && castii->in(0)->in(0)->is_If()) { + Node* ifnode = castii->in(0)->in(0); + if (ifnode->in(1) != NULL && ifnode->in(1)->is_Bool() && ifnode->in(1)->in(1) == use) { + // Reprocess a CastII node that may depend on an + // opaque node value when the opaque node is + // removed. In case it carries a dependency we can do + // a better job of computing its type. + _worklist.push(castii); + } + } + } + } + } } - uint use_op = use->Opcode(); // If changed Cast input, check Phi users for simple cycles if( use->is_ConstraintCast() || use->is_CheckCastPP() ) { for (DUIterator_Fast i2max, i2 = use->fast_outs(i2max); i2 < i2max; i2++) {
--- a/src/share/vm/opto/subnode.cpp Thu Jan 08 12:47:32 2015 +0000 +++ b/src/share/vm/opto/subnode.cpp Tue Feb 03 16:48:05 2015 +0000 @@ -1147,12 +1147,10 @@ //------------------------------dump_spec------------------------------------- // Print special per-node info -#ifndef PRODUCT void BoolTest::dump_on(outputStream *st) const { const char *msg[] = {"eq","gt","of","lt","ne","le","nof","ge"}; st->print("%s", msg[_test]); } -#endif //============================================================================= uint BoolNode::hash() const { return (Node::hash() << 3)|(_test._test+1); }
--- a/src/share/vm/opto/subnode.hpp Thu Jan 08 12:47:32 2015 +0000 +++ b/src/share/vm/opto/subnode.hpp Tue Feb 03 16:48:05 2015 +0000 @@ -275,9 +275,7 @@ mask commute( ) const { return mask("032147658"[_test]-'0'); } mask negate( ) const { return mask(_test^4); } bool is_canonical( ) const { return (_test == BoolTest::ne || _test == BoolTest::lt || _test == BoolTest::le || _test == BoolTest::overflow); } -#ifndef PRODUCT void dump_on(outputStream *st) const; -#endif }; //------------------------------BoolNode---------------------------------------
--- a/src/share/vm/prims/jni.cpp Thu Jan 08 12:47:32 2015 +0000 +++ b/src/share/vm/prims/jni.cpp Tue Feb 03 16:48:05 2015 +0000 @@ -5080,6 +5080,7 @@ void TestNewSize_test(); void TestKlass_test(); void Test_linked_list(); +void TestChunkedList_test(); #if INCLUDE_ALL_GCS void TestOldFreeSpaceCalculation_test(); void TestG1BiasedArray_test(); @@ -5108,6 +5109,7 @@ run_unit_test(TestNewSize_test()); run_unit_test(TestKlass_test()); run_unit_test(Test_linked_list()); + run_unit_test(TestChunkedList_test()); #if INCLUDE_VM_STRUCTS run_unit_test(VMStructs::test()); #endif
--- a/src/share/vm/prims/jvm.cpp Thu Jan 08 12:47:32 2015 +0000 +++ b/src/share/vm/prims/jvm.cpp Tue Feb 03 16:48:05 2015 +0000 @@ -24,6 +24,7 @@ #include "precompiled.hpp" #include "classfile/classLoader.hpp" +#include "classfile/classLoaderExt.hpp" #include "classfile/javaAssertions.hpp" #include "classfile/javaClasses.hpp" #include "classfile/symbolTable.hpp" @@ -393,6 +394,14 @@ } } + const char* enableSharedLookupCache = "false"; +#if INCLUDE_CDS + if (ClassLoaderExt::is_lookup_cache_enabled()) { + enableSharedLookupCache = "true"; + } +#endif + PUTPROP(props, "sun.cds.enableSharedLookupCache", enableSharedLookupCache); + return properties; JVM_END @@ -594,13 +603,14 @@ // Make shallow object copy const int size = obj->size(); - oop new_obj = NULL; + oop new_obj_oop = NULL; if (obj->is_array()) { const int length = ((arrayOop)obj())->length(); - new_obj = CollectedHeap::array_allocate(klass, size, length, CHECK_NULL); + new_obj_oop = CollectedHeap::array_allocate(klass, size, length, CHECK_NULL); } else { - new_obj = CollectedHeap::obj_allocate(klass, size, CHECK_NULL); + new_obj_oop = CollectedHeap::obj_allocate(klass, size, CHECK_NULL); } + // 4839641 (4840070): We must do an oop-atomic copy, because if another thread // is modifying a reference field in the clonee, a non-oop-atomic copy might // be suspended in the middle of copying the pointer and end up with parts @@ -611,24 +621,41 @@ // The same is true of StubRoutines::object_copy and the various oop_copy // variants, and of the code generated by the inline_native_clone intrinsic. assert(MinObjAlignmentInBytes >= BytesPerLong, "objects misaligned"); - Copy::conjoint_jlongs_atomic((jlong*)obj(), (jlong*)new_obj, + Copy::conjoint_jlongs_atomic((jlong*)obj(), (jlong*)new_obj_oop, (size_t)align_object_size(size) / HeapWordsPerLong); // Clear the header - new_obj->init_mark(); + new_obj_oop->init_mark(); // Store check (mark entire object and let gc sort it out) BarrierSet* bs = Universe::heap()->barrier_set(); assert(bs->has_write_region_opt(), "Barrier set does not have write_region"); - bs->write_region(MemRegion((HeapWord*)new_obj, size)); + bs->write_region(MemRegion((HeapWord*)new_obj_oop, size)); + + Handle new_obj(THREAD, new_obj_oop); + // Special handling for MemberNames. Since they contain Method* metadata, they + // must be registered so that RedefineClasses can fix metadata contained in them. + if (java_lang_invoke_MemberName::is_instance(new_obj()) && + java_lang_invoke_MemberName::is_method(new_obj())) { + Method* method = (Method*)java_lang_invoke_MemberName::vmtarget(new_obj()); + // MemberName may be unresolved, so doesn't need registration until resolved. + if (method != NULL) { + methodHandle m(THREAD, method); + // This can safepoint and redefine method, so need both new_obj and method + // in a handle, for two different reasons. new_obj can move, method can be + // deleted if nothing is using it on the stack. + m->method_holder()->add_member_name(new_obj()); + } + } // Caution: this involves a java upcall, so the clone should be // "gc-robust" by this stage. if (klass->has_finalizer()) { assert(obj->is_instance(), "should be instanceOop"); - new_obj = InstanceKlass::register_finalizer(instanceOop(new_obj), CHECK_NULL); + new_obj_oop = InstanceKlass::register_finalizer(instanceOop(new_obj()), CHECK_NULL); + new_obj = Handle(THREAD, new_obj_oop); } - return JNIHandles::make_local(env, oop(new_obj)); + return JNIHandles::make_local(env, new_obj()); JVM_END // java.lang.Compiler //////////////////////////////////////////////////// @@ -766,6 +793,36 @@ JVM_END +JVM_ENTRY(jboolean, JVM_KnownToNotExist(JNIEnv *env, jobject loader, const char *classname)) + JVMWrapper("JVM_KnownToNotExist"); +#if INCLUDE_CDS + return ClassLoaderExt::known_to_not_exist(env, loader, classname, CHECK_(false)); +#else + return false; +#endif +JVM_END + + +JVM_ENTRY(jobjectArray, JVM_GetResourceLookupCacheURLs(JNIEnv *env, jobject loader)) + JVMWrapper("JVM_GetResourceLookupCacheURLs"); +#if INCLUDE_CDS + return ClassLoaderExt::get_lookup_cache_urls(env, loader, CHECK_NULL); +#else + return NULL; +#endif +JVM_END + + +JVM_ENTRY(jintArray, JVM_GetResourceLookupCache(JNIEnv *env, jobject loader, const char *resource_name)) + JVMWrapper("JVM_GetResourceLookupCache"); +#if INCLUDE_CDS + return ClassLoaderExt::get_lookup_cache(env, loader, resource_name, CHECK_NULL); +#else + return NULL; +#endif +JVM_END + + // Returns a class loaded by the bootstrap class loader; or null // if not found. ClassNotFoundException is not thrown. // @@ -4497,7 +4554,7 @@ JVM_ENTRY(void, JVM_GetVersionInfo(JNIEnv* env, jvm_version_info* info, size_t info_size)) { - memset(info, 0, sizeof(info_size)); + memset(info, 0, info_size); info->jvm_version = Abstract_VM_Version::jvm_version(); info->update_version = 0; /* 0 in HotSpot Express VM */
--- a/src/share/vm/prims/jvm.h Thu Jan 08 12:47:32 2015 +0000 +++ b/src/share/vm/prims/jvm.h Tue Feb 03 16:48:05 2015 +0000 @@ -1553,6 +1553,31 @@ JNIEXPORT jobjectArray JNICALL JVM_GetThreadStateNames(JNIEnv* env, jint javaThreadState, jintArray values); +/* + * Returns true if the JVM's lookup cache indicates that this class is + * known to NOT exist for the given loader. + */ +JNIEXPORT jboolean JNICALL +JVM_KnownToNotExist(JNIEnv *env, jobject loader, const char *classname); + +/* + * Returns an array of all URLs that are stored in the JVM's lookup cache + * for the given loader. NULL if the lookup cache is unavailable. + */ +JNIEXPORT jobjectArray JNICALL +JVM_GetResourceLookupCacheURLs(JNIEnv *env, jobject loader); + +/* + * Returns an array of all URLs that *may* contain the resource_name for the + * given loader. This function returns an integer array, each element + * of which can be used to index into the array returned by + * JVM_GetResourceLookupCacheURLs of the same loader to determine the + * URLs. + */ +JNIEXPORT jintArray JNICALL +JVM_GetResourceLookupCache(JNIEnv *env, jobject loader, const char *resource_name); + + /* ========================================================================= * The following defines a private JVM interface that the JDK can query * for the JVM version and capabilities. sun.misc.Version defines
--- a/src/share/vm/prims/jvmtiClassFileReconstituter.cpp Thu Jan 08 12:47:32 2015 +0000 +++ b/src/share/vm/prims/jvmtiClassFileReconstituter.cpp Tue Feb 03 16:48:05 2015 +0000 @@ -57,6 +57,7 @@ void JvmtiClassFileReconstituter::write_field_infos() { HandleMark hm(thread()); Array<AnnotationArray*>* fields_anno = ikh()->fields_annotations(); + Array<AnnotationArray*>* fields_type_anno = ikh()->fields_type_annotations(); // Compute the real number of Java fields int java_fields = ikh()->java_fields_count(); @@ -71,6 +72,7 @@ // int offset = ikh()->field_offset( index ); int generic_signature_index = fs.generic_signature_index(); AnnotationArray* anno = fields_anno == NULL ? NULL : fields_anno->at(fs.index()); + AnnotationArray* type_anno = fields_type_anno == NULL ? NULL : fields_type_anno->at(fs.index()); // JVMSpec| field_info { // JVMSpec| u2 access_flags; @@ -96,6 +98,9 @@ if (anno != NULL) { ++attr_count; // has RuntimeVisibleAnnotations attribute } + if (type_anno != NULL) { + ++attr_count; // has RuntimeVisibleTypeAnnotations attribute + } write_u2(attr_count); @@ -113,6 +118,9 @@ if (anno != NULL) { write_annotations_attribute("RuntimeVisibleAnnotations", anno); } + if (type_anno != NULL) { + write_annotations_attribute("RuntimeVisibleTypeAnnotations", type_anno); + } } } @@ -553,6 +561,7 @@ AnnotationArray* anno = method->annotations(); AnnotationArray* param_anno = method->parameter_annotations(); AnnotationArray* default_anno = method->annotation_default(); + AnnotationArray* type_anno = method->type_annotations(); // skip generated default interface methods if (method->is_overpass()) { @@ -588,6 +597,9 @@ if (param_anno != NULL) { ++attr_count; // has RuntimeVisibleParameterAnnotations attribute } + if (type_anno != NULL) { + ++attr_count; // has RuntimeVisibleTypeAnnotations attribute + } write_u2(attr_count); if (const_method->code_size() > 0) { @@ -612,6 +624,9 @@ if (param_anno != NULL) { write_annotations_attribute("RuntimeVisibleParameterAnnotations", param_anno); } + if (type_anno != NULL) { + write_annotations_attribute("RuntimeVisibleTypeAnnotations", type_anno); + } } // Write the class attributes portion of ClassFile structure @@ -621,6 +636,7 @@ u2 inner_classes_length = inner_classes_attribute_length(); Symbol* generic_signature = ikh()->generic_signature(); AnnotationArray* anno = ikh()->class_annotations(); + AnnotationArray* type_anno = ikh()->class_type_annotations(); int attr_count = 0; if (generic_signature != NULL) { @@ -638,6 +654,9 @@ if (anno != NULL) { ++attr_count; // has RuntimeVisibleAnnotations attribute } + if (type_anno != NULL) { + ++attr_count; // has RuntimeVisibleTypeAnnotations attribute + } if (cpool()->operands() != NULL) { ++attr_count; } @@ -659,6 +678,9 @@ if (anno != NULL) { write_annotations_attribute("RuntimeVisibleAnnotations", anno); } + if (type_anno != NULL) { + write_annotations_attribute("RuntimeVisibleTypeAnnotations", type_anno); + } if (cpool()->operands() != NULL) { write_bootstrapmethod_attribute(); }
--- a/src/share/vm/prims/jvmtiEnv.cpp Thu Jan 08 12:47:32 2015 +0000 +++ b/src/share/vm/prims/jvmtiEnv.cpp Tue Feb 03 16:48:05 2015 +0000 @@ -23,6 +23,7 @@ */ #include "precompiled.hpp" +#include "classfile/classLoaderExt.hpp" #include "classfile/systemDictionary.hpp" #include "classfile/vmSymbols.hpp" #include "interpreter/bytecodeStream.hpp" @@ -475,7 +476,7 @@ if (TraceClassLoading) { tty->print_cr("[Opened %s]", zip_entry->name()); } - ClassLoader::add_to_list(zip_entry); + ClassLoaderExt::append_boot_classpath(zip_entry); return JVMTI_ERROR_NONE; } else { return JVMTI_ERROR_WRONG_PHASE;
--- a/src/share/vm/prims/jvmtiRedefineClasses.cpp Thu Jan 08 12:47:32 2015 +0000 +++ b/src/share/vm/prims/jvmtiRedefineClasses.cpp Tue Feb 03 16:48:05 2015 +0000 @@ -135,7 +135,7 @@ // Mark methods seen on stack and everywhere else so old methods are not // cleaned up if they're on the stack. - MetadataOnStackMark md_on_stack; + MetadataOnStackMark md_on_stack(true); HandleMark hm(thread); // make sure any handles created are deleted // before the stack walk again. @@ -1569,6 +1569,29 @@ return false; } + // rewrite constant pool references in the class_type_annotations: + if (!rewrite_cp_refs_in_class_type_annotations(scratch_class, THREAD)) { + // propagate failure back to caller + return false; + } + + // rewrite constant pool references in the fields_type_annotations: + if (!rewrite_cp_refs_in_fields_type_annotations(scratch_class, THREAD)) { + // propagate failure back to caller + return false; + } + + // rewrite constant pool references in the methods_type_annotations: + if (!rewrite_cp_refs_in_methods_type_annotations(scratch_class, THREAD)) { + // propagate failure back to caller + return false; + } + + // There can be type annotations in the Code part of a method_info attribute. + // These annotations are not accessible, even by reflection. + // Currently they are not even parsed by the ClassFileParser. + // If runtime access is added they will also need to be rewritten. + // rewrite source file name index: u2 source_file_name_idx = scratch_class->source_file_name_index(); if (source_file_name_idx != 0) { @@ -2239,6 +2262,588 @@ } // end rewrite_cp_refs_in_methods_default_annotations() +// Rewrite constant pool references in a class_type_annotations field. +bool VM_RedefineClasses::rewrite_cp_refs_in_class_type_annotations( + instanceKlassHandle scratch_class, TRAPS) { + + AnnotationArray* class_type_annotations = scratch_class->class_type_annotations(); + if (class_type_annotations == NULL || class_type_annotations->length() == 0) { + // no class_type_annotations so nothing to do + return true; + } + + RC_TRACE_WITH_THREAD(0x02000000, THREAD, + ("class_type_annotations length=%d", class_type_annotations->length())); + + int byte_i = 0; // byte index into class_type_annotations + return rewrite_cp_refs_in_type_annotations_typeArray(class_type_annotations, + byte_i, "ClassFile", THREAD); +} // end rewrite_cp_refs_in_class_type_annotations() + + +// Rewrite constant pool references in a fields_type_annotations field. +bool VM_RedefineClasses::rewrite_cp_refs_in_fields_type_annotations( + instanceKlassHandle scratch_class, TRAPS) { + + Array<AnnotationArray*>* fields_type_annotations = scratch_class->fields_type_annotations(); + if (fields_type_annotations == NULL || fields_type_annotations->length() == 0) { + // no fields_type_annotations so nothing to do + return true; + } + + RC_TRACE_WITH_THREAD(0x02000000, THREAD, + ("fields_type_annotations length=%d", fields_type_annotations->length())); + + for (int i = 0; i < fields_type_annotations->length(); i++) { + AnnotationArray* field_type_annotations = fields_type_annotations->at(i); + if (field_type_annotations == NULL || field_type_annotations->length() == 0) { + // this field does not have any annotations so skip it + continue; + } + + int byte_i = 0; // byte index into field_type_annotations + if (!rewrite_cp_refs_in_type_annotations_typeArray(field_type_annotations, + byte_i, "field_info", THREAD)) { + RC_TRACE_WITH_THREAD(0x02000000, THREAD, + ("bad field_type_annotations at %d", i)); + // propagate failure back to caller + return false; + } + } + + return true; +} // end rewrite_cp_refs_in_fields_type_annotations() + + +// Rewrite constant pool references in a methods_type_annotations field. +bool VM_RedefineClasses::rewrite_cp_refs_in_methods_type_annotations( + instanceKlassHandle scratch_class, TRAPS) { + + for (int i = 0; i < scratch_class->methods()->length(); i++) { + Method* m = scratch_class->methods()->at(i); + AnnotationArray* method_type_annotations = m->constMethod()->type_annotations(); + + if (method_type_annotations == NULL || method_type_annotations->length() == 0) { + // this method does not have any annotations so skip it + continue; + } + + RC_TRACE_WITH_THREAD(0x02000000, THREAD, + ("methods type_annotations length=%d", method_type_annotations->length())); + + int byte_i = 0; // byte index into method_type_annotations + if (!rewrite_cp_refs_in_type_annotations_typeArray(method_type_annotations, + byte_i, "method_info", THREAD)) { + RC_TRACE_WITH_THREAD(0x02000000, THREAD, + ("bad method_type_annotations at %d", i)); + // propagate failure back to caller + return false; + } + } + + return true; +} // end rewrite_cp_refs_in_methods_type_annotations() + + +// Rewrite constant pool references in a type_annotations +// field. This "structure" is adapted from the +// RuntimeVisibleTypeAnnotations_attribute described in +// section 4.7.20 of the Java SE 8 Edition of the VM spec: +// +// type_annotations_typeArray { +// u2 num_annotations; +// type_annotation annotations[num_annotations]; +// } +// +bool VM_RedefineClasses::rewrite_cp_refs_in_type_annotations_typeArray( + AnnotationArray* type_annotations_typeArray, int &byte_i_ref, + const char * location_mesg, TRAPS) { + + if ((byte_i_ref + 2) > type_annotations_typeArray->length()) { + // not enough room for num_annotations field + RC_TRACE_WITH_THREAD(0x02000000, THREAD, + ("length() is too small for num_annotations field")); + return false; + } + + u2 num_annotations = Bytes::get_Java_u2((address) + type_annotations_typeArray->adr_at(byte_i_ref)); + byte_i_ref += 2; + + RC_TRACE_WITH_THREAD(0x02000000, THREAD, + ("num_type_annotations=%d", num_annotations)); + + int calc_num_annotations = 0; + for (; calc_num_annotations < num_annotations; calc_num_annotations++) { + if (!rewrite_cp_refs_in_type_annotation_struct(type_annotations_typeArray, + byte_i_ref, location_mesg, THREAD)) { + RC_TRACE_WITH_THREAD(0x02000000, THREAD, + ("bad type_annotation_struct at %d", calc_num_annotations)); + // propagate failure back to caller + return false; + } + } + assert(num_annotations == calc_num_annotations, "sanity check"); + + if (byte_i_ref != type_annotations_typeArray->length()) { + RC_TRACE_WITH_THREAD(0x02000000, THREAD, + ("read wrong amount of bytes at end of processing " + "type_annotations_typeArray (%d of %d bytes were read)", + byte_i_ref, type_annotations_typeArray->length())); + return false; + } + + return true; +} // end rewrite_cp_refs_in_type_annotations_typeArray() + + +// Rewrite constant pool references in a type_annotation +// field. This "structure" is adapted from the +// RuntimeVisibleTypeAnnotations_attribute described in +// section 4.7.20 of the Java SE 8 Edition of the VM spec: +// +// type_annotation { +// u1 target_type; +// union { +// type_parameter_target; +// supertype_target; +// type_parameter_bound_target; +// empty_target; +// method_formal_parameter_target; +// throws_target; +// localvar_target; +// catch_target; +// offset_target; +// type_argument_target; +// } target_info; +// type_path target_path; +// annotation anno; +// } +// +bool VM_RedefineClasses::rewrite_cp_refs_in_type_annotation_struct( + AnnotationArray* type_annotations_typeArray, int &byte_i_ref, + const char * location_mesg, TRAPS) { + + if (!skip_type_annotation_target(type_annotations_typeArray, + byte_i_ref, location_mesg, THREAD)) { + return false; + } + + if (!skip_type_annotation_type_path(type_annotations_typeArray, + byte_i_ref, THREAD)) { + return false; + } + + if (!rewrite_cp_refs_in_annotation_struct(type_annotations_typeArray, + byte_i_ref, THREAD)) { + return false; + } + + return true; +} // end rewrite_cp_refs_in_type_annotation_struct() + + +// Read, verify and skip over the target_type and target_info part +// so that rewriting can continue in the later parts of the struct. +// +// u1 target_type; +// union { +// type_parameter_target; +// supertype_target; +// type_parameter_bound_target; +// empty_target; +// method_formal_parameter_target; +// throws_target; +// localvar_target; +// catch_target; +// offset_target; +// type_argument_target; +// } target_info; +// +bool VM_RedefineClasses::skip_type_annotation_target( + AnnotationArray* type_annotations_typeArray, int &byte_i_ref, + const char * location_mesg, TRAPS) { + + if ((byte_i_ref + 1) > type_annotations_typeArray->length()) { + // not enough room for a target_type let alone the rest of a type_annotation + RC_TRACE_WITH_THREAD(0x02000000, THREAD, + ("length() is too small for a target_type")); + return false; + } + + u1 target_type = type_annotations_typeArray->at(byte_i_ref); + byte_i_ref += 1; + RC_TRACE_WITH_THREAD(0x02000000, THREAD, ("target_type=0x%.2x", target_type)); + RC_TRACE_WITH_THREAD(0x02000000, THREAD, ("location=%s", location_mesg)); + + // Skip over target_info + switch (target_type) { + case 0x00: + // kind: type parameter declaration of generic class or interface + // location: ClassFile + case 0x01: + // kind: type parameter declaration of generic method or constructor + // location: method_info + + { + // struct: + // type_parameter_target { + // u1 type_parameter_index; + // } + // + if ((byte_i_ref + 1) > type_annotations_typeArray->length()) { + RC_TRACE_WITH_THREAD(0x02000000, THREAD, + ("length() is too small for a type_parameter_target")); + return false; + } + + u1 type_parameter_index = type_annotations_typeArray->at(byte_i_ref); + byte_i_ref += 1; + + RC_TRACE_WITH_THREAD(0x02000000, THREAD, + ("type_parameter_target: type_parameter_index=%d", + type_parameter_index)); + } break; + + case 0x10: + // kind: type in extends clause of class or interface declaration + // (including the direct superclass of an anonymous class declaration), + // or in implements clause of interface declaration + // location: ClassFile + + { + // struct: + // supertype_target { + // u2 supertype_index; + // } + // + if ((byte_i_ref + 2) > type_annotations_typeArray->length()) { + RC_TRACE_WITH_THREAD(0x02000000, THREAD, + ("length() is too small for a supertype_target")); + return false; + } + + u2 supertype_index = Bytes::get_Java_u2((address) + type_annotations_typeArray->adr_at(byte_i_ref)); + byte_i_ref += 2; + + RC_TRACE_WITH_THREAD(0x02000000, THREAD, + ("supertype_target: supertype_index=%d", supertype_index)); + } break; + + case 0x11: + // kind: type in bound of type parameter declaration of generic class or interface + // location: ClassFile + case 0x12: + // kind: type in bound of type parameter declaration of generic method or constructor + // location: method_info + + { + // struct: + // type_parameter_bound_target { + // u1 type_parameter_index; + // u1 bound_index; + // } + // + if ((byte_i_ref + 2) > type_annotations_typeArray->length()) { + RC_TRACE_WITH_THREAD(0x02000000, THREAD, + ("length() is too small for a type_parameter_bound_target")); + return false; + } + + u1 type_parameter_index = type_annotations_typeArray->at(byte_i_ref); + byte_i_ref += 1; + u1 bound_index = type_annotations_typeArray->at(byte_i_ref); + byte_i_ref += 1; + + RC_TRACE_WITH_THREAD(0x02000000, THREAD, + ("type_parameter_bound_target: type_parameter_index=%d, bound_index=%d", + type_parameter_index, bound_index)); + } break; + + case 0x13: + // kind: type in field declaration + // location: field_info + case 0x14: + // kind: return type of method, or type of newly constructed object + // location: method_info + case 0x15: + // kind: receiver type of method or constructor + // location: method_info + + { + // struct: + // empty_target { + // } + // + RC_TRACE_WITH_THREAD(0x02000000, THREAD, + ("empty_target")); + } break; + + case 0x16: + // kind: type in formal parameter declaration of method, constructor, or lambda expression + // location: method_info + + { + // struct: + // formal_parameter_target { + // u1 formal_parameter_index; + // } + // + if ((byte_i_ref + 1) > type_annotations_typeArray->length()) { + RC_TRACE_WITH_THREAD(0x02000000, THREAD, + ("length() is too small for a formal_parameter_target")); + return false; + } + + u1 formal_parameter_index = type_annotations_typeArray->at(byte_i_ref); + byte_i_ref += 1; + + RC_TRACE_WITH_THREAD(0x02000000, THREAD, + ("formal_parameter_target: formal_parameter_index=%d", + formal_parameter_index)); + } break; + + case 0x17: + // kind: type in throws clause of method or constructor + // location: method_info + + { + // struct: + // throws_target { + // u2 throws_type_index + // } + // + if ((byte_i_ref + 2) > type_annotations_typeArray->length()) { + RC_TRACE_WITH_THREAD(0x02000000, THREAD, + ("length() is too small for a throws_target")); + return false; + } + + u2 throws_type_index = Bytes::get_Java_u2((address) + type_annotations_typeArray->adr_at(byte_i_ref)); + byte_i_ref += 2; + + RC_TRACE_WITH_THREAD(0x02000000, THREAD, + ("throws_target: throws_type_index=%d", throws_type_index)); + } break; + + case 0x40: + // kind: type in local variable declaration + // location: Code + case 0x41: + // kind: type in resource variable declaration + // location: Code + + { + // struct: + // localvar_target { + // u2 table_length; + // struct { + // u2 start_pc; + // u2 length; + // u2 index; + // } table[table_length]; + // } + // + if ((byte_i_ref + 2) > type_annotations_typeArray->length()) { + // not enough room for a table_length let alone the rest of a localvar_target + RC_TRACE_WITH_THREAD(0x02000000, THREAD, + ("length() is too small for a localvar_target table_length")); + return false; + } + + u2 table_length = Bytes::get_Java_u2((address) + type_annotations_typeArray->adr_at(byte_i_ref)); + byte_i_ref += 2; + + RC_TRACE_WITH_THREAD(0x02000000, THREAD, + ("localvar_target: table_length=%d", table_length)); + + int table_struct_size = 2 + 2 + 2; // 3 u2 variables per table entry + int table_size = table_length * table_struct_size; + + if ((byte_i_ref + table_size) > type_annotations_typeArray->length()) { + // not enough room for a table + RC_TRACE_WITH_THREAD(0x02000000, THREAD, + ("length() is too small for a table array of length %d", table_length)); + return false; + } + + // Skip over table + byte_i_ref += table_size; + } break; + + case 0x42: + // kind: type in exception parameter declaration + // location: Code + + { + // struct: + // catch_target { + // u2 exception_table_index; + // } + // + if ((byte_i_ref + 2) > type_annotations_typeArray->length()) { + RC_TRACE_WITH_THREAD(0x02000000, THREAD, + ("length() is too small for a catch_target")); + return false; + } + + u2 exception_table_index = Bytes::get_Java_u2((address) + type_annotations_typeArray->adr_at(byte_i_ref)); + byte_i_ref += 2; + + RC_TRACE_WITH_THREAD(0x02000000, THREAD, + ("catch_target: exception_table_index=%d", exception_table_index)); + } break; + + case 0x43: + // kind: type in instanceof expression + // location: Code + case 0x44: + // kind: type in new expression + // location: Code + case 0x45: + // kind: type in method reference expression using ::new + // location: Code + case 0x46: + // kind: type in method reference expression using ::Identifier + // location: Code + + { + // struct: + // offset_target { + // u2 offset; + // } + // + if ((byte_i_ref + 2) > type_annotations_typeArray->length()) { + RC_TRACE_WITH_THREAD(0x02000000, THREAD, + ("length() is too small for a offset_target")); + return false; + } + + u2 offset = Bytes::get_Java_u2((address) + type_annotations_typeArray->adr_at(byte_i_ref)); + byte_i_ref += 2; + + RC_TRACE_WITH_THREAD(0x02000000, THREAD, + ("offset_target: offset=%d", offset)); + } break; + + case 0x47: + // kind: type in cast expression + // location: Code + case 0x48: + // kind: type argument for generic constructor in new expression or + // explicit constructor invocation statement + // location: Code + case 0x49: + // kind: type argument for generic method in method invocation expression + // location: Code + case 0x4A: + // kind: type argument for generic constructor in method reference expression using ::new + // location: Code + case 0x4B: + // kind: type argument for generic method in method reference expression using ::Identifier + // location: Code + + { + // struct: + // type_argument_target { + // u2 offset; + // u1 type_argument_index; + // } + // + if ((byte_i_ref + 3) > type_annotations_typeArray->length()) { + RC_TRACE_WITH_THREAD(0x02000000, THREAD, + ("length() is too small for a type_argument_target")); + return false; + } + + u2 offset = Bytes::get_Java_u2((address) + type_annotations_typeArray->adr_at(byte_i_ref)); + byte_i_ref += 2; + u1 type_argument_index = type_annotations_typeArray->at(byte_i_ref); + byte_i_ref += 1; + + RC_TRACE_WITH_THREAD(0x02000000, THREAD, + ("type_argument_target: offset=%d, type_argument_index=%d", + offset, type_argument_index)); + } break; + + default: + RC_TRACE_WITH_THREAD(0x02000000, THREAD, + ("unknown target_type")); +#ifdef ASSERT + ShouldNotReachHere(); +#endif + return false; + } + + return true; +} // end skip_type_annotation_target() + + +// Read, verify and skip over the type_path part so that rewriting +// can continue in the later parts of the struct. +// +// type_path { +// u1 path_length; +// { +// u1 type_path_kind; +// u1 type_argument_index; +// } path[path_length]; +// } +// +bool VM_RedefineClasses::skip_type_annotation_type_path( + AnnotationArray* type_annotations_typeArray, int &byte_i_ref, TRAPS) { + + if ((byte_i_ref + 1) > type_annotations_typeArray->length()) { + // not enough room for a path_length let alone the rest of the type_path + RC_TRACE_WITH_THREAD(0x02000000, THREAD, + ("length() is too small for a type_path")); + return false; + } + + u1 path_length = type_annotations_typeArray->at(byte_i_ref); + byte_i_ref += 1; + + RC_TRACE_WITH_THREAD(0x02000000, THREAD, + ("type_path: path_length=%d", path_length)); + + int calc_path_length = 0; + for (; calc_path_length < path_length; calc_path_length++) { + if ((byte_i_ref + 1 + 1) > type_annotations_typeArray->length()) { + // not enough room for a path + RC_TRACE_WITH_THREAD(0x02000000, THREAD, + ("length() is too small for path entry %d of %d", + calc_path_length, path_length)); + return false; + } + + u1 type_path_kind = type_annotations_typeArray->at(byte_i_ref); + byte_i_ref += 1; + u1 type_argument_index = type_annotations_typeArray->at(byte_i_ref); + byte_i_ref += 1; + + RC_TRACE_WITH_THREAD(0x02000000, THREAD, + ("type_path: path[%d]: type_path_kind=%d, type_argument_index=%d", + calc_path_length, type_path_kind, type_argument_index)); + + if (type_path_kind > 3 || (type_path_kind != 3 && type_argument_index != 0)) { + // not enough room for a path + RC_TRACE_WITH_THREAD(0x02000000, THREAD, + ("inconsistent type_path values")); + return false; + } + } + assert(path_length == calc_path_length, "sanity check"); + + return true; +} // end skip_type_annotation_type_path() + + // Rewrite constant pool references in the method's stackmap table. // These "structures" are adapted from the StackMapTable_attribute that // is described in section 4.8.4 of the 6.0 version of the VM spec @@ -3223,23 +3828,6 @@ void VM_RedefineClasses::swap_annotations(instanceKlassHandle the_class, instanceKlassHandle scratch_class) { - // Since there is currently no rewriting of type annotations indexes - // into the CP, we null out type annotations on scratch_class before - // we swap annotations with the_class rather than facing the - // possibility of shipping annotations with broken indexes to - // Java-land. - ClassLoaderData* loader_data = scratch_class->class_loader_data(); - AnnotationArray* new_class_type_annotations = scratch_class->class_type_annotations(); - if (new_class_type_annotations != NULL) { - MetadataFactory::free_array<u1>(loader_data, new_class_type_annotations); - scratch_class->annotations()->set_class_type_annotations(NULL); - } - Array<AnnotationArray*>* new_field_type_annotations = scratch_class->fields_type_annotations(); - if (new_field_type_annotations != NULL) { - Annotations::free_contents(loader_data, new_field_type_annotations); - scratch_class->annotations()->set_fields_type_annotations(NULL); - } - // Swap annotation fields values Annotations* old_annotations = the_class->annotations(); the_class->set_annotations(scratch_class->annotations());
--- a/src/share/vm/prims/jvmtiRedefineClasses.hpp Thu Jan 08 12:47:32 2015 +0000 +++ b/src/share/vm/prims/jvmtiRedefineClasses.hpp Tue Feb 03 16:48:05 2015 +0000 @@ -457,6 +457,17 @@ instanceKlassHandle scratch_class, TRAPS); bool rewrite_cp_refs_in_element_value( AnnotationArray* class_annotations, int &byte_i_ref, TRAPS); + bool rewrite_cp_refs_in_type_annotations_typeArray( + AnnotationArray* type_annotations_typeArray, int &byte_i_ref, + const char * location_mesg, TRAPS); + bool rewrite_cp_refs_in_type_annotation_struct( + AnnotationArray* type_annotations_typeArray, int &byte_i_ref, + const char * location_mesg, TRAPS); + bool skip_type_annotation_target( + AnnotationArray* type_annotations_typeArray, int &byte_i_ref, + const char * location_mesg, TRAPS); + bool skip_type_annotation_type_path( + AnnotationArray* type_annotations_typeArray, int &byte_i_ref, TRAPS); bool rewrite_cp_refs_in_fields_annotations( instanceKlassHandle scratch_class, TRAPS); void rewrite_cp_refs_in_method(methodHandle method, @@ -468,6 +479,12 @@ instanceKlassHandle scratch_class, TRAPS); bool rewrite_cp_refs_in_methods_parameter_annotations( instanceKlassHandle scratch_class, TRAPS); + bool rewrite_cp_refs_in_class_type_annotations( + instanceKlassHandle scratch_class, TRAPS); + bool rewrite_cp_refs_in_fields_type_annotations( + instanceKlassHandle scratch_class, TRAPS); + bool rewrite_cp_refs_in_methods_type_annotations( + instanceKlassHandle scratch_class, TRAPS); void rewrite_cp_refs_in_stack_map_table(methodHandle method, TRAPS); void rewrite_cp_refs_in_verification_type_info( address& stackmap_addr_ref, address stackmap_end, u2 frame_i,
--- a/src/share/vm/prims/methodHandles.cpp Thu Jan 08 12:47:32 2015 +0000 +++ b/src/share/vm/prims/methodHandles.cpp Tue Feb 03 16:48:05 2015 +0000 @@ -29,7 +29,6 @@ #include "interpreter/oopMapCache.hpp" #include "memory/allocation.inline.hpp" #include "memory/oopFactory.hpp" -#include "prims/jvmtiRedefineClassesTrace.hpp" #include "prims/methodHandles.hpp" #include "runtime/compilationPolicy.hpp" #include "runtime/javaCalls.hpp" @@ -271,9 +270,12 @@ // This is done eagerly, since it is readily available without // constructing any new objects. // TO DO: maybe intern mname_oop - m->method_holder()->add_member_name(m->method_idnum(), mname); - - return mname(); + if (m->method_holder()->add_member_name(mname)) { + return mname(); + } else { + // Redefinition caused this to fail. Return NULL (and an exception?) + return NULL; + } } oop MethodHandles::init_field_MemberName(Handle mname, fieldDescriptor& fd, bool is_setter) { @@ -946,63 +948,27 @@ } } -void MemberNameTable::add_member_name(int index, jweak mem_name_wref) { +void MemberNameTable::add_member_name(jweak mem_name_wref) { assert_locked_or_safepoint(MemberNameTable_lock); - this->at_put_grow(index, mem_name_wref); -} - -// Return a member name oop or NULL. -oop MemberNameTable::get_member_name(int index) { - assert_locked_or_safepoint(MemberNameTable_lock); - - jweak ref = this->at(index); - oop mem_name = JNIHandles::resolve(ref); - return mem_name; + this->push(mem_name_wref); } #if INCLUDE_JVMTI -oop MemberNameTable::find_member_name_by_method(Method* old_method) { - assert_locked_or_safepoint(MemberNameTable_lock); - oop found = NULL; - int len = this->length(); - - for (int idx = 0; idx < len; idx++) { - oop mem_name = JNIHandles::resolve(this->at(idx)); - if (mem_name == NULL) { - continue; - } - Method* method = (Method*)java_lang_invoke_MemberName::vmtarget(mem_name); - if (method == old_method) { - found = mem_name; - break; - } - } - return found; -} - -// It is called at safepoint only +// It is called at safepoint only for RedefineClasses void MemberNameTable::adjust_method_entries(Method** old_methods, Method** new_methods, int methods_length, bool *trace_name_printed) { assert(SafepointSynchronize::is_at_safepoint(), "only called at safepoint"); - // search the MemberNameTable for uses of either obsolete or EMCP methods + // For each redefined method for (int j = 0; j < methods_length; j++) { Method* old_method = old_methods[j]; Method* new_method = new_methods[j]; - oop mem_name = find_member_name_by_method(old_method); - if (mem_name != NULL) { - java_lang_invoke_MemberName::adjust_vmtarget(mem_name, new_method); - if (RC_TRACE_IN_RANGE(0x00100000, 0x00400000)) { - if (!(*trace_name_printed)) { - // RC_TRACE_MESG macro has an embedded ResourceMark - RC_TRACE_MESG(("adjust: name=%s", - old_method->method_holder()->external_name())); - *trace_name_printed = true; - } - // RC_TRACE macro has an embedded ResourceMark - RC_TRACE(0x00400000, ("MemberName method update: %s(%s)", - new_method->name()->as_C_string(), - new_method->signature()->as_C_string())); + // search the MemberNameTable for uses of either obsolete or EMCP methods + for (int idx = 0; idx < length(); idx++) { + oop mem_name = JNIHandles::resolve(this->at(idx)); + if (mem_name != NULL) { + java_lang_invoke_MemberName::adjust_vmtarget(mem_name, old_method, new_method, + trace_name_printed); } } }
--- a/src/share/vm/prims/methodHandles.hpp Thu Jan 08 12:47:32 2015 +0000 +++ b/src/share/vm/prims/methodHandles.hpp Tue Feb 03 16:48:05 2015 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2008, 2014, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -239,18 +239,14 @@ public: MemberNameTable(int methods_cnt); ~MemberNameTable(); - void add_member_name(int index, jweak mem_name_ref); - oop get_member_name(int index); + void add_member_name(jweak mem_name_ref); #if INCLUDE_JVMTI - public: // RedefineClasses() API support: // If a MemberName refers to old_method then update it // to refer to new_method. void adjust_method_entries(Method** old_methods, Method** new_methods, int methods_length, bool *trace_name_printed); - private: - oop find_member_name_by_method(Method* old_method); #endif // INCLUDE_JVMTI };
--- a/src/share/vm/prims/whitebox.cpp Thu Jan 08 12:47:32 2015 +0000 +++ b/src/share/vm/prims/whitebox.cpp Tue Feb 03 16:48:05 2015 +0000 @@ -56,6 +56,7 @@ #endif // INCLUDE_NMT #include "compiler/compileBroker.hpp" +#include "jvmtifiles/jvmtiEnv.hpp" #include "runtime/compilationPolicy.hpp" PRAGMA_FORMAT_MUTE_WARNINGS_FOR_GCC @@ -104,6 +105,51 @@ return closure.found(); WB_END +WB_ENTRY(jboolean, WB_ClassKnownToNotExist(JNIEnv* env, jobject o, jobject loader, jstring name)) + ThreadToNativeFromVM ttnfv(thread); // can't be in VM when we call JNI + const char* class_name = env->GetStringUTFChars(name, NULL); + jboolean result = JVM_KnownToNotExist(env, loader, class_name); + env->ReleaseStringUTFChars(name, class_name); + return result; +WB_END + +WB_ENTRY(jobjectArray, WB_GetLookupCacheURLs(JNIEnv* env, jobject o, jobject loader)) + ThreadToNativeFromVM ttnfv(thread); // can't be in VM when we call JNI + return JVM_GetResourceLookupCacheURLs(env, loader); +WB_END + +WB_ENTRY(jintArray, WB_GetLookupCacheMatches(JNIEnv* env, jobject o, jobject loader, jstring name)) + ThreadToNativeFromVM ttnfv(thread); // can't be in VM when we call JNI + const char* resource_name = env->GetStringUTFChars(name, NULL); + jintArray result = JVM_GetResourceLookupCache(env, loader, resource_name); + + env->ReleaseStringUTFChars(name, resource_name); + return result; +WB_END + +WB_ENTRY(void, WB_AddToBootstrapClassLoaderSearch(JNIEnv* env, jobject o, jstring segment)) { +#if INCLUDE_JVMTI + ResourceMark rm; + const char* seg = java_lang_String::as_utf8_string(JNIHandles::resolve_non_null(segment)); + JvmtiEnv* jvmti_env = JvmtiEnv::create_a_jvmti(JVMTI_VERSION); + jvmtiError err = jvmti_env->AddToBootstrapClassLoaderSearch(seg); + assert(err == JVMTI_ERROR_NONE, "must not fail"); +#endif +} +WB_END + +WB_ENTRY(void, WB_AddToSystemClassLoaderSearch(JNIEnv* env, jobject o, jstring segment)) { +#if INCLUDE_JVMTI + ResourceMark rm; + const char* seg = java_lang_String::as_utf8_string(JNIHandles::resolve_non_null(segment)); + JvmtiEnv* jvmti_env = JvmtiEnv::create_a_jvmti(JVMTI_VERSION); + jvmtiError err = jvmti_env->AddToSystemClassLoaderSearch(seg); + assert(err == JVMTI_ERROR_NONE, "must not fail"); +#endif +} +WB_END + + WB_ENTRY(jlong, WB_GetCompressedOopsMaxHeapSize(JNIEnv* env, jobject o)) { return (jlong)Arguments::max_heap_for_compressed_oops(); } @@ -278,7 +324,7 @@ // NMT picks it up correctly WB_ENTRY(jlong, WB_NMTMalloc(JNIEnv* env, jobject o, jlong size)) jlong addr = 0; - addr = (jlong)(uintptr_t)os::malloc(size, mtTest); + addr = (jlong)(uintptr_t)os::malloc(size, mtTest); return addr; WB_END @@ -287,7 +333,7 @@ WB_ENTRY(jlong, WB_NMTMallocWithPseudoStack(JNIEnv* env, jobject o, jlong size, jint pseudo_stack)) address pc = (address)(size_t)pseudo_stack; NativeCallStack stack(&pc, 1); - return (jlong)os::malloc(size, mtTest, stack); + return (jlong)(uintptr_t)os::malloc(size, mtTest, stack); WB_END // Free the memory allocated by NMTAllocTest @@ -322,15 +368,6 @@ return MemTracker::tracking_level() == NMT_detail; WB_END -WB_ENTRY(void, WB_NMTOverflowHashBucket(JNIEnv* env, jobject o, jlong num)) - address pc = (address)1; - for (jlong index = 0; index < num; index ++) { - NativeCallStack stack(&pc, 1); - os::malloc(0, mtTest, stack); - pc += MallocSiteTable::hash_buckets(); - } -WB_END - WB_ENTRY(jboolean, WB_NMTChangeTrackingLevel(JNIEnv* env)) // Test that we can downgrade NMT levels but not upgrade them. if (MemTracker::tracking_level() == NMT_off) { @@ -361,6 +398,12 @@ return MemTracker::tracking_level() == NMT_minimal; } WB_END + +WB_ENTRY(jint, WB_NMTGetHashSize(JNIEnv* env, jobject o)) + int hash_size = MallocSiteTable::hash_buckets(); + assert(hash_size > 0, "NMT hash_size should be > 0"); + return (jint)hash_size; +WB_END #endif // INCLUDE_NMT static jmethodID reflected_method_to_jmid(JavaThread* thread, JNIEnv* env, jobject method) { @@ -382,19 +425,10 @@ CHECK_JNI_EXCEPTION_(env, result); MutexLockerEx mu(Compile_lock); methodHandle mh(THREAD, Method::checked_resolve_jmethod_id(jmid)); - nmethod* code; if (is_osr) { - int bci = InvocationEntryBci; - while ((code = mh->lookup_osr_nmethod_for(bci, CompLevel_none, false)) != NULL) { - code->mark_for_deoptimization(); - ++result; - bci = code->osr_entry_bci() + 1; - } - } else { - code = mh->code(); - } - if (code != NULL) { - code->mark_for_deoptimization(); + result += mh->mark_osr_nmethods(); + } else if (mh->code() != NULL) { + mh->code()->mark_for_deoptimization(); ++result; } result += CodeCache::mark_for_deoptimization(mh()); @@ -939,10 +973,19 @@ {CC"isObjectInOldGen", CC"(Ljava/lang/Object;)Z", (void*)&WB_isObjectInOldGen }, {CC"getHeapOopSize", CC"()I", (void*)&WB_GetHeapOopSize }, {CC"isClassAlive0", CC"(Ljava/lang/String;)Z", (void*)&WB_IsClassAlive }, + {CC"classKnownToNotExist", + CC"(Ljava/lang/ClassLoader;Ljava/lang/String;)Z",(void*)&WB_ClassKnownToNotExist}, + {CC"getLookupCacheURLs", CC"(Ljava/lang/ClassLoader;)[Ljava/net/URL;", (void*)&WB_GetLookupCacheURLs}, + {CC"getLookupCacheMatches", CC"(Ljava/lang/ClassLoader;Ljava/lang/String;)[I", + (void*)&WB_GetLookupCacheMatches}, {CC"parseCommandLine", CC"(Ljava/lang/String;[Lsun/hotspot/parser/DiagnosticCommand;)[Ljava/lang/Object;", (void*) &WB_ParseCommandLine }, + {CC"addToBootstrapClassLoaderSearch", CC"(Ljava/lang/String;)V", + (void*)&WB_AddToBootstrapClassLoaderSearch}, + {CC"addToSystemClassLoaderSearch", CC"(Ljava/lang/String;)V", + (void*)&WB_AddToSystemClassLoaderSearch}, {CC"getCompressedOopsMaxHeapSize", CC"()J", (void*)&WB_GetCompressedOopsMaxHeapSize}, {CC"printHeapSizes", CC"()V", (void*)&WB_PrintHeapSizes }, @@ -963,9 +1006,9 @@ {CC"NMTCommitMemory", CC"(JJ)V", (void*)&WB_NMTCommitMemory }, {CC"NMTUncommitMemory", CC"(JJ)V", (void*)&WB_NMTUncommitMemory }, {CC"NMTReleaseMemory", CC"(JJ)V", (void*)&WB_NMTReleaseMemory }, - {CC"NMTOverflowHashBucket", CC"(J)V", (void*)&WB_NMTOverflowHashBucket}, {CC"NMTIsDetailSupported",CC"()Z", (void*)&WB_NMTIsDetailSupported}, {CC"NMTChangeTrackingLevel", CC"()Z", (void*)&WB_NMTChangeTrackingLevel}, + {CC"NMTGetHashSize", CC"()I", (void*)&WB_NMTGetHashSize }, #endif // INCLUDE_NMT {CC"deoptimizeAll", CC"()V", (void*)&WB_DeoptimizeAll }, {CC"deoptimizeMethod", CC"(Ljava/lang/reflect/Executable;Z)I",
--- a/src/share/vm/runtime/advancedThresholdPolicy.cpp Thu Jan 08 12:47:32 2015 +0000 +++ b/src/share/vm/runtime/advancedThresholdPolicy.cpp Tue Feb 03 16:48:05 2015 +0000 @@ -316,8 +316,8 @@ * 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, because it'll allow it to run much faster without full profiling while c2 - * is compiling. + * 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 @@ -451,7 +451,7 @@ if (should_create_mdo(mh(), level)) { create_mdo(mh, thread); } - if (is_compilation_enabled() && !CompileBroker::compilation_is_in_queue(mh, InvocationEntryBci)) { + if (is_compilation_enabled() && !CompileBroker::compilation_is_in_queue(mh)) { CompLevel next_level = call_event(mh(), level); if (next_level != level) { compile(mh, InvocationEntryBci, next_level, thread); @@ -475,7 +475,7 @@ CompLevel next_osr_level = loop_event(imh(), level); 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, bci) && next_osr_level != level) { + if (!CompileBroker::compilation_is_in_queue(imh) && (next_osr_level != level)) { compile(imh, bci, next_osr_level, thread); } @@ -509,7 +509,7 @@ nm->make_not_entrant(); } } - if (!CompileBroker::compilation_is_in_queue(mh, InvocationEntryBci)) { + if (!CompileBroker::compilation_is_in_queue(mh)) { // 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; @@ -521,7 +521,7 @@ } else { cur_level = comp_level(imh()); next_level = call_event(imh(), cur_level); - if (!CompileBroker::compilation_is_in_queue(imh, bci) && next_level != cur_level) { + if (!CompileBroker::compilation_is_in_queue(imh) && (next_level != cur_level)) { compile(imh, InvocationEntryBci, next_level, thread); } }
--- a/src/share/vm/runtime/arguments.cpp Thu Jan 08 12:47:32 2015 +0000 +++ b/src/share/vm/runtime/arguments.cpp Tue Feb 03 16:48:05 2015 +0000 @@ -66,7 +66,7 @@ #endif // INCLUDE_ALL_GCS // Note: This is a special bug reporting site for the JVM -#define DEFAULT_VENDOR_URL_BUG "http://bugreport.sun.com/bugreport/crash.jsp" +#define DEFAULT_VENDOR_URL_BUG "http://bugreport.java.com/bugreport/crash.jsp" #define DEFAULT_JAVA_LAUNCHER "generic" // Disable options not supported in this release, with a warning if they @@ -300,6 +300,7 @@ { "UseStringCache", JDK_Version::jdk(8), JDK_Version::jdk(9) }, { "UseOldInlining", JDK_Version::jdk(9), JDK_Version::jdk(10) }, { "AutoShutdownNMT", JDK_Version::jdk(9), JDK_Version::jdk(10) }, + { "CompilationRepeat", JDK_Version::jdk(8), JDK_Version::jdk(9) }, #ifdef PRODUCT { "DesiredMethodLimit", JDK_Version::jdk_update(7, 2), JDK_Version::jdk(8) }, @@ -1146,6 +1147,32 @@ } } +/** + * Returns the minimum number of compiler threads needed to run the JVM. The following + * configurations are possible. + * + * 1) The JVM is build using an interpreter only. As a result, the minimum number of + * compiler threads is 0. + * 2) The JVM is build using the compiler(s) and tiered compilation is disabled. As + * a result, either C1 or C2 is used, so the minimum number of compiler threads is 1. + * 3) The JVM is build using the compiler(s) and tiered compilation is enabled. However, + * the option "TieredStopAtLevel < CompLevel_full_optimization". As a result, only + * C1 can be used, so the minimum number of compiler threads is 1. + * 4) The JVM is build using the compilers and tiered compilation is enabled. The option + * 'TieredStopAtLevel = CompLevel_full_optimization' (the default value). As a result, + * the minimum number of compiler threads is 2. + */ +int Arguments::get_min_number_of_compiler_threads() { +#if !defined(COMPILER1) && !defined(COMPILER2) && !defined(SHARK) + return 0; // case 1 +#else + if (!TieredCompilation || (TieredStopAtLevel < CompLevel_full_optimization)) { + return 1; // case 2 or case 3 + } + return 2; // case 4 (tiered) +#endif +} + #if INCLUDE_ALL_GCS static void disable_adaptive_size_policy(const char* collector_name) { if (UseAdaptiveSizePolicy) { @@ -2207,7 +2234,7 @@ FLAG_SET_DEFAULT(UseGCOverheadLimit, false); } - status = status && ArgumentsExt::check_gc_consistency_user(); + status = status && check_gc_consistency_user(); status = status && check_stack_pages(); if (CMSIncrementalMode) { @@ -2462,6 +2489,12 @@ status &= verify_interval(SafepointPollOffset, 0, os::vm_page_size() - BytesPerWord, "SafepointPollOffset"); #endif + int min_number_of_compiler_threads = get_min_number_of_compiler_threads(); + // The default CICompilerCount's value is CI_COMPILER_COUNT. + assert(min_number_of_compiler_threads <= CI_COMPILER_COUNT, "minimum should be less or equal default number"); + // Check the minimum number of compiler threads + status &=verify_min_value(CICompilerCount, min_number_of_compiler_threads, "CICompilerCount"); + return status; } @@ -2930,6 +2963,23 @@ #endif // -D } else if (match_option(option, "-D", &tail)) { + if (CheckEndorsedAndExtDirs) { + if (match_option(option, "-Djava.endorsed.dirs=", &tail)) { + // abort if -Djava.endorsed.dirs is set + jio_fprintf(defaultStream::output_stream(), + "-Djava.endorsed.dirs will not be supported in a future release.\n" + "Refer to JEP 220 for details (http://openjdk.java.net/jeps/220).\n"); + return JNI_EINVAL; + } + if (match_option(option, "-Djava.ext.dirs=", &tail)) { + // abort if -Djava.ext.dirs is set + jio_fprintf(defaultStream::output_stream(), + "-Djava.ext.dirs will not be supported in a future release.\n" + "Refer to JEP 220 for details (http://openjdk.java.net/jeps/220).\n"); + return JNI_EINVAL; + } + } + if (!add_property(tail)) { return JNI_ENOMEM; } @@ -3363,6 +3413,146 @@ } } +static bool has_jar_files(const char* directory) { + DIR* dir = os::opendir(directory); + if (dir == NULL) return false; + + struct dirent *entry; + char *dbuf = NEW_C_HEAP_ARRAY(char, os::readdir_buf_size(directory), mtInternal); + bool hasJarFile = false; + while (!hasJarFile && (entry = os::readdir(dir, (dirent *) dbuf)) != NULL) { + const char* name = entry->d_name; + const char* ext = name + strlen(name) - 4; + hasJarFile = ext > name && (os::file_name_strcmp(ext, ".jar") == 0); + } + FREE_C_HEAP_ARRAY(char, dbuf, mtInternal); + os::closedir(dir); + return hasJarFile ; +} + +// returns the number of directories in the given path containing JAR files +// If the skip argument is not NULL, it will skip that directory +static int check_non_empty_dirs(const char* path, const char* type, const char* skip) { + const char separator = *os::path_separator(); + const char* const end = path + strlen(path); + int nonEmptyDirs = 0; + while (path < end) { + const char* tmp_end = strchr(path, separator); + if (tmp_end == NULL) { + if ((skip == NULL || strcmp(path, skip) != 0) && has_jar_files(path)) { + nonEmptyDirs++; + jio_fprintf(defaultStream::output_stream(), + "Non-empty %s directory: %s\n", type, path); + } + path = end; + } else { + char* dirpath = NEW_C_HEAP_ARRAY(char, tmp_end - path + 1, mtInternal); + memcpy(dirpath, path, tmp_end - path); + dirpath[tmp_end - path] = '\0'; + if ((skip == NULL || strcmp(dirpath, skip) != 0) && has_jar_files(dirpath)) { + nonEmptyDirs++; + jio_fprintf(defaultStream::output_stream(), + "Non-empty %s directory: %s\n", type, dirpath); + } + FREE_C_HEAP_ARRAY(char, dirpath, mtInternal); + path = tmp_end + 1; + } + } + return nonEmptyDirs; +} + +// Returns true if endorsed standards override mechanism and extension mechanism +// are not used. +static bool check_endorsed_and_ext_dirs() { + if (!CheckEndorsedAndExtDirs) + return true; + + char endorsedDir[JVM_MAXPATHLEN]; + char extDir[JVM_MAXPATHLEN]; + const char* fileSep = os::file_separator(); + jio_snprintf(endorsedDir, sizeof(endorsedDir), "%s%slib%sendorsed", + Arguments::get_java_home(), fileSep, fileSep); + jio_snprintf(extDir, sizeof(extDir), "%s%slib%sext", + Arguments::get_java_home(), fileSep, fileSep); + + // check endorsed directory + int nonEmptyDirs = check_non_empty_dirs(Arguments::get_endorsed_dir(), "endorsed", NULL); + + // check the extension directories but skip the default lib/ext directory + nonEmptyDirs += check_non_empty_dirs(Arguments::get_ext_dirs(), "extension", extDir); + + // List of JAR files installed in the default lib/ext directory. + // -XX:+CheckEndorsedAndExtDirs checks if any non-JDK file installed + static const char* jdk_ext_jars[] = { + "access-bridge-32.jar", + "access-bridge-64.jar", + "access-bridge.jar", + "cldrdata.jar", + "dnsns.jar", + "jaccess.jar", + "jfxrt.jar", + "localedata.jar", + "nashorn.jar", + "sunec.jar", + "sunjce_provider.jar", + "sunmscapi.jar", + "sunpkcs11.jar", + "ucrypto.jar", + "zipfs.jar", + NULL + }; + + // check if the default lib/ext directory has any non-JDK jar files; if so, error + DIR* dir = os::opendir(extDir); + if (dir != NULL) { + int num_ext_jars = 0; + struct dirent *entry; + char *dbuf = NEW_C_HEAP_ARRAY(char, os::readdir_buf_size(extDir), mtInternal); + while ((entry = os::readdir(dir, (dirent *) dbuf)) != NULL) { + const char* name = entry->d_name; + const char* ext = name + strlen(name) - 4; + if (ext > name && (os::file_name_strcmp(ext, ".jar") == 0)) { + bool is_jdk_jar = false; + const char* jarfile = NULL; + for (int i=0; (jarfile = jdk_ext_jars[i]) != NULL; i++) { + if (os::file_name_strcmp(name, jarfile) == 0) { + is_jdk_jar = true; + break; + } + } + if (!is_jdk_jar) { + jio_fprintf(defaultStream::output_stream(), + "%s installed in <JAVA_HOME>/lib/ext\n", name); + num_ext_jars++; + } + } + } + FREE_C_HEAP_ARRAY(char, dbuf, mtInternal); + os::closedir(dir); + if (num_ext_jars > 0) { + nonEmptyDirs += 1; + } + } + + // check if the default lib/endorsed directory exists; if so, error + dir = os::opendir(endorsedDir); + if (dir != NULL) { + jio_fprintf(defaultStream::output_stream(), "<JAVA_HOME>/lib/endorsed exists\n"); + os::closedir(dir); + nonEmptyDirs += 1; + } + + if (nonEmptyDirs > 0) { + jio_fprintf(defaultStream::output_stream(), + "Endorsed standards override mechanism and extension mechanism " + "will not be supported in a future release.\n" + "Refer to JEP 220 for details (http://openjdk.java.net/jeps/220).\n"); + return false; + } + + return true; +} + jint Arguments::finalize_vm_init_args(SysClassPath* scp_p, bool scp_assembly_required) { // This must be done after all -D arguments have been processed. scp_p->expand_endorsed(); @@ -3372,6 +3562,10 @@ Arguments::set_sysclasspath(scp_p->combined_path()); } + if (!check_endorsed_and_ext_dirs()) { + return JNI_ERR; + } + // This must be done after all arguments have been processed. // java_compiler() true means set to "NONE" or empty. if (java_compiler() && !xdebug_mode()) { @@ -3432,7 +3626,7 @@ } } - if (!ArgumentsExt::check_vm_args_consistency()) { + if (!check_vm_args_consistency()) { return JNI_ERR; } @@ -3618,6 +3812,8 @@ bool settings_file_specified = false; bool needs_hotspotrc_warning = false; + ArgumentsExt::process_options(args); + const char* flags_file; int index; for (index = 0; index < args->nOptions; index++) { @@ -3833,7 +4029,7 @@ // Set heap size based on available physical memory set_heap_size(); - set_gc_specific_flags(); + ArgumentsExt::set_gc_specific_flags(); // Initialize Metaspace flags and alignments. Metaspace::ergo_initialize();
--- a/src/share/vm/runtime/arguments.hpp Thu Jan 08 12:47:32 2015 +0000 +++ b/src/share/vm/runtime/arguments.hpp Tue Feb 03 16:48:05 2015 +0000 @@ -327,6 +327,7 @@ // Tiered static void set_tiered_flags(); + static int get_min_number_of_compiler_threads(); // CMS/ParNew garbage collectors static void set_parnew_gc_flags(); static void set_cms_and_parnew_gc_flags(); @@ -341,7 +342,6 @@ static void select_gc(); static void set_ergonomics_flags(); static void set_shared_spaces_flags(); - static void set_gc_specific_flags(); // limits the given memory size by the maximum amount of memory this process is // currently allowed to allocate or reserve. static julong limit_by_allocatable_memory(julong size); @@ -453,6 +453,7 @@ // Adjusts the arguments after the OS have adjusted the arguments static jint adjust_after_os(); + static void set_gc_specific_flags(); static inline bool gc_selected(); // whether a gc has been selected static void select_gc_ergonomically();
--- a/src/share/vm/runtime/arguments_ext.hpp Thu Jan 08 12:47:32 2015 +0000 +++ b/src/share/vm/runtime/arguments_ext.hpp Tue Feb 03 16:48:05 2015 +0000 @@ -31,25 +31,21 @@ class ArgumentsExt: AllStatic { public: static inline void select_gc_ergonomically(); - static inline bool check_gc_consistency_user(); + static inline void set_gc_specific_flags(); static inline bool check_gc_consistency_ergo(); - static inline bool check_vm_args_consistency(); + static void process_options(const JavaVMInitArgs* args) {} }; void ArgumentsExt::select_gc_ergonomically() { Arguments::select_gc_ergonomically(); } -bool ArgumentsExt::check_gc_consistency_user() { - return Arguments::check_gc_consistency_user(); +void ArgumentsExt::set_gc_specific_flags() { + Arguments::set_gc_specific_flags(); } bool ArgumentsExt::check_gc_consistency_ergo() { return Arguments::check_gc_consistency_ergo(); } -bool ArgumentsExt::check_vm_args_consistency() { - return Arguments::check_vm_args_consistency(); -} - #endif // SHARE_VM_RUNTIME_ARGUMENTS_EXT_HPP
--- a/src/share/vm/runtime/deoptimization.cpp Thu Jan 08 12:47:32 2015 +0000 +++ b/src/share/vm/runtime/deoptimization.cpp Tue Feb 03 16:48:05 2015 +0000 @@ -219,6 +219,8 @@ assert(vf->is_compiled_frame(), "Wrong frame type"); chunk->push(compiledVFrame::cast(vf)); + bool realloc_failures = false; + #ifdef COMPILER2 // Reallocate the non-escaping objects and restore their fields. Then // relock objects if synchronization on them was eliminated. @@ -249,19 +251,16 @@ tty->print_cr("SAVED OOP RESULT " INTPTR_FORMAT " in thread " INTPTR_FORMAT, (void *)result, thread); } } - bool reallocated = false; if (objects != NULL) { JRT_BLOCK - reallocated = realloc_objects(thread, &deoptee, objects, THREAD); + realloc_failures = realloc_objects(thread, &deoptee, objects, THREAD); JRT_END - } - if (reallocated) { - reassign_fields(&deoptee, &map, objects); + reassign_fields(&deoptee, &map, objects, realloc_failures); #ifndef PRODUCT if (TraceDeoptimization) { ttyLocker ttyl; tty->print_cr("REALLOC OBJECTS in thread " INTPTR_FORMAT, thread); - print_objects(objects); + print_objects(objects, realloc_failures); } #endif } @@ -279,7 +278,7 @@ assert (cvf->scope() != NULL,"expect only compiled java frames"); GrowableArray<MonitorInfo*>* monitors = cvf->monitors(); if (monitors->is_nonempty()) { - relock_objects(monitors, thread); + relock_objects(monitors, thread, realloc_failures); #ifndef PRODUCT if (TraceDeoptimization) { ttyLocker ttyl; @@ -290,7 +289,12 @@ first = false; tty->print_cr("RELOCK OBJECTS in thread " INTPTR_FORMAT, thread); } - tty->print_cr(" object <" INTPTR_FORMAT "> locked", (void *)mi->owner()); + if (mi->owner_is_scalar_replaced()) { + Klass* k = java_lang_Class::as_Klass(mi->owner_klass()); + tty->print_cr(" failed reallocation for klass %s", k->external_name()); + } else { + tty->print_cr(" object <" INTPTR_FORMAT "> locked", (void *)mi->owner()); + } } } } @@ -305,9 +309,14 @@ // out the java state residing in the vframeArray will be missed. No_Safepoint_Verifier no_safepoint; - vframeArray* array = create_vframeArray(thread, deoptee, &map, chunk); + vframeArray* array = create_vframeArray(thread, deoptee, &map, chunk, realloc_failures); +#ifdef COMPILER2 + if (realloc_failures) { + pop_frames_failed_reallocs(thread, array); + } +#endif - assert(thread->vframe_array_head() == NULL, "Pending deopt!");; + assert(thread->vframe_array_head() == NULL, "Pending deopt!"); thread->set_vframe_array_head(array); // Now that the vframeArray has been created if we have any deferred local writes @@ -759,6 +768,8 @@ int exception_line = thread->exception_line(); thread->clear_pending_exception(); + bool failures = false; + for (int i = 0; i < objects->length(); i++) { assert(objects->at(i)->is_object(), "invalid debug information"); ObjectValue* sv = (ObjectValue*) objects->at(i); @@ -768,27 +779,34 @@ if (k->oop_is_instance()) { InstanceKlass* ik = InstanceKlass::cast(k()); - obj = ik->allocate_instance(CHECK_(false)); + obj = ik->allocate_instance(THREAD); } else if (k->oop_is_typeArray()) { TypeArrayKlass* ak = TypeArrayKlass::cast(k()); assert(sv->field_size() % type2size[ak->element_type()] == 0, "non-integral array length"); int len = sv->field_size() / type2size[ak->element_type()]; - obj = ak->allocate(len, CHECK_(false)); + obj = ak->allocate(len, THREAD); } else if (k->oop_is_objArray()) { ObjArrayKlass* ak = ObjArrayKlass::cast(k()); - obj = ak->allocate(sv->field_size(), CHECK_(false)); + obj = ak->allocate(sv->field_size(), THREAD); } - assert(obj != NULL, "allocation failed"); + if (obj == NULL) { + failures = true; + } + assert(sv->value().is_null(), "redundant reallocation"); + assert(obj != NULL || HAS_PENDING_EXCEPTION, "allocation should succeed or we should get an exception"); + CLEAR_PENDING_EXCEPTION; sv->set_value(obj); } - if (pending_exception.not_null()) { + if (failures) { + THROW_OOP_(Universe::out_of_memory_error_realloc_objects(), failures); + } else if (pending_exception.not_null()) { thread->set_pending_exception(pending_exception(), exception_file, exception_line); } - return true; + return failures; } // This assumes that the fields are stored in ObjectValue in the same order @@ -926,12 +944,15 @@ // restore fields of all eliminated objects and arrays -void Deoptimization::reassign_fields(frame* fr, RegisterMap* reg_map, GrowableArray<ScopeValue*>* objects) { +void Deoptimization::reassign_fields(frame* fr, RegisterMap* reg_map, GrowableArray<ScopeValue*>* objects, bool realloc_failures) { for (int i = 0; i < objects->length(); i++) { ObjectValue* sv = (ObjectValue*) objects->at(i); KlassHandle k(java_lang_Class::as_Klass(sv->klass()->as_ConstantOopReadValue()->value()())); Handle obj = sv->value(); - assert(obj.not_null(), "reallocation was missed"); + assert(obj.not_null() || realloc_failures, "reallocation was missed"); + if (obj.is_null()) { + continue; + } if (k->oop_is_instance()) { InstanceKlass* ik = InstanceKlass::cast(k()); @@ -948,34 +969,36 @@ // relock objects for which synchronization was eliminated -void Deoptimization::relock_objects(GrowableArray<MonitorInfo*>* monitors, JavaThread* thread) { +void Deoptimization::relock_objects(GrowableArray<MonitorInfo*>* monitors, JavaThread* thread, bool realloc_failures) { for (int i = 0; i < monitors->length(); i++) { MonitorInfo* mon_info = monitors->at(i); if (mon_info->eliminated()) { - assert(mon_info->owner() != NULL, "reallocation was missed"); - Handle obj = Handle(mon_info->owner()); - markOop mark = obj->mark(); - if (UseBiasedLocking && mark->has_bias_pattern()) { - // New allocated objects may have the mark set to anonymously biased. - // Also the deoptimized method may called methods with synchronization - // where the thread-local object is bias locked to the current thread. - assert(mark->is_biased_anonymously() || - mark->biased_locker() == thread, "should be locked to current thread"); - // Reset mark word to unbiased prototype. - markOop unbiased_prototype = markOopDesc::prototype()->set_age(mark->age()); - obj->set_mark(unbiased_prototype); + assert(!mon_info->owner_is_scalar_replaced() || realloc_failures, "reallocation was missed"); + if (!mon_info->owner_is_scalar_replaced()) { + Handle obj = Handle(mon_info->owner()); + markOop mark = obj->mark(); + if (UseBiasedLocking && mark->has_bias_pattern()) { + // New allocated objects may have the mark set to anonymously biased. + // Also the deoptimized method may called methods with synchronization + // where the thread-local object is bias locked to the current thread. + assert(mark->is_biased_anonymously() || + mark->biased_locker() == thread, "should be locked to current thread"); + // Reset mark word to unbiased prototype. + markOop unbiased_prototype = markOopDesc::prototype()->set_age(mark->age()); + obj->set_mark(unbiased_prototype); + } + BasicLock* lock = mon_info->lock(); + ObjectSynchronizer::slow_enter(obj, lock, thread); + assert(mon_info->owner()->is_locked(), "object must be locked now"); } - BasicLock* lock = mon_info->lock(); - ObjectSynchronizer::slow_enter(obj, lock, thread); } - assert(mon_info->owner()->is_locked(), "object must be locked now"); } } #ifndef PRODUCT // print information about reallocated objects -void Deoptimization::print_objects(GrowableArray<ScopeValue*>* objects) { +void Deoptimization::print_objects(GrowableArray<ScopeValue*>* objects, bool realloc_failures) { fieldDescriptor fd; for (int i = 0; i < objects->length(); i++) { @@ -985,10 +1008,15 @@ tty->print(" object <" INTPTR_FORMAT "> of type ", (void *)sv->value()()); k->print_value(); - tty->print(" allocated (%d bytes)", obj->size() * HeapWordSize); + assert(obj.not_null() || realloc_failures, "reallocation was missed"); + if (obj.is_null()) { + tty->print(" allocation failed"); + } else { + tty->print(" allocated (%d bytes)", obj->size() * HeapWordSize); + } tty->cr(); - if (Verbose) { + if (Verbose && !obj.is_null()) { k->oop_print_on(obj(), tty); } } @@ -996,7 +1024,7 @@ #endif #endif // COMPILER2 -vframeArray* Deoptimization::create_vframeArray(JavaThread* thread, frame fr, RegisterMap *reg_map, GrowableArray<compiledVFrame*>* chunk) { +vframeArray* Deoptimization::create_vframeArray(JavaThread* thread, frame fr, RegisterMap *reg_map, GrowableArray<compiledVFrame*>* chunk, bool realloc_failures) { Events::log(thread, "DEOPT PACKING pc=" INTPTR_FORMAT " sp=" INTPTR_FORMAT, fr.pc(), fr.sp()); #ifndef PRODUCT @@ -1039,7 +1067,7 @@ // Since the Java thread being deoptimized will eventually adjust it's own stack, // the vframeArray containing the unpacking information is allocated in the C heap. // For Compiler1, the caller of the deoptimized frame is saved for use by unpack_frames(). - vframeArray* array = vframeArray::allocate(thread, frame_size, chunk, reg_map, sender, caller, fr); + vframeArray* array = vframeArray::allocate(thread, frame_size, chunk, reg_map, sender, caller, fr, realloc_failures); // Compare the vframeArray to the collected vframes assert(array->structural_compare(thread, chunk), "just checking"); @@ -1054,6 +1082,33 @@ return array; } +#ifdef COMPILER2 +void Deoptimization::pop_frames_failed_reallocs(JavaThread* thread, vframeArray* array) { + // Reallocation of some scalar replaced objects failed. Record + // that we need to pop all the interpreter frames for the + // deoptimized compiled frame. + assert(thread->frames_to_pop_failed_realloc() == 0, "missed frames to pop?"); + thread->set_frames_to_pop_failed_realloc(array->frames()); + // Unlock all monitors here otherwise the interpreter will see a + // mix of locked and unlocked monitors (because of failed + // reallocations of synchronized objects) and be confused. + for (int i = 0; i < array->frames(); i++) { + MonitorChunk* monitors = array->element(i)->monitors(); + if (monitors != NULL) { + for (int j = 0; j < monitors->number_of_monitors(); j++) { + BasicObjectLock* src = monitors->at(j); + if (src->obj() != NULL) { + ObjectSynchronizer::fast_exit(src->obj(), src->lock(), thread); + } + } + array->element(i)->free_monitors(thread); +#ifdef ASSERT + array->element(i)->set_removed_monitors(); +#endif + } + } +} +#endif static void collect_monitors(compiledVFrame* cvf, GrowableArray<Handle>* objects_to_revoke) { GrowableArray<MonitorInfo*>* monitors = cvf->monitors();
--- a/src/share/vm/runtime/deoptimization.hpp Thu Jan 08 12:47:32 2015 +0000 +++ b/src/share/vm/runtime/deoptimization.hpp Tue Feb 03 16:48:05 2015 +0000 @@ -120,13 +120,14 @@ static bool realloc_objects(JavaThread* thread, frame* fr, GrowableArray<ScopeValue*>* objects, TRAPS); static void reassign_type_array_elements(frame* fr, RegisterMap* reg_map, ObjectValue* sv, typeArrayOop obj, BasicType type); static void reassign_object_array_elements(frame* fr, RegisterMap* reg_map, ObjectValue* sv, objArrayOop obj); - static void reassign_fields(frame* fr, RegisterMap* reg_map, GrowableArray<ScopeValue*>* objects); - static void relock_objects(GrowableArray<MonitorInfo*>* monitors, JavaThread* thread); - NOT_PRODUCT(static void print_objects(GrowableArray<ScopeValue*>* objects);) + static void reassign_fields(frame* fr, RegisterMap* reg_map, GrowableArray<ScopeValue*>* objects, bool realloc_failures); + static void relock_objects(GrowableArray<MonitorInfo*>* monitors, JavaThread* thread, bool realloc_failures); + static void pop_frames_failed_reallocs(JavaThread* thread, vframeArray* array); + NOT_PRODUCT(static void print_objects(GrowableArray<ScopeValue*>* objects, bool realloc_failures);) #endif // COMPILER2 public: - static vframeArray* create_vframeArray(JavaThread* thread, frame fr, RegisterMap *reg_map, GrowableArray<compiledVFrame*>* chunk); + static vframeArray* create_vframeArray(JavaThread* thread, frame fr, RegisterMap *reg_map, GrowableArray<compiledVFrame*>* chunk, bool realloc_failures); // Interface used for unpacking deoptimized frames
--- a/src/share/vm/runtime/globals.cpp Thu Jan 08 12:47:32 2015 +0000 +++ b/src/share/vm/runtime/globals.cpp Tue Feb 03 16:48:05 2015 +0000 @@ -243,6 +243,11 @@ return is_unlocked_ext(); } +void Flag::unlock_diagnostic() { + assert(is_diagnostic(), "sanity"); + _flags = Flags(_flags & ~KIND_DIAGNOSTIC); +} + // Get custom message for this locked flag, or return NULL if // none is available. void Flag::get_locked_message(char* buf, int buflen) const {
--- a/src/share/vm/runtime/globals.hpp Thu Jan 08 12:47:32 2015 +0000 +++ b/src/share/vm/runtime/globals.hpp Tue Feb 03 16:48:05 2015 +0000 @@ -325,6 +325,8 @@ bool is_writeable_ext() const; bool is_external_ext() const; + void unlock_diagnostic(); + void get_locked_message(char*, int) const; void get_locked_message_ext(char*, int) const; @@ -1220,6 +1222,9 @@ product(bool, CheckJNICalls, false, \ "Verify all arguments to JNI calls") \ \ + product(bool, CheckEndorsedAndExtDirs, false, \ + "Verify the endorsed and extension directories are not used") \ + \ product(bool, UseFastJNIAccessors, false, \ "Use optimized versions of Get<Primitive>Field") \ \
--- a/src/share/vm/runtime/interfaceSupport.cpp Thu Jan 08 12:47:32 2015 +0000 +++ b/src/share/vm/runtime/interfaceSupport.cpp Tue Feb 03 16:48:05 2015 +0000 @@ -85,7 +85,7 @@ // Short-circuit any possible re-entrant gc-a-lot attempt if (thread->skip_gcalot()) return; - if (is_init_completed()) { + if (Threads::is_vm_complete()) { if (++_fullgc_alot_invocation < FullGCALotStart) { return;
--- a/src/share/vm/runtime/os.cpp Thu Jan 08 12:47:32 2015 +0000 +++ b/src/share/vm/runtime/os.cpp Tue Feb 03 16:48:05 2015 +0000 @@ -571,17 +571,6 @@ NOT_PRODUCT(inc_stat_counter(&num_mallocs, 1)); NOT_PRODUCT(inc_stat_counter(&alloc_bytes, size)); -#if INCLUDE_NMT - // NMT can not track malloc allocation size > MAX_MALLOC_SIZE, which is - // (1GB - 1) on 32-bit system. It is not an issue on 64-bit system, where - // MAX_MALLOC_SIZE = ((1 << 62) - 1). - // VM code does not have such large malloc allocation. However, it can come - // Unsafe call. - if (MemTracker::tracking_level() >= NMT_summary && size > MAX_MALLOC_SIZE) { - return NULL; - } -#endif - #ifdef ASSERT // checking for the WatcherThread and crash_protection first // since os::malloc can be called when the libjvm.{dll,so} is @@ -652,12 +641,6 @@ } void* os::realloc(void *memblock, size_t size, MEMFLAGS memflags, const NativeCallStack& stack) { -#if INCLUDE_NMT - // See comments in os::malloc() above - if (MemTracker::tracking_level() >= NMT_summary && size > MAX_MALLOC_SIZE) { - return NULL; - } -#endif #ifndef ASSERT NOT_PRODUCT(inc_stat_counter(&num_mallocs, 1));
--- a/src/share/vm/runtime/sharedRuntime.cpp Thu Jan 08 12:47:32 2015 +0000 +++ b/src/share/vm/runtime/sharedRuntime.cpp Tue Feb 03 16:48:05 2015 +0000 @@ -490,6 +490,7 @@ address SharedRuntime::raw_exception_handler_for_return_address(JavaThread* thread, address return_address) { assert(frame::verify_return_pc(return_address), err_msg("must be a return address: " INTPTR_FORMAT, return_address)); + assert(thread->frames_to_pop_failed_realloc() == 0 || Interpreter::contains(return_address), "missed frames to pop?"); // Reset method handle flag. thread->set_is_method_handle_return(false);
--- a/src/share/vm/runtime/simpleThresholdPolicy.cpp Thu Jan 08 12:47:32 2015 +0000 +++ b/src/share/vm/runtime/simpleThresholdPolicy.cpp Tue Feb 03 16:48:05 2015 +0000 @@ -196,7 +196,6 @@ // Don't trigger other compiles in testing mode return NULL; } - nmethod *osr_nm = NULL; handle_counter_overflow(method()); if (method() != inlinee()) { @@ -210,14 +209,16 @@ 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); - // method == inlinee if the event originated in the main method - int highest_level = inlinee->highest_osr_comp_level(); - if (highest_level > comp_level) { - osr_nm = inlinee->lookup_osr_nmethod_for(bci, highest_level, false); + // Check if event led to a higher level OSR compilation + nmethod* osr_nm = inlinee->lookup_osr_nmethod_for(bci, comp_level, false); + if (osr_nm != NULL && osr_nm->comp_level() > comp_level) { + // Perform OSR with new nmethod + return osr_nm; } } - return osr_nm; + return NULL; } // Check if the method can be compiled, change level if necessary @@ -239,7 +240,7 @@ if (bci != InvocationEntryBci && mh->is_not_osr_compilable(level)) { return; } - if (!CompileBroker::compilation_is_in_queue(mh, bci)) { + if (!CompileBroker::compilation_is_in_queue(mh)) { if (PrintTieredEvents) { print_event(COMPILE, mh, mh, bci, level); } @@ -378,7 +379,7 @@ // Handle the invocation event. void SimpleThresholdPolicy::method_invocation_event(methodHandle mh, methodHandle imh, CompLevel level, nmethod* nm, JavaThread* thread) { - if (is_compilation_enabled() && !CompileBroker::compilation_is_in_queue(mh, InvocationEntryBci)) { + if (is_compilation_enabled() && !CompileBroker::compilation_is_in_queue(mh)) { CompLevel next_level = call_event(mh(), level); if (next_level != level) { compile(mh, InvocationEntryBci, next_level, thread); @@ -391,8 +392,8 @@ void SimpleThresholdPolicy::method_back_branch_event(methodHandle mh, methodHandle imh, int bci, CompLevel level, nmethod* nm, JavaThread* thread) { // If the method is already compiling, quickly bail out. - if (is_compilation_enabled() && !CompileBroker::compilation_is_in_queue(mh, bci)) { - // Use loop event as an opportinity to also check there's been + if (is_compilation_enabled() && !CompileBroker::compilation_is_in_queue(mh)) { + // Use loop event as an opportunity to also check there's been // enough calls. CompLevel cur_level = comp_level(mh()); CompLevel next_level = call_event(mh(), cur_level);
--- a/src/share/vm/runtime/simpleThresholdPolicy.inline.hpp Thu Jan 08 12:47:32 2015 +0000 +++ b/src/share/vm/runtime/simpleThresholdPolicy.inline.hpp Tue Feb 03 16:48:05 2015 +0000 @@ -54,13 +54,17 @@ // Simple methods are as good being compiled with C1 as C2. // Determine if a given method is such a case. bool SimpleThresholdPolicy::is_trivial(Method* method) { - if (method->is_accessor()) return true; - if (method->code() != NULL) { - MethodData* mdo = method->method_data(); - if (mdo != NULL && mdo->num_loops() == 0 && - (method->code_size() < 5 || (mdo->num_blocks() < 4) && (method->code_size() < 15))) { - return !mdo->would_profile(); - } + if (method->is_accessor() || + method->is_constant_getter()) { + return true; + } + if (method->has_loops() || method->code_size() >= 15) { + return false; + } + MethodData* mdo = method->method_data(); + if (mdo != NULL && !mdo->would_profile() && + (method->code_size() < 5 || (mdo->num_blocks() < 4))) { + return true; } return false; }
--- a/src/share/vm/runtime/thread.cpp Thu Jan 08 12:47:32 2015 +0000 +++ b/src/share/vm/runtime/thread.cpp Tue Feb 03 16:48:05 2015 +0000 @@ -234,6 +234,8 @@ // This initial value ==> never claimed. _oops_do_parity = 0; + _metadata_on_stack_buffer = NULL; + // the handle mark links itself to last_handle_mark new HandleMark(this); @@ -1493,6 +1495,7 @@ _popframe_condition = popframe_inactive; _popframe_preserved_args = NULL; _popframe_preserved_args_size = 0; + _frames_to_pop_failed_realloc = 0; pd_initialize(); }
--- a/src/share/vm/runtime/thread.hpp Thu Jan 08 12:47:32 2015 +0000 +++ b/src/share/vm/runtime/thread.hpp Tue Feb 03 16:48:05 2015 +0000 @@ -42,11 +42,10 @@ #include "runtime/threadLocalStorage.hpp" #include "runtime/thread_ext.hpp" #include "runtime/unhandledOops.hpp" -#include "utilities/macros.hpp" - #include "trace/traceBackend.hpp" #include "trace/traceMacros.hpp" #include "utilities/exceptions.hpp" +#include "utilities/macros.hpp" #include "utilities/top.hpp" #if INCLUDE_ALL_GCS #include "gc_implementation/g1/dirtyCardQueue.hpp" @@ -83,6 +82,10 @@ class ThreadClosure; class IdealGraphPrinter; +class Metadata; +template <class T, MEMFLAGS F> class ChunkedList; +typedef ChunkedList<Metadata*, mtInternal> MetadataOnStackBuffer; + DEBUG_ONLY(class ResourceMark;) class WorkerThread; @@ -256,6 +259,9 @@ jlong _allocated_bytes; // Cumulative number of bytes allocated on // the Java heap + // Thread-local buffer used by MetadataOnStackMark. + MetadataOnStackBuffer* _metadata_on_stack_buffer; + TRACE_DATA _trace_data; // Thread-local data for tracing ThreadExt _ext; @@ -517,7 +523,10 @@ // creation fails due to lack of memory, too many threads etc. bool set_as_starting_thread(); - protected: + void set_metadata_on_stack_buffer(MetadataOnStackBuffer* buffer) { _metadata_on_stack_buffer = buffer; } + MetadataOnStackBuffer* metadata_on_stack_buffer() const { return _metadata_on_stack_buffer; } + +protected: // OS data associated with the thread OSThread* _osthread; // Platform-specific thread information @@ -924,6 +933,12 @@ // This is set to popframe_pending to signal that top Java frame should be popped immediately int _popframe_condition; + // If reallocation of scalar replaced objects fails, we throw OOM + // and during exception propagation, pop the top + // _frames_to_pop_failed_realloc frames, the ones that reference + // failed reallocations. + int _frames_to_pop_failed_realloc; + #ifndef PRODUCT int _jmp_ring_index; struct { @@ -1576,6 +1591,10 @@ void clr_pop_frame_in_process(void) { _popframe_condition &= ~popframe_processing_bit; } #endif + int frames_to_pop_failed_realloc() const { return _frames_to_pop_failed_realloc; } + void set_frames_to_pop_failed_realloc(int nb) { _frames_to_pop_failed_realloc = nb; } + void dec_frames_to_pop_failed_realloc() { _frames_to_pop_failed_realloc--; } + private: // Saved incoming arguments to popped frame. // Used only when popped interpreted frame returns to deoptimized frame.
--- a/src/share/vm/runtime/vframeArray.cpp Thu Jan 08 12:47:32 2015 +0000 +++ b/src/share/vm/runtime/vframeArray.cpp Tue Feb 03 16:48:05 2015 +0000 @@ -56,7 +56,7 @@ } } -void vframeArrayElement::fill_in(compiledVFrame* vf) { +void vframeArrayElement::fill_in(compiledVFrame* vf, bool realloc_failures) { // Copy the information from the compiled vframe to the // interpreter frame we will be creating to replace vf @@ -64,6 +64,9 @@ _method = vf->method(); _bci = vf->raw_bci(); _reexecute = vf->should_reexecute(); +#ifdef ASSERT + _removed_monitors = false; +#endif int index; @@ -81,11 +84,15 @@ // Migrate the BasicLocks from the stack to the monitor chunk for (index = 0; index < list->length(); index++) { MonitorInfo* monitor = list->at(index); - assert(!monitor->owner_is_scalar_replaced(), "object should be reallocated already"); - assert(monitor->owner() == NULL || (!monitor->owner()->is_unlocked() && !monitor->owner()->has_bias_pattern()), "object must be null or locked, and unbiased"); + assert(!monitor->owner_is_scalar_replaced() || realloc_failures, "object should be reallocated already"); BasicObjectLock* dest = _monitors->at(index); - dest->set_obj(monitor->owner()); - monitor->lock()->move_to(monitor->owner(), dest->lock()); + if (monitor->owner_is_scalar_replaced()) { + dest->set_obj(NULL); + } else { + assert(monitor->owner() == NULL || (!monitor->owner()->is_unlocked() && !monitor->owner()->has_bias_pattern()), "object must be null or locked, and unbiased"); + dest->set_obj(monitor->owner()); + monitor->lock()->move_to(monitor->owner(), dest->lock()); + } } } @@ -110,7 +117,7 @@ StackValue* value = locs->at(index); switch(value->type()) { case T_OBJECT: - assert(!value->obj_is_scalar_replaced(), "object should be reallocated already"); + assert(!value->obj_is_scalar_replaced() || realloc_failures, "object should be reallocated already"); // preserve object type _locals->add( new StackValue(cast_from_oop<intptr_t>((value->get_obj()())), T_OBJECT )); break; @@ -135,7 +142,7 @@ StackValue* value = exprs->at(index); switch(value->type()) { case T_OBJECT: - assert(!value->obj_is_scalar_replaced(), "object should be reallocated already"); + assert(!value->obj_is_scalar_replaced() || realloc_failures, "object should be reallocated already"); // preserve object type _expressions->add( new StackValue(cast_from_oop<intptr_t>((value->get_obj()())), T_OBJECT )); break; @@ -286,7 +293,7 @@ _frame.patch_pc(thread, pc); - assert (!method()->is_synchronized() || locks > 0, "synchronized methods must have monitors"); + assert (!method()->is_synchronized() || locks > 0 || _removed_monitors, "synchronized methods must have monitors"); BasicObjectLock* top = iframe()->interpreter_frame_monitor_begin(); for (int index = 0; index < locks; index++) { @@ -438,7 +445,8 @@ vframeArray* vframeArray::allocate(JavaThread* thread, int frame_size, GrowableArray<compiledVFrame*>* chunk, - RegisterMap *reg_map, frame sender, frame caller, frame self) { + RegisterMap *reg_map, frame sender, frame caller, frame self, + bool realloc_failures) { // Allocate the vframeArray vframeArray * result = (vframeArray*) AllocateHeap(sizeof(vframeArray) + // fixed part @@ -450,19 +458,20 @@ result->_caller = caller; result->_original = self; result->set_unroll_block(NULL); // initialize it - result->fill_in(thread, frame_size, chunk, reg_map); + result->fill_in(thread, frame_size, chunk, reg_map, realloc_failures); return result; } void vframeArray::fill_in(JavaThread* thread, int frame_size, GrowableArray<compiledVFrame*>* chunk, - const RegisterMap *reg_map) { + const RegisterMap *reg_map, + bool realloc_failures) { // Set owner first, it is used when adding monitor chunks _frame_size = frame_size; for(int i = 0; i < chunk->length(); i++) { - element(i)->fill_in(chunk->at(i)); + element(i)->fill_in(chunk->at(i), realloc_failures); } // Copy registers for callee-saved registers
--- a/src/share/vm/runtime/vframeArray.hpp Thu Jan 08 12:47:32 2015 +0000 +++ b/src/share/vm/runtime/vframeArray.hpp Tue Feb 03 16:48:05 2015 +0000 @@ -58,6 +58,9 @@ MonitorChunk* _monitors; // active monitors for this vframe StackValueCollection* _locals; StackValueCollection* _expressions; +#ifdef ASSERT + bool _removed_monitors; +#endif public: @@ -78,7 +81,7 @@ StackValueCollection* expressions(void) const { return _expressions; } - void fill_in(compiledVFrame* vf); + void fill_in(compiledVFrame* vf, bool realloc_failures); // Formerly part of deoptimizedVFrame @@ -99,6 +102,12 @@ bool is_bottom_frame, int exec_mode); +#ifdef ASSERT + void set_removed_monitors() { + _removed_monitors = true; + } +#endif + #ifndef PRODUCT void print(outputStream* st); #endif /* PRODUCT */ @@ -160,13 +169,14 @@ int frames() const { return _frames; } static vframeArray* allocate(JavaThread* thread, int frame_size, GrowableArray<compiledVFrame*>* chunk, - RegisterMap* reg_map, frame sender, frame caller, frame self); + RegisterMap* reg_map, frame sender, frame caller, frame self, + bool realloc_failures); vframeArrayElement* element(int index) { assert(is_within_bounds(index), "Bad index"); return &_elements[index]; } // Allocates a new vframe in the array and fills the array with vframe information in chunk - void fill_in(JavaThread* thread, int frame_size, GrowableArray<compiledVFrame*>* chunk, const RegisterMap *reg_map); + void fill_in(JavaThread* thread, int frame_size, GrowableArray<compiledVFrame*>* chunk, const RegisterMap *reg_map, bool realloc_failures); // Returns the owner of this vframeArray JavaThread* owner_thread() const { return _owner_thread; }
--- a/src/share/vm/runtime/vmStructs.cpp Thu Jan 08 12:47:32 2015 +0000 +++ b/src/share/vm/runtime/vmStructs.cpp Tue Feb 03 16:48:05 2015 +0000 @@ -680,6 +680,7 @@ static_field(SystemDictionary, WK_KLASS(WeakReference_klass), Klass*) \ static_field(SystemDictionary, WK_KLASS(FinalReference_klass), Klass*) \ static_field(SystemDictionary, WK_KLASS(PhantomReference_klass), Klass*) \ + static_field(SystemDictionary, WK_KLASS(Cleaner_klass), Klass*) \ static_field(SystemDictionary, WK_KLASS(Finalizer_klass), Klass*) \ static_field(SystemDictionary, WK_KLASS(Thread_klass), Klass*) \ static_field(SystemDictionary, WK_KLASS(ThreadGroup_klass), Klass*) \
--- a/src/share/vm/services/mallocTracker.cpp Thu Jan 08 12:47:32 2015 +0000 +++ b/src/share/vm/services/mallocTracker.cpp Tue Feb 03 16:48:05 2015 +0000 @@ -72,7 +72,7 @@ MallocMemorySummary::record_free(size(), flags()); MallocMemorySummary::record_free_malloc_header(sizeof(MallocHeader)); - if (tracking_level() == NMT_detail) { + if (MemTracker::tracking_level() == NMT_detail) { MallocSiteTable::deallocation_at(size(), _bucket_idx, _pos_idx); } } @@ -128,36 +128,18 @@ } // Uses placement global new operator to initialize malloc header - switch(level) { - case NMT_off: - return malloc_base; - case NMT_minimal: { - MallocHeader* hdr = ::new (malloc_base) MallocHeader(); - break; - } - case NMT_summary: { - assert(size <= MAX_MALLOC_SIZE, "malloc size overrun for NMT"); - header = ::new (malloc_base) MallocHeader(size, flags); - break; - } - case NMT_detail: { - assert(size <= MAX_MALLOC_SIZE, "malloc size overrun for NMT"); - header = ::new (malloc_base) MallocHeader(size, flags, stack); - break; - } - default: - ShouldNotReachHere(); + + if (level == NMT_off) { + return malloc_base; } + + header = ::new (malloc_base)MallocHeader(size, flags, stack, level); memblock = (void*)((char*)malloc_base + sizeof(MallocHeader)); // The alignment check: 8 bytes alignment for 32 bit systems. // 16 bytes alignment for 64-bit systems. assert(((size_t)memblock & (sizeof(size_t) * 2 - 1)) == 0, "Alignment check"); - // Sanity check - assert(get_memory_tracking_level(memblock) == level, - "Wrong tracking level"); - #ifdef ASSERT if (level > NMT_minimal) { // Read back
--- a/src/share/vm/services/mallocTracker.hpp Thu Jan 08 12:47:32 2015 +0000 +++ b/src/share/vm/services/mallocTracker.hpp Tue Feb 03 16:48:05 2015 +0000 @@ -239,68 +239,46 @@ class MallocHeader VALUE_OBJ_CLASS_SPEC { #ifdef _LP64 - size_t _size : 62; - size_t _level : 2; + size_t _size : 64; size_t _flags : 8; size_t _pos_idx : 16; size_t _bucket_idx: 40; -#define MAX_MALLOCSITE_TABLE_SIZE ((size_t)1 << 40) -#define MAX_BUCKET_LENGTH ((size_t)(1 << 16)) -#define MAX_MALLOC_SIZE (((size_t)1 << 62) - 1) +#define MAX_MALLOCSITE_TABLE_SIZE right_n_bits(40) +#define MAX_BUCKET_LENGTH right_n_bits(16) #else - size_t _size : 30; - size_t _level : 2; + size_t _size : 32; size_t _flags : 8; size_t _pos_idx : 8; size_t _bucket_idx: 16; -#define MAX_MALLOCSITE_TABLE_SIZE ((size_t)(1 << 16)) -#define MAX_BUCKET_LENGTH ((size_t)(1 << 8)) -// Max malloc size = 1GB - 1 on 32 bit system, such has total 4GB memory -#define MAX_MALLOC_SIZE ((size_t)(1 << 30) - 1) +#define MAX_MALLOCSITE_TABLE_SIZE right_n_bits(16) +#define MAX_BUCKET_LENGTH right_n_bits(8) #endif // _LP64 public: - // Summary tracking header - MallocHeader(size_t size, MEMFLAGS flags) { + MallocHeader(size_t size, MEMFLAGS flags, const NativeCallStack& stack, NMT_TrackingLevel level) { assert(sizeof(MallocHeader) == sizeof(void*) * 2, "Wrong header size"); - _level = NMT_summary; - _flags = flags; - set_size(size); - MallocMemorySummary::record_malloc(size, flags); - MallocMemorySummary::record_new_malloc_header(sizeof(MallocHeader)); - } - // Detail tracking header - MallocHeader(size_t size, MEMFLAGS flags, const NativeCallStack& stack) { - assert(sizeof(MallocHeader) == sizeof(void*) * 2, - "Wrong header size"); + if (level == NMT_minimal) { + return; + } - _level = NMT_detail; _flags = flags; set_size(size); - size_t bucket_idx; - size_t pos_idx; - if (record_malloc_site(stack, size, &bucket_idx, &pos_idx)) { - assert(bucket_idx <= MAX_MALLOCSITE_TABLE_SIZE, "Overflow bucket index"); - assert(pos_idx <= MAX_BUCKET_LENGTH, "Overflow bucket position index"); - _bucket_idx = bucket_idx; - _pos_idx = pos_idx; + if (level == NMT_detail) { + size_t bucket_idx; + size_t pos_idx; + if (record_malloc_site(stack, size, &bucket_idx, &pos_idx)) { + assert(bucket_idx <= MAX_MALLOCSITE_TABLE_SIZE, "Overflow bucket index"); + assert(pos_idx <= MAX_BUCKET_LENGTH, "Overflow bucket position index"); + _bucket_idx = bucket_idx; + _pos_idx = pos_idx; + } } + MallocMemorySummary::record_malloc(size, flags); MallocMemorySummary::record_new_malloc_header(sizeof(MallocHeader)); } - // Minimal tracking header - MallocHeader() { - assert(sizeof(MallocHeader) == sizeof(void*) * 2, - "Wrong header size"); - - _level = (unsigned short)NMT_minimal; - } - - inline NMT_TrackingLevel tracking_level() const { - return (NMT_TrackingLevel)_level; - } inline size_t size() const { return _size; } inline MEMFLAGS flags() const { return (MEMFLAGS)_flags; } @@ -311,7 +289,6 @@ private: inline void set_size(size_t size) { - assert(size <= MAX_MALLOC_SIZE, "Malloc size too large, should use virtual memory?"); _size = size; } bool record_malloc_site(const NativeCallStack& stack, size_t size, @@ -347,10 +324,6 @@ // Record free on specified memory block static void* record_free(void* memblock); - // Get tracking level of specified memory block - static inline NMT_TrackingLevel get_memory_tracking_level(void* memblock); - - // Offset memory address to header address static inline void* get_base(void* memblock); static inline void* get_base(void* memblock, NMT_TrackingLevel level) { @@ -361,16 +334,12 @@ // Get memory size static inline size_t get_size(void* memblock) { MallocHeader* header = malloc_header(memblock); - assert(header->tracking_level() >= NMT_summary, - "Wrong tracking level"); return header->size(); } // Get memory type static inline MEMFLAGS get_flags(void* memblock) { MallocHeader* header = malloc_header(memblock); - assert(header->tracking_level() >= NMT_summary, - "Wrong tracking level"); return header->flags(); } @@ -394,7 +363,6 @@ static inline MallocHeader* malloc_header(void *memblock) { assert(memblock != NULL, "NULL pointer"); MallocHeader* header = (MallocHeader*)((char*)memblock - sizeof(MallocHeader)); - assert(header->tracking_level() >= NMT_minimal, "Bad header"); return header; } };
--- a/src/share/vm/services/mallocTracker.inline.hpp Thu Jan 08 12:47:32 2015 +0000 +++ b/src/share/vm/services/mallocTracker.inline.hpp Tue Feb 03 16:48:05 2015 +0000 @@ -28,13 +28,6 @@ #include "services/mallocTracker.hpp" #include "services/memTracker.hpp" -inline NMT_TrackingLevel MallocTracker::get_memory_tracking_level(void* memblock) { - assert(memblock != NULL, "Sanity check"); - if (MemTracker::tracking_level() == NMT_off) return NMT_off; - MallocHeader* header = malloc_header(memblock); - return header->tracking_level(); -} - inline void* MallocTracker::get_base(void* memblock){ return get_base(memblock, MemTracker::tracking_level()); }
--- a/src/share/vm/services/runtimeService.cpp Thu Jan 08 12:47:32 2015 +0000 +++ b/src/share/vm/services/runtimeService.cpp Tue Feb 03 16:48:05 2015 +0000 @@ -46,6 +46,7 @@ PerfCounter* RuntimeService::_thread_interrupt_signaled_count = NULL; PerfCounter* RuntimeService::_interrupted_before_count = NULL; PerfCounter* RuntimeService::_interrupted_during_count = NULL; +double RuntimeService::_last_safepoint_sync_time_sec = 0.0; void RuntimeService::init() { // Make sure the VM version is initialized @@ -128,6 +129,7 @@ // update the time stamp to begin recording safepoint time _safepoint_timer.update(); + _last_safepoint_sync_time_sec = 0.0; if (UsePerfData) { _total_safepoints->inc(); if (_app_timer.is_updated()) { @@ -140,6 +142,9 @@ if (UsePerfData) { _sync_time_ticks->inc(_safepoint_timer.ticks_since_update()); } + if (PrintGCApplicationStoppedTime) { + _last_safepoint_sync_time_sec = last_safepoint_time_sec(); + } } void RuntimeService::record_safepoint_end() { @@ -155,8 +160,10 @@ gclog_or_tty->date_stamp(PrintGCDateStamps); gclog_or_tty->stamp(PrintGCTimeStamps); gclog_or_tty->print_cr("Total time for which application threads " - "were stopped: %3.7f seconds", - last_safepoint_time_sec()); + "were stopped: %3.7f seconds, " + "Stopping threads took: %3.7f seconds", + last_safepoint_time_sec(), + _last_safepoint_sync_time_sec); } // update the time stamp to begin recording app time
--- a/src/share/vm/services/runtimeService.hpp Thu Jan 08 12:47:32 2015 +0000 +++ b/src/share/vm/services/runtimeService.hpp Tue Feb 03 16:48:05 2015 +0000 @@ -40,6 +40,7 @@ static TimeStamp _safepoint_timer; static TimeStamp _app_timer; + static double _last_safepoint_sync_time_sec; public: static void init();
--- a/src/share/vm/trace/noTraceBackend.hpp Thu Jan 08 12:47:32 2015 +0000 +++ b/src/share/vm/trace/noTraceBackend.hpp Tue Feb 03 16:48:05 2015 +0000 @@ -41,4 +41,4 @@ typedef NoTraceBackend Tracing; -#endif +#endif // SHARE_VM_TRACE_NOTRACEBACKEND_HPP
--- a/src/share/vm/trace/traceBackend.hpp Thu Jan 08 12:47:32 2015 +0000 +++ b/src/share/vm/trace/traceBackend.hpp Tue Feb 03 16:48:05 2015 +0000 @@ -25,9 +25,7 @@ #define SHARE_VM_TRACE_TRACEBACKEND_HPP #include "utilities/macros.hpp" - #if INCLUDE_TRACE - #include "runtime/globals.hpp" #include "runtime/os.hpp" #include "trace/traceTime.hpp" @@ -58,9 +56,7 @@ typedef TraceBackend Tracing; -#else /* INCLUDE_TRACE */ - +#else // !INCLUDE_TRACE #include "trace/noTraceBackend.hpp" - -#endif /* INCLUDE_TRACE */ -#endif /* SHARE_VM_TRACE_TRACEBACKEND_HPP */ +#endif // INCLUDE_TRACE +#endif // SHARE_VM_TRACE_TRACEBACKEND_HPP
--- a/src/share/vm/trace/traceEvent.hpp Thu Jan 08 12:47:32 2015 +0000 +++ b/src/share/vm/trace/traceEvent.hpp Tue Feb 03 16:48:05 2015 +0000 @@ -33,7 +33,6 @@ }; #if INCLUDE_TRACE - #include "trace/traceBackend.hpp" #include "trace/tracing.hpp" #include "tracefiles/traceEventIds.hpp" @@ -154,6 +153,5 @@ } }; -#endif /* INCLUDE_TRACE */ - -#endif /* SHARE_VM_TRACE_TRACEEVENT_HPP */ +#endif // INCLUDE_TRACE +#endif // SHARE_VM_TRACE_TRACEEVENT_HPP
--- a/src/share/vm/trace/traceEventClasses.xsl Thu Jan 08 12:47:32 2015 +0000 +++ b/src/share/vm/trace/traceEventClasses.xsl Tue Feb 03 16:48:05 2015 +0000 @@ -41,17 +41,14 @@ #include "trace/traceEvent.hpp" #include "utilities/macros.hpp" #include "utilities/ticks.hpp" - #if INCLUDE_TRACE - - #include "trace/traceStream.hpp" #include "utilities/ostream.hpp" <xsl:apply-templates select="trace/events/struct" mode="trace"/> <xsl:apply-templates select="trace/events/event" mode="trace"/> -#else +#else // !INCLUDE_TRACE class TraceEvent { public: @@ -65,9 +62,8 @@ <xsl:apply-templates select="trace/events/struct" mode="empty"/> <xsl:apply-templates select="trace/events/event" mode="empty"/> -#endif - -#endif +#endif // INCLUDE_TRACE +#endif // TRACEFILES_TRACEEVENTCLASSES_HPP </xsl:template> <xsl:template match="struct" mode="trace">
--- a/src/share/vm/trace/traceEventIds.xsl Thu Jan 08 12:47:32 2015 +0000 +++ b/src/share/vm/trace/traceEventIds.xsl Tue Feb 03 16:48:05 2015 +0000 @@ -29,13 +29,11 @@ <xsl:template match="/"> <xsl:call-template name="file-header"/> -#ifndef TRACEFILES_JFREVENTIDS_HPP -#define TRACEFILES_JFREVENTIDS_HPP +#ifndef TRACEFILES_TRACEEVENTIDS_HPP +#define TRACEFILES_TRACEEVENTIDS_HPP #include "utilities/macros.hpp" - #if INCLUDE_TRACE - #include "trace/traceDataTypes.hpp" /** @@ -67,8 +65,8 @@ typedef enum TraceEventId TraceEventId; typedef enum TraceStructId TraceStructId; -#endif -#endif +#endif // INCLUDE_TRACE +#endif // TRACEFILES_TRACEEVENTIDS_HPP </xsl:template> </xsl:stylesheet>
--- a/src/share/vm/trace/traceMacros.hpp Thu Jan 08 12:47:32 2015 +0000 +++ b/src/share/vm/trace/traceMacros.hpp Tue Feb 03 16:48:05 2015 +0000 @@ -22,8 +22,8 @@ * */ -#ifndef SHARE_VM_TRACE_TRACE_MACRO_HPP -#define SHARE_VM_TRACE_TRACE_MACRO_HPP +#ifndef SHARE_VM_TRACE_TRACEMACROS_HPP +#define SHARE_VM_TRACE_TRACEMACROS_HPP #define EVENT_THREAD_EXIT(thread) #define EVENT_THREAD_DESTRUCT(thread) @@ -41,4 +41,4 @@ #define TRACE_TEMPLATES(template) #define TRACE_INTRINSICS(do_intrinsic, do_class, do_name, do_signature, do_alias) -#endif +#endif // SHARE_VM_TRACE_TRACEMACROS_HPP
--- a/src/share/vm/trace/traceStream.hpp Thu Jan 08 12:47:32 2015 +0000 +++ b/src/share/vm/trace/traceStream.hpp Tue Feb 03 16:48:05 2015 +0000 @@ -26,9 +26,7 @@ #define SHARE_VM_TRACE_TRACESTREAM_HPP #include "utilities/macros.hpp" - #if INCLUDE_TRACE - #include "oops/klass.hpp" #include "oops/method.hpp" #include "oops/symbol.hpp" @@ -117,5 +115,5 @@ } }; -#endif /* INCLUDE_TRACE */ -#endif /* SHARE_VM_TRACE_TRACESTREAM_HPP */ +#endif // INCLUDE_TRACE +#endif // SHARE_VM_TRACE_TRACESTREAM_HPP
--- a/src/share/vm/trace/traceTypes.xsl Thu Jan 08 12:47:32 2015 +0000 +++ b/src/share/vm/trace/traceTypes.xsl Tue Feb 03 16:48:05 2015 +0000 @@ -29,15 +29,14 @@ <xsl:template match="/"> <xsl:call-template name="file-header"/> -#ifndef TRACEFILES_JFRTYPES_HPP -#define TRACEFILES_JFRTYPES_HPP +#ifndef TRACEFILES_TRACETYPES_HPP +#define TRACEFILES_TRACETYPES_HPP #include "oops/symbol.hpp" #include "trace/traceDataTypes.hpp" #include "utilities/globalDefinitions.hpp" #include "utilities/ticks.hpp" - enum JVMContentType { _not_a_content_type = (JVM_CONTENT_TYPES_START - 1), @@ -58,7 +57,7 @@ }; /** - * Create typedefs for the JRA types: + * Create typedefs for the TRACE types: * typedef s8 TYPE_LONG; * typedef s4 TYPE_INTEGER; * typedef const char * TYPE_STRING; @@ -68,7 +67,7 @@ typedef <xsl:value-of select="@type"/> TYPE_<xsl:value-of select="@symbol"/>; </xsl:for-each> -#endif // JFRFILES_JFRTYPES_HPP +#endif // TRACEFILES_TRACETYPES_HPP </xsl:template> </xsl:stylesheet>
--- a/src/share/vm/trace/tracing.hpp Thu Jan 08 12:47:32 2015 +0000 +++ b/src/share/vm/trace/tracing.hpp Tue Feb 03 16:48:05 2015 +0000 @@ -28,4 +28,4 @@ #include "tracefiles/traceEventClasses.hpp" #include "tracefiles/traceEventIds.hpp" -#endif +#endif // SHARE_VM_TRACE_TRACING_HPP
--- a/src/share/vm/utilities/accessFlags.cpp Thu Jan 08 12:47:32 2015 +0000 +++ b/src/share/vm/utilities/accessFlags.cpp Tue Feb 03 16:48:05 2015 +0000 @@ -62,6 +62,21 @@ } while(f != old_flags); } +// Returns true iff this thread succeeded setting the bit. +bool AccessFlags::atomic_set_one_bit(jint bit) { + // Atomically update the flags with the bit given + jint old_flags, new_flags, f; + bool is_setting_bit = false; + do { + old_flags = _flags; + new_flags = old_flags | bit; + is_setting_bit = old_flags != new_flags; + f = Atomic::cmpxchg(new_flags, &_flags, old_flags); + } while(f != old_flags); + + return is_setting_bit; +} + #if !defined(PRODUCT) || INCLUDE_JVMTI void AccessFlags::print_on(outputStream* st) const {
--- a/src/share/vm/utilities/accessFlags.hpp Thu Jan 08 12:47:32 2015 +0000 +++ b/src/share/vm/utilities/accessFlags.hpp Tue Feb 03 16:48:05 2015 +0000 @@ -170,6 +170,7 @@ // Atomic update of flags void atomic_set_bits(jint bits); + bool atomic_set_one_bit(jint bit); void atomic_clear_bits(jint bits); private: @@ -230,12 +231,13 @@ atomic_set_bits(JVM_ACC_FIELD_HAS_GENERIC_SIGNATURE); } - void set_on_stack(const bool value) + bool set_on_stack(const bool value) { if (value) { - atomic_set_bits(JVM_ACC_ON_STACK); + return atomic_set_one_bit(JVM_ACC_ON_STACK); } else { atomic_clear_bits(JVM_ACC_ON_STACK); + return true; // Ignored } } // Conversion
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/share/vm/utilities/chunkedList.cpp Tue Feb 03 16:48:05 2015 +0000 @@ -0,0 +1,109 @@ +/* + * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * 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 "utilities/chunkedList.hpp" +#include "utilities/debug.hpp" + +/////////////// Unit tests /////////////// + +#ifndef PRODUCT + +template <typename T> +class TestChunkedList { + typedef ChunkedList<T, mtOther> ChunkedListT; + + public: + static void testEmpty() { + ChunkedListT buffer; + assert(buffer.size() == 0, "assert"); + } + + static void testFull() { + ChunkedListT buffer; + for (uintptr_t i = 0; i < ChunkedListT::BufferSize; i++) { + buffer.push((T)i); + } + assert(buffer.size() == ChunkedListT::BufferSize, "assert"); + assert(buffer.is_full(), "assert"); + } + + static void testSize() { + ChunkedListT buffer; + for (uintptr_t i = 0; i < ChunkedListT::BufferSize; i++) { + assert(buffer.size() == i, "assert"); + buffer.push((T)i); + assert(buffer.size() == i + 1, "assert"); + } + } + + static void testClear() { + ChunkedListT buffer; + + buffer.clear(); + assert(buffer.size() == 0, "assert"); + + for (uintptr_t i = 0; i < ChunkedListT::BufferSize / 2; i++) { + buffer.push((T)i); + } + buffer.clear(); + assert(buffer.size() == 0, "assert"); + + for (uintptr_t i = 0; i < ChunkedListT::BufferSize; i++) { + buffer.push((T)i); + } + buffer.clear(); + assert(buffer.size() == 0, "assert"); + } + + static void testAt() { + ChunkedListT buffer; + + for (uintptr_t i = 0; i < ChunkedListT::BufferSize; i++) { + buffer.push((T)i); + assert(buffer.at(i) == (T)i, "assert"); + } + + for (uintptr_t i = 0; i < ChunkedListT::BufferSize; i++) { + assert(buffer.at(i) == (T)i, "assert"); + } + } + + static void test() { + testEmpty(); + testFull(); + testSize(); + testClear(); + testAt(); + } +}; + +class Metadata; + +void TestChunkedList_test() { + TestChunkedList<Metadata*>::test(); + TestChunkedList<size_t>::test(); +} + +#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/share/vm/utilities/chunkedList.hpp Tue Feb 03 16:48:05 2015 +0000 @@ -0,0 +1,81 @@ +/* + * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +#ifndef SHARE_VM_UTILITIES_CHUNKED_LIST_HPP +#define SHARE_VM_UTILITIES_CHUNKED_LIST_HPP + +#include "memory/allocation.hpp" +#include "utilities/debug.hpp" + +template <class T, MEMFLAGS F> class ChunkedList : public CHeapObj<F> { + template <class U> friend class TestChunkedList; + + static const size_t BufferSize = 64; + + T _values[BufferSize]; + T* _top; + + ChunkedList<T, F>* _next_used; + ChunkedList<T, F>* _next_free; + + T const * end() const { + return &_values[BufferSize]; + } + + public: + ChunkedList<T, F>() : _top(_values), _next_used(NULL), _next_free(NULL) {} + + bool is_full() const { + return _top == end(); + } + + void clear() { + _top = _values; + // Don't clear the next pointers since that would interfere + // with other threads trying to iterate through the lists. + } + + void push(T m) { + assert(!is_full(), "Buffer is full"); + *_top = m; + _top++; + } + + void set_next_used(ChunkedList<T, F>* buffer) { _next_used = buffer; } + void set_next_free(ChunkedList<T, F>* buffer) { _next_free = buffer; } + + ChunkedList<T, F>* next_used() const { return _next_used; } + ChunkedList<T, F>* next_free() const { return _next_free; } + + size_t size() const { + return pointer_delta(_top, _values, sizeof(T)); + } + + T at(size_t i) { + assert(i < size(), err_msg("IOOBE i: " SIZE_FORMAT " size(): " SIZE_FORMAT, i, size())); + return _values[i]; + } +}; + +#endif // SHARE_VM_UTILITIES_CHUNKED_LIST_HPP
--- a/src/share/vm/utilities/debug.cpp Thu Jan 08 12:47:32 2015 +0000 +++ b/src/share/vm/utilities/debug.cpp Tue Feb 03 16:48:05 2015 +0000 @@ -266,17 +266,19 @@ "native memory for metadata", "shared read only space", "shared read write space", - "shared miscellaneous data space" + "shared miscellaneous data space", + "shared miscellaneous code space" }; static const char* flag[] = { "Metaspace", "SharedReadOnlySize", "SharedReadWriteSize", - "SharedMiscDataSize" + "SharedMiscDataSize", + "SharedMiscCodeSize" }; warning("\nThe %s is not large enough\n" - "to preload requested classes. Use -XX:%s=\n" + "to preload requested classes. Use -XX:%s=<size>\n" "to increase the initial size of %s.\n", name[shared_space], flag[shared_space], name[shared_space]); exit(2);
--- a/src/share/vm/utilities/debug.hpp Thu Jan 08 12:47:32 2015 +0000 +++ b/src/share/vm/utilities/debug.hpp Tue Feb 03 16:48:05 2015 +0000 @@ -246,7 +246,8 @@ SharedPermGen, SharedReadOnly, SharedReadWrite, - SharedMiscData + SharedMiscData, + SharedMiscCode }; void report_out_of_shared_space(SharedSpaceType space_type);
--- a/src/share/vm/utilities/defaultStream.hpp Thu Jan 08 12:47:32 2015 +0000 +++ b/src/share/vm/utilities/defaultStream.hpp Tue Feb 03 16:48:05 2015 +0000 @@ -41,6 +41,8 @@ void init(); void init_log(); + fileStream* open_file(const char* log_name); + void start_log(); void finish_log(); void finish_log_on_error(char *buf, int buflen); public:
--- a/src/share/vm/utilities/ostream.cpp Thu Jan 08 12:47:32 2015 +0000 +++ b/src/share/vm/utilities/ostream.cpp Tue Feb 03 16:48:05 2015 +0000 @@ -370,7 +370,6 @@ #define EXTRACHARLEN 32 #define CURRENTAPPX ".current" -#define FILENAMEBUFLEN 1024 // convert YYYY-MM-DD HH:MM:SS to YYYY-MM-DD_HH-MM-SS char* get_datetime_string(char *buf, size_t len) { os::local_time_string(buf, len); @@ -404,7 +403,6 @@ buffer_length = strlen(log_name) + 1; } - // const char* star = strchr(basename, '*'); const char* pts = strstr(basename, "%p"); int pid_pos = (pts == NULL) ? -1 : (pts - nametail); @@ -419,6 +417,11 @@ buffer_length += strlen(tms); } + // File name is too long. + if (buffer_length > JVM_MAXPATHLEN) { + return NULL; + } + // Create big enough buffer. char *buf = NEW_C_HEAP_ARRAY(char, buffer_length, mtInternal); @@ -492,46 +495,88 @@ void test_loggc_filename() { int pid; char tms[32]; - char i_result[FILENAMEBUFLEN]; + char i_result[JVM_MAXPATHLEN]; const char* o_result; get_datetime_string(tms, sizeof(tms)); pid = os::current_process_id(); // test.log - jio_snprintf(i_result, sizeof(char)*FILENAMEBUFLEN, "test.log", tms); + jio_snprintf(i_result, JVM_MAXPATHLEN, "test.log", tms); o_result = make_log_name_internal("test.log", NULL, pid, tms); assert(strcmp(i_result, o_result) == 0, "failed on testing make_log_name(\"test.log\", NULL)"); FREE_C_HEAP_ARRAY(char, o_result, mtInternal); // test-%t-%p.log - jio_snprintf(i_result, sizeof(char)*FILENAMEBUFLEN, "test-%s-pid%u.log", tms, pid); + jio_snprintf(i_result, JVM_MAXPATHLEN, "test-%s-pid%u.log", tms, pid); o_result = make_log_name_internal("test-%t-%p.log", NULL, pid, tms); assert(strcmp(i_result, o_result) == 0, "failed on testing make_log_name(\"test-%%t-%%p.log\", NULL)"); FREE_C_HEAP_ARRAY(char, o_result, mtInternal); // test-%t%p.log - jio_snprintf(i_result, sizeof(char)*FILENAMEBUFLEN, "test-%spid%u.log", tms, pid); + jio_snprintf(i_result, JVM_MAXPATHLEN, "test-%spid%u.log", tms, pid); o_result = make_log_name_internal("test-%t%p.log", NULL, pid, tms); assert(strcmp(i_result, o_result) == 0, "failed on testing make_log_name(\"test-%%t%%p.log\", NULL)"); FREE_C_HEAP_ARRAY(char, o_result, mtInternal); // %p%t.log - jio_snprintf(i_result, sizeof(char)*FILENAMEBUFLEN, "pid%u%s.log", pid, tms); + jio_snprintf(i_result, JVM_MAXPATHLEN, "pid%u%s.log", pid, tms); o_result = make_log_name_internal("%p%t.log", NULL, pid, tms); assert(strcmp(i_result, o_result) == 0, "failed on testing make_log_name(\"%%p%%t.log\", NULL)"); FREE_C_HEAP_ARRAY(char, o_result, mtInternal); // %p-test.log - jio_snprintf(i_result, sizeof(char)*FILENAMEBUFLEN, "pid%u-test.log", pid); + jio_snprintf(i_result, JVM_MAXPATHLEN, "pid%u-test.log", pid); o_result = make_log_name_internal("%p-test.log", NULL, pid, tms); assert(strcmp(i_result, o_result) == 0, "failed on testing make_log_name(\"%%p-test.log\", NULL)"); FREE_C_HEAP_ARRAY(char, o_result, mtInternal); // %t.log - jio_snprintf(i_result, sizeof(char)*FILENAMEBUFLEN, "%s.log", tms); + jio_snprintf(i_result, JVM_MAXPATHLEN, "%s.log", tms); o_result = make_log_name_internal("%t.log", NULL, pid, tms); assert(strcmp(i_result, o_result) == 0, "failed on testing make_log_name(\"%%t.log\", NULL)"); FREE_C_HEAP_ARRAY(char, o_result, mtInternal); + + { + // longest filename + char longest_name[JVM_MAXPATHLEN]; + memset(longest_name, 'a', sizeof(longest_name)); + longest_name[JVM_MAXPATHLEN - 1] = '\0'; + o_result = make_log_name_internal((const char*)&longest_name, NULL, pid, tms); + assert(strcmp(longest_name, o_result) == 0, err_msg("longest name does not match. expected '%s' but got '%s'", longest_name, o_result)); + FREE_C_HEAP_ARRAY(char, o_result, mtInternal); + } + + { + // too long file name + char too_long_name[JVM_MAXPATHLEN + 100]; + int too_long_length = sizeof(too_long_name); + memset(too_long_name, 'a', too_long_length); + too_long_name[too_long_length - 1] = '\0'; + o_result = make_log_name_internal((const char*)&too_long_name, NULL, pid, tms); + assert(o_result == NULL, err_msg("Too long file name should return NULL, but got '%s'", o_result)); + } + + { + // too long with timestamp + char longest_name[JVM_MAXPATHLEN]; + memset(longest_name, 'a', JVM_MAXPATHLEN); + longest_name[JVM_MAXPATHLEN - 3] = '%'; + longest_name[JVM_MAXPATHLEN - 2] = 't'; + longest_name[JVM_MAXPATHLEN - 1] = '\0'; + o_result = make_log_name_internal((const char*)&longest_name, NULL, pid, tms); + assert(o_result == NULL, err_msg("Too long file name after timestamp expansion should return NULL, but got '%s'", o_result)); + } + + { + // too long with pid + char longest_name[JVM_MAXPATHLEN]; + memset(longest_name, 'a', JVM_MAXPATHLEN); + longest_name[JVM_MAXPATHLEN - 3] = '%'; + longest_name[JVM_MAXPATHLEN - 2] = 'p'; + longest_name[JVM_MAXPATHLEN - 1] = '\0'; + o_result = make_log_name_internal((const char*)&longest_name, NULL, pid, tms); + assert(o_result == NULL, err_msg("Too long file name after pid expansion should return NULL, but got '%s'", o_result)); + } } #endif // PRODUCT @@ -640,9 +685,16 @@ _bytes_written = 0L; _file_name = make_log_name(file_name, NULL); + if (_file_name == NULL) { + warning("Cannot open file %s: file name is too long.\n", file_name); + _need_close = false; + UseGCLogFileRotation = false; + return; + } + // gc log file rotation if (UseGCLogFileRotation && NumberOfGCLogFiles > 1) { - char tempbuf[FILENAMEBUFLEN]; + char tempbuf[JVM_MAXPATHLEN]; jio_snprintf(tempbuf, sizeof(tempbuf), "%s.%d" CURRENTAPPX, _file_name, _cur_file_num); _file = fopen(tempbuf, "w"); } else { @@ -674,10 +726,10 @@ // concurrent GC threads to run parallel with VMThread at safepoint, write and rotate_log // must be synchronized. void gcLogFileStream::rotate_log(bool force, outputStream* out) { - char time_msg[FILENAMEBUFLEN]; + char time_msg[O_BUFLEN]; char time_str[EXTRACHARLEN]; - char current_file_name[FILENAMEBUFLEN]; - char renamed_file_name[FILENAMEBUFLEN]; + char current_file_name[JVM_MAXPATHLEN]; + char renamed_file_name[JVM_MAXPATHLEN]; if (!should_rotate(force)) { return; @@ -716,12 +768,15 @@ // have a form of extended_filename.<i>.current where i is the current rotation // file number. After it reaches max file size, the file will be saved and renamed // with .current removed from its tail. - size_t filename_len = strlen(_file_name); if (_file != NULL) { - jio_snprintf(renamed_file_name, filename_len + EXTRACHARLEN, "%s.%d", + jio_snprintf(renamed_file_name, JVM_MAXPATHLEN, "%s.%d", _file_name, _cur_file_num); - jio_snprintf(current_file_name, filename_len + EXTRACHARLEN, "%s.%d" CURRENTAPPX, - _file_name, _cur_file_num); + int result = jio_snprintf(current_file_name, JVM_MAXPATHLEN, + "%s.%d" CURRENTAPPX, _file_name, _cur_file_num); + if (result >= JVM_MAXPATHLEN) { + warning("Cannot create new log file name: %s: file name is too long.\n", current_file_name); + return; + } const char* msg = force ? "GC log rotation request has been received." : "GC log file has reached the maximum size."; @@ -760,19 +815,23 @@ _cur_file_num++; if (_cur_file_num > NumberOfGCLogFiles - 1) _cur_file_num = 0; - jio_snprintf(current_file_name, filename_len + EXTRACHARLEN, "%s.%d" CURRENTAPPX, + int result = jio_snprintf(current_file_name, JVM_MAXPATHLEN, "%s.%d" CURRENTAPPX, _file_name, _cur_file_num); + if (result >= JVM_MAXPATHLEN) { + warning("Cannot create new log file name: %s: file name is too long.\n", current_file_name); + return; + } + _file = fopen(current_file_name, "w"); if (_file != NULL) { _bytes_written = 0L; _need_close = true; // reuse current_file_name for time_msg - jio_snprintf(current_file_name, filename_len + EXTRACHARLEN, + jio_snprintf(current_file_name, JVM_MAXPATHLEN, "%s.%d", _file_name, _cur_file_num); jio_snprintf(time_msg, sizeof(time_msg), "%s GC log file created %s\n", - os::local_time_string((char *)time_str, sizeof(time_str)), - current_file_name); + os::local_time_string((char *)time_str, sizeof(time_str)), current_file_name); write(time_msg, strlen(time_msg)); if (out != NULL) { @@ -820,32 +879,64 @@ return _log_file != NULL; } +fileStream* defaultStream::open_file(const char* log_name) { + const char* try_name = make_log_name(log_name, NULL); + if (try_name == NULL) { + warning("Cannot open file %s: file name is too long.\n", log_name); + return NULL; + } + + fileStream* file = new(ResourceObj::C_HEAP, mtInternal) fileStream(try_name); + FREE_C_HEAP_ARRAY(char, try_name, mtInternal); + if (file->is_open()) { + return file; + } + + // Try again to open the file in the temp directory. + delete file; + char warnbuf[O_BUFLEN*2]; + jio_snprintf(warnbuf, sizeof(warnbuf), "Warning: Cannot open log file: %s\n", log_name); + // Note: This feature is for maintainer use only. No need for L10N. + jio_print(warnbuf); + try_name = make_log_name(log_name, os::get_temp_directory()); + if (try_name == NULL) { + warning("Cannot open file %s: file name is too long for directory %s.\n", log_name, os::get_temp_directory()); + return NULL; + } + + jio_snprintf(warnbuf, sizeof(warnbuf), + "Warning: Forcing option -XX:LogFile=%s\n", try_name); + jio_print(warnbuf); + + file = new(ResourceObj::C_HEAP, mtInternal) fileStream(try_name); + FREE_C_HEAP_ARRAY(char, try_name, mtInternal); + if (file->is_open()) { + return file; + } + + delete file; + return NULL; +} + void defaultStream::init_log() { // %%% Need a MutexLocker? const char* log_name = LogFile != NULL ? LogFile : "hotspot_%p.log"; - const char* try_name = make_log_name(log_name, NULL); - fileStream* file = new(ResourceObj::C_HEAP, mtInternal) fileStream(try_name); - if (!file->is_open()) { - // Try again to open the file. - char warnbuf[O_BUFLEN*2]; - jio_snprintf(warnbuf, sizeof(warnbuf), - "Warning: Cannot open log file: %s\n", try_name); - // Note: This feature is for maintainer use only. No need for L10N. - jio_print(warnbuf); - FREE_C_HEAP_ARRAY(char, try_name, mtInternal); - try_name = make_log_name(log_name, os::get_temp_directory()); - jio_snprintf(warnbuf, sizeof(warnbuf), - "Warning: Forcing option -XX:LogFile=%s\n", try_name); - jio_print(warnbuf); - delete file; - file = new(ResourceObj::C_HEAP, mtInternal) fileStream(try_name); + fileStream* file = open_file(log_name); + + if (file != NULL) { + _log_file = file; + _outer_xmlStream = new(ResourceObj::C_HEAP, mtInternal) xmlStream(file); + start_log(); + } else { + // and leave xtty as NULL + LogVMOutput = false; + DisplayVMOutput = true; + LogCompilation = false; } - FREE_C_HEAP_ARRAY(char, try_name, mtInternal); +} - if (file->is_open()) { - _log_file = file; - xmlStream* xs = new(ResourceObj::C_HEAP, mtInternal) xmlStream(file); - _outer_xmlStream = xs; +void defaultStream::start_log() { + xmlStream*xs = _outer_xmlStream; if (this == tty) xtty = xs; // Write XML header. xs->print_cr("<?xml version='1.0' encoding='UTF-8'?>"); @@ -900,13 +991,6 @@ xs->head("tty"); // All further non-markup text gets copied to the tty: xs->_text = this; // requires friend declaration! - } else { - delete(file); - // and leave xtty as NULL - LogVMOutput = false; - DisplayVMOutput = true; - LogCompilation = false; - } } // finish_log() is called during normal VM shutdown. finish_log_on_error() is
--- a/src/share/vm/utilities/vmError.cpp Thu Jan 08 12:47:32 2015 +0000 +++ b/src/share/vm/utilities/vmError.cpp Tue Feb 03 16:48:05 2015 +0000 @@ -22,6 +22,7 @@ * */ +#include <fcntl.h> #include "precompiled.hpp" #include "compiler/compileBroker.hpp" #include "gc_interface/collectedHeap.hpp" @@ -841,7 +842,8 @@ static int expand_and_open(const char* pattern, char* buf, size_t buflen, size_t pos) { int fd = -1; if (Arguments::copy_expand_pid(pattern, strlen(pattern), &buf[pos], buflen - pos)) { - fd = open(buf, O_RDWR | O_CREAT | O_TRUNC, 0666); + // the O_EXCL flag will cause the open to fail if the file exists + fd = open(buf, O_RDWR | O_CREAT | O_EXCL, 0666); } return fd; }
--- a/test/TEST.ROOT Thu Jan 08 12:47:32 2015 +0000 +++ b/test/TEST.ROOT Tue Feb 03 16:48:05 2015 +0000 @@ -30,3 +30,4 @@ keys=cte_test jcmd nmt regression gc stress groups=TEST.groups [closed/TEST.groups] +requires.properties=sun.arch.data.model
--- a/test/TEST.groups Thu Jan 08 12:47:32 2015 +0000 +++ b/test/TEST.groups Tue Feb 03 16:48:05 2015 +0000 @@ -90,7 +90,6 @@ runtime/NMT/SummarySanityCheck.java \ runtime/NMT/ThreadedMallocTestType.java \ runtime/NMT/ThreadedVirtualAllocTestType.java \ - runtime/NMT/UnsafeMallocLimit.java \ runtime/NMT/VirtualAllocCommitUncommitRecommit.java \ runtime/NMT/VirtualAllocTestType.java \ runtime/RedefineObject/TestRedefineObject.java \ @@ -172,6 +171,7 @@ gc/g1/TestShrinkAuxiliaryData20.java \ gc/g1/TestShrinkAuxiliaryData25.java \ gc/g1/TestShrinkAuxiliaryData30.java \ + gc/survivorAlignment \ runtime/InternalApi/ThreadCpuTimesDeadlock.java \ serviceability/threads/TestFalseDeadLock.java \ serviceability/jvmti/GetObjectSizeOverflow.java \
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/compiler/EliminateAutoBox/UnsignedLoads.java Tue Feb 03 16:48:05 2015 +0000 @@ -0,0 +1,63 @@ +/* + * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @library /testlibrary + * @run main/othervm -Xbatch -XX:+IgnoreUnrecognizedVMOptions -XX:+EliminateAutoBox + * -XX:CompileOnly=::valueOf,::byteValue,::shortValue,::testUnsignedByte,::testUnsignedShort + * UnsignedLoads + */ +import static com.oracle.java.testlibrary.Asserts.assertEQ; + +public class UnsignedLoads { + public static int testUnsignedByte() { + byte[] bytes = new byte[] {-1}; + int res = 0; + for (int i = 0; i < 100000; i++) { + for (Byte b : bytes) { + res = b & 0xff; + } + } + return res; + } + + public static int testUnsignedShort() { + int res = 0; + short[] shorts = new short[] {-1}; + for (int i = 0; i < 100000; i++) { + for (Short s : shorts) { + res = s & 0xffff; + } + } + return res; + } + + public static void main(String[] args) { + assertEQ(testUnsignedByte(), 255); + assertEQ(testUnsignedShort(), 65535); + System.out.println("TEST PASSED"); + } +}
--- a/test/compiler/ciReplay/common.sh Thu Jan 08 12:47:32 2015 +0000 +++ b/test/compiler/ciReplay/common.sh Tue Feb 03 16:48:05 2015 +0000 @@ -213,7 +213,7 @@ -XX:VMThreadStackSize=512 \ -XX:CompilerThreadStackSize=512 \ -XX:ParallelGCThreads=1 \ - -XX:CICompilerCount=1 \ + -XX:CICompilerCount=2 \ -Xcomp \ -XX:CICrashAt=1 \ -XX:+CreateMinidumpOnCrash \
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/compiler/dependencies/MonomorphicObjectCall/TestMonomorphicObjectCall.java Tue Feb 03 16:48:05 2015 +0000 @@ -0,0 +1,73 @@ +/* + * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.io.File; +import java.util.ArrayList; +import java.util.Collections; + +import com.oracle.java.testlibrary.*; + +/* + * @test + * @bug 8050079 + * @summary Compiles a monomorphic call to finalizeObject() on a modified java.lang.Object to test C1 CHA. + * @library /testlibrary + * @compile -XDignore.symbol.file java/lang/Object.java TestMonomorphicObjectCall.java + * @run main TestMonomorphicObjectCall + */ +public class TestMonomorphicObjectCall { + final static String testClasses = System.getProperty("test.classes") + File.separator; + + private static void callFinalize(Object object) throws Throwable { + // Call modified version of java.lang.Object::finalize() that is + // not overridden by any subclass. C1 CHA should mark the call site + // as monomorphic and inline the method. + object.finalizeObject(); + } + + public static void main(String[] args) throws Throwable { + if (args.length == 0) { + // Execute new instance with modified java.lang.Object + executeTestJvm(); + } else { + // Trigger compilation of 'callFinalize' + callFinalize(new Object()); + } + } + + public static void executeTestJvm() throws Throwable { + // Execute test with modified version of java.lang.Object + // in -Xbootclasspath. + String[] vmOpts = new String[] { + "-Xbootclasspath/p:" + testClasses, + "-Xcomp", + "-XX:-VerifyDependencies", + "-XX:CompileOnly=TestMonomorphicObjectCall::callFinalize", + "-XX:CompileOnly=Object::finalizeObject", + "-XX:TieredStopAtLevel=1", + TestMonomorphicObjectCall.class.getName(), + "true"}; + OutputAnalyzer output = ProcessTools.executeTestJvm(vmOpts); + output.shouldHaveExitValue(0); + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/compiler/dependencies/MonomorphicObjectCall/java/lang/Object.java Tue Feb 03 16:48:05 2015 +0000 @@ -0,0 +1,87 @@ +/* + * Copyright (c) 1994, 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package java.lang; + +/** + * Slightly modified version of java.lang.Object that replaces + * finalize() by finalizeObject() to avoid overriding in subclasses. + */ +public class Object { + + private static native void registerNatives(); + static { + registerNatives(); + } + + public final native Class<?> getClass(); + + public native int hashCode(); + + public boolean equals(Object obj) { + return (this == obj); + } + + protected native Object clone() throws CloneNotSupportedException; + + public String toString() { + return getClass().getName() + "@" + Integer.toHexString(hashCode()); + } + + public final native void notify(); + + public final native void notifyAll(); + + public final native void wait(long timeout) throws InterruptedException; + + public final void wait(long timeout, int nanos) throws InterruptedException { + if (timeout < 0) { + throw new IllegalArgumentException("timeout value is negative"); + } + + if (nanos < 0 || nanos > 999999) { + throw new IllegalArgumentException( + "nanosecond timeout value out of range"); + } + + if (nanos >= 500000 || (nanos != 0 && timeout == 0)) { + timeout++; + } + + wait(timeout); + } + + public final void wait() throws InterruptedException { + wait(0); + } + + /** + * Replaces original finalize() method and is therefore not + * overridden by any subclasses of Object. + * @throws Throwable + */ + // protected void finalize() throws Throwable { } + public void finalizeObject() throws Throwable { } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/compiler/exceptions/SumTest.java Tue Feb 03 16:48:05 2015 +0000 @@ -0,0 +1,86 @@ +/* + * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 8066900 + * @summary FP registers are not properly restored by C1 when handling exceptions + * @run main/othervm -Xbatch SumTest + * + */ +public class SumTest { + private static class Sum { + + double[] sums; + + /** + * Construct empty Sum + */ + public Sum() { + sums = new double[0]; + } + + /** + * Return the sum of all numbers added to this Sum + * + * @return the sum + */ + final public double getSum() { + double sum = 0; + for (final double s : sums) { + sum += s; + } + + return sum; + } + + /** + * Add a new number to this Sum + * + * @param a number to be added. + */ + final public void add(double a) { + try { + sums[sums.length] = -1; // Cause IndexOutOfBoundsException + } catch (final IndexOutOfBoundsException e) { + final double[] oldSums = sums; + sums = new double[oldSums.length + 1]; // Extend sums + System.arraycopy(oldSums, 0, sums, 0, oldSums.length); + sums[oldSums.length] = a; // Append a + } + } + } + + public static void main(String[] args) throws Exception { + final Sum sum = new Sum(); + for (int i = 1; i <= 10000; ++i) { + sum.add(1); + double ii = sum.getSum(); + if (i != ii) { + throw new Exception("Failure: computed = " + ii + ", expected = " + i); + } + } + } + +} +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/compiler/jsr292/NullConstantReceiver.java Tue Feb 03 16:48:05 2015 +0000 @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/** + * @test + * @bug 8059556 + * @run main/othervm -Xbatch NullConstantReceiver + */ + +import java.lang.invoke.MethodHandle; +import java.lang.invoke.MethodHandles; +import java.lang.invoke.MethodType; + +public class NullConstantReceiver { + static final MethodHandle target; + static { + try { + target = MethodHandles.lookup().findVirtual(NullConstantReceiver.class, "test", MethodType.methodType(void.class)); + } catch (ReflectiveOperationException e) { + throw new Error(e); + } + } + + public void test() {} + + static void run() throws Throwable { + target.invokeExact((NullConstantReceiver) null); + } + + public static void main(String[] args) throws Throwable { + for (int i = 0; i<15000; i++) { + try { + run(); + } catch (NullPointerException e) { + // expected + continue; + } + throw new AssertionError("NPE wasn't thrown"); + } + System.out.println("TEST PASSED"); + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/compiler/jsr292/RedefineMethodUsedByMultipleMethodHandles.java Tue Feb 03 16:48:05 2015 +0000 @@ -0,0 +1,174 @@ +/* + * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/** + * @test + * @bug 8042235 + * @summary redefining method used by multiple MethodHandles crashes VM + * @compile -XDignore.symbol.file RedefineMethodUsedByMultipleMethodHandles.java + * @run main RedefineMethodUsedByMultipleMethodHandles + */ + +import java.io.*; +import java.lang.instrument.*; +import java.lang.invoke.*; +import java.lang.invoke.MethodHandles.Lookup; +import java.lang.management.*; +import java.lang.reflect.*; +import java.nio.file.*; +import java.security.*; +import java.util.jar.*; + +import javax.tools.*; + +import jdk.internal.org.objectweb.asm.*; + +public class RedefineMethodUsedByMultipleMethodHandles { + + static class Foo { + public static Object getName() { + return "foo"; + } + } + + public static void main(String[] args) throws Throwable { + + Lookup lookup = MethodHandles.lookup(); + Method fooMethod = Foo.class.getDeclaredMethod("getName"); + + // fooMH2 displaces fooMH1 from the MemberNamesTable + MethodHandle fooMH1 = lookup.unreflect(fooMethod); + MethodHandle fooMH2 = lookup.unreflect(fooMethod); + + System.out.println("fooMH1.invoke = " + fooMH1.invokeExact()); + System.out.println("fooMH2.invoke = " + fooMH2.invokeExact()); + + // Redefining Foo.getName() causes vmtarget to be updated + // in fooMH2 but not fooMH1 + redefineFoo(); + + // Full GC causes fooMH1.vmtarget to be deallocated + System.gc(); + + // Calling fooMH1.vmtarget crashes the VM + System.out.println("fooMH1.invoke = " + fooMH1.invokeExact()); + } + + /** + * Adds the class file bytes for {@code c} to {@code jar}. + */ + static void add(JarOutputStream jar, Class<?> c) throws IOException { + String classAsPath = c.getName().replace('.', '/') + ".class"; + jar.putNextEntry(new JarEntry(classAsPath)); + InputStream stream = c.getClassLoader().getResourceAsStream(classAsPath); + + int b; + while ((b = stream.read()) != -1) { + jar.write(b); + } + } + + static void redefineFoo() throws Exception { + Manifest manifest = new Manifest(); + manifest.getMainAttributes().put(Attributes.Name.MANIFEST_VERSION, "1.0"); + Attributes mainAttrs = manifest.getMainAttributes(); + mainAttrs.putValue("Agent-Class", FooAgent.class.getName()); + mainAttrs.putValue("Can-Redefine-Classes", "true"); + mainAttrs.putValue("Can-Retransform-Classes", "true"); + + Path jar = Files.createTempFile("myagent", ".jar"); + try { + JarOutputStream jarStream = new JarOutputStream(new FileOutputStream(jar.toFile()), manifest); + add(jarStream, FooAgent.class); + add(jarStream, FooTransformer.class); + jarStream.close(); + runAgent(jar); + } finally { + Files.deleteIfExists(jar); + } + } + + public static void runAgent(Path agent) throws Exception { + String vmName = ManagementFactory.getRuntimeMXBean().getName(); + int p = vmName.indexOf('@'); + assert p != -1 : "VM name not in <pid>@<host> format: " + vmName; + String pid = vmName.substring(0, p); + ClassLoader cl = ToolProvider.getSystemToolClassLoader(); + Class<?> c = Class.forName("com.sun.tools.attach.VirtualMachine", true, cl); + Method attach = c.getDeclaredMethod("attach", String.class); + Method loadAgent = c.getDeclaredMethod("loadAgent", String.class); + Method detach = c.getDeclaredMethod("detach"); + Object vm = attach.invoke(null, pid); + loadAgent.invoke(vm, agent.toString()); + detach.invoke(vm); + } + + public static class FooAgent { + + public static void agentmain(@SuppressWarnings("unused") String args, Instrumentation inst) throws Exception { + assert inst.isRedefineClassesSupported(); + assert inst.isRetransformClassesSupported(); + inst.addTransformer(new FooTransformer(), true); + Class<?>[] classes = inst.getAllLoadedClasses(); + for (int i = 0; i < classes.length; i++) { + Class<?> c = classes[i]; + if (c == Foo.class) { + inst.retransformClasses(new Class[]{c}); + } + } + } + } + + static class FooTransformer implements ClassFileTransformer { + + @Override + public byte[] transform(ClassLoader cl, String className, Class<?> classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) throws IllegalClassFormatException { + if (Foo.class.equals(classBeingRedefined)) { + System.out.println("redefining " + classBeingRedefined); + ClassReader cr = new ClassReader(classfileBuffer); + ClassWriter cw = new ClassWriter(cr, ClassWriter.COMPUTE_FRAMES); + ClassVisitor adapter = new ClassVisitor(Opcodes.ASM5, cw) { + @Override + public MethodVisitor visitMethod(int access, String base, String desc, String signature, String[] exceptions) { + MethodVisitor mv = cv.visitMethod(access, base, desc, signature, exceptions); + if (mv != null) { + mv = new MethodVisitor(Opcodes.ASM5, mv) { + @Override + public void visitLdcInsn(Object cst) { + System.out.println("replacing \"" + cst + "\" with \"bar\""); + mv.visitLdcInsn("bar"); + } + }; + } + return mv; + } + }; + + cr.accept(adapter, ClassReader.SKIP_FRAMES); + cw.visitEnd(); + return cw.toByteArray(); + } + return classfileBuffer; + } + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/compiler/jsr292/VMAnonymousClasses.java Tue Feb 03 16:48:05 2015 +0000 @@ -0,0 +1,125 @@ +/* + * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/** + * @test + * @bug 8058828 + * @run main/bootclasspath -Xbatch VMAnonymousClasses + */ + +import jdk.internal.org.objectweb.asm.ClassWriter; +import jdk.internal.org.objectweb.asm.MethodVisitor; +import jdk.internal.org.objectweb.asm.Opcodes; +import sun.misc.Unsafe; + +import java.lang.invoke.ConstantCallSite; +import java.lang.invoke.MethodHandle; +import java.lang.invoke.MethodHandles; +import java.lang.invoke.MethodType; +import java.lang.invoke.MutableCallSite; +import java.lang.invoke.VolatileCallSite; + +public class VMAnonymousClasses { + static final String TEST_METHOD_NAME = "constant"; + + static final Unsafe UNSAFE = Unsafe.getUnsafe(); + + static int getConstantPoolSize(byte[] classFile) { + // The first few bytes: + // u4 magic; + // u2 minor_version; + // u2 major_version; + // u2 constant_pool_count; + return ((classFile[8] & 0xFF) << 8) | (classFile[9] & 0xFF); + } + + static void test(Object value) throws ReflectiveOperationException { + System.out.printf("Test: %s", value != null ? value.getClass() : "null"); + + ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_MAXS | ClassWriter.COMPUTE_FRAMES); + cw.visit(Opcodes.V1_8, Opcodes.ACC_PUBLIC | Opcodes.ACC_SUPER, "Test", null, "java/lang/Object", null); + + MethodVisitor mv = cw.visitMethod(Opcodes.ACC_STATIC | Opcodes.ACC_PUBLIC, TEST_METHOD_NAME, "()Ljava/lang/Object;", null, null); + + String placeholder = "CONSTANT"; + int index = cw.newConst(placeholder); + mv.visitLdcInsn(placeholder); + mv.visitInsn(Opcodes.ARETURN); + + mv.visitMaxs(0, 0); + mv.visitEnd(); + + byte[] classFile = cw.toByteArray(); + + Object[] cpPatches = new Object[getConstantPoolSize(classFile)]; + cpPatches[index] = value; + + Class<?> test = UNSAFE.defineAnonymousClass(VMAnonymousClasses.class, classFile, cpPatches); + + Object expectedResult = (value != null) ? value : placeholder; + for (int i = 0; i<15000; i++) { + Object result = test.getMethod(TEST_METHOD_NAME).invoke(null); + if (result != expectedResult) { + throw new AssertionError(String.format("Wrong value returned: %s != %s", value, result)); + } + } + System.out.println(" PASSED"); + } + + public static void main(String[] args) throws ReflectiveOperationException { + // Objects + test(new Object()); + test("TEST"); + test(new VMAnonymousClasses()); + test(null); + + // Class + test(String.class); + + // Arrays + test(new boolean[0]); + test(new byte[0]); + test(new char[0]); + test(new short[0]); + test(new int[0]); + test(new long[0]); + test(new float[0]); + test(new double[0]); + test(new Object[0]); + + // Multi-dimensional arrays + test(new byte[0][0]); + test(new Object[0][0]); + + // MethodHandle-related + MethodType mt = MethodType.methodType(void.class, String[].class); + MethodHandle mh = MethodHandles.lookup().findStatic(VMAnonymousClasses.class, "main", mt); + test(mt); + test(mh); + test(new ConstantCallSite(mh)); + test(new MutableCallSite(MethodType.methodType(void.class))); + test(new VolatileCallSite(MethodType.methodType(void.class))); + + System.out.println("TEST PASSED"); + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/compiler/loopopts/TestDeadBackbranchArrayAccess.java Tue Feb 03 16:48:05 2015 +0000 @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +/** + * @test + * @bug 8054478 + * @summary dead backbranch in main loop results in erroneous array access + * @run main/othervm -XX:CompileOnly=TestDeadBackbranchArrayAccess -Xcomp TestDeadBackbranchArrayAccess + * + */ + +public class TestDeadBackbranchArrayAccess { + static char[] pattern0 = {0}; + static char[] pattern1 = {1}; + + static void test(char[] array) { + if (pattern1 == null) return; + + int i = 0; + int pos = 0; + char c = array[pos]; + + while (i >= 0 && (c == pattern0[i] || c == pattern1[i])) { + i--; + pos--; + if (pos != -1) { + c = array[pos]; + } + } + } + + public static void main(String[] args) { + for (int i = 0; i < 1000000; i++) { + test(new char[1]); + } + } +}
--- a/test/compiler/membars/DekkerTest.java Thu Jan 08 12:47:32 2015 +0000 +++ b/test/compiler/membars/DekkerTest.java Tue Feb 03 16:48:05 2015 +0000 @@ -25,9 +25,9 @@ * @test * @bug 8007898 * @summary Incorrect optimization of Memory Barriers in Matcher::post_store_load_barrier(). - * @run main/othervm -Xbatch -XX:+IgnoreUnrecognizedVMOptions -XX:CICompilerCount=1 -XX:+StressGCM -XX:+StressLCM DekkerTest - * @run main/othervm -Xbatch -XX:+IgnoreUnrecognizedVMOptions -XX:CICompilerCount=1 -XX:+StressGCM -XX:+StressLCM DekkerTest - * @run main/othervm -Xbatch -XX:+IgnoreUnrecognizedVMOptions -XX:CICompilerCount=1 -XX:+StressGCM -XX:+StressLCM DekkerTest + * @run main/othervm -Xbatch -XX:+IgnoreUnrecognizedVMOptions -XX:CICompilerCount=1 -XX:-TieredCompilation -XX:+StressGCM -XX:+StressLCM DekkerTest + * @run main/othervm -Xbatch -XX:+IgnoreUnrecognizedVMOptions -XX:CICompilerCount=1 -XX:-TieredCompilation -XX:+StressGCM -XX:+StressLCM DekkerTest + * @run main/othervm -Xbatch -XX:+IgnoreUnrecognizedVMOptions -XX:CICompilerCount=1 -XX:-TieredCompilation -XX:+StressGCM -XX:+StressLCM DekkerTest * @author Martin Doerr martin DOT doerr AT sap DOT com * * Run 3 times since the failure is intermittent.
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/compiler/rangechecks/TestRangeCheckSmearing.java Tue Feb 03 16:48:05 2015 +0000 @@ -0,0 +1,436 @@ +/* + * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 8066103 + * @summary C2's range check smearing allows out of bound array accesses + * @library /testlibrary /testlibrary/whitebox /compiler/whitebox /testlibrary/com/oracle/java/testlibrary + * @build TestRangeCheckSmearing + * @run main ClassFileInstaller sun.hotspot.WhiteBox + * @run main ClassFileInstaller com.oracle.java.testlibrary.Platform + * @run main/othervm -ea -Xmixed -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI + * -XX:-BackgroundCompilation -XX:-UseOnStackReplacement TestRangeCheckSmearing + * + */ + +import java.lang.annotation.*; +import java.lang.reflect.*; +import java.util.*; +import sun.hotspot.WhiteBox; +import sun.hotspot.code.NMethod; +import com.oracle.java.testlibrary.Platform; + +public class TestRangeCheckSmearing { + private static final WhiteBox WHITE_BOX = WhiteBox.getWhiteBox(); + + @Retention(RetentionPolicy.RUNTIME) + @interface Args { int[] value(); } + + // first range check is i + max of all constants + @Args({0, 8}) + static int m1(int[] array, int i, boolean allaccesses) { + int res = 0; + res += array[i+9]; + if (allaccesses) { + res += array[i+8]; + res += array[i+7]; + res += array[i+6]; + res += array[i+5]; + res += array[i+4]; + res += array[i+3]; + res += array[i+2]; + res += array[i+1]; + } + return res; + } + + // first range check is i + min of all constants + @Args({0, -9}) + static int m2(int[] array, int i, boolean allaccesses) { + int res = 0; + res += array[i+1]; + if (allaccesses) { + res += array[i+2]; + res += array[i+3]; + res += array[i+4]; + res += array[i+5]; + res += array[i+6]; + res += array[i+7]; + res += array[i+8]; + res += array[i+9]; + } + return res; + } + + // first range check is not i + min/max of all constants + @Args({0, 8}) + static int m3(int[] array, int i, boolean allaccesses) { + int res = 0; + res += array[i+3]; + if (allaccesses) { + res += array[i+2]; + res += array[i+1]; + res += array[i+4]; + res += array[i+5]; + res += array[i+6]; + res += array[i+7]; + res += array[i+8]; + res += array[i+9]; + } + return res; + } + + @Args({0, -9}) + static int m4(int[] array, int i, boolean allaccesses) { + int res = 0; + res += array[i+3]; + if (allaccesses) { + res += array[i+4]; + res += array[i+1]; + res += array[i+2]; + res += array[i+5]; + res += array[i+6]; + res += array[i+7]; + res += array[i+8]; + res += array[i+9]; + } + return res; + } + + @Args({0, -3}) + static int m5(int[] array, int i, boolean allaccesses) { + int res = 0; + res += array[i+3]; + res += array[i+2]; + if (allaccesses) { + res += array[i+1]; + res += array[i+4]; + res += array[i+5]; + res += array[i+6]; + res += array[i+7]; + res += array[i+8]; + res += array[i+9]; + } + return res; + } + + @Args({0, 6}) + static int m6(int[] array, int i, boolean allaccesses) { + int res = 0; + res += array[i+3]; + res += array[i+4]; + if (allaccesses) { + res += array[i+2]; + res += array[i+1]; + res += array[i+5]; + res += array[i+6]; + res += array[i+7]; + res += array[i+8]; + res += array[i+9]; + } + return res; + } + + @Args({0, 6}) + static int m7(int[] array, int i, boolean allaccesses) { + int res = 0; + res += array[i+3]; + res += array[i+2]; + res += array[i+4]; + if (allaccesses) { + res += array[i+1]; + res += array[i+5]; + res += array[i+6]; + res += array[i+7]; + res += array[i+8]; + res += array[i+9]; + } + return res; + } + + @Args({0, -3}) + static int m8(int[] array, int i, boolean allaccesses) { + int res = 0; + res += array[i+3]; + res += array[i+4]; + res += array[i+2]; + if (allaccesses) { + res += array[i+1]; + res += array[i+5]; + res += array[i+6]; + res += array[i+7]; + res += array[i+8]; + res += array[i+9]; + } + return res; + } + + @Args({6, 15}) + static int m9(int[] array, int i, boolean allaccesses) { + int res = 0; + res += array[i+3]; + if (allaccesses) { + res += array[i-2]; + res += array[i-1]; + res += array[i-4]; + res += array[i-5]; + res += array[i-6]; + } + return res; + } + + @Args({3, 12}) + static int m10(int[] array, int i, boolean allaccesses) { + int res = 0; + res += array[i+3]; + if (allaccesses) { + res += array[i-2]; + res += array[i-1]; + res += array[i-3]; + res += array[i+4]; + res += array[i+5]; + res += array[i+6]; + } + return res; + } + + @Args({3, -3}) + static int m11(int[] array, int i, boolean allaccesses) { + int res = 0; + res += array[i+3]; + res += array[i-2]; + if (allaccesses) { + res += array[i+5]; + res += array[i+6]; + } + return res; + } + + @Args({3, 6}) + static int m12(int[] array, int i, boolean allaccesses) { + int res = 0; + res += array[i+3]; + res += array[i+6]; + if (allaccesses) { + res += array[i-2]; + res += array[i-3]; + } + return res; + } + + // check that identical range check is replaced by dominating one + // only when correct + @Args({0}) + static int m13(int[] array, int i, boolean ignore) { + int res = 0; + res += array[i+3]; + res += array[i+3]; + return res; + } + + @Args({2, 0}) + static int m14(int[] array, int i, boolean ignore) { + int res = 0; + + res += array[i]; + res += array[i-2]; + res += array[i]; // If range check below were to be removed first this cannot be considered identical to first range check + res += array[i-1]; // range check removed so i-1 array access depends on previous check + + return res; + } + + static int[] m15_dummy = new int[10]; + @Args({2, 0}) + static int m15(int[] array, int i, boolean ignore) { + int res = 0; + res += array[i]; + + // When the loop is optimized out we don't want the + // array[i-1] access which is dependent on array[i]'s + // range check to become dependent on the identical range + // check above. + + int[] array2 = m15_dummy; + int j = 0; + for (; j < 10; j++); + if (j == 10) { + array2 = array; + } + + res += array2[i-2]; + res += array2[i]; + res += array2[i-1]; // range check removed so i-1 array access depends on previous check + + return res; + } + + @Args({2, 0}) + static int m16(int[] array, int i, boolean ignore) { + int res = 0; + + res += array[i]; + res += array[i-1]; + res += array[i-1]; + res += array[i-2]; + + return res; + } + + @Args({2, 0}) + static int m17(int[] array, int i, boolean ignore) { + int res = 0; + + res += array[i]; + res += array[i-2]; + res += array[i-2]; + res += array[i+2]; + res += array[i+2]; + res += array[i-1]; + res += array[i-1]; + + return res; + } + + static public void main(String[] args) { + if (WHITE_BOX.getBooleanVMFlag("BackgroundCompilation")) { + throw new AssertionError("Background compilation enabled"); + } + new TestRangeCheckSmearing().doTests(); + } + boolean success = true; + boolean exception = false; + final int[] array = new int[10]; + final HashMap<String,Method> tests = new HashMap<>(); + { + final Class<?> TEST_PARAM_TYPES[] = { int[].class, int.class, boolean.class }; + for (Method m : this.getClass().getDeclaredMethods()) { + if (m.getName().matches("m[0-9]+")) { + assert(Modifier.isStatic(m.getModifiers())) : m; + assert(m.getReturnType() == int.class) : m; + assert(Arrays.equals(m.getParameterTypes(), TEST_PARAM_TYPES)) : m; + tests.put(m.getName(), m); + } + } + } + + void invokeTest(Method m, int[] array, int index, boolean z) { + try { + m.invoke(null, array, index, z); + } catch (ReflectiveOperationException roe) { + Throwable ex = roe.getCause(); + if (ex instanceof ArrayIndexOutOfBoundsException) + throw (ArrayIndexOutOfBoundsException) ex; + throw new AssertionError(roe); + } + } + + void doTest(String name) { + Method m = tests.get(name); + tests.remove(name); + int[] args = m.getAnnotation(Args.class).value(); + int index0 = args[0], index1; + boolean exceptionRequired = true; + if (args.length == 2) { + index1 = args[1]; + } else { + // no negative test for this one + assert(args.length == 1); + assert(name.equals("m13")); + exceptionRequired = false; + index1 = index0; + } + // Get the method compiled. + if (!WHITE_BOX.isMethodCompiled(m)) { + // If not, try to compile it with C2 + if(!WHITE_BOX.enqueueMethodForCompilation(m, CompilerWhiteBoxTest.COMP_LEVEL_FULL_OPTIMIZATION)) { + // C2 compiler not available, try to compile with C1 + WHITE_BOX.enqueueMethodForCompilation(m, CompilerWhiteBoxTest.COMP_LEVEL_SIMPLE); + } + } + if (!WHITE_BOX.isMethodCompiled(m)) { + throw new RuntimeException(m + " not compiled"); + } + + // valid access + invokeTest(m, array, index0, true); + + if (!WHITE_BOX.isMethodCompiled(m)) { + throw new RuntimeException(m + " deoptimized on valid array access"); + } + + exception = false; + boolean test_success = true; + try { + invokeTest(m, array, index1, false); + } catch(ArrayIndexOutOfBoundsException aioob) { + exception = true; + System.out.println("ArrayIndexOutOfBoundsException thrown in "+name); + } + if (!exception) { + System.out.println("ArrayIndexOutOfBoundsException was not thrown in "+name); + } + + if (Platform.isServer()) { + if (exceptionRequired == WHITE_BOX.isMethodCompiled(m)) { + System.out.println((exceptionRequired?"Didn't deoptimized":"deoptimized") + " in "+name); + test_success = false; + } + } + + if (exception != exceptionRequired) { + System.out.println((exceptionRequired?"exception required but not thrown":"not exception required but thrown") + " in "+name); + test_success = false; + } + + if (!test_success) { + success = false; + System.out.println("TEST FAILED: "+name); + } + + } + void doTests() { + doTest("m1"); + doTest("m2"); + doTest("m3"); + doTest("m4"); + doTest("m5"); + doTest("m6"); + doTest("m7"); + doTest("m8"); + doTest("m9"); + doTest("m10"); + doTest("m11"); + doTest("m12"); + doTest("m13"); + doTest("m14"); + doTest("m15"); + doTest("m16"); + doTest("m17"); + if (!success) { + throw new RuntimeException("Some tests failed"); + } + assert(tests.isEmpty()) : tests; + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/compiler/rangechecks/TestRangeCheckSmearingLoopOpts.java Tue Feb 03 16:48:05 2015 +0000 @@ -0,0 +1,76 @@ +/* + * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 8048170 + * @summary Following range check smearing, range check cannot be replaced by dominating identical test. + * @run main/othervm -XX:-BackgroundCompilation -XX:-UseOnStackReplacement TestRangeCheckSmearingLoopOpts + * + */ +public class TestRangeCheckSmearingLoopOpts { + + static int dummy; + + static int m1(int[] array, int i) { + for (;;) { + for (;;) { + if (array[i] < 0) { // range check (i+0) dominates equivalent check below + break; + } + i++; + } + + // A control flow that stops IfNode::up_one_dom() + if ((i % 2)== 0) { + if ((array[i] % 2) == 0) { + dummy = i; + } + } + + // IfNode::Ideal will rewrite some range checks if Compile::allow_range_check_smearing + if (array[i-1] == 9) { // range check (i-1) unchanged + int res = array[i-3]; // range check (i-3) unchanged + res += array[i]; // range check (i+0) unchanged + res += array[i-2]; // removed redundant range check + // the previous access might be hoisted by + // PhaseIdealLoop::split_if_with_blocks_post because + // it appears to have the same guard, but it also + // depends on the previous guards + return res; + } + i++; + } + } + + static public void main(String[] args) { + int[] array = { 0, 1, 2, -3, 4, 5, -2, 7, 8, 9, -1 }; + for (int i = 0; i < 20000; i++) { + m1(array, 0); + } + array[0] = -1; + try { + m1(array, 0); + } catch(ArrayIndexOutOfBoundsException aioobe) {} + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/compiler/startup/NumCompilerThreadsCheck.java Tue Feb 03 16:48:05 2015 +0000 @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 8034775 + * @summary Ensures correct minimal number of compiler threads (provided by -XX:CICompilerCount=) + * @library /testlibrary + */ +import com.oracle.java.testlibrary.*; + +public class NumCompilerThreadsCheck { + + public static void main(String[] args) throws Exception { + ProcessBuilder pb = ProcessTools.createJavaProcessBuilder("-XX:CICompilerCount=-1"); + OutputAnalyzer out = new OutputAnalyzer(pb.start()); + + String expectedOutput = "CICompilerCount of -1 is invalid"; + out.shouldContain(expectedOutput); + + if (isZeroVm()) { + String expectedLowWaterMarkText = "must be at least 0"; + out.shouldContain(expectedLowWaterMarkText); + } + } + + private static boolean isZeroVm() { + String vmName = System.getProperty("java.vm.name"); + if (vmName == null) { + throw new RuntimeException("No VM name"); + } + if (vmName.toLowerCase().contains("zero")) { + return true; + } + return false; + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/compiler/uncommontrap/TestDeoptOOM.java Tue Feb 03 16:48:05 2015 +0000 @@ -0,0 +1,426 @@ +/* + * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 6898462 + * @summary failed reallocations of scalar replaced objects during deoptimization causes crash + * @run main/othervm -XX:-BackgroundCompilation -XX:CompileCommand=exclude,TestDeoptOOM::main -XX:CompileCommand=exclude,TestDeoptOOM::m9_1 -Xmx128M TestDeoptOOM + * + */ + +public class TestDeoptOOM { + + long f1; + long f2; + long f3; + long f4; + long f5; + + static class LinkedList { + LinkedList l; + long[] array; + LinkedList(LinkedList l, int size) { + array = new long[size]; + this.l = l; + } + } + + static LinkedList ll; + + static void consume_all_memory() { + int size = 128 * 1024 * 1024; + while(size > 0) { + try { + while(true) { + ll = new LinkedList(ll, size); + } + } catch(OutOfMemoryError oom) { + } + size = size / 2; + } + } + + static void free_memory() { + ll = null; + } + + static TestDeoptOOM m1(boolean deopt) { + try { + TestDeoptOOM tdoom = new TestDeoptOOM(); + if (deopt) { + return tdoom; + } + } catch(OutOfMemoryError oom) { + free_memory(); + System.out.println("OOM caught in m1"); + } + return null; + } + + static TestDeoptOOM m2_1(boolean deopt) { + try { + TestDeoptOOM tdoom = new TestDeoptOOM(); + if (deopt) { + return tdoom; + } + } catch(OutOfMemoryError oom) { + free_memory(); + System.out.println("OOM caught in m2_1"); + } + return null; + } + + static TestDeoptOOM m2(boolean deopt) { + try { + return m2_1(deopt); + } catch(OutOfMemoryError oom) { + free_memory(); + System.out.println("OOM caught in m2"); + } + return null; + } + + static TestDeoptOOM m3_3(boolean deopt) { + try { + TestDeoptOOM tdoom = new TestDeoptOOM(); + if (deopt) { + return tdoom; + } + } catch(OutOfMemoryError oom) { + free_memory(); + System.out.println("OOM caught in m3_3"); + } + return null; + } + + static boolean m3_2(boolean deopt) { + try { + return m3_3(deopt) != null; + } catch(OutOfMemoryError oom) { + free_memory(); + System.out.println("OOM caught in m3_2"); + } + return false; + } + + static TestDeoptOOM m3_1(boolean deopt) { + try { + TestDeoptOOM tdoom = new TestDeoptOOM(); + if (m3_2(deopt)) { + return tdoom; + } + } catch(OutOfMemoryError oom) { + free_memory(); + System.out.println("OOM caught in m3_1"); + } + return null; + } + + static TestDeoptOOM m3(boolean deopt) { + try { + return m3_1(deopt); + } catch(OutOfMemoryError oom) { + free_memory(); + System.out.println("OOM caught in m3"); + } + return null; + } + + static TestDeoptOOM m4(boolean deopt) { + try { + TestDeoptOOM tdoom = new TestDeoptOOM(); + if (deopt) { + tdoom.f1 = 1l; + tdoom.f2 = 2l; + tdoom.f3 = 3l; + return tdoom; + } + } catch(OutOfMemoryError oom) { + free_memory(); + System.out.println("OOM caught in m4"); + } + return null; + } + + static TestDeoptOOM m5(boolean deopt) { + try { + TestDeoptOOM tdoom = new TestDeoptOOM(); + synchronized(tdoom) { + if (deopt) { + return tdoom; + } + } + } catch(OutOfMemoryError oom) { + free_memory(); + System.out.println("OOM caught in m5"); + } + return null; + } + + synchronized TestDeoptOOM m6_1(boolean deopt) { + if (deopt) { + return this; + } + return null; + } + + static TestDeoptOOM m6(boolean deopt) { + try { + TestDeoptOOM tdoom = new TestDeoptOOM(); + return tdoom.m6_1(deopt); + } catch(OutOfMemoryError oom) { + free_memory(); + System.out.println("OOM caught in m6"); + } + return null; + } + + static TestDeoptOOM m7_1(boolean deopt, Object lock) { + try { + synchronized(lock) { + TestDeoptOOM tdoom = new TestDeoptOOM(); + if (deopt) { + return tdoom; + } + } + } catch(OutOfMemoryError oom) { + free_memory(); + System.out.println("OOM caught in m7_1"); + } + return null; + } + + static TestDeoptOOM m7(boolean deopt, Object lock) { + try { + return m7_1(deopt, lock); + } catch(OutOfMemoryError oom) { + free_memory(); + System.out.println("OOM caught in m7"); + } + return null; + } + + static class A { + long f1; + long f2; + long f3; + long f4; + long f5; + } + + static class B { + long f1; + long f2; + long f3; + long f4; + long f5; + + A a; + } + + static B m8(boolean deopt) { + try { + A a = new A(); + B b = new B(); + b.a = a; + if (deopt) { + return b; + } + } catch(OutOfMemoryError oom) { + free_memory(); + System.out.println("OOM caught in m8"); + } + return null; + } + + static void m9_1(int i) { + if (i > 90000) { + consume_all_memory(); + } + } + + static TestDeoptOOM m9() { + try { + for (int i = 0; i < 100000; i++) { + TestDeoptOOM tdoom = new TestDeoptOOM(); + m9_1(i); + if (i > 90000) { + return tdoom; + } + } + } catch(OutOfMemoryError oom) { + free_memory(); + System.out.println("OOM caught in m1"); + } + return null; + } + + public static void main(String[] args) { + for (int i = 0; i < 20000; i++) { + m1(false); + } + + consume_all_memory(); + + try { + m1(true); + } catch(OutOfMemoryError oom) { + free_memory(); + System.out.println("OOM caught in main " + oom.getMessage()); + } + + free_memory(); + + for (int i = 0; i < 20000; i++) { + m2(false); + } + + consume_all_memory(); + + try { + m2(true); + } catch(OutOfMemoryError oom) { + free_memory(); + System.out.println("OOM caught in main"); + } + + free_memory(); + + for (int i = 0; i < 20000; i++) { + m3(false); + } + + consume_all_memory(); + + try { + m3(true); + } catch(OutOfMemoryError oom) { + free_memory(); + System.out.println("OOM caught in main"); + } + + free_memory(); + + for (int i = 0; i < 20000; i++) { + m4(false); + } + + consume_all_memory(); + + try { + m4(true); + } catch(OutOfMemoryError oom) { + free_memory(); + System.out.println("OOM caught in main"); + } + + free_memory(); + + for (int i = 0; i < 20000; i++) { + m5(false); + } + + consume_all_memory(); + + try { + m5(true); + } catch(OutOfMemoryError oom) { + free_memory(); + System.out.println("OOM caught in main"); + } + + free_memory(); + + for (int i = 0; i < 20000; i++) { + m6(false); + } + + consume_all_memory(); + + try { + m6(true); + } catch(OutOfMemoryError oom) { + free_memory(); + System.out.println("OOM caught in main"); + } + + free_memory(); + + final Object lock = new Object(); + + for (int i = 0; i < 20000; i++) { + m7(false, lock); + } + + consume_all_memory(); + + try { + m7(true, lock); + } catch(OutOfMemoryError oom) { + free_memory(); + System.out.println("OOM caught in main"); + } + + free_memory(); + + Thread thread = new Thread() { + public void run() { + System.out.println("Acquiring lock"); + synchronized(lock) { + System.out.println("Lock acquired"); + } + System.out.println("Lock released"); + } + }; + thread.start(); + try { + thread.join(); + } catch(InterruptedException ie) { + } + + for (int i = 0; i < 20000; i++) { + m8(false); + } + + consume_all_memory(); + + try { + m8(true); + } catch(OutOfMemoryError oom) { + free_memory(); + System.out.println("OOM caught in main"); + } + + free_memory(); + + try { + m9(); + } catch(OutOfMemoryError oom) { + free_memory(); + System.out.println("OOM caught in main"); + } + + free_memory(); + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/compiler/uncommontrap/TraceDeoptimizationNoRealloc.java Tue Feb 03 16:48:05 2015 +0000 @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 8067144 + * @summary -XX:+TraceDeoptimization tries to print realloc'ed objects even when there are none + * @run main/othervm -XX:-BackgroundCompilation -XX:-UseOnStackReplacement -XX:+IgnoreUnrecognizedVMOptions -XX:+TraceDeoptimization TraceDeoptimizationNoRealloc + * + */ + +public class TraceDeoptimizationNoRealloc { + + static void m(boolean some_condition) { + if (some_condition) { + return; + } + } + + + static public void main(String[] args) { + for (int i = 0; i < 20000; i++) { + m(false); + } + m(true); + } +}
--- a/test/compiler/whitebox/CompilerWhiteBoxTest.java Thu Jan 08 12:47:32 2015 +0000 +++ b/test/compiler/whitebox/CompilerWhiteBoxTest.java Tue Feb 03 16:48:05 2015 +0000 @@ -72,9 +72,9 @@ /** Flag for verbose output, true if {@code -Dverbose} specified */ protected static final boolean IS_VERBOSE = System.getProperty("verbose") != null; - /** count of invocation to triger compilation */ + /** invocation count to trigger compilation */ protected static final int THRESHOLD; - /** count of invocation to triger OSR compilation */ + /** invocation count to trigger OSR compilation */ protected static final long BACKEDGE_THRESHOLD; /** Value of {@code java.vm.info} (interpreted|mixed|comp mode) */ protected static final String MODE = System.getProperty("java.vm.info"); @@ -206,7 +206,6 @@ * is compiled, or if {@linkplain #method} has zero * compilation level. */ - protected final void checkNotCompiled(int compLevel) { if (WHITE_BOX.isMethodQueuedForCompilation(method)) { throw new RuntimeException(method + " must not be in queue"); @@ -227,20 +226,30 @@ * compilation level. */ protected final void checkNotCompiled() { + checkNotCompiled(true); + checkNotCompiled(false); + } + + /** + * Checks, that {@linkplain #method} is not (OSR-)compiled. + * + * @param isOsr Check for OSR compilation if true + * @throws RuntimeException if {@linkplain #method} is in compiler queue or + * is compiled, or if {@linkplain #method} has zero + * compilation level. + */ + protected final void checkNotCompiled(boolean isOsr) { + waitBackgroundCompilation(); if (WHITE_BOX.isMethodQueuedForCompilation(method)) { throw new RuntimeException(method + " must not be in queue"); } - if (WHITE_BOX.isMethodCompiled(method, false)) { - throw new RuntimeException(method + " must be not compiled"); - } - if (WHITE_BOX.getMethodCompilationLevel(method, false) != 0) { - throw new RuntimeException(method + " comp_level must be == 0"); + if (WHITE_BOX.isMethodCompiled(method, isOsr)) { + throw new RuntimeException(method + " must not be " + + (isOsr ? "osr_" : "") + "compiled"); } - if (WHITE_BOX.isMethodCompiled(method, true)) { - throw new RuntimeException(method + " must be not osr_compiled"); - } - if (WHITE_BOX.getMethodCompilationLevel(method, true) != 0) { - throw new RuntimeException(method + " osr_comp_level must be == 0"); + if (WHITE_BOX.getMethodCompilationLevel(method, isOsr) != 0) { + throw new RuntimeException(method + (isOsr ? " osr_" : " ") + + "comp_level must be == 0"); } } @@ -306,12 +315,21 @@ * Waits for completion of background compilation of {@linkplain #method}. */ protected final void waitBackgroundCompilation() { + waitBackgroundCompilation(method); + } + + /** + * Waits for completion of background compilation of the given executable. + * + * @param executable Executable + */ + protected static final void waitBackgroundCompilation(Executable executable) { if (!BACKGROUND_COMPILATION) { return; } final Object obj = new Object(); for (int i = 0; i < 10 - && WHITE_BOX.isMethodQueuedForCompilation(method); ++i) { + && WHITE_BOX.isMethodQueuedForCompilation(executable); ++i) { synchronized (obj) { try { obj.wait(1000); @@ -425,14 +443,14 @@ /** constructor test case */ CONSTRUCTOR_TEST(Helper.CONSTRUCTOR, Helper.CONSTRUCTOR_CALLABLE, false), /** method test case */ - METOD_TEST(Helper.METHOD, Helper.METHOD_CALLABLE, false), + METHOD_TEST(Helper.METHOD, Helper.METHOD_CALLABLE, false), /** static method test case */ STATIC_TEST(Helper.STATIC, Helper.STATIC_CALLABLE, false), /** OSR constructor test case */ OSR_CONSTRUCTOR_TEST(Helper.OSR_CONSTRUCTOR, Helper.OSR_CONSTRUCTOR_CALLABLE, true), /** OSR method test case */ - OSR_METOD_TEST(Helper.OSR_METHOD, Helper.OSR_METHOD_CALLABLE, true), + OSR_METHOD_TEST(Helper.OSR_METHOD, Helper.OSR_METHOD_CALLABLE, true), /** OSR static method test case */ OSR_STATIC_TEST(Helper.OSR_STATIC, Helper.OSR_STATIC_CALLABLE, true); @@ -494,7 +512,7 @@ = new Callable<Integer>() { @Override public Integer call() throws Exception { - return new Helper(null).hashCode(); + return new Helper(null, CompilerWhiteBoxTest.BACKEDGE_THRESHOLD).hashCode(); } }; @@ -504,7 +522,7 @@ @Override public Integer call() throws Exception { - return helper.osrMethod(); + return helper.osrMethod(CompilerWhiteBoxTest.BACKEDGE_THRESHOLD); } }; @@ -512,7 +530,7 @@ = new Callable<Integer>() { @Override public Integer call() throws Exception { - return osrStaticMethod(); + return osrStaticMethod(CompilerWhiteBoxTest.BACKEDGE_THRESHOLD); } }; @@ -532,25 +550,24 @@ } try { OSR_CONSTRUCTOR = Helper.class.getDeclaredConstructor( - Object.class); + Object.class, long.class); } catch (NoSuchMethodException | SecurityException e) { throw new RuntimeException( - "exception on getting method Helper.<init>(Object)", e); + "exception on getting method Helper.<init>(Object, long)", e); } METHOD = getMethod("method"); STATIC = getMethod("staticMethod"); - OSR_METHOD = getMethod("osrMethod"); - OSR_STATIC = getMethod("osrStaticMethod"); + OSR_METHOD = getMethod("osrMethod", long.class); + OSR_STATIC = getMethod("osrStaticMethod", long.class); } - private static Method getMethod(String name) { + private static Method getMethod(String name, Class<?>... parameterTypes) { try { - return Helper.class.getDeclaredMethod(name); + return Helper.class.getDeclaredMethod(name, parameterTypes); } catch (NoSuchMethodException | SecurityException e) { throw new RuntimeException( "exception on getting method Helper." + name, e); } - } private static int staticMethod() { @@ -561,17 +578,84 @@ return 42; } - private static int osrStaticMethod() { + /** + * Deoptimizes all non-osr versions of the given executable after + * compilation finished. + * + * @param e Executable + * @throws Exception + */ + private static void waitAndDeoptimize(Executable e) { + CompilerWhiteBoxTest.waitBackgroundCompilation(e); + if (WhiteBox.getWhiteBox().isMethodQueuedForCompilation(e)) { + throw new RuntimeException(e + " must not be in queue"); + } + // Deoptimize non-osr versions of executable + WhiteBox.getWhiteBox().deoptimizeMethod(e, false); + } + + /** + * Executes the method multiple times to make sure we have + * enough profiling information before triggering an OSR + * compilation. Otherwise the C2 compiler may add uncommon traps. + * + * @param m Method to be executed + * @return Number of times the method was executed + * @throws Exception + */ + private static int warmup(Method m) throws Exception { + waitAndDeoptimize(m); + Helper helper = new Helper(); int result = 0; - for (long i = 0; i < CompilerWhiteBoxTest.BACKEDGE_THRESHOLD; ++i) { + for (long i = 0; i < CompilerWhiteBoxTest.THRESHOLD; ++i) { + result += (int)m.invoke(helper, 1); + } + // Wait to make sure OSR compilation is not blocked by + // non-OSR compilation in the compile queue + CompilerWhiteBoxTest.waitBackgroundCompilation(m); + return result; + } + + /** + * Executes the constructor multiple times to make sure we + * have enough profiling information before triggering an OSR + * compilation. Otherwise the C2 compiler may add uncommon traps. + * + * @param c Constructor to be executed + * @return Number of times the constructor was executed + * @throws Exception + */ + private static int warmup(Constructor c) throws Exception { + waitAndDeoptimize(c); + int result = 0; + for (long i = 0; i < CompilerWhiteBoxTest.THRESHOLD; ++i) { + result += c.newInstance(null, 1).hashCode(); + } + // Wait to make sure OSR compilation is not blocked by + // non-OSR compilation in the compile queue + CompilerWhiteBoxTest.waitBackgroundCompilation(c); + return result; + } + + private static int osrStaticMethod(long limit) throws Exception { + int result = 0; + if (limit != 1) { + result = warmup(OSR_STATIC); + } + // Trigger osr compilation + for (long i = 0; i < limit; ++i) { result += staticMethod(); } return result; } - private int osrMethod() { + private int osrMethod(long limit) throws Exception { int result = 0; - for (long i = 0; i < CompilerWhiteBoxTest.BACKEDGE_THRESHOLD; ++i) { + if (limit != 1) { + result = warmup(OSR_METHOD); + } + // Trigger osr compilation + for (long i = 0; i < limit; ++i) { result += method(); } return result; @@ -585,9 +669,13 @@ } // for OSR constructor test case - private Helper(Object o) { + private Helper(Object o, long limit) throws Exception { int result = 0; - for (long i = 0; i < CompilerWhiteBoxTest.BACKEDGE_THRESHOLD; ++i) { + if (limit != 1) { + result = warmup(OSR_CONSTRUCTOR); + } + // Trigger osr compilation + for (long i = 0; i < limit; ++i) { result += method(); } x = result;
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/compiler/whitebox/DeoptimizeMultipleOSRTest.java Tue Feb 03 16:48:05 2015 +0000 @@ -0,0 +1,95 @@ +/* + * Copyright (c) 2013, 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import sun.hotspot.WhiteBox; +import java.lang.reflect.Executable; +import java.lang.reflect.Method; + +/* + * @test DeoptimizeMultipleOSRTest + * @bug 8061817 + * @library /testlibrary /testlibrary/whitebox + * @build DeoptimizeMultipleOSRTest + * @run main ClassFileInstaller sun.hotspot.WhiteBox + * sun.hotspot.WhiteBox$WhiteBoxPermission + * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -XX:CompileCommand=compileonly,DeoptimizeMultipleOSRTest::triggerOSR DeoptimizeMultipleOSRTest + * @summary testing of WB::deoptimizeMethod() + */ +public class DeoptimizeMultipleOSRTest { + private static final WhiteBox WHITE_BOX = WhiteBox.getWhiteBox(); + private static final long BACKEDGE_THRESHOLD = 150000; + private Method method; + private int counter = 0; + + public static void main(String[] args) throws Exception { + DeoptimizeMultipleOSRTest test = new DeoptimizeMultipleOSRTest(); + test.test(); + } + + /** + * Triggers two different OSR compilations for the same method and + * checks if WhiteBox.deoptimizeMethod() deoptimizes both. + * + * @throws Exception + */ + public void test() throws Exception { + method = DeoptimizeMultipleOSRTest.class.getDeclaredMethod("triggerOSR", boolean.class, long.class); + // Trigger two OSR compiled versions + triggerOSR(true, BACKEDGE_THRESHOLD); + triggerOSR(false, BACKEDGE_THRESHOLD); + // Wait for compilation + CompilerWhiteBoxTest.waitBackgroundCompilation(method); + // Deoptimize + WHITE_BOX.deoptimizeMethod(method, true); + if (WHITE_BOX.isMethodCompiled(method, true)) { + throw new AssertionError("Not all OSR compiled versions were deoptimized"); + } + } + + /** + * Triggers OSR compilations by executing loops. + * + * @param first Determines which loop to execute + * @param limit The number of loop iterations + */ + public void triggerOSR(boolean first, long limit) { + if (limit != 1) { + // Warmup method to avoid uncommon traps + for (int i = 0; i < limit; ++i) { + triggerOSR(first, 1); + } + CompilerWhiteBoxTest.waitBackgroundCompilation(method); + } + if (first) { + // Trigger OSR compilation 1 + for (int i = 0; i < limit; ++i) { + counter++; + } + } else { + // Trigger OSR compilation 2 + for (int i = 0; i < limit; ++i) { + counter++; + } + } + } +}
--- a/test/compiler/whitebox/IsMethodCompilableTest.java Thu Jan 08 12:47:32 2015 +0000 +++ b/test/compiler/whitebox/IsMethodCompilableTest.java Tue Feb 03 16:48:05 2015 +0000 @@ -28,7 +28,7 @@ * @build IsMethodCompilableTest * @run main ClassFileInstaller sun.hotspot.WhiteBox * @run main ClassFileInstaller com.oracle.java.testlibrary.Platform - * @run main/othervm/timeout=2400 -Xbootclasspath/a:. -Xmixed -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -XX:PerMethodRecompilationCutoff=3 -XX:CompileCommand=compileonly,SimpleTestCase$Helper::* IsMethodCompilableTest + * @run main/othervm/timeout=2400 -Xbootclasspath/a:. -Xmixed -XX:-TieredCompilation -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -XX:PerMethodRecompilationCutoff=3 -XX:CompileCommand=compileonly,SimpleTestCase$Helper::* IsMethodCompilableTest * @summary testing of WB::isMethodCompilable() * @author igor.ignatyev@oracle.com */
--- a/test/compiler/whitebox/MakeMethodNotCompilableTest.java Thu Jan 08 12:47:32 2015 +0000 +++ b/test/compiler/whitebox/MakeMethodNotCompilableTest.java Tue Feb 03 16:48:05 2015 +0000 @@ -131,14 +131,15 @@ throw new RuntimeException(method + " is not compilable after clearMethodState()"); } - + // Make method not (OSR-)compilable (depending on testCase.isOsr()) makeNotCompilable(); if (isCompilable()) { throw new RuntimeException(method + " must be not compilable"); } - + // Try to (OSR-)compile method compile(); - checkNotCompiled(); + // Method should not be (OSR-)compiled + checkNotCompiled(testCase.isOsr()); if (isCompilable()) { throw new RuntimeException(method + " must be not compilable"); }
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/gc/arguments/TestSurvivorAlignmentInBytesOption.java Tue Feb 03 16:48:05 2015 +0000 @@ -0,0 +1,107 @@ +/* + * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import com.oracle.java.testlibrary.ExitCode; +import com.oracle.java.testlibrary.cli.CommandLineOptionTest; + +/** + * @test + * @bug 8031323 + * @summary Verify SurvivorAlignmentInBytes option processing. + * @library /testlibrary + * @requires vm.opt.SurvivorAlignmentInBytes == null + * & vm.opt.ObjectAlignmentInBytes == null + * & vm.opt.UnlockExperimentalVMOptions == null + * & (vm.opt.IgnoreUnrecognizedVMOptions == null + * | vm.opt.IgnoreUnrecognizedVMOptions == "false") + * @run main TestSurvivorAlignmentInBytesOption + */ +public class TestSurvivorAlignmentInBytesOption { + public static void main(String args[]) throws Throwable { + String optionName = "SurvivorAlignmentInBytes"; + String unlockExperimentalVMOpts = "UnlockExperimentalVMOptions"; + String optionIsExperimental + = CommandLineOptionTest.getExperimentalOptionErrorMessage( + optionName); + String valueIsTooSmall= ".*SurvivorAlignmentInBytes=.*must be greater" + + " than ObjectAlignmentInBytes.*"; + String mustBePowerOf2 = ".*SurvivorAlignmentInBytes=.*must be " + + "power of 2.*"; + + // Verify that without -XX:+UnlockExperimentalVMOptions usage of + // SurvivorAlignmentInBytes option will cause JVM startup failure + // with the warning message saying that that option is experimental. + CommandLineOptionTest.verifyJVMStartup( + new String[]{optionIsExperimental}, null, ExitCode.FAIL, false, + "-XX:-UnlockExperimentalVMOptions", + CommandLineOptionTest.prepareBooleanFlag( + unlockExperimentalVMOpts, false), + CommandLineOptionTest.prepareNumericFlag(optionName, 64)); + + // Verify that with -XX:+UnlockExperimentalVMOptions passed to JVM + // usage of SurvivorAlignmentInBytes option won't cause JVM startup + // failure. + CommandLineOptionTest.verifyJVMStartup( + null, new String[]{optionIsExperimental}, ExitCode.OK, false, + CommandLineOptionTest.prepareBooleanFlag( + unlockExperimentalVMOpts, true), + CommandLineOptionTest.prepareNumericFlag(optionName, 64)); + + // Verify that if specified SurvivorAlignmentInBytes is lower then + // ObjectAlignmentInBytes, then the JVM startup will fail with + // appropriate error message. + CommandLineOptionTest.verifyJVMStartup( + new String[]{valueIsTooSmall}, null, ExitCode.FAIL, false, + CommandLineOptionTest.prepareBooleanFlag( + unlockExperimentalVMOpts, true), + CommandLineOptionTest.prepareNumericFlag(optionName, 2)); + + // Verify that if specified SurvivorAlignmentInBytes value is not + // a power of 2 then the JVM startup will fail with appropriate error + // message. + CommandLineOptionTest.verifyJVMStartup( + new String[]{mustBePowerOf2}, null, ExitCode.FAIL, false, + CommandLineOptionTest.prepareBooleanFlag( + unlockExperimentalVMOpts, true), + CommandLineOptionTest.prepareNumericFlag(optionName, 127)); + + // Verify that if SurvivorAlignmentInBytes has correct value, then + // the JVM will be started without errors. + CommandLineOptionTest.verifyJVMStartup( + null, new String[]{".*SurvivorAlignmentInBytes.*"}, + ExitCode.OK, false, + CommandLineOptionTest.prepareBooleanFlag( + unlockExperimentalVMOpts, true), + CommandLineOptionTest.prepareNumericFlag(optionName, 128)); + + // Verify that we can setup different SurvivorAlignmentInBytes values. + for (int alignment = 32; alignment <= 128; alignment *= 2) { + CommandLineOptionTest.verifyOptionValue(optionName, + Integer.toString(alignment), + CommandLineOptionTest.prepareBooleanFlag( + unlockExperimentalVMOpts, true), + CommandLineOptionTest.prepareNumericFlag( + optionName, alignment)); + } + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/gc/concurrentMarkSweep/DisableResizePLAB.java Tue Feb 03 16:48:05 2015 +0000 @@ -0,0 +1,44 @@ +/* +* Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. +* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +* +* This code is free software; you can redistribute it and/or modify it +* under the terms of the GNU General Public License version 2 only, as +* published by the Free Software Foundation. +* +* This code is distributed in the hope that it will be useful, but WITHOUT +* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +* version 2 for more details (a copy is included in the LICENSE file that +* accompanied this code). +* +* You should have received a copy of the GNU General Public License version +* 2 along with this work; if not, write to the Free Software Foundation, +* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. +* +* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA +* or visit www.oracle.com if you need additional information or have any +* questions. +*/ + +/* + * @test DisableResizePLAB + * @key gc + * @bug 8060467 + * @author filipp.zhinkin@oracle.com, john.coomes@oracle.com + * @summary Run CMS with PLAB resizing disabled and a small OldPLABSize + * @run main/othervm -XX:+UseConcMarkSweepGC -XX:-ResizePLAB -XX:OldPLABSize=1k -Xmx256m -XX:+PrintGCDetails DisableResizePLAB + */ + +public class DisableResizePLAB { + public static void main(String args[]) throws Exception { + Object garbage[] = new Object[1_000]; + for (int i = 0; i < garbage.length; i++) { + garbage[i] = new byte[0]; + } + long startTime = System.currentTimeMillis(); + while (System.currentTimeMillis() - startTime < 10_000) { + Object o = new byte[1024]; + } + } +}
--- a/test/gc/g1/TestHumongousShrinkHeap.java Thu Jan 08 12:47:32 2015 +0000 +++ b/test/gc/g1/TestHumongousShrinkHeap.java Tue Feb 03 16:48:05 2015 +0000 @@ -24,9 +24,12 @@ /** * @test TestHumongousShrinkHeap * @bug 8036025 8056043 - * @summary Verify that heap shrinks after GC in the presence of fragmentation due to humongous objects + * @summary Verify that heap shrinks after GC in the presence of fragmentation + * due to humongous objects * @library /testlibrary - * @run main/othervm -XX:MinHeapFreeRatio=10 -XX:MaxHeapFreeRatio=12 -XX:+UseG1GC -XX:G1HeapRegionSize=1M -verbose:gc TestHumongousShrinkHeap + * @run main/othervm -XX:-ExplicitGCInvokesConcurrent -XX:MinHeapFreeRatio=10 + * -XX:MaxHeapFreeRatio=12 -XX:+UseG1GC -XX:G1HeapRegionSize=1M -verbose:gc + * TestHumongousShrinkHeap */ import java.lang.management.ManagementFactory;
--- a/test/gc/g1/TestShrinkAuxiliaryData.java Thu Jan 08 12:47:32 2015 +0000 +++ b/test/gc/g1/TestShrinkAuxiliaryData.java Tue Feb 03 16:48:05 2015 +0000 @@ -45,6 +45,7 @@ "-XX:MaxHeapFreeRatio=11", "-XX:+UseG1GC", "-XX:G1HeapRegionSize=1m", + "-XX:-ExplicitGCInvokesConcurrent", "-XX:+PrintGCDetails" };
--- a/test/gc/g1/TestShrinkDefragmentedHeap.java Thu Jan 08 12:47:32 2015 +0000 +++ b/test/gc/g1/TestShrinkDefragmentedHeap.java Tue Feb 03 16:48:05 2015 +0000 @@ -59,6 +59,7 @@ "-XX:MaxHeapFreeRatio=11", "-XX:+UseG1GC", "-XX:G1HeapRegionSize=" + REGION_SIZE, + "-XX:-ExplicitGCInvokesConcurrent", "-verbose:gc", GCTest.class.getName() );
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/gc/survivorAlignment/AlignmentHelper.java Tue Feb 03 16:48:05 2015 +0000 @@ -0,0 +1,174 @@ +/* + * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.lang.management.MemoryPoolMXBean; +import java.util.Optional; + +import sun.hotspot.WhiteBox; + +/** + * Helper class aimed to provide information about alignment of objects in + * particular heap space, expected memory usage after objects' allocation so on. + */ +public class AlignmentHelper { + private static final WhiteBox WHITE_BOX = WhiteBox.getWhiteBox(); + + private static final long OBJECT_ALIGNMENT_IN_BYTES_FOR_32_VM = 8L; + + /** + * Max relative allowed actual memory usage deviation from expected memory + * usage. + */ + private static final float MAX_RELATIVE_DEVIATION = 0.05f; // 5% + + public static final long OBJECT_ALIGNMENT_IN_BYTES = Optional.ofNullable( + AlignmentHelper.WHITE_BOX.getIntxVMFlag("ObjectAlignmentInBytes")) + .orElse(AlignmentHelper.OBJECT_ALIGNMENT_IN_BYTES_FOR_32_VM); + + public static final long SURVIVOR_ALIGNMENT_IN_BYTES = Optional.ofNullable( + AlignmentHelper.WHITE_BOX.getIntxVMFlag("SurvivorAlignmentInBytes")) + .orElseThrow(() ->new AssertionError( + "Unable to get SurvivorAlignmentInBytes value")); + /** + * Min amount of memory that will be occupied by an object. + */ + public static final long MIN_OBJECT_SIZE + = AlignmentHelper.WHITE_BOX.getObjectSize(new Object()); + /** + * Min amount of memory that will be occupied by an empty byte array. + */ + public static final long MIN_ARRAY_SIZE + = AlignmentHelper.WHITE_BOX.getObjectSize(new byte[0]); + + /** + * Precision at which actual memory usage in a heap space represented by + * this sizing helper could be measured. + */ + private final long memoryUsageMeasurementPrecision; + /** + * Min amount of memory that will be occupied by an object allocated in a + * heap space represented by this sizing helper. + */ + private final long minObjectSizeInThisSpace; + /** + * Object's alignment in a heap space represented by this sizing helper. + */ + private final long objectAlignmentInThisRegion; + /** + * MemoryPoolMXBean associated with a heap space represented by this sizing + * helper. + */ + private final MemoryPoolMXBean poolMXBean; + + private static long alignUp(long value, long alignment) { + return ((value - 1) / alignment + 1) * alignment; + } + + protected AlignmentHelper(long memoryUsageMeasurementPrecision, + long objectAlignmentInThisRegion, long minObjectSizeInThisSpace, + MemoryPoolMXBean poolMXBean) { + this.memoryUsageMeasurementPrecision = memoryUsageMeasurementPrecision; + this.minObjectSizeInThisSpace = minObjectSizeInThisSpace; + this.objectAlignmentInThisRegion = objectAlignmentInThisRegion; + this.poolMXBean = poolMXBean; + } + + /** + * Returns how many objects have to be allocated to fill + * {@code memoryToFill} bytes in this heap space using objects of size + * {@code objectSize}. + */ + public int getObjectsCount(long memoryToFill, long objectSize) { + return (int) (memoryToFill / getObjectSizeInThisSpace(objectSize)); + } + + /** + * Returns amount of memory that {@code objectsCount} of objects with size + * {@code objectSize} will occupy this this space after allocation. + */ + public long getExpectedMemoryUsage(long objectSize, int objectsCount) { + long correctedObjectSize = getObjectSizeInThisSpace(objectSize); + return AlignmentHelper.alignUp(correctedObjectSize * objectsCount, + memoryUsageMeasurementPrecision); + } + + /** + * Returns current memory usage in this heap space. + */ + public long getActualMemoryUsage() { + return poolMXBean.getUsage().getUsed(); + } + + /** + * Returns maximum memory usage deviation from {@code expectedMemoryUsage} + * given the max allowed relative deviation equal to + * {@code relativeDeviation}. + * + * Note that value returned by this method is aligned according to + * memory measurement precision for this heap space. + */ + public long getAllowedMemoryUsageDeviation(long expectedMemoryUsage) { + long unalignedDeviation = (long) (expectedMemoryUsage * + AlignmentHelper.MAX_RELATIVE_DEVIATION); + return AlignmentHelper.alignUp(unalignedDeviation, + memoryUsageMeasurementPrecision); + } + + /** + * Returns amount of memory that will be occupied by an object with size + * {@code objectSize} in this heap space. + */ + public long getObjectSizeInThisSpace(long objectSize) { + objectSize = Math.max(objectSize, minObjectSizeInThisSpace); + + long alignedObjectSize = AlignmentHelper.alignUp(objectSize, + objectAlignmentInThisRegion); + long sizeDiff = alignedObjectSize - objectSize; + + // If there is not enough space to fit padding object, then object will + // be aligned to {@code 2 * objectAlignmentInThisRegion}. + if (sizeDiff >= AlignmentHelper.OBJECT_ALIGNMENT_IN_BYTES + && sizeDiff < AlignmentHelper.MIN_OBJECT_SIZE) { + alignedObjectSize += AlignmentHelper.MIN_OBJECT_SIZE; + alignedObjectSize = AlignmentHelper.alignUp(alignedObjectSize, + objectAlignmentInThisRegion); + } + + return alignedObjectSize; + } + @Override + public String toString() { + StringBuilder builder = new StringBuilder(); + + builder.append(String.format("AlignmentHelper for memory pool '%s':%n", + poolMXBean.getName())); + builder.append(String.format("Memory usage measurement precision: %d%n", + memoryUsageMeasurementPrecision)); + builder.append(String.format("Min object size in this space: %d%n", + minObjectSizeInThisSpace)); + builder.append(String.format("Object alignment in this space: %d%n", + objectAlignmentInThisRegion)); + + return builder.toString(); + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/gc/survivorAlignment/SurvivorAlignmentTestMain.java Tue Feb 03 16:48:05 2015 +0000 @@ -0,0 +1,416 @@ +/* + * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.lang.management.ManagementFactory; +import java.lang.management.MemoryPoolMXBean; +import java.util.Objects; +import java.util.Optional; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import com.oracle.java.testlibrary.Asserts; +import com.sun.management.ThreadMXBean; +import sun.hotspot.WhiteBox; +import sun.misc.Unsafe; + +/** + * Main class for tests on {@code SurvivorAlignmentInBytes} option. + * + * Typical usage is to obtain instance using fromArgs method, allocate objects + * and verify that actual memory usage in tested heap space is close to + * expected. + */ +public class SurvivorAlignmentTestMain { + enum HeapSpace { + EDEN, + SURVIVOR, + TENURED + } + + public static final WhiteBox WHITE_BOX = WhiteBox.getWhiteBox(); + + public static final long MAX_TENURING_THRESHOLD = Optional.ofNullable( + SurvivorAlignmentTestMain.WHITE_BOX.getIntxVMFlag( + "MaxTenuringThreshold")).orElse(15L); + + /** + * Regexp used to parse memory size params, like 2G, 34m or 15k. + */ + private static final Pattern SIZE_REGEX + = Pattern.compile("(?<size>[0-9]+)(?<multiplier>[GMKgmk])?"); + + // Names of different heap spaces. + private static final String DEF_NEW_EDEN = "Eden Space"; + private static final String DEF_NEW_SURVIVOR = "Survivor Space"; + private static final String PAR_NEW_EDEN = "Par Eden Space"; + private static final String PAR_NEW_SURVIVOR = "Par Survivor Space"; + private static final String PS_EDEN = "PS Eden Space"; + private static final String PS_SURVIVOR = "PS Survivor Space"; + private static final String G1_EDEN = "G1 Eden Space"; + private static final String G1_SURVIVOR = "G1 Survivor Space"; + private static final String SERIAL_TENURED = "Tenured Gen"; + private static final String CMS_TENURED = "CMS Old Gen"; + private static final String PS_TENURED = "PS Old Gen"; + private static final String G1_TENURED = "G1 Old Gen"; + + private static final long G1_HEAP_REGION_SIZE = Optional.ofNullable( + SurvivorAlignmentTestMain.WHITE_BOX.getUintxVMFlag( + "G1HeapRegionSize")).orElse(-1L); + + /** + * Min size of free chunk in CMS generation. + * An object allocated in CMS generation will at least occupy this amount + * of bytes. + */ + private static final long CMS_MIN_FREE_CHUNK_SIZE + = 3L * Unsafe.ADDRESS_SIZE; + + private static final AlignmentHelper EDEN_SPACE_HELPER; + private static final AlignmentHelper SURVIVOR_SPACE_HELPER; + private static final AlignmentHelper TENURED_SPACE_HELPER; + /** + * Amount of memory that should be filled during a test run. + */ + private final long memoryToFill; + /** + * The size of an objects that will be allocated during a test run. + */ + private final long objectSize; + /** + * Amount of memory that will be actually occupied by an object in eden + * space. + */ + private final long actualObjectSize; + /** + * Storage for allocated objects. + */ + private final Object[] garbage; + /** + * Heap space whose memory usage is a subject of assertions during the test + * run. + */ + private final HeapSpace testedSpace; + + private long[] baselinedThreadMemoryUsage = null; + private long[] threadIds = null; + + /** + * Initialize {@code EDEN_SPACE_HELPER}, {@code SURVIVOR_SPACE_HELPER} and + * {@code TENURED_SPACE_HELPER} to represent heap spaces in use. + * + * Note that regardless to GC object's alignment in survivor space is + * expected to be equal to {@code SurvivorAlignmentInBytes} value and + * alignment in other spaces is expected to be equal to + * {@code ObjectAlignmentInBytes} value. + * + * In CMS generation we can't allocate less then {@code MinFreeChunk} value, + * for other CGs we expect that object of size {@code MIN_OBJECT_SIZE} + * could be allocated as it is (of course, its size could be aligned + * according to alignment value used in a particular space). + * + * For G1 GC MXBeans could report memory usage only with region size + * precision (if an object allocated in some G1 heap region, then all region + * will claimed as used), so for G1's spaces precision is equal to + * {@code G1HeapRegionSize} value. + */ + static { + AlignmentHelper edenHelper = null; + AlignmentHelper survivorHelper = null; + AlignmentHelper tenuredHelper = null; + for (MemoryPoolMXBean pool : ManagementFactory.getMemoryPoolMXBeans()) { + switch (pool.getName()) { + case SurvivorAlignmentTestMain.DEF_NEW_EDEN: + case SurvivorAlignmentTestMain.PAR_NEW_EDEN: + case SurvivorAlignmentTestMain.PS_EDEN: + Asserts.assertNull(edenHelper, + "Only one bean for eden space is expected."); + edenHelper = new AlignmentHelper( + AlignmentHelper.OBJECT_ALIGNMENT_IN_BYTES, + AlignmentHelper.OBJECT_ALIGNMENT_IN_BYTES, + AlignmentHelper.MIN_OBJECT_SIZE, pool); + break; + case SurvivorAlignmentTestMain.G1_EDEN: + Asserts.assertNull(edenHelper, + "Only one bean for eden space is expected."); + edenHelper = new AlignmentHelper( + SurvivorAlignmentTestMain.G1_HEAP_REGION_SIZE, + AlignmentHelper.OBJECT_ALIGNMENT_IN_BYTES, + AlignmentHelper.MIN_OBJECT_SIZE, pool); + break; + case SurvivorAlignmentTestMain.DEF_NEW_SURVIVOR: + case SurvivorAlignmentTestMain.PAR_NEW_SURVIVOR: + case SurvivorAlignmentTestMain.PS_SURVIVOR: + Asserts.assertNull(survivorHelper, + "Only one bean for survivor space is expected."); + survivorHelper = new AlignmentHelper( + AlignmentHelper.OBJECT_ALIGNMENT_IN_BYTES, + AlignmentHelper.SURVIVOR_ALIGNMENT_IN_BYTES, + AlignmentHelper.MIN_OBJECT_SIZE, pool); + break; + case SurvivorAlignmentTestMain.G1_SURVIVOR: + Asserts.assertNull(survivorHelper, + "Only one bean for survivor space is expected."); + survivorHelper = new AlignmentHelper( + SurvivorAlignmentTestMain.G1_HEAP_REGION_SIZE, + AlignmentHelper.SURVIVOR_ALIGNMENT_IN_BYTES, + AlignmentHelper.MIN_OBJECT_SIZE, pool); + break; + case SurvivorAlignmentTestMain.SERIAL_TENURED: + case SurvivorAlignmentTestMain.PS_TENURED: + case SurvivorAlignmentTestMain.G1_TENURED: + Asserts.assertNull(tenuredHelper, + "Only one bean for tenured space is expected."); + tenuredHelper = new AlignmentHelper( + AlignmentHelper.OBJECT_ALIGNMENT_IN_BYTES, + AlignmentHelper.OBJECT_ALIGNMENT_IN_BYTES, + AlignmentHelper.MIN_OBJECT_SIZE, pool); + break; + case SurvivorAlignmentTestMain.CMS_TENURED: + Asserts.assertNull(tenuredHelper, + "Only one bean for tenured space is expected."); + tenuredHelper = new AlignmentHelper( + AlignmentHelper.OBJECT_ALIGNMENT_IN_BYTES, + AlignmentHelper.OBJECT_ALIGNMENT_IN_BYTES, + SurvivorAlignmentTestMain.CMS_MIN_FREE_CHUNK_SIZE, + pool); + break; + } + } + EDEN_SPACE_HELPER = Objects.requireNonNull(edenHelper, + "AlignmentHelper for eden space should be initialized."); + SURVIVOR_SPACE_HELPER = Objects.requireNonNull(survivorHelper, + "AlignmentHelper for survivor space should be initialized."); + TENURED_SPACE_HELPER = Objects.requireNonNull(tenuredHelper, + "AlignmentHelper for tenured space should be initialized."); + } + /** + * Returns an SurvivorAlignmentTestMain instance constructed using CLI + * options. + * + * Following options are expected: + * <ul> + * <li>memoryToFill</li> + * <li>objectSize</li> + * </ul> + * + * Both argument may contain multiplier suffix k, m or g. + */ + public static SurvivorAlignmentTestMain fromArgs(String[] args) { + Asserts.assertEQ(args.length, 3, "Expected three arguments: " + + "memory size, object size and tested heap space name."); + + long memoryToFill = parseSize(args[0]); + long objectSize = Math.max(parseSize(args[1]), + AlignmentHelper.MIN_ARRAY_SIZE); + HeapSpace testedSpace = HeapSpace.valueOf(args[2]); + + return new SurvivorAlignmentTestMain(memoryToFill, objectSize, + testedSpace); + } + + /** + * Returns a value parsed from a string with format + * <integer><multiplier>. + */ + private static long parseSize(String sizeString) { + Matcher matcher = SIZE_REGEX.matcher(sizeString); + Asserts.assertTrue(matcher.matches(), + "sizeString should have following format \"[0-9]+([MBK])?\""); + long size = Long.valueOf(matcher.group("size")); + + if (matcher.group("multiplier") != null) { + long K = 1024L; + // fall through multipliers + switch (matcher.group("multiplier").toLowerCase()) { + case "g": + size *= K; + case "m": + size *= K; + case "k": + size *= K; + } + } + return size; + } + + private SurvivorAlignmentTestMain(long memoryToFill, long objectSize, + HeapSpace testedSpace) { + this.objectSize = objectSize; + this.memoryToFill = memoryToFill; + this.testedSpace = testedSpace; + + AlignmentHelper helper = SurvivorAlignmentTestMain.EDEN_SPACE_HELPER; + + this.actualObjectSize = helper.getObjectSizeInThisSpace( + this.objectSize); + int arrayLength = helper.getObjectsCount(memoryToFill, this.objectSize); + garbage = new Object[arrayLength]; + } + + /** + * Allocate byte arrays to fill {@code memoryToFill} memory. + */ + public void allocate() { + int byteArrayLength = Math.max((int) (objectSize + - Unsafe.ARRAY_BYTE_BASE_OFFSET), 0); + + for (int i = 0; i < garbage.length; i++) { + garbage[i] = new byte[byteArrayLength]; + } + } + + /** + * Release memory occupied after {@code allocate} call. + */ + public void release() { + for (int i = 0; i < garbage.length; i++) { + garbage[i] = null; + } + } + + /** + * Returns expected amount of memory occupied in a {@code heapSpace} by + * objects referenced from {@code garbage} array. + */ + public long getExpectedMemoryUsage() { + AlignmentHelper alignmentHelper = getAlignmentHelper(testedSpace); + return alignmentHelper.getExpectedMemoryUsage(objectSize, + garbage.length); + } + + /** + * Verifies that memory usage in a {@code heapSpace} deviates from + * {@code expectedUsage} for no more than {@code MAX_RELATIVE_DEVIATION}. + */ + public void verifyMemoryUsage(long expectedUsage) { + AlignmentHelper alignmentHelper = getAlignmentHelper(testedSpace); + + long actualMemoryUsage = alignmentHelper.getActualMemoryUsage(); + boolean otherThreadsAllocatedMemory = areOtherThreadsAllocatedMemory(); + + long memoryUsageDiff = Math.abs(actualMemoryUsage - expectedUsage); + long maxAllowedUsageDiff + = alignmentHelper.getAllowedMemoryUsageDeviation(expectedUsage); + + System.out.println("Verifying memory usage in space: " + testedSpace); + System.out.println("Allocated objects count: " + garbage.length); + System.out.println("Desired object size: " + objectSize); + System.out.println("Actual object size: " + actualObjectSize); + System.out.println("Expected object size in space: " + + alignmentHelper.getObjectSizeInThisSpace(objectSize)); + System.out.println("Expected memory usage: " + expectedUsage); + System.out.println("Actual memory usage: " + actualMemoryUsage); + System.out.println("Memory usage diff: " + memoryUsageDiff); + System.out.println("Max allowed usage diff: " + maxAllowedUsageDiff); + + if (memoryUsageDiff > maxAllowedUsageDiff + && otherThreadsAllocatedMemory) { + System.out.println("Memory usage diff is incorrect, but it seems " + + "like someone else allocated objects"); + return; + } + + Asserts.assertLTE(memoryUsageDiff, maxAllowedUsageDiff, + "Actual memory usage should not deviate from expected for " + + "more then " + maxAllowedUsageDiff); + } + + /** + * Baselines amount of memory allocated by each thread. + */ + public void baselineMemoryAllocation() { + ThreadMXBean bean = (ThreadMXBean) ManagementFactory.getThreadMXBean(); + threadIds = bean.getAllThreadIds(); + baselinedThreadMemoryUsage = bean.getThreadAllocatedBytes(threadIds); + } + + /** + * Checks if threads other then the current thread were allocating objects + * after baselinedThreadMemoryUsage call. + * + * If baselinedThreadMemoryUsage was not called, then this method will return + * {@code false}. + */ + public boolean areOtherThreadsAllocatedMemory() { + if (baselinedThreadMemoryUsage == null) { + return false; + } + + ThreadMXBean bean = (ThreadMXBean) ManagementFactory.getThreadMXBean(); + long currentMemoryAllocation[] + = bean.getThreadAllocatedBytes(threadIds); + boolean otherThreadsAllocatedMemory = false; + + System.out.println("Verifying amount of memory allocated by threads:"); + for (int i = 0; i < threadIds.length; i++) { + System.out.format("Thread %d%nbaseline allocation: %d" + + "%ncurrent allocation:%d%n", threadIds[i], + baselinedThreadMemoryUsage[i], currentMemoryAllocation[i]); + System.out.println(bean.getThreadInfo(threadIds[i])); + + long bytesAllocated = Math.abs(currentMemoryAllocation[i] + - baselinedThreadMemoryUsage[i]); + if (bytesAllocated > 0 + && threadIds[i] != Thread.currentThread().getId()) { + otherThreadsAllocatedMemory = true; + } + } + + return otherThreadsAllocatedMemory; + } + + @Override + public String toString() { + StringBuilder builder = new StringBuilder(); + + builder.append(String.format("SurvivorAlignmentTestMain info:%n")); + builder.append(String.format("Desired object size: %d%n", objectSize)); + builder.append(String.format("Memory to fill: %d%n", memoryToFill)); + builder.append(String.format("Objects to be allocated: %d%n", + garbage.length)); + + builder.append(String.format("Alignment helpers to be used: %n")); + for (HeapSpace heapSpace: HeapSpace.values()) { + builder.append(String.format("For space %s:%n%s%n", heapSpace, + getAlignmentHelper(heapSpace))); + } + + return builder.toString(); + } + + /** + * Returns {@code AlignmentHelper} for a space {@code heapSpace}. + */ + public static AlignmentHelper getAlignmentHelper(HeapSpace heapSpace) { + switch (heapSpace) { + case EDEN: + return SurvivorAlignmentTestMain.EDEN_SPACE_HELPER; + case SURVIVOR: + return SurvivorAlignmentTestMain.SURVIVOR_SPACE_HELPER; + case TENURED: + return SurvivorAlignmentTestMain.TENURED_SPACE_HELPER; + default: + throw new Error("Unexpected heap space: " + heapSpace); + } + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/gc/survivorAlignment/TestAllocationInEden.java Tue Feb 03 16:48:05 2015 +0000 @@ -0,0 +1,90 @@ +/* + * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/** + * @test + * @bug 8031323 + * @summary Verify that object's alignment in eden space is not affected by + * SurvivorAlignmentInBytes option. + * @library /testlibrary /testlibrary/whitebox + * @build TestAllocationInEden SurvivorAlignmentTestMain AlignmentHelper + * @run main ClassFileInstaller sun.hotspot.WhiteBox + * sun.hotspot.WhiteBox$WhiteBoxPermission + * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions + * -XX:+WhiteBoxAPI -XX:NewSize=64m -XX:MaxNewSize=64m + * -XX:SurvivorRatio=1 -XX:+UnlockExperimentalVMOptions + * -XX:SurvivorAlignmentInBytes=32 -XX:-UseTLAB + * -XX:OldSize=128m -XX:MaxHeapSize=192m + * -XX:-ExplicitGCInvokesConcurrent + * TestAllocationInEden 10m 9 EDEN + * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions + * -XX:+WhiteBoxAPI -XX:NewSize=64m -XX:MaxNewSize=64m + * -XX:SurvivorRatio=1 -XX:+UnlockExperimentalVMOptions + * -XX:SurvivorAlignmentInBytes=32 -XX:-UseTLAB + * -XX:OldSize=128m -XX:MaxHeapSize=192m + * -XX:-ExplicitGCInvokesConcurrent + * TestAllocationInEden 10m 47 EDEN + * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions + * -XX:+WhiteBoxAPI -XX:NewSize=64m -XX:MaxNewSize=64m + * -XX:SurvivorRatio=1 -XX:+UnlockExperimentalVMOptions + * -XX:SurvivorAlignmentInBytes=64 -XX:-UseTLAB + * -XX:OldSize=128m -XX:MaxHeapSize=192m + * -XX:-ExplicitGCInvokesConcurrent + * TestAllocationInEden 10m 9 EDEN + * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions + * -XX:+WhiteBoxAPI -XX:NewSize=64m -XX:MaxNewSize=64m + * -XX:SurvivorRatio=1 -XX:+UnlockExperimentalVMOptions + * -XX:SurvivorAlignmentInBytes=64 -XX:-UseTLAB + * -XX:OldSize=128m -XX:MaxHeapSize=192m + * -XX:-ExplicitGCInvokesConcurrent + * TestAllocationInEden 10m 87 EDEN + * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions + * -XX:+WhiteBoxAPI -XX:NewSize=64m -XX:MaxNewSize=64m + * -XX:SurvivorRatio=1 -XX:+UnlockExperimentalVMOptions + * -XX:SurvivorAlignmentInBytes=128 -XX:-UseTLAB + * -XX:OldSize=128m -XX:MaxHeapSize=192m + * -XX:-ExplicitGCInvokesConcurrent + * TestAllocationInEden 10m 9 EDEN + * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions + * -XX:+WhiteBoxAPI -XX:NewSize=64m -XX:MaxNewSize=64m + * -XX:SurvivorRatio=1 -XX:+UnlockExperimentalVMOptions + * -XX:SurvivorAlignmentInBytes=128 -XX:-UseTLAB + * -XX:OldSize=128m -XX:MaxHeapSize=192m + * -XX:-ExplicitGCInvokesConcurrent + * TestAllocationInEden 10m 147 EDEN + */ +public class TestAllocationInEden { + public static void main(String args[]) { + SurvivorAlignmentTestMain test + = SurvivorAlignmentTestMain.fromArgs(args); + System.out.println(test); + + long expectedMemoryUsage = test.getExpectedMemoryUsage(); + test.baselineMemoryAllocation(); + System.gc(); + + test.allocate(); + + test.verifyMemoryUsage(expectedMemoryUsage); + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/gc/survivorAlignment/TestPromotionFromEdenToTenured.java Tue Feb 03 16:48:05 2015 +0000 @@ -0,0 +1,96 @@ +/* + * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/** + * @test + * @bug 8031323 + * @summary Verify that objects promoted from eden space to tenured space during + * full GC are not aligned to SurvivorAlignmentInBytes value. + * @library /testlibrary /testlibrary/whitebox + * @build TestPromotionFromEdenToTenured SurvivorAlignmentTestMain + * AlignmentHelper + * @run main ClassFileInstaller sun.hotspot.WhiteBox + * sun.hotspot.WhiteBox$WhiteBoxPermission + * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions + * -XX:+WhiteBoxAPI -XX:NewSize=64m -XX:MaxNewSize=64m + * -XX:OldSize=32m -XX:MaxHeapSize=96m -XX:SurvivorRatio=1 + * -XX:-ExplicitGCInvokesConcurrent + * -XX:+UnlockExperimentalVMOptions + * -XX:SurvivorAlignmentInBytes=32 + * TestPromotionFromEdenToTenured 10m 9 TENURED + * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions + * -XX:+WhiteBoxAPI -XX:NewSize=64m -XX:MaxNewSize=64m + * -XX:OldSize=32m -XX:MaxHeapSize=96m -XX:SurvivorRatio=1 + * -XX:-ExplicitGCInvokesConcurrent + * -XX:+UnlockExperimentalVMOptions + * -XX:SurvivorAlignmentInBytes=32 + * TestPromotionFromEdenToTenured 10m 47 TENURED + * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions + * -XX:+WhiteBoxAPI -XX:NewSize=64m -XX:MaxNewSize=64m + * -XX:OldSize=32m -XX:MaxHeapSize=96m + * -XX:SurvivorRatio=1 -XX:-ExplicitGCInvokesConcurrent + * -XX:+UnlockExperimentalVMOptions + * -XX:SurvivorAlignmentInBytes=64 + * TestPromotionFromEdenToTenured 10m 9 TENURED + * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions + * -XX:+WhiteBoxAPI -XX:NewSize=64m -XX:MaxNewSize=64m + * -XX:OldSize=32m -XX:MaxHeapSize=128m + * -XX:SurvivorRatio=1 -XX:-ExplicitGCInvokesConcurrent + * -XX:+UnlockExperimentalVMOptions + * -XX:SurvivorAlignmentInBytes=64 + * TestPromotionFromEdenToTenured 10m 87 TENURED + * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions + * -XX:+WhiteBoxAPI -XX:NewSize=64m -XX:MaxNewSize=64m + * -XX:OldSize=32M -XX:MaxHeapSize=96m -XX:SurvivorRatio=1 + * -XX:-ExplicitGCInvokesConcurrent + * -XX:+UnlockExperimentalVMOptions + * -XX:SurvivorAlignmentInBytes=128 + * TestPromotionFromEdenToTenured 10m 9 TENURED + * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions + * -XX:+WhiteBoxAPI -XX:NewSize=64m -XX:MaxNewSize=64m + * -XX:OldSize=32m -XX:MaxHeapSize=96m -XX:SurvivorRatio=1 + * -XX:-ExplicitGCInvokesConcurrent + * -XX:+UnlockExperimentalVMOptions + * -XX:SurvivorAlignmentInBytes=128 + * TestPromotionFromEdenToTenured 10m 147 TENURED + */ +public class TestPromotionFromEdenToTenured { + public static void main(String args[]) { + SurvivorAlignmentTestMain test + = SurvivorAlignmentTestMain.fromArgs(args); + System.out.println(test); + + long expectedMemoryUsage = test.getExpectedMemoryUsage(); + test.baselineMemoryAllocation(); + System.gc(); + // increase expected usage by current old gen usage + expectedMemoryUsage += SurvivorAlignmentTestMain.getAlignmentHelper( + SurvivorAlignmentTestMain.HeapSpace.TENURED) + .getActualMemoryUsage(); + + test.allocate(); + System.gc(); + + test.verifyMemoryUsage(expectedMemoryUsage); + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/gc/survivorAlignment/TestPromotionFromSurvivorToTenuredAfterFullGC.java Tue Feb 03 16:48:05 2015 +0000 @@ -0,0 +1,101 @@ +/* + * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/** + * @test + * @bug 8031323 + * @summary Verify that objects promoted from survivor space to tenured space + * during full GC are not aligned to SurvivorAlignmentInBytes value. + * @library /testlibrary /testlibrary/whitebox + * @build TestPromotionFromSurvivorToTenuredAfterFullGC + * SurvivorAlignmentTestMain AlignmentHelper + * @run main ClassFileInstaller sun.hotspot.WhiteBox + * sun.hotspot.WhiteBox$WhiteBoxPermission + * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions + * -XX:+WhiteBoxAPI -XX:NewSize=128m -XX:MaxNewSize=128m + * -XX:OldSize=32m -XX:MaxHeapSize=160m + * -XX:SurvivorRatio=1 -XX:-ExplicitGCInvokesConcurrent + * -XX:+UnlockExperimentalVMOptions + * -XX:SurvivorAlignmentInBytes=32 + * TestPromotionFromSurvivorToTenuredAfterFullGC 10m 9 TENURED + * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions + * -XX:+WhiteBoxAPI -XX:NewSize=128m -XX:MaxNewSize=128m + * -XX:OldSize=32m -XX:MaxHeapSize=160m + * -XX:SurvivorRatio=1 -XX:-ExplicitGCInvokesConcurrent + * -XX:+UnlockExperimentalVMOptions + * -XX:SurvivorAlignmentInBytes=32 + * TestPromotionFromSurvivorToTenuredAfterFullGC 20m 47 + * TENURED + * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions + * -XX:+WhiteBoxAPI -XX:NewSize=200m -XX:MaxNewSize=200m + * -XX:OldSize=32m -XX:MaxHeapSize=232m + * -XX:SurvivorRatio=1 -XX:-ExplicitGCInvokesConcurrent + * -XX:+UnlockExperimentalVMOptions + * -XX:SurvivorAlignmentInBytes=64 + * TestPromotionFromSurvivorToTenuredAfterFullGC 10m 9 TENURED + * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions + * -XX:+WhiteBoxAPI -XX:NewSize=128m -XX:MaxNewSize=128m + * -XX:OldSize=32m -XX:MaxHeapSize=160m + * -XX:SurvivorRatio=1 -XX:-ExplicitGCInvokesConcurrent + * -XX:+UnlockExperimentalVMOptions + * -XX:SurvivorAlignmentInBytes=64 + * TestPromotionFromSurvivorToTenuredAfterFullGC 20m 87 + * TENURED + * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions + * -XX:+WhiteBoxAPI -XX:NewSize=256m -XX:MaxNewSize=256m + * -XX:OldSize=32M -XX:MaxHeapSize=288m + * -XX:SurvivorRatio=1 -XX:-ExplicitGCInvokesConcurrent + * -XX:+UnlockExperimentalVMOptions + * -XX:SurvivorAlignmentInBytes=128 + * TestPromotionFromSurvivorToTenuredAfterFullGC 10m 9 + * TENURED + * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions + * -XX:+WhiteBoxAPI -XX:NewSize=128m -XX:MaxNewSize=128m + * -XX:OldSize=32m -XX:MaxHeapSize=160m + * -XX:SurvivorRatio=1 -XX:-ExplicitGCInvokesConcurrent + * -XX:+UnlockExperimentalVMOptions + * -XX:SurvivorAlignmentInBytes=128 + * TestPromotionFromSurvivorToTenuredAfterFullGC 20m 147 + * TENURED + */ +public class TestPromotionFromSurvivorToTenuredAfterFullGC { + public static void main(String args[]) { + SurvivorAlignmentTestMain test + = SurvivorAlignmentTestMain.fromArgs(args); + System.out.println(test); + + long expectedMemoryUsage = test.getExpectedMemoryUsage(); + test.baselineMemoryAllocation(); + System.gc(); + // increase expected usage by current old gen usage + expectedMemoryUsage += SurvivorAlignmentTestMain.getAlignmentHelper( + SurvivorAlignmentTestMain.HeapSpace.TENURED) + .getActualMemoryUsage(); + + test.allocate(); + SurvivorAlignmentTestMain.WHITE_BOX.youngGC(); + System.gc(); + + test.verifyMemoryUsage(expectedMemoryUsage); + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/gc/survivorAlignment/TestPromotionFromSurvivorToTenuredAfterMinorGC.java Tue Feb 03 16:48:05 2015 +0000 @@ -0,0 +1,106 @@ +/* + * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/** + * @test + * @bug 8031323 + * @summary Verify that objects promoted from survivor space to tenured space + * when their age exceeded tenuring threshold are not aligned to + * SurvivorAlignmentInBytes value. + * @library /testlibrary /testlibrary/whitebox + * @build TestPromotionFromSurvivorToTenuredAfterMinorGC + * SurvivorAlignmentTestMain AlignmentHelper + * @run main ClassFileInstaller sun.hotspot.WhiteBox + * sun.hotspot.WhiteBox$WhiteBoxPermission + * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions + * -XX:+WhiteBoxAPI -XX:NewSize=128m -XX:MaxNewSize=128m + * -XX:OldSize=32M -XX:MaxHeapSize=160m -XX:SurvivorRatio=1 + * -XX:-ExplicitGCInvokesConcurrent + * -XX:+UnlockExperimentalVMOptions + * -XX:SurvivorAlignmentInBytes=32 + * TestPromotionFromSurvivorToTenuredAfterMinorGC 10m 9 + * TENURED + * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions + * -XX:+WhiteBoxAPI -XX:NewSize=128m -XX:MaxNewSize=128m + * -XX:OldSize=32M -XX:MaxHeapSize=160m -XX:SurvivorRatio=1 + * -XX:-ExplicitGCInvokesConcurrent + * -XX:+UnlockExperimentalVMOptions + * -XX:SurvivorAlignmentInBytes=32 + * TestPromotionFromSurvivorToTenuredAfterMinorGC 20m 47 + * TENURED + * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions + * -XX:+WhiteBoxAPI -XX:NewSize=200m -XX:MaxNewSize=200m + * -XX:OldSize=32M -XX:MaxHeapSize=232m -XX:SurvivorRatio=1 + * -XX:-ExplicitGCInvokesConcurrent + * -XX:+UnlockExperimentalVMOptions + * -XX:SurvivorAlignmentInBytes=64 + * TestPromotionFromSurvivorToTenuredAfterMinorGC 10m 9 + * TENURED + * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions + * -XX:+WhiteBoxAPI -XX:NewSize=128m -XX:MaxNewSize=128m + * -XX:OldSize=32M -XX:MaxHeapSize=160m -XX:SurvivorRatio=1 + * -XX:-ExplicitGCInvokesConcurrent + * -XX:+UnlockExperimentalVMOptions + * -XX:SurvivorAlignmentInBytes=64 + * TestPromotionFromSurvivorToTenuredAfterMinorGC 20m 87 + * TENURED + * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions + * -XX:+WhiteBoxAPI -XX:NewSize=256m -XX:MaxNewSize=256m + * -XX:OldSize=32M -XX:MaxHeapSize=288m -XX:SurvivorRatio=1 + * -XX:-ExplicitGCInvokesConcurrent + * -XX:+UnlockExperimentalVMOptions + * -XX:SurvivorAlignmentInBytes=128 + * TestPromotionFromSurvivorToTenuredAfterMinorGC 10m 9 + * TENURED + * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions + * -XX:+WhiteBoxAPI -XX:NewSize=128m -XX:MaxNewSize=128m + * -XX:OldSize=32M -XX:MaxHeapSize=160m -XX:SurvivorRatio=1 + * -XX:-ExplicitGCInvokesConcurrent + * -XX:+UnlockExperimentalVMOptions + * -XX:SurvivorAlignmentInBytes=128 + * TestPromotionFromSurvivorToTenuredAfterMinorGC 20m 147 + * TENURED + */ +public class TestPromotionFromSurvivorToTenuredAfterMinorGC { + public static void main(String args[]) throws Exception { + SurvivorAlignmentTestMain test + = SurvivorAlignmentTestMain.fromArgs(args); + System.out.println(test); + + long expectedMemoryUsage = test.getExpectedMemoryUsage(); + test.baselineMemoryAllocation(); + SurvivorAlignmentTestMain.WHITE_BOX.fullGC(); + // increase expected usage by current old gen usage + expectedMemoryUsage += SurvivorAlignmentTestMain.getAlignmentHelper( + SurvivorAlignmentTestMain.HeapSpace.TENURED) + .getActualMemoryUsage(); + + test.allocate(); + for (int i = 0; i <= SurvivorAlignmentTestMain.MAX_TENURING_THRESHOLD; + i++) { + SurvivorAlignmentTestMain.WHITE_BOX.youngGC(); + } + + test.verifyMemoryUsage(expectedMemoryUsage); + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/gc/survivorAlignment/TestPromotionToSurvivor.java Tue Feb 03 16:48:05 2015 +0000 @@ -0,0 +1,86 @@ +/* + * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/** + * @test + * @bug 8031323 + * @summary Verify that objects promoted from eden space to survivor space after + * minor GC are aligned to SurvivorAlignmentInBytes. + * @library /testlibrary /testlibrary/whitebox + * @build TestPromotionToSurvivor + * SurvivorAlignmentTestMain AlignmentHelper + * @run main ClassFileInstaller sun.hotspot.WhiteBox + * sun.hotspot.WhiteBox$WhiteBoxPermission + * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions + * -XX:+WhiteBoxAPI -XX:NewSize=128m -XX:MaxNewSize=128m + * -XX:SurvivorRatio=1 -XX:+UnlockExperimentalVMOptions + * -XX:SurvivorAlignmentInBytes=32 -XX:OldSize=128m + * -XX:MaxHeapSize=256m -XX:-ExplicitGCInvokesConcurrent + * TestPromotionToSurvivor 10m 9 SURVIVOR + * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions + * -XX:+WhiteBoxAPI -XX:NewSize=128m -XX:MaxNewSize=128m + * -XX:SurvivorRatio=1 -XX:+UnlockExperimentalVMOptions + * -XX:SurvivorAlignmentInBytes=32 -XX:OldSize=128m + * -XX:MaxHeapSize=256m -XX:-ExplicitGCInvokesConcurrent + * TestPromotionToSurvivor 20m 47 SURVIVOR + * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions + * -XX:+WhiteBoxAPI -XX:NewSize=128m -XX:MaxNewSize=128m + * -XX:SurvivorRatio=1 -XX:+UnlockExperimentalVMOptions + * -XX:SurvivorAlignmentInBytes=64 -XX:OldSize=128m + * -XX:MaxHeapSize=256m -XX:-ExplicitGCInvokesConcurrent + * TestPromotionToSurvivor 8m 9 SURVIVOR + * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions + * -XX:+WhiteBoxAPI -XX:NewSize=128m -XX:MaxNewSize=128m + * -XX:SurvivorRatio=1 -XX:+UnlockExperimentalVMOptions + * -XX:SurvivorAlignmentInBytes=64 -XX:OldSize=128m + * -XX:MaxHeapSize=256m -XX:-ExplicitGCInvokesConcurrent + * TestPromotionToSurvivor 20m 87 SURVIVOR + * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions + * -XX:+WhiteBoxAPI -XX:NewSize=256m -XX:MaxNewSize=256m + * -XX:SurvivorRatio=1 -XX:+UnlockExperimentalVMOptions + * -XX:SurvivorAlignmentInBytes=128 -XX:OldSize=128m + * -XX:MaxHeapSize=384m -XX:-ExplicitGCInvokesConcurrent + * TestPromotionToSurvivor 10m 9 SURVIVOR + * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions + * -XX:+WhiteBoxAPI -XX:NewSize=128m -XX:MaxNewSize=128m + * -XX:SurvivorRatio=1 -XX:+UnlockExperimentalVMOptions + * -XX:SurvivorAlignmentInBytes=128 -XX:OldSize=128m + * -XX:MaxHeapSize=256m -XX:-ExplicitGCInvokesConcurrent + * TestPromotionToSurvivor 20m 147 SURVIVOR + */ +public class TestPromotionToSurvivor { + public static void main(String args[]) { + SurvivorAlignmentTestMain test + = SurvivorAlignmentTestMain.fromArgs(args); + System.out.println(test); + + long expectedUsage = test.getExpectedMemoryUsage(); + test.baselineMemoryAllocation(); + SurvivorAlignmentTestMain.WHITE_BOX.fullGC(); + + test.allocate(); + SurvivorAlignmentTestMain.WHITE_BOX.youngGC(); + + test.verifyMemoryUsage(expectedUsage); + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/runtime/CheckEndorsedAndExtDirs/EndorsedExtDirs.java Tue Feb 03 16:48:05 2015 +0000 @@ -0,0 +1,93 @@ +/* + * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 8064667 + * @summary Sanity test for -XX:+CheckEndorsedAndExtDirs + * @library /testlibrary + * @build com.oracle.java.testlibrary.* + * @run main/othervm EndorsedExtDirs + */ + +import com.oracle.java.testlibrary.*; +import java.io.File; +import java.io.IOException; +import java.nio.file.attribute.BasicFileAttributes; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.ArrayList; +import java.util.List; + +public class EndorsedExtDirs { + static final String cpath = System.getProperty("test.classes", "."); + public static void main(String arg[]) throws Exception { + fatalError("-XX:+CheckEndorsedAndExtDirs", "-Djava.endorsed.dirs=foo"); + fatalError("-XX:+CheckEndorsedAndExtDirs", "-Djava.ext.dirs=bar"); + testNonEmptySystemExtDirs(); + } + + static void testNonEmptySystemExtDirs() throws Exception { + String home = System.getProperty("java.home"); + Path ext = Paths.get(home, "lib", "ext"); + String extDirs = System.getProperty("java.ext.dirs"); + String[] dirs = extDirs.split(File.pathSeparator); + long count = 0; + for (String d : dirs) { + Path path = Paths.get(d); + if (Files.notExists(path) || path.equals(ext)) continue; + count += Files.find(path, 1, (Path p, BasicFileAttributes attr) + -> p.getFileName().toString().endsWith(".jar")) + .count(); + } + if (count > 0) { + fatalError("-XX:+CheckEndorsedAndExtDirs"); + } + } + + static ProcessBuilder newProcessBuilder(String... args) { + List<String> commands = new ArrayList<>(); + String java = System.getProperty("java.home") + "/bin/java"; + commands.add(java); + for (String s : args) { + commands.add(s); + } + commands.add("-cp"); + commands.add(cpath); + commands.add("EndorsedExtDirs"); + + System.out.println("Process " + commands); + return new ProcessBuilder(commands); + } + + static void fatalError(String... args) throws Exception { + fatalError(newProcessBuilder(args)); + } + + static void fatalError(ProcessBuilder pb) throws Exception { + OutputAnalyzer output = new OutputAnalyzer(pb.start()); + output.shouldContain("Could not create the Java Virtual Machine"); + output.shouldHaveExitValue(1); + } +}
--- a/test/runtime/NMT/MallocSiteHashOverflow.java Thu Jan 08 12:47:32 2015 +0000 +++ b/test/runtime/NMT/MallocSiteHashOverflow.java Tue Feb 03 16:48:05 2015 +0000 @@ -24,41 +24,55 @@ /* * @test * @summary Test corner case that overflows malloc site hashtable bucket + * @requires sun.arch.data.model == "32" * @key nmt jcmd stress * @library /testlibrary /testlibrary/whitebox - * @ignore - This test is disabled since it will stress NMT and timeout during normal testing * @build MallocSiteHashOverflow * @run main ClassFileInstaller sun.hotspot.WhiteBox - * @run main/othervm/timeout=480 -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -XX:NativeMemoryTracking=detail MallocSiteHashOverflow + * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -XX:NativeMemoryTracking=detail MallocSiteHashOverflow */ import com.oracle.java.testlibrary.*; import sun.hotspot.WhiteBox; public class MallocSiteHashOverflow { - private static long K = 1024; + public static void main(String args[]) throws Exception { - String vm_name = System.getProperty("java.vm.name"); + // Size of entries based on malloc tracking header defined in mallocTracker.hpp // For 32-bit systems, create 257 malloc sites with the same hash bucket to overflow a hash bucket - // For 64-bit systems, create 64K + 1 malloc sites with the same hash bucket to overflow a hash bucket long entries = 257; - if (Platform.is64bit()) { - entries = 64 * K + 1; - } OutputAnalyzer output; WhiteBox wb = WhiteBox.getWhiteBox(); + int MAX_HASH_SIZE = wb.NMTGetHashSize(); // Grab my own PID String pid = Integer.toString(ProcessTools.getProcessId()); ProcessBuilder pb = new ProcessBuilder(); - wb.NMTOverflowHashBucket(entries); - - // Run 'jcmd <pid> VM.native_memory summary' + // Verify that current tracking level is "detail" pb.command(new String[] { JDKToolFinder.getJDKTool("jcmd"), pid, "VM.native_memory", "statistics"}); output = new OutputAnalyzer(pb.start()); - output.shouldContain("Tracking level has been downgraded due to lack of resources"); + output.shouldContain("Native Memory Tracking Statistics"); + + // Attempt to cause NMT to downgrade tracking level by allocating small amounts + // of memory with random pseudo call stack + int pc = 1; + for (int i = 0; i < entries; i++) { + long addr = wb.NMTMallocWithPseudoStack(1, pc); + if (addr == 0) { + throw new RuntimeException("NMTMallocWithPseudoStack: out of memory"); + } + // We free memory here since it doesn't affect pseudo malloc alloc site hash table entries + wb.NMTFree(addr); + pc += MAX_HASH_SIZE; + if (i == entries) { + // Verify that tracking has been downgraded + pb.command(new String[] { JDKToolFinder.getJDKTool("jcmd"), pid, "VM.native_memory", "statistics"}); + output = new OutputAnalyzer(pb.start()); + output.shouldContain("Tracking level has been downgraded due to lack of resources"); + } + } } }
--- a/test/runtime/NMT/PrintNMTStatistics.java Thu Jan 08 12:47:32 2015 +0000 +++ b/test/runtime/NMT/PrintNMTStatistics.java Tue Feb 03 16:48:05 2015 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2014 Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2014, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -24,42 +24,40 @@ /* * @test * @key nmt regression - * @bug 8005936 - * @summary Make sure PrintNMTStatistics works on normal JVM exit - * @library /testlibrary /testlibrary/whitebox - * @build PrintNMTStatistics - * @run main ClassFileInstaller sun.hotspot.WhiteBox - * @run main PrintNMTStatistics + * @bug 8005936 8058606 + * @summary Verify PrintNMTStatistics on normal JVM exit for detail and summary tracking level + * @library /testlibrary */ import com.oracle.java.testlibrary.*; -import java.util.regex.Matcher; -import java.util.regex.Pattern; -import sun.hotspot.WhiteBox; - public class PrintNMTStatistics { - public static void main(String args[]) throws Exception { - - // We start a new java process running with an argument and use WB API to ensure - // we have data for NMT on VM exit - if (args.length > 0) { - return; - } + public static void main(String args[]) throws Exception { ProcessBuilder pb = ProcessTools.createJavaProcessBuilder( - "-XX:+UnlockDiagnosticVMOptions", - "-Xbootclasspath/a:.", - "-XX:+WhiteBoxAPI", - "-XX:NativeMemoryTracking=summary", - "-XX:+PrintNMTStatistics", - "PrintNMTStatistics", - "test"); + "-XX:+UnlockDiagnosticVMOptions", + "-XX:+PrintNMTStatistics", + "-XX:NativeMemoryTracking=detail", + "-version"); + + OutputAnalyzer output_detail = new OutputAnalyzer(pb.start()); + output_detail.shouldContain("Virtual memory map:"); + output_detail.shouldContain("Details:"); + output_detail.shouldNotContain("error"); + output_detail.shouldHaveExitValue(0); - OutputAnalyzer output = new OutputAnalyzer(pb.start()); - output.shouldContain("Java Heap (reserved="); - output.shouldNotContain("error"); - output.shouldHaveExitValue(0); - } + ProcessBuilder pb1 = ProcessTools.createJavaProcessBuilder( + "-XX:+UnlockDiagnosticVMOptions", + "-XX:+PrintNMTStatistics", + "-XX:NativeMemoryTracking=summary", + "-version"); + + OutputAnalyzer output_summary = new OutputAnalyzer(pb1.start()); + output_summary.shouldContain("Java Heap (reserved="); + output_summary.shouldNotContain("Virtual memory map:"); + output_summary.shouldNotContain("Details:"); + output_summary.shouldNotContain("error"); + output_summary.shouldHaveExitValue(0); + } }
--- a/test/runtime/NMT/UnsafeMallocLimit.java Thu Jan 08 12:47:32 2015 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,50 +0,0 @@ -/* - * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -/* - * @test - * @bug 8055289 - * @library /testlibrary - * @build UnsafeMallocLimit - * @run main/othervm -Xmx32m -XX:NativeMemoryTracking=summary UnsafeMallocLimit - */ - -import com.oracle.java.testlibrary.*; -import sun.misc.Unsafe; - -public class UnsafeMallocLimit { - - public static void main(String args[]) throws Exception { - if (Platform.is32bit()) { - Unsafe unsafe = Utils.getUnsafe(); - try { - unsafe.allocateMemory(1 << 30); - throw new RuntimeException("Did not get expected OOME"); - } catch (OutOfMemoryError e) { - // Expected exception - } - } else { - System.out.println("Test only valid on 32-bit platforms"); - } - } -}
--- a/test/runtime/NMT/UnsafeMallocLimit2.java Thu Jan 08 12:47:32 2015 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,54 +0,0 @@ -/* - * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -/* - * @test - * @bug 8058818 - * @library /testlibrary - * @build UnsafeMallocLimit2 - * @run main/othervm -Xmx32m -XX:NativeMemoryTracking=off UnsafeMallocLimit2 - */ - -import com.oracle.java.testlibrary.*; -import sun.misc.Unsafe; - -public class UnsafeMallocLimit2 { - - public static void main(String args[]) throws Exception { - if (Platform.is32bit()) { - Unsafe unsafe = Utils.getUnsafe(); - try { - // Allocate greater than MALLOC_MAX and likely won't fail to allocate, - // so it hits the NMT code that asserted. - // Test that this doesn't cause an assertion with NMT off. - // The option above overrides if all the tests are run with NMT on. - unsafe.allocateMemory(0x40000000); - System.out.println("Allocation succeeded"); - } catch (OutOfMemoryError e) { - System.out.println("Allocation failed"); - } - } else { - System.out.println("Test only valid on 32-bit platforms"); - } - } -}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/runtime/RedefineTests/RedefineAnnotations.java Tue Feb 03 16:48:05 2015 +0000 @@ -0,0 +1,410 @@ +/* + * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @library /testlibrary + * @summary Test that type annotations are retained after a retransform + * @run main RedefineAnnotations buildagent + * @run main/othervm -javaagent:redefineagent.jar RedefineAnnotations + */ + +import static com.oracle.java.testlibrary.Asserts.assertTrue; +import java.io.FileNotFoundException; +import java.io.PrintWriter; +import java.lang.NoSuchFieldException; +import java.lang.NoSuchMethodException; +import java.lang.RuntimeException; +import java.lang.annotation.Annotation; +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; +import java.lang.instrument.ClassFileTransformer; +import java.lang.instrument.IllegalClassFormatException; +import java.lang.instrument.Instrumentation; +import java.lang.instrument.UnmodifiableClassException; +import java.lang.reflect.AnnotatedArrayType; +import java.lang.reflect.AnnotatedParameterizedType; +import java.lang.reflect.AnnotatedType; +import java.lang.reflect.AnnotatedWildcardType; +import java.lang.reflect.Executable; +import java.lang.reflect.TypeVariable; +import java.security.ProtectionDomain; +import java.util.Arrays; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import jdk.internal.org.objectweb.asm.ClassReader; +import jdk.internal.org.objectweb.asm.ClassVisitor; +import jdk.internal.org.objectweb.asm.ClassWriter; +import jdk.internal.org.objectweb.asm.FieldVisitor; +import static jdk.internal.org.objectweb.asm.Opcodes.ASM5; + +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.TYPE_USE) +@interface TestAnn { + String site(); +} + +public class RedefineAnnotations { + static Instrumentation inst; + public static void premain(String agentArgs, Instrumentation inst) { + RedefineAnnotations.inst = inst; + } + + static class Transformer implements ClassFileTransformer { + + public byte[] asm(ClassLoader loader, String className, + Class<?> classBeingRedefined, + ProtectionDomain protectionDomain, byte[] classfileBuffer) + throws IllegalClassFormatException { + + ClassWriter cw = new ClassWriter(0); + ClassVisitor cv = new ReAddDummyFieldsClassVisitor(ASM5, cw) { }; + ClassReader cr = new ClassReader(classfileBuffer); + cr.accept(cv, 0); + return cw.toByteArray(); + } + + public class ReAddDummyFieldsClassVisitor extends ClassVisitor { + + LinkedList<F> fields = new LinkedList<>(); + + public ReAddDummyFieldsClassVisitor(int api, ClassVisitor cv) { + super(api, cv); + } + + @Override public FieldVisitor visitField(int access, String name, + String desc, String signature, Object value) { + if (name.startsWith("dummy")) { + // Remove dummy field + fields.addLast(new F(access, name, desc, signature, value)); + return null; + } + return cv.visitField(access, name, desc, signature, value); + } + + @Override public void visitEnd() { + F f; + while ((f = fields.pollFirst()) != null) { + // Re-add dummy fields + cv.visitField(f.access, f.name, f.desc, f.signature, f.value); + } + } + + private class F { + private int access; + private String name; + private String desc; + private String signature; + private Object value; + F(int access, String name, String desc, String signature, Object value) { + this.access = access; + this.name = name; + this.desc = desc; + this.signature = signature; + this.value = value; + } + } + } + + @Override public byte[] transform(ClassLoader loader, String className, + Class<?> classBeingRedefined, + ProtectionDomain protectionDomain, byte[] classfileBuffer) + throws IllegalClassFormatException { + + if (className.contains("TypeAnnotatedTestClass")) { + try { + // Here we remove and re-add the dummy fields. This shuffles the constant pool + return asm(loader, className, classBeingRedefined, protectionDomain, classfileBuffer); + } catch (Throwable e) { + // The retransform native code that called this method does not propagate + // exceptions. Instead of getting an uninformative generic error, catch + // problems here and print it, then exit. + e.printStackTrace(); + System.exit(1); + } + } + return null; + } + } + + private static void buildAgent() { + try { + ClassFileInstaller.main("RedefineAnnotations"); + } catch (Exception e) { + throw new RuntimeException("Could not write agent classfile", e); + } + + try { + PrintWriter pw = new PrintWriter("MANIFEST.MF"); + pw.println("Premain-Class: RedefineAnnotations"); + pw.println("Agent-Class: RedefineAnnotations"); + pw.println("Can-Retransform-Classes: true"); + pw.close(); + } catch (FileNotFoundException e) { + throw new RuntimeException("Could not write manifest file for the agent", e); + } + + sun.tools.jar.Main jarTool = new sun.tools.jar.Main(System.out, System.err, "jar"); + if (!jarTool.run(new String[] { "-cmf", "MANIFEST.MF", "redefineagent.jar", "RedefineAnnotations.class" })) { + throw new RuntimeException("Could not write the agent jar file"); + } + } + + public static void main(String argv[]) throws NoSuchFieldException, NoSuchMethodException { + if (argv.length == 1 && argv[0].equals("buildagent")) { + buildAgent(); + return; + } + + if (inst == null) { + throw new RuntimeException("Instrumentation object was null"); + } + + RedefineAnnotations test = new RedefineAnnotations(); + test.testTransformAndVerify(); + } + + // Class type annotations + private Annotation classTypeParameterTA; + private Annotation extendsTA; + private Annotation implementsTA; + + // Field type annotations + private Annotation fieldTA; + private Annotation innerTA; + private Annotation[] arrayTA = new Annotation[4]; + private Annotation[] mapTA = new Annotation[5]; + + // Method type annotations + private Annotation returnTA, methodTypeParameterTA, formalParameterTA, throwsTA; + + private void testTransformAndVerify() + throws NoSuchFieldException, NoSuchMethodException { + + Class<TypeAnnotatedTestClass> c = TypeAnnotatedTestClass.class; + Class<?> myClass = c; + + /* + * Verify that the expected annotations are where they should be before transform. + */ + verifyClassTypeAnnotations(c); + verifyFieldTypeAnnotations(c); + verifyMethodTypeAnnotations(c); + + try { + inst.addTransformer(new Transformer(), true); + inst.retransformClasses(myClass); + } catch (UnmodifiableClassException e) { + throw new RuntimeException(e); + } + + /* + * Verify that the expected annotations are where they should be after transform. + * Also verify that before and after are equal. + */ + verifyClassTypeAnnotations(c); + verifyFieldTypeAnnotations(c); + verifyMethodTypeAnnotations(c); + } + + private void verifyClassTypeAnnotations(Class c) { + Annotation anno; + + anno = c.getTypeParameters()[0].getAnnotations()[0]; + verifyTestAnn(classTypeParameterTA, anno, "classTypeParameter"); + classTypeParameterTA = anno; + + anno = c.getAnnotatedSuperclass().getAnnotations()[0]; + verifyTestAnn(extendsTA, anno, "extends"); + extendsTA = anno; + + anno = c.getAnnotatedInterfaces()[0].getAnnotations()[0]; + verifyTestAnn(implementsTA, anno, "implements"); + implementsTA = anno; + } + + private void verifyFieldTypeAnnotations(Class c) + throws NoSuchFieldException, NoSuchMethodException { + + verifyBasicFieldTypeAnnotations(c); + verifyInnerFieldTypeAnnotations(c); + verifyArrayFieldTypeAnnotations(c); + verifyMapFieldTypeAnnotations(c); + } + + private void verifyBasicFieldTypeAnnotations(Class c) + throws NoSuchFieldException, NoSuchMethodException { + + Annotation anno = c.getDeclaredField("typeAnnotatedBoolean").getAnnotatedType().getAnnotations()[0]; + verifyTestAnn(fieldTA, anno, "field"); + fieldTA = anno; + } + + private void verifyInnerFieldTypeAnnotations(Class c) + throws NoSuchFieldException, NoSuchMethodException { + + AnnotatedType at = c.getDeclaredField("typeAnnotatedInner").getAnnotatedType(); + Annotation anno = at.getAnnotations()[0]; + verifyTestAnn(innerTA, anno, "inner"); + innerTA = anno; + } + + private void verifyArrayFieldTypeAnnotations(Class c) + throws NoSuchFieldException, NoSuchMethodException { + + Annotation anno; + AnnotatedType at; + + at = c.getDeclaredField("typeAnnotatedArray").getAnnotatedType(); + anno = at.getAnnotations()[0]; + verifyTestAnn(arrayTA[0], anno, "array1"); + arrayTA[0] = anno; + + for (int i = 1; i <= 3; i++) { + at = ((AnnotatedArrayType) at).getAnnotatedGenericComponentType(); + anno = at.getAnnotations()[0]; + verifyTestAnn(arrayTA[i], anno, "array" + (i + 1)); + arrayTA[i] = anno; + } + } + + private void verifyMapFieldTypeAnnotations(Class c) + throws NoSuchFieldException, NoSuchMethodException { + + Annotation anno; + AnnotatedType atBase; + AnnotatedType atParameter; + atBase = c.getDeclaredField("typeAnnotatedMap").getAnnotatedType(); + + anno = atBase.getAnnotations()[0]; + verifyTestAnn(mapTA[0], anno, "map1"); + mapTA[0] = anno; + + atParameter = + ((AnnotatedParameterizedType) atBase). + getAnnotatedActualTypeArguments()[0]; + anno = ((AnnotatedWildcardType) atParameter).getAnnotations()[0]; + verifyTestAnn(mapTA[1], anno, "map2"); + mapTA[1] = anno; + + anno = + ((AnnotatedWildcardType) atParameter). + getAnnotatedUpperBounds()[0].getAnnotations()[0]; + verifyTestAnn(mapTA[2], anno, "map3"); + mapTA[2] = anno; + + atParameter = + ((AnnotatedParameterizedType) atBase). + getAnnotatedActualTypeArguments()[1]; + anno = ((AnnotatedParameterizedType) atParameter).getAnnotations()[0]; + verifyTestAnn(mapTA[3], anno, "map4"); + mapTA[3] = anno; + + anno = + ((AnnotatedParameterizedType) atParameter). + getAnnotatedActualTypeArguments()[0].getAnnotations()[0]; + verifyTestAnn(mapTA[4], anno, "map5"); + mapTA[4] = anno; + } + + private void verifyMethodTypeAnnotations(Class c) + throws NoSuchFieldException, NoSuchMethodException { + Annotation anno; + Executable typeAnnotatedMethod = + c.getDeclaredMethod("typeAnnotatedMethod", TypeAnnotatedTestClass.class); + + anno = typeAnnotatedMethod.getAnnotatedReturnType().getAnnotations()[0]; + verifyTestAnn(returnTA, anno, "return"); + returnTA = anno; + + anno = typeAnnotatedMethod.getTypeParameters()[0].getAnnotations()[0]; + verifyTestAnn(methodTypeParameterTA, anno, "methodTypeParameter"); + methodTypeParameterTA = anno; + + anno = typeAnnotatedMethod.getAnnotatedParameterTypes()[0].getAnnotations()[0]; + verifyTestAnn(formalParameterTA, anno, "formalParameter"); + formalParameterTA = anno; + + anno = typeAnnotatedMethod.getAnnotatedExceptionTypes()[0].getAnnotations()[0]; + verifyTestAnn(throwsTA, anno, "throws"); + throwsTA = anno; + } + + private static void verifyTestAnn(Annotation verifyAgainst, Annotation anno, String expectedSite) { + verifyTestAnnSite(anno, expectedSite); + + // When called before transform verifyAgainst will be null, when called + // after transform it will be the annotation from before the transform + if (verifyAgainst != null) { + assertTrue(anno.equals(verifyAgainst), + "Annotations do not match before and after." + + " Before: \"" + verifyAgainst + "\", After: \"" + anno + "\""); + } + } + + private static void verifyTestAnnSite(Annotation testAnn, String expectedSite) { + String expectedAnn = "@TestAnn(site=" + expectedSite + ")"; + assertTrue(testAnn.toString().equals(expectedAnn), + "Expected \"" + expectedAnn + "\", got \"" + testAnn + "\""); + } + + public static class TypeAnnotatedTestClass <@TestAnn(site="classTypeParameter") S,T> + extends @TestAnn(site="extends") Thread + implements @TestAnn(site="implements") Runnable { + + public @TestAnn(site="field") boolean typeAnnotatedBoolean; + + public + RedefineAnnotations. + @TestAnn(site="inner") TypeAnnotatedTestClass + typeAnnotatedInner; + + public + @TestAnn(site="array4") boolean + @TestAnn(site="array1") [] + @TestAnn(site="array2") [] + @TestAnn(site="array3") [] + typeAnnotatedArray; + + public @TestAnn(site="map1") Map + <@TestAnn(site="map2") ? extends @TestAnn(site="map3") String, + @TestAnn(site="map4") List<@TestAnn(site="map5") Object>> typeAnnotatedMap; + + public int dummy1; + public int dummy2; + public int dummy3; + + @TestAnn(site="return") <@TestAnn(site="methodTypeParameter") U,V> Class + typeAnnotatedMethod(@TestAnn(site="formalParameter") TypeAnnotatedTestClass arg) + throws @TestAnn(site="throws") ClassNotFoundException { + + @TestAnn(site="local_variable_type") int foo = 0; + throw new ClassNotFoundException(); + } + + public void run() {} + } +}
--- a/test/runtime/SharedArchiveFile/LimitSharedSizes.java Thu Jan 08 12:47:32 2015 +0000 +++ b/test/runtime/SharedArchiveFile/LimitSharedSizes.java Tue Feb 03 16:48:05 2015 +0000 @@ -51,9 +51,12 @@ // Known issue, JDK-8038422 (assert() on Windows) // new SharedSizeTestData("-XX:SharedMiscDataSize", "500k", "miscellaneous data"), - // This will cause a VM crash; commenting out for now; see bug JDK-8038268 - // @ignore JDK-8038268 - // new SharedSizeTestData("-XX:SharedMiscCodeSize", "20k", "miscellaneous code"), + // Too small of a misc code size should not cause a vm crash. + // It should result in the following error message: + // The shared miscellaneous code space is not large enough + // to preload requested classes. Use -XX:SharedMiscCodeSize= + // to increase the initial size of shared miscellaneous code space. + new SharedSizeTestData("-XX:SharedMiscCodeSize", "20k", "miscellaneous code"), // these values are larger than default ones, but should // be acceptable and not cause failure
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/runtime/SharedArchiveFile/PrintSharedArchiveAndExit.java Tue Feb 03 16:48:05 2015 +0000 @@ -0,0 +1,83 @@ +/* + * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 8066670 + * @summary Testing -XX:+PrintSharedArchiveAndExit option + * @library /testlibrary + */ + +import com.oracle.java.testlibrary.*; + +public class PrintSharedArchiveAndExit { + public static void main(String[] args) throws Exception { + ProcessBuilder pb = ProcessTools.createJavaProcessBuilder( + "-XX:+UnlockDiagnosticVMOptions", "-XX:SharedArchiveFile=./sample.jsa", "-Xshare:dump"); + OutputAnalyzer output = new OutputAnalyzer(pb.start()); + try { + output.shouldContain("Loading classes to share"); + output.shouldHaveExitValue(0); + + // (1) With a valid archive + pb = ProcessTools.createJavaProcessBuilder( + "-XX:+UnlockDiagnosticVMOptions", "-XX:SharedArchiveFile=./sample.jsa", + "-XX:+PrintSharedArchiveAndExit", "-version"); + output = new OutputAnalyzer(pb.start()); + output.shouldContain("archive is valid"); + output.shouldNotContain("java version"); // Should not print JVM version + output.shouldHaveExitValue(0); // Should report success in error code. + + pb = ProcessTools.createJavaProcessBuilder( + "-XX:+UnlockDiagnosticVMOptions", "-XX:SharedArchiveFile=./sample.jsa", + "-XX:+PrintSharedArchiveAndExit"); + output = new OutputAnalyzer(pb.start()); + output.shouldContain("archive is valid"); + output.shouldNotContain("Usage:"); // Should not print JVM help message + output.shouldHaveExitValue(0); // Should report success in error code. + + // (2) With an invalid archive (boot class path has been prepended) + pb = ProcessTools.createJavaProcessBuilder( + "-Xbootclasspath/p:foo.jar", + "-XX:+UnlockDiagnosticVMOptions", "-XX:SharedArchiveFile=./sample.jsa", + "-XX:+PrintSharedArchiveAndExit", "-version"); + output = new OutputAnalyzer(pb.start()); + output.shouldContain("archive is invalid"); + output.shouldNotContain("java version"); // Should not print JVM version + output.shouldHaveExitValue(1); // Should report failure in error code. + + pb = ProcessTools.createJavaProcessBuilder( + "-Xbootclasspath/p:foo.jar", + "-XX:+UnlockDiagnosticVMOptions", "-XX:SharedArchiveFile=./sample.jsa", + "-XX:+PrintSharedArchiveAndExit"); + output = new OutputAnalyzer(pb.start()); + output.shouldContain("archive is invalid"); + output.shouldNotContain("Usage:"); // Should not print JVM help message + output.shouldHaveExitValue(1); // Should report failure in error code. + } catch (RuntimeException e) { + e.printStackTrace(); + output.shouldContain("Unable to use shared archive"); + output.shouldHaveExitValue(1); + } + } +}
--- a/test/runtime/lambda-features/InvokespecialInterface.java Thu Jan 08 12:47:32 2015 +0000 +++ b/test/runtime/lambda-features/InvokespecialInterface.java Tue Feb 03 16:48:05 2015 +0000 @@ -33,11 +33,12 @@ import java.util.function.*; import java.util.*; +public class InvokespecialInterface { interface I { default void imethod() { System.out.println("I::imethod"); } } -class C implements I { +static class C implements I { public void foo() { I.super.imethod(); } // invokespecial InterfaceMethod public void bar() { I i = this; i.imethod(); } // invokeinterface same public void doSomeInvokedynamic() { @@ -48,7 +49,6 @@ } } -public class InvokespecialInterface { public static void main(java.lang.String[] unused) { // need to create C and call I::foo() C c = new C();
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/runtime/lambda-features/TestInterfaceInit.java Tue Feb 03 16:48:05 2015 +0000 @@ -0,0 +1,87 @@ +/* + * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +/* + * @test + * @bug 8034275 + * @summary [JDK 8u40] Test interface initialization: only for interfaces declaring default methods + * @run main TestInterfaceInit + */ +import java.util.List; +import java.util.Arrays; +import java.util.ArrayList; + +public class TestInterfaceInit { + + static List<Class<?>> cInitOrder = new ArrayList<>(); + + // Declares a default method and initializes + interface I { + boolean v = TestInterfaceInit.out(I.class); + default void x() {} + } + + // Declares a default method and initializes + interface J extends I { + boolean v = TestInterfaceInit.out(J.class); + default void x() {} + } + // No default method, does not initialize + interface JN extends J { + boolean v = TestInterfaceInit.out(JN.class); + } + + // Declares a default method and initializes + interface K extends I { + boolean v = TestInterfaceInit.out(K.class); + default void x() {} + } + + // No default method, does not initialize + interface KN extends K { + boolean v = TestInterfaceInit.out(KN.class); + } + + interface L extends JN, KN { + boolean v = TestInterfaceInit.out(L.class); + default void x() {} + } + + public static void main(String[] args) { + // Trigger initialization + boolean v = L.v; + + List<Class<?>> expectedCInitOrder = Arrays.asList(I.class,J.class,K.class,L.class); + if (!cInitOrder.equals(expectedCInitOrder)) { + throw new RuntimeException(String.format("Class initialization array %s not equal to expected array %s", cInitOrder, expectedCInitOrder)); + } + } + + static boolean out(Class c) { + System.out.println("#: initializing " + c.getName()); + cInitOrder.add(c); + return true; + } + +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/runtime/lambda-features/TestInterfaceOrder.java Tue Feb 03 16:48:05 2015 +0000 @@ -0,0 +1,88 @@ +/* + * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +/* + * @test + * @bug 8034275 + * @summary [JDK 8u40] Test interface initialization order + * @run main TestInterfaceOrder + */ + +import java.util.List; +import java.util.Arrays; +import java.util.ArrayList; + +public class TestInterfaceOrder { + static List<Class<?>> cInitOrder = new ArrayList<>(); + + public static void main(java.lang.String[] args) { + //Trigger initialization + C c = new C(); + + List<Class<?>> expectedCInitOrder = Arrays.asList(I.class, J.class, A.class, K.class, B.class, L.class, C.class); + if (!cInitOrder.equals(expectedCInitOrder)) { + throw new RuntimeException(String.format("Class initialization order %s not equal to expected order %s", cInitOrder, expectedCInitOrder)); + } + } + + interface I { + boolean v = TestInterfaceOrder.out(I.class); + default void i() {} + } + + interface J extends I { + boolean v = TestInterfaceOrder.out(J.class); + default void j() {} + } + + static class A implements J { + static boolean v = TestInterfaceOrder.out(A.class); + } + + interface K extends I { + boolean v = TestInterfaceOrder.out(K.class); + default void k() {} + } + + static class B extends A implements K { + static boolean v = TestInterfaceOrder.out(B.class); + } + + interface L { + boolean v = TestInterfaceOrder.out(L.class); + default void l() {} + } + + static class C extends B implements L { + static boolean v = TestInterfaceOrder.out(C.class); + } + + + static boolean out(Class c) { + System.out.println("#: initializing " + c.getName()); + cInitOrder.add(c); + return true; + } + +}
--- a/test/testlibrary/whitebox/sun/hotspot/WhiteBox.java Thu Jan 08 12:47:32 2015 +0000 +++ b/test/testlibrary/whitebox/sun/hotspot/WhiteBox.java Tue Feb 03 16:48:05 2015 +0000 @@ -30,6 +30,7 @@ import java.util.function.Function; import java.util.stream.Stream; import java.security.BasicPermission; +import java.net.URL; import sun.hotspot.parser.DiagnosticCommand; @@ -84,6 +85,15 @@ } private native boolean isClassAlive0(String name); + // Resource/Class Lookup Cache + public native boolean classKnownToNotExist(ClassLoader loader, String name); + public native URL[] getLookupCacheURLs(ClassLoader loader); + public native int[] getLookupCacheMatches(ClassLoader loader, String name); + + // JVMTI + public native void addToBootstrapClassLoaderSearch(String segment); + public native void addToSystemClassLoaderSearch(String segment); + // G1 public native boolean g1InConcurrentMark(); public native boolean g1IsHumongous(Object o); @@ -98,10 +108,10 @@ public native void NMTCommitMemory(long addr, long size); public native void NMTUncommitMemory(long addr, long size); public native void NMTReleaseMemory(long addr, long size); - public native void NMTOverflowHashBucket(long num); public native long NMTMallocWithPseudoStack(long size, int index); public native boolean NMTIsDetailSupported(); public native boolean NMTChangeTrackingLevel(); + public native int NMTGetHashSize(); // Compiler public native void deoptimizeAll(); @@ -202,4 +212,13 @@ .findAny() .orElse(null); } + public native int getOffsetForName0(String name); + public int getOffsetForName(String name) throws Exception { + int offset = getOffsetForName0(name); + if (offset == -1) { + throw new RuntimeException(name + " not found"); + } + return offset; + } + }