# HG changeset patch # User Christian Wimmer # Date 1453762647 28800 # Node ID 7eb99acd567febe6c23cff95cc4a5900c1ed2dce # Parent c2687aa5e5ca8815e540e3c4716388e3d694c481# Parent 7f298e4d1afba9e26187e59e5fdff31b95fc2427 Merge diff -r c2687aa5e5ca -r 7eb99acd567f .hgtags --- a/.hgtags Mon Jan 25 14:56:57 2016 -0800 +++ b/.hgtags Mon Jan 25 14:57:27 2016 -0800 @@ -565,6 +565,38 @@ 4206e725d584be942c25ff46ff23d8e299ca4a4c jdk8u31-b13 b517d3a9aebf0fee64808f9a7c0ef8e0b82d5ed3 jdk8u31-b31 15d8108258cb60a58bdd03b9ff8e77dd6727a804 jdk8u31-b32 +26b1dc6891c4fae03575a9090f7d04bd631d9164 jdk8u31-b33 +1b3abbeee961dee49780c0e4af5337feb918c555 jdk8u40-b10 +f10fe402dfb1543723b4b117a7cba3ea3d4159f1 hs25.40-b15 +99372b2fee0eb8b3452f47230e84aa6e97003184 jdk8u40-b11 +8b9ec2da541a74ac698560b6a2bc45fccb789919 hs25.40-b16 +6b93bf9ea3ea57ed0fe53cfedb2f9ab912c324e5 jdk8u40-b12 +521e269ae1daa9df1cb0835b97aa76bdf340fcb2 hs25.40-b17 +86307d47790785398d0695acc361bccaefe25f94 jdk8u40-b13 +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 +0e67683b700174eab71ea205d1cfa4f1cf4523ba jdk8u40-b23 +fa4e797f61e6dda1a60e06944018213bff2a1b76 jdk8u40-b24 +698dd28ecc785ffc43e3f12266b13e85382c26a8 jdk8u40-b25 +f39b6944ad447269b81e06ca5da9edff9e9e67c8 jdk8u40-b26 +6824e2475e0432e27f9cc51838bc34ea5fbf5113 jdk8u40-b27 +8220f68a195f6eeed2f5fb6e8a303726b512e899 jdk8u40-b31 +850a290eb1088a61178d1910c500e170ef4f4386 jdk8u40-b32 1b3abbeee961dee49780c0e4af5337feb918c555 jdk8u40-b10 f10fe402dfb1543723b4b117a7cba3ea3d4159f1 hs25.40-b15 99372b2fee0eb8b3452f47230e84aa6e97003184 jdk8u40-b11 @@ -591,15 +623,6 @@ 0ee548a1cda08c884eccd563e2d5fdb6ee769b5a jdk8u40-b22 0e67683b700174eab71ea205d1cfa4f1cf4523ba jdk8u40-b23 fa4e797f61e6dda1a60e06944018213bff2a1b76 jdk8u40-b24 -b124e22eb772806c13d942cc110de38da0108147 graal-0.1 -483d05bf77a7c2a762aca1e06c4191bc06647176 graal-0.2 -9535eccd2a115f6c6f0b15efb508b11ff74cc0d3 graal-0.3 -7d4f630172a16e983212d46c0f1ad6cdb826dfce graal-0.4 -ae5b662550836e851c39e4fbb5c80517fc62488f graal-0.5 -3b60f720b955c466d913abb0113af9b38962950b graal-0.6 -1b0ef9634252c422b6f9839fc62eebc112545486 gpu-0.1 -9a12234da10cfa6934617274c203672389a1bbdd baseline-0.1 -754f2b20d8bc43053d254826e6b9f09db3f3c992 graal-0.7 698dd28ecc785ffc43e3f12266b13e85382c26a8 jdk8u40-b25 f39b6944ad447269b81e06ca5da9edff9e9e67c8 jdk8u40-b26 6824e2475e0432e27f9cc51838bc34ea5fbf5113 jdk8u40-b27 @@ -617,5 +640,129 @@ f4822d12204179e6a3e7aaf98991b6171670cbf2 jdk8u45-b11 dc29108bcbcbfcd49eaa9135368306dc85db73a6 jdk8u45-b12 efbf340fc7f56e49735111c23cef030413146409 jdk8u45-b13 +5321d26956b283b7cb73b04b91db41c7c9fe9158 jdk8u45-b14 +a5ba7c9a0b916ea088aaac5d40e17b4675c2b026 jdk8u45-b15 +894b92a02c533bcd1203c4beb5b6ec067b63466e jdk8u45-b31 +1428b6aa09c4e17202b801530c3c4993c7ce8e5b jdk8u45-b32 +9b2bf0d8a9a0fa7fe7486eb29454eae4b08f3d82 jdk8u45-b33 +dc3c47fc6218003b23338b978b3f13a6d7976b41 jdk8u45-b34 +3cb364e46590add7cb42ec8b6565a3c62adf824d jdk8u45-b35 +48b09bb741171b0069000ac1cf5407ef2357d3d1 jdk8u45-b36 +3c2ea5da6afd55a524e25dc56747940324befda2 jdk8u45-b37 +b22b01407a8140041545afe1f2d6335db4d94ba5 jdk8u51-b00 +c1de2652a48c1d4a0c96707acc73db3cd317df2a jdk8u51-b01 +8f03c2f5fc170da5fca2cf65734941efb619feca jdk8u51-b02 +cf295659243009ded76b6c14307c177a02f9fe82 jdk8u51-b03 +0b3f449553884d88f6c9d7ab067fa858f18cc3f1 jdk8u51-b04 +6ce994385353023e6b3f9c5ef331f390b324a355 jdk8u51-b05 +3816de51b5e7d6050584057fae5f2262dae53d7e jdk8u51-b06 +5c017acbaf015fb8ecca6f00870965f3deb4e1ac jdk8u51-b07 +631d4029d851b59613e6748e17447001a682276e jdk8u51-b08 +ce81c4487dd1e9f89d4570a8cd25e349f6bae00d jdk8u51-b09 +928e1994ad43272f808ca22b9cc1b08a7ce2824f jdk8u51-b10 +1a122beb9dc6881850ef1d1250f40a83709b8b72 jdk8u51-b11 +05c80f1060f0c0d5720de9eadd09162af1168eab jdk8u51-b12 +07e103f3f43886a3b47945e5295eb5accad505de jdk8u51-b13 +a4eea4bee2d4fdb05f1a8358d70ec6adb1135526 jdk8u51-b14 +9a70cba6a3c3e44486f9c199d03a16b2b09d0a13 jdk8u51-b15 +3639e38bd73f5efa8ce092f0a745bb0c90759575 jdk8u51-b16 +20bad8c6c7b406c3603b4e22b15cd990840a9d62 jdk8u51-b31 +d9349fa8822336e0244da0a8448f3e6b2d62741d jdk8u60-b00 +d9349fa8822336e0244da0a8448f3e6b2d62741d hs25.60-b00 +ebf89088c08ab0508b9002b48dd3d68a340259af hs25.60-b01 +5fa73007ceb92a13742fc4a24ec935a6494f8045 hs25.60-b02 +702cc6067686acaa45f7b455b7490edc056c2ae0 jdk8u60-b01 +1f6ba0d2923dadba87aac4ed779dd1ed0161ec2b hs25.60-b03 +38f6080523831ae9a6907c780f2042b82f3213ca jdk8u60-b02 +9d6eb2757167744a17ea71f8b860430d70941eda jdk8u60-b03 +0fb1ac49ae7764c5d7c6dfb9fe046d0e1a4eb5aa hs25.60-b04 +586a449cd30332dd53c0f74bf2ead6f3d4724bfc jdk8u60-b04 +74931e85352be8556eaa511ca0dd7c38fe272ec3 hs25.60-b05 +b13f1890afb8abc31ecb9c21fd2ba95aba3e33f8 jdk8u60-b05 +b17a8a22a0344e3c93e2e4677de20d35f99cf4f5 hs25.60-b06 +7b70923c8e04920b60278f90ad23a63c773cee7b jdk8u60-b06 +d51ef6da82b486e7b2b3c08eef9ca0a186935ded hs25.60-b07 +353e580ce6878d80c7b7cd27f8ad24609b12c58b jdk8u60-b07 +a72a4192a36d6d84766d6135fe6515346c742007 hs25.60-b08 +bf68e15dc8fe73eeb1eb3c656df51fdb1f707a97 jdk8u60-b08 +d937e6a0674841d670232ecf1611f52e1ae998e7 hs25.60-b09 +f1058b5c6294235d8ad032dcc72c8f8bc202cb5a jdk8u60-b09 +57a14c3927eba6372d909ae164fa90bb9b6a6ce4 hs25.60-b10 +8e4518dc2b38957072704ffe4cbf29f046dc9325 jdk8u60-b10 +64a32bc18e88eed6131ed036dc3e10e566ef339b hs25.60-b11 +d8f133adf05d310bd7e1d9adf32cbeb71ff33c37 jdk8u60-b11 +4390345de45c7768c04bfafabf006a401824c5b5 hs25.60-b12 +ccca7162738eee1be74890342c67d3b26540dcf6 jdk8u60-b12 +ced08ed4924fc6581626c7ce2d769fc18d7b23e0 jdk8u60-b13 +30e04eba9e298cc5094793e279306535239187cc hs25.60-b13 +1f0d760ccac1ff82a03a9b7d6bd5c697ef0a7c4a hs25.60-b14 +c9f8b7319d0a5ab07310cf53507642a8fd91589b jdk8u60-b14 +4187dc92e90b16b4097627b8af4f5e6e63f3b497 hs25.60-b15 +b99f1bf208f385277b03a985d35b6614b4095f3e jdk8u60-b15 +f5800068c61d0627c14e99836e9ce5cf0ef00075 hs25.60-b16 +ab2353694ea7fd4907c5c88b8334f8feaafca8c7 jdk8u60-b16 +5efc25c367164b6856554b0d625f3c422fdf9558 hs25.60-b17 +c26d09f1065cd26bd8b926efc5d3938b71e09eb5 jdk8u60-b17 +624f4cc05e7e95dd2103f343c54d7bdea6a81919 hs25.60-b18 +3fa5c654c143fe309e5ddda92adc5fb132365bcf jdk8u60-b18 +b852350a2bc6d5f43006e2be53fb74d148290708 hs25.60-b19 +bd9221771f6e34e63b3b340ffcf9906ccf882dae jdk8u60-b19 +e01a710549a962cee94728271248a7d89fb56c49 hs25.60-b20 +3b6c97747ccc61d189bca64b4afa3ffc13680810 jdk8u60-b20 +4b6687a4f2fe84211b8b3b5afb34b5186afbddf6 hs25.60-b21 +e0d75c284bd1c09fd7d9ef09627d8a99b88d468d jdk8u60-b21 +ff8fdeb2fb6d6f3348597339c53412f8f6202c3f hs25.60-b22 +878cb0df27c22c6b1e9f4add1eb3da3edc8ab51d jdk8u60-b22 +ad04e0ef0f85625b68ed18e949c75399b8d9b99b hs25.66-b01 +0e4094950cd312c8f95c7f37336606323fe049fe jdk8u60-b23 +d89ceecf1bad55e1aee2932b8895d60fc64c15db hs25.60-b23 +fb157d537278cda4150740e27bb57cd8694e15bf jdk8u60-b24 +6b4ea38c01bd9cc86d0aa8926f4855ff6ee365ee jdk8u60-b25 +6a6759372807f49aa7a66ddc36aa91d6648d2097 jdk8u60-b26 +10ad4b9d79f98fa3545c88a342a68a80d198b808 jdk8u60-b27 +0219ab69f00782e5c49687e2fa75138a7ffddea1 jdk8u52-b06 +9b6f44853eed8caba935915c7e710c546b205c8e jdk8u52-b07 +0219ab69f00782e5c49687e2fa75138a7ffddea1 jdk8u65-b00 +b6815d853c359be92e61f422ea5018af1f81d0c7 jdk8u65-b01 +488661b9cbdaeb24be14873f3bd39a945575692a jdk8u65-b02 +ea47136e6ea4253c0bf238fb61760f98a8d01ebc jdk8u65-b03 +2a03fd592fe60fd113c1c89e431ebaa6857c4998 jdk8u65-b04 +aa915217a00c4b8ce0e82d1b23fa1df8a9e4cc70 jdk8u65-b05 +3070e116da4cfebc2ceb0df8f40faeefd38a6d4a jdk8u65-b06 +008b42595f2babc98e1b23bc00f27e308f9a35b9 jdk8u65-b07 +d8519b30e607f87cad6c949c6b52c1dba0cde7a8 jdk8u65-b08 +c6d1a21e213d62f423ac9013bcc7dc0bc05e38b6 jdk8u65-b09 +0274b03fdf4a3e4d125547d68ed74b4f55d515ec jdk8u65-b10 +a106723ba50719c479614d1f599e951edb51506c jdk8u65-b11 +a5fbc6967cf5d170be56c9804b90ebb6bbd02832 jdk8u65-b12 +529bea83b67412ffb5a7eb0ed8f8772732bbf446 jdk8u65-b13 +ccc03258fbcfbcdf515ceb87bd3699c8f849dc0d jdk8u65-b14 +03ca585abe68e4dcce5bc162a0fa0593eb8fa2ee jdk8u65-b15 +b4137dc9b1a83409fbd2b80d2ffd5ae949cd7a6b jdk8u65-b16 +8e9c73f18f7e565f1d2100fab7cb8e9e785b1991 jdk8u65-b17 +878cb0df27c22c6b1e9f4add1eb3da3edc8ab51d jdk8u66-b00 +777a354cada52b831a32bfc5362ad7cedfde4450 jdk8u66-b01 +0366ad2644f58ec88af9cb2ea8c23a02559fb2d1 hs25.66-b02 +47110b037994f9006c22abcb12569fcafad84edb hs25.66-b03 +ae5624088d86abe8e7981dbb893c1b6da5140a1c jdk8u66-b02 +6594411c4eb4d00e439330a61744f077d0b96363 jdk8u66-b07 +aedefb75358f3cda5181bf594c2cda833056b25a jdk8u66-b08 +83621deea0fcb4a517b94c5546b4f8738588cb6c jdk8u66-b09 +5280a8174aea13bd242480419e6228857dac7b59 jdk8u66-b10 +8a23b6392c590b7bf5f6ad2c4746dc03981a7f60 jdk8u66-b11 +ab64d7ea4f48ea4bdbcc43d4a653be157d9c29e3 jdk8u66-b12 +4d699853544cf869d4edaf23b7cc9cfbb2900a2b jdk8u66-b13 +9f7f29ff487ae023ca1f697445004a532751b0d2 jdk8u66-b14 +5b67af3317bce1f940c5dc1535411a1002bed6c1 jdk8u66-b15 +4bbf0e9196f2786e0bc4f17664e2533808d944bf jdk8u66-b16 +b124e22eb772806c13d942cc110de38da0108147 graal-0.1 +483d05bf77a7c2a762aca1e06c4191bc06647176 graal-0.2 +9535eccd2a115f6c6f0b15efb508b11ff74cc0d3 graal-0.3 +7d4f630172a16e983212d46c0f1ad6cdb826dfce graal-0.4 +ae5b662550836e851c39e4fbb5c80517fc62488f graal-0.5 +3b60f720b955c466d913abb0113af9b38962950b graal-0.6 +1b0ef9634252c422b6f9839fc62eebc112545486 gpu-0.1 +9a12234da10cfa6934617274c203672389a1bbdd baseline-0.1 +754f2b20d8bc43053d254826e6b9f09db3f3c992 graal-0.7 3c622007e098d8905d8e0947362a3894a629a5f1 graal-0.8 3c622007e098d8905d8e0947362a3894a629a5f1 jvmci-0.8 diff -r c2687aa5e5ca -r 7eb99acd567f THIRD_PARTY_README --- a/THIRD_PARTY_README Mon Jan 25 14:56:57 2016 -0800 +++ b/THIRD_PARTY_README Mon Jan 25 14:57:27 2016 -0800 @@ -1140,37 +1140,6 @@ -------------------------------------------------------------------------------- -%% This notice is provided with respect to JSON, which may be included -with JRE 8 & JDK 8. - ---- begin of LICENSE --- - -Copyright (c) 2002 JSON.org - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -The Software shall be used for Good, not Evil. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. - ---- end of LICENSE --- - -------------------------------------------------------------------------------- - %% This notice is provided with respect to Kerberos functionality, which which may be included with JRE 8, JDK 8, and OpenJDK 8. @@ -1250,7 +1219,7 @@ ------------------------------------------------------------------------------- -%% This notice is provided with respect to libpng 1.6.16, which may be +%% This notice is provided with respect to libpng 1.6.16, which may be included with JRE 8, JDK 8, and OpenJDK 8. --- begin of LICENSE --- @@ -1370,7 +1339,7 @@ ------------------------------------------------------------------------------- -%% This notice is provided with respect to libungif 4.1.3, which may be +%% This notice is provided with respect to GIFLIB 5.1.1 & libungif 4.1.3, which may be included with JRE 8, JDK 8, and OpenJDK 8. --- begin of LICENSE --- @@ -1399,13 +1368,13 @@ ------------------------------------------------------------------------------- -%% This notice is provided with respect to Little CMS 2.5, which may be +%% This notice is provided with respect to Little CMS 2.7, which may be included with JRE 8, JDK 8, and OpenJDK 8. --- begin of LICENSE --- Little CMS -Copyright (c) 1998-2011 Marti Maria Saguer +Copyright (c) 1998-2015 Marti Maria Saguer Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff -r c2687aa5e5ca -r 7eb99acd567f agent/src/os/bsd/MacosxDebuggerLocal.m --- a/agent/src/os/bsd/MacosxDebuggerLocal.m Mon Jan 25 14:56:57 2016 -0800 +++ b/agent/src/os/bsd/MacosxDebuggerLocal.m Mon Jan 25 14:57:27 2016 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 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 @@ -26,7 +26,7 @@ #import #import -#include +#include #import #import diff -r c2687aa5e5ca -r 7eb99acd567f agent/src/os/bsd/Makefile --- a/agent/src/os/bsd/Makefile Mon Jan 25 14:56:57 2016 -0800 +++ b/agent/src/os/bsd/Makefile Mon Jan 25 14:57:27 2016 -0800 @@ -1,5 +1,5 @@ # -# Copyright (c) 2002, 2013, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2002, 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 @@ -50,9 +50,9 @@ ps_core.c OBJS = $(SOURCES:.c=.o) OBJSPLUS = MacosxDebuggerLocal.o sadis.o $(OBJS) -EXTINCLUDE = -I/System/Library/Frameworks/JavaVM.framework/Headers -I. +EXTINCLUDE = -I. EXTCFLAGS = -m64 -D__APPLE__ -framework JavaNativeFoundation -FOUNDATIONFLAGS = -framework Foundation -F/System/Library/Frameworks/JavaVM.framework/Frameworks -framework JavaNativeFoundation -framework Security -framework CoreFoundation +FOUNDATIONFLAGS = -framework Foundation -framework JavaNativeFoundation -framework Security -framework CoreFoundation LIBSA = $(ARCH)/libsaproc.dylib endif # Darwin diff -r c2687aa5e5ca -r 7eb99acd567f agent/src/os/linux/libproc.h --- a/agent/src/os/linux/libproc.h Mon Jan 25 14:56:57 2016 -0800 +++ b/agent/src/os/linux/libproc.h Mon Jan 25 14:57:27 2016 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 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 @@ -30,7 +30,7 @@ #include #include "proc_service.h" -#if defined(arm) || defined(ppc) +#ifdef ALT_SASRCDIR #include "libproc_md.h" #endif diff -r c2687aa5e5ca -r 7eb99acd567f agent/src/os/linux/ps_proc.c --- a/agent/src/os/linux/ps_proc.c Mon Jan 25 14:56:57 2016 -0800 +++ b/agent/src/os/linux/ps_proc.c Mon Jan 25 14:57:27 2016 -0800 @@ -27,9 +27,11 @@ #include #include #include +#include #include #include #include +#include #include "libproc_impl.h" #if defined(x86_64) && !defined(amd64) @@ -138,6 +140,15 @@ return false; } return true; +#elif defined(PTRACE_GETREGSET) + struct iovec iov; + iov.iov_base = user; + iov.iov_len = sizeof(*user); + if (ptrace(PTRACE_GETREGSET, pid, NT_PRSTATUS, (void*) &iov) < 0) { + print_debug("ptrace(PTRACE_GETREGSET, ...) failed for lwp %d\n", pid); + return false; + } + return true; #else print_debug("ptrace(PTRACE_GETREGS, ...) not supported\n"); return false; diff -r c2687aa5e5ca -r 7eb99acd567f agent/src/os/solaris/proc/saproc.cpp --- a/agent/src/os/solaris/proc/saproc.cpp Mon Jan 25 14:56:57 2016 -0800 +++ b/agent/src/os/solaris/proc/saproc.cpp Mon Jan 25 14:57:27 2016 -0800 @@ -314,7 +314,7 @@ handle = dlopen(name, mode); } if (_libsaproc_debug) { - printf("libsaproc DEBUG: pathmap_dlopen %s return 0x%x\n", name, handle); + printf("libsaproc DEBUG: pathmap_dlopen %s return 0x%lx\n", name, (unsigned long) handle); } return handle; } @@ -661,30 +661,30 @@ // read FileMapHeader size_t n = read(fd, pheader, sizeof(struct FileMapHeader)); if (n != sizeof(struct FileMapHeader)) { - free(pheader); - close(fd); char errMsg[ERR_MSG_SIZE]; sprintf(errMsg, "unable to read shared archive file map header from %s", classes_jsa); + close(fd); + free(pheader); THROW_NEW_DEBUGGER_EXCEPTION_(errMsg, 1); } // check file magic if (pheader->_magic != 0xf00baba2) { - free(pheader); - close(fd); char errMsg[ERR_MSG_SIZE]; sprintf(errMsg, "%s has bad shared archive magic 0x%x, expecting 0xf00baba2", classes_jsa, pheader->_magic); + close(fd); + free(pheader); THROW_NEW_DEBUGGER_EXCEPTION_(errMsg, 1); } // check version if (pheader->_version != CURRENT_ARCHIVE_VERSION) { - free(pheader); - close(fd); char errMsg[ERR_MSG_SIZE]; sprintf(errMsg, "%s has wrong shared archive version %d, expecting %d", classes_jsa, pheader->_version, CURRENT_ARCHIVE_VERSION); + close(fd); + free(pheader); THROW_NEW_DEBUGGER_EXCEPTION_(errMsg, 1); } diff -r c2687aa5e5ca -r 7eb99acd567f agent/src/share/classes/com/sun/java/swing/action/ActionManager.java --- a/agent/src/share/classes/com/sun/java/swing/action/ActionManager.java Mon Jan 25 14:56:57 2016 -0800 +++ b/agent/src/share/classes/com/sun/java/swing/action/ActionManager.java Mon Jan 25 14:57:27 2016 -0800 @@ -46,6 +46,11 @@ return manager; } + protected static void setInstance(ActionManager m) + { + manager = m; + } + protected abstract void addActions(); protected void addAction(String cmdname, Action action) @@ -90,6 +95,6 @@ private HashMap actions; private static ActionUtilities utilities = new ActionUtilities(); - protected static ActionManager manager; + private static ActionManager manager; } diff -r c2687aa5e5ca -r 7eb99acd567f agent/src/share/classes/com/sun/java/swing/ui/CommonToolBar.java --- a/agent/src/share/classes/com/sun/java/swing/ui/CommonToolBar.java Mon Jan 25 14:56:57 2016 -0800 +++ b/agent/src/share/classes/com/sun/java/swing/ui/CommonToolBar.java Mon Jan 25 14:57:27 2016 -0800 @@ -46,7 +46,7 @@ { this.manager = manager; statusBar = status; - buttonSize = new Dimension(CommonUI.buttconPrefSize); + buttonSize = new Dimension(CommonUI.getButtconPrefSize()); buttonInsets = new Insets(0, 0, 0, 0); addComponents(); } diff -r c2687aa5e5ca -r 7eb99acd567f agent/src/share/classes/com/sun/java/swing/ui/CommonUI.java --- a/agent/src/share/classes/com/sun/java/swing/ui/CommonUI.java Mon Jan 25 14:56:57 2016 -0800 +++ b/agent/src/share/classes/com/sun/java/swing/ui/CommonUI.java Mon Jan 25 14:57:27 2016 -0800 @@ -373,20 +373,25 @@ comp.setCursor(Cursor.getPredefinedCursor(0)); } - public static final int BUTTON_WIDTH = 100; - public static final int BUTTON_HEIGHT = 26; - public static final int BUTTCON_WIDTH = 28; - public static final int BUTTCON_HEIGHT = 28; - public static final int SM_BUTTON_WIDTH = 72; - public static final int SM_BUTTON_HEIGHT = 26; - public static final int LABEL_WIDTH = 100; - public static final int LABEL_HEIGHT = 20; - public static final int TEXT_WIDTH = 150; - public static final int TEXT_HEIGHT = 20; - public static Dimension buttonPrefSize = new Dimension(100, 26); - public static Dimension buttconPrefSize = new Dimension(28, 28); - public static Dimension smbuttonPrefSize = new Dimension(72, 26); - public static Dimension labelPrefSize = new Dimension(100, 20); - public static Dimension textPrefSize = new Dimension(150, 20); + public static Dimension getButtconPrefSize() + { + return buttconPrefSize; + } + + private static final int BUTTON_WIDTH = 100; + private static final int BUTTON_HEIGHT = 26; + private static final int BUTTCON_WIDTH = 28; + private static final int BUTTCON_HEIGHT = 28; + private static final int SM_BUTTON_WIDTH = 72; + private static final int SM_BUTTON_HEIGHT = 26; + private static final int LABEL_WIDTH = 100; + private static final int LABEL_HEIGHT = 20; + private static final int TEXT_WIDTH = 150; + private static final int TEXT_HEIGHT = 20; + private static final Dimension buttonPrefSize = new Dimension(100, 26); + private static final Dimension buttconPrefSize = new Dimension(28, 28); + private static final Dimension smbuttonPrefSize = new Dimension(72, 26); + private static final Dimension labelPrefSize = new Dimension(100, 20); + private static final Dimension textPrefSize = new Dimension(150, 20); } diff -r c2687aa5e5ca -r 7eb99acd567f agent/src/share/classes/sun/jvm/hotspot/HotSpotTypeDataBase.java --- a/agent/src/share/classes/sun/jvm/hotspot/HotSpotTypeDataBase.java Mon Jan 25 14:56:57 2016 -0800 +++ b/agent/src/share/classes/sun/jvm/hotspot/HotSpotTypeDataBase.java Mon Jan 25 14:57:27 2016 -0800 @@ -51,6 +51,9 @@ private static final int C_INT32_SIZE = 4; private static final int C_INT64_SIZE = 8; private static int pointerSize = UNINITIALIZED_SIZE; + // Counter to ensure read loops terminate: + private static final int MAX_DUPLICATE_DEFINITIONS = 100; + private int duplicateDefCount = 0; private static final boolean DEBUG; static { @@ -166,6 +169,10 @@ typeEntrySizeOffset = getLongValueFromProcess("gHotSpotVMTypeEntrySizeOffset"); typeEntryArrayStride = getLongValueFromProcess("gHotSpotVMTypeEntryArrayStride"); + if (typeEntryArrayStride == 0L) { + throw new RuntimeException("zero stride: cannot read types."); + } + // Start iterating down it until we find an entry with no name Address typeNameAddr = null; do { @@ -192,7 +199,11 @@ } entryAddr = entryAddr.addOffsetTo(typeEntryArrayStride); - } while (typeNameAddr != null); + } while (typeNameAddr != null && duplicateDefCount < MAX_DUPLICATE_DEFINITIONS); + + if (duplicateDefCount >= MAX_DUPLICATE_DEFINITIONS) { + throw new RuntimeException("too many duplicate definitions"); + } } private void initializePrimitiveTypes() { @@ -395,6 +406,10 @@ structEntryAddressOffset = getLongValueFromProcess("gHotSpotVMStructEntryAddressOffset"); structEntryArrayStride = getLongValueFromProcess("gHotSpotVMStructEntryArrayStride"); + if (structEntryArrayStride == 0L) { + throw new RuntimeException("zero stride: cannot read types."); + } + // Fetch the address of the VMStructEntry* Address entryAddr = lookupInProcess("gHotSpotVMStructs"); // Dereference this once to get the pointer to the first VMStructEntry @@ -472,6 +487,11 @@ intConstantEntryValueOffset = getLongValueFromProcess("gHotSpotVMIntConstantEntryValueOffset"); intConstantEntryArrayStride = getLongValueFromProcess("gHotSpotVMIntConstantEntryArrayStride"); + if (intConstantEntryArrayStride == 0L) { + throw new RuntimeException("zero stride: cannot read types."); + } + + // Fetch the address of the VMIntConstantEntry* Address entryAddr = lookupInProcess("gHotSpotVMIntConstants"); // Dereference this once to get the pointer to the first VMIntConstantEntry @@ -501,12 +521,17 @@ } else { System.err.println("Warning: the int constant \"" + name + "\" (declared in the remote VM in VMStructs::localHotSpotVMIntConstants) " + "had its value declared as " + value + " twice. Continuing."); + duplicateDefCount++; } } } entryAddr = entryAddr.addOffsetTo(intConstantEntryArrayStride); - } while (nameAddr != null); + } while (nameAddr != null && duplicateDefCount < MAX_DUPLICATE_DEFINITIONS); + + if (duplicateDefCount >= MAX_DUPLICATE_DEFINITIONS) { + throw new RuntimeException("too many duplicate definitions"); + } } private void readVMLongConstants() { @@ -519,6 +544,10 @@ longConstantEntryValueOffset = getLongValueFromProcess("gHotSpotVMLongConstantEntryValueOffset"); longConstantEntryArrayStride = getLongValueFromProcess("gHotSpotVMLongConstantEntryArrayStride"); + if (longConstantEntryArrayStride == 0L) { + throw new RuntimeException("zero stride: cannot read types."); + } + // Fetch the address of the VMLongConstantEntry* Address entryAddr = lookupInProcess("gHotSpotVMLongConstants"); // Dereference this once to get the pointer to the first VMLongConstantEntry @@ -548,12 +577,17 @@ } else { System.err.println("Warning: the long constant \"" + name + "\" (declared in the remote VM in VMStructs::localHotSpotVMLongConstants) " + "had its value declared as " + value + " twice. Continuing."); + duplicateDefCount++; } } } entryAddr = entryAddr.addOffsetTo(longConstantEntryArrayStride); - } while (nameAddr != null); + } while (nameAddr != null && duplicateDefCount < MAX_DUPLICATE_DEFINITIONS); + + if (duplicateDefCount >= MAX_DUPLICATE_DEFINITIONS) { + throw new RuntimeException("too many duplicate definitions."); + } } private BasicType lookupOrFail(String typeName) { @@ -740,9 +774,10 @@ } if (!typeNameIsPointerType(typeName)) { - System.err.println("Warning: the type \"" + typeName + "\" (declared in the remote VM in VMStructs::localHotSpotVMTypes) " + - "had its size declared as " + size + " twice. Continuing."); - } + System.err.println("Warning: the type \"" + typeName + "\" (declared in the remote VM in VMStructs::localHotSpotVMTypes) " + + "had its size declared as " + size + " twice. Continuing."); + duplicateDefCount++; + } } } diff -r c2687aa5e5ca -r 7eb99acd567f agent/src/share/classes/sun/jvm/hotspot/gc_interface/G1YCType.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/agent/src/share/classes/sun/jvm/hotspot/gc_interface/G1YCType.java Mon Jan 25 14:57:27 2016 -0800 @@ -0,0 +1,45 @@ +/* + * Copyright (c) 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 + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +package sun.jvm.hotspot.gc_interface; + +//These definitions should be kept in sync with the definitions in the HotSpot +//code. + +public enum G1YCType { + Normal ("Normal"), + InitialMark ("Initial Mark"), + DuringMark ("During Mark"), + Mixed ("Mixed"), + G1YCTypeEndSentinel ("Unknown"); + + private final String value; + + G1YCType(String val) { + this.value = val; + } + public String value() { + return value; + } +} diff -r c2687aa5e5ca -r 7eb99acd567f agent/src/share/classes/sun/jvm/hotspot/gc_interface/GCCause.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/agent/src/share/classes/sun/jvm/hotspot/gc_interface/GCCause.java Mon Jan 25 14:57:27 2016 -0800 @@ -0,0 +1,69 @@ +/* + * Copyright (c) 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 + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +package sun.jvm.hotspot.gc_interface; + +//These definitions should be kept in sync with the definitions in the HotSpot code. + +public enum GCCause { + _java_lang_system_gc ("System.gc()"), + _full_gc_alot ("FullGCAlot"), + _scavenge_alot ("ScavengeAlot"), + _allocation_profiler ("Allocation Profiler"), + _jvmti_force_gc ("JvmtiEnv ForceGarbageCollection"), + _gc_locker ("GCLocker Initiated GC"), + _heap_inspection ("Heap Inspection Initiated GC"), + _heap_dump ("Heap Dump Initiated GC"), + + _no_gc ("No GC"), + _no_cause_specified ("Unknown GCCause"), + _allocation_failure ("Allocation Failure"), + + _tenured_generation_full ("Tenured Generation Full"), + _metadata_GC_threshold ("Metadata GC Threshold"), + + _cms_generation_full ("CMS Generation Full"), + _cms_initial_mark ("CMS Initial Mark"), + _cms_final_remark ("CMS Final Remark"), + _cms_concurrent_mark ("CMS Concurrent Mark"), + + _old_generation_expanded_on_last_scavenge ("Old Generation Expanded On Last Scavenge"), + _old_generation_too_full_to_scavenge ("Old Generation Too Full To Scavenge"), + _adaptive_size_policy ("Ergonomics"), + + _g1_inc_collection_pause ("G1 Evacuation Pause"), + _g1_humongous_allocation ("G1 Humongous Allocation"), + + _last_ditch_collection ("Last ditch collection"), + _last_gc_cause ("ILLEGAL VALUE - last gc cause - ILLEGAL VALUE"); + + private final String value; + + GCCause(String val) { + this.value = val; + } + public String value() { + return value; + } +} diff -r c2687aa5e5ca -r 7eb99acd567f agent/src/share/classes/sun/jvm/hotspot/gc_interface/GCName.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/agent/src/share/classes/sun/jvm/hotspot/gc_interface/GCName.java Mon Jan 25 14:57:27 2016 -0800 @@ -0,0 +1,50 @@ +/* + * Copyright (c) 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 + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +package sun.jvm.hotspot.gc_interface; + +//These definitions should be kept in sync with the definitions in the HotSpot code. + +public enum GCName { + ParallelOld ("ParallelOld"), + SerialOld ("SerialOld"), + PSMarkSweep ("PSMarkSweep"), + ParallelScavenge ("ParallelScavenge"), + DefNew ("DefNew"), + ParNew ("ParNew"), + G1New ("G1New"), + ConcurrentMarkSweep ("ConcurrentMarkSweep"), + G1Old ("G1Old"), + GCNameEndSentinel ("GCNameEndSentinel"); + + private final String value; + + GCName(String val) { + this.value = val; + } + public String value() { + return value; + } +} + diff -r c2687aa5e5ca -r 7eb99acd567f agent/src/share/classes/sun/jvm/hotspot/gc_interface/GCWhen.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/agent/src/share/classes/sun/jvm/hotspot/gc_interface/GCWhen.java Mon Jan 25 14:57:27 2016 -0800 @@ -0,0 +1,45 @@ +/* + * Copyright (c) 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 + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +package sun.jvm.hotspot.gc_interface; + +//These definitions should be kept in sync with the definitions in the HotSpot code. + +public enum GCWhen { + BeforeGC ("Before GC"), + AfterGC ("After GC"), + GCWhenEndSentinel ("GCWhenEndSentinel"); + + private final String value; + + GCWhen(String val) { + this.value = val; + } + public String value() { + return value; + } +} + + + diff -r c2687aa5e5ca -r 7eb99acd567f agent/src/share/classes/sun/jvm/hotspot/gc_interface/ReferenceType.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/agent/src/share/classes/sun/jvm/hotspot/gc_interface/ReferenceType.java Mon Jan 25 14:57:27 2016 -0800 @@ -0,0 +1,45 @@ +/* + * Copyright (c) 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 + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +package sun.jvm.hotspot.gc_interface; + +//These definitions should be kept in sync with the definitions in the HotSpot code. + +public enum ReferenceType { + REF_NONE ("None reference"), // Regular class + REF_OTHER ("Other reference"), // Subclass of java/lang/ref/Reference, but not subclass of one of the classes below + REF_SOFT ("Soft reference"), // Subclass of java/lang/ref/SoftReference + REF_WEAK ("Weak reference"), // Subclass of java/lang/ref/WeakReference + REF_FINAL ("Final reference"), // Subclass of java/lang/ref/FinalReference + REF_PHANTOM ("Phantom reference"); // Subclass of java/lang/ref/PhantomReference + + private final String value; + + ReferenceType(String val) { + this.value = val; + } + public String value() { + return value; + } +} diff -r c2687aa5e5ca -r 7eb99acd567f agent/src/share/classes/sun/jvm/hotspot/memory/AdaptiveFreeList.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/agent/src/share/classes/sun/jvm/hotspot/memory/AdaptiveFreeList.java Mon Jan 25 14:57:27 2016 -0800 @@ -0,0 +1,77 @@ +/* + * @(#)AdaptiveFreeList.java + * + * Copyright (c) 2000, 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. + * + */ + +package sun.jvm.hotspot.memory; + +import java.util.Observable; +import java.util.Observer; + +import sun.jvm.hotspot.debugger.Address; +import sun.jvm.hotspot.runtime.VM; +import sun.jvm.hotspot.runtime.VMObject; +import sun.jvm.hotspot.types.CIntegerField; +import sun.jvm.hotspot.types.Type; +import sun.jvm.hotspot.types.TypeDataBase; + +public class AdaptiveFreeList extends VMObject { + static { + VM.registerVMInitializedObserver(new Observer() { + public void update(Observable o, Object data) { + initialize(VM.getVM().getTypeDataBase()); + } + }); + } + + private static synchronized void initialize(TypeDataBase db) { + Type type = db.lookupType("AdaptiveFreeList"); + sizeField = type.getCIntegerField("_size"); + countField = type.getCIntegerField("_count"); + headerSize = type.getSize(); + } + + // Fields + private static CIntegerField sizeField; + private static CIntegerField countField; + private static long headerSize; + + //Constructor + public AdaptiveFreeList(Address address) { + super(address); + } + + // Accessors + public long size() { + return sizeField.getValue(addr); + } + + public long count() { + return countField.getValue(addr); + } + + public static long sizeOf() { + return headerSize; + } +} diff -r c2687aa5e5ca -r 7eb99acd567f agent/src/share/classes/sun/jvm/hotspot/memory/CompactibleFreeListSpace.java --- a/agent/src/share/classes/sun/jvm/hotspot/memory/CompactibleFreeListSpace.java Mon Jan 25 14:56:57 2016 -0800 +++ b/agent/src/share/classes/sun/jvm/hotspot/memory/CompactibleFreeListSpace.java Mon Jan 25 14:57:27 2016 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 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,25 +24,29 @@ package sun.jvm.hotspot.memory; -import java.io.*; -import java.util.*; -import sun.jvm.hotspot.debugger.*; -import sun.jvm.hotspot.oops.*; -import sun.jvm.hotspot.runtime.*; -import sun.jvm.hotspot.types.*; -import sun.jvm.hotspot.utilities.*; +import java.io.PrintStream; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; +import java.util.Observable; +import java.util.Observer; + +import sun.jvm.hotspot.debugger.Address; +import sun.jvm.hotspot.debugger.Debugger; +import sun.jvm.hotspot.oops.ObjectHeap; +import sun.jvm.hotspot.oops.Oop; +import sun.jvm.hotspot.runtime.VM; +import sun.jvm.hotspot.runtime.VMObjectFactory; +import sun.jvm.hotspot.types.AddressField; +import sun.jvm.hotspot.types.Type; +import sun.jvm.hotspot.types.TypeDataBase; +import sun.jvm.hotspot.utilities.Assert; public class CompactibleFreeListSpace extends CompactibleSpace { private static AddressField collectorField; - - // for free size, three fields - // FreeBlockDictionary* _dictionary; // ptr to dictionary for large size blocks - // FreeList _indexedFreeList[IndexSetSize]; // indexed array for small size blocks - // LinearAllocBlock _smallLinearAllocBlock; // small linear alloc in TLAB private static AddressField indexedFreeListField; private static AddressField dictionaryField; private static long smallLinearAllocBlockFieldOffset; - private static long indexedFreeListSizeOf; private int heapWordSize; // 4 for 32bit, 8 for 64 bits private int IndexSetStart; // for small indexed list @@ -109,11 +113,11 @@ // small chunks long size = 0; Address cur = addr.addOffsetTo( indexedFreeListField.getOffset() ); - cur = cur.addOffsetTo(IndexSetStart*FreeList.sizeOf()); + cur = cur.addOffsetTo(IndexSetStart*AdaptiveFreeList.sizeOf()); for (int i=IndexSetStart; i"); - sizeField = type.getCIntegerField("_size"); - countField = type.getCIntegerField("_count"); - headerSize = type.getSize(); - } - - // Fields - private static CIntegerField sizeField; - private static CIntegerField countField; - private static long headerSize; - - //Constructor - public FreeList(Address address) { - super(address); - } - - // Accessors - public long size() { - return sizeField.getValue(addr); - } - - public long count() { - return countField.getValue(addr); - } - - public static long sizeOf() { - return headerSize; - } -} diff -r c2687aa5e5ca -r 7eb99acd567f agent/src/share/classes/sun/jvm/hotspot/memory/Universe.java --- a/agent/src/share/classes/sun/jvm/hotspot/memory/Universe.java Mon Jan 25 14:56:57 2016 -0800 +++ b/agent/src/share/classes/sun/jvm/hotspot/memory/Universe.java Mon Jan 25 14:57:27 2016 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 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 @@ -56,6 +56,12 @@ private static AddressField narrowKlassBaseField; private static CIntegerField narrowKlassShiftField; + public enum NARROW_OOP_MODE { + UnscaledNarrowOop, + ZeroBasedNarrowOop, + HeapBasedNarrowOop + } + static { VM.registerVMInitializedObserver(new Observer() { public void update(Observable o, Object data) { @@ -94,7 +100,17 @@ public Universe() { } - + public static String narrowOopModeToString(NARROW_OOP_MODE mode) { + switch (mode) { + case UnscaledNarrowOop: + return "32-bits Oops"; + case ZeroBasedNarrowOop: + return "zero based Compressed Oops"; + case HeapBasedNarrowOop: + return "Compressed Oops with base"; + } + return ""; + } public CollectedHeap heap() { try { return (CollectedHeap) heapConstructor.instantiateWrapperFor(collectedHeapField.getValue()); diff -r c2687aa5e5ca -r 7eb99acd567f agent/src/share/classes/sun/jvm/hotspot/oops/Klass.java --- a/agent/src/share/classes/sun/jvm/hotspot/oops/Klass.java Mon Jan 25 14:56:57 2016 -0800 +++ b/agent/src/share/classes/sun/jvm/hotspot/oops/Klass.java Mon Jan 25 14:57:27 2016 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 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 @@ -55,6 +55,10 @@ layoutHelper = new IntField(type.getJIntField("_layout_helper"), 0); name = type.getAddressField("_name"); accessFlags = new CIntField(type.getCIntegerField("_access_flags"), 0); + try { + traceIDField = type.getField("_trace_id"); + } catch(Exception e) { + } subklass = new MetadataField(type.getAddressField("_subklass"), 0); nextSibling = new MetadataField(type.getAddressField("_next_sibling"), 0); @@ -86,6 +90,7 @@ private static CIntField accessFlags; private static MetadataField subklass; private static MetadataField nextSibling; + private static sun.jvm.hotspot.types.Field traceIDField; private Address getValue(AddressField field) { return addr.getAddressAt(field.getOffset()); @@ -107,6 +112,11 @@ public Klass getSubklassKlass() { return (Klass) subklass.getValue(this); } public Klass getNextSiblingKlass() { return (Klass) nextSibling.getValue(this); } + public long traceID() { + if (traceIDField == null) return 0; + return traceIDField.getJLong(addr); + } + // computed access flags - takes care of inner classes etc. // This is closer to actual source level than getAccessFlags() etc. public long computeModifierFlags() { diff -r c2687aa5e5ca -r 7eb99acd567f agent/src/share/classes/sun/jvm/hotspot/oops/OopUtilities.java --- a/agent/src/share/classes/sun/jvm/hotspot/oops/OopUtilities.java Mon Jan 25 14:56:57 2016 -0800 +++ b/agent/src/share/classes/sun/jvm/hotspot/oops/OopUtilities.java Mon Jan 25 14:57:27 2016 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 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 @@ -54,6 +54,8 @@ private static OopField threadNameField; private static OopField threadGroupField; private static LongField threadEETopField; + //tid field is new since 1.5 + private static LongField threadTIDField; // threadStatus field is new since 1.5 private static IntField threadStatusField; // parkBlocker field is new since 1.6 @@ -220,6 +222,7 @@ threadNameField = (OopField) k.findField("name", "[C"); threadGroupField = (OopField) k.findField("group", "Ljava/lang/ThreadGroup;"); threadEETopField = (LongField) k.findField("eetop", "J"); + threadTIDField = (LongField) k.findField("tid", "J"); threadStatusField = (IntField) k.findField("threadStatus", "I"); threadParkBlockerField = (OopField) k.findField("parkBlocker", "Ljava/lang/Object;"); @@ -268,6 +271,15 @@ return VM.getVM().getThreads().createJavaThreadWrapper(addr); } + public static long threadOopGetTID(Oop threadOop) { + initThreadFields(); + if (threadTIDField != null) { + return threadTIDField.getValue(threadOop); + } else { + return 0; + } + } + /** returns value of java.lang.Thread.threadStatus field */ public static int threadOopGetThreadStatus(Oop threadOop) { initThreadFields(); diff -r c2687aa5e5ca -r 7eb99acd567f agent/src/share/classes/sun/jvm/hotspot/opto/CompilerPhaseType.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/agent/src/share/classes/sun/jvm/hotspot/opto/CompilerPhaseType.java Mon Jan 25 14:57:27 2016 -0800 @@ -0,0 +1,67 @@ +/* + * Copyright (c) 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 + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +package sun.jvm.hotspot.opto; + +//These definitions should be kept in sync with the definitions in the HotSpot code. + +public enum CompilerPhaseType { + PHASE_BEFORE_STRINGOPTS ("Before StringOpts"), + PHASE_AFTER_STRINGOPTS ("After StringOpts"), + PHASE_BEFORE_REMOVEUSELESS ("Before RemoveUseless"), + PHASE_AFTER_PARSING ("After Parsing"), + PHASE_ITER_GVN1 ("Iter GVN 1"), + PHASE_PHASEIDEAL_BEFORE_EA ("PhaseIdealLoop before EA"), + PHASE_ITER_GVN_AFTER_EA ("Iter GVN after EA"), + PHASE_ITER_GVN_AFTER_ELIMINATION ("Iter GVN after eliminating allocations and locks"), + PHASE_PHASEIDEALLOOP1 ("PhaseIdealLoop 1"), + PHASE_PHASEIDEALLOOP2 ("PhaseIdealLoop 2"), + PHASE_PHASEIDEALLOOP3 ("PhaseIdealLoop 3"), + PHASE_CPP1 ("PhaseCPP 1"), + PHASE_ITER_GVN2 ("Iter GVN 2"), + PHASE_PHASEIDEALLOOP_ITERATIONS ("PhaseIdealLoop iterations"), + PHASE_OPTIMIZE_FINISHED ("Optimize finished"), + PHASE_GLOBAL_CODE_MOTION ("Global code motion"), + PHASE_FINAL_CODE ("Final Code"), + PHASE_AFTER_EA ("After Escape Analysis"), + PHASE_BEFORE_CLOOPS ("Before CountedLoop"), + PHASE_AFTER_CLOOPS ("After CountedLoop"), + PHASE_BEFORE_BEAUTIFY_LOOPS ("Before beautify loops"), + PHASE_AFTER_BEAUTIFY_LOOPS ("After beautify loops"), + PHASE_BEFORE_MATCHING ("Before Matching"), + PHASE_INCREMENTAL_INLINE ("Incremental Inline"), + PHASE_INCREMENTAL_BOXING_INLINE ("Incremental Boxing Inline"), + PHASE_END ("End"), + PHASE_FAILURE ("Failure"), + PHASE_NUM_TYPES ("Number of Phase Types"); + + private final String value; + + CompilerPhaseType(String val) { + this.value = val; + } + public String value() { + return value; + } +} diff -r c2687aa5e5ca -r 7eb99acd567f agent/src/share/classes/sun/jvm/hotspot/runtime/Flags.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/agent/src/share/classes/sun/jvm/hotspot/runtime/Flags.java Mon Jan 25 14:57:27 2016 -0800 @@ -0,0 +1,48 @@ +/* + * Copyright (c) 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 + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +package sun.jvm.hotspot.runtime; + +//These definitions should be kept in sync with the definitions in the HotSpot code. + +public enum Flags { + // value origin + DEFAULT ("Default"), + COMMAND_LINE ("Command line"), + ENVIRON_VAR ("Environment variable"), + CONFIG_FILE ("Config file"), + MANAGEMENT ("Management"), + ERGONOMIC ("Ergonomic"), + ATTACH_ON_DEMAND ("Attach on demand"), + INTERNAL ("Internal"); + + private final String value; + + Flags(String val) { + this.value = val; + } + public String value() { + return value; + } +} diff -r c2687aa5e5ca -r 7eb99acd567f agent/src/share/classes/sun/jvm/hotspot/runtime/Thread.java --- a/agent/src/share/classes/sun/jvm/hotspot/runtime/Thread.java Mon Jan 25 14:56:57 2016 -0800 +++ b/agent/src/share/classes/sun/jvm/hotspot/runtime/Thread.java Mon Jan 25 14:57:27 2016 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2011, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 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 @@ -41,6 +41,8 @@ private static AddressField currentPendingMonitorField; private static AddressField currentWaitingMonitorField; + private static JLongField allocatedBytesField; + static { VM.registerVMInitializedObserver(new Observer() { public void update(Observable o, Object data) { @@ -61,6 +63,7 @@ activeHandlesField = type.getAddressField("_active_handles"); currentPendingMonitorField = type.getAddressField("_current_pending_monitor"); currentWaitingMonitorField = type.getAddressField("_current_waiting_monitor"); + allocatedBytesField = type.getJLongField("_allocated_bytes"); } public Thread(Address addr) { @@ -104,6 +107,10 @@ return new JNIHandleBlock(a); } + public long allocatedBytes() { + return allocatedBytesField.getValue(addr); + } + public boolean isVMThread() { return false; } public boolean isJavaThread() { return false; } public boolean isCompilerThread() { return false; } diff -r c2687aa5e5ca -r 7eb99acd567f agent/src/share/classes/sun/jvm/hotspot/runtime/VMOps.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/agent/src/share/classes/sun/jvm/hotspot/runtime/VMOps.java Mon Jan 25 14:57:27 2016 -0800 @@ -0,0 +1,86 @@ +/* + * Copyright (c) 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 + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +package sun.jvm.hotspot.runtime; + +//These definitions should be kept in sync with the definitions in the HotSpot code. + +public enum VMOps { + Dummy, + ThreadStop, + ThreadDump, + PrintThreads, + FindDeadlocks, + ForceSafepoint, + ForceAsyncSafepoint, + Deoptimize, + DeoptimizeFrame, + DeoptimizeAll, + ZombieAll, + UnlinkSymbols, + Verify, + PrintJNI, + HeapDumper, + DeoptimizeTheWorld, + CollectForMetadataAllocation, + GC_HeapInspection, + GenCollectFull, + GenCollectFullConcurrent, + GenCollectForAllocation, + ParallelGCFailedAllocation, + ParallelGCSystemGC, + CGC_Operation, + CMS_Initial_Mark, + CMS_Final_Remark, + G1CollectFull, + G1CollectForAllocation, + G1IncCollectionPause, + EnableBiasedLocking, + RevokeBias, + BulkRevokeBias, + PopulateDumpSharedSpace, + JNIFunctionTableCopier, + RedefineClasses, + GetOwnedMonitorInfo, + GetObjectMonitorUsage, + GetCurrentContendedMonitor, + GetStackTrace, + GetMultipleStackTraces, + GetAllStackTraces, + GetThreadListStackTraces, + GetFrameCount, + GetFrameLocation, + ChangeBreakpoints, + GetOrSetLocal, + GetCurrentLocation, + EnterInterpOnlyMode, + ChangeSingleStep, + HeapWalkOperation, + HeapIterateOperation, + ReportJavaOutOfMemory, + JFRCheckpoint, + Exit, + LinuxDllLoad, + Terminating +} diff -r c2687aa5e5ca -r 7eb99acd567f agent/src/share/classes/sun/jvm/hotspot/runtime/x86/X86Frame.java --- a/agent/src/share/classes/sun/jvm/hotspot/runtime/x86/X86Frame.java Mon Jan 25 14:56:57 2016 -0800 +++ b/agent/src/share/classes/sun/jvm/hotspot/runtime/x86/X86Frame.java Mon Jan 25 14:57:27 2016 -0800 @@ -317,26 +317,17 @@ //------------------------------------------------------------------------------ // frame::adjust_unextended_sp private void adjustUnextendedSP() { - // If we are returning to a compiled MethodHandle call site, the - // saved_fp will in fact be a saved value of the unextended SP. The - // simplest way to tell whether we are returning to such a call site - // is as follows: + // On x86, sites calling method handle intrinsics and lambda forms are treated + // as any other call site. Therefore, no special action is needed when we are + // returning to any of these call sites. CodeBlob cb = cb(); NMethod senderNm = (cb == null) ? null : cb.asNMethodOrNull(); if (senderNm != null) { - // If the sender PC is a deoptimization point, get the original - // PC. For MethodHandle call site the unextended_sp is stored in - // saved_fp. - if (senderNm.isDeoptMhEntry(getPC())) { - // DEBUG_ONLY(verifyDeoptMhOriginalPc(senderNm, getFP())); - raw_unextendedSP = getFP(); - } - else if (senderNm.isDeoptEntry(getPC())) { - // DEBUG_ONLY(verifyDeoptOriginalPc(senderNm, raw_unextendedSp)); - } - else if (senderNm.isMethodHandleReturn(getPC())) { - raw_unextendedSP = getFP(); + // If the sender PC is a deoptimization point, get the original PC. + if (senderNm.isDeoptEntry(getPC()) || + senderNm.isDeoptMhEntry(getPC())) { + // DEBUG_ONLY(verifyDeoptriginalPc(senderNm, raw_unextendedSp)); } } } diff -r c2687aa5e5ca -r 7eb99acd567f agent/src/share/classes/sun/jvm/hotspot/ui/action/HSDBActionManager.java --- a/agent/src/share/classes/sun/jvm/hotspot/ui/action/HSDBActionManager.java Mon Jan 25 14:56:57 2016 -0800 +++ b/agent/src/share/classes/sun/jvm/hotspot/ui/action/HSDBActionManager.java Mon Jan 25 14:57:27 2016 -0800 @@ -32,10 +32,12 @@ public class HSDBActionManager extends ActionManager { public static ActionManager getInstance() { - if (manager == null) { - manager = new HSDBActionManager(); + ActionManager m = ActionManager.getInstance(); + if (m == null) { + m = new HSDBActionManager(); + ActionManager.setInstance(m); } - return manager; + return m; } protected void addActions() { diff -r c2687aa5e5ca -r 7eb99acd567f agent/src/share/classes/sun/jvm/hotspot/utilities/HeapHprofBinWriter.java --- a/agent/src/share/classes/sun/jvm/hotspot/utilities/HeapHprofBinWriter.java Mon Jan 25 14:56:57 2016 -0800 +++ b/agent/src/share/classes/sun/jvm/hotspot/utilities/HeapHprofBinWriter.java Mon Jan 25 14:57:27 2016 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2004, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2004, 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 @@ -799,6 +799,18 @@ writeObjectID(klass.getJavaMirror()); ClassData cd = (ClassData) classDataCache.get(klass); + if (cd == null) { + // The class is not present in the system dictionary, probably Lambda. + // Add it to cache here + if (klass instanceof InstanceKlass) { + InstanceKlass ik = (InstanceKlass) klass; + List fields = getInstanceFields(ik); + int instSize = getSizeForFields(fields); + cd = new ClassData(instSize, fields); + classDataCache.put(ik, cd); + } + } + if (Assert.ASSERTS_ENABLED) { Assert.that(cd != null, "can not get class data for " + klass.getName().asString() + klass.getAddress()); } diff -r c2687aa5e5ca -r 7eb99acd567f jvmci/jdk.vm.ci.aarch64/src/jdk/vm/ci/aarch64/AArch64.java --- a/jvmci/jdk.vm.ci.aarch64/src/jdk/vm/ci/aarch64/AArch64.java Mon Jan 25 14:56:57 2016 -0800 +++ b/jvmci/jdk.vm.ci.aarch64/src/jdk/vm/ci/aarch64/AArch64.java Mon Jan 25 14:57:27 2016 -0800 @@ -70,56 +70,64 @@ public static final Register r28 = new Register(28, 28, "r28", CPU); public static final Register r29 = new Register(29, 29, "r29", CPU); public static final Register r30 = new Register(30, 30, "r30", CPU); + + /* + * r31 is not a general purpose register, but represents either the stackpointer or the + * zero/discard register depending on the instruction. So we represent those two uses as two + * different registers. The register numbers are kept in sync with register_aarch64.hpp and have + * to be sequential, hence we also need a general r31 register here, which is never used. + */ public static final Register r31 = new Register(31, 31, "r31", CPU); + public static final Register zr = new Register(32, 31, "zr", CPU); + public static final Register sp = new Register(33, 31, "sp", CPU); public static final Register lr = r30; - public static final Register zr = r31; - public static final Register sp = r31; // @formatter:off public static final Register[] cpuRegisters = { r0, r1, r2, r3, r4, r5, r6, r7, r8, r9, r10, r11, r12, r13, r14, r15, r16, r17, r18, r19, r20, r21, r22, r23, - r24, r25, r26, r27, r28, r29, r30, r31 + r24, r25, r26, r27, r28, r29, r30, r31, + zr, sp }; // @formatter:on public static final RegisterCategory SIMD = new RegisterCategory("SIMD"); // Simd registers - public static final Register v0 = new Register(32, 0, "v0", SIMD); - public static final Register v1 = new Register(33, 1, "v1", SIMD); - public static final Register v2 = new Register(34, 2, "v2", SIMD); - public static final Register v3 = new Register(35, 3, "v3", SIMD); - public static final Register v4 = new Register(36, 4, "v4", SIMD); - public static final Register v5 = new Register(37, 5, "v5", SIMD); - public static final Register v6 = new Register(38, 6, "v6", SIMD); - public static final Register v7 = new Register(39, 7, "v7", SIMD); - public static final Register v8 = new Register(40, 8, "v8", SIMD); - public static final Register v9 = new Register(41, 9, "v9", SIMD); - public static final Register v10 = new Register(42, 10, "v10", SIMD); - public static final Register v11 = new Register(43, 11, "v11", SIMD); - public static final Register v12 = new Register(44, 12, "v12", SIMD); - public static final Register v13 = new Register(45, 13, "v13", SIMD); - public static final Register v14 = new Register(46, 14, "v14", SIMD); - public static final Register v15 = new Register(47, 15, "v15", SIMD); - public static final Register v16 = new Register(48, 16, "v16", SIMD); - public static final Register v17 = new Register(49, 17, "v17", SIMD); - public static final Register v18 = new Register(50, 18, "v18", SIMD); - public static final Register v19 = new Register(51, 19, "v19", SIMD); - public static final Register v20 = new Register(52, 20, "v20", SIMD); - public static final Register v21 = new Register(53, 21, "v21", SIMD); - public static final Register v22 = new Register(54, 22, "v22", SIMD); - public static final Register v23 = new Register(55, 23, "v23", SIMD); - public static final Register v24 = new Register(56, 24, "v24", SIMD); - public static final Register v25 = new Register(57, 25, "v25", SIMD); - public static final Register v26 = new Register(58, 26, "v26", SIMD); - public static final Register v27 = new Register(59, 27, "v27", SIMD); - public static final Register v28 = new Register(60, 28, "v28", SIMD); - public static final Register v29 = new Register(61, 29, "v29", SIMD); - public static final Register v30 = new Register(62, 30, "v30", SIMD); - public static final Register v31 = new Register(63, 31, "v31", SIMD); + public static final Register v0 = new Register(34, 0, "v0", SIMD); + public static final Register v1 = new Register(35, 1, "v1", SIMD); + public static final Register v2 = new Register(36, 2, "v2", SIMD); + public static final Register v3 = new Register(37, 3, "v3", SIMD); + public static final Register v4 = new Register(38, 4, "v4", SIMD); + public static final Register v5 = new Register(39, 5, "v5", SIMD); + public static final Register v6 = new Register(40, 6, "v6", SIMD); + public static final Register v7 = new Register(41, 7, "v7", SIMD); + public static final Register v8 = new Register(42, 8, "v8", SIMD); + public static final Register v9 = new Register(43, 9, "v9", SIMD); + public static final Register v10 = new Register(44, 10, "v10", SIMD); + public static final Register v11 = new Register(45, 11, "v11", SIMD); + public static final Register v12 = new Register(46, 12, "v12", SIMD); + public static final Register v13 = new Register(47, 13, "v13", SIMD); + public static final Register v14 = new Register(48, 14, "v14", SIMD); + public static final Register v15 = new Register(49, 15, "v15", SIMD); + public static final Register v16 = new Register(50, 16, "v16", SIMD); + public static final Register v17 = new Register(51, 17, "v17", SIMD); + public static final Register v18 = new Register(52, 18, "v18", SIMD); + public static final Register v19 = new Register(53, 19, "v19", SIMD); + public static final Register v20 = new Register(54, 20, "v20", SIMD); + public static final Register v21 = new Register(55, 21, "v21", SIMD); + public static final Register v22 = new Register(56, 22, "v22", SIMD); + public static final Register v23 = new Register(57, 23, "v23", SIMD); + public static final Register v24 = new Register(58, 24, "v24", SIMD); + public static final Register v25 = new Register(59, 25, "v25", SIMD); + public static final Register v26 = new Register(60, 26, "v26", SIMD); + public static final Register v27 = new Register(61, 27, "v27", SIMD); + public static final Register v28 = new Register(62, 28, "v28", SIMD); + public static final Register v29 = new Register(63, 29, "v29", SIMD); + public static final Register v30 = new Register(64, 30, "v30", SIMD); + public static final Register v31 = new Register(65, 31, "v31", SIMD); // @formatter:off public static final Register[] simdRegisters = { @@ -136,6 +144,7 @@ r8, r9, r10, r11, r12, r13, r14, r15, r16, r17, r18, r19, r20, r21, r22, r23, r24, r25, r26, r27, r28, r29, r30, r31, + zr, sp, v0, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, diff -r c2687aa5e5ca -r 7eb99acd567f jvmci/jdk.vm.ci.hotspot.aarch64/src/jdk/vm/ci/hotspot/aarch64/AArch64HotSpotRegisterConfig.java --- a/jvmci/jdk.vm.ci.hotspot.aarch64/src/jdk/vm/ci/hotspot/aarch64/AArch64HotSpotRegisterConfig.java Mon Jan 25 14:56:57 2016 -0800 +++ b/jvmci/jdk.vm.ci.hotspot.aarch64/src/jdk/vm/ci/hotspot/aarch64/AArch64HotSpotRegisterConfig.java Mon Jan 25 14:57:27 2016 -0800 @@ -31,6 +31,7 @@ import static jdk.vm.ci.aarch64.AArch64.r28; import static jdk.vm.ci.aarch64.AArch64.r29; import static jdk.vm.ci.aarch64.AArch64.r3; +import static jdk.vm.ci.aarch64.AArch64.r31; import static jdk.vm.ci.aarch64.AArch64.r4; import static jdk.vm.ci.aarch64.AArch64.r5; import static jdk.vm.ci.aarch64.AArch64.r6; @@ -45,11 +46,13 @@ import static jdk.vm.ci.aarch64.AArch64.v5; import static jdk.vm.ci.aarch64.AArch64.v6; import static jdk.vm.ci.aarch64.AArch64.v7; +import static jdk.vm.ci.aarch64.AArch64.zr; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.HashSet; +import java.util.List; import java.util.Set; import jdk.vm.ci.aarch64.AArch64; @@ -97,6 +100,7 @@ return allocatable.clone(); } + @Override public Register[] filterAllocatableRegisters(PlatformKind kind, Register[] registers) { ArrayList list = new ArrayList<>(); for (Register reg : registers) { @@ -129,16 +133,20 @@ public static final Register threadRegister = r28; public static final Register fp = r29; + private static final Register[] reservedRegisters = {threadRegister, fp, lr, r31, zr, sp}; + private static Register[] initAllocatable(Architecture arch, boolean reserveForHeapBase) { Register[] allRegisters = arch.getAvailableValueRegisters(); - Register[] registers = new Register[allRegisters.length - (reserveForHeapBase ? 5 : 4)]; + Register[] registers = new Register[allRegisters.length - reservedRegisters.length - (reserveForHeapBase ? 1 : 0)]; + List reservedRegistersList = Arrays.asList(reservedRegisters); int idx = 0; for (Register reg : allRegisters) { - if (reg.equals(threadRegister) || reg.equals(fp) || reg.equals(lr) || reg.equals(sp)) { - // skip thread register, frame pointer, link register and stack pointer + if (reservedRegistersList.contains(reg)) { + // skip reserved registers continue; } + assert !(reg.equals(threadRegister) || reg.equals(fp) || reg.equals(lr) || reg.equals(r31) || reg.equals(zr) || reg.equals(sp)); if (reserveForHeapBase && reg.equals(heapBaseRegister)) { // skip heap base register continue; @@ -193,15 +201,18 @@ @Override public CallingConvention getCallingConvention(Type type, JavaType returnType, JavaType[] parameterTypes, TargetDescription target) { + HotSpotCallingConventionType hotspotType = (HotSpotCallingConventionType) type; if (type == HotSpotCallingConventionType.NativeCall) { - return callingConvention(nativeGeneralParameterRegisters, returnType, parameterTypes, (HotSpotCallingConventionType) type, target); + return callingConvention(nativeGeneralParameterRegisters, returnType, parameterTypes, hotspotType, target); } // On x64, parameter locations are the same whether viewed // from the caller or callee perspective - return callingConvention(javaGeneralParameterRegisters, returnType, parameterTypes, (HotSpotCallingConventionType) type, target); + return callingConvention(javaGeneralParameterRegisters, returnType, parameterTypes, hotspotType, target); } + @Override public Register[] getCallingConventionRegisters(Type type, JavaKind kind) { + HotSpotCallingConventionType hotspotType = (HotSpotCallingConventionType) type; switch (kind) { case Boolean: case Byte: @@ -210,7 +221,7 @@ case Int: case Long: case Object: - return type == HotSpotCallingConventionType.NativeCall ? nativeGeneralParameterRegisters : javaGeneralParameterRegisters; + return hotspotType == HotSpotCallingConventionType.NativeCall ? nativeGeneralParameterRegisters : javaGeneralParameterRegisters; case Float: case Double: return simdParameterRegisters; diff -r c2687aa5e5ca -r 7eb99acd567f jvmci/jdk.vm.ci.hotspot.amd64/src/jdk/vm/ci/hotspot/amd64/AMD64HotSpotRegisterConfig.java --- a/jvmci/jdk.vm.ci.hotspot.amd64/src/jdk/vm/ci/hotspot/amd64/AMD64HotSpotRegisterConfig.java Mon Jan 25 14:56:57 2016 -0800 +++ b/jvmci/jdk.vm.ci.hotspot.amd64/src/jdk/vm/ci/hotspot/amd64/AMD64HotSpotRegisterConfig.java Mon Jan 25 14:57:27 2016 -0800 @@ -45,6 +45,7 @@ import java.util.Arrays; import java.util.Collections; import java.util.HashSet; +import java.util.List; import java.util.Set; import jdk.vm.ci.code.Architecture; @@ -91,6 +92,7 @@ return allocatable.clone(); } + @Override public Register[] filterAllocatableRegisters(PlatformKind kind, Register[] registers) { ArrayList list = new ArrayList<>(); for (Register reg : registers) { @@ -118,14 +120,17 @@ */ private final boolean needsNativeStackHomeSpace; + private static final Register[] reservedRegisters = {rsp, r15}; + private static Register[] initAllocatable(Architecture arch, boolean reserveForHeapBase) { Register[] allRegisters = arch.getAvailableValueRegisters(); - Register[] registers = new Register[allRegisters.length - (reserveForHeapBase ? 3 : 2)]; + Register[] registers = new Register[allRegisters.length - reservedRegisters.length - (reserveForHeapBase ? 1 : 0)]; + List reservedRegistersList = Arrays.asList(reservedRegisters); int idx = 0; for (Register reg : allRegisters) { - if (reg.equals(rsp) || reg.equals(r15)) { - // skip stack pointer and thread register + if (reservedRegistersList.contains(reg)) { + // skip reserved registers continue; } if (reserveForHeapBase && reg.equals(r12)) { @@ -176,6 +181,7 @@ return callerSaved; } + @Override public Register[] getCalleeSaveRegisters() { return null; } @@ -192,15 +198,18 @@ @Override public CallingConvention getCallingConvention(Type type, JavaType returnType, JavaType[] parameterTypes, TargetDescription target) { + HotSpotCallingConventionType hotspotType = (HotSpotCallingConventionType) type; if (type == HotSpotCallingConventionType.NativeCall) { - return callingConvention(nativeGeneralParameterRegisters, returnType, parameterTypes, (HotSpotCallingConventionType) type, target); + return callingConvention(nativeGeneralParameterRegisters, returnType, parameterTypes, hotspotType, target); } // On x64, parameter locations are the same whether viewed // from the caller or callee perspective - return callingConvention(javaGeneralParameterRegisters, returnType, parameterTypes, (HotSpotCallingConventionType) type, target); + return callingConvention(javaGeneralParameterRegisters, returnType, parameterTypes, hotspotType, target); } + @Override public Register[] getCallingConventionRegisters(Type type, JavaKind kind) { + HotSpotCallingConventionType hotspotType = (HotSpotCallingConventionType) type; switch (kind) { case Boolean: case Byte: @@ -209,7 +218,7 @@ case Int: case Long: case Object: - return type == HotSpotCallingConventionType.NativeCall ? nativeGeneralParameterRegisters : javaGeneralParameterRegisters; + return hotspotType == HotSpotCallingConventionType.NativeCall ? nativeGeneralParameterRegisters : javaGeneralParameterRegisters; case Float: case Double: return xmmParameterRegisters; diff -r c2687aa5e5ca -r 7eb99acd567f jvmci/jdk.vm.ci.hotspot.sparc/src/jdk/vm/ci/hotspot/sparc/SPARCHotSpotRegisterConfig.java --- a/jvmci/jdk.vm.ci.hotspot.sparc/src/jdk/vm/ci/hotspot/sparc/SPARCHotSpotRegisterConfig.java Mon Jan 25 14:56:57 2016 -0800 +++ b/jvmci/jdk.vm.ci.hotspot.sparc/src/jdk/vm/ci/hotspot/sparc/SPARCHotSpotRegisterConfig.java Mon Jan 25 14:57:27 2016 -0800 @@ -68,6 +68,7 @@ import java.util.Arrays; import java.util.Collections; import java.util.HashSet; +import java.util.List; import jdk.vm.ci.code.Architecture; import jdk.vm.ci.code.CallingConvention; @@ -105,6 +106,7 @@ return allocatable.clone(); } + @Override public Register[] filterAllocatableRegisters(PlatformKind kind, Register[] registers) { ArrayList list = new ArrayList<>(); for (Register reg : registers) { @@ -139,14 +141,17 @@ i0, i1, i2, i3, i4, i5, i6, i7}; // @formatter:on + private static final Register[] reservedRegisters = {sp, g0, g2}; + private static Register[] initAllocatable(Architecture arch, boolean reserveForHeapBase) { Register[] allRegisters = arch.getAvailableValueRegisters(); - Register[] registers = new Register[allRegisters.length - (reserveForHeapBase ? 4 : 3)]; + Register[] registers = new Register[allRegisters.length - reservedRegisters.length - (reserveForHeapBase ? 1 : 0)]; + List reservedRegistersList = Arrays.asList(reservedRegisters); int idx = 0; for (Register reg : allRegisters) { - if (reg.equals(sp) || reg.equals(g2) || reg.equals(g0)) { - // skip g0, stack pointer and thread register + if (reservedRegistersList.contains(reg)) { + // skip reserved registers continue; } if (reserveForHeapBase && reg.equals(g6)) { @@ -199,16 +204,19 @@ @Override public CallingConvention getCallingConvention(Type type, JavaType returnType, JavaType[] parameterTypes, TargetDescription target) { + HotSpotCallingConventionType hotspotType = (HotSpotCallingConventionType) type; if (type == HotSpotCallingConventionType.JavaCall || type == HotSpotCallingConventionType.NativeCall) { - return callingConvention(cpuCallerParameterRegisters, returnType, parameterTypes, (HotSpotCallingConventionType) type, target); + return callingConvention(cpuCallerParameterRegisters, returnType, parameterTypes, hotspotType, target); } if (type == HotSpotCallingConventionType.JavaCallee) { - return callingConvention(cpuCalleeParameterRegisters, returnType, parameterTypes, (HotSpotCallingConventionType) type, target); + return callingConvention(cpuCalleeParameterRegisters, returnType, parameterTypes, hotspotType, target); } throw JVMCIError.shouldNotReachHere(); } + @Override public Register[] getCallingConventionRegisters(Type type, JavaKind kind) { + HotSpotCallingConventionType hotspotType = (HotSpotCallingConventionType) type; switch (kind) { case Boolean: case Byte: @@ -217,7 +225,7 @@ case Int: case Long: case Object: - return type == HotSpotCallingConventionType.JavaCallee ? cpuCalleeParameterRegisters : cpuCallerParameterRegisters; + return hotspotType == HotSpotCallingConventionType.JavaCallee ? cpuCalleeParameterRegisters : cpuCallerParameterRegisters; case Double: case Float: return fpuFloatParameterRegisters; @@ -303,7 +311,7 @@ return getReturnRegister(kind, HotSpotCallingConventionType.JavaCallee); } - private static Register getReturnRegister(JavaKind kind, Type type) { + private static Register getReturnRegister(JavaKind kind, HotSpotCallingConventionType type) { switch (kind) { case Boolean: case Byte: diff -r c2687aa5e5ca -r 7eb99acd567f make/aix/makefiles/adlc.make --- a/make/aix/makefiles/adlc.make Mon Jan 25 14:56:57 2016 -0800 +++ b/make/aix/makefiles/adlc.make Mon Jan 25 14:57:27 2016 -0800 @@ -1,5 +1,5 @@ # -# Copyright (c) 1999, 2013, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 1999, 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 @@ -140,13 +140,7 @@ # Note "+="; it is a hook so flags.make can add more flags, like -g or -DFOO. ADLCFLAGS += -q -T -# Normally, debugging is done directly on the ad_*.cpp files. -# But -g will put #line directives in those files pointing back to .ad. -# Some builds of gcc 3.2 have a bug that gets tickled by the extra #line directives -# so skip it for 3.2 and ealier. -ifneq "$(shell expr \( $(CC_VER_MAJOR) \> 3 \) \| \( \( $(CC_VER_MAJOR) = 3 \) \& \( $(CC_VER_MINOR) \>= 3 \) \))" "0" ADLCFLAGS += -g -endif ifdef LP64 ADLCFLAGS += -D_LP64 diff -r c2687aa5e5ca -r 7eb99acd567f make/aix/makefiles/ppc64.make --- a/make/aix/makefiles/ppc64.make Mon Jan 25 14:56:57 2016 -0800 +++ b/make/aix/makefiles/ppc64.make Mon Jan 25 14:57:27 2016 -0800 @@ -1,6 +1,6 @@ # -# Copyright (c) 2004, 2013, Oracle and/or its affiliates. All rights reserved. -# Copyright 2012, 2013 SAP AG. All rights reserved. +# Copyright (c) 2004, 2015, Oracle and/or its affiliates. All rights reserved. +# Copyright 2012, 2015 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 @@ -46,7 +46,9 @@ # - 1540-1090 (I) The destructor of "..." might not be called. # - 1500-010: (W) WARNING in ...: Infinite loop. Program may not stop. # There are several infinite loops in the vm, suppress. -CFLAGS += -qsuppress=1540-1090 -qsuppress=1500-010 +# - 1540-1639 (I) The behavior of long type bit fields has changed ... +# ... long type bit fields now default to long, not int. +CFLAGS += -qsuppress=1540-1090 -qsuppress=1500-010 -qsuppress=1540-1639 # Suppress # - 540-1088 (W) The exception specification is being ignored. @@ -69,9 +71,6 @@ OPT_CFLAGS/sharedRuntimeTrig.o = $(OPT_CFLAGS/NOOPT) OPT_CFLAGS/sharedRuntimeTrans.o = $(OPT_CFLAGS/NOOPT) -# xlc 10.01 parameters for ipa compile. -QIPA_COMPILE=$(if $(CXX_IS_V10),-qipa) - # Xlc 10.1 parameters for aggressive optimization: # - qhot=level=1: Most aggressive loop optimizations. # - qignerrno: Assume errno is not modified by system calls. @@ -86,7 +85,7 @@ OPT_CFLAGS/synchronizer.o = $(OPT_CFLAGS) -qnoinline # Set all the xlC V10.1 options here. -OPT_CFLAGS += $(QIPA_COMPILE) $(QV10_OPT) $(QV10_OPT_AGGRESSIVE) +OPT_CFLAGS += $(QV10_OPT) $(QV10_OPT_AGGRESSIVE) export OBJECT_MODE=64 diff -r c2687aa5e5ca -r 7eb99acd567f make/aix/makefiles/xlc.make --- a/make/aix/makefiles/xlc.make Mon Jan 25 14:56:57 2016 -0800 +++ b/make/aix/makefiles/xlc.make Mon Jan 25 14:57:27 2016 -0800 @@ -1,6 +1,6 @@ # -# Copyright (c) 1999, 2013, Oracle and/or its affiliates. All rights reserved. -# Copyright (c) 2012, 2013 SAP. All rights reserved. +# Copyright (c) 1999, 2015, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2012, 2015 SAP. All rights reserved. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. # # This code is free software; you can redistribute it and/or modify it @@ -34,13 +34,17 @@ AS = $(CC) -c -# get xlc version -CXX_VERSION := $(shell $(CXX) -qversion 2>&1 | sed -n 's/.*Version: \([0-9.]*\)/\1/p') +# get xlc version which comes as VV.RR.MMMM.LLLL where 'VV' is the version, +# 'RR' is the release, 'MMMM' is the modification and 'LLLL' is the level. +# We only use 'VV.RR.LLLL' to avoid integer overflows in bash when comparing +# the version numbers (some shells only support 32-bit integer compares!). +CXX_VERSION := $(shell $(CXX) -qversion 2>&1 | \ + sed -n 's/.*Version: \([0-9]\{2\}\).\([0-9]\{2\}\).[0-9]\{4\}.\([0-9]\{4\}\)/\1\2\3/p') # xlc 08.00.0000.0023 and higher supports -qtune=balanced -CXX_SUPPORTS_BALANCED_TUNING=$(shell if [ $(subst .,,$(CXX_VERSION)) -ge 080000000023 ] ; then echo "true" ; fi) +CXX_SUPPORTS_BALANCED_TUNING := $(shell if [ $(CXX_VERSION) -ge 08000023 ] ; then echo "true" ; fi) # xlc 10.01 is used with aggressive optimizations to boost performance -CXX_IS_V10=$(shell if [ $(subst .,,$(CXX_VERSION)) -ge 100100000000 ] ; then echo "true" ; fi) +CXX_IS_V10 := $(shell if [ $(CXX_VERSION) -ge 10010000 ] ; then echo "true" ; fi) # check for precompiled headers support @@ -130,7 +134,7 @@ # MAPFLAG = -Xlinker --version-script=FILENAME # Build shared library -SHARED_FLAG = -q64 -b64 -bexpall -G -bnoentry -qmkshrobj -brtl -bnolibpath +SHARED_FLAG = -q64 -b64 -bexpall -G -bnoentry -qmkshrobj -brtl -bnolibpath -bernotok #------------------------------------------------------------------------ # Debug flags diff -r c2687aa5e5ca -r 7eb99acd567f make/bsd/makefiles/gcc.make --- a/make/bsd/makefiles/gcc.make Mon Jan 25 14:56:57 2016 -0800 +++ b/make/bsd/makefiles/gcc.make Mon Jan 25 14:57:27 2016 -0800 @@ -369,7 +369,7 @@ # The macro takes the version with no dots, ex: 1070 CFLAGS += -DMAC_OS_X_VERSION_MAX_ALLOWED=$(subst .,,$(MACOSX_VERSION_MIN)) \ -mmacosx-version-min=$(MACOSX_VERSION_MIN) - LDFLAGS += -mmacosx-version-min=$(MACOSX_VERSION_MIN) + LFLAGS += -mmacosx-version-min=$(MACOSX_VERSION_MIN) endif diff -r c2687aa5e5ca -r 7eb99acd567f make/bsd/makefiles/sa.make --- a/make/bsd/makefiles/sa.make Mon Jan 25 14:56:57 2016 -0800 +++ b/make/bsd/makefiles/sa.make Mon Jan 25 14:57:27 2016 -0800 @@ -1,5 +1,5 @@ # -# Copyright (c) 2003, 2012, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2003, 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 @@ -34,6 +34,8 @@ include $(GAMMADIR)/make/sa.files +-include $(HS_ALT_MAKE)/bsd/makefiles/sa.make + TOPDIR = $(shell echo `pwd`) GENERATED = $(TOPDIR)/../generated diff -r c2687aa5e5ca -r 7eb99acd567f make/bsd/makefiles/saproc.make --- a/make/bsd/makefiles/saproc.make Mon Jan 25 14:56:57 2016 -0800 +++ b/make/bsd/makefiles/saproc.make Mon Jan 25 14:57:27 2016 -0800 @@ -1,5 +1,5 @@ # -# Copyright (c) 2005, 2014, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2005, 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 @@ -19,7 +19,7 @@ # 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 serviceability agent library, used by vm.make @@ -72,21 +72,20 @@ #objc compiler blows up on -march=i586, perhaps it should not be included in the macosx intel 32-bit C++ compiles? SAARCH = $(subst -march=i586,,$(ARCHFLAG)) + ifeq ($(SDKPATH),) + SDKPATH = $(shell xcrun --show-sdk-path) + endif # This is needed to locate JavaNativeFoundation.framework - ifeq ($(SYSROOT_CFLAGS),) - # this will happen when building without spec.gmk, set SDKROOT to a valid SDK - # path if your system does not have headers installed in the system frameworks - ifeq ($(SDKROOT),) - SDKROOT = `xcodebuild -sdk macosx -version|grep '^Path: '|sed 's/Path: //'` - endif - SA_SYSROOT_FLAGS = -F"$(SDKROOT)/System/Library/Frameworks/JavaVM.framework/Frameworks" - else - # Just use SYSROOT_CFLAGS - SA_SYSROOT_FLAGS=$(SYSROOT_CFLAGS) + # JDK 8 doesn't have SYSROOT_CFLAGS, so we'll cobble it together here + SA_SYSROOT_FLAGS= + ifneq ($(SDKPATH),) + SA_SYSROOT_FLAGS += -isysroot "$(SDKPATH)" -iframework"$(SDKPATH)/System/Library/Frameworks" endif + # always needed, even if SDKPATH is empty + SA_SYSROOT_FLAGS += -F"$(SDKPATH)/System/Library/Frameworks/JavaVM.framework/Frameworks" else SASRCFILES = $(SASRCDIR)/StubDebuggerLocal.c - SALIBS = + SALIBS = SAARCH = $(ARCHFLAG) endif endif @@ -114,6 +113,9 @@ ifneq ($(OS_VENDOR), Darwin) SA_LFLAGS = $(MAPFLAG:FILENAME=$(SAMAPFILE)) +else +# bring in minimum version argument or we'll fail on OSX 10.10 +SA_LFLAGS = $(LFLAGS) endif SA_LFLAGS += $(LDFLAGS_HASH_STYLE) @@ -125,7 +127,7 @@ echo "ALT_BOOTDIR, BOOTDIR or JAVA_HOME needs to be defined to build SA"; \ exit 1; \ fi - @echo $(LOG_INFO) Making SA debugger back-end... + @echo Making SA debugger back-end... $(QUIETLY) $(CC) -D$(BUILDARCH) -D_GNU_SOURCE \ $(SA_SYSROOT_FLAGS) \ $(SYMFLAG) $(SAARCH) $(SHARED_FLAG) $(PICFLAG) \ diff -r c2687aa5e5ca -r 7eb99acd567f make/defs.make --- a/make/defs.make Mon Jan 25 14:56:57 2016 -0800 +++ b/make/defs.make Mon Jan 25 14:57:27 2016 -0800 @@ -1,5 +1,5 @@ # -# Copyright (c) 2006, 2013, 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 @@ -121,6 +121,18 @@ # hotspot version definitions include $(GAMMADIR)/make/hotspot_version +# When config parameter --with-update-version is defined, +# Hotspot minor version should be set to that +ifneq ($(JDK_UPDATE_VERSION),) + HS_MINOR_VER=$(JDK_UPDATE_VERSION) +endif + +# When config parameter --with-build-number is defined, +# Hotspot build number should be set to that +ifneq ($(JDK_BUILD_NUMBER),) + HS_BUILD_NUMBER=$(subst b,,$(JDK_BUILD_NUMBER)) +endif + # Java versions needed ifeq ($(PREVIOUS_JDK_VERSION),) PREVIOUS_JDK_VERSION=$(JDK_PREVIOUS_VERSION) @@ -278,7 +290,7 @@ # Use uname output for SRCARCH, but deal with platform differences. If ARCH # is not explicitly listed below, it is treated as x86. - SRCARCH = $(ARCH/$(filter sparc sparc64 ia64 amd64 x86_64 arm ppc ppc64 zero,$(ARCH))) + SRCARCH ?= $(ARCH/$(filter sparc sparc64 ia64 amd64 x86_64 ppc64 zero,$(ARCH))) ARCH/ = x86 ARCH/sparc = sparc ARCH/sparc64= sparc @@ -286,12 +298,10 @@ ARCH/amd64 = x86 ARCH/x86_64 = x86 ARCH/ppc64 = ppc - ARCH/ppc = ppc - ARCH/arm = arm ARCH/zero = zero # BUILDARCH is usually the same as SRCARCH, except for sparcv9 - BUILDARCH = $(SRCARCH) + BUILDARCH ?= $(SRCARCH) ifeq ($(BUILDARCH), x86) ifdef LP64 BUILDARCH = amd64 @@ -311,18 +321,16 @@ endif # LIBARCH is 1:1 mapping from BUILDARCH - LIBARCH = $(LIBARCH/$(BUILDARCH)) + LIBARCH ?= $(LIBARCH/$(BUILDARCH)) LIBARCH/i486 = i386 LIBARCH/amd64 = amd64 LIBARCH/sparc = sparc LIBARCH/sparcv9 = sparcv9 LIBARCH/ia64 = ia64 LIBARCH/ppc64 = ppc64 - LIBARCH/ppc = ppc - LIBARCH/arm = arm LIBARCH/zero = $(ZERO_LIBARCH) - LP64_ARCH = sparcv9 amd64 ia64 ppc64 zero + LP64_ARCH += sparcv9 amd64 ia64 ppc64 zero endif # Required make macro settings for all platforms diff -r c2687aa5e5ca -r 7eb99acd567f make/hotspot_version --- a/make/hotspot_version Mon Jan 25 14:56:57 2016 -0800 +++ b/make/hotspot_version Mon Jan 25 14:57:27 2016 -0800 @@ -34,8 +34,8 @@ HOTSPOT_VM_COPYRIGHT=Copyright 2015 HS_MAJOR_VER=25 -HS_MINOR_VER=45 -HS_BUILD_NUMBER=02 +HS_MINOR_VER=66 +HS_BUILD_NUMBER=00 JDK_MAJOR_VER=1 JDK_MINOR_VER=8 diff -r c2687aa5e5ca -r 7eb99acd567f make/linux/Makefile --- a/make/linux/Makefile Mon Jan 25 14:56:57 2016 -0800 +++ b/make/linux/Makefile Mon Jan 25 14:57:27 2016 -0800 @@ -1,5 +1,5 @@ # -# Copyright (c) 1999, 2013, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 1999, 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 diff -r c2687aa5e5ca -r 7eb99acd567f make/linux/makefiles/arm.make --- a/make/linux/makefiles/arm.make Mon Jan 25 14:56:57 2016 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,31 +0,0 @@ -# -# Copyright (c) 2008, 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. -# -# - -Obj_Files += linux_arm.o - -ifneq ($(EXT_LIBS_PATH),) - LIBS += $(EXT_LIBS_PATH)/sflt_glibc.a -endif - -CFLAGS += -DVM_LITTLE_ENDIAN diff -r c2687aa5e5ca -r 7eb99acd567f make/linux/makefiles/build_vm_def.sh --- a/make/linux/makefiles/build_vm_def.sh Mon Jan 25 14:56:57 2016 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,16 +0,0 @@ -#!/bin/sh - -# If we're cross compiling use that path for nm -if [ "$CROSS_COMPILE_ARCH" != "" ]; then -NM=$ALT_COMPILER_PATH/nm -else -NM=nm -fi - -$NM --defined-only $* \ - | awk '{ - if ($3 ~ /^_ZTV/ || $3 ~ /^gHotSpotVM/) print "\t" $3 ";" - if ($3 ~ /^UseSharedSpaces$/) print "\t" $3 ";" - if ($3 ~ /^_ZN9Arguments17SharedArchivePathE$/) print "\t" $3 ";" - }' \ - | sort -u diff -r c2687aa5e5ca -r 7eb99acd567f make/linux/makefiles/buildtree.make --- a/make/linux/makefiles/buildtree.make Mon Jan 25 14:56:57 2016 -0800 +++ b/make/linux/makefiles/buildtree.make Mon Jan 25 14:57:27 2016 -0800 @@ -1,5 +1,5 @@ # -# Copyright (c) 2005, 2013, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2005, 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 @@ -70,6 +70,8 @@ PLATFORM_FILE = $(GAMMADIR)/make/$(OS_FAMILY)/platform_$(BUILDARCH).suncc else PLATFORM_FILE = $(GAMMADIR)/make/$(OS_FAMILY)/platform_$(BUILDARCH) + ALT_PLATFORM_FILE = $(HS_ALT_MAKE)/$(OS_FAMILY)/platform_$(BUILDARCH) + PLATFORM_FILE := $(if $(wildcard $(ALT_PLATFORM_FILE)),$(ALT_PLATFORM_FILE),$(PLATFORM_FILE)) endif endif @@ -202,7 +204,7 @@ $(QUIETLY) ( \ $(BUILDTREE_COMMENT); \ echo; \ - echo "Platform_file = $(PLATFORM_FILE)" | sed 's|$(GAMMADIR)|$$(GAMMADIR)|'; \ + echo "Platform_file = $(PLATFORM_FILE)" | sed -e 's|$(HS_ALT_MAKE)|$$(HS_ALT_MAKE)|' -e 's|$(GAMMADIR)|$$(GAMMADIR)|'; \ sed -n '/=/s/^ */Platform_/p' < $(PLATFORM_FILE); \ echo; \ echo "GAMMADIR = $(GAMMADIR)"; \ diff -r c2687aa5e5ca -r 7eb99acd567f make/linux/makefiles/defs.make --- a/make/linux/makefiles/defs.make Mon Jan 25 14:56:57 2016 -0800 +++ b/make/linux/makefiles/defs.make Mon Jan 25 14:57:27 2016 -0800 @@ -1,5 +1,5 @@ # -# Copyright (c) 2006, 2013, 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 @@ -109,22 +109,6 @@ HS_ARCH = x86 endif -# ARM -ifeq ($(ARCH), arm) - ARCH_DATA_MODEL = 32 - PLATFORM = linux-arm - VM_PLATFORM = linux_arm - HS_ARCH = arm -endif - -# PPC -ifeq ($(ARCH), ppc) - ARCH_DATA_MODEL = 32 - PLATFORM = linux-ppc - VM_PLATFORM = linux_ppc - HS_ARCH = ppc -endif - # PPC64 ifeq ($(ARCH), ppc64) ARCH_DATA_MODEL = 64 diff -r c2687aa5e5ca -r 7eb99acd567f make/linux/makefiles/dtrace.make --- a/make/linux/makefiles/dtrace.make Mon Jan 25 14:56:57 2016 -0800 +++ b/make/linux/makefiles/dtrace.make Mon Jan 25 14:57:27 2016 -0800 @@ -31,8 +31,8 @@ REASON = "This JDK does not support SDT probes" else -# We need a recent GCC for the default -ifeq "$(shell expr \( $(CC_VER_MAJOR) \>= 4 \) \& \( $(CC_VER_MINOR) \>= 4 \) )" "0" +# We need a recent GCC for the default (4.4 or later) +ifeq "$(shell expr \( \( $(CC_VER_MAJOR) = 4 \) \& \( $(CC_VER_MINOR) \>= 4 \) \) \| \( $(CC_VER_MAJOR) \>= 5 \) )" "0" REASON = "gcc version is too old" else diff -r c2687aa5e5ca -r 7eb99acd567f make/linux/makefiles/gcc.make --- a/make/linux/makefiles/gcc.make Mon Jan 25 14:56:57 2016 -0800 +++ b/make/linux/makefiles/gcc.make Mon Jan 25 14:57:27 2016 -0800 @@ -1,5 +1,5 @@ # -# Copyright (c) 1999, 2013, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 1999, 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 @@ -176,11 +176,7 @@ ARCHFLAG/ia64 = ARCHFLAG/sparc = -m32 -mcpu=v9 ARCHFLAG/sparcv9 = -m64 -mcpu=v9 -ARCHFLAG/arm = -fsigned-char ARCHFLAG/zero = $(ZERO_ARCHFLAG) -ifndef E500V2 -ARCHFLAG/ppc = -mcpu=powerpc -endif ARCHFLAG/ppc64 = -m64 CFLAGS += $(ARCHFLAG) @@ -188,10 +184,6 @@ LFLAGS += $(ARCHFLAG) ASFLAGS += $(ARCHFLAG) -ifdef E500V2 -CFLAGS += -DE500V2 -endif - # Use C++ Interpreter ifdef CC_INTERP CFLAGS += -DCC_INTERP @@ -346,47 +338,41 @@ # Note: The Itanium gcc compiler crashes when using -gstabs. DEBUG_CFLAGS/ia64 = -g DEBUG_CFLAGS/amd64 = -g - DEBUG_CFLAGS/arm = -g - DEBUG_CFLAGS/ppc = -g DEBUG_CFLAGS/ppc64 = -g DEBUG_CFLAGS += $(DEBUG_CFLAGS/$(BUILDARCH)) ifeq ($(DEBUG_CFLAGS/$(BUILDARCH)),) ifeq ($(USE_CLANG), true) # Clang doesn't understand -gstabs - DEBUG_CFLAGS += -g + DEBUG_CFLAGS/$(BUILDARCH) = -g else - DEBUG_CFLAGS += -gstabs + DEBUG_CFLAGS/$(BUILDARCH) = -gstabs endif endif ifeq ($(ENABLE_FULL_DEBUG_SYMBOLS),1) FASTDEBUG_CFLAGS/ia64 = -g FASTDEBUG_CFLAGS/amd64 = -g - FASTDEBUG_CFLAGS/arm = -g - FASTDEBUG_CFLAGS/ppc = -g FASTDEBUG_CFLAGS/ppc64 = -g - FASTDEBUG_CFLAGS += $(DEBUG_CFLAGS/$(BUILDARCH)) + FASTDEBUG_CFLAGS += $(FASTDEBUG_CFLAGS/$(BUILDARCH)) ifeq ($(FASTDEBUG_CFLAGS/$(BUILDARCH)),) ifeq ($(USE_CLANG), true) # Clang doesn't understand -gstabs - FASTDEBUG_CFLAGS += -g + FASTDEBUG_CFLAGS/$(BUILDARCH) = -g else - FASTDEBUG_CFLAGS += -gstabs + FASTDEBUG_CFLAGS/$(BUILDARCH) = -gstabs endif endif OPT_CFLAGS/ia64 = -g OPT_CFLAGS/amd64 = -g - OPT_CFLAGS/arm = -g - OPT_CFLAGS/ppc = -g OPT_CFLAGS/ppc64 = -g OPT_CFLAGS += $(OPT_CFLAGS/$(BUILDARCH)) ifeq ($(OPT_CFLAGS/$(BUILDARCH)),) ifeq ($(USE_CLANG), true) # Clang doesn't understand -gstabs - OPT_CFLAGS += -g + OPT_CFLAGS/$(BUILDARCH) = -g else - OPT_CFLAGS += -gstabs + OPT_CFLAGS/$(BUILDARCH) = -gstabs endif endif endif @@ -410,3 +396,5 @@ ifndef USE_SUNCC CFLAGS += -fno-omit-frame-pointer endif + +-include $(HS_ALT_MAKE)/linux/makefiles/gcc.make diff -r c2687aa5e5ca -r 7eb99acd567f make/linux/makefiles/ppc.make --- a/make/linux/makefiles/ppc.make Mon Jan 25 14:56:57 2016 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,33 +0,0 @@ -# -# Copyright (c) 2004, 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. -# -# - -# The copied fdlibm routines in sharedRuntimeTrig.o must not be optimized -OPT_CFLAGS/sharedRuntimeTrig.o = $(OPT_CFLAGS/NOOPT) - -# Must also specify if CPU is big endian -CFLAGS += -DVM_BIG_ENDIAN - -ifdef E500V2 -ASFLAGS += -Wa,-mspe -Wa,--defsym -Wa,E500V2=1 -endif diff -r c2687aa5e5ca -r 7eb99acd567f make/linux/makefiles/saproc.make --- a/make/linux/makefiles/saproc.make Mon Jan 25 14:56:57 2016 -0800 +++ b/make/linux/makefiles/saproc.make Mon Jan 25 14:57:27 2016 -0800 @@ -1,5 +1,5 @@ # -# Copyright (c) 2005, 2013, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2005, 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 @@ -69,19 +69,21 @@ endif ifneq ($(ALT_SASRCDIR),) -ALT_SAINCDIR=-I$(ALT_SASRCDIR) +ALT_SAINCDIR=-I$(ALT_SASRCDIR) -DALT_SASRCDIR else ALT_SAINCDIR= endif SA_LFLAGS = $(MAPFLAG:FILENAME=$(SAMAPFILE)) $(LDFLAGS_HASH_STYLE) +SAARCH ?= $(BUILDARCH) + $(LIBSAPROC): $(SASRCFILES) $(SAMAPFILE) $(QUIETLY) if [ "$(BOOT_JAVA_HOME)" = "" ]; then \ echo "ALT_BOOTDIR, BOOTDIR or JAVA_HOME needs to be defined to build SA"; \ exit 1; \ fi @echo Making SA debugger back-end... - $(QUIETLY) $(CC) -D$(BUILDARCH) -D_GNU_SOURCE \ + $(QUIETLY) $(CC) -D$(SAARCH) -D_GNU_SOURCE \ -D_FILE_OFFSET_BITS=64 \ $(SYMFLAG) $(ARCHFLAG) $(SHARED_FLAG) $(PICFLAG) \ -I$(SASRCDIR) \ diff -r c2687aa5e5ca -r 7eb99acd567f make/linux/makefiles/vm.make --- a/make/linux/makefiles/vm.make Mon Jan 25 14:56:57 2016 -0800 +++ b/make/linux/makefiles/vm.make Mon Jan 25 14:57:27 2016 -0800 @@ -1,5 +1,5 @@ # -# Copyright (c) 1999, 2013, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 1999, 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 @@ -45,8 +45,9 @@ ifeq ($(findstring true, $(JVM_VARIANT_ZERO) $(JVM_VARIANT_ZEROSHARK)), true) include $(MAKEFILES_DIR)/zeroshark.make else - include $(MAKEFILES_DIR)/$(BUILDARCH).make - -include $(HS_ALT_MAKE)/$(Platform_os_family)/makefiles/$(BUILDARCH).make + BUILDARCH_MAKE = $(MAKEFILES_DIR)/$(BUILDARCH).make + ALT_BUILDARCH_MAKE = $(HS_ALT_MAKE)/$(Platform_os_family)/makefiles/$(BUILDARCH).make + include $(if $(wildcard $(ALT_BUILDARCH_MAKE)),$(ALT_BUILDARCH_MAKE),$(BUILDARCH_MAKE)) endif # set VPATH so make knows where to look for source files @@ -257,8 +258,14 @@ rm -f $@ cat $^ > $@ +VMDEF_PAT = ^_ZTV +VMDEF_PAT := ^gHotSpotVM|$(VMDEF_PAT) +VMDEF_PAT := ^UseSharedSpaces$$|$(VMDEF_PAT) +VMDEF_PAT := ^_ZN9Arguments17SharedArchivePathE$$|$(VMDEF_PAT) + vm.def: $(Res_Files) $(Obj_Files) - sh $(GAMMADIR)/make/linux/makefiles/build_vm_def.sh *.o > $@ + $(QUIETLY) $(NM) --defined-only $(Obj_Files) | sort -k3 -u | \ + awk '$$3 ~ /$(VMDEF_PAT)/ { print "\t" $$3 ";" }' > $@ mapfile_ext: rm -f $@ diff -r c2687aa5e5ca -r 7eb99acd567f make/linux/platform_arm --- a/make/linux/platform_arm Mon Jan 25 14:56:57 2016 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,17 +0,0 @@ -os_family = linux - -arch = arm - -arch_model = arm - -os_arch = linux_arm - -os_arch_model = linux_arm - -lib_arch = arm - -compiler = gcc - -gnu_dis_arch = arm - -sysdefs = -DLINUX -D_GNU_SOURCE -DARM diff -r c2687aa5e5ca -r 7eb99acd567f make/linux/platform_ppc --- a/make/linux/platform_ppc Mon Jan 25 14:56:57 2016 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,17 +0,0 @@ -os_family = linux - -arch = ppc - -arch_model = ppc_32 - -os_arch = linux_ppc - -os_arch_model = linux_ppc_32 - -lib_arch = ppc - -compiler = gcc - -gnu_dis_arch = ppc - -sysdefs = -DLINUX -D_GNU_SOURCE -DPPC32 diff -r c2687aa5e5ca -r 7eb99acd567f make/solaris/makefiles/buildtree.make --- a/make/solaris/makefiles/buildtree.make Mon Jan 25 14:56:57 2016 -0800 +++ b/make/solaris/makefiles/buildtree.make Mon Jan 25 14:57:27 2016 -0800 @@ -264,6 +264,8 @@ echo "HOTSPOT_EXTRA_SYSDEFS\$$(HOTSPOT_EXTRA_SYSDEFS) = $(HOTSPOT_EXTRA_SYSDEFS)" && \ echo "SYSDEFS += \$$(HOTSPOT_EXTRA_SYSDEFS)"; \ echo; \ + [ -n "$(INCLUDE_TRACE)" ] && \ + echo && echo "INCLUDE_TRACE = $(INCLUDE_TRACE)"; \ [ -n "$(SPEC)" ] && \ echo "include $(SPEC)"; \ echo "include \$$(GAMMADIR)/make/$(OS_FAMILY)/makefiles/$(VARIANT).make"; \ diff -r c2687aa5e5ca -r 7eb99acd567f make/solaris/makefiles/sa.make --- a/make/solaris/makefiles/sa.make Mon Jan 25 14:56:57 2016 -0800 +++ b/make/solaris/makefiles/sa.make Mon Jan 25 14:57:27 2016 -0800 @@ -1,5 +1,5 @@ # -# Copyright (c) 2003, 2012, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2003, 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 @@ -29,8 +29,12 @@ # and generate JNI header file for native methods. include $(GAMMADIR)/make/solaris/makefiles/rules.make +include $(GAMMADIR)/make/defs.make AGENT_DIR = $(GAMMADIR)/agent include $(GAMMADIR)/make/sa.files + +-include $(HS_ALT_MAKE)/solaris/makefiles/sa.make + GENERATED = ../generated # tools.jar is needed by the JDI - SA binding diff -r c2687aa5e5ca -r 7eb99acd567f make/solaris/makefiles/trace.make --- a/make/solaris/makefiles/trace.make Mon Jan 25 14:56:57 2016 -0800 +++ b/make/solaris/makefiles/trace.make Mon Jan 25 14:57:27 2016 -0800 @@ -56,8 +56,12 @@ ifeq ($(HAS_ALT_SRC), true) TraceGeneratedNames += \ traceRequestables.hpp \ - traceEventControl.hpp \ - traceProducer.cpp + traceEventControl.hpp + +ifneq ($(INCLUDE_TRACE), false) + TraceGeneratedNames += traceProducer.cpp +endif + endif TraceGeneratedFiles = $(TraceGeneratedNames:%=$(TraceOutDir)/%) diff -r c2687aa5e5ca -r 7eb99acd567f make/solaris/makefiles/vm.make --- a/make/solaris/makefiles/vm.make Mon Jan 25 14:56:57 2016 -0800 +++ b/make/solaris/makefiles/vm.make Mon Jan 25 14:57:27 2016 -0800 @@ -215,7 +215,7 @@ endif # Always exclude these. -Src_Files_EXCLUDE := dtrace jsig.c jvmtiEnvRecommended.cpp jvmtiEnvStub.cpp +Src_Files_EXCLUDE += dtrace jsig.c jvmtiEnvRecommended.cpp jvmtiEnvStub.cpp # Exclude per type. Src_Files_EXCLUDE/CORE := $(COMPILER1_SPECIFIC_FILES) $(COMPILER2_SPECIFIC_FILES) $(ZERO_SPECIFIC_FILES) $(SHARK_SPECIFIC_FILES) $(JVMCI_SPECIFIC_FILES) ciTypeFlow.cpp diff -r c2687aa5e5ca -r 7eb99acd567f make/windows/makefiles/sa.make --- a/make/windows/makefiles/sa.make Mon Jan 25 14:56:57 2016 -0800 +++ b/make/windows/makefiles/sa.make Mon Jan 25 14:57:27 2016 -0800 @@ -1,5 +1,5 @@ # -# Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2003, 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 @@ -38,6 +38,22 @@ GENERATED = ../generated +HS_COMMON_SRC_REL = src + +!if "$(OPENJDK)" != "true" +HS_ALT_SRC_REL=src/closed +HS_ALT_SRC = $(WorkSpace)/$(HS_ALT_SRC_REL) +!ifndef HS_ALT_MAKE +HS_ALT_MAKE=$(WorkSpace)/make/closed +!endif +!endif + +HS_COMMON_SRC = $(WorkSpace)/$(HS_COMMON_SRC_REL) + +!ifdef HS_ALT_MAKE +!include $(HS_ALT_MAKE)/windows/makefiles/sa.make +!endif + # tools.jar is needed by the JDI - SA binding SA_CLASSPATH = $(BOOT_JAVA_HOME)/lib/tools.jar diff -r c2687aa5e5ca -r 7eb99acd567f mx.jvmci/mx_jvmci.py --- a/mx.jvmci/mx_jvmci.py Mon Jan 25 14:56:57 2016 -0800 +++ b/mx.jvmci/mx_jvmci.py Mon Jan 25 14:57:27 2016 -0800 @@ -589,8 +589,8 @@ del versions['hotspot'] fp.write('SOURCE=" ' + ' '.join((k + ":" + v for k, v in versions.iteritems())) + '"' + os.linesep) mx.logv("Updating " + releaseFile) - except: - mx.warn("Exception while updaing release file") + except BaseException as e: + mx.warn("Exception " + str(e) + " while updaing release file") fp.write(line) else: fp.write(line) diff -r c2687aa5e5ca -r 7eb99acd567f src/cpu/ppc/vm/frame_ppc.cpp --- a/src/cpu/ppc/vm/frame_ppc.cpp Mon Jan 25 14:56:57 2016 -0800 +++ b/src/cpu/ppc/vm/frame_ppc.cpp Mon Jan 25 14:57:27 2016 -0800 @@ -318,3 +318,10 @@ // unused... but returns fp() to minimize changes introduced by 7087445 return fp(); } + +#ifndef PRODUCT +// This is a generic constructor which is only used by pns() in debug.cpp. +frame::frame(void* sp, void* fp, void* pc) : _sp((intptr_t*)sp), _unextended_sp((intptr_t*)sp) { + find_codeblob_and_set_pc_and_deopt_state((address)pc); // also sets _fp and adjusts _unextended_sp +} +#endif diff -r c2687aa5e5ca -r 7eb99acd567f src/cpu/ppc/vm/globals_ppc.hpp --- a/src/cpu/ppc/vm/globals_ppc.hpp Mon Jan 25 14:56:57 2016 -0800 +++ b/src/cpu/ppc/vm/globals_ppc.hpp Mon Jan 25 14:57:27 2016 -0800 @@ -55,6 +55,8 @@ define_pd_global(bool, UseMembar, false); +define_pd_global(bool, PreserveFramePointer, false); + // GC Ergo Flags define_pd_global(uintx, CMSYoungGenPerWorker, 16*M); // Default max size of CMS young gen, per GC worker thread. diff -r c2687aa5e5ca -r 7eb99acd567f src/cpu/ppc/vm/interpreter_ppc.cpp --- a/src/cpu/ppc/vm/interpreter_ppc.cpp Mon Jan 25 14:56:57 2016 -0800 +++ b/src/cpu/ppc/vm/interpreter_ppc.cpp Mon Jan 25 14:57:27 2016 -0800 @@ -1,6 +1,6 @@ /* - * Copyright (c) 1997, 2014, Oracle and/or its affiliates. All rights reserved. - * Copyright 2012, 2014 SAP AG. All rights reserved. + * Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright 2012, 2015 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 @@ -459,7 +459,8 @@ // This is not a leaf but we have a JavaFrameAnchor now and we will // check (create) exceptions afterward so this is ok. - __ call_VM_leaf(CAST_FROM_FN_PTR(address, InterpreterRuntime::throw_AbstractMethodError)); + __ call_VM_leaf(CAST_FROM_FN_PTR(address, InterpreterRuntime::throw_AbstractMethodError), + R16_thread); // Pop the C frame and restore LR. __ pop_frame(); diff -r c2687aa5e5ca -r 7eb99acd567f src/cpu/ppc/vm/ppc.ad --- a/src/cpu/ppc/vm/ppc.ad Mon Jan 25 14:56:57 2016 -0800 +++ b/src/cpu/ppc/vm/ppc.ad Mon Jan 25 14:57:27 2016 -0800 @@ -2264,9 +2264,8 @@ // Do we need to mask the count passed to shift instructions or does // the cpu only look at the lower 5/6 bits anyway? -// Off, as masks are generated in expand rules where required. -// Constant shift counts are handled in Ideal phase. -const bool Matcher::need_masked_shift_count = false; +// PowerPC requires masked shift counts. +const bool Matcher::need_masked_shift_count = true; // This affects two different things: // - how Decode nodes are matched @@ -4418,11 +4417,11 @@ interface(CONST_INTER); %} -// constant 'float +0.0'. +// Float Immediate: +0.0f. operand immF_0() %{ - predicate((n->getf() == 0) && - (fpclassify(n->getf()) == FP_ZERO) && (signbit(n->getf()) == 0)); + predicate(jint_cast(n->getf()) == 0); match(ConF); + op_cost(0); format %{ %} interface(CONST_INTER); diff -r c2687aa5e5ca -r 7eb99acd567f src/cpu/sparc/vm/frame_sparc.cpp --- a/src/cpu/sparc/vm/frame_sparc.cpp Mon Jan 25 14:56:57 2016 -0800 +++ b/src/cpu/sparc/vm/frame_sparc.cpp Mon Jan 25 14:57:27 2016 -0800 @@ -342,7 +342,7 @@ // constructors // Construct an unpatchable, deficient frame -frame::frame(intptr_t* sp, unpatchable_t, address pc, CodeBlob* cb) { +void frame::init(intptr_t* sp, address pc, CodeBlob* cb) { #ifdef _LP64 assert( (((intptr_t)sp & (wordSize-1)) == 0), "frame constructor passed an invalid sp"); #endif @@ -364,6 +364,10 @@ #endif // ASSERT } +frame::frame(intptr_t* sp, unpatchable_t, address pc, CodeBlob* cb) { + init(sp, pc, cb); +} + frame::frame(intptr_t* sp, intptr_t* younger_sp, bool younger_frame_is_interpreted) : _sp(sp), _younger_sp(younger_sp), @@ -418,6 +422,13 @@ } } +#ifndef PRODUCT +// This is a generic constructor which is only used by pns() in debug.cpp. +frame::frame(void* sp, void* fp, void* pc) { + init((intptr_t*)sp, (address)pc, NULL); +} +#endif + bool frame::is_interpreted_frame() const { return Interpreter::contains(pc()); } diff -r c2687aa5e5ca -r 7eb99acd567f src/cpu/sparc/vm/frame_sparc.hpp --- a/src/cpu/sparc/vm/frame_sparc.hpp Mon Jan 25 14:56:57 2016 -0800 +++ b/src/cpu/sparc/vm/frame_sparc.hpp Mon Jan 25 14:57:27 2016 -0800 @@ -164,6 +164,8 @@ enum unpatchable_t { unpatchable }; frame(intptr_t* sp, unpatchable_t, address pc = NULL, CodeBlob* cb = NULL); + void init(intptr_t* sp, address pc, CodeBlob* cb); + // Walk from sp outward looking for old_sp, and return old_sp's predecessor // (i.e. return the sp from the frame where old_sp is the fp). // Register windows are assumed to be flushed for the stack in question. diff -r c2687aa5e5ca -r 7eb99acd567f src/cpu/sparc/vm/globals_sparc.hpp --- a/src/cpu/sparc/vm/globals_sparc.hpp Mon Jan 25 14:56:57 2016 -0800 +++ b/src/cpu/sparc/vm/globals_sparc.hpp Mon Jan 25 14:57:27 2016 -0800 @@ -74,6 +74,8 @@ define_pd_global(bool, UseMembar, false); +define_pd_global(bool, PreserveFramePointer, false); + // GC Ergo Flags define_pd_global(uintx, CMSYoungGenPerWorker, 16*M); // default max size of CMS young gen, per GC worker thread diff -r c2687aa5e5ca -r 7eb99acd567f src/cpu/sparc/vm/sparc.ad --- a/src/cpu/sparc/vm/sparc.ad Mon Jan 25 14:56:57 2016 -0800 +++ b/src/cpu/sparc/vm/sparc.ad Mon Jan 25 14:57:27 2016 -0800 @@ -3760,13 +3760,9 @@ interface(CONST_INTER); %} +// Double Immediate: +0.0d operand immD0() %{ -#ifdef _LP64 - // on 64-bit architectures this comparision is faster predicate(jlong_cast(n->getd()) == 0); -#else - predicate((n->getd() == 0) && (fpclass(n->getd()) == FP_PZERO)); -#endif match(ConD); op_cost(0); @@ -3783,9 +3779,9 @@ interface(CONST_INTER); %} -// Float Immediate: 0 -operand immF0() %{ - predicate((n->getf() == 0) && (fpclass(n->getf()) == FP_PZERO)); +// Float Immediate: +0.0f +operand immF0() %{ + predicate(jint_cast(n->getf()) == 0); match(ConF); op_cost(0); diff -r c2687aa5e5ca -r 7eb99acd567f src/cpu/sparc/vm/vm_version_sparc.cpp --- a/src/cpu/sparc/vm/vm_version_sparc.cpp Mon Jan 25 14:56:57 2016 -0800 +++ b/src/cpu/sparc/vm/vm_version_sparc.cpp Mon Jan 25 14:57:27 2016 -0800 @@ -37,7 +37,7 @@ int VM_Version::_features = VM_Version::unknown_m; const char* VM_Version::_features_str = ""; -unsigned int VM_Version::_L2_cache_line_size = 0; +unsigned int VM_Version::_L2_data_cache_line_size = 0; void VM_Version::initialize() { _features = determine_features(); @@ -363,7 +363,7 @@ #ifndef PRODUCT if (PrintMiscellaneous && Verbose) { - tty->print_cr("L2 cache line size: %u", L2_cache_line_size()); + tty->print_cr("L2 data cache line size: %u", L2_data_cache_line_size()); tty->print("Allocation"); if (AllocatePrefetchStyle <= 0) { tty->print_cr(": no prefetching"); diff -r c2687aa5e5ca -r 7eb99acd567f src/cpu/sparc/vm/vm_version_sparc.hpp --- a/src/cpu/sparc/vm/vm_version_sparc.hpp Mon Jan 25 14:56:57 2016 -0800 +++ b/src/cpu/sparc/vm/vm_version_sparc.hpp Mon Jan 25 14:57:27 2016 -0800 @@ -97,8 +97,8 @@ static int _features; static const char* _features_str; - static unsigned int _L2_cache_line_size; - static unsigned int L2_cache_line_size() { return _L2_cache_line_size; } + static unsigned int _L2_data_cache_line_size; + static unsigned int L2_data_cache_line_size() { return _L2_data_cache_line_size; } static void print_features(); static int determine_features(); @@ -172,7 +172,7 @@ static const char* cpu_features() { return _features_str; } // default prefetch block size on sparc - static intx prefetch_data_size() { return L2_cache_line_size(); } + static intx prefetch_data_size() { return L2_data_cache_line_size(); } // Prefetch static intx prefetch_copy_interval_in_bytes() { diff -r c2687aa5e5ca -r 7eb99acd567f src/cpu/x86/vm/assembler_x86.hpp --- a/src/cpu/x86/vm/assembler_x86.hpp Mon Jan 25 14:56:57 2016 -0800 +++ b/src/cpu/x86/vm/assembler_x86.hpp Mon Jan 25 14:57:27 2016 -0800 @@ -141,8 +141,10 @@ #endif // _LP64 -// JSR 292 fixed register usages: -REGISTER_DECLARATION(Register, rbp_mh_SP_save, rbp); +// JSR 292 +// On x86, the SP does not have to be saved when invoking method handle intrinsics +// or compiled lambda forms. We indicate that by setting rbp_mh_SP_save to noreg. +REGISTER_DECLARATION(Register, rbp_mh_SP_save, noreg); // Address is an abstraction used to represent a memory location // using any of the amd64 addressing modes with one object. diff -r c2687aa5e5ca -r 7eb99acd567f src/cpu/x86/vm/c1_FrameMap_x86.cpp --- a/src/cpu/x86/vm/c1_FrameMap_x86.cpp Mon Jan 25 14:56:57 2016 -0800 +++ b/src/cpu/x86/vm/c1_FrameMap_x86.cpp Mon Jan 25 14:57:27 2016 -0800 @@ -343,14 +343,13 @@ return FrameMap::rsp_opr; } - // JSR 292 +// On x86, there is no need to save the SP, because neither +// method handle intrinsics, nor compiled lambda forms modify it. LIR_Opr FrameMap::method_handle_invoke_SP_save_opr() { - assert(rbp == rbp_mh_SP_save, "must be same register"); - return rbp_opr; + return LIR_OprFact::illegalOpr; } - bool FrameMap::validate_frame() { return true; } diff -r c2687aa5e5ca -r 7eb99acd567f src/cpu/x86/vm/c1_MacroAssembler_x86.cpp --- a/src/cpu/x86/vm/c1_MacroAssembler_x86.cpp Mon Jan 25 14:56:57 2016 -0800 +++ b/src/cpu/x86/vm/c1_MacroAssembler_x86.cpp Mon Jan 25 14:57:27 2016 -0800 @@ -359,6 +359,9 @@ generate_stack_overflow_check(bang_size_in_bytes); push(rbp); + if (PreserveFramePointer) { + mov(rbp, rsp); + } #ifdef TIERED // c2 leaves fpu stack dirty. Clean it on entry if (UseSSE < 2 ) { diff -r c2687aa5e5ca -r 7eb99acd567f src/cpu/x86/vm/c1_Runtime1_x86.cpp --- a/src/cpu/x86/vm/c1_Runtime1_x86.cpp Mon Jan 25 14:56:57 2016 -0800 +++ b/src/cpu/x86/vm/c1_Runtime1_x86.cpp Mon Jan 25 14:57:27 2016 -0800 @@ -754,14 +754,9 @@ // WIN64_ONLY: No need to add frame::arg_reg_save_area_bytes to SP // since we do a leave anyway. - // Pop the return address since we are possibly changing SP (restoring from BP). + // Pop the return address. __ leave(); __ pop(rcx); - - // Restore SP from BP if the exception PC is a method handle call site. - NOT_LP64(__ get_thread(thread);) - __ cmpl(Address(thread, JavaThread::is_method_handle_return_offset()), 0); - __ cmovptr(Assembler::notEqual, rsp, rbp_mh_SP_save); __ jmp(rcx); // jump to exception handler break; default: ShouldNotReachHere(); @@ -832,11 +827,6 @@ // the pop is also necessary to simulate the effect of a ret(0) __ pop(exception_pc); - // Restore SP from BP if the exception PC is a method handle call site. - NOT_LP64(__ get_thread(thread);) - __ cmpl(Address(thread, JavaThread::is_method_handle_return_offset()), 0); - __ cmovptr(Assembler::notEqual, rsp, rbp_mh_SP_save); - // continue at exception handler (return address removed) // note: do *not* remove arguments when unwinding the // activation since the caller assumes having diff -r c2687aa5e5ca -r 7eb99acd567f src/cpu/x86/vm/frame_x86.cpp --- a/src/cpu/x86/vm/frame_x86.cpp Mon Jan 25 14:56:57 2016 -0800 +++ b/src/cpu/x86/vm/frame_x86.cpp Mon Jan 25 14:57:27 2016 -0800 @@ -216,7 +216,8 @@ if (sender_blob->is_nmethod()) { nmethod* nm = sender_blob->as_nmethod_or_null(); if (nm != NULL) { - if (nm->is_deopt_mh_entry(sender_pc) || nm->is_deopt_entry(sender_pc)) { + if (nm->is_deopt_mh_entry(sender_pc) || nm->is_deopt_entry(sender_pc) || + nm->method()->is_method_handle_intrinsic()) { return false; } } @@ -383,10 +384,9 @@ // frame::verify_deopt_original_pc // // Verifies the calculated original PC of a deoptimization PC for the -// given unextended SP. The unextended SP might also be the saved SP -// for MethodHandle call sites. +// given unextended SP. #ifdef ASSERT -void frame::verify_deopt_original_pc(nmethod* nm, intptr_t* unextended_sp, bool is_method_handle_return) { +void frame::verify_deopt_original_pc(nmethod* nm, intptr_t* unextended_sp) { frame fr; // This is ugly but it's better than to change {get,set}_original_pc @@ -396,33 +396,23 @@ address original_pc = nm->get_original_pc(&fr); assert(nm->insts_contains(original_pc), "original PC must be in nmethod"); - assert(nm->is_method_handle_return(original_pc) == is_method_handle_return, "must be"); } #endif //------------------------------------------------------------------------------ // frame::adjust_unextended_sp void frame::adjust_unextended_sp() { - // If we are returning to a compiled MethodHandle call site, the - // saved_fp will in fact be a saved value of the unextended SP. The - // simplest way to tell whether we are returning to such a call site - // is as follows: + // On x86, sites calling method handle intrinsics and lambda forms are treated + // as any other call site. Therefore, no special action is needed when we are + // returning to any of these call sites. nmethod* sender_nm = (_cb == NULL) ? NULL : _cb->as_nmethod_or_null(); if (sender_nm != NULL) { - // If the sender PC is a deoptimization point, get the original - // PC. For MethodHandle call site the unextended_sp is stored in - // saved_fp. - if (sender_nm->is_deopt_mh_entry(_pc)) { - DEBUG_ONLY(verify_deopt_mh_original_pc(sender_nm, _fp)); - _unextended_sp = _fp; - } - else if (sender_nm->is_deopt_entry(_pc)) { + // If the sender PC is a deoptimization point, get the original PC. + if (sender_nm->is_deopt_entry(_pc) || + sender_nm->is_deopt_mh_entry(_pc)) { DEBUG_ONLY(verify_deopt_original_pc(sender_nm, _unextended_sp)); } - else if (sender_nm->is_method_handle_return(_pc)) { - _unextended_sp = _fp; - } } } @@ -726,3 +716,10 @@ assert(! is_compiled_frame(), "unknown compiled frame size"); return fp(); } + +#ifndef PRODUCT +// This is a generic constructor which is only used by pns() in debug.cpp. +frame::frame(void* sp, void* fp, void* pc) { + init((intptr_t*)sp, (intptr_t*)fp, (address)pc); +} +#endif diff -r c2687aa5e5ca -r 7eb99acd567f src/cpu/x86/vm/frame_x86.hpp --- a/src/cpu/x86/vm/frame_x86.hpp Mon Jan 25 14:56:57 2016 -0800 +++ b/src/cpu/x86/vm/frame_x86.hpp Mon Jan 25 14:57:27 2016 -0800 @@ -76,11 +76,11 @@ // [locals and parameters ] // <- sender sp -// [1] When the c++ interpreter calls a new method it returns to the frame +// [1] When the C++ interpreter calls a new method it returns to the frame // manager which allocates a new frame on the stack. In that case there // is no real callee of this newly allocated frame. The frame manager is -// aware of the additional frame(s) and will pop them as nested calls -// complete. Howevers tTo make it look good in the debugger the frame +// aware of the additional frame(s) and will pop them as nested calls +// complete. However, to make it look good in the debugger the frame // manager actually installs a dummy pc pointing to RecursiveInterpreterActivation // with a fake interpreter_state* parameter to make it easy to debug // nested calls. @@ -88,7 +88,7 @@ // Note that contrary to the layout for the assembly interpreter the // expression stack allocated for the C++ interpreter is full sized. // However this is not as bad as it seems as the interpreter frame_manager -// will truncate the unused space on succesive method calls. +// will truncate the unused space on successive method calls. // // ------------------------------ C++ interpreter ---------------------------------------- @@ -172,10 +172,7 @@ #ifdef ASSERT // Used in frame::sender_for_{interpreter,compiled}_frame - static void verify_deopt_original_pc( nmethod* nm, intptr_t* unextended_sp, bool is_method_handle_return = false); - static void verify_deopt_mh_original_pc(nmethod* nm, intptr_t* unextended_sp) { - verify_deopt_original_pc(nm, unextended_sp, true); - } + static void verify_deopt_original_pc(nmethod* nm, intptr_t* unextended_sp); #endif public: @@ -187,6 +184,8 @@ frame(intptr_t* sp, intptr_t* fp); + void init(intptr_t* sp, intptr_t* fp, address pc); + // accessors for the instance variables // Note: not necessarily the real 'frame pointer' (see real_fp) intptr_t* fp() const { return _fp; } diff -r c2687aa5e5ca -r 7eb99acd567f src/cpu/x86/vm/frame_x86.inline.hpp --- a/src/cpu/x86/vm/frame_x86.inline.hpp Mon Jan 25 14:56:57 2016 -0800 +++ b/src/cpu/x86/vm/frame_x86.inline.hpp Mon Jan 25 14:57:27 2016 -0800 @@ -40,7 +40,7 @@ _deopt_state = unknown; } -inline frame::frame(intptr_t* sp, intptr_t* fp, address pc) { +inline void frame::init(intptr_t* sp, intptr_t* fp, address pc) { _sp = sp; _unextended_sp = sp; _fp = fp; @@ -58,6 +58,10 @@ } } +inline frame::frame(intptr_t* sp, intptr_t* fp, address pc) { + init(sp, fp, pc); +} + inline frame::frame(intptr_t* sp, intptr_t* unextended_sp, intptr_t* fp, address pc) { _sp = sp; _unextended_sp = unextended_sp; @@ -89,7 +93,7 @@ // find_blob call. This is also why we can have no asserts on the validity // of the pc we find here. AsyncGetCallTrace -> pd_get_top_frame_for_signal_handler // -> pd_last_frame should use a specialized version of pd_last_frame which could - // call a specilaized frame constructor instead of this one. + // call a specialized frame constructor instead of this one. // Then we could use the assert below. However this assert is of somewhat dubious // value. // assert(_pc != NULL, "no pc?"); diff -r c2687aa5e5ca -r 7eb99acd567f src/cpu/x86/vm/globals_x86.hpp --- a/src/cpu/x86/vm/globals_x86.hpp Mon Jan 25 14:56:57 2016 -0800 +++ b/src/cpu/x86/vm/globals_x86.hpp Mon Jan 25 14:57:27 2016 -0800 @@ -87,6 +87,8 @@ define_pd_global(uintx, TypeProfileLevel, 111); #endif +define_pd_global(bool, PreserveFramePointer, false); + #define ARCH_FLAGS(develop, product, diagnostic, experimental, notproduct) \ \ develop(bool, IEEEPrecision, true, \ diff -r c2687aa5e5ca -r 7eb99acd567f src/cpu/x86/vm/macroAssembler_x86.cpp --- a/src/cpu/x86/vm/macroAssembler_x86.cpp Mon Jan 25 14:56:57 2016 -0800 +++ b/src/cpu/x86/vm/macroAssembler_x86.cpp Mon Jan 25 14:57:27 2016 -0800 @@ -6122,6 +6122,10 @@ // We always push rbp, so that on return to interpreter rbp, will be // restored correctly and we can correct the stack. push(rbp); + // Save caller's stack pointer into RBP if the frame pointer is preserved. + if (PreserveFramePointer) { + mov(rbp, rsp); + } // Remove word for ebp framesize -= wordSize; @@ -6136,6 +6140,11 @@ // Save RBP register now. framesize -= wordSize; movptr(Address(rsp, framesize), rbp); + // Save caller's stack pointer into RBP if the frame pointer is preserved. + if (PreserveFramePointer) { + movptr(rbp, rsp); + addptr(rbp, framesize + wordSize); + } } if (VerifyStackAtCalls) { // Majik cookie to verify stack depth @@ -6690,7 +6699,7 @@ subl(cnt2, stride2); jccb(Assembler::notZero, COMPARE_WIDE_VECTORS_LOOP); // clean upper bits of YMM registers - vzeroupper(); + vpxor(vec1, vec1); // compare wide vectors tail bind(COMPARE_WIDE_TAIL); @@ -6705,7 +6714,7 @@ // Identifies the mismatching (higher or lower)16-bytes in the 32-byte vectors. bind(VECTOR_NOT_EQUAL); // clean upper bits of YMM registers - vzeroupper(); + vpxor(vec1, vec1); lea(str1, Address(str1, result, scale)); lea(str2, Address(str2, result, scale)); jmp(COMPARE_16_CHARS); @@ -6964,7 +6973,8 @@ bind(DONE); if (UseAVX >= 2) { // clean upper bits of YMM registers - vzeroupper(); + vpxor(vec1, vec1); + vpxor(vec2, vec2); } } @@ -7098,7 +7108,8 @@ BIND(L_check_fill_8_bytes); // clean upper bits of YMM registers - vzeroupper(); + movdl(xtmp, value); + pshufd(xtmp, xtmp, 0); } else { // Fill 32-byte chunks pshufd(xtmp, xtmp, 0); @@ -7261,7 +7272,11 @@ bind(L_copy_16_chars_exit); if (UseAVX >= 2) { // clean upper bits of YMM registers - vzeroupper(); + vpxor(tmp2Reg, tmp2Reg); + vpxor(tmp3Reg, tmp3Reg); + vpxor(tmp4Reg, tmp4Reg); + movdl(tmp1Reg, tmp5); + pshufd(tmp1Reg, tmp1Reg, 0); } subptr(len, 8); jccb(Assembler::greater, L_copy_8_chars_exit); diff -r c2687aa5e5ca -r 7eb99acd567f src/cpu/x86/vm/methodHandles_x86.cpp --- a/src/cpu/x86/vm/methodHandles_x86.cpp Mon Jan 25 14:56:57 2016 -0800 +++ b/src/cpu/x86/vm/methodHandles_x86.cpp Mon Jan 25 14:57:27 2016 -0800 @@ -373,7 +373,7 @@ // member_reg - MemberName that was the trailing argument // temp1_recv_klass - klass of stacked receiver, if needed // rsi/r13 - interpreter linkage (if interpreted) - // rcx, rdx, rsi, rdi, r8, r8 - compiler arguments (if compiled) + // rcx, rdx, rsi, rdi, r8 - compiler arguments (if compiled) Label L_incompatible_class_change_error; switch (iid) { diff -r c2687aa5e5ca -r 7eb99acd567f src/cpu/x86/vm/runtime_x86_32.cpp --- a/src/cpu/x86/vm/runtime_x86_32.cpp Mon Jan 25 14:56:57 2016 -0800 +++ b/src/cpu/x86/vm/runtime_x86_32.cpp Mon Jan 25 14:57:27 2016 -0800 @@ -126,10 +126,6 @@ // rax: exception handler for given - // Restore SP from BP if the exception PC is a MethodHandle call site. - __ cmpl(Address(rcx, JavaThread::is_method_handle_return_offset()), 0); - __ cmovptr(Assembler::notEqual, rsp, rbp_mh_SP_save); - // We have a handler in rax, (could be deopt blob) // rdx - throwing pc, deopt blob will need it. diff -r c2687aa5e5ca -r 7eb99acd567f src/cpu/x86/vm/sharedRuntime_x86_64.cpp --- a/src/cpu/x86/vm/sharedRuntime_x86_64.cpp Mon Jan 25 14:56:57 2016 -0800 +++ b/src/cpu/x86/vm/sharedRuntime_x86_64.cpp Mon Jan 25 14:57:27 2016 -0800 @@ -4110,8 +4110,8 @@ // Save callee-saved registers. See x86_64.ad. - // rbp is an implicitly saved callee saved register (i.e. the calling - // convention will save restore it in prolog/epilog) Other than that + // rbp is an implicitly saved callee saved register (i.e., the calling + // convention will save/restore it in the prolog/epilog). Other than that // there are no callee save registers now that adapter frames are gone. __ movptr(Address(rsp, SimpleRuntimeFrame::rbp_off << LogBytesPerInt), rbp); @@ -4153,9 +4153,9 @@ // Restore callee-saved registers - // rbp is an implicitly saved callee saved register (i.e. the calling + // rbp is an implicitly saved callee-saved register (i.e., the calling // convention will save restore it in prolog/epilog) Other than that - // there are no callee save registers no that adapter frames are gone. + // there are no callee save registers now that adapter frames are gone. __ movptr(rbp, Address(rsp, SimpleRuntimeFrame::rbp_off << LogBytesPerInt)); @@ -4164,10 +4164,6 @@ // rax: exception handler - // Restore SP from BP if the exception PC is a MethodHandle call site. - __ cmpl(Address(r15_thread, JavaThread::is_method_handle_return_offset()), 0); - __ cmovptr(Assembler::notEqual, rsp, rbp_mh_SP_save); - // We have a handler in rax (could be deopt blob). __ mov(r8, rax); diff -r c2687aa5e5ca -r 7eb99acd567f src/cpu/x86/vm/stubGenerator_x86_32.cpp --- a/src/cpu/x86/vm/stubGenerator_x86_32.cpp Mon Jan 25 14:56:57 2016 -0800 +++ b/src/cpu/x86/vm/stubGenerator_x86_32.cpp Mon Jan 25 14:57:27 2016 -0800 @@ -837,7 +837,8 @@ if (UseUnalignedLoadStores && (UseAVX >= 2)) { // clean upper bits of YMM registers - __ vzeroupper(); + __ vpxor(xmm0, xmm0); + __ vpxor(xmm1, xmm1); } __ addl(qword_count, 8); __ jccb(Assembler::zero, L_exit); diff -r c2687aa5e5ca -r 7eb99acd567f src/cpu/x86/vm/stubGenerator_x86_64.cpp --- a/src/cpu/x86/vm/stubGenerator_x86_64.cpp Mon Jan 25 14:56:57 2016 -0800 +++ b/src/cpu/x86/vm/stubGenerator_x86_64.cpp Mon Jan 25 14:57:27 2016 -0800 @@ -1328,7 +1328,8 @@ __ BIND(L_end); if (UseAVX >= 2) { // clean upper bits of YMM registers - __ vzeroupper(); + __ vpxor(xmm0, xmm0); + __ vpxor(xmm1, xmm1); } } else { // Copy 32-bytes per iteration @@ -1405,7 +1406,8 @@ __ BIND(L_end); if (UseAVX >= 2) { // clean upper bits of YMM registers - __ vzeroupper(); + __ vpxor(xmm0, xmm0); + __ vpxor(xmm1, xmm1); } } else { // Copy 32-bytes per iteration diff -r c2687aa5e5ca -r 7eb99acd567f src/cpu/x86/vm/vm_version_x86.hpp --- a/src/cpu/x86/vm/vm_version_x86.hpp Mon Jan 25 14:56:57 2016 -0800 +++ b/src/cpu/x86/vm/vm_version_x86.hpp Mon Jan 25 14:57:27 2016 -0800 @@ -571,10 +571,12 @@ static uint cores_per_cpu() { uint result = 1; if (is_intel()) { - if (supports_processor_topology()) { + bool supports_topology = supports_processor_topology(); + if (supports_topology) { result = _cpuid_info.tpl_cpuidB1_ebx.bits.logical_cpus / _cpuid_info.tpl_cpuidB0_ebx.bits.logical_cpus; - } else { + } + if (!supports_topology || result == 0) { result = (_cpuid_info.dcp_cpuid4_eax.bits.cores_per_cpu + 1); } } else if (is_amd()) { diff -r c2687aa5e5ca -r 7eb99acd567f src/cpu/x86/vm/x86.ad --- a/src/cpu/x86/vm/x86.ad Mon Jan 25 14:56:57 2016 -0800 +++ b/src/cpu/x86/vm/x86.ad Mon Jan 25 14:57:27 2016 -0800 @@ -912,21 +912,6 @@ encode %{ - enc_class preserve_SP %{ - debug_only(int off0 = cbuf.insts_size()); - MacroAssembler _masm(&cbuf); - // RBP is preserved across all calls, even compiled calls. - // Use it to preserve RSP in places where the callee might change the SP. - __ movptr(rbp_mh_SP_save, rsp); - debug_only(int off1 = cbuf.insts_size()); - assert(off1 - off0 == preserve_SP_size(), "correct size prediction"); - %} - - enc_class restore_SP %{ - MacroAssembler _masm(&cbuf); - __ movptr(rsp, rbp_mh_SP_save); - %} - enc_class call_epilog %{ if (VerifyStackAtCalls) { // Check that stack depth is unchanged: find majik cookie on stack diff -r c2687aa5e5ca -r 7eb99acd567f src/cpu/x86/vm/x86_32.ad --- a/src/cpu/x86/vm/x86_32.ad Mon Jan 25 14:56:57 2016 -0800 +++ b/src/cpu/x86/vm/x86_32.ad Mon Jan 25 14:57:27 2016 -0800 @@ -123,50 +123,94 @@ // 2) reg_class interpreter_method_oop_reg ( /* as def'd in frame section */ ) // 3) reg_class stack_slots( /* one chunk of stack-based "registers" */ ) // +// Class for no registers (empty set). +reg_class no_reg(); + // Class for all registers -reg_class any_reg(EAX, EDX, EBP, EDI, ESI, ECX, EBX, ESP); +reg_class any_reg_with_ebp(EAX, EDX, EBP, EDI, ESI, ECX, EBX, ESP); +// Class for all registers (excluding EBP) +reg_class any_reg_no_ebp(EAX, EDX, EDI, ESI, ECX, EBX, ESP); +// Dynamic register class that selects at runtime between register classes +// any_reg and any_no_ebp_reg (depending on the value of the flag PreserveFramePointer). +// Equivalent to: return PreserveFramePointer ? any_no_ebp_reg : any_reg; +reg_class_dynamic any_reg(any_reg_no_ebp, any_reg_with_ebp, %{ PreserveFramePointer %}); + // Class for general registers -reg_class int_reg(EAX, EDX, EBP, EDI, ESI, ECX, EBX); -// Class for general registers which may be used for implicit null checks on win95 -// Also safe for use by tailjump. We don't want to allocate in rbp, -reg_class int_reg_no_rbp(EAX, EDX, EDI, ESI, ECX, EBX); +reg_class int_reg_with_ebp(EAX, EDX, EBP, EDI, ESI, ECX, EBX); +// Class for general registers (excluding EBP). +// This register class can be used for implicit null checks on win95. +// It is also safe for use by tailjumps (we don't want to allocate in ebp). +// Used also if the PreserveFramePointer flag is true. +reg_class int_reg_no_ebp(EAX, EDX, EDI, ESI, ECX, EBX); +// Dynamic register class that selects between int_reg and int_reg_no_ebp. +reg_class_dynamic int_reg(int_reg_no_ebp, int_reg_with_ebp, %{ PreserveFramePointer %}); + // Class of "X" registers reg_class int_x_reg(EBX, ECX, EDX, EAX); + // Class of registers that can appear in an address with no offset. // EBP and ESP require an extra instruction byte for zero offset. // Used in fast-unlock reg_class p_reg(EDX, EDI, ESI, EBX); -// Class for general registers not including ECX -reg_class ncx_reg(EAX, EDX, EBP, EDI, ESI, EBX); -// Class for general registers not including EAX + +// Class for general registers excluding ECX +reg_class ncx_reg_with_ebp(EAX, EDX, EBP, EDI, ESI, EBX); +// Class for general registers excluding ECX (and EBP) +reg_class ncx_reg_no_ebp(EAX, EDX, EDI, ESI, EBX); +// Dynamic register class that selects between ncx_reg and ncx_reg_no_ebp. +reg_class_dynamic ncx_reg(ncx_reg_no_ebp, ncx_reg_with_ebp, %{ PreserveFramePointer %}); + +// Class for general registers excluding EAX reg_class nax_reg(EDX, EDI, ESI, ECX, EBX); -// Class for general registers not including EAX or EBX. -reg_class nabx_reg(EDX, EDI, ESI, ECX, EBP); + +// Class for general registers excluding EAX and EBX. +reg_class nabx_reg_with_ebp(EDX, EDI, ESI, ECX, EBP); +// Class for general registers excluding EAX and EBX (and EBP) +reg_class nabx_reg_no_ebp(EDX, EDI, ESI, ECX); +// Dynamic register class that selects between nabx_reg and nabx_reg_no_ebp. +reg_class_dynamic nabx_reg(nabx_reg_no_ebp, nabx_reg_with_ebp, %{ PreserveFramePointer %}); + // Class of EAX (for multiply and divide operations) reg_class eax_reg(EAX); + // Class of EBX (for atomic add) reg_class ebx_reg(EBX); + // Class of ECX (for shift and JCXZ operations and cmpLTMask) reg_class ecx_reg(ECX); + // Class of EDX (for multiply and divide operations) reg_class edx_reg(EDX); + // Class of EDI (for synchronization) reg_class edi_reg(EDI); + // Class of ESI (for synchronization) reg_class esi_reg(ESI); -// Singleton class for interpreter's stack pointer -reg_class ebp_reg(EBP); + // Singleton class for stack pointer reg_class sp_reg(ESP); + // Singleton class for instruction pointer // reg_class ip_reg(EIP); + // Class of integer register pairs -reg_class long_reg( EAX,EDX, ECX,EBX, EBP,EDI ); +reg_class long_reg_with_ebp( EAX,EDX, ECX,EBX, EBP,EDI ); +// Class of integer register pairs (excluding EBP and EDI); +reg_class long_reg_no_ebp( EAX,EDX, ECX,EBX ); +// Dynamic register class that selects between long_reg and long_reg_no_ebp. +reg_class_dynamic long_reg(long_reg_no_ebp, long_reg_with_ebp, %{ PreserveFramePointer %}); + // Class of integer register pairs that aligns with calling convention reg_class eadx_reg( EAX,EDX ); reg_class ebcx_reg( ECX,EBX ); + // Not AX or DX, used in divides -reg_class nadx_reg( EBX,ECX,ESI,EDI,EBP ); +reg_class nadx_reg_with_ebp(EBX, ECX, ESI, EDI, EBP); +// Not AX or DX (and neither EBP), used in divides +reg_class nadx_reg_no_ebp(EBX, ECX, ESI, EDI); +// Dynamic register class that selects between nadx_reg and nadx_reg_no_ebp. +reg_class_dynamic nadx_reg(nadx_reg_no_ebp, nadx_reg_with_ebp, %{ PreserveFramePointer %}); // Floating point registers. Notice FPR0 is not a choice. // FPR0 is not ever allocated; we use clever encodings to fake @@ -240,18 +284,11 @@ return size; } -static int preserve_SP_size() { - return 2; // op, rm(reg/reg) -} - // !!!!! Special hack to get all type of calls to specify the byte offset // from the start of the call to the point where the return address // will point. int MachCallStaticJavaNode::ret_addr_offset() { - int offset = 5 + pre_call_resets_size(); // 5 bytes from start of call to where return address points - if (_method_handle_invoke) - offset += preserve_SP_size(); - return offset; + return 5 + pre_call_resets_size(); // 5 bytes from start of call to where return address points } int MachCallDynamicJavaNode::ret_addr_offset() { @@ -285,15 +322,6 @@ // The address of the call instruction needs to be 4-byte aligned to // ensure that it does not span a cache line so that it can be patched. -int CallStaticJavaHandleNode::compute_padding(int current_offset) const { - current_offset += pre_call_resets_size(); // skip fldcw, if any - current_offset += preserve_SP_size(); // skip mov rbp, rsp - current_offset += 1; // skip call opcode byte - return round_to(current_offset, alignment_required()) - current_offset; -} - -// The address of the call instruction needs to be 4-byte aligned to -// ensure that it does not span a cache line so that it can be patched. int CallDynamicJavaDirectNode::compute_padding(int current_offset) const { current_offset += pre_call_resets_size(); // skip fldcw, if any current_offset += 5; // skip MOV instruction @@ -523,6 +551,10 @@ st->print("# stack bang (%d bytes)", bangsize); st->print("\n\t"); st->print("PUSH EBP\t# Save EBP"); + if (PreserveFramePointer) { + st->print("\n\t"); + st->print("MOV EBP, ESP\t# Save the caller's SP into EBP"); + } if (framesize) { st->print("\n\t"); st->print("SUB ESP, #%d\t# Create frame",framesize); @@ -532,6 +564,10 @@ st->print("\n\t"); framesize -= wordSize; st->print("MOV [ESP + #%d], EBP\t# Save EBP",framesize); + if (PreserveFramePointer) { + st->print("\n\t"); + st->print("MOV EBP, [ESP + #%d]\t# Save the caller's SP into EBP", (framesize + wordSize)); + } } if (VerifyStackAtCalls) { @@ -1488,7 +1524,7 @@ } const RegMask Matcher::method_handle_invoke_SP_save_mask() { - return EBP_REG_mask(); + return NO_REG_mask(); } // Returns true if the high 32 bits of the value is known to be zero. @@ -3734,7 +3770,7 @@ // On windows95, EBP is not safe to use for implicit null tests. operand eRegP_no_EBP() %{ - constraint(ALLOC_IN_RC(int_reg_no_rbp)); + constraint(ALLOC_IN_RC(int_reg_no_ebp)); match(RegP); match(eAXRegP); match(eBXRegP); @@ -3823,13 +3859,6 @@ interface(REG_INTER); %} -operand eBPRegP() %{ - constraint(ALLOC_IN_RC(ebp_reg)); - match(RegP); - format %{ "EBP" %} - interface(REG_INTER); -%} - operand eRegL() %{ constraint(ALLOC_IN_RC(long_reg)); match(RegL); @@ -12708,7 +12737,6 @@ // compute_padding() functions will have to be adjusted. instruct CallStaticJavaDirect(method meth) %{ match(CallStaticJava); - predicate(! ((CallStaticJavaNode*)n)->is_method_handle_invoke()); effect(USE meth); ins_cost(300); @@ -12722,29 +12750,6 @@ ins_alignment(4); %} -// Call Java Static Instruction (method handle version) -// Note: If this code changes, the corresponding ret_addr_offset() and -// compute_padding() functions will have to be adjusted. -instruct CallStaticJavaHandle(method meth, eBPRegP ebp_mh_SP_save) %{ - match(CallStaticJava); - predicate(((CallStaticJavaNode*)n)->is_method_handle_invoke()); - effect(USE meth); - // EBP is saved by all callees (for interpreter stack correction). - // We use it here for a similar purpose, in {preserve,restore}_SP. - - ins_cost(300); - format %{ "CALL,static/MethodHandle " %} - opcode(0xE8); /* E8 cd */ - ins_encode( pre_call_resets, - preserve_SP, - Java_Static_Call( meth ), - restore_SP, - call_epilog, - post_call_FPU ); - ins_pipe( pipe_slow ); - ins_alignment(4); -%} - // Call Java Dynamic Instruction // Note: If this code changes, the corresponding ret_addr_offset() and // compute_padding() functions will have to be adjusted. diff -r c2687aa5e5ca -r 7eb99acd567f src/cpu/x86/vm/x86_64.ad --- a/src/cpu/x86/vm/x86_64.ad Mon Jan 25 14:56:57 2016 -0800 +++ b/src/cpu/x86/vm/x86_64.ad Mon Jan 25 14:57:27 2016 -0800 @@ -166,42 +166,67 @@ // 3) reg_class stack_slots( /* one chunk of stack-based "registers" */ ) // -// Class for all pointer registers (including RSP) -reg_class any_reg(RAX, RAX_H, - RDX, RDX_H, - RBP, RBP_H, - RDI, RDI_H, - RSI, RSI_H, - RCX, RCX_H, - RBX, RBX_H, - RSP, RSP_H, - R8, R8_H, - R9, R9_H, - R10, R10_H, - R11, R11_H, - R12, R12_H, - R13, R13_H, - R14, R14_H, - R15, R15_H); - -// Class for all pointer registers except RSP -reg_class ptr_reg(RAX, RAX_H, - RDX, RDX_H, - RBP, RBP_H, - RDI, RDI_H, - RSI, RSI_H, - RCX, RCX_H, - RBX, RBX_H, - R8, R8_H, - R9, R9_H, - R10, R10_H, - R11, R11_H, - R13, R13_H, - R14, R14_H); - -// Class for all pointer registers except RAX and RSP -reg_class ptr_no_rax_reg(RDX, RDX_H, - RBP, RBP_H, +// Empty register class. +reg_class no_reg(); + +// Class for all pointer registers (including RSP and RBP) +reg_class any_reg_with_rbp(RAX, RAX_H, + RDX, RDX_H, + RBP, RBP_H, + RDI, RDI_H, + RSI, RSI_H, + RCX, RCX_H, + RBX, RBX_H, + RSP, RSP_H, + R8, R8_H, + R9, R9_H, + R10, R10_H, + R11, R11_H, + R12, R12_H, + R13, R13_H, + R14, R14_H, + R15, R15_H); + +// Class for all pointer registers (including RSP, but excluding RBP) +reg_class any_reg_no_rbp(RAX, RAX_H, + RDX, RDX_H, + RDI, RDI_H, + RSI, RSI_H, + RCX, RCX_H, + RBX, RBX_H, + RSP, RSP_H, + R8, R8_H, + R9, R9_H, + R10, R10_H, + R11, R11_H, + R12, R12_H, + R13, R13_H, + R14, R14_H, + R15, R15_H); + +// Dynamic register class that selects at runtime between register classes +// any_reg_no_rbp and any_reg_with_rbp (depending on the value of the flag PreserveFramePointer). +// Equivalent to: return PreserveFramePointer ? any_reg_no_rbp : any_reg_with_rbp; +reg_class_dynamic any_reg(any_reg_no_rbp, any_reg_with_rbp, %{ PreserveFramePointer %}); + +// Class for all pointer registers (excluding RSP) +reg_class ptr_reg_with_rbp(RAX, RAX_H, + RDX, RDX_H, + RBP, RBP_H, + RDI, RDI_H, + RSI, RSI_H, + RCX, RCX_H, + RBX, RBX_H, + R8, R8_H, + R9, R9_H, + R10, R10_H, + R11, R11_H, + R13, R13_H, + R14, R14_H); + +// Class for all pointer registers (excluding RSP and RBP) +reg_class ptr_reg_no_rbp(RAX, RAX_H, + RDX, RDX_H, RDI, RDI_H, RSI, RSI_H, RCX, RCX_H, @@ -213,31 +238,66 @@ R13, R13_H, R14, R14_H); -reg_class ptr_no_rbp_reg(RDX, RDX_H, - RAX, RAX_H, - RDI, RDI_H, - RSI, RSI_H, - RCX, RCX_H, - RBX, RBX_H, - R8, R8_H, - R9, R9_H, - R10, R10_H, - R11, R11_H, - R13, R13_H, - R14, R14_H); - -// Class for all pointer registers except RAX, RBX and RSP -reg_class ptr_no_rax_rbx_reg(RDX, RDX_H, - RBP, RBP_H, - RDI, RDI_H, - RSI, RSI_H, - RCX, RCX_H, - R8, R8_H, - R9, R9_H, - R10, R10_H, - R11, R11_H, - R13, R13_H, - R14, R14_H); +// Dynamic register class that selects between ptr_reg_no_rbp and ptr_reg_with_rbp. +reg_class_dynamic ptr_reg(ptr_reg_no_rbp, ptr_reg_with_rbp, %{ PreserveFramePointer %}); + +// Class for all pointer registers (excluding RAX and RSP) +reg_class ptr_no_rax_reg_with_rbp(RDX, RDX_H, + RBP, RBP_H, + RDI, RDI_H, + RSI, RSI_H, + RCX, RCX_H, + RBX, RBX_H, + R8, R8_H, + R9, R9_H, + R10, R10_H, + R11, R11_H, + R13, R13_H, + R14, R14_H); + +// Class for all pointer registers (excluding RAX, RSP, and RBP) +reg_class ptr_no_rax_reg_no_rbp(RDX, RDX_H, + RDI, RDI_H, + RSI, RSI_H, + RCX, RCX_H, + RBX, RBX_H, + R8, R8_H, + R9, R9_H, + R10, R10_H, + R11, R11_H, + R13, R13_H, + R14, R14_H); + +// Dynamic register class that selects between ptr_no_rax_reg_no_rbp and ptr_no_rax_reg_with_rbp. +reg_class_dynamic ptr_no_rax_reg(ptr_no_rax_reg_no_rbp, ptr_no_rax_reg_with_rbp, %{ PreserveFramePointer %}); + +// Class for all pointer registers (excluding RAX, RBX, and RSP) +reg_class ptr_no_rax_rbx_reg_with_rbp(RDX, RDX_H, + RBP, RBP_H, + RDI, RDI_H, + RSI, RSI_H, + RCX, RCX_H, + R8, R8_H, + R9, R9_H, + R10, R10_H, + R11, R11_H, + R13, R13_H, + R14, R14_H); + +// Class for all pointer registers (excluding RAX, RBX, RSP, and RBP) +reg_class ptr_no_rax_rbx_reg_no_rbp(RDX, RDX_H, + RDI, RDI_H, + RSI, RSI_H, + RCX, RCX_H, + R8, R8_H, + R9, R9_H, + R10, R10_H, + R11, R11_H, + R13, R13_H, + R14, R14_H); + +// Dynamic register class that selects between ptr_no_rax_rbx_reg_no_rbp and ptr_no_rax_rbx_reg_with_rbp. +reg_class_dynamic ptr_no_rax_rbx_reg(ptr_no_rax_rbx_reg_no_rbp, ptr_no_rax_rbx_reg_with_rbp, %{ PreserveFramePointer %}); // Singleton class for RAX pointer register reg_class ptr_rax_reg(RAX, RAX_H); @@ -251,59 +311,29 @@ // Singleton class for RDI pointer register reg_class ptr_rdi_reg(RDI, RDI_H); -// Singleton class for RBP pointer register -reg_class ptr_rbp_reg(RBP, RBP_H); - // Singleton class for stack pointer reg_class ptr_rsp_reg(RSP, RSP_H); // Singleton class for TLS pointer reg_class ptr_r15_reg(R15, R15_H); -// Class for all long registers (except RSP) -reg_class long_reg(RAX, RAX_H, - RDX, RDX_H, - RBP, RBP_H, - RDI, RDI_H, - RSI, RSI_H, - RCX, RCX_H, - RBX, RBX_H, - R8, R8_H, - R9, R9_H, - R10, R10_H, - R11, R11_H, - R13, R13_H, - R14, R14_H); - -// Class for all long registers except RAX, RDX (and RSP) -reg_class long_no_rax_rdx_reg(RBP, RBP_H, - RDI, RDI_H, - RSI, RSI_H, - RCX, RCX_H, - RBX, RBX_H, - R8, R8_H, - R9, R9_H, - R10, R10_H, - R11, R11_H, - R13, R13_H, - R14, R14_H); - -// Class for all long registers except RCX (and RSP) -reg_class long_no_rcx_reg(RBP, RBP_H, - RDI, RDI_H, - RSI, RSI_H, - RAX, RAX_H, - RDX, RDX_H, - RBX, RBX_H, - R8, R8_H, - R9, R9_H, - R10, R10_H, - R11, R11_H, - R13, R13_H, - R14, R14_H); - -// Class for all long registers except RAX (and RSP) -reg_class long_no_rax_reg(RBP, RBP_H, +// Class for all long registers (excluding RSP) +reg_class long_reg_with_rbp(RAX, RAX_H, + RDX, RDX_H, + RBP, RBP_H, + RDI, RDI_H, + RSI, RSI_H, + RCX, RCX_H, + RBX, RBX_H, + R8, R8_H, + R9, R9_H, + R10, R10_H, + R11, R11_H, + R13, R13_H, + R14, R14_H); + +// Class for all long registers (excluding RSP and RBP) +reg_class long_reg_no_rbp(RAX, RAX_H, RDX, RDX_H, RDI, RDI_H, RSI, RSI_H, @@ -316,6 +346,67 @@ R13, R13_H, R14, R14_H); +// Dynamic register class that selects between long_reg_no_rbp and long_reg_with_rbp. +reg_class_dynamic long_reg(long_reg_no_rbp, long_reg_with_rbp, %{ PreserveFramePointer %}); + +// Class for all long registers (excluding RAX, RDX and RSP) +reg_class long_no_rax_rdx_reg_with_rbp(RBP, RBP_H, + RDI, RDI_H, + RSI, RSI_H, + RCX, RCX_H, + RBX, RBX_H, + R8, R8_H, + R9, R9_H, + R10, R10_H, + R11, R11_H, + R13, R13_H, + R14, R14_H); + +// Class for all long registers (excluding RAX, RDX, RSP, and RBP) +reg_class long_no_rax_rdx_reg_no_rbp(RDI, RDI_H, + RSI, RSI_H, + RCX, RCX_H, + RBX, RBX_H, + R8, R8_H, + R9, R9_H, + R10, R10_H, + R11, R11_H, + R13, R13_H, + R14, R14_H); + +// Dynamic register class that selects between long_no_rax_rdx_reg_no_rbp and long_no_rax_rdx_reg_with_rbp. +reg_class_dynamic long_no_rax_rdx_reg(long_no_rax_rdx_reg_no_rbp, long_no_rax_rdx_reg_with_rbp, %{ PreserveFramePointer %}); + +// Class for all long registers (excluding RCX and RSP) +reg_class long_no_rcx_reg_with_rbp(RBP, RBP_H, + RDI, RDI_H, + RSI, RSI_H, + RAX, RAX_H, + RDX, RDX_H, + RBX, RBX_H, + R8, R8_H, + R9, R9_H, + R10, R10_H, + R11, R11_H, + R13, R13_H, + R14, R14_H); + +// Class for all long registers (excluding RCX, RSP, and RBP) +reg_class long_no_rcx_reg_no_rbp(RDI, RDI_H, + RSI, RSI_H, + RAX, RAX_H, + RDX, RDX_H, + RBX, RBX_H, + R8, R8_H, + R9, R9_H, + R10, R10_H, + R11, R11_H, + R13, R13_H, + R14, R14_H); + +// Dynamic register class that selects between long_no_rcx_reg_no_rbp and long_no_rcx_reg_with_rbp. +reg_class_dynamic long_no_rcx_reg(long_no_rcx_reg_no_rbp, long_no_rcx_reg_with_rbp, %{ PreserveFramePointer %}); + // Singleton class for RAX long register reg_class long_rax_reg(RAX, RAX_H); @@ -325,27 +416,27 @@ // Singleton class for RDX long register reg_class long_rdx_reg(RDX, RDX_H); -// Class for all int registers (except RSP) -reg_class int_reg(RAX, - RDX, - RBP, - RDI, - RSI, - RCX, - RBX, - R8, - R9, - R10, - R11, - R13, - R14); - -// Class for all int registers except RCX (and RSP) -reg_class int_no_rcx_reg(RAX, +// Class for all int registers (excluding RSP) +reg_class int_reg_with_rbp(RAX, + RDX, + RBP, + RDI, + RSI, + RCX, + RBX, + R8, + R9, + R10, + R11, + R13, + R14); + +// Class for all int registers (excluding RSP and RBP) +reg_class int_reg_no_rbp(RAX, RDX, - RBP, RDI, RSI, + RCX, RBX, R8, R9, @@ -354,18 +445,66 @@ R13, R14); -// Class for all int registers except RAX, RDX (and RSP) -reg_class int_no_rax_rdx_reg(RBP, - RDI, - RSI, - RCX, - RBX, - R8, - R9, - R10, - R11, - R13, - R14); +// Dynamic register class that selects between int_reg_no_rbp and int_reg_with_rbp. +reg_class_dynamic int_reg(int_reg_no_rbp, int_reg_with_rbp, %{ PreserveFramePointer %}); + +// Class for all int registers (excluding RCX and RSP) +reg_class int_no_rcx_reg_with_rbp(RAX, + RDX, + RBP, + RDI, + RSI, + RBX, + R8, + R9, + R10, + R11, + R13, + R14); + +// Class for all int registers (excluding RCX, RSP, and RBP) +reg_class int_no_rcx_reg_no_rbp(RAX, + RDX, + RDI, + RSI, + RBX, + R8, + R9, + R10, + R11, + R13, + R14); + +// Dynamic register class that selects between int_no_rcx_reg_no_rbp and int_no_rcx_reg_with_rbp. +reg_class_dynamic int_no_rcx_reg(int_no_rcx_reg_no_rbp, int_no_rcx_reg_with_rbp, %{ PreserveFramePointer %}); + +// Class for all int registers (excluding RAX, RDX, and RSP) +reg_class int_no_rax_rdx_reg_with_rbp(RBP, + RDI, + RSI, + RCX, + RBX, + R8, + R9, + R10, + R11, + R13, + R14); + +// Class for all int registers (excluding RAX, RDX, RSP, and RBP) +reg_class int_no_rax_rdx_reg_no_rbp(RDI, + RSI, + RCX, + RBX, + R8, + R9, + R10, + R11, + R13, + R14); + +// Dynamic register class that selects between int_no_rax_rdx_reg_no_rbp and int_no_rax_rdx_reg_with_rbp. +reg_class_dynamic int_no_rax_rdx_reg(int_no_rax_rdx_reg_no_rbp, int_no_rax_rdx_reg_with_rbp, %{ PreserveFramePointer %}); // Singleton class for RAX int register reg_class int_rax_reg(RAX); @@ -396,9 +535,6 @@ #define __ _masm. -static int preserve_SP_size() { - return 3; // rex.w, op, rm(reg/reg) -} static int clear_avx_size() { return (Compile::current()->max_vector_size() > 16) ? 3 : 0; // vzeroupper } @@ -409,9 +545,7 @@ int MachCallStaticJavaNode::ret_addr_offset() { int offset = 5; // 5 bytes from start of call to where return address points - offset += clear_avx_size(); - if (_method_handle_invoke) - offset += preserve_SP_size(); + offset += clear_avx_size(); return offset; } @@ -450,16 +584,6 @@ // The address of the call instruction needs to be 4-byte aligned to // ensure that it does not span a cache line so that it can be patched. -int CallStaticJavaHandleNode::compute_padding(int current_offset) const -{ - current_offset += preserve_SP_size(); // skip mov rbp, rsp - current_offset += clear_avx_size(); // skip vzeroupper - current_offset += 1; // skip call opcode byte - return round_to(current_offset, alignment_required()) - current_offset; -} - -// The address of the call instruction needs to be 4-byte aligned to -// ensure that it does not span a cache line so that it can be patched. int CallDynamicJavaDirectNode::compute_padding(int current_offset) const { current_offset += clear_avx_size(); // skip vzeroupper @@ -724,6 +848,10 @@ st->print("# stack bang (%d bytes)", bangsize); st->print("\n\t"); st->print("pushq rbp\t# Save rbp"); + if (PreserveFramePointer) { + st->print("\n\t"); + st->print("movq rbp, rsp\t# Save the caller's SP into rbp"); + } if (framesize) { st->print("\n\t"); st->print("subq rsp, #%d\t# Create frame",framesize); @@ -732,7 +860,11 @@ st->print("subq rsp, #%d\t# Create frame",framesize); st->print("\n\t"); framesize -= wordSize; - st->print("movq [rsp + #%d], rbp\t# Save rbp",framesize); + st->print("movq [rsp + #%d], rbp\t# Save rbp",framesize); + if (PreserveFramePointer) { + st->print("\n\t"); + st->print("movq rbp, [rsp + #%d]\t# Save the caller's SP into rbp", (framesize + wordSize)); + } } if (VerifyStackAtCalls) { @@ -1598,8 +1730,9 @@ return LONG_RDX_REG_mask(); } +// Register for saving SP into on method handle invokes. Not used on x86_64. const RegMask Matcher::method_handle_invoke_SP_save_mask() { - return PTR_RBP_REG_mask(); + return NO_REG_mask(); } %} @@ -3202,7 +3335,7 @@ // Pointer Register operand any_RegP() %{ - constraint(ALLOC_IN_RC(any_reg)); + constraint(ALLOC_IN_RC(any_reg)); match(RegP); match(rax_RegP); match(rbx_RegP); @@ -3224,8 +3357,8 @@ match(rbx_RegP); match(rdi_RegP); match(rsi_RegP); - match(rbp_RegP); - match(r15_RegP); // See Q&A below about r15_RegP. + match(rbp_RegP); // See Q&A below about + match(r15_RegP); // r15_RegP and rbp_RegP. format %{ %} interface(REG_INTER); @@ -3241,11 +3374,14 @@ // Question: Why is r15_RegP (the read-only TLS register) a match for rRegP? // Answer: Operand match rules govern the DFA as it processes instruction inputs. -// It's fine for an instruction input which expects rRegP to match a r15_RegP. +// It's fine for an instruction input that expects rRegP to match a r15_RegP. // The output of an instruction is controlled by the allocator, which respects // register class masks, not match rules. Unless an instruction mentions // r15_RegP or any_RegP explicitly as its output, r15 will not be considered // by the allocator as an input. +// The same logic applies to rbp_RegP being a match for rRegP: If PreserveFramePointer==true, +// the RBP is used as a proper frame pointer and is not included in ptr_reg. As a +// result, RBP is not included in the output of the instruction either. operand no_rax_RegP() %{ @@ -3259,9 +3395,11 @@ interface(REG_INTER); %} +// This operand is not allowed to use RBP even if +// RBP is not used to hold the frame pointer. operand no_rbp_RegP() %{ - constraint(ALLOC_IN_RC(ptr_no_rbp_reg)); + constraint(ALLOC_IN_RC(ptr_reg_no_rbp)); match(RegP); match(rbx_RegP); match(rsi_RegP); @@ -3338,16 +3476,6 @@ interface(REG_INTER); %} -operand rbp_RegP() -%{ - constraint(ALLOC_IN_RC(ptr_rbp_reg)); - match(RegP); - match(rRegP); - - format %{ %} - interface(REG_INTER); -%} - operand r15_RegP() %{ constraint(ALLOC_IN_RC(ptr_r15_reg)); @@ -11414,7 +11542,6 @@ // compute_padding() functions will have to be adjusted. instruct CallStaticJavaDirect(method meth) %{ match(CallStaticJava); - predicate(!((CallStaticJavaNode*) n)->is_method_handle_invoke()); effect(USE meth); ins_cost(300); @@ -11425,27 +11552,6 @@ ins_alignment(4); %} -// Call Java Static Instruction (method handle version) -// Note: If this code changes, the corresponding ret_addr_offset() and -// compute_padding() functions will have to be adjusted. -instruct CallStaticJavaHandle(method meth, rbp_RegP rbp_mh_SP_save) %{ - match(CallStaticJava); - predicate(((CallStaticJavaNode*) n)->is_method_handle_invoke()); - effect(USE meth); - // RBP is saved by all callees (for interpreter stack correction). - // We use it here for a similar purpose, in {preserve,restore}_SP. - - ins_cost(300); - format %{ "call,static/MethodHandle " %} - opcode(0xE8); /* E8 cd */ - ins_encode(clear_avx, preserve_SP, - Java_Static_Call(meth), - restore_SP, - call_epilog); - ins_pipe(pipe_slow); - ins_alignment(4); -%} - // Call Java Dynamic Instruction // Note: If this code changes, the corresponding ret_addr_offset() and // compute_padding() functions will have to be adjusted. diff -r c2687aa5e5ca -r 7eb99acd567f src/cpu/zero/vm/cppInterpreter_zero.cpp --- a/src/cpu/zero/vm/cppInterpreter_zero.cpp Mon Jan 25 14:56:57 2016 -0800 +++ b/src/cpu/zero/vm/cppInterpreter_zero.cpp Mon Jan 25 14:57:27 2016 -0800 @@ -730,7 +730,7 @@ if (method->is_static()) object = method->constants()->pool_holder()->java_mirror(); else - object = (oop) locals[0]; + object = (oop) (void*)locals[0]; monitor->set_obj(object); } diff -r c2687aa5e5ca -r 7eb99acd567f src/cpu/zero/vm/frame_zero.cpp --- a/src/cpu/zero/vm/frame_zero.cpp Mon Jan 25 14:56:57 2016 -0800 +++ b/src/cpu/zero/vm/frame_zero.cpp Mon Jan 25 14:57:27 2016 -0800 @@ -441,3 +441,10 @@ // unused... but returns fp() to minimize changes introduced by 7087445 return fp(); } + +#ifndef PRODUCT +// This is a generic constructor which is only used by pns() in debug.cpp. +frame::frame(void* sp, void* fp, void* pc) { + Unimplemented(); +} +#endif diff -r c2687aa5e5ca -r 7eb99acd567f src/cpu/zero/vm/frame_zero.inline.hpp --- a/src/cpu/zero/vm/frame_zero.inline.hpp Mon Jan 25 14:56:57 2016 -0800 +++ b/src/cpu/zero/vm/frame_zero.inline.hpp Mon Jan 25 14:57:27 2016 -0800 @@ -26,6 +26,8 @@ #ifndef CPU_ZERO_VM_FRAME_ZERO_INLINE_HPP #define CPU_ZERO_VM_FRAME_ZERO_INLINE_HPP +#include "code/codeCache.hpp" + // Constructors inline frame::frame() { diff -r c2687aa5e5ca -r 7eb99acd567f src/cpu/zero/vm/globals_zero.hpp --- a/src/cpu/zero/vm/globals_zero.hpp Mon Jan 25 14:56:57 2016 -0800 +++ b/src/cpu/zero/vm/globals_zero.hpp Mon Jan 25 14:57:27 2016 -0800 @@ -61,6 +61,8 @@ define_pd_global(uintx, TypeProfileLevel, 0); +define_pd_global(bool, PreserveFramePointer, false); + #define ARCH_FLAGS(develop, product, diagnostic, experimental, notproduct) #endif // CPU_ZERO_VM_GLOBALS_ZERO_HPP diff -r c2687aa5e5ca -r 7eb99acd567f src/cpu/zero/vm/stack_zero.cpp --- a/src/cpu/zero/vm/stack_zero.cpp Mon Jan 25 14:56:57 2016 -0800 +++ b/src/cpu/zero/vm/stack_zero.cpp Mon Jan 25 14:57:27 2016 -0800 @@ -30,7 +30,9 @@ int ZeroStack::suggest_size(Thread *thread) const { assert(needs_setup(), "already set up"); - return align_size_down(abi_stack_available(thread) / 2, wordSize); + int abi_available = abi_stack_available(thread); + assert(abi_available >= 0, "available abi stack must be >= 0"); + return align_size_down(abi_available / 2, wordSize); } void ZeroStack::handle_overflow(TRAPS) { diff -r c2687aa5e5ca -r 7eb99acd567f src/cpu/zero/vm/stack_zero.inline.hpp --- a/src/cpu/zero/vm/stack_zero.inline.hpp Mon Jan 25 14:56:57 2016 -0800 +++ b/src/cpu/zero/vm/stack_zero.inline.hpp Mon Jan 25 14:57:27 2016 -0800 @@ -48,9 +48,11 @@ // to use under normal circumstances. Note that the returned // value can be negative. inline int ZeroStack::abi_stack_available(Thread *thread) const { - int stack_used = thread->stack_base() - (address) &stack_used; + guarantee(Thread::current() == thread, "should run in the same thread"); + int stack_used = thread->stack_base() - (address) &stack_used + + (StackYellowPages+StackRedPages+StackShadowPages) * os::vm_page_size(); int stack_free = thread->stack_size() - stack_used; - return stack_free - shadow_pages_size(); + return stack_free; } #endif // CPU_ZERO_VM_STACK_ZERO_INLINE_HPP diff -r c2687aa5e5ca -r 7eb99acd567f src/os/aix/vm/os_aix.cpp --- a/src/os/aix/vm/os_aix.cpp Mon Jan 25 14:56:57 2016 -0800 +++ b/src/os/aix/vm/os_aix.cpp Mon Jan 25 14:57:27 2016 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2015, 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. * @@ -3727,6 +3727,11 @@ tty->print_cr(" found:%s", get_signal_handler_name(thisHandler, buf, O_BUFLEN)); // No need to check this sig any longer sigaddset(&check_signal_done, sig); + // Running under non-interactive shell, SHUTDOWN2_SIGNAL will be reassigned SIG_IGN + if (sig == SHUTDOWN2_SIGNAL && !isatty(fileno(stdin))) { + tty->print_cr("Running in non-interactive shell, %s handler is replaced by shell", + exception_name(sig, buf, O_BUFLEN)); + } } else if (os::Aix::get_our_sigflags(sig) != 0 && (int)act.sa_flags != os::Aix::get_our_sigflags(sig)) { tty->print("Warning: %s handler flags ", exception_name(sig, buf, O_BUFLEN)); tty->print("expected:" PTR32_FORMAT, os::Aix::get_our_sigflags(sig)); @@ -3987,11 +3992,6 @@ return JNI_OK; } -// this is called at the end of vm_initialization -void os::init_3(void) { - return; -} - // Mark the polling page as unreadable void os::make_polling_page_unreadable(void) { if (!guard_memory((char*)_polling_page, Aix::page_size())) { diff -r c2687aa5e5ca -r 7eb99acd567f src/os/bsd/vm/jsig.c --- a/src/os/bsd/vm/jsig.c Mon Jan 25 14:56:57 2016 -0800 +++ b/src/os/bsd/vm/jsig.c Mon Jan 25 14:57:27 2016 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 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 @@ -36,6 +36,7 @@ #include #include #include +#include #define MAXSIGNUM 32 #define MASK(sig) ((unsigned int)1 << sig) @@ -43,6 +44,9 @@ static struct sigaction sact[MAXSIGNUM]; /* saved signal handlers */ static unsigned int jvmsigs = 0; /* signals used by jvm */ +static pthread_key_t reentry_flag_key; +static pthread_once_t reentry_key_init_once = PTHREAD_ONCE_INIT; + /* used to synchronize the installation of signal handlers */ static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; static pthread_cond_t cond = PTHREAD_COND_INITIALIZER; @@ -59,6 +63,15 @@ static bool jvm_signal_installing = false; static bool jvm_signal_installed = false; +#define check_status(cmd) \ + do { \ + int status = (cmd); \ + if (status != 0) { \ + printf("error %s (%d) in " #cmd "\n", strerror(status), status); \ + exit(1); \ + } \ + } while (0) + static void signal_lock() { pthread_mutex_lock(&mutex); /* When the jvm is installing its set of signal handlers, threads @@ -74,8 +87,15 @@ pthread_mutex_unlock(&mutex); } +static void reentry_tls_init() { + // value for reentry_flag_key will default to NULL (false) + check_status(pthread_key_create(&reentry_flag_key, NULL)); +} + static sa_handler_t call_os_signal(int sig, sa_handler_t disp, bool is_sigset) { + sa_handler_t res; + if (os_signal == NULL) { if (!is_sigset) { os_signal = (signal_t)dlsym(RTLD_NEXT, "signal"); @@ -87,7 +107,12 @@ exit(0); } } - return (*os_signal)(sig, disp); + check_status(pthread_once(&reentry_key_init_once, reentry_tls_init)); + // set reentry_flag_key to non-NULL to show reentry + check_status(pthread_setspecific(reentry_flag_key, &res)); + res = (*os_signal)(sig, disp); + check_status(pthread_setspecific(reentry_flag_key, NULL)); + return res; } static void save_signal_handler(int sig, sa_handler_t disp) { @@ -161,6 +186,11 @@ bool sigused; struct sigaction oldAct; + check_status(pthread_once(&reentry_key_init_once, reentry_tls_init)); + if (pthread_getspecific(reentry_flag_key) != NULL) { + return call_os_sigaction(sig, act, oact); + } + signal_lock(); sigused = (MASK(sig) & jvmsigs) != 0; diff -r c2687aa5e5ca -r 7eb99acd567f src/os/bsd/vm/os_bsd.cpp --- a/src/os/bsd/vm/os_bsd.cpp Mon Jan 25 14:56:57 2016 -0800 +++ b/src/os/bsd/vm/os_bsd.cpp Mon Jan 25 14:57:27 2016 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 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 @@ -1197,12 +1197,18 @@ guarantee(retval != 0, "just checking"); return retval; -#elif __FreeBSD__ +#else + #ifdef __FreeBSD__ retval = syscall(SYS_thr_self); -#elif __OpenBSD__ + #else + #ifdef __OpenBSD__ retval = syscall(SYS_getthrid); -#elif __NetBSD__ + #else + #ifdef __NetBSD__ retval = (pid_t) syscall(SYS__lwp_self); + #endif + #endif + #endif #endif if (retval == -1) { @@ -3545,6 +3551,11 @@ tty->print_cr(" found:%s", get_signal_handler_name(thisHandler, buf, O_BUFLEN)); // No need to check this sig any longer sigaddset(&check_signal_done, sig); + // Running under non-interactive shell, SHUTDOWN2_SIGNAL will be reassigned SIG_IGN + if (sig == SHUTDOWN2_SIGNAL && !isatty(fileno(stdin))) { + tty->print_cr("Running in non-interactive shell, %s handler is replaced by shell", + exception_name(sig, buf, O_BUFLEN)); + } } else if(os::Bsd::get_our_sigflags(sig) != 0 && (int)act.sa_flags != os::Bsd::get_our_sigflags(sig)) { tty->print("Warning: %s handler flags ", exception_name(sig, buf, O_BUFLEN)); tty->print("expected:" PTR32_FORMAT, os::Bsd::get_our_sigflags(sig)); @@ -3745,9 +3756,6 @@ return JNI_OK; } -// this is called at the end of vm_initialization -void os::init_3(void) { } - // Mark the polling page as unreadable void os::make_polling_page_unreadable(void) { if( !guard_memory((char*)_polling_page, Bsd::page_size()) ) diff -r c2687aa5e5ca -r 7eb99acd567f src/os/linux/vm/os_linux.cpp --- a/src/os/linux/vm/os_linux.cpp Mon Jan 25 14:56:57 2016 -0800 +++ b/src/os/linux/vm/os_linux.cpp Mon Jan 25 14:57:27 2016 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 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 @@ -160,35 +160,6 @@ // Declarations static void unpackTime(timespec* absTime, bool isAbsolute, jlong time); -#ifdef JAVASE_EMBEDDED -class MemNotifyThread: public Thread { - friend class VMStructs; - public: - virtual void run(); - - private: - static MemNotifyThread* _memnotify_thread; - int _fd; - - public: - - // Constructor - MemNotifyThread(int fd); - - // Tester - bool is_memnotify_thread() const { return true; } - - // Printing - char* name() const { return (char*)"Linux MemNotify Thread"; } - - // Returns the single instance of the MemNotifyThread - static MemNotifyThread* memnotify_thread() { return _memnotify_thread; } - - // Create and start the single instance of MemNotifyThread - static void start(); -}; -#endif // JAVASE_EMBEDDED - // utility functions static int SR_initialize(); @@ -238,44 +209,27 @@ #ifndef SYS_gettid // i386: 224, ia64: 1105, amd64: 186, sparc 143 -#ifdef __ia64__ -#define SYS_gettid 1105 -#elif __i386__ -#define SYS_gettid 224 -#elif __amd64__ -#define SYS_gettid 186 -#elif __sparc__ -#define SYS_gettid 143 -#else -#error define gettid for the arch -#endif + #ifdef __ia64__ + #define SYS_gettid 1105 + #else + #ifdef __i386__ + #define SYS_gettid 224 + #else + #ifdef __amd64__ + #define SYS_gettid 186 + #else + #ifdef __sparc__ + #define SYS_gettid 143 + #else + #error define gettid for the arch + #endif + #endif + #endif + #endif #endif // Cpu architecture string -#if defined(ZERO) -static char cpu_arch[] = ZERO_LIBARCH; -#elif defined(IA64) -static char cpu_arch[] = "ia64"; -#elif defined(IA32) -static char cpu_arch[] = "i386"; -#elif defined(AMD64) -static char cpu_arch[] = "amd64"; -#elif defined(ARM) -static char cpu_arch[] = "arm"; -#elif defined(PPC32) -static char cpu_arch[] = "ppc"; -#elif defined(PPC64) -static char cpu_arch[] = "ppc64"; -#elif defined(SPARC) -# ifdef _LP64 -static char cpu_arch[] = "sparcv9"; -# else -static char cpu_arch[] = "sparc"; -# endif -#else -#error Add appropriate cpu_arch setting -#endif - +static char cpu_arch[] = HOTSPOT_LIB_ARCH; // pid_t gettid() // @@ -4681,6 +4635,11 @@ tty->print_cr(" found:%s", get_signal_handler_name(thisHandler, buf, O_BUFLEN)); // No need to check this sig any longer sigaddset(&check_signal_done, sig); + // Running under non-interactive shell, SHUTDOWN2_SIGNAL will be reassigned SIG_IGN + if (sig == SHUTDOWN2_SIGNAL && !isatty(fileno(stdin))) { + tty->print_cr("Running in non-interactive shell, %s handler is replaced by shell", + exception_name(sig, buf, O_BUFLEN)); + } } else if(os::Linux::get_our_sigflags(sig) != 0 && (int)act.sa_flags != os::Linux::get_our_sigflags(sig)) { tty->print("Warning: %s handler flags ", exception_name(sig, buf, O_BUFLEN)); tty->print("expected:" PTR32_FORMAT, os::Linux::get_our_sigflags(sig)); @@ -4936,17 +4895,6 @@ return JNI_OK; } -// this is called at the end of vm_initialization -void os::init_3(void) { -#ifdef JAVASE_EMBEDDED - // Start the MemNotifyThread - if (LowMemoryProtection) { - MemNotifyThread::start(); - } - return; -#endif -} - // Mark the polling page as unreadable void os::make_polling_page_unreadable(void) { if( !guard_memory((char*)_polling_page, Linux::page_size()) ) @@ -5992,14 +5940,6 @@ extern char** environ; -#ifndef __NR_fork -#define __NR_fork IA32_ONLY(2) IA64_ONLY(not defined) AMD64_ONLY(57) -#endif - -#ifndef __NR_execve -#define __NR_execve IA32_ONLY(11) IA64_ONLY(1033) AMD64_ONLY(59) -#endif - // Run the specified command in a separate process. Return its exit value, // or -1 on failure (e.g. can't fork a new process). // Unlike system(), this function can be called from signal handler. It @@ -6007,13 +5947,7 @@ int os::fork_and_exec(char* cmd) { const char * argv[4] = {"sh", "-c", cmd, NULL}; - // fork() in LinuxThreads/NPTL is not async-safe. It needs to run - // pthread_atfork handlers and reset pthread library. All we need is a - // separate process to execve. Make a direct syscall to fork process. - // On IA64 there's no fork syscall, we have to use fork() and hope for - // the best... - pid_t pid = NOT_IA64(syscall(__NR_fork);) - IA64_ONLY(fork();) + pid_t pid = fork(); if (pid < 0) { // fork failed @@ -6022,15 +5956,7 @@ } else if (pid == 0) { // child process - // execve() in LinuxThreads will call pthread_kill_other_threads_np() - // first to kill every thread on the thread list. Because this list is - // not reset by fork() (see notes above), execve() will instead kill - // every thread in the parent process. We know this is the only thread - // in the new process, so make a system call directly. - // IA64 should use normal execve() from glibc to match the glibc fork() - // above. - NOT_IA64(syscall(__NR_execve, "/bin/sh", argv, environ);) - IA64_ONLY(execve("/bin/sh", (char* const*)argv, environ);) + execve("/bin/sh", (char* const*)argv, environ); // execve failed _exit(-1); @@ -6123,83 +6049,6 @@ return strlen(buffer); } -#ifdef JAVASE_EMBEDDED -// -// A thread to watch the '/dev/mem_notify' device, which will tell us when the OS is running low on memory. -// -MemNotifyThread* MemNotifyThread::_memnotify_thread = NULL; - -// ctor -// -MemNotifyThread::MemNotifyThread(int fd): Thread() { - assert(memnotify_thread() == NULL, "we can only allocate one MemNotifyThread"); - _fd = fd; - - if (os::create_thread(this, os::os_thread)) { - _memnotify_thread = this; - os::set_priority(this, NearMaxPriority); - os::start_thread(this); - } -} - -// Where all the work gets done -// -void MemNotifyThread::run() { - assert(this == memnotify_thread(), "expected the singleton MemNotifyThread"); - - // Set up the select arguments - fd_set rfds; - if (_fd != -1) { - FD_ZERO(&rfds); - FD_SET(_fd, &rfds); - } - - // Now wait for the mem_notify device to wake up - while (1) { - // Wait for the mem_notify device to signal us.. - int rc = select(_fd+1, _fd != -1 ? &rfds : NULL, NULL, NULL, NULL); - if (rc == -1) { - perror("select!\n"); - break; - } else if (rc) { - //ssize_t free_before = os::available_memory(); - //tty->print ("Notified: Free: %dK \n",os::available_memory()/1024); - - // The kernel is telling us there is not much memory left... - // try to do something about that - - // If we are not already in a GC, try one. - if (!Universe::heap()->is_gc_active()) { - Universe::heap()->collect(GCCause::_allocation_failure); - - //ssize_t free_after = os::available_memory(); - //tty->print ("Post-Notify: Free: %dK\n",free_after/1024); - //tty->print ("GC freed: %dK\n", (free_after - free_before)/1024); - } - // We might want to do something like the following if we find the GC's are not helping... - // Universe::heap()->size_policy()->set_gc_time_limit_exceeded(true); - } - } -} - -// -// See if the /dev/mem_notify device exists, and if so, start a thread to monitor it. -// -void MemNotifyThread::start() { - int fd; - fd = open ("/dev/mem_notify", O_RDONLY, 0); - if (fd < 0) { - return; - } - - if (memnotify_thread() == NULL) { - new MemNotifyThread(fd); - } -} - -#endif // JAVASE_EMBEDDED - - /////////////// Unit tests /////////////// #ifndef PRODUCT diff -r c2687aa5e5ca -r 7eb99acd567f src/os/solaris/vm/jvm_solaris.h --- a/src/os/solaris/vm/jvm_solaris.h Mon Jan 25 14:56:57 2016 -0800 +++ b/src/os/solaris/vm/jvm_solaris.h Mon Jan 25 14:57:27 2016 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 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 @@ -40,6 +40,7 @@ * This file is currently collecting system-specific dregs for the * JNI conversion, which should be sorted out later. */ + #define __USE_LEGACY_PROTOTYPES__ #include /* For DIR */ #undef __USE_LEGACY_PROTOTYPES__ diff -r c2687aa5e5ca -r 7eb99acd567f src/os/solaris/vm/os_solaris.cpp --- a/src/os/solaris/vm/os_solaris.cpp Mon Jan 25 14:56:57 2016 -0800 +++ b/src/os/solaris/vm/os_solaris.cpp Mon Jan 25 14:57:27 2016 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 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 @@ -2696,29 +2696,30 @@ } } +size_t os::Solaris::page_size_for_alignment(size_t alignment) { + assert(is_size_aligned(alignment, (size_t) vm_page_size()), + err_msg(SIZE_FORMAT " is not aligned to " SIZE_FORMAT, + alignment, (size_t) vm_page_size())); + + for (int i = 0; _page_sizes[i] != 0; i++) { + if (is_size_aligned(alignment, _page_sizes[i])) { + return _page_sizes[i]; + } + } + + return (size_t) vm_page_size(); +} + int os::Solaris::commit_memory_impl(char* addr, size_t bytes, size_t alignment_hint, bool exec) { int err = Solaris::commit_memory_impl(addr, bytes, exec); - if (err == 0) { - if (UseLargePages && (alignment_hint > (size_t)vm_page_size())) { - // If the large page size has been set and the VM - // is using large pages, use the large page size - // if it is smaller than the alignment hint. This is - // a case where the VM wants to use a larger alignment size - // for its own reasons but still want to use large pages - // (which is what matters to setting the mpss range. - size_t page_size = 0; - if (large_page_size() < alignment_hint) { - assert(UseLargePages, "Expected to be here for large page use only"); - page_size = large_page_size(); - } else { - // If the alignment hint is less than the large page - // size, the VM wants a particular alignment (thus the hint) - // for internal reasons. Try to set the mpss range using - // the alignment_hint. - page_size = alignment_hint; - } - // Since this is a hint, ignore any failures. + if (err == 0 && UseLargePages && alignment_hint > 0) { + assert(is_size_aligned(bytes, alignment_hint), + err_msg(SIZE_FORMAT " is not aligned to " SIZE_FORMAT, bytes, alignment_hint)); + + // The syscall memcntl requires an exact page size (see man memcntl for details). + size_t page_size = page_size_for_alignment(alignment_hint); + if (page_size > (size_t) vm_page_size()) { (void)Solaris::setup_large_pages(addr, bytes, page_size); } } @@ -3251,7 +3252,22 @@ } } +bool os::Solaris::is_valid_page_size(size_t bytes) { + for (int i = 0; _page_sizes[i] != 0; i++) { + if (_page_sizes[i] == bytes) { + return true; + } + } + return false; +} + bool os::Solaris::setup_large_pages(caddr_t start, size_t bytes, size_t align) { + assert(is_valid_page_size(align), err_msg(SIZE_FORMAT " is not a valid page size", align)); + assert(is_ptr_aligned((void*) start, align), + err_msg(PTR_FORMAT " is not aligned to " SIZE_FORMAT, p2i((void*) start), align)); + assert(is_size_aligned(bytes, align), + err_msg(SIZE_FORMAT " is not aligned to " SIZE_FORMAT, bytes, align)); + // Signal to OS that we want large pages for addresses // from addr, addr + bytes struct memcntl_mha mpss_struct; @@ -4576,6 +4592,11 @@ tty->print_cr(" found:%s", get_signal_handler_name(thisHandler, buf, O_BUFLEN)); // No need to check this sig any longer sigaddset(&check_signal_done, sig); + // Running under non-interactive shell, SHUTDOWN2_SIGNAL will be reassigned SIG_IGN + if (sig == SHUTDOWN2_SIGNAL && !isatty(fileno(stdin))) { + tty->print_cr("Running in non-interactive shell, %s handler is replaced by shell", + exception_name(sig, buf, O_BUFLEN)); + } } else if(os::Solaris::get_our_sigflags(sig) != 0 && act.sa_flags != os::Solaris::get_our_sigflags(sig)) { tty->print("Warning: %s handler flags ", exception_name(sig, buf, O_BUFLEN)); tty->print("expected:" PTR32_FORMAT, os::Solaris::get_our_sigflags(sig)); @@ -5193,10 +5214,6 @@ return JNI_OK; } -void os::init_3(void) { - return; -} - // Mark the polling page as unreadable void os::make_polling_page_unreadable(void) { if( mprotect((char *)_polling_page, page_size, PROT_NONE) != 0 ) diff -r c2687aa5e5ca -r 7eb99acd567f src/os/solaris/vm/os_solaris.hpp --- a/src/os/solaris/vm/os_solaris.hpp Mon Jan 25 14:56:57 2016 -0800 +++ b/src/os/solaris/vm/os_solaris.hpp Mon Jan 25 14:57:27 2016 -0800 @@ -110,6 +110,8 @@ static meminfo_func_t _meminfo; // Large Page Support + static bool is_valid_page_size(size_t bytes); + static size_t page_size_for_alignment(size_t alignment); static bool setup_large_pages(caddr_t start, size_t bytes, size_t align); static void init_thread_fpu_state(void); diff -r c2687aa5e5ca -r 7eb99acd567f src/os/windows/vm/os_windows.cpp --- a/src/os/windows/vm/os_windows.cpp Mon Jan 25 14:56:57 2016 -0800 +++ b/src/os/windows/vm/os_windows.cpp Mon Jan 25 14:57:27 2016 -0800 @@ -110,11 +110,13 @@ static FILETIME process_kernel_time; #ifdef _M_IA64 -#define __CPU__ ia64 -#elif _M_AMD64 -#define __CPU__ amd64 + #define __CPU__ ia64 #else -#define __CPU__ i486 + #ifdef _M_AMD64 + #define __CPU__ amd64 + #else + #define __CPU__ i486 + #endif #endif // save DLL module handle, used by GetModuleFileName @@ -2138,20 +2140,22 @@ // at the beginning of the target bundle. exceptionInfo->ContextRecord->StIPSR &= 0xFFFFF9FFFFFFFFFF; assert(((DWORD64)handler & 0xF) == 0, "Target address must point to the beginning of a bundle!"); -#elif _M_AMD64 +#else + #ifdef _M_AMD64 // Do not blow up if no thread info available. if (thread) { thread->set_saved_exception_pc((address)(DWORD_PTR)exceptionInfo->ContextRecord->Rip); } // Set pc to handler exceptionInfo->ContextRecord->Rip = (DWORD64)handler; -#else + #else // Do not blow up if no thread info available. if (thread) { thread->set_saved_exception_pc((address)(DWORD_PTR)exceptionInfo->ContextRecord->Eip); } // Set pc to handler exceptionInfo->ContextRecord->Eip = (DWORD)(DWORD_PTR)handler; + #endif #endif // Continue the execution @@ -2250,7 +2254,8 @@ // (division by zero is handled explicitly) #ifdef _M_IA64 assert(0, "Fix Handle_IDiv_Exception"); -#elif _M_AMD64 +#else + #ifdef _M_AMD64 PCONTEXT ctx = exceptionInfo->ContextRecord; address pc = (address)ctx->Rip; #if INCLUDE_JVMCI @@ -2274,7 +2279,7 @@ #endif // JVMCI ctx->Rdx = (DWORD)0; // remainder // Continue the execution -#else + #else PCONTEXT ctx = exceptionInfo->ContextRecord; address pc = (address)ctx->Eip; assert(pc[0] == 0xF7, "not an idiv opcode"); @@ -2285,6 +2290,7 @@ ctx->Eax = (DWORD)min_jint; // result ctx->Edx = (DWORD)0; // remainder // Continue the execution + #endif #endif return EXCEPTION_CONTINUE_EXECUTION; } @@ -2364,10 +2370,12 @@ // This is needed for IA64 because "relocation" / "implicit null check" / "poll instruction" // information is saved in the Unix format. address pc_unix_format = (address) ((((uint64_t)pc) & 0xFFFFFFFFFFFFFFF0) | ((((uint64_t)pc) & 0xF) >> 2)); -#elif _M_AMD64 +#else + #ifdef _M_AMD64 address pc = (address) exceptionInfo->ContextRecord->Rip; -#else + #else address pc = (address) exceptionInfo->ContextRecord->Eip; + #endif #endif Thread* t = ThreadLocalStorage::get_thread_slow(); // slow & steady @@ -4075,10 +4083,6 @@ return JNI_OK; } -void os::init_3(void) { - return; -} - // Mark the polling page as unreadable void os::make_polling_page_unreadable(void) { DWORD old_status; diff -r c2687aa5e5ca -r 7eb99acd567f src/os_cpu/bsd_zero/vm/atomic_bsd_zero.inline.hpp --- a/src/os_cpu/bsd_zero/vm/atomic_bsd_zero.inline.hpp Mon Jan 25 14:56:57 2016 -0800 +++ b/src/os_cpu/bsd_zero/vm/atomic_bsd_zero.inline.hpp Mon Jan 25 14:57:27 2016 -0800 @@ -238,7 +238,13 @@ // operation. Note that some platforms only support this with the // limitation that the only valid value to store is the immediate // constant 1. There is a test for this in JNI_CreateJavaVM(). - return __sync_lock_test_and_set (dest, exchange_value); + jint result = __sync_lock_test_and_set (dest, exchange_value); + // All atomic operations are expected to be full memory barriers + // (see atomic.hpp). However, __sync_lock_test_and_set is not + // a full memory barrier, but an acquire barrier. Hence, this added + // barrier. + __sync_synchronize(); + return result; #endif // M68K #endif // ARM } @@ -251,7 +257,9 @@ #ifdef M68K return m68k_lock_test_and_set(dest, exchange_value); #else - return __sync_lock_test_and_set (dest, exchange_value); + intptr_t result = __sync_lock_test_and_set (dest, exchange_value); + __sync_synchronize(); + return result; #endif // M68K #endif // ARM } diff -r c2687aa5e5ca -r 7eb99acd567f src/os_cpu/linux_ppc/vm/os_linux_ppc.cpp --- a/src/os_cpu/linux_ppc/vm/os_linux_ppc.cpp Mon Jan 25 14:56:57 2016 -0800 +++ b/src/os_cpu/linux_ppc/vm/os_linux_ppc.cpp Mon Jan 25 14:57:27 2016 -0800 @@ -1,6 +1,6 @@ /* - * Copyright (c) 1997, 2014, Oracle and/or its affiliates. All rights reserved. - * Copyright 2012, 2014 SAP AG. All rights reserved. + * Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright 2012, 2015 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 @@ -10,7 +10,7 @@ * 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 hat + * 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 @@ -290,6 +290,7 @@ goto report_and_die; } + CodeBlob *cb = NULL; // Handle signal from NativeJump::patch_verified_entry(). if (( TrapBasedNotEntrantChecks && sig == SIGTRAP && nativeInstruction_at(pc)->is_sigtrap_zombie_not_entrant()) || (!TrapBasedNotEntrantChecks && sig == SIGILL && nativeInstruction_at(pc)->is_sigill_zombie_not_entrant())) { @@ -305,7 +306,10 @@ // especially when we try to read from the safepoint polling page. So the check // (address)info->si_addr == os::get_standard_polling_page() // doesn't work for us. We use: - ((NativeInstruction*)pc)->is_safepoint_poll()) { + ((NativeInstruction*)pc)->is_safepoint_poll() && + CodeCache::contains((void*) pc) && + ((cb = CodeCache::find_blob(pc)) != NULL) && + cb->is_nmethod()) { if (TraceTraps) { tty->print_cr("trap: safepoint_poll at " INTPTR_FORMAT " (SIGSEGV)", p2i(pc)); } diff -r c2687aa5e5ca -r 7eb99acd567f src/os_cpu/linux_sparc/vm/vm_version_linux_sparc.cpp --- a/src/os_cpu/linux_sparc/vm/vm_version_linux_sparc.cpp Mon Jan 25 14:56:57 2016 -0800 +++ b/src/os_cpu/linux_sparc/vm/vm_version_linux_sparc.cpp Mon Jan 25 14:57:27 2016 -0800 @@ -26,8 +26,8 @@ #include "runtime/os.hpp" #include "vm_version_sparc.hpp" -static bool detect_niagara() { - char cpu[128]; +static bool cpuinfo_field_contains(const char* field, const char* value) { + char line[1024]; bool rv = false; FILE* fp = fopen("/proc/cpuinfo", "r"); @@ -35,9 +35,10 @@ return rv; } - while (!feof(fp)) { - if (fscanf(fp, "cpu\t\t: %100[^\n]", &cpu) == 1) { - if (strstr(cpu, "Niagara") != NULL) { + while (fgets(line, sizeof(line), fp) != NULL) { + assert(strlen(line) < sizeof(line) - 1, "buffer line[1024] is too small."); + if (strncmp(line, field, strlen(field)) == 0) { + if (strstr(line, value) != NULL) { rv = true; } break; @@ -45,8 +46,15 @@ } fclose(fp); + return rv; +} - return rv; +static bool detect_niagara() { + return cpuinfo_field_contains("cpu", "Niagara"); +} + +static bool detect_blkinit() { + return cpuinfo_field_contains("cpucaps", "blkinit"); } int VM_Version::platform_features(int features) { @@ -58,5 +66,9 @@ features = niagara1_m | T_family_m; } + if (detect_blkinit()) { + features |= blk_init_instructions_m; + } + return features; } diff -r c2687aa5e5ca -r 7eb99acd567f src/os_cpu/linux_zero/vm/atomic_linux_zero.inline.hpp --- a/src/os_cpu/linux_zero/vm/atomic_linux_zero.inline.hpp Mon Jan 25 14:56:57 2016 -0800 +++ b/src/os_cpu/linux_zero/vm/atomic_linux_zero.inline.hpp Mon Jan 25 14:57:27 2016 -0800 @@ -1,6 +1,6 @@ /* - * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved. - * Copyright 2007, 2008, 2011 Red Hat, Inc. + * Copyright (c) 2003, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright 2007, 2008, 2011, 2015, Red Hat, Inc. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -232,7 +232,13 @@ // operation. Note that some platforms only support this with the // limitation that the only valid value to store is the immediate // constant 1. There is a test for this in JNI_CreateJavaVM(). - return __sync_lock_test_and_set (dest, exchange_value); + jint result = __sync_lock_test_and_set (dest, exchange_value); + // All atomic operations are expected to be full memory barriers + // (see atomic.hpp). However, __sync_lock_test_and_set is not + // a full memory barrier, but an acquire barrier. Hence, this added + // barrier. + __sync_synchronize(); + return result; #endif // M68K #endif // ARM } @@ -245,7 +251,9 @@ #ifdef M68K return m68k_lock_test_and_set(dest, exchange_value); #else - return __sync_lock_test_and_set (dest, exchange_value); + intptr_t result = __sync_lock_test_and_set (dest, exchange_value); + __sync_synchronize(); + return result; #endif // M68K #endif // ARM } diff -r c2687aa5e5ca -r 7eb99acd567f src/os_cpu/solaris_sparc/vm/os_solaris_sparc.cpp --- a/src/os_cpu/solaris_sparc/vm/os_solaris_sparc.cpp Mon Jan 25 14:56:57 2016 -0800 +++ b/src/os_cpu/solaris_sparc/vm/os_solaris_sparc.cpp Mon Jan 25 14:57:27 2016 -0800 @@ -265,7 +265,7 @@ CAST_FROM_FN_PTR(address, os::current_frame)); if (os::is_first_C_frame(&myframe)) { // stack is not walkable - return frame(NULL, NULL, NULL); + return frame(NULL, NULL, false); } else { return os::get_sender_for_C_frame(&myframe); } diff -r c2687aa5e5ca -r 7eb99acd567f src/os_cpu/solaris_sparc/vm/vm_version_solaris_sparc.cpp --- a/src/os_cpu/solaris_sparc/vm/vm_version_solaris_sparc.cpp Mon Jan 25 14:56:57 2016 -0800 +++ b/src/os_cpu/solaris_sparc/vm/vm_version_solaris_sparc.cpp Mon Jan 25 14:57:27 2016 -0800 @@ -34,8 +34,7 @@ #include #include -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); +extern "C" static int PICL_visit_cpu_helper(picl_nodehdl_t nodeh, void *result); // Functions from the library we need (signatures should match those in picl.h) extern "C" { @@ -128,60 +127,87 @@ bool is_inconsistent() { return _state == INCONSISTENT; } void set_inconsistent() { _state = INCONSISTENT; } - static int visit(picl_nodehdl_t nodeh, const char* name, void *arg) { - UniqueValueVisitor *state = static_cast(arg); - PICL* picl = state->_picl; - assert(!state->is_inconsistent(), "Precondition"); + bool visit(picl_nodehdl_t nodeh, const char* name) { + assert(!is_inconsistent(), "Precondition"); int curr; - 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 - state->set_inconsistent(); + if (_picl->get_int_property(nodeh, name, &curr) == PICL_SUCCESS) { + if (!is_assigned()) { // first iteration + set_value(curr); + } else if (curr != value()) { // following iterations + set_inconsistent(); + } + return true; + } + return false; + } + }; + + class CPUVisitor { + UniqueValueVisitor _l1_visitor; + UniqueValueVisitor _l2_visitor; + int _limit; // number of times visit() can be run + public: + CPUVisitor(PICL *picl, int limit) : _l1_visitor(picl), _l2_visitor(picl), _limit(limit) {} + static int visit(picl_nodehdl_t nodeh, void *arg) { + CPUVisitor *cpu_visitor = static_cast(arg); + UniqueValueVisitor* l1_visitor = cpu_visitor->l1_visitor(); + UniqueValueVisitor* l2_visitor = cpu_visitor->l2_visitor(); + if (!l1_visitor->is_inconsistent()) { + l1_visitor->visit(nodeh, "l1-dcache-line-size"); + } + static const char* l2_data_cache_line_property_name = NULL; + // On the first visit determine the name of the l2 cache line size property and memoize it. + if (l2_data_cache_line_property_name == NULL) { + assert(!l2_visitor->is_inconsistent(), "First iteration cannot be inconsistent"); + l2_data_cache_line_property_name = "l2-cache-line-size"; + if (!l2_visitor->visit(nodeh, l2_data_cache_line_property_name)) { + l2_data_cache_line_property_name = "l2-dcache-line-size"; + l2_visitor->visit(nodeh, l2_data_cache_line_property_name); + } + } else { + if (!l2_visitor->is_inconsistent()) { + l2_visitor->visit(nodeh, l2_data_cache_line_property_name); } } - if (state->is_inconsistent()) { + + if (l1_visitor->is_inconsistent() && l2_visitor->is_inconsistent()) { + return PICL_WALK_TERMINATE; + } + cpu_visitor->_limit--; + if (cpu_visitor->_limit <= 0) { return PICL_WALK_TERMINATE; } return PICL_WALK_CONTINUE; } + UniqueValueVisitor* l1_visitor() { return &_l1_visitor; } + UniqueValueVisitor* l2_visitor() { return &_l2_visitor; } }; - int _L1_data_cache_line_size; - int _L2_cache_line_size; + int _L2_data_cache_line_size; public: - static int get_l1_data_cache_line_size(picl_nodehdl_t nodeh, void *state) { - return UniqueValueVisitor::visit(nodeh, "l1-dcache-line-size", state); - } - static int get_l2_cache_line_size(picl_nodehdl_t nodeh, void *state) { - return UniqueValueVisitor::visit(nodeh, "l2-cache-line-size", state); + static int visit_cpu(picl_nodehdl_t nodeh, void *state) { + return CPUVisitor::visit(nodeh, state); } - PICL() : _L1_data_cache_line_size(0), _L2_cache_line_size(0), _dl_handle(NULL) { + PICL(bool is_fujitsu, bool is_sun4v) : _L1_data_cache_line_size(0), _L2_data_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(this); - // Visit all "cpu" class instances - _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); + const char* cpu_class = "cpu"; + // If it's a Fujitsu machine, it's a "core" + if (is_fujitsu) { + cpu_class = "core"; } - if (L1_state.is_assigned()) { // Is there a value? - _L1_data_cache_line_size = L1_state.value(); + CPUVisitor cpu_visitor(this, (is_sun4v && !is_fujitsu) ? 1 : os::processor_count()); + _picl_walk_tree_by_class(rooth, cpu_class, &cpu_visitor, PICL_visit_cpu_helper); + if (cpu_visitor.l1_visitor()->is_assigned()) { // Is there a value? + _L1_data_cache_line_size = cpu_visitor.l1_visitor()->value(); } - - 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); - } - if (L2_state.is_assigned()) { - _L2_cache_line_size = L2_state.value(); + if (cpu_visitor.l2_visitor()->is_assigned()) { + _L2_data_cache_line_size = cpu_visitor.l2_visitor()->value(); } } _picl_shutdown(); @@ -190,14 +216,12 @@ } unsigned int L1_data_cache_line_size() const { return _L1_data_cache_line_size; } - unsigned int L2_cache_line_size() const { return _L2_cache_line_size; } + unsigned int L2_data_cache_line_size() const { return _L2_data_cache_line_size; } }; -extern "C" static int PICL_get_l1_data_cache_line_size_helper(picl_nodehdl_t nodeh, void *result) { - return PICL::get_l1_data_cache_line_size(nodeh, result); -} -extern "C" static int PICL_get_l2_cache_line_size_helper(picl_nodehdl_t nodeh, void *result) { - return PICL::get_l2_cache_line_size(nodeh, result); + +extern "C" static int PICL_visit_cpu_helper(picl_nodehdl_t nodeh, void *result) { + return PICL::visit_cpu(nodeh, result); } template @@ -470,8 +494,8 @@ } // Figure out cache line sizes using PICL - PICL picl; - _L2_cache_line_size = picl.L2_cache_line_size(); + PICL picl((features & sparc64_family_m) != 0, (features & sun4v_m) != 0); + _L2_data_cache_line_size = picl.L2_data_cache_line_size(); return features; } diff -r c2687aa5e5ca -r 7eb99acd567f src/share/tools/LogCompilation/src/com/sun/hotspot/tools/compiler/LogParser.java --- a/src/share/tools/LogCompilation/src/com/sun/hotspot/tools/compiler/LogParser.java Mon Jan 25 14:56:57 2016 -0800 +++ b/src/share/tools/LogCompilation/src/com/sun/hotspot/tools/compiler/LogParser.java Mon Jan 25 14:57:27 2016 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2009, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2009, 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 @@ -24,12 +24,12 @@ /** * A SAX based parser of LogCompilation output from HotSpot. It takes a complete - * @author never */ package com.sun.hotspot.tools.compiler; import java.io.FileReader; +import java.io.PrintStream; import java.io.Reader; import java.util.ArrayList; import java.util.Collections; @@ -130,6 +130,44 @@ } }; + class Jvms { + Jvms(Method method, int bci) { + this.method = method; + this.bci = bci; + } + final public Method method; + final public int bci; + final public String toString() { + return "@" + bci + " " + method; + } + } + + class LockElimination extends BasicLogEvent { + + ArrayList jvms = new ArrayList(1); + final String kind; + final String classId; + final String tagName; + LockElimination(String tagName, double start, String id, String kind, String classId) { + super(start, id); + this.kind = kind; + this.classId = classId; + this.tagName = tagName; + } + + @Override + public void print(PrintStream stream) { + stream.printf("%s %s %s %s %.3f ", getId(), tagName, kind, classId, getStart()); + stream.print(jvms.toString()); + stream.print("\n"); + } + + void addJVMS(Method method, int bci) { + jvms.add(new Jvms(method, bci)); + } + + } + private ArrayList events = new ArrayList(); private HashMap types = new HashMap(); @@ -143,10 +181,9 @@ private Compilation compile; private CallSite site; private Stack phaseStack = new Stack(); + private LockElimination currentLockElimination; private UncommonTrapEvent currentTrap; private Stack late_inline_scope; - private JVMState eliminated_lock; - private boolean in_eliminate_lock; long parseLong(String l) { try { @@ -188,7 +225,12 @@ } LogParser log = new LogParser(); - p.parse(new InputSource(reader), log); + try { + p.parse(new InputSource(reader), log); + } catch (Throwable th) { + th.printStackTrace(); + // Carry on with what we've got... + } // Associate compilations with their NMethods for (LogEvent le : log.events) { @@ -409,30 +451,31 @@ // uncommon trap inserted during parsing. // ignore for now } + } else if (qname.startsWith("eliminate_lock")) { + String id = atts.getValue("compile_id"); + if (id != null) { + id = makeId(atts); + String kind = atts.getValue("kind"); + String classId = atts.getValue("class_id"); + currentLockElimination = new LockElimination(qname, Double.parseDouble(search(atts, "stamp")), id, kind, classId); + events.add(currentLockElimination); + } } else if (qname.equals("late_inline")) { late_inline_scope = new Stack(); site = new CallSite(-999, method(search(atts, "method"))); late_inline_scope.push(site); - } else if (qname.equals("eliminate_lock")) { - in_eliminate_lock = true; } else if (qname.equals("jvms")) { // if (currentTrap != null) { currentTrap.addJVMS(atts.getValue("method"), Integer.parseInt(atts.getValue("bci"))); + } else if (currentLockElimination != null) { + currentLockElimination.addJVMS(method(atts.getValue("method")), Integer.parseInt(atts.getValue("bci"))); } else if (late_inline_scope != null) { bci = Integer.parseInt(search(atts, "bci")); site = new CallSite(bci, method(search(atts, "method"))); late_inline_scope.push(site); - } else if (in_eliminate_lock) { - JVMState jvms = new JVMState(method(atts.getValue("method")), Integer.parseInt(atts.getValue("bci"))); - if (eliminated_lock == null) { - eliminated_lock = jvms; - } else { - eliminated_lock.push(jvms); - } } else { // Ignore , - // , // } } else if (qname.equals("nmethod")) { @@ -492,13 +535,8 @@ scopes.pop(); } else if (qname.equals("uncommon_trap")) { currentTrap = null; - } else if (qname.equals("eliminate_lock")) { - if (eliminated_lock != null) { - // There's no JVM state on the unlock, so ignore it - compile.addEliminatedLock(eliminated_lock); - } - eliminated_lock = null; - in_eliminate_lock = false; + } else if (qname.startsWith("eliminate_lock")) { + currentLockElimination = null; } else if (qname.equals("late_inline")) { // Populate late inlining info. @@ -507,8 +545,8 @@ CallSite caller = late_inline_scope.pop(); Method m = compile.getMethod(); if (m != caller.getMethod()) { - System.out.println(m); - System.out.println(caller.getMethod() + " bci: " + bci); + System.err.println(m); + System.err.println(caller.getMethod() + " bci: " + bci); throw new InternalError("call site and late_inline info don't match"); } diff -r c2687aa5e5ca -r 7eb99acd567f src/share/tools/LogCompilation/src/com/sun/hotspot/tools/compiler/UncommonTrapEvent.java --- a/src/share/tools/LogCompilation/src/com/sun/hotspot/tools/compiler/UncommonTrapEvent.java Mon Jan 25 14:56:57 2016 -0800 +++ b/src/share/tools/LogCompilation/src/com/sun/hotspot/tools/compiler/UncommonTrapEvent.java Mon Jan 25 14:57:27 2016 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2009, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2009, 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 @@ -40,6 +40,7 @@ count = c; } + public void addJVMS(String method, int bci) { setJvms(getJvms() + " @" + bci + " " + method + "\n"); } @@ -49,7 +50,7 @@ } public void print(PrintStream stream) { - stream.printf("%s uncommon trap %s %s\n", compilation.shortName(), getReason(), getAction()); + stream.printf("%s %s uncommon trap %.3f %s %s\n", compilation.shortName(), getId(), getStart(), getReason(), getAction()); stream.print(getJvms()); } @@ -80,4 +81,8 @@ public void setJvms(String jvms) { this.jvms = jvms; } + + public void setCompilation(Compilation compilation) { + this.compilation = compilation; + } } diff -r c2687aa5e5ca -r 7eb99acd567f src/share/vm/adlc/adlparse.cpp --- a/src/share/vm/adlc/adlparse.cpp Mon Jan 25 14:56:57 2016 -0800 +++ b/src/share/vm/adlc/adlparse.cpp Mon Jan 25 14:57:27 2016 -0800 @@ -800,6 +800,7 @@ } if (strcmp(token,"reg_def")==0) { reg_def_parse(); } else if (strcmp(token,"reg_class")==0) { reg_class_parse(); } + else if (strcmp(token, "reg_class_dynamic") == 0) { reg_class_dynamic_parse(); } else if (strcmp(token,"alloc_class")==0) { alloc_class_parse(); } else if (strcmp(token,"#define")==0) { preproc_define(); } else { parse_err(SYNERR, "bad token %s inside register block.\n", token); break; } @@ -2323,11 +2324,12 @@ // Debug Stuff if (_AD._adl_debug >1) fprintf(stderr,"Register Class: %s\n", cname); - RegClass *reg_class = _AD._register->addRegClass(cname); - - // Collect registers in class skipws(); if (_curchar == '(') { + // A register list is defined for the register class. + // Collect registers into a generic RegClass register class. + RegClass* reg_class = _AD._register->addRegClass(cname); + next_char(); // Skip '(' skipws(); while (_curchar != ')') { @@ -2352,12 +2354,15 @@ } next_char(); // Skip closing ')' } else if (_curchar == '%') { + // A code snippet is defined for the register class. + // Collect the code snippet into a CodeSnippetRegClass register class. + CodeSnippetRegClass* reg_class = _AD._register->addRegClass(cname); char *code = find_cpp_block("reg class"); if (code == NULL) { parse_err(SYNERR, "missing code declaration for reg class.\n"); return; } - reg_class->_user_defined = code; + reg_class->set_code_snippet(code); return; } @@ -2374,6 +2379,87 @@ return; } +//------------------------------reg_class_dynamic_parse------------------------ +void ADLParser::reg_class_dynamic_parse(void) { + char *cname; // Name of dynamic register class being defined + + // Get register class name + skipws(); + cname = get_ident(); + if (cname == NULL) { + parse_err(SYNERR, "missing dynamic register class name after 'reg_class_dynamic'\n"); + return; + } + + if (_AD._adl_debug > 1) { + fprintf(stdout, "Dynamic Register Class: %s\n", cname); + } + + skipws(); + if (_curchar != '(') { + parse_err(SYNERR, "missing '(' at the beginning of reg_class_dynamic definition\n"); + return; + } + next_char(); + skipws(); + + // Collect two register classes and the C++ code representing the condition code used to + // select between the two classes into a ConditionalRegClass register class. + ConditionalRegClass* reg_class = _AD._register->addRegClass(cname); + int i; + for (i = 0; i < 2; i++) { + char* name = get_ident(); + if (name == NULL) { + parse_err(SYNERR, "missing class identifier inside reg_class_dynamic list.\n"); + return; + } + RegClass* rc = _AD._register->getRegClass(name); + if (rc == NULL) { + parse_err(SEMERR, "unknown identifier %s inside reg_class_dynamic list.\n", name); + } else { + reg_class->set_rclass_at_index(i, rc); + } + + skipws(); + if (_curchar == ',') { + next_char(); + skipws(); + } else { + parse_err(SYNERR, "missing separator ',' inside reg_class_dynamic list.\n"); + } + } + + // Collect the condition code. + skipws(); + if (_curchar == '%') { + char* code = find_cpp_block("reg class dynamic"); + if (code == NULL) { + parse_err(SYNERR, "missing code declaration for reg_class_dynamic.\n"); + return; + } + reg_class->set_condition_code(code); + } else { + parse_err(SYNERR, "missing %% at the beginning of code block in reg_class_dynamic definition\n"); + return; + } + + skipws(); + if (_curchar != ')') { + parse_err(SYNERR, "missing ')' at the end of reg_class_dynamic definition\n"); + return; + } + next_char(); + + skipws(); + if (_curchar != ';') { + parse_err(SYNERR, "missing ';' at the end of reg_class_dynamic definition.\n"); + return; + } + next_char(); // Skip trailing ';' + + return; +} + //------------------------------alloc_class_parse------------------------------ void ADLParser::alloc_class_parse(void) { char *name; // Name of allocation class being defined diff -r c2687aa5e5ca -r 7eb99acd567f src/share/vm/adlc/adlparse.hpp --- a/src/share/vm/adlc/adlparse.hpp Mon Jan 25 14:56:57 2016 -0800 +++ b/src/share/vm/adlc/adlparse.hpp Mon Jan 25 14:57:27 2016 -0800 @@ -53,6 +53,8 @@ // ***** Register Section ***** class RegDef; class RegClass; +class CodeSnippetRegClass; +class ConditionalRegClass; class AllocClass; class ResourceForm; // ***** Pipeline Section ***** @@ -127,6 +129,7 @@ // Parse components of the register section void reg_def_parse(void); // Parse register definition void reg_class_parse(void); // Parse register class definition + void reg_class_dynamic_parse(void); // Parse dynamic register class definition void alloc_class_parse(void); // Parse allocation class definition // Parse components of the definition section diff -r c2687aa5e5ca -r 7eb99acd567f src/share/vm/adlc/archDesc.cpp --- a/src/share/vm/adlc/archDesc.cpp Mon Jan 25 14:56:57 2016 -0800 +++ b/src/share/vm/adlc/archDesc.cpp Mon Jan 25 14:57:27 2016 -0800 @@ -934,7 +934,7 @@ void ArchDesc::set_stack_or_reg(const char *reg_class_name) { if( _register ) { RegClass *reg_class = _register->getRegClass(reg_class_name); - reg_class->_stack_or_reg = true; + reg_class->set_stack_version(true); } } diff -r c2687aa5e5ca -r 7eb99acd567f src/share/vm/adlc/forms.hpp --- a/src/share/vm/adlc/forms.hpp Mon Jan 25 14:56:57 2016 -0800 +++ b/src/share/vm/adlc/forms.hpp Mon Jan 25 14:57:27 2016 -0800 @@ -68,6 +68,8 @@ class InsEncode; class RegDef; class RegClass; +class CodeSnippetRegClass; +class ConditionalRegClass; class AllocClass; class ResourceForm; class PipeClassForm; diff -r c2687aa5e5ca -r 7eb99acd567f src/share/vm/adlc/formsopt.cpp --- a/src/share/vm/adlc/formsopt.cpp Mon Jan 25 14:56:57 2016 -0800 +++ b/src/share/vm/adlc/formsopt.cpp Mon Jan 25 14:57:27 2016 -0800 @@ -47,13 +47,19 @@ } // record a new register class -RegClass *RegisterForm::addRegClass(const char *className) { - RegClass *regClass = new RegClass(className); +template +T* RegisterForm::addRegClass(const char* className) { + T* regClass = new T(className); _rclasses.addName(className); - _regClass.Insert(className,regClass); + _regClass.Insert(className, regClass); return regClass; } +// Explicit instantiation for all supported register classes. +template RegClass* RegisterForm::addRegClass(const char* className); +template CodeSnippetRegClass* RegisterForm::addRegClass(const char* className); +template ConditionalRegClass* RegisterForm::addRegClass(const char* className); + // record a new register class AllocClass *RegisterForm::addAllocClass(char *className) { AllocClass *allocClass = new AllocClass(className); @@ -67,9 +73,9 @@ void RegisterForm::addSpillRegClass() { // Stack slots start at the next available even register number. _reg_ctr = (_reg_ctr+7) & ~7; - const char *rc_name = "stack_slots"; - RegClass *reg_class = new RegClass(rc_name); - reg_class->_stack_or_reg = true; + const char *rc_name = "stack_slots"; + RegClass* reg_class = new RegClass(rc_name); + reg_class->set_stack_version(true); _rclasses.addName(rc_name); _regClass.Insert(rc_name,reg_class); } @@ -224,9 +230,11 @@ //------------------------------RegClass--------------------------------------- // Construct a register class into which registers will be inserted -RegClass::RegClass(const char *classid) : _stack_or_reg(false), _classid(classid), _regDef(cmpstr,hashstr, Form::arena), - _user_defined(NULL) -{ +RegClass::RegClass(const char* classid) : _stack_or_reg(false), _classid(classid), _regDef(cmpstr, hashstr, Form::arena) { +} + +RegClass::~RegClass() { + delete _classid; } // record a register in this class @@ -305,6 +313,91 @@ fprintf(fp,"--- done with entries for reg_class %s\n\n",_classid); } +void RegClass::declare_register_masks(FILE* fp) { + const char* prefix = ""; + const char* rc_name_to_upper = toUpper(_classid); + fprintf(fp, "extern const RegMask _%s%s_mask;\n", prefix, rc_name_to_upper); + fprintf(fp, "inline const RegMask &%s%s_mask() { return _%s%s_mask; }\n", prefix, rc_name_to_upper, prefix, rc_name_to_upper); + if (_stack_or_reg) { + fprintf(fp, "extern const RegMask _%sSTACK_OR_%s_mask;\n", prefix, rc_name_to_upper); + fprintf(fp, "inline const RegMask &%sSTACK_OR_%s_mask() { return _%sSTACK_OR_%s_mask; }\n", prefix, rc_name_to_upper, prefix, rc_name_to_upper); + } + delete[] rc_name_to_upper; +} + +void RegClass::build_register_masks(FILE* fp) { + int len = RegisterForm::RegMask_Size(); + const char *prefix = ""; + const char* rc_name_to_upper = toUpper(_classid); + fprintf(fp, "const RegMask _%s%s_mask(", prefix, rc_name_to_upper); + + int i; + for(i = 0; i < len - 1; i++) { + fprintf(fp," 0x%x,", regs_in_word(i, false)); + } + fprintf(fp," 0x%x );\n", regs_in_word(i, false)); + + if (_stack_or_reg) { + fprintf(fp, "const RegMask _%sSTACK_OR_%s_mask(", prefix, rc_name_to_upper); + for(i = 0; i < len - 1; i++) { + fprintf(fp," 0x%x,", regs_in_word(i, true)); + } + fprintf(fp," 0x%x );\n", regs_in_word(i, true)); + } + delete[] rc_name_to_upper; +} + +//------------------------------CodeSnippetRegClass--------------------------- +CodeSnippetRegClass::CodeSnippetRegClass(const char* classid) : RegClass(classid), _code_snippet(NULL) { +} + +CodeSnippetRegClass::~CodeSnippetRegClass() { + delete _code_snippet; +} + +void CodeSnippetRegClass::declare_register_masks(FILE* fp) { + const char* prefix = ""; + const char* rc_name_to_upper = toUpper(_classid); + fprintf(fp, "inline const RegMask &%s%s_mask() { %s }\n", prefix, rc_name_to_upper, _code_snippet); + delete[] rc_name_to_upper; +} + +//------------------------------ConditionalRegClass--------------------------- +ConditionalRegClass::ConditionalRegClass(const char *classid) : RegClass(classid), _condition_code(NULL) { +} + +ConditionalRegClass::~ConditionalRegClass() { + delete _condition_code; +} + +void ConditionalRegClass::declare_register_masks(FILE* fp) { + const char* prefix = ""; + const char* rc_name_to_upper = toUpper(_classid); + const char* rclass_0_to_upper = toUpper(_rclasses[0]->_classid); + const char* rclass_1_to_upper = toUpper(_rclasses[1]->_classid); + fprintf(fp, "inline const RegMask &%s%s_mask() {" + " return (%s) ?" + " %s%s_mask() :" + " %s%s_mask(); }\n", + prefix, rc_name_to_upper, + _condition_code, + prefix, rclass_0_to_upper, + prefix, rclass_1_to_upper); + if (_stack_or_reg) { + fprintf(fp, "inline const RegMask &%sSTACK_OR_%s_mask() {" + " return (%s) ?" + " %sSTACK_OR_%s_mask() :" + " %sSTACK_OR_%s_mask(); }\n", + prefix, rc_name_to_upper, + _condition_code, + prefix, rclass_0_to_upper, + prefix, rclass_1_to_upper); + } + delete[] rc_name_to_upper; + delete[] rclass_0_to_upper; + delete[] rclass_1_to_upper; + return; +} //------------------------------AllocClass------------------------------------- AllocClass::AllocClass(char *classid) : _classid(classid), _regDef(cmpstr,hashstr, Form::arena) { diff -r c2687aa5e5ca -r 7eb99acd567f src/share/vm/adlc/formsopt.hpp --- a/src/share/vm/adlc/formsopt.hpp Mon Jan 25 14:56:57 2016 -0800 +++ b/src/share/vm/adlc/formsopt.hpp Mon Jan 25 14:57:27 2016 -0800 @@ -60,6 +60,8 @@ class InsEncode; class RegDef; class RegClass; +class CodeSnippetRegClass; +class ConditionalRegClass; class AllocClass; class ResourceForm; class PipeClassForm; @@ -98,7 +100,8 @@ void addRegDef(char *regName, char *callingConv, char *c_conv, char * idealtype, char *encoding, char* concreteName); - RegClass *addRegClass(const char *className); + template T* addRegClass(const char* className); + AllocClass *addAllocClass(char *allocName); void addSpillRegClass(); @@ -154,17 +157,28 @@ }; //------------------------------RegClass--------------------------------------- +// Generic register class. This register class is the internal representation +// for the following .ad file format: +// +// reg_class ptr(RAX, RBX, ...); +// +// where ptr is the name of the register class, RAX and RBX are registers. +// +// This register class allows registers to be spilled onto the stack. Spilling +// is allowed is field _stack_or_reg is true. class RegClass : public Form { public: // Public Data const char *_classid; // Name of class NameList _regDefs; // List of registers in class Dict _regDef; // Dictionary of registers in class +protected: bool _stack_or_reg; // Allowed on any stack slot - char* _user_defined; +public: // Public Methods RegClass(const char *classid);// Constructor + virtual ~RegClass(); void addReg(RegDef *regDef); // Add a register to this class @@ -183,6 +197,115 @@ void dump(); // Debug printer void output(FILE *fp); // Write info to output files + + virtual bool has_stack_version() { + return _stack_or_reg; + } + virtual void set_stack_version(bool flag) { + _stack_or_reg = flag; + } + + virtual void declare_register_masks(FILE* fp); + virtual void build_register_masks(FILE* fp); +}; + +//------------------------------CodeSnippetRegClass---------------------------- +// Register class that has an user-defined C++ code snippet attached to it +// to determine at runtime which register class to use. This register class is +// the internal representation for the following .ad file format: +// +// reg_class actual_dflt_reg %{ +// if (VM_Version::has_vfp3_32()) { +// return DFLT_REG_mask(); +// } else { +// return DFLT_LOW_REG_mask(); +// } +// %} +// +// where DFLT_REG_mask() and DFLT_LOW_REG_mask() are the internal names of the +// masks of register classes dflt_reg and dflt_low_reg. +// +// The attached code snippet can select also between more than two register classes. +// This register class can be, however, used only if the register class is not +// cisc-spillable (i.e., the registers of this class are not allowed on the stack, +// which is equivalent with _stack_or_reg being false). +class CodeSnippetRegClass : public RegClass { +protected: + char* _code_snippet; +public: + CodeSnippetRegClass(const char* classid);// Constructor + ~CodeSnippetRegClass(); + + void set_code_snippet(char* code) { + _code_snippet = code; + } + char* code_snippet() { + return _code_snippet; + } + void set_stack_version(bool flag) { + assert(false, "User defined register classes are not allowed to spill to the stack."); + } + void declare_register_masks(FILE* fp); + void build_register_masks(FILE* fp) { + // We do not need to generate register masks because we select at runtime + // between register masks generated for other register classes. + return; + } +}; + +//------------------------------ConditionalRegClass---------------------------- +// Register class that has two register classes and a runtime condition attached +// to it. The condition is evaluated at runtime and either one of the register +// attached register classes is selected. This register class is the internal +// representation for the following .ad format: +// +// reg_class_dynamic actual_dflt_reg(dflt_reg, low_reg, +// %{ VM_Version::has_vfp3_32() }% +// ); +// +// This example is equivalent to the example used with the CodeSnippetRegClass +// register class. A ConditionalRegClass works also if a register class is cisc-spillable +// (i.e., _stack_or_reg is true), but if can select only between two register classes. +class ConditionalRegClass : public RegClass { +protected: + // reference to condition code + char* _condition_code; // C++ condition code to dynamically determine which register class to use. + + // Example syntax (equivalent to previous example): + // + // reg_class actual_dflt_reg(dflt_reg, low_reg, + // %{ VM_Version::has_vfp3_32() }% + // ); + // reference to conditional register classes + RegClass* _rclasses[2]; // 0 is the register class selected if the condition code returns true + // 1 is the register class selected if the condition code returns false +public: + ConditionalRegClass(const char* classid);// Constructor + ~ConditionalRegClass(); + + virtual void set_stack_version(bool flag) { + RegClass::set_stack_version(flag); + assert((_rclasses[0] != NULL), "Register class NULL for condition code == true"); + assert((_rclasses[1] != NULL), "Register class NULL for condition code == false"); + _rclasses[0]->set_stack_version(flag); + _rclasses[1]->set_stack_version(flag); + } + void declare_register_masks(FILE* fp); + void build_register_masks(FILE* fp) { + // We do not need to generate register masks because we select at runtime + // between register masks generated for other register classes. + return; + } + void set_rclass_at_index(int index, RegClass* rclass) { + assert((0 <= index && index < 2), "Condition code can select only between two register classes"); + _rclasses[index] = rclass; + } + void set_condition_code(char* code) { + _condition_code = code; + } + char* condition_code() { + return _condition_code; + } }; //------------------------------AllocClass------------------------------------- diff -r c2687aa5e5ca -r 7eb99acd567f src/share/vm/adlc/formssel.hpp --- a/src/share/vm/adlc/formssel.hpp Mon Jan 25 14:56:57 2016 -0800 +++ b/src/share/vm/adlc/formssel.hpp Mon Jan 25 14:57:27 2016 -0800 @@ -59,6 +59,8 @@ class InsEncode; class RegDef; class RegClass; +class CodeSnippetRegClass; +class ConditionalRegClass; class AllocClass; class ResourceForm; class PipeDesc; diff -r c2687aa5e5ca -r 7eb99acd567f src/share/vm/adlc/output_c.cpp --- a/src/share/vm/adlc/output_c.cpp Mon Jan 25 14:56:57 2016 -0800 +++ b/src/share/vm/adlc/output_c.cpp Mon Jan 25 14:57:27 2016 -0800 @@ -155,26 +155,9 @@ fprintf(fp_hpp,"// Register masks, one for each register class.\n"); _register->_rclasses.reset(); for (rc_name = NULL; (rc_name = _register->_rclasses.iter()) != NULL;) { - const char *prefix = ""; RegClass *reg_class = _register->getRegClass(rc_name); assert(reg_class, "Using an undefined register class"); - - const char* rc_name_to_upper = toUpper(rc_name); - - if (reg_class->_user_defined == NULL) { - fprintf(fp_hpp, "extern const RegMask _%s%s_mask;\n", prefix, rc_name_to_upper); - fprintf(fp_hpp, "inline const RegMask &%s%s_mask() { return _%s%s_mask; }\n", prefix, rc_name_to_upper, prefix, rc_name_to_upper); - } else { - fprintf(fp_hpp, "inline const RegMask &%s%s_mask() { %s }\n", prefix, rc_name_to_upper, reg_class->_user_defined); - } - - if (reg_class->_stack_or_reg) { - assert(reg_class->_user_defined == NULL, "no user defined reg class here"); - fprintf(fp_hpp, "extern const RegMask _%sSTACK_OR_%s_mask;\n", prefix, rc_name_to_upper); - fprintf(fp_hpp, "inline const RegMask &%sSTACK_OR_%s_mask() { return _%sSTACK_OR_%s_mask; }\n", prefix, rc_name_to_upper, prefix, rc_name_to_upper); - } - delete[] rc_name_to_upper; - + reg_class->declare_register_masks(fp_hpp); } } } @@ -190,35 +173,9 @@ fprintf(fp_cpp,"// Register masks, one for each register class.\n"); _register->_rclasses.reset(); for (rc_name = NULL; (rc_name = _register->_rclasses.iter()) != NULL;) { - const char *prefix = ""; RegClass *reg_class = _register->getRegClass(rc_name); assert(reg_class, "Using an undefined register class"); - - if (reg_class->_user_defined != NULL) { - continue; - } - - int len = RegisterForm::RegMask_Size(); - const char* rc_name_to_upper = toUpper(rc_name); - fprintf(fp_cpp, "const RegMask _%s%s_mask(", prefix, rc_name_to_upper); - - { - int i; - for(i = 0; i < len - 1; i++) { - fprintf(fp_cpp," 0x%x,", reg_class->regs_in_word(i, false)); - } - fprintf(fp_cpp," 0x%x );\n", reg_class->regs_in_word(i, false)); - } - - if (reg_class->_stack_or_reg) { - int i; - fprintf(fp_cpp, "const RegMask _%sSTACK_OR_%s_mask(", prefix, rc_name_to_upper); - for(i = 0; i < len - 1; i++) { - fprintf(fp_cpp," 0x%x,",reg_class->regs_in_word(i, true)); - } - fprintf(fp_cpp," 0x%x );\n",reg_class->regs_in_word(i, true)); - } - delete[] rc_name_to_upper; + reg_class->build_register_masks(fp_cpp); } } } diff -r c2687aa5e5ca -r 7eb99acd567f src/share/vm/c1/c1_GraphBuilder.cpp --- a/src/share/vm/c1/c1_GraphBuilder.cpp Mon Jan 25 14:56:57 2016 -0800 +++ b/src/share/vm/c1/c1_GraphBuilder.cpp Mon Jan 25 14:57:27 2016 -0800 @@ -4066,7 +4066,7 @@ ValueType* type = apop()->type(); if (type->is_constant()) { ciMethod* target = type->as_ObjectType()->constant_value()->as_member_name()->get_vmtarget(); - // If the target is another method handle invoke try recursivly to get + // If the target is another method handle invoke, try to recursively get // a better target. if (target->is_method_handle_intrinsic()) { if (try_method_handle_inline(target)) { diff -r c2687aa5e5ca -r 7eb99acd567f src/share/vm/c1/c1_LIR.cpp --- a/src/share/vm/c1/c1_LIR.cpp Mon Jan 25 14:56:57 2016 -0800 +++ b/src/share/vm/c1/c1_LIR.cpp Mon Jan 25 14:57:27 2016 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 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 @@ -142,16 +142,11 @@ #ifndef PRODUCT -void LIR_Address::verify() const { +void LIR_Address::verify0() const { #if defined(SPARC) || defined(PPC) assert(scale() == times_1, "Scaled addressing mode not available on SPARC/PPC and should not be used"); assert(disp() == 0 || index()->is_illegal(), "can't have both"); #endif -#ifdef ARM - assert(disp() == 0 || index()->is_illegal(), "can't have both"); - // Note: offsets higher than 4096 must not be rejected here. They can - // be handled by the back-end or will be rejected if not. -#endif #ifdef _LP64 assert(base()->is_cpu_register(), "wrong base operand"); assert(index()->is_illegal() || index()->is_double_cpu(), "wrong index operand"); @@ -459,7 +454,7 @@ //-------------------visits-------------------------- // complete rework of LIR instruction visitor. -// The virtual calls for each instruction type is replaced by a big +// The virtual call for each instruction type is replaced by a big // switch that adds the operands for each instruction void LIR_OpVisitState::visit(LIR_Op* op) { @@ -828,7 +823,8 @@ } if (opJavaCall->_info) do_info(opJavaCall->_info); - if (opJavaCall->is_method_handle_invoke()) { + if (FrameMap::method_handle_invoke_SP_save_opr() != LIR_OprFact::illegalOpr && + opJavaCall->is_method_handle_invoke()) { opJavaCall->_method_handle_invoke_SP_save_opr = FrameMap::method_handle_invoke_SP_save_opr(); do_temp(opJavaCall->_method_handle_invoke_SP_save_opr); } diff -r c2687aa5e5ca -r 7eb99acd567f src/share/vm/c1/c1_LIR.hpp --- a/src/share/vm/c1/c1_LIR.hpp Mon Jan 25 14:56:57 2016 -0800 +++ b/src/share/vm/c1/c1_LIR.hpp Mon Jan 25 14:57:27 2016 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 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 @@ -25,6 +25,7 @@ #ifndef SHARE_VM_C1_C1_LIR_HPP #define SHARE_VM_C1_C1_LIR_HPP +#include "c1/c1_Defs.hpp" #include "c1/c1_ValueType.hpp" #include "oops/method.hpp" @@ -561,7 +562,13 @@ virtual BasicType type() const { return _type; } virtual void print_value_on(outputStream* out) const PRODUCT_RETURN; - void verify() const PRODUCT_RETURN; + void verify0() const PRODUCT_RETURN; +#if defined(LIR_ADDRESS_PD_VERIFY) && !defined(PRODUCT) + void pd_verify() const; + void verify() const { pd_verify(); } +#else + void verify() const { verify0(); } +#endif static Scale scale(BasicType type); }; @@ -610,19 +617,15 @@ LIR_OprDesc::float_type | LIR_OprDesc::fpu_register | LIR_OprDesc::single_size); } -#if defined(ARM) - static LIR_Opr double_fpu(int reg1, int reg2) { return (LIR_Opr)((reg1 << LIR_OprDesc::reg1_shift) | (reg2 << LIR_OprDesc::reg2_shift) | LIR_OprDesc::double_type | LIR_OprDesc::fpu_register | LIR_OprDesc::double_size); } - static LIR_Opr single_softfp(int reg) { return (LIR_Opr)((reg << LIR_OprDesc::reg1_shift) | LIR_OprDesc::float_type | LIR_OprDesc::cpu_register | LIR_OprDesc::single_size); } - static LIR_Opr double_softfp(int reg1, int reg2) { return (LIR_Opr)((reg1 << LIR_OprDesc::reg1_shift) | (reg2 << LIR_OprDesc::reg2_shift) | LIR_OprDesc::double_type | LIR_OprDesc::cpu_register | LIR_OprDesc::double_size); } -#endif -#ifdef SPARC +#if defined(C1_LIR_MD_HPP) +# include C1_LIR_MD_HPP +#elif defined(SPARC) static LIR_Opr double_fpu(int reg1, int reg2) { return (LIR_Opr)(intptr_t)((reg1 << LIR_OprDesc::reg1_shift) | (reg2 << LIR_OprDesc::reg2_shift) | LIR_OprDesc::double_type | LIR_OprDesc::fpu_register | LIR_OprDesc::double_size); } -#endif -#ifdef X86 +#elif defined(X86) static LIR_Opr double_fpu(int reg) { return (LIR_Opr)(intptr_t)((reg << LIR_OprDesc::reg1_shift) | (reg << LIR_OprDesc::reg2_shift) | LIR_OprDesc::double_type | @@ -640,8 +643,7 @@ LIR_OprDesc::fpu_register | LIR_OprDesc::double_size | LIR_OprDesc::is_xmm_mask); } -#endif // X86 -#ifdef PPC +#elif defined(PPC) static LIR_Opr double_fpu(int reg) { return (LIR_Opr)(intptr_t)((reg << LIR_OprDesc::reg1_shift) | (reg << LIR_OprDesc::reg2_shift) | LIR_OprDesc::double_type | @@ -1214,10 +1216,8 @@ // JSR 292 support. bool is_invokedynamic() const { return code() == lir_dynamic_call; } bool is_method_handle_invoke() const { - return - method()->is_compiled_lambda_form() // Java-generated adapter - || - method()->is_method_handle_intrinsic(); // JVM-generated MH intrinsic + return method()->is_compiled_lambda_form() || // Java-generated lambda form + method()->is_method_handle_intrinsic(); // JVM-generated MH intrinsic } intptr_t vtable_offset() const { diff -r c2687aa5e5ca -r 7eb99acd567f src/share/vm/c1/c1_LIRGenerator.cpp --- a/src/share/vm/c1/c1_LIRGenerator.cpp Mon Jan 25 14:56:57 2016 -0800 +++ b/src/share/vm/c1/c1_LIRGenerator.cpp Mon Jan 25 14:57:27 2016 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 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 @@ -23,6 +23,7 @@ */ #include "precompiled.hpp" +#include "c1/c1_Defs.hpp" #include "c1/c1_Compilation.hpp" #include "c1/c1_FrameMap.hpp" #include "c1/c1_Instruction.hpp" @@ -46,10 +47,7 @@ #define __ gen()->lir()-> #endif -// TODO: ARM - Use some recognizable constant which still fits architectural constraints -#ifdef ARM -#define PATCHED_ADDR (204) -#else +#ifndef PATCHED_ADDR #define PATCHED_ADDR (max_jint) #endif @@ -1599,25 +1597,9 @@ } assert(addr->is_register(), "must be a register at this point"); -#ifdef ARM - // TODO: ARM - move to platform-dependent code - LIR_Opr tmp = FrameMap::R14_opr; - if (VM_Version::supports_movw()) { - __ move((LIR_Opr)card_table_base, tmp); - } else { - __ move(new LIR_Address(FrameMap::Rthread_opr, in_bytes(JavaThread::card_table_base_offset()), T_ADDRESS), tmp); - } - - CardTableModRefBS* ct = (CardTableModRefBS*)_bs; - LIR_Address *card_addr = new LIR_Address(tmp, addr, (LIR_Address::Scale) -CardTableModRefBS::card_shift, 0, T_BYTE); - if(((int)ct->byte_map_base & 0xff) == 0) { - __ move(tmp, card_addr); - } else { - LIR_Opr tmp_zero = new_register(T_INT); - __ move(LIR_OprFact::intConst(0), tmp_zero); - __ move(tmp_zero, card_addr); - } -#else // ARM +#ifdef CARDTABLEMODREF_POST_BARRIER_HELPER + CardTableModRef_post_barrier_helper(addr, card_table_base); +#else LIR_Opr tmp = new_pointer_register(); if (TwoOperandLIRForm) { __ move(addr, tmp); @@ -1633,7 +1615,7 @@ new LIR_Address(tmp, load_constant(card_table_base), T_BYTE)); } -#endif // ARM +#endif } @@ -2121,7 +2103,7 @@ } else { #ifdef X86 addr = new LIR_Address(base_op, index_op, LIR_Address::Scale(log2_scale), 0, dst_type); -#elif defined(ARM) +#elif defined(GENERATE_ADDRESS_IS_PREFERRED) addr = generate_address(base_op, index_op, log2_scale, 0, dst_type); #else if (index_op->is_illegal() || log2_scale == 0) { @@ -2175,6 +2157,9 @@ LIR_Opr base_op = base.result(); LIR_Opr index_op = idx.result(); +#ifdef GENERATE_ADDRESS_IS_PREFERRED + LIR_Address* addr = generate_address(base_op, index_op, log2_scale, 0, x->basic_type()); +#else #ifndef _LP64 if (base_op->type() == T_LONG) { base_op = new_register(T_INT); @@ -2204,10 +2189,19 @@ if (log2_scale != 0) { // temporary fix (platform dependent code without shift on Intel would be better) // TODO: ARM also allows embedded shift in the address - __ shift_left(index_op, log2_scale, index_op); + LIR_Opr tmp = new_pointer_register(); + if (TwoOperandLIRForm) { + __ move(index_op, tmp); + index_op = tmp; + } + __ shift_left(index_op, log2_scale, tmp); + if (!TwoOperandLIRForm) { + index_op = tmp; + } } LIR_Address* addr = new LIR_Address(base_op, index_op, x->basic_type()); +#endif // !GENERATE_ADDRESS_IS_PREFERRED __ move(value.result(), addr); } @@ -2561,7 +2555,7 @@ // need to free up storage used for OSR entry point LIR_Opr osrBuffer = block()->next()->operand(); BasicTypeList signature; - signature.append(T_INT); + signature.append(NOT_LP64(T_INT) LP64_ONLY(T_LONG)); // pass a pointer to osrBuffer CallingConvention* cc = frame_map()->c_calling_convention(&signature); __ move(osrBuffer, cc->args()->at(0)); __ call_runtime_leaf(CAST_FROM_FN_PTR(address, SharedRuntime::OSR_migration_end), @@ -2901,7 +2895,7 @@ // g) lock result registers and emit call operation // // Before issuing a call, we must spill-save all values on stack -// that are in caller-save register. "spill-save" moves thos registers +// that are in caller-save register. "spill-save" moves those registers // either in a free callee-save register or spills them if no free // callee save register is available. // @@ -2909,7 +2903,7 @@ // - if invoked between e) and f), we may lock callee save // register in "spill-save" that destroys the receiver register // before f) is executed -// - if we rearange the f) to be earlier, by loading %o0, it +// - if we rearrange f) to be earlier (by loading %o0) it // may destroy a value on the stack that is currently in %o0 // and is waiting to be spilled // - if we keep the receiver locked while doing spill-save, @@ -2942,14 +2936,16 @@ assert(receiver->is_illegal() || receiver->is_equal(LIR_Assembler::receiverOpr()), "must match"); // JSR 292 - // Preserve the SP over MethodHandle call sites. + // Preserve the SP over MethodHandle call sites, if needed. ciMethod* target = x->target(); bool is_method_handle_invoke = (// %%% FIXME: Are both of these relevant? target->is_method_handle_intrinsic() || target->is_compiled_lambda_form()); if (is_method_handle_invoke) { info->set_is_method_handle_invoke(true); - __ move(FrameMap::stack_pointer(), FrameMap::method_handle_invoke_SP_save_opr()); + if(FrameMap::method_handle_invoke_SP_save_opr() != LIR_OprFact::illegalOpr) { + __ move(FrameMap::stack_pointer(), FrameMap::method_handle_invoke_SP_save_opr()); + } } switch (x->code()) { @@ -2989,8 +2985,9 @@ } // JSR 292 - // Restore the SP after MethodHandle call sites. - if (is_method_handle_invoke) { + // Restore the SP after MethodHandle call sites, if needed. + if (is_method_handle_invoke + && FrameMap::method_handle_invoke_SP_save_opr() != LIR_OprFact::illegalOpr) { __ move(FrameMap::method_handle_invoke_SP_save_opr(), FrameMap::stack_pointer()); } diff -r c2687aa5e5ca -r 7eb99acd567f src/share/vm/c1/c1_LIRGenerator.hpp --- a/src/share/vm/c1/c1_LIRGenerator.hpp Mon Jan 25 14:56:57 2016 -0800 +++ b/src/share/vm/c1/c1_LIRGenerator.hpp Mon Jan 25 14:57:27 2016 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 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 @@ -277,6 +277,9 @@ void G1SATBCardTableModRef_post_barrier(LIR_OprDesc* addr, LIR_OprDesc* new_val); void CardTableModRef_post_barrier(LIR_OprDesc* addr, LIR_OprDesc* new_val); +#ifdef CARDTABLEMODREF_POST_BARRIER_HELPER + void CardTableModRef_post_barrier_helper(LIR_OprDesc* addr, LIR_Const* card_table_base); +#endif static LIR_Opr result_register_for(ValueType* type, bool callee = false); @@ -550,6 +553,10 @@ #ifdef ASSERT virtual void do_Assert (Assert* x); #endif + +#ifdef C1_LIRGENERATOR_MD_HPP +#include C1_LIRGENERATOR_MD_HPP +#endif }; diff -r c2687aa5e5ca -r 7eb99acd567f src/share/vm/c1/c1_LinearScan.cpp --- a/src/share/vm/c1/c1_LinearScan.cpp Mon Jan 25 14:56:57 2016 -0800 +++ b/src/share/vm/c1/c1_LinearScan.cpp Mon Jan 25 14:57:27 2016 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 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 @@ -2138,7 +2138,7 @@ assert(interval->assigned_regHi() >= pd_first_fpu_reg && interval->assigned_regHi() <= pd_last_fpu_reg, "no fpu register"); assert(assigned_reg % 2 == 0 && assigned_reg + 1 == interval->assigned_regHi(), "must be sequential and even"); LIR_Opr result = LIR_OprFact::double_fpu(interval->assigned_regHi() - pd_first_fpu_reg, assigned_reg - pd_first_fpu_reg); -#elif defined(ARM) +#elif defined(ARM32) assert(assigned_reg >= pd_first_fpu_reg && assigned_reg <= pd_last_fpu_reg, "no fpu register"); assert(interval->assigned_regHi() >= pd_first_fpu_reg && interval->assigned_regHi() <= pd_last_fpu_reg, "no fpu register"); assert(assigned_reg % 2 == 0 && assigned_reg + 1 == interval->assigned_regHi(), "must be sequential and even"); @@ -2727,7 +2727,7 @@ #ifdef SPARC assert(opr->fpu_regnrLo() == opr->fpu_regnrHi() + 1, "assumed in calculation (only fpu_regnrHi is used)"); #endif -#ifdef ARM +#ifdef ARM32 assert(opr->fpu_regnrHi() == opr->fpu_regnrLo() + 1, "assumed in calculation (only fpu_regnrLo is used)"); #endif #ifdef PPC diff -r c2687aa5e5ca -r 7eb99acd567f src/share/vm/c1/c1_Runtime1.cpp --- a/src/share/vm/c1/c1_Runtime1.cpp Mon Jan 25 14:56:57 2016 -0800 +++ b/src/share/vm/c1/c1_Runtime1.cpp Mon Jan 25 14:57:27 2016 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 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 @@ -1085,7 +1085,7 @@ #ifdef ARM if((load_klass_or_mirror_patch_id || stub_id == Runtime1::load_appendix_patching_id) && - !VM_Version::supports_movw()) { + nativeMovConstReg_at(copy_buff)->is_pc_relative()) { nmethod* nm = CodeCache::find_nmethod(instr_pc); address addr = NULL; assert(nm != NULL, "invalid nmethod_pc"); diff -r c2687aa5e5ca -r 7eb99acd567f src/share/vm/ci/bcEscapeAnalyzer.cpp --- a/src/share/vm/ci/bcEscapeAnalyzer.cpp Mon Jan 25 14:56:57 2016 -0800 +++ b/src/share/vm/ci/bcEscapeAnalyzer.cpp Mon Jan 25 14:57:27 2016 -0800 @@ -42,7 +42,7 @@ #define TRACE_BCEA(level, code) #endif -// Maintain a map of which aguments a local variable or +// Maintain a map of which arguments a local variable or // stack slot may contain. In addition to tracking // arguments, it tracks two special values, "allocated" // which represents any object allocated in the current @@ -318,14 +318,16 @@ bool must_record_dependencies = false; for (i = arg_size - 1; i >= 0; i--) { ArgumentMap arg = state.raw_pop(); - if (!is_argument(arg)) + // Check if callee arg is a caller arg or an allocated object + bool allocated = arg.contains_allocated(); + if (!(is_argument(arg) || allocated)) continue; for (int j = 0; j < _arg_size; j++) { if (arg.contains(j)) { _arg_modified[j] |= analyzer._arg_modified[i]; } } - if (!is_arg_stack(arg)) { + if (!(is_arg_stack(arg) || allocated)) { // arguments have already been recognized as escaping } else if (analyzer.is_arg_stack(i) && !analyzer.is_arg_returned(i)) { set_method_escape(arg); diff -r c2687aa5e5ca -r 7eb99acd567f src/share/vm/ci/ciMethod.cpp --- a/src/share/vm/ci/ciMethod.cpp Mon Jan 25 14:56:57 2016 -0800 +++ b/src/share/vm/ci/ciMethod.cpp Mon Jan 25 14:57:27 2016 -0800 @@ -689,7 +689,8 @@ // via assert_unique_concrete_method or assert_leaf_type. ciMethod* ciMethod::find_monomorphic_target(ciInstanceKlass* caller, ciInstanceKlass* callee_holder, - ciInstanceKlass* actual_recv) { + ciInstanceKlass* actual_recv, + bool check_access) { check_is_loaded(); if (actual_recv->is_interface()) { @@ -697,7 +698,7 @@ return NULL; } - ciMethod* root_m = resolve_invoke(caller, actual_recv); + ciMethod* root_m = resolve_invoke(caller, actual_recv, check_access); if (root_m == NULL) { // Something went wrong looking up the actual receiver method. return NULL; @@ -776,7 +777,7 @@ // // Given a known receiver klass, find the target for the call. // Return NULL if the call has no target or the target is abstract. -ciMethod* ciMethod::resolve_invoke(ciKlass* caller, ciKlass* exact_receiver) { +ciMethod* ciMethod::resolve_invoke(ciKlass* caller, ciKlass* exact_receiver, bool check_access) { check_is_loaded(); VM_ENTRY_MARK; @@ -793,9 +794,9 @@ || InstanceKlass::cast(h_recv())->is_linked() && !exact_receiver->is_interface()) { if (holder()->is_interface()) { - m = LinkResolver::resolve_interface_call_or_null(h_recv, h_resolved, h_name, h_signature, caller_klass); + m = LinkResolver::resolve_interface_call_or_null(h_recv, h_resolved, h_name, h_signature, caller_klass, check_access); } else { - m = LinkResolver::resolve_virtual_call_or_null(h_recv, h_resolved, h_name, h_signature, caller_klass); + m = LinkResolver::resolve_virtual_call_or_null(h_recv, h_resolved, h_name, h_signature, caller_klass, check_access); } } diff -r c2687aa5e5ca -r 7eb99acd567f src/share/vm/ci/ciMethod.hpp --- a/src/share/vm/ci/ciMethod.hpp Mon Jan 25 14:56:57 2016 -0800 +++ b/src/share/vm/ci/ciMethod.hpp Mon Jan 25 14:57:27 2016 -0800 @@ -172,9 +172,9 @@ // Code size for inlining decisions. int code_size_for_inlining(); - bool caller_sensitive() { return get_Method()->caller_sensitive(); } - bool force_inline() { return get_Method()->force_inline(); } - bool dont_inline() { return get_Method()->dont_inline(); } + bool caller_sensitive() const { return get_Method()->caller_sensitive(); } + bool force_inline() const { return get_Method()->force_inline(); } + bool dont_inline() const { return get_Method()->dont_inline(); } int comp_level(); int highest_osr_comp_level(); @@ -248,11 +248,12 @@ // its calling environment. ciMethod* find_monomorphic_target(ciInstanceKlass* caller, ciInstanceKlass* callee_holder, - ciInstanceKlass* actual_receiver); + ciInstanceKlass* actual_receiver, + bool check_access = true); // Given a known receiver klass, find the target for the call. // Return NULL if the call has no target or is abstract. - ciMethod* resolve_invoke(ciKlass* caller, ciKlass* exact_receiver); + ciMethod* resolve_invoke(ciKlass* caller, ciKlass* exact_receiver, bool check_access = true); // Find the proper vtable index to invoke this method. int resolve_vtable_index(ciKlass* caller, ciKlass* receiver); diff -r c2687aa5e5ca -r 7eb99acd567f src/share/vm/ci/ciTypeFlow.cpp diff -r c2687aa5e5ca -r 7eb99acd567f src/share/vm/classfile/classFileParser.cpp --- a/src/share/vm/classfile/classFileParser.cpp Mon Jan 25 14:56:57 2016 -0800 +++ b/src/share/vm/classfile/classFileParser.cpp Mon Jan 25 14:57:27 2016 -0800 @@ -1783,6 +1783,10 @@ if (_location != _in_method) break; // only allow for methods if (!privileged) break; // only allow in privileged code return _method_DontInline; + case vmSymbols::VM_SYMBOL_ENUM_NAME(java_lang_invoke_InjectedProfile_signature): + if (_location != _in_method) break; // only allow for methods + if (!privileged) break; // only allow in privileged code + return _method_InjectedProfile; case vmSymbols::VM_SYMBOL_ENUM_NAME(java_lang_invoke_LambdaForm_Compiled_signature): if (_location != _in_method) break; // only allow for methods if (!privileged) break; // only allow in privileged code @@ -1830,6 +1834,8 @@ m->set_force_inline(true); if (has_annotation(_method_DontInline)) m->set_dont_inline(true); + if (has_annotation(_method_InjectedProfile)) + m->set_has_injected_profile(true); if (has_annotation(_method_LambdaForm_Compiled) && m->intrinsic_id() == vmIntrinsics::_none) m->set_intrinsic_id(vmIntrinsics::_compiledLambdaForm); if (has_annotation(_method_LambdaForm_Hidden)) @@ -4426,9 +4432,15 @@ Method* m = k->lookup_method(vmSymbols::finalize_method_name(), vmSymbols::void_method_signature()); if (m != NULL && !m->is_empty_method()) { - f = true; + f = true; } - assert(f == k->has_finalizer(), "inconsistent has_finalizer"); + + // Spec doesn't prevent agent from redefinition of empty finalizer. + // Despite the fact that it's generally bad idea and redefined finalizer + // will not work as expected we shouldn't abort vm in this case + if (!k->has_redefined_this_or_super()) { + assert(f == k->has_finalizer(), "inconsistent has_finalizer"); + } #endif // Check if this klass supports the java.lang.Cloneable interface diff -r c2687aa5e5ca -r 7eb99acd567f src/share/vm/classfile/classFileParser.hpp --- a/src/share/vm/classfile/classFileParser.hpp Mon Jan 25 14:56:57 2016 -0800 +++ b/src/share/vm/classfile/classFileParser.hpp Mon Jan 25 14:57:27 2016 -0800 @@ -126,6 +126,7 @@ _method_CallerSensitive, _method_ForceInline, _method_DontInline, + _method_InjectedProfile, _method_LambdaForm_Compiled, _method_LambdaForm_Hidden, _sun_misc_Contended, diff -r c2687aa5e5ca -r 7eb99acd567f src/share/vm/classfile/classLoaderData.cpp --- a/src/share/vm/classfile/classLoaderData.cpp Mon Jan 25 14:56:57 2016 -0800 +++ b/src/share/vm/classfile/classLoaderData.cpp Mon Jan 25 14:57:27 2016 -0800 @@ -320,27 +320,6 @@ } } -#ifdef ASSERT -class AllAliveClosure : public OopClosure { - BoolObjectClosure* _is_alive_closure; - bool _found_dead; - public: - AllAliveClosure(BoolObjectClosure* is_alive_closure) : _is_alive_closure(is_alive_closure), _found_dead(false) {} - template void do_oop_work(T* p) { - T heap_oop = oopDesc::load_heap_oop(p); - if (!oopDesc::is_null(heap_oop)) { - oop obj = oopDesc::decode_heap_oop_not_null(heap_oop); - if (!_is_alive_closure->do_object_b(obj)) { - _found_dead = true; - } - } - } - void do_oop(oop* p) { do_oop_work(p); } - void do_oop(narrowOop* p) { do_oop_work(p); } - bool found_dead() { return _found_dead; } -}; -#endif - oop ClassLoaderData::keep_alive_object() const { assert(!keep_alive(), "Don't use with CLDs that are artificially kept alive"); return is_anonymous() ? _klasses->java_mirror() : class_loader(); @@ -350,15 +329,6 @@ bool alive = keep_alive() // null class loader and incomplete anonymous klasses. || is_alive_closure->do_object_b(keep_alive_object()); -#ifdef ASSERT - if (alive) { - AllAliveClosure all_alive_closure(is_alive_closure); - KlassToOopClosure klass_closure(&all_alive_closure); - const_cast(this)->oops_do(&all_alive_closure, &klass_closure, false); - assert(!all_alive_closure.found_dead(), err_msg("Found dead oop in alive cld: " PTR_FORMAT, p2i(this))); - } -#endif - return alive; } @@ -912,7 +882,7 @@ } Klass* ClassLoaderDataGraphKlassIteratorAtomic::next_klass() { - Klass* head = (Klass*)_next_klass; + Klass* head = _next_klass; while (head != NULL) { Klass* next = next_klass_in_cldg(head); diff -r c2687aa5e5ca -r 7eb99acd567f src/share/vm/classfile/classLoaderData.hpp --- a/src/share/vm/classfile/classLoaderData.hpp Mon Jan 25 14:56:57 2016 -0800 +++ b/src/share/vm/classfile/classLoaderData.hpp Mon Jan 25 14:57:27 2016 -0800 @@ -307,7 +307,7 @@ // An iterator that distributes Klasses to parallel worker threads. class ClassLoaderDataGraphKlassIteratorAtomic : public StackObj { - volatile Klass* _next_klass; + Klass* volatile _next_klass; public: ClassLoaderDataGraphKlassIteratorAtomic(); Klass* next_klass(); diff -r c2687aa5e5ca -r 7eb99acd567f src/share/vm/classfile/defaultMethods.cpp --- a/src/share/vm/classfile/defaultMethods.cpp Mon Jan 25 14:56:57 2016 -0800 +++ b/src/share/vm/classfile/defaultMethods.cpp Mon Jan 25 14:57:27 2016 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 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 @@ -1096,6 +1096,7 @@ } // update idnum for new location merged_methods->at(i)->set_method_idnum(i); + merged_methods->at(i)->set_orig_method_idnum(i); } // Verify correct order diff -r c2687aa5e5ca -r 7eb99acd567f src/share/vm/classfile/javaClasses.cpp --- a/src/share/vm/classfile/javaClasses.cpp Mon Jan 25 14:56:57 2016 -0800 +++ b/src/share/vm/classfile/javaClasses.cpp Mon Jan 25 14:57:27 2016 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 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 @@ -124,7 +124,7 @@ tty->print_cr(" name: %s, sig: %s, flags: %08x", fs.name()->as_C_string(), fs.signature()->as_C_string(), fs.access_flags().as_int()); } #endif //PRODUCT - fatal("Invalid layout of preloaded class"); + vm_exit_during_initialization("Invalid layout of preloaded class: use -XX:+TraceClassLoading to see the origin of the problem class"); } dest_offset = fd.offset(); } @@ -788,6 +788,22 @@ return name; } +// Returns the Java name for this Java mirror (Resource allocated) +// See Klass::external_name(). +// For primitive type Java mirrors, its type name is returned. +const char* java_lang_Class::as_external_name(oop java_class) { + assert(java_lang_Class::is_instance(java_class), "must be a Class object"); + const char* name = NULL; + if (is_primitive(java_class)) { + name = type2name(primitive_type(java_class)); + } else { + name = as_Klass(java_class)->external_name(); + } + if (name == NULL) { + name = ""; + } + return name; +} Klass* java_lang_Class::array_klass(oop java_class) { Klass* k = ((Klass*)java_class->metadata_field(_array_klass_offset)); @@ -1284,7 +1300,8 @@ } static inline bool version_matches(Method* method, int version) { - return (method->constants()->version() == version && version < MAX_VERSION); + assert(version < MAX_VERSION, "version is too big"); + return method != NULL && (method->constants()->version() == version); } static inline int get_line_number(Method* method, int bci) { @@ -1314,6 +1331,7 @@ typeArrayOop _methods; typeArrayOop _bcis; objArrayOop _mirrors; + typeArrayOop _cprefs; // needed to insulate method name against redefinition int _index; No_Safepoint_Verifier _nsv; @@ -1321,8 +1339,9 @@ enum { trace_methods_offset = java_lang_Throwable::trace_methods_offset, - trace_bcis_offset = java_lang_Throwable::trace_bcis_offset, + trace_bcis_offset = java_lang_Throwable::trace_bcis_offset, trace_mirrors_offset = java_lang_Throwable::trace_mirrors_offset, + trace_cprefs_offset = java_lang_Throwable::trace_cprefs_offset, trace_next_offset = java_lang_Throwable::trace_next_offset, trace_size = java_lang_Throwable::trace_size, trace_chunk_size = java_lang_Throwable::trace_chunk_size @@ -1344,9 +1363,14 @@ assert(mirrors != NULL, "mirror array should be initialized in backtrace"); return mirrors; } + static typeArrayOop get_cprefs(objArrayHandle chunk) { + typeArrayOop cprefs = typeArrayOop(chunk->obj_at(trace_cprefs_offset)); + assert(cprefs != NULL, "cprefs array should be initialized in backtrace"); + return cprefs; + } // constructor for new backtrace - BacktraceBuilder(TRAPS): _methods(NULL), _bcis(NULL), _head(NULL), _mirrors(NULL) { + BacktraceBuilder(TRAPS): _methods(NULL), _bcis(NULL), _head(NULL), _mirrors(NULL), _cprefs(NULL) { expand(CHECK); _backtrace = _head; _index = 0; @@ -1356,6 +1380,7 @@ _methods = get_methods(backtrace); _bcis = get_bcis(backtrace); _mirrors = get_mirrors(backtrace); + _cprefs = get_cprefs(backtrace); assert(_methods->length() == _bcis->length() && _methods->length() == _mirrors->length(), "method and source information arrays should match"); @@ -1381,17 +1406,22 @@ objArrayOop mirrors = oopFactory::new_objectArray(trace_chunk_size, CHECK); objArrayHandle new_mirrors(THREAD, mirrors); + typeArrayOop cprefs = oopFactory::new_shortArray(trace_chunk_size, CHECK); + typeArrayHandle new_cprefs(THREAD, cprefs); + if (!old_head.is_null()) { old_head->obj_at_put(trace_next_offset, new_head()); } new_head->obj_at_put(trace_methods_offset, new_methods()); new_head->obj_at_put(trace_bcis_offset, new_bcis()); new_head->obj_at_put(trace_mirrors_offset, new_mirrors()); + new_head->obj_at_put(trace_cprefs_offset, new_cprefs()); _head = new_head(); _methods = new_methods(); _bcis = new_bcis(); _mirrors = new_mirrors(); + _cprefs = new_cprefs(); _index = 0; } @@ -1411,8 +1441,9 @@ method = mhandle(); } - _methods->short_at_put(_index, method->method_idnum()); + _methods->short_at_put(_index, method->orig_method_idnum()); _bcis->int_at_put(_index, merge_bci_and_version(bci, method->constants()->version())); + _cprefs->short_at_put(_index, method->name_index()); // We need to save the mirrors in the backtrace to keep the class // from being unloaded while we still have this stack trace. @@ -1425,27 +1456,26 @@ // Print stack trace element to resource allocated buffer char* java_lang_Throwable::print_stack_element_to_buffer(Handle mirror, - int method_id, int version, int bci) { + int method_id, int version, int bci, int cpref) { // Get strings and string lengths InstanceKlass* holder = InstanceKlass::cast(java_lang_Class::as_Klass(mirror())); const char* klass_name = holder->external_name(); int buf_len = (int)strlen(klass_name); - // The method id may point to an obsolete method, can't get more stack information - Method* method = holder->method_with_idnum(method_id); - if (method == NULL) { - char* buf = NEW_RESOURCE_ARRAY(char, buf_len + 64); - // This is what the java code prints in this case - added Redefined - sprintf(buf, "\tat %s.null (Redefined)", klass_name); - return buf; - } - - char* method_name = method->name()->as_C_string(); + Method* method = holder->method_with_orig_idnum(method_id, version); + + // The method can be NULL if the requested class version is gone + Symbol* sym = (method != NULL) ? method->name() : holder->constants()->symbol_at(cpref); + char* method_name = sym->as_C_string(); buf_len += (int)strlen(method_name); + // Use a specific ik version as a holder since the mirror might + // refer to a version that is now obsolete and no longer accessible + // via the previous versions list. + holder = holder->get_klass_version(version); char* source_file_name = NULL; - if (version_matches(method, version)) { + if (holder != NULL) { Symbol* source = holder->source_file_name(); if (source != NULL) { source_file_name = source->as_C_string(); @@ -1487,17 +1517,18 @@ } void java_lang_Throwable::print_stack_element(outputStream *st, Handle mirror, - int method_id, int version, int bci) { + int method_id, int version, int bci, int cpref) { ResourceMark rm; - char* buf = print_stack_element_to_buffer(mirror, method_id, version, bci); + char* buf = print_stack_element_to_buffer(mirror, method_id, version, bci, cpref); st->print_cr("%s", buf); } void java_lang_Throwable::print_stack_element(outputStream *st, methodHandle method, int bci) { Handle mirror = method->method_holder()->java_mirror(); - int method_id = method->method_idnum(); + int method_id = method->orig_method_idnum(); int version = method->constants()->version(); - print_stack_element(st, mirror, method_id, version, bci); + int cpref = method->name_index(); + print_stack_element(st, mirror, method_id, version, bci, cpref); } const char* java_lang_Throwable::no_stack_trace_message() { @@ -1522,6 +1553,7 @@ typeArrayHandle methods (THREAD, BacktraceBuilder::get_methods(result)); typeArrayHandle bcis (THREAD, BacktraceBuilder::get_bcis(result)); objArrayHandle mirrors (THREAD, BacktraceBuilder::get_mirrors(result)); + typeArrayHandle cprefs (THREAD, BacktraceBuilder::get_cprefs(result)); int length = methods()->length(); for (int index = 0; index < length; index++) { @@ -1531,7 +1563,8 @@ int method = methods->short_at(index); int version = version_at(bcis->int_at(index)); int bci = bci_at(bcis->int_at(index)); - print_stack_element(st, mirror, method, version, bci); + int cpref = cprefs->short_at(index); + print_stack_element(st, mirror, method, version, bci, cpref); } result = objArrayHandle(THREAD, objArrayOop(result->obj_at(trace_next_offset))); } @@ -1815,29 +1848,30 @@ if (chunk == NULL) { THROW_(vmSymbols::java_lang_IndexOutOfBoundsException(), NULL); } - // Get method id, bci, version and mirror from chunk + // Get method id, bci, version, mirror and cpref from chunk typeArrayOop methods = BacktraceBuilder::get_methods(chunk); typeArrayOop bcis = BacktraceBuilder::get_bcis(chunk); objArrayOop mirrors = BacktraceBuilder::get_mirrors(chunk); + typeArrayOop cprefs = BacktraceBuilder::get_cprefs(chunk); assert(methods != NULL && bcis != NULL && mirrors != NULL, "sanity check"); int method = methods->short_at(chunk_index); int version = version_at(bcis->int_at(chunk_index)); int bci = bci_at(bcis->int_at(chunk_index)); + int cpref = cprefs->short_at(chunk_index); Handle mirror(THREAD, mirrors->obj_at(chunk_index)); // Chunk can be partial full if (mirror.is_null()) { THROW_(vmSymbols::java_lang_IndexOutOfBoundsException(), NULL); } - - oop element = java_lang_StackTraceElement::create(mirror, method, version, bci, CHECK_0); + oop element = java_lang_StackTraceElement::create(mirror, method, version, bci, cpref, CHECK_0); return element; } oop java_lang_StackTraceElement::create(Handle mirror, int method_id, - int version, int bci, TRAPS) { + int version, int bci, int cpref, TRAPS) { // Allocate java.lang.StackTraceElement instance Klass* k = SystemDictionary::StackTraceElement_klass(); assert(k != NULL, "must be loaded in 1.4+"); @@ -1854,17 +1888,13 @@ oop classname = StringTable::intern((char*) str, CHECK_0); java_lang_StackTraceElement::set_declaringClass(element(), classname); - Method* method = holder->method_with_idnum(method_id); - // Method on stack may be obsolete because it was redefined so cannot be - // found by idnum. - if (method == NULL) { - // leave name and fileName null - java_lang_StackTraceElement::set_lineNumber(element(), -1); - return element(); - } + Method* method = holder->method_with_orig_idnum(method_id, version); + + // The method can be NULL if the requested class version is gone + Symbol* sym = (method != NULL) ? method->name() : holder->constants()->symbol_at(cpref); // Fill in method name - oop methodname = StringTable::intern(method->name(), CHECK_0); + oop methodname = StringTable::intern(sym, CHECK_0); java_lang_StackTraceElement::set_methodName(element(), methodname); if (!version_matches(method, version)) { @@ -1873,6 +1903,11 @@ java_lang_StackTraceElement::set_lineNumber(element(), -1); } else { // Fill in source file name and line number. + // Use a specific ik version as a holder since the mirror might + // refer to a version that is now obsolete and no longer accessible + // via the previous versions list. + holder = holder->get_klass_version(version); + assert(holder != NULL, "sanity check"); Symbol* source = holder->source_file_name(); if (ShowHiddenFrames && source == NULL) source = vmSymbols::unknown_class_name(); @@ -1887,8 +1922,9 @@ oop java_lang_StackTraceElement::create(methodHandle method, int bci, TRAPS) { Handle mirror (THREAD, method->method_holder()->java_mirror()); - int method_id = method->method_idnum(); - return create(mirror, method_id, method->constants()->version(), bci, THREAD); + int method_id = method->orig_method_idnum(); + int cpref = method->name_index(); + return create(mirror, method_id, method->constants()->version(), bci, cpref, THREAD); } void java_lang_reflect_AccessibleObject::compute_offsets() { @@ -2787,33 +2823,6 @@ 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, 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"); - - 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 - void java_lang_invoke_MemberName::set_vmtarget(oop mname, Metadata* ref) { assert(is_instance(mname), "wrong type"); // check the type of the vmtarget @@ -3587,7 +3596,7 @@ tty->print_cr(" name: %s, sig: %s, flags: %08x", fs.name()->as_C_string(), fs.signature()->as_C_string(), fs.access_flags().as_int()); } #endif //PRODUCT - fatal("Invalid layout of preloaded class"); + vm_exit_during_initialization("Invalid layout of preloaded class: use -XX:+TraceClassLoading to see the origin of the problem class"); return -1; } diff -r c2687aa5e5ca -r 7eb99acd567f src/share/vm/classfile/javaClasses.hpp --- a/src/share/vm/classfile/javaClasses.hpp Mon Jan 25 14:56:57 2016 -0800 +++ b/src/share/vm/classfile/javaClasses.hpp Mon Jan 25 14:57:27 2016 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 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 @@ -275,6 +275,7 @@ } static Symbol* as_signature(oop java_class, bool intern_if_not_found, TRAPS); static void print_signature(oop java_class, outputStream *st); + static const char* as_external_name(oop java_class); // Testing static bool is_instance(oop obj) { return obj != NULL && obj->klass() == SystemDictionary::Class_klass(); @@ -489,8 +490,9 @@ trace_methods_offset = 0, trace_bcis_offset = 1, trace_mirrors_offset = 2, - trace_next_offset = 3, - trace_size = 4, + trace_cprefs_offset = 3, + trace_next_offset = 4, + trace_size = 5, trace_chunk_size = 32 }; @@ -501,7 +503,7 @@ static int static_unassigned_stacktrace_offset; // Printing - static char* print_stack_element_to_buffer(Handle mirror, int method, int version, int bci); + static char* print_stack_element_to_buffer(Handle mirror, int method, int version, int bci, int cpref); // StackTrace (programmatic access, new since 1.4) static void clear_stacktrace(oop throwable); // No stack trace available @@ -522,7 +524,7 @@ static oop message(Handle throwable); static void set_message(oop throwable, oop value); static void print_stack_element(outputStream *st, Handle mirror, int method, - int version, int bci); + int version, int bci, int cpref); static void print_stack_element(outputStream *st, methodHandle method, int bci); static void print_stack_usage(Handle stream); @@ -1100,10 +1102,6 @@ static Metadata* vmtarget(oop mname); static void set_vmtarget(oop mname, Metadata* target); -#if INCLUDE_JVMTI - 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); static void set_vmindex(oop mname, intptr_t index); @@ -1331,7 +1329,7 @@ static void set_lineNumber(oop element, int value); // Create an instance of StackTraceElement - static oop create(Handle mirror, int method, int version, int bci, TRAPS); + static oop create(Handle mirror, int method, int version, int bci, int cpref, TRAPS); static oop create(methodHandle method, int bci, TRAPS); // Debugging diff -r c2687aa5e5ca -r 7eb99acd567f src/share/vm/classfile/systemDictionary.cpp --- a/src/share/vm/classfile/systemDictionary.cpp Mon Jan 25 14:56:57 2016 -0800 +++ b/src/share/vm/classfile/systemDictionary.cpp Mon Jan 25 14:57:27 2016 -0800 @@ -2366,9 +2366,6 @@ assert(THREAD->can_call_java() ,""); Handle method_type = SystemDictionary::find_method_handle_type(signature, accessing_klass, CHECK_(empty)); - if (false) { // FIXME: Decide if the Java upcall should resolve signatures. - method_type = java_lang_String::create_from_symbol(signature, CHECK_(empty)); - } KlassHandle mh_klass = SystemDictionary::MethodHandle_klass(); int ref_kind = JVM_REF_invokeVirtual; @@ -2400,6 +2397,24 @@ return unpack_method_and_appendix(mname, accessing_klass, appendix_box, appendix_result, THREAD); } +// Decide if we can globally cache a lookup of this class, to be returned to any client that asks. +// We must ensure that all class loaders everywhere will reach this class, for any client. +// This is a safe bet for public classes in java.lang, such as Object and String. +// We also include public classes in java.lang.invoke, because they appear frequently in system-level method types. +// Out of an abundance of caution, we do not include any other classes, not even for packages like java.util. +static bool is_always_visible_class(oop mirror) { + Klass* klass = java_lang_Class::as_Klass(mirror); + if (klass->oop_is_objArray()) { + klass = ObjArrayKlass::cast(klass)->bottom_klass(); // check element type + } + if (klass->oop_is_typeArray()) { + return true; // primitive array + } + assert(klass->oop_is_instance(), klass->external_name()); + return klass->is_public() && + (InstanceKlass::cast(klass)->is_same_class_package(SystemDictionary::Object_klass()) || // java.lang + InstanceKlass::cast(klass)->is_same_class_package(SystemDictionary::MethodHandle_klass())); // java.lang.invoke +} // Ask Java code to find or construct a java.lang.invoke.MethodType for the given // signature, as interpreted relative to the given class loader. @@ -2422,32 +2437,33 @@ } Handle class_loader, protection_domain; - bool is_on_bcp = true; // keep this true as long as we can materialize from the boot classloader + if (accessing_klass.not_null()) { + class_loader = Handle(THREAD, InstanceKlass::cast(accessing_klass())->class_loader()); + protection_domain = Handle(THREAD, InstanceKlass::cast(accessing_klass())->protection_domain()); + } + bool can_be_cached = true; int npts = ArgumentCount(signature).size(); objArrayHandle pts = oopFactory::new_objArray(SystemDictionary::Class_klass(), npts, CHECK_(empty)); int arg = 0; - Handle rt; // the return type from the signature + Handle rt; // the return type from the signature ResourceMark rm(THREAD); for (SignatureStream ss(signature); !ss.is_done(); ss.next()) { oop mirror = NULL; - if (is_on_bcp) { - // Note: class_loader & protection_domain are both null at this point. - mirror = ss.as_java_mirror(class_loader, protection_domain, + if (can_be_cached) { + // Use neutral class loader to lookup candidate classes to be placed in the cache. + mirror = ss.as_java_mirror(Handle(), Handle(), SignatureStream::ReturnNull, CHECK_(empty)); - if (mirror == NULL) { - // fall back from BCP to accessing_klass - if (accessing_klass.not_null()) { - class_loader = Handle(THREAD, InstanceKlass::cast(accessing_klass())->class_loader()); - protection_domain = Handle(THREAD, InstanceKlass::cast(accessing_klass())->protection_domain()); - } - is_on_bcp = false; + if (mirror == NULL || (ss.is_object() && !is_always_visible_class(mirror))) { + // Fall back to accessing_klass context. + can_be_cached = false; } } - if (!is_on_bcp) { + if (!can_be_cached) { // Resolve, throwing a real error if it doesn't work. mirror = ss.as_java_mirror(class_loader, protection_domain, SignatureStream::NCDFError, CHECK_(empty)); } + assert(!oopDesc::is_null(mirror), ss.as_symbol(THREAD)->as_C_string()); if (ss.at_return_type()) rt = Handle(THREAD, mirror); else @@ -2479,7 +2495,7 @@ &args, CHECK_(empty)); Handle method_type(THREAD, (oop) result.get_jobject()); - if (is_on_bcp) { + if (can_be_cached) { // We can cache this MethodType inside the JVM. MutexLocker ml(SystemDictionary_lock, THREAD); spe = invoke_method_table()->find_entry(index, hash, signature, null_iid); diff -r c2687aa5e5ca -r 7eb99acd567f src/share/vm/classfile/verifier.cpp --- a/src/share/vm/classfile/verifier.cpp Mon Jan 25 14:56:57 2016 -0800 +++ b/src/share/vm/classfile/verifier.cpp Mon Jan 25 14:57:27 2016 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 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 @@ -655,6 +655,7 @@ bool this_uninit = false; // Set to true when invokespecial initialized 'this' + bool verified_exc_handlers = false; // Merge with the next instruction { @@ -686,6 +687,18 @@ } } + // Look for possible jump target in exception handlers and see if it + // matches current_frame. Do this check here for astore*, dstore*, + // fstore*, istore*, and lstore* opcodes because they can change the type + // state by adding a local. JVM Spec says that the incoming type state + // should be used for this check. So, do the check here before a possible + // local is added to the type state. + if (Bytecodes::is_store_into_local(opcode) && bci >= ex_min && bci < ex_max) { + verify_exception_handler_targets( + bci, this_uninit, ¤t_frame, &stackmap_table, CHECK_VERIFY(this)); + verified_exc_handlers = true; + } + switch (opcode) { case Bytecodes::_nop : no_control_flow = false; break; @@ -1662,9 +1675,13 @@ } // end switch } // end Merge with the next instruction - // Look for possible jump target in exception handlers and see if it - // matches current_frame - if (bci >= ex_min && bci < ex_max) { + // Look for possible jump target in exception handlers and see if it matches + // current_frame. Don't do this check if it has already been done (for + // ([a,d,f,i,l]store* opcodes). This check cannot be done earlier because + // opcodes, such as invokespecial, may set the this_uninit flag. + assert(!(verified_exc_handlers && this_uninit), + "Exception handler targets got verified before this_uninit got set"); + if (!verified_exc_handlers && bci >= ex_min && bci < ex_max) { verify_exception_handler_targets( bci, this_uninit, ¤t_frame, &stackmap_table, CHECK_VERIFY(this)); } @@ -2232,14 +2249,20 @@ } // Look at the method's handlers. If the bci is in the handler's try block -// then check if the handler_pc is already on the stack. If not, push it. +// then check if the handler_pc is already on the stack. If not, push it +// unless the handler has already been scanned. void ClassVerifier::push_handlers(ExceptionTable* exhandlers, + GrowableArray* handler_list, GrowableArray* handler_stack, u4 bci) { int exlength = exhandlers->length(); for(int x = 0; x < exlength; x++) { if (bci >= exhandlers->start_pc(x) && bci < exhandlers->end_pc(x)) { - handler_stack->append_if_missing(exhandlers->handler_pc(x)); + u4 exhandler_pc = exhandlers->handler_pc(x); + if (!handler_list->contains(exhandler_pc)) { + handler_stack->append_if_missing(exhandler_pc); + handler_list->append(exhandler_pc); + } } } } @@ -2257,6 +2280,10 @@ GrowableArray* bci_stack = new GrowableArray(30); // Create stack for handlers for try blocks containing this handler. GrowableArray* handler_stack = new GrowableArray(30); + // Create list of handlers that have been pushed onto the handler_stack + // so that handlers embedded inside of their own TRY blocks only get + // scanned once. + GrowableArray* handler_list = new GrowableArray(30); // Create list of visited branch opcodes (goto* and if*). GrowableArray* visited_branches = new GrowableArray(30); ExceptionTable exhandlers(_method()); @@ -2275,7 +2302,7 @@ // If the bytecode is in a TRY block, push its handlers so they // will get parsed. - push_handlers(&exhandlers, handler_stack, bci); + push_handlers(&exhandlers, handler_list, handler_stack, bci); switch (opcode) { case Bytecodes::_if_icmpeq: @@ -2488,8 +2515,7 @@ // of the current class. VerificationType objectref_type = new_class_type; if (name_in_supers(ref_class_type.name(), current_class())) { - Klass* ref_klass = load_class( - ref_class_type.name(), CHECK_VERIFY(this)); + Klass* ref_klass = load_class(ref_class_type.name(), CHECK); Method* m = InstanceKlass::cast(ref_klass)->uncached_lookup_method( vmSymbols::object_initializer_name(), cp->signature_ref_at(bcs->get_index_u2()), Klass::normal); diff -r c2687aa5e5ca -r 7eb99acd567f src/share/vm/classfile/verifier.hpp --- a/src/share/vm/classfile/verifier.hpp Mon Jan 25 14:56:57 2016 -0800 +++ b/src/share/vm/classfile/verifier.hpp Mon Jan 25 14:57:27 2016 -0800 @@ -305,9 +305,10 @@ 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. + // Used by ends_in_athrow() to push all handlers that contain bci onto the + // handler_stack, if the handler has not already been pushed on the stack. void push_handlers(ExceptionTable* exhandlers, + GrowableArray* handler_list, GrowableArray* handler_stack, u4 bci); diff -r c2687aa5e5ca -r 7eb99acd567f src/share/vm/classfile/vmSymbols.hpp --- a/src/share/vm/classfile/vmSymbols.hpp Mon Jan 25 14:56:57 2016 -0800 +++ b/src/share/vm/classfile/vmSymbols.hpp Mon Jan 25 14:57:27 2016 -0800 @@ -45,6 +45,7 @@ #define VM_SYMBOL_IGNORE(id, name) /*ignored*/ #define VM_ALIAS_IGNORE(id, id2) /*ignored*/ + // Mapping function names to values. New entries should be added below. #define VM_SYMBOLS_DO(template, do_alias) \ @@ -244,7 +245,6 @@ template(returnType_name, "returnType") \ template(signature_name, "signature") \ template(slot_name, "slot") \ - template(selectAlternative_name, "selectAlternative") \ \ /* Support for annotations (JDK 1.5 and above) */ \ \ @@ -279,6 +279,7 @@ template(java_lang_invoke_LambdaForm, "java/lang/invoke/LambdaForm") \ template(java_lang_invoke_ForceInline_signature, "Ljava/lang/invoke/ForceInline;") \ template(java_lang_invoke_DontInline_signature, "Ljava/lang/invoke/DontInline;") \ + template(java_lang_invoke_InjectedProfile_signature, "Ljava/lang/invoke/InjectedProfile;") \ template(java_lang_invoke_Stable_signature, "Ljava/lang/invoke/Stable;") \ template(java_lang_invoke_LambdaForm_Compiled_signature, "Ljava/lang/invoke/LambdaForm$Compiled;") \ template(java_lang_invoke_LambdaForm_Hidden_signature, "Ljava/lang/invoke/LambdaForm$Hidden;") \ @@ -296,8 +297,7 @@ template(setTarget_signature, "(Ljava/lang/invoke/MethodHandle;)V") \ NOT_LP64( do_alias(intptr_signature, int_signature) ) \ LP64_ONLY( do_alias(intptr_signature, long_signature) ) \ - template(selectAlternative_signature, "(ZLjava/lang/invoke/MethodHandle;Ljava/lang/invoke/MethodHandle;)Ljava/lang/invoke/MethodHandle;") \ - \ + \ /* Support for JVMCI */ \ JVMCI_VM_SYMBOLS_DO(template, do_alias) \ \ @@ -873,6 +873,12 @@ do_name( fullFence_name, "fullFence") \ do_alias( fullFence_signature, void_method_signature) \ \ + /* Custom branch frequencies profiling support for JSR292 */ \ + do_class(java_lang_invoke_MethodHandleImpl, "java/lang/invoke/MethodHandleImpl") \ + do_intrinsic(_profileBoolean, java_lang_invoke_MethodHandleImpl, profileBoolean_name, profileBoolean_signature, F_S) \ + do_name( profileBoolean_name, "profileBoolean") \ + do_signature(profileBoolean_signature, "(Z[I)Z") \ + \ /* unsafe memory references (there are a lot of them...) */ \ do_signature(getObject_signature, "(Ljava/lang/Object;J)Ljava/lang/Object;") \ do_signature(putObject_signature, "(Ljava/lang/Object;JLjava/lang/Object;)V") \ diff -r c2687aa5e5ca -r 7eb99acd567f src/share/vm/code/dependencies.cpp diff -r c2687aa5e5ca -r 7eb99acd567f src/share/vm/code/vmreg.hpp --- a/src/share/vm/code/vmreg.hpp Mon Jan 25 14:56:57 2016 -0800 +++ b/src/share/vm/code/vmreg.hpp Mon Jan 25 14:57:27 2016 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 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 @@ -32,25 +32,17 @@ #ifdef COMPILER2 #include "opto/adlcVMDeps.hpp" #include "utilities/ostream.hpp" -#ifdef TARGET_ARCH_MODEL_x86_32 +#if defined ADGLOBALS_MD_HPP +# include ADGLOBALS_MD_HPP +#elif defined TARGET_ARCH_MODEL_x86_32 # include "adfiles/adGlobals_x86_32.hpp" -#endif -#ifdef TARGET_ARCH_MODEL_x86_64 +#elif defined TARGET_ARCH_MODEL_x86_64 # include "adfiles/adGlobals_x86_64.hpp" -#endif -#ifdef TARGET_ARCH_MODEL_sparc +#elif defined TARGET_ARCH_MODEL_sparc # include "adfiles/adGlobals_sparc.hpp" -#endif -#ifdef TARGET_ARCH_MODEL_zero +#elif defined TARGET_ARCH_MODEL_zero # include "adfiles/adGlobals_zero.hpp" -#endif -#ifdef TARGET_ARCH_MODEL_arm -# include "adfiles/adGlobals_arm.hpp" -#endif -#ifdef TARGET_ARCH_MODEL_ppc_32 -# include "adfiles/adGlobals_ppc_32.hpp" -#endif -#ifdef TARGET_ARCH_MODEL_ppc_64 +#elif defined TARGET_ARCH_MODEL_ppc_64 # include "adfiles/adGlobals_ppc_64.hpp" #endif #endif diff -r c2687aa5e5ca -r 7eb99acd567f src/share/vm/compiler/compileBroker.cpp --- a/src/share/vm/compiler/compileBroker.cpp Mon Jan 25 14:56:57 2016 -0800 +++ b/src/share/vm/compiler/compileBroker.cpp Mon Jan 25 14:57:27 2016 -0800 @@ -2152,6 +2152,8 @@ DTRACE_METHOD_COMPILE_BEGIN_PROBE(method, compiler_name(task_level)); } + // Allocate a new set of JNI handles. + push_jni_handle_block(); Method* target_handle = task->method(); int compilable = ciEnv::MethodCompilable; const char* failure_reason = NULL; @@ -2185,9 +2187,6 @@ } else #endif // COMPILERJVMCI { - // Allocate a new set of JNI handles. - push_jni_handle_block(); - NoHandleMark nhm; ThreadToNativeFromVM ttn(thread); @@ -2234,9 +2233,10 @@ } post_compile(thread, task, event, !ci_env.failing(), &ci_env); - - pop_jni_handle_block(); } + // Remove the JNI handle block after the ciEnv destructor has run in + // the previous block. + pop_jni_handle_block(); if (failure_reason != NULL) { if (_compilation_log != NULL) { diff -r c2687aa5e5ca -r 7eb99acd567f src/share/vm/gc_implementation/concurrentMarkSweep/concurrentMarkSweepGeneration.cpp --- a/src/share/vm/gc_implementation/concurrentMarkSweep/concurrentMarkSweepGeneration.cpp Mon Jan 25 14:56:57 2016 -0800 +++ b/src/share/vm/gc_implementation/concurrentMarkSweep/concurrentMarkSweepGeneration.cpp Mon Jan 25 14:57:27 2016 -0800 @@ -598,7 +598,7 @@ _collector_policy(cp), _should_unload_classes(CMSClassUnloadingEnabled), _concurrent_cycles_since_last_unload(0), - _roots_scanning_options(SharedHeap::SO_None), + _roots_scanning_options(GenCollectedHeap::SO_None), _inter_sweep_estimate(CMS_SweepWeight, CMS_SweepPadding), _intra_sweep_estimate(CMS_SweepWeight, CMS_SweepPadding), _gc_tracer_cm(new (ResourceObj::C_HEAP, mtGC) CMSTracer()), @@ -3072,7 +3072,7 @@ gch->gen_process_roots(_cmsGen->level(), true, // younger gens are roots true, // activate StrongRootsScope - SharedHeap::ScanningOption(roots_scanning_options()), + GenCollectedHeap::ScanningOption(roots_scanning_options()), should_unload_classes(), ¬Older, NULL, @@ -3140,7 +3140,7 @@ gch->gen_process_roots(_cmsGen->level(), true, // younger gens are roots true, // activate StrongRootsScope - SharedHeap::ScanningOption(roots_scanning_options()), + GenCollectedHeap::ScanningOption(roots_scanning_options()), should_unload_classes(), ¬Older, NULL, @@ -3331,7 +3331,7 @@ void CMSCollector::setup_cms_unloading_and_verification_state() { const bool should_verify = VerifyBeforeGC || VerifyAfterGC || VerifyDuringGC || VerifyBeforeExit; - const int rso = SharedHeap::SO_AllCodeCache; + const int rso = GenCollectedHeap::SO_AllCodeCache; // We set the proper root for this CMS cycle here. if (should_unload_classes()) { // Should unload classes this cycle @@ -3343,9 +3343,11 @@ // Not unloading classes this cycle assert(!should_unload_classes(), "Inconsitency!"); + // If we are not unloading classes then add SO_AllCodeCache to root + // scanning options. + add_root_scanning_option(rso); + if ((!verifying() || unloaded_classes_last_cycle()) && should_verify) { - // Include symbols, strings and code cache elements to prevent their resurrection. - add_root_scanning_option(rso); set_verifying(true); } else if (verifying() && !should_verify) { // We were verifying, but some verification flags got disabled. @@ -3759,7 +3761,7 @@ gch->gen_process_roots(_cmsGen->level(), true, // younger gens are roots true, // activate StrongRootsScope - SharedHeap::ScanningOption(roots_scanning_options()), + GenCollectedHeap::ScanningOption(roots_scanning_options()), should_unload_classes(), ¬Older, NULL, @@ -5262,13 +5264,13 @@ gch->gen_process_roots(_collector->_cmsGen->level(), false, // yg was scanned above false, // this is parallel code - SharedHeap::ScanningOption(_collector->CMSCollector::roots_scanning_options()), + GenCollectedHeap::ScanningOption(_collector->CMSCollector::roots_scanning_options()), _collector->should_unload_classes(), &par_mri_cl, NULL, &cld_closure); assert(_collector->should_unload_classes() - || (_collector->CMSCollector::roots_scanning_options() & SharedHeap::SO_AllCodeCache), + || (_collector->CMSCollector::roots_scanning_options() & GenCollectedHeap::SO_AllCodeCache), "if we didn't scan the code cache, we have to be ready to drop nmethods with expired weak oops"); _timer.stop(); if (PrintCMSStatistics != 0) { @@ -5398,14 +5400,14 @@ gch->gen_process_roots(_collector->_cmsGen->level(), false, // yg was scanned above false, // this is parallel code - SharedHeap::ScanningOption(_collector->CMSCollector::roots_scanning_options()), + GenCollectedHeap::ScanningOption(_collector->CMSCollector::roots_scanning_options()), _collector->should_unload_classes(), &par_mrias_cl, NULL, NULL); // The dirty klasses will be handled below assert(_collector->should_unload_classes() - || (_collector->CMSCollector::roots_scanning_options() & SharedHeap::SO_AllCodeCache), + || (_collector->CMSCollector::roots_scanning_options() & GenCollectedHeap::SO_AllCodeCache), "if we didn't scan the code cache, we have to be ready to drop nmethods with expired weak oops"); _timer.stop(); if (PrintCMSStatistics != 0) { @@ -5990,14 +5992,14 @@ gch->gen_process_roots(_cmsGen->level(), true, // younger gens as roots false, // use the local StrongRootsScope - SharedHeap::ScanningOption(roots_scanning_options()), + GenCollectedHeap::ScanningOption(roots_scanning_options()), should_unload_classes(), &mrias_cl, NULL, NULL); // The dirty klasses will be handled below assert(should_unload_classes() - || (roots_scanning_options() & SharedHeap::SO_AllCodeCache), + || (roots_scanning_options() & GenCollectedHeap::SO_AllCodeCache), "if we didn't scan the code cache, we have to be ready to drop nmethods with expired weak oops"); } @@ -6642,7 +6644,6 @@ } void CMSCollector::do_CMS_operation(CMS_op_type op, GCCause::Cause gc_cause) { - gclog_or_tty->date_stamp(PrintGC && PrintGCDateStamps); TraceCPUTime tcpu(PrintGCDetails, true, gclog_or_tty); GCTraceTime t(GCCauseString("GC", gc_cause), PrintGC, !PrintGCDetails, NULL, _gc_tracer_cm->gc_id()); TraceCollectorStats tcs(counters()); diff -r c2687aa5e5ca -r 7eb99acd567f src/share/vm/gc_implementation/concurrentMarkSweep/vmCMSOperations.hpp --- a/src/share/vm/gc_implementation/concurrentMarkSweep/vmCMSOperations.hpp Mon Jan 25 14:56:57 2016 -0800 +++ b/src/share/vm/gc_implementation/concurrentMarkSweep/vmCMSOperations.hpp Mon Jan 25 14:57:27 2016 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2011, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 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 @@ -130,8 +130,8 @@ class VM_GenCollectFullConcurrent: public VM_GC_Operation { bool _disabled_icms; public: - VM_GenCollectFullConcurrent(unsigned int gc_count_before, - unsigned int full_gc_count_before, + VM_GenCollectFullConcurrent(uint gc_count_before, + uint full_gc_count_before, GCCause::Cause gc_cause) : VM_GC_Operation(gc_count_before, gc_cause, full_gc_count_before, true /* full */), _disabled_icms(false) diff -r c2687aa5e5ca -r 7eb99acd567f src/share/vm/gc_implementation/concurrentMarkSweep/vmStructs_cms.hpp --- a/src/share/vm/gc_implementation/concurrentMarkSweep/vmStructs_cms.hpp Mon Jan 25 14:56:57 2016 -0800 +++ b/src/share/vm/gc_implementation/concurrentMarkSweep/vmStructs_cms.hpp Mon Jan 25 14:57:27 2016 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2007, 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 @@ -41,7 +41,7 @@ nonstatic_field(LinearAllocBlock, _word_size, size_t) \ nonstatic_field(AFLBinaryTreeDictionary, _total_size, size_t) \ nonstatic_field(CompactibleFreeListSpace, _dictionary, AFLBinaryTreeDictionary*) \ - nonstatic_field(CompactibleFreeListSpace, _indexedFreeList[0], FreeList) \ + nonstatic_field(CompactibleFreeListSpace, _indexedFreeList[0], AdaptiveFreeList) \ nonstatic_field(CompactibleFreeListSpace, _smallLinearAllocBlock, LinearAllocBlock) diff -r c2687aa5e5ca -r 7eb99acd567f src/share/vm/gc_implementation/g1/concurrentMark.cpp --- a/src/share/vm/gc_implementation/g1/concurrentMark.cpp Mon Jan 25 14:56:57 2016 -0800 +++ b/src/share/vm/gc_implementation/g1/concurrentMark.cpp Mon Jan 25 14:57:27 2016 -0800 @@ -114,7 +114,7 @@ } size_t CMBitMap::compute_size(size_t heap_size) { - return heap_size / mark_distance(); + return ReservedSpace::allocation_align_size_up(heap_size / mark_distance()); } size_t CMBitMap::mark_distance() { @@ -2640,24 +2640,41 @@ _nextMarkBitMap = (CMBitMap*) temp; } -class CMObjectClosure; - -// Closure for iterating over objects, currently only used for -// processing SATB buffers. -class CMObjectClosure : public ObjectClosure { +// Closure for marking entries in SATB buffers. +class CMSATBBufferClosure : public SATBBufferClosure { private: CMTask* _task; + G1CollectedHeap* _g1h; + + // This is very similar to CMTask::deal_with_reference, but with + // more relaxed requirements for the argument, so this must be more + // circumspect about treating the argument as an object. + void do_entry(void* entry) const { + _task->increment_refs_reached(); + HeapRegion* hr = _g1h->heap_region_containing_raw(entry); + if (entry < hr->next_top_at_mark_start()) { + // Until we get here, we don't know whether entry refers to a valid + // object; it could instead have been a stale reference. + oop obj = static_cast(entry); + assert(obj->is_oop(true /* ignore mark word */), + err_msg("Invalid oop in SATB buffer: " PTR_FORMAT, p2i(obj))); + _task->make_reference_grey(obj, hr); + } + } public: - void do_object(oop obj) { - _task->deal_with_reference(obj); + CMSATBBufferClosure(CMTask* task, G1CollectedHeap* g1h) + : _task(task), _g1h(g1h) { } + + virtual void do_buffer(void** buffer, size_t size) { + for (size_t i = 0; i < size; ++i) { + do_entry(buffer[i]); + } } - - CMObjectClosure(CMTask* task) : _task(task) { } }; class G1RemarkThreadsClosure : public ThreadClosure { - CMObjectClosure _cm_obj; + CMSATBBufferClosure _cm_satb_cl; G1CMOopClosure _cm_cl; MarkingCodeBlobClosure _code_cl; int _thread_parity; @@ -2665,7 +2682,9 @@ public: G1RemarkThreadsClosure(G1CollectedHeap* g1h, CMTask* task, bool is_par) : - _cm_obj(task), _cm_cl(g1h, g1h->concurrent_mark(), task), _code_cl(&_cm_cl, !CodeBlobToOopClosure::FixRelocations), + _cm_satb_cl(task, g1h), + _cm_cl(g1h, g1h->concurrent_mark(), task), + _code_cl(&_cm_cl, !CodeBlobToOopClosure::FixRelocations), _thread_parity(SharedHeap::heap()->strong_roots_parity()), _is_par(is_par) {} void do_thread(Thread* thread) { @@ -2681,11 +2700,11 @@ // live by the SATB invariant but other oops recorded in nmethods may behave differently. jt->nmethods_do(&_code_cl); - jt->satb_mark_queue().apply_closure_and_empty(&_cm_obj); + jt->satb_mark_queue().apply_closure_and_empty(&_cm_satb_cl); } } else if (thread->is_VM_thread()) { if (thread->claim_oops_do(_is_par, _thread_parity)) { - JavaThread::satb_mark_queue_set().shared_satb_queue()->apply_closure_and_empty(&_cm_obj); + JavaThread::satb_mark_queue_set().shared_satb_queue()->apply_closure_and_empty(&_cm_satb_cl); } } } @@ -3059,9 +3078,7 @@ #ifndef PRODUCT enum VerifyNoCSetOopsPhase { VerifyNoCSetOopsStack, - VerifyNoCSetOopsQueues, - VerifyNoCSetOopsSATBCompleted, - VerifyNoCSetOopsSATBThread + VerifyNoCSetOopsQueues }; class VerifyNoCSetOopsClosure : public OopClosure, public ObjectClosure { @@ -3074,8 +3091,6 @@ switch (_phase) { case VerifyNoCSetOopsStack: return "Stack"; case VerifyNoCSetOopsQueues: return "Queue"; - case VerifyNoCSetOopsSATBCompleted: return "Completed SATB Buffers"; - case VerifyNoCSetOopsSATBThread: return "Thread SATB Buffers"; default: ShouldNotReachHere(); } return NULL; @@ -3102,7 +3117,7 @@ virtual void do_oop(narrowOop* p) { // We should not come across narrow oops while scanning marking - // stacks and SATB buffers. + // stacks ShouldNotReachHere(); } @@ -3111,10 +3126,7 @@ } }; -void ConcurrentMark::verify_no_cset_oops(bool verify_stacks, - bool verify_enqueued_buffers, - bool verify_thread_buffers, - bool verify_fingers) { +void ConcurrentMark::verify_no_cset_oops() { assert(SafepointSynchronize::is_at_safepoint(), "should be at a safepoint"); if (!G1CollectedHeap::heap()->mark_in_progress()) { return; @@ -3122,65 +3134,47 @@ VerifyNoCSetOopsClosure cl; - if (verify_stacks) { - // Verify entries on the global mark stack - cl.set_phase(VerifyNoCSetOopsStack); - _markStack.oops_do(&cl); - - // Verify entries on the task queues - for (uint i = 0; i < _max_worker_id; i += 1) { - cl.set_phase(VerifyNoCSetOopsQueues, i); - CMTaskQueue* queue = _task_queues->queue(i); - queue->oops_do(&cl); - } - } - - SATBMarkQueueSet& satb_qs = JavaThread::satb_mark_queue_set(); - - // Verify entries on the enqueued SATB buffers - if (verify_enqueued_buffers) { - cl.set_phase(VerifyNoCSetOopsSATBCompleted); - satb_qs.iterate_completed_buffers_read_only(&cl); - } - - // Verify entries on the per-thread SATB buffers - if (verify_thread_buffers) { - cl.set_phase(VerifyNoCSetOopsSATBThread); - satb_qs.iterate_thread_buffers_read_only(&cl); + // Verify entries on the global mark stack + cl.set_phase(VerifyNoCSetOopsStack); + _markStack.oops_do(&cl); + + // Verify entries on the task queues + for (uint i = 0; i < _max_worker_id; i += 1) { + cl.set_phase(VerifyNoCSetOopsQueues, i); + CMTaskQueue* queue = _task_queues->queue(i); + queue->oops_do(&cl); } - if (verify_fingers) { - // Verify the global finger - HeapWord* global_finger = finger(); - if (global_finger != NULL && global_finger < _heap_end) { - // The global finger always points to a heap region boundary. We - // use heap_region_containing_raw() to get the containing region - // given that the global finger could be pointing to a free region - // which subsequently becomes continues humongous. If that - // happens, heap_region_containing() will return the bottom of the - // corresponding starts humongous region and the check below will - // not hold any more. - // Since we always iterate over all regions, we might get a NULL HeapRegion - // here. - HeapRegion* global_hr = _g1h->heap_region_containing_raw(global_finger); - guarantee(global_hr == NULL || global_finger == global_hr->bottom(), - err_msg("global finger: "PTR_FORMAT" region: "HR_FORMAT, - p2i(global_finger), HR_FORMAT_PARAMS(global_hr))); - } - - // Verify the task fingers - assert(parallel_marking_threads() <= _max_worker_id, "sanity"); - for (int i = 0; i < (int) parallel_marking_threads(); i += 1) { - CMTask* task = _tasks[i]; - HeapWord* task_finger = task->finger(); - if (task_finger != NULL && task_finger < _heap_end) { - // See above note on the global finger verification. - HeapRegion* task_hr = _g1h->heap_region_containing_raw(task_finger); - guarantee(task_hr == NULL || task_finger == task_hr->bottom() || - !task_hr->in_collection_set(), - err_msg("task finger: "PTR_FORMAT" region: "HR_FORMAT, - p2i(task_finger), HR_FORMAT_PARAMS(task_hr))); - } + // Verify the global finger + HeapWord* global_finger = finger(); + if (global_finger != NULL && global_finger < _heap_end) { + // The global finger always points to a heap region boundary. We + // use heap_region_containing_raw() to get the containing region + // given that the global finger could be pointing to a free region + // which subsequently becomes continues humongous. If that + // happens, heap_region_containing() will return the bottom of the + // corresponding starts humongous region and the check below will + // not hold any more. + // Since we always iterate over all regions, we might get a NULL HeapRegion + // here. + HeapRegion* global_hr = _g1h->heap_region_containing_raw(global_finger); + guarantee(global_hr == NULL || global_finger == global_hr->bottom(), + err_msg("global finger: "PTR_FORMAT" region: "HR_FORMAT, + p2i(global_finger), HR_FORMAT_PARAMS(global_hr))); + } + + // Verify the task fingers + assert(parallel_marking_threads() <= _max_worker_id, "sanity"); + for (int i = 0; i < (int) parallel_marking_threads(); i += 1) { + CMTask* task = _tasks[i]; + HeapWord* task_finger = task->finger(); + if (task_finger != NULL && task_finger < _heap_end) { + // See above note on the global finger verification. + HeapRegion* task_hr = _g1h->heap_region_containing_raw(task_finger); + guarantee(task_hr == NULL || task_finger == task_hr->bottom() || + !task_hr->in_collection_set(), + err_msg("task finger: "PTR_FORMAT" region: "HR_FORMAT, + p2i(task_finger), HR_FORMAT_PARAMS(task_hr))); } } } @@ -3510,22 +3504,29 @@ } #endif -void CMTask::scan_object(oop obj) { +template +inline void CMTask::process_grey_object(oop obj) { + assert(scan || obj->is_typeArray(), "Skipping scan of grey non-typeArray"); assert(_nextMarkBitMap->isMarked((HeapWord*) obj), "invariant"); if (_cm->verbose_high()) { - gclog_or_tty->print_cr("[%u] we're scanning object "PTR_FORMAT, + gclog_or_tty->print_cr("[%u] processing grey object " PTR_FORMAT, _worker_id, p2i((void*) obj)); } size_t obj_size = obj->size(); _words_scanned += obj_size; - obj->oop_iterate(_cm_oop_closure); + if (scan) { + obj->oop_iterate(_cm_oop_closure); + } statsOnly( ++_objs_scanned ); check_limits(); } +template void CMTask::process_grey_object(oop); +template void CMTask::process_grey_object(oop); + // Closure for iteration over bitmaps class CMBitMapClosure : public BitMapClosure { private: @@ -3994,34 +3995,18 @@ // very counter productive if it did that. :-) _draining_satb_buffers = true; - CMObjectClosure oc(this); + CMSATBBufferClosure satb_cl(this, _g1h); SATBMarkQueueSet& satb_mq_set = JavaThread::satb_mark_queue_set(); - if (G1CollectedHeap::use_parallel_gc_threads()) { - satb_mq_set.set_par_closure(_worker_id, &oc); - } else { - satb_mq_set.set_closure(&oc); - } // This keeps claiming and applying the closure to completed buffers // until we run out of buffers or we need to abort. - if (G1CollectedHeap::use_parallel_gc_threads()) { - while (!has_aborted() && - satb_mq_set.par_apply_closure_to_completed_buffer(_worker_id)) { - if (_cm->verbose_medium()) { - gclog_or_tty->print_cr("[%u] processed an SATB buffer", _worker_id); - } - statsOnly( ++_satb_buffers_processed ); - regular_clock_call(); + while (!has_aborted() && + satb_mq_set.apply_closure_to_completed_buffer(&satb_cl)) { + if (_cm->verbose_medium()) { + gclog_or_tty->print_cr("[%u] processed an SATB buffer", _worker_id); } - } else { - while (!has_aborted() && - satb_mq_set.apply_closure_to_completed_buffer()) { - if (_cm->verbose_medium()) { - gclog_or_tty->print_cr("[%u] processed an SATB buffer", _worker_id); - } - statsOnly( ++_satb_buffers_processed ); - regular_clock_call(); - } + statsOnly( ++_satb_buffers_processed ); + regular_clock_call(); } _draining_satb_buffers = false; @@ -4030,12 +4015,6 @@ concurrent() || satb_mq_set.completed_buffers_num() == 0, "invariant"); - if (G1CollectedHeap::use_parallel_gc_threads()) { - satb_mq_set.set_par_closure(_worker_id, NULL); - } else { - satb_mq_set.set_closure(NULL); - } - // again, this was a potentially expensive operation, decrease the // limits to get the regular clock call early decrease_limits(); diff -r c2687aa5e5ca -r 7eb99acd567f src/share/vm/gc_implementation/g1/concurrentMark.hpp --- a/src/share/vm/gc_implementation/g1/concurrentMark.hpp Mon Jan 25 14:56:57 2016 -0800 +++ b/src/share/vm/gc_implementation/g1/concurrentMark.hpp Mon Jan 25 14:57:27 2016 -0800 @@ -793,14 +793,9 @@ } // Verify that there are no CSet oops on the stacks (taskqueues / - // global mark stack), enqueued SATB buffers, per-thread SATB - // buffers, and fingers (global / per-task). The boolean parameters - // decide which of the above data structures to verify. If marking - // is not in progress, it's a no-op. - void verify_no_cset_oops(bool verify_stacks, - bool verify_enqueued_buffers, - bool verify_thread_buffers, - bool verify_fingers) PRODUCT_RETURN; + // global mark stack) and fingers (global / per-task). + // If marking is not in progress, it's a no-op. + void verify_no_cset_oops() PRODUCT_RETURN; bool isPrevMarked(oop p) const { assert(p != NULL && p->is_oop(), "expected an oop"); @@ -1108,6 +1103,12 @@ void regular_clock_call(); bool concurrent() { return _concurrent; } + // Test whether obj might have already been passed over by the + // mark bitmap scan, and so needs to be pushed onto the mark stack. + bool is_below_finger(oop obj, HeapWord* global_finger) const; + + template void process_grey_object(oop obj); + public: // It resets the task; it should be called right at the beginning of // a marking phase. @@ -1155,12 +1156,22 @@ void set_cm_oop_closure(G1CMOopClosure* cm_oop_closure); - // It grays the object by marking it and, if necessary, pushing it - // on the local queue + // Increment the number of references this task has visited. + void increment_refs_reached() { ++_refs_reached; } + + // Grey the object by marking it. If not already marked, push it on + // the local queue if below the finger. + // Precondition: obj is in region. + // Precondition: obj is below region's NTAMS. + inline void make_reference_grey(oop obj, HeapRegion* region); + + // Grey the object (by calling make_grey_reference) if required, + // e.g. obj is below its containing region's NTAMS. + // Precondition: obj is a valid heap object. inline void deal_with_reference(oop obj); // It scans an object and visits its children. - void scan_object(oop obj); + void scan_object(oop obj) { process_grey_object(obj); } // It pushes an object on the local queue. inline void push(oop obj); diff -r c2687aa5e5ca -r 7eb99acd567f src/share/vm/gc_implementation/g1/concurrentMark.inline.hpp --- a/src/share/vm/gc_implementation/g1/concurrentMark.inline.hpp Mon Jan 25 14:56:57 2016 -0800 +++ b/src/share/vm/gc_implementation/g1/concurrentMark.inline.hpp Mon Jan 25 14:57:27 2016 -0800 @@ -259,14 +259,87 @@ ++_local_pushes ); } -// This determines whether the method below will check both the local -// and global fingers when determining whether to push on the stack a -// gray object (value 1) or whether it will only check the global one -// (value 0). The tradeoffs are that the former will be a bit more -// accurate and possibly push less on the stack, but it might also be -// a little bit slower. +inline bool CMTask::is_below_finger(oop obj, HeapWord* global_finger) const { + // If obj is above the global finger, then the mark bitmap scan + // will find it later, and no push is needed. Similarly, if we have + // a current region and obj is between the local finger and the + // end of the current region, then no push is needed. The tradeoff + // of checking both vs only checking the global finger is that the + // local check will be more accurate and so result in fewer pushes, + // but may also be a little slower. + HeapWord* objAddr = (HeapWord*)obj; + if (_finger != NULL) { + // We have a current region. + + // Finger and region values are all NULL or all non-NULL. We + // use _finger to check since we immediately use its value. + assert(_curr_region != NULL, "invariant"); + assert(_region_limit != NULL, "invariant"); + assert(_region_limit <= global_finger, "invariant"); + + // True if obj is less than the local finger, or is between + // the region limit and the global finger. + if (objAddr < _finger) { + return true; + } else if (objAddr < _region_limit) { + return false; + } // Else check global finger. + } + // Check global finger. + return objAddr < global_finger; +} + +inline void CMTask::make_reference_grey(oop obj, HeapRegion* hr) { + if (_cm->par_mark_and_count(obj, hr, _marked_bytes_array, _card_bm)) { + + if (_cm->verbose_high()) { + gclog_or_tty->print_cr("[%u] marked object " PTR_FORMAT, + _worker_id, p2i(obj)); + } -#define _CHECK_BOTH_FINGERS_ 1 + // No OrderAccess:store_load() is needed. It is implicit in the + // CAS done in CMBitMap::parMark() call in the routine above. + HeapWord* global_finger = _cm->finger(); + + // We only need to push a newly grey object on the mark + // stack if it is in a section of memory the mark bitmap + // scan has already examined. Mark bitmap scanning + // maintains progress "fingers" for determining that. + // + // Notice that the global finger might be moving forward + // concurrently. This is not a problem. In the worst case, we + // mark the object while it is above the global finger and, by + // the time we read the global finger, it has moved forward + // past this object. In this case, the object will probably + // be visited when a task is scanning the region and will also + // be pushed on the stack. So, some duplicate work, but no + // correctness problems. + if (is_below_finger(obj, global_finger)) { + if (obj->is_typeArray()) { + // Immediately process arrays of primitive types, rather + // than pushing on the mark stack. This keeps us from + // adding humongous objects to the mark stack that might + // be reclaimed before the entry is processed - see + // selection of candidates for eager reclaim of humongous + // objects. The cost of the additional type test is + // mitigated by avoiding a trip through the mark stack, + // by only doing a bookkeeping update and avoiding the + // actual scan of the object - a typeArray contains no + // references, and the metadata is built-in. + process_grey_object(obj); + } else { + if (_cm->verbose_high()) { + gclog_or_tty->print_cr("[%u] below a finger (local: " PTR_FORMAT + ", global: " PTR_FORMAT ") pushing " + PTR_FORMAT " on mark stack", + _worker_id, p2i(_finger), + p2i(global_finger), p2i(obj)); + } + push(obj); + } + } + } +} inline void CMTask::deal_with_reference(oop obj) { if (_cm->verbose_high()) { @@ -274,7 +347,7 @@ _worker_id, p2i((void*) obj)); } - ++_refs_reached; + increment_refs_reached(); HeapWord* objAddr = (HeapWord*) obj; assert(obj->is_oop_or_null(true /* ignore mark word */), "Error"); @@ -286,62 +359,7 @@ // anything with it). HeapRegion* hr = _g1h->heap_region_containing_raw(obj); if (!hr->obj_allocated_since_next_marking(obj)) { - if (_cm->verbose_high()) { - gclog_or_tty->print_cr("[%u] "PTR_FORMAT" is not considered marked", - _worker_id, p2i((void*) obj)); - } - - // we need to mark it first - if (_cm->par_mark_and_count(obj, hr, _marked_bytes_array, _card_bm)) { - // No OrderAccess:store_load() is needed. It is implicit in the - // CAS done in CMBitMap::parMark() call in the routine above. - HeapWord* global_finger = _cm->finger(); - -#if _CHECK_BOTH_FINGERS_ - // we will check both the local and global fingers - - if (_finger != NULL && objAddr < _finger) { - if (_cm->verbose_high()) { - gclog_or_tty->print_cr("[%u] below the local finger ("PTR_FORMAT"), " - "pushing it", _worker_id, p2i(_finger)); - } - push(obj); - } else if (_curr_region != NULL && objAddr < _region_limit) { - // do nothing - } else if (objAddr < global_finger) { - // Notice that the global finger might be moving forward - // concurrently. This is not a problem. In the worst case, we - // mark the object while it is above the global finger and, by - // the time we read the global finger, it has moved forward - // passed this object. In this case, the object will probably - // be visited when a task is scanning the region and will also - // be pushed on the stack. So, some duplicate work, but no - // correctness problems. - - if (_cm->verbose_high()) { - gclog_or_tty->print_cr("[%u] below the global finger " - "("PTR_FORMAT"), pushing it", - _worker_id, p2i(global_finger)); - } - push(obj); - } else { - // do nothing - } -#else // _CHECK_BOTH_FINGERS_ - // we will only check the global finger - - if (objAddr < global_finger) { - // see long comment above - - if (_cm->verbose_high()) { - gclog_or_tty->print_cr("[%u] below the global finger " - "("PTR_FORMAT"), pushing it", - _worker_id, p2i(global_finger)); - } - push(obj); - } -#endif // _CHECK_BOTH_FINGERS_ - } + make_reference_grey(obj, hr); } } } diff -r c2687aa5e5ca -r 7eb99acd567f src/share/vm/gc_implementation/g1/g1AllocRegion.cpp --- a/src/share/vm/gc_implementation/g1/g1AllocRegion.cpp Mon Jan 25 14:56:57 2016 -0800 +++ b/src/share/vm/gc_implementation/g1/g1AllocRegion.cpp Mon Jan 25 14:57:27 2016 -0800 @@ -254,25 +254,23 @@ HeapRegion* SurvivorGCAllocRegion::allocate_new_region(size_t word_size, bool force) { assert(!force, "not supported for GC alloc regions"); - return _g1h->new_gc_alloc_region(word_size, count(), GCAllocForSurvived); + return _g1h->new_gc_alloc_region(word_size, count(), InCSetState::Young); } void SurvivorGCAllocRegion::retire_region(HeapRegion* alloc_region, size_t allocated_bytes) { - _g1h->retire_gc_alloc_region(alloc_region, allocated_bytes, - GCAllocForSurvived); + _g1h->retire_gc_alloc_region(alloc_region, allocated_bytes, InCSetState::Young); } HeapRegion* OldGCAllocRegion::allocate_new_region(size_t word_size, bool force) { assert(!force, "not supported for GC alloc regions"); - return _g1h->new_gc_alloc_region(word_size, count(), GCAllocForTenured); + return _g1h->new_gc_alloc_region(word_size, count(), InCSetState::Old); } void OldGCAllocRegion::retire_region(HeapRegion* alloc_region, size_t allocated_bytes) { - _g1h->retire_gc_alloc_region(alloc_region, allocated_bytes, - GCAllocForTenured); + _g1h->retire_gc_alloc_region(alloc_region, allocated_bytes, InCSetState::Old); } HeapRegion* OldGCAllocRegion::release() { diff -r c2687aa5e5ca -r 7eb99acd567f src/share/vm/gc_implementation/g1/g1Allocator.cpp --- a/src/share/vm/gc_implementation/g1/g1Allocator.cpp Mon Jan 25 14:56:57 2016 -0800 +++ b/src/share/vm/gc_implementation/g1/g1Allocator.cpp Mon Jan 25 14:57:27 2016 -0800 @@ -59,7 +59,7 @@ !(retained_region->top() == retained_region->end()) && !retained_region->is_empty() && !retained_region->isHumongous()) { - retained_region->record_top_and_timestamp(); + retained_region->record_timestamp(); // The retained region was added to the old region set when it was // retired. We have to remove it now, since we don't allow regions // we allocate to in the region sets. We'll re-add it later, when @@ -94,6 +94,9 @@ // want either way so no reason to check explicitly for either // condition. _retained_old_gc_alloc_region = old_gc_alloc_region(context)->release(); + if (_retained_old_gc_alloc_region != NULL) { + _retained_old_gc_alloc_region->record_retained_region(); + } if (ResizePLAB) { _g1h->_survivor_plab_stats.adjust_desired_plab_sz(no_of_gc_workers); @@ -110,15 +113,16 @@ G1ParGCAllocBuffer::G1ParGCAllocBuffer(size_t gclab_word_size) : ParGCAllocBuffer(gclab_word_size), _retired(true) { } -HeapWord* G1ParGCAllocator::allocate_slow(GCAllocPurpose purpose, size_t word_sz, AllocationContext_t context) { - HeapWord* obj = NULL; - size_t gclab_word_size = _g1h->desired_plab_sz(purpose); +HeapWord* G1ParGCAllocator::allocate_direct_or_new_plab(InCSetState dest, + size_t word_sz, + AllocationContext_t context) { + size_t gclab_word_size = _g1h->desired_plab_sz(dest); if (word_sz * 100 < gclab_word_size * ParallelGCBufferWastePct) { - G1ParGCAllocBuffer* alloc_buf = alloc_buffer(purpose, context); + G1ParGCAllocBuffer* alloc_buf = alloc_buffer(dest, context); add_to_alloc_buffer_waste(alloc_buf->words_remaining()); alloc_buf->retire(false /* end_of_gc */, false /* retain */); - HeapWord* buf = _g1h->par_allocate_during_gc(purpose, gclab_word_size, context); + HeapWord* buf = _g1h->par_allocate_during_gc(dest, gclab_word_size, context); if (buf == NULL) { return NULL; // Let caller handle allocation failure. } @@ -126,30 +130,33 @@ alloc_buf->set_word_size(gclab_word_size); alloc_buf->set_buf(buf); - obj = alloc_buf->allocate(word_sz); + HeapWord* const obj = alloc_buf->allocate(word_sz); assert(obj != NULL, "buffer was definitely big enough..."); + return obj; } else { - obj = _g1h->par_allocate_during_gc(purpose, word_sz, context); + return _g1h->par_allocate_during_gc(dest, word_sz, context); } - return obj; } G1DefaultParGCAllocator::G1DefaultParGCAllocator(G1CollectedHeap* g1h) : - G1ParGCAllocator(g1h), - _surviving_alloc_buffer(g1h->desired_plab_sz(GCAllocForSurvived)), - _tenured_alloc_buffer(g1h->desired_plab_sz(GCAllocForTenured)) { - - _alloc_buffers[GCAllocForSurvived] = &_surviving_alloc_buffer; - _alloc_buffers[GCAllocForTenured] = &_tenured_alloc_buffer; - + G1ParGCAllocator(g1h), + _surviving_alloc_buffer(g1h->desired_plab_sz(InCSetState::Young)), + _tenured_alloc_buffer(g1h->desired_plab_sz(InCSetState::Old)) { + for (uint state = 0; state < InCSetState::Num; state++) { + _alloc_buffers[state] = NULL; + } + _alloc_buffers[InCSetState::Young] = &_surviving_alloc_buffer; + _alloc_buffers[InCSetState::Old] = &_tenured_alloc_buffer; } void G1DefaultParGCAllocator::retire_alloc_buffers() { - for (int ap = 0; ap < GCAllocPurposeCount; ++ap) { - size_t waste = _alloc_buffers[ap]->words_remaining(); - add_to_alloc_buffer_waste(waste); - _alloc_buffers[ap]->flush_stats_and_retire(_g1h->stats_for_purpose((GCAllocPurpose)ap), - true /* end_of_gc */, - false /* retain */); + for (uint state = 0; state < InCSetState::Num; state++) { + G1ParGCAllocBuffer* const buf = _alloc_buffers[state]; + if (buf != NULL) { + add_to_alloc_buffer_waste(buf->words_remaining()); + buf->flush_stats_and_retire(_g1h->alloc_buffer_stats(state), + true /* end_of_gc */, + false /* retain */); + } } } diff -r c2687aa5e5ca -r 7eb99acd567f src/share/vm/gc_implementation/g1/g1Allocator.hpp --- a/src/share/vm/gc_implementation/g1/g1Allocator.hpp Mon Jan 25 14:56:57 2016 -0800 +++ b/src/share/vm/gc_implementation/g1/g1Allocator.hpp Mon Jan 25 14:57:27 2016 -0800 @@ -27,14 +27,9 @@ #include "gc_implementation/g1/g1AllocationContext.hpp" #include "gc_implementation/g1/g1AllocRegion.hpp" +#include "gc_implementation/g1/g1InCSetState.hpp" #include "gc_implementation/shared/parGCAllocBuffer.hpp" -enum GCAllocPurpose { - GCAllocForTenured, - GCAllocForSurvived, - GCAllocPurposeCount -}; - // Base class for G1 allocators. class G1Allocator : public CHeapObj { friend class VMStructs; @@ -178,20 +173,40 @@ protected: G1CollectedHeap* _g1h; + // The survivor alignment in effect in bytes. + // == 0 : don't align survivors + // != 0 : align survivors to that alignment + // These values were chosen to favor the non-alignment case since some + // architectures have a special compare against zero instructions. + const uint _survivor_alignment_bytes; + size_t _alloc_buffer_waste; size_t _undo_waste; void add_to_alloc_buffer_waste(size_t waste) { _alloc_buffer_waste += waste; } void add_to_undo_waste(size_t waste) { _undo_waste += waste; } - HeapWord* allocate_slow(GCAllocPurpose purpose, size_t word_sz, AllocationContext_t context); + virtual void retire_alloc_buffers() = 0; + virtual G1ParGCAllocBuffer* alloc_buffer(InCSetState dest, AllocationContext_t context) = 0; - virtual void retire_alloc_buffers() = 0; - virtual G1ParGCAllocBuffer* alloc_buffer(GCAllocPurpose purpose, AllocationContext_t context) = 0; + // Calculate the survivor space object alignment in bytes. Returns that or 0 if + // there are no restrictions on survivor alignment. + static uint calc_survivor_alignment_bytes() { + assert(SurvivorAlignmentInBytes >= ObjectAlignmentInBytes, "sanity"); + if (SurvivorAlignmentInBytes == ObjectAlignmentInBytes) { + // No need to align objects in the survivors differently, return 0 + // which means "survivor alignment is not used". + return 0; + } else { + assert(SurvivorAlignmentInBytes > 0, "sanity"); + return SurvivorAlignmentInBytes; + } + } public: G1ParGCAllocator(G1CollectedHeap* g1h) : - _g1h(g1h), _alloc_buffer_waste(0), _undo_waste(0) { + _g1h(g1h), _survivor_alignment_bytes(calc_survivor_alignment_bytes()), + _alloc_buffer_waste(0), _undo_waste(0) { } static G1ParGCAllocator* create_allocator(G1CollectedHeap* g1h); @@ -199,24 +214,40 @@ size_t alloc_buffer_waste() { return _alloc_buffer_waste; } size_t undo_waste() {return _undo_waste; } - HeapWord* allocate(GCAllocPurpose purpose, size_t word_sz, AllocationContext_t context) { - HeapWord* obj = NULL; - if (purpose == GCAllocForSurvived) { - obj = alloc_buffer(purpose, context)->allocate_aligned(word_sz, SurvivorAlignmentInBytes); + // Allocate word_sz words in dest, either directly into the regions or by + // allocating a new PLAB. Returns the address of the allocated memory, NULL if + // not successful. + HeapWord* allocate_direct_or_new_plab(InCSetState dest, + size_t word_sz, + AllocationContext_t context); + + // Allocate word_sz words in the PLAB of dest. Returns the address of the + // allocated memory, NULL if not successful. + HeapWord* plab_allocate(InCSetState dest, + size_t word_sz, + AllocationContext_t context) { + G1ParGCAllocBuffer* buffer = alloc_buffer(dest, context); + if (_survivor_alignment_bytes == 0) { + return buffer->allocate(word_sz); } else { - obj = alloc_buffer(purpose, context)->allocate(word_sz); + return buffer->allocate_aligned(word_sz, _survivor_alignment_bytes); } + } + + HeapWord* allocate(InCSetState dest, size_t word_sz, + AllocationContext_t context) { + HeapWord* const obj = plab_allocate(dest, word_sz, context); if (obj != NULL) { return obj; } - return allocate_slow(purpose, word_sz, context); + return allocate_direct_or_new_plab(dest, word_sz, context); } - void undo_allocation(GCAllocPurpose purpose, HeapWord* obj, size_t word_sz, AllocationContext_t context) { - if (alloc_buffer(purpose, context)->contains(obj)) { - assert(alloc_buffer(purpose, context)->contains(obj + word_sz - 1), + void undo_allocation(InCSetState dest, HeapWord* obj, size_t word_sz, AllocationContext_t context) { + if (alloc_buffer(dest, context)->contains(obj)) { + assert(alloc_buffer(dest, context)->contains(obj + word_sz - 1), "should contain whole object"); - alloc_buffer(purpose, context)->undo_allocation(obj, word_sz); + alloc_buffer(dest, context)->undo_allocation(obj, word_sz); } else { CollectedHeap::fill_with_object(obj, word_sz); add_to_undo_waste(word_sz); @@ -227,13 +258,17 @@ class G1DefaultParGCAllocator : public G1ParGCAllocator { G1ParGCAllocBuffer _surviving_alloc_buffer; G1ParGCAllocBuffer _tenured_alloc_buffer; - G1ParGCAllocBuffer* _alloc_buffers[GCAllocPurposeCount]; + G1ParGCAllocBuffer* _alloc_buffers[InCSetState::Num]; public: G1DefaultParGCAllocator(G1CollectedHeap* g1h); - virtual G1ParGCAllocBuffer* alloc_buffer(GCAllocPurpose purpose, AllocationContext_t context) { - return _alloc_buffers[purpose]; + virtual G1ParGCAllocBuffer* alloc_buffer(InCSetState dest, AllocationContext_t context) { + assert(dest.is_valid(), + err_msg("Allocation buffer index out-of-bounds: " CSETSTATE_FORMAT, dest.value())); + assert(_alloc_buffers[dest.value()] != NULL, + err_msg("Allocation buffer is NULL: " CSETSTATE_FORMAT, dest.value())); + return _alloc_buffers[dest.value()]; } virtual void retire_alloc_buffers() ; diff -r c2687aa5e5ca -r 7eb99acd567f src/share/vm/gc_implementation/g1/g1BiasedArray.hpp --- a/src/share/vm/gc_implementation/g1/g1BiasedArray.hpp Mon Jan 25 14:56:57 2016 -0800 +++ b/src/share/vm/gc_implementation/g1/g1BiasedArray.hpp Mon Jan 25 14:57:27 2016 -0800 @@ -75,7 +75,7 @@ assert((uintptr_t)end % mapping_granularity_in_bytes == 0, err_msg("end mapping area address must be a multiple of mapping granularity %zd, is " PTR_FORMAT, mapping_granularity_in_bytes, p2i(end))); - size_t num_target_elems = (end - bottom) / (mapping_granularity_in_bytes / HeapWordSize); + size_t num_target_elems = pointer_delta(end, bottom, mapping_granularity_in_bytes); idx_t bias = (uintptr_t)bottom / mapping_granularity_in_bytes; address base = create_new_base_array(num_target_elems, target_elem_size_in_bytes); initialize_base(base, num_target_elems, bias, target_elem_size_in_bytes, log2_intptr(mapping_granularity_in_bytes)); diff -r c2687aa5e5ca -r 7eb99acd567f src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp --- a/src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp Mon Jan 25 14:56:57 2016 -0800 +++ b/src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp Mon Jan 25 14:57:27 2016 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 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 @@ -46,6 +46,7 @@ #include "gc_implementation/g1/g1ParScanThreadState.inline.hpp" #include "gc_implementation/g1/g1RegionToSpaceMapper.hpp" #include "gc_implementation/g1/g1RemSet.inline.hpp" +#include "gc_implementation/g1/g1RootProcessor.hpp" #include "gc_implementation/g1/g1StringDedup.hpp" #include "gc_implementation/g1/g1YCTypes.hpp" #include "gc_implementation/g1/heapRegion.inline.hpp" @@ -85,18 +86,6 @@ // apply to TLAB allocation, which is not part of this interface: it // is done by clients of this interface.) -// Notes on implementation of parallelism in different tasks. -// -// G1ParVerifyTask uses heap_region_par_iterate_chunked() for parallelism. -// The number of GC workers is passed to heap_region_par_iterate_chunked(). -// It does use run_task() which sets _n_workers in the task. -// G1ParTask executes g1_process_roots() -> -// SharedHeap::process_roots() which calls eventually to -// CardTableModRefBS::par_non_clean_card_iterate_work() which uses -// SequentialSubTasksDone. SharedHeap::process_roots() also -// directly uses SubTasksDone (_process_strong_tasks field in SharedHeap). -// - // Local to this file. class RefineCardTableEntryClosure: public CardTableEntryClosure { @@ -364,7 +353,7 @@ HeapRegion* lists[] = {_head, _survivor_head}; const char* names[] = {"YOUNG", "SURVIVOR"}; - for (unsigned int list = 0; list < ARRAY_SIZE(lists); ++list) { + for (uint list = 0; list < ARRAY_SIZE(lists); ++list) { gclog_or_tty->print_cr("%s LIST CONTENTS", names[list]); HeapRegion *curr = lists[list]; if (curr == NULL) @@ -838,8 +827,8 @@ assert_heap_not_locked_and_not_at_safepoint(); assert(!isHumongous(word_size), "we do not allow humongous TLABs"); - unsigned int dummy_gc_count_before; - int dummy_gclocker_retry_count = 0; + uint dummy_gc_count_before; + uint dummy_gclocker_retry_count = 0; return attempt_allocation(word_size, &dummy_gc_count_before, &dummy_gclocker_retry_count); } @@ -849,8 +838,8 @@ assert_heap_not_locked_and_not_at_safepoint(); // Loop until the allocation is satisfied, or unsatisfied after GC. - for (int try_count = 1, gclocker_retry_count = 0; /* we'll return */; try_count += 1) { - unsigned int gc_count_before; + for (uint try_count = 1, gclocker_retry_count = 0; /* we'll return */; try_count += 1) { + uint gc_count_before; HeapWord* result = NULL; if (!isHumongous(word_size)) { @@ -902,8 +891,8 @@ HeapWord* G1CollectedHeap::attempt_allocation_slow(size_t word_size, AllocationContext_t context, - unsigned int *gc_count_before_ret, - int* gclocker_retry_count_ret) { + uint* gc_count_before_ret, + uint* gclocker_retry_count_ret) { // Make sure you read the note in attempt_allocation_humongous(). assert_heap_not_locked_and_not_at_safepoint(); @@ -920,7 +909,7 @@ HeapWord* result = NULL; for (int try_count = 1; /* we'll return */; try_count += 1) { bool should_try_gc; - unsigned int gc_count_before; + uint gc_count_before; { MutexLockerEx x(Heap_lock); @@ -964,7 +953,7 @@ if (should_try_gc) { bool succeeded; result = do_collection_pause(word_size, gc_count_before, &succeeded, - GCCause::_g1_inc_collection_pause); + GCCause::_g1_inc_collection_pause); if (result != NULL) { assert(succeeded, "only way to get back a non-NULL result"); return result; @@ -1018,8 +1007,8 @@ } HeapWord* G1CollectedHeap::attempt_allocation_humongous(size_t word_size, - unsigned int * gc_count_before_ret, - int* gclocker_retry_count_ret) { + uint* gc_count_before_ret, + uint* gclocker_retry_count_ret) { // The structure of this method has a lot of similarities to // attempt_allocation_slow(). The reason these two were not merged // into a single one is that such a method would require several "if @@ -1052,7 +1041,7 @@ HeapWord* result = NULL; for (int try_count = 1; /* we'll return */; try_count += 1) { bool should_try_gc; - unsigned int gc_count_before; + uint gc_count_before; { MutexLockerEx x(Heap_lock); @@ -1090,7 +1079,7 @@ bool succeeded; result = do_collection_pause(word_size, gc_count_before, &succeeded, - GCCause::_g1_humongous_allocation); + GCCause::_g1_humongous_allocation); if (result != NULL) { assert(succeeded, "only way to get back a non-NULL result"); return result; @@ -1297,7 +1286,6 @@ // Timing assert(gc_cause() != GCCause::_java_lang_system_gc || explicit_gc, "invariant"); - gclog_or_tty->date_stamp(G1Log::fine() && PrintGCDateStamps); TraceCPUTime tcpu(G1Log::finer(), true, gclog_or_tty); { @@ -1859,7 +1847,6 @@ _is_alive_closure_stw(this), _ref_processor_cm(NULL), _ref_processor_stw(NULL), - _process_strong_tasks(new SubTasksDone(G1H_PS_NumElements)), _bot_shared(NULL), _evac_failure_scan_stack(NULL), _mark_in_progress(false), @@ -1870,7 +1857,7 @@ _secondary_free_list("Secondary Free List", new SecondaryFreeRegionListMtSafeChecker()), _old_set("Old Set", false /* humongous */, new OldRegionSetMtSafeChecker()), _humongous_set("Master Humongous Set", true /* humongous */, new HumongousRegionSetMtSafeChecker()), - _humongous_is_live(), + _humongous_reclaim_candidates(), _has_humongous_reclaim_candidates(false), _free_regions_coming(false), _young_list(new YoungList(this)), @@ -1882,6 +1869,7 @@ _old_marking_cycles_started(0), _old_marking_cycles_completed(0), _concurrent_cycle_started(false), + _heap_summary_sent(false), _in_cset_fast_test(), _dirty_cards_region_list(NULL), _worker_cset_start_region(NULL), @@ -1892,9 +1880,6 @@ _gc_tracer_cm(new (ResourceObj::C_HEAP, mtGC) G1OldTracer()) { _g1h = this; - if (_process_strong_tasks == NULL || !_process_strong_tasks->valid()) { - vm_exit_during_initialization("Failed necessary allocation."); - } _allocator = G1Allocator::create_allocator(_g1h); _humongous_object_threshold_in_words = HeapRegion::GrainWords / 2; @@ -1906,7 +1891,7 @@ assert(n_rem_sets > 0, "Invariant."); _worker_cset_start_region = NEW_C_HEAP_ARRAY(HeapRegion*, n_queues, mtGC); - _worker_cset_start_region_time_stamp = NEW_C_HEAP_ARRAY(unsigned int, n_queues, mtGC); + _worker_cset_start_region_time_stamp = NEW_C_HEAP_ARRAY(uint, n_queues, mtGC); _evacuation_failed_info_array = NEW_C_HEAP_ARRAY(EvacuationFailedInfo, n_queues, mtGC); for (int i = 0; i < n_queues; i++) { @@ -1923,6 +1908,26 @@ guarantee(_task_queues != NULL, "task_queues allocation failure."); } +G1RegionToSpaceMapper* G1CollectedHeap::create_aux_memory_mapper(const char* description, + size_t size, + size_t translation_factor) { + size_t preferred_page_size = os::page_size_for_region_unaligned(size, 1); + // Allocate a new reserved space, preferring to use large pages. + ReservedSpace rs(size, preferred_page_size); + G1RegionToSpaceMapper* result = + G1RegionToSpaceMapper::create_mapper(rs, + size, + rs.alignment(), + HeapRegion::GrainBytes, + translation_factor, + mtGC); + if (TracePageSizes) { + gclog_or_tty->print_cr("G1 '%s': pg_sz=" SIZE_FORMAT " base=" PTR_FORMAT " size=" SIZE_FORMAT " alignment=" SIZE_FORMAT " reqsize=" SIZE_FORMAT, + description, preferred_page_size, p2i(rs.base()), rs.size(), rs.alignment(), size); + } + return result; +} + jint G1CollectedHeap::initialize() { CollectedHeap::pre_initialize(); os::enable_vtime(); @@ -1996,57 +2001,35 @@ ReservedSpace g1_rs = heap_rs.first_part(max_byte_size); G1RegionToSpaceMapper* heap_storage = G1RegionToSpaceMapper::create_mapper(g1_rs, + g1_rs.size(), UseLargePages ? os::large_page_size() : os::vm_page_size(), HeapRegion::GrainBytes, 1, mtJavaHeap); heap_storage->set_mapping_changed_listener(&_listener); - // Reserve space for the block offset table. We do not support automatic uncommit - // for the card table at this time. BOT only. - ReservedSpace bot_rs(G1BlockOffsetSharedArray::compute_size(g1_rs.size() / HeapWordSize)); + // Create storage for the BOT, card table, card counts table (hot card cache) and the bitmaps. G1RegionToSpaceMapper* bot_storage = - G1RegionToSpaceMapper::create_mapper(bot_rs, - os::vm_page_size(), - HeapRegion::GrainBytes, - G1BlockOffsetSharedArray::N_bytes, - mtGC); + create_aux_memory_mapper("Block offset table", + G1BlockOffsetSharedArray::compute_size(g1_rs.size() / HeapWordSize), + G1BlockOffsetSharedArray::N_bytes); ReservedSpace cardtable_rs(G1SATBCardTableLoggingModRefBS::compute_size(g1_rs.size() / HeapWordSize)); G1RegionToSpaceMapper* cardtable_storage = - G1RegionToSpaceMapper::create_mapper(cardtable_rs, - os::vm_page_size(), - HeapRegion::GrainBytes, - G1BlockOffsetSharedArray::N_bytes, - mtGC); - - // Reserve space for the card counts table. - ReservedSpace card_counts_rs(G1BlockOffsetSharedArray::compute_size(g1_rs.size() / HeapWordSize)); + create_aux_memory_mapper("Card table", + G1SATBCardTableLoggingModRefBS::compute_size(g1_rs.size() / HeapWordSize), + G1BlockOffsetSharedArray::N_bytes); + G1RegionToSpaceMapper* card_counts_storage = - G1RegionToSpaceMapper::create_mapper(card_counts_rs, - os::vm_page_size(), - HeapRegion::GrainBytes, - G1BlockOffsetSharedArray::N_bytes, - mtGC); - - // Reserve space for prev and next bitmap. + create_aux_memory_mapper("Card counts table", + G1BlockOffsetSharedArray::compute_size(g1_rs.size() / HeapWordSize), + G1BlockOffsetSharedArray::N_bytes); + size_t bitmap_size = CMBitMap::compute_size(g1_rs.size()); - - ReservedSpace prev_bitmap_rs(ReservedSpace::allocation_align_size_up(bitmap_size)); G1RegionToSpaceMapper* prev_bitmap_storage = - G1RegionToSpaceMapper::create_mapper(prev_bitmap_rs, - os::vm_page_size(), - HeapRegion::GrainBytes, - CMBitMap::mark_distance(), - mtGC); - - ReservedSpace next_bitmap_rs(ReservedSpace::allocation_align_size_up(bitmap_size)); + create_aux_memory_mapper("Prev Bitmap", bitmap_size, CMBitMap::mark_distance()); G1RegionToSpaceMapper* next_bitmap_storage = - G1RegionToSpaceMapper::create_mapper(next_bitmap_rs, - os::vm_page_size(), - HeapRegion::GrainBytes, - CMBitMap::mark_distance(), - mtGC); + create_aux_memory_mapper("Next Bitmap", bitmap_size, CMBitMap::mark_distance()); _hrm.initialize(heap_storage, prev_bitmap_storage, next_bitmap_storage, bot_storage, cardtable_storage, card_counts_storage); g1_barrier_set()->initialize(cardtable_storage); @@ -2069,8 +2052,14 @@ _g1h = this; - _in_cset_fast_test.initialize(_hrm.reserved().start(), _hrm.reserved().end(), HeapRegion::GrainBytes); - _humongous_is_live.initialize(_hrm.reserved().start(), _hrm.reserved().end(), HeapRegion::GrainBytes); + { + HeapWord* start = _hrm.reserved().start(); + HeapWord* end = _hrm.reserved().end(); + size_t granularity = HeapRegion::GrainBytes; + + _in_cset_fast_test.initialize(start, end, granularity); + _humongous_reclaim_candidates.initialize(start, end, granularity); + } // Create the ConcurrentMark data structure and thread. // (Must do this late, so that "max_regions" is defined.) @@ -2162,11 +2151,6 @@ } } -void G1CollectedHeap::clear_humongous_is_live_table() { - guarantee(G1ReclaimDeadHumongousObjectsAtYoungGC, "Should only be called if true"); - _humongous_is_live.clear(); -} - size_t G1CollectedHeap::conservative_max_heap_alignment() { return HeapRegion::max_region_size(); } @@ -2303,11 +2287,11 @@ hot_card_cache->drain(worker_i, g1_rem_set(), into_cset_dcq); DirtyCardQueueSet& dcqs = JavaThread::dirty_card_queue_set(); - int n_completed_buffers = 0; + size_t n_completed_buffers = 0; while (dcqs.apply_closure_to_completed_buffer(cl, worker_i, 0, true)) { n_completed_buffers++; } - g1_policy()->phase_times()->record_update_rs_processed_buffers(worker_i, n_completed_buffers); + g1_policy()->phase_times()->record_thread_work_item(G1GCPhaseTimes::UpdateRS, worker_i, n_completed_buffers); dcqs.clear_n_completed_buffers(); assert(!dcqs.completed_buffers_exist_dirty(), "Completed buffers exist!"); } @@ -2452,13 +2436,24 @@ _gc_timer_cm->register_gc_end(); _gc_tracer_cm->report_gc_end(_gc_timer_cm->gc_end(), _gc_timer_cm->time_partitions()); + // Clear state variables to prepare for the next concurrent cycle. _concurrent_cycle_started = false; + _heap_summary_sent = false; } } void G1CollectedHeap::trace_heap_after_concurrent_cycle() { if (_concurrent_cycle_started) { - trace_heap_after_gc(_gc_tracer_cm); + // This function can be called when: + // the cleanup pause is run + // the concurrent cycle is aborted before the cleanup pause. + // the concurrent cycle is aborted after the cleanup pause, + // but before the concurrent cycle end has been registered. + // Make sure that we only send the heap information once. + if (!_heap_summary_sent) { + trace_heap_after_gc(_gc_tracer_cm); + _heap_summary_sent = true; + } } } @@ -2481,9 +2476,9 @@ void G1CollectedHeap::collect(GCCause::Cause cause) { assert_heap_not_locked(); - unsigned int gc_count_before; - unsigned int old_marking_count_before; - unsigned int full_gc_count_before; + uint gc_count_before; + uint old_marking_count_before; + uint full_gc_count_before; bool retry_gc; do { @@ -3296,11 +3291,12 @@ G1VerifyCodeRootOopClosure codeRootsCl(this, &rootsCl, vo); G1VerifyCodeRootBlobClosure blobsCl(&codeRootsCl); - process_all_roots(true, // activate StrongRootsScope - SO_AllCodeCache, // roots scanning options - &rootsCl, - &cldCl, - &blobsCl); + { + G1RootProcessor root_processor(this); + root_processor.process_all_roots(&rootsCl, + &cldCl, + &blobsCl); + } bool failures = rootsCl.failures() || codeRootsCl.failures(); @@ -3621,7 +3617,7 @@ } HeapWord* G1CollectedHeap::do_collection_pause(size_t word_size, - unsigned int gc_count_before, + uint gc_count_before, bool* succeeded, GCCause::Cause gc_cause) { assert_heap_not_locked_and_not_at_safepoint(); @@ -3676,18 +3672,73 @@ return g1_rem_set()->cardsScanned(); } -bool G1CollectedHeap::humongous_region_is_always_live(uint index) { - HeapRegion* region = region_at(index); - assert(region->startsHumongous(), "Must start a humongous object"); - return oop(region->bottom())->is_objArray() || !region->rem_set()->is_empty(); -} - class RegisterHumongousWithInCSetFastTestClosure : public HeapRegionClosure { private: size_t _total_humongous; size_t _candidate_humongous; + + DirtyCardQueue _dcq; + + // We don't nominate objects with many remembered set entries, on + // the assumption that such objects are likely still live. + bool is_remset_small(HeapRegion* region) const { + HeapRegionRemSet* const rset = region->rem_set(); + return G1EagerReclaimHumongousObjectsWithStaleRefs + ? rset->occupancy_less_or_equal_than(G1RSetSparseRegionEntries) + : rset->is_empty(); + } + + bool is_typeArray_region(HeapRegion* region) const { + return oop(region->bottom())->is_typeArray(); + } + + bool humongous_region_is_candidate(G1CollectedHeap* heap, HeapRegion* region) const { + assert(region->startsHumongous(), "Must start a humongous object"); + + // Candidate selection must satisfy the following constraints + // while concurrent marking is in progress: + // + // * In order to maintain SATB invariants, an object must not be + // reclaimed if it was allocated before the start of marking and + // has not had its references scanned. Such an object must have + // its references (including type metadata) scanned to ensure no + // live objects are missed by the marking process. Objects + // allocated after the start of concurrent marking don't need to + // be scanned. + // + // * An object must not be reclaimed if it is on the concurrent + // mark stack. Objects allocated after the start of concurrent + // marking are never pushed on the mark stack. + // + // Nominating only objects allocated after the start of concurrent + // marking is sufficient to meet both constraints. This may miss + // some objects that satisfy the constraints, but the marking data + // structures don't support efficiently performing the needed + // additional tests or scrubbing of the mark stack. + // + // However, we presently only nominate is_typeArray() objects. + // A humongous object containing references induces remembered + // set entries on other regions. In order to reclaim such an + // object, those remembered sets would need to be cleaned up. + // + // We also treat is_typeArray() objects specially, allowing them + // to be reclaimed even if allocated before the start of + // concurrent mark. For this we rely on mark stack insertion to + // exclude is_typeArray() objects, preventing reclaiming an object + // that is in the mark stack. We also rely on the metadata for + // such objects to be built-in and so ensured to be kept live. + // Frequent allocation and drop of large binary blobs is an + // important use case for eager reclaim, and this special handling + // may reduce needed headroom. + + return is_typeArray_region(region) && is_remset_small(region); + } + public: - RegisterHumongousWithInCSetFastTestClosure() : _total_humongous(0), _candidate_humongous(0) { + RegisterHumongousWithInCSetFastTestClosure() + : _total_humongous(0), + _candidate_humongous(0), + _dcq(&JavaThread::dirty_card_queue_set()) { } virtual bool doHeapRegion(HeapRegion* r) { @@ -3696,14 +3747,33 @@ } G1CollectedHeap* g1h = G1CollectedHeap::heap(); - uint region_idx = r->hrm_index(); - bool is_candidate = !g1h->humongous_region_is_always_live(region_idx); - // Is_candidate already filters out humongous regions with some remembered set. - // This will not lead to humongous object that we mistakenly keep alive because - // during young collection the remembered sets will only be added to. + bool is_candidate = humongous_region_is_candidate(g1h, r); + uint rindex = r->hrm_index(); + g1h->set_humongous_reclaim_candidate(rindex, is_candidate); if (is_candidate) { - g1h->register_humongous_region_with_in_cset_fast_test(region_idx); _candidate_humongous++; + g1h->register_humongous_region_with_in_cset_fast_test(rindex); + // Is_candidate already filters out humongous object with large remembered sets. + // If we have a humongous object with a few remembered sets, we simply flush these + // remembered set entries into the DCQS. That will result in automatic + // re-evaluation of their remembered set entries during the following evacuation + // phase. + if (!r->rem_set()->is_empty()) { + guarantee(r->rem_set()->occupancy_less_or_equal_than(G1RSetSparseRegionEntries), + "Found a not-small remembered set here. This is inconsistent with previous assumptions."); + G1SATBCardTableLoggingModRefBS* bs = g1h->g1_barrier_set(); + HeapRegionRemSetIterator hrrs(r->rem_set()); + size_t card_index; + while (hrrs.has_next(card_index)) { + jbyte* card_ptr = (jbyte*)bs->byte_for_index(card_index); + if (*card_ptr != CardTableModRefBS::dirty_card_val()) { + *card_ptr = CardTableModRefBS::dirty_card_val(); + _dcq.enqueue(card_ptr); + } + } + r->rem_set()->clear_locked(); + } + assert(r->rem_set()->is_empty(), "At this point any humongous candidate remembered set must be empty."); } _total_humongous++; @@ -3712,23 +3782,29 @@ size_t total_humongous() const { return _total_humongous; } size_t candidate_humongous() const { return _candidate_humongous; } + + void flush_rem_set_entries() { _dcq.flush(); } }; void G1CollectedHeap::register_humongous_regions_with_in_cset_fast_test() { - if (!G1ReclaimDeadHumongousObjectsAtYoungGC) { - g1_policy()->phase_times()->record_fast_reclaim_humongous_stats(0, 0); + if (!G1EagerReclaimHumongousObjects) { + g1_policy()->phase_times()->record_fast_reclaim_humongous_stats(0.0, 0, 0); return; } - + double time = os::elapsed_counter(); + + // Collect reclaim candidate information and register candidates with cset. RegisterHumongousWithInCSetFastTestClosure cl; heap_region_iterate(&cl); - g1_policy()->phase_times()->record_fast_reclaim_humongous_stats(cl.total_humongous(), + + time = ((double)(os::elapsed_counter() - time) / os::elapsed_frequency()) * 1000.0; + g1_policy()->phase_times()->record_fast_reclaim_humongous_stats(time, + cl.total_humongous(), cl.candidate_humongous()); _has_humongous_reclaim_candidates = cl.candidate_humongous() > 0; - if (_has_humongous_reclaim_candidates) { - clear_humongous_is_live_table(); - } + // Finally flush all remembered set entries to re-check into the global DCQS. + cl.flush_rem_set_entries(); } void @@ -3906,10 +3982,10 @@ TraceCPUTime tcpu(G1Log::finer(), true, gclog_or_tty); - int active_workers = (G1CollectedHeap::use_parallel_gc_threads() ? + uint active_workers = (G1CollectedHeap::use_parallel_gc_threads() ? workers()->active_workers() : 1); double pause_start_sec = os::elapsedTime(); - g1_policy()->phase_times()->note_gc_start(active_workers); + g1_policy()->phase_times()->note_gc_start(active_workers, mark_in_progress()); log_gc_header(); TraceCollectorStats tcs(g1mm()->incremental_collection_counters()); @@ -4021,15 +4097,12 @@ register_humongous_regions_with_in_cset_fast_test(); + assert(check_cset_fast_test(), "Inconsistency in the InCSetState table."); + _cm->note_start_of_gc(); - // We should not verify the per-thread SATB buffers given that - // we have not filtered them yet (we'll do so during the - // GC). We also call this after finalize_cset() to + // We call this after finalize_cset() to // ensure that the CSet has been finalized. - _cm->verify_no_cset_oops(true /* verify_stacks */, - true /* verify_enqueued_buffers */, - false /* verify_thread_buffers */, - true /* verify_fingers */); + _cm->verify_no_cset_oops(); if (_hr_printer.is_active()) { HeapRegion* hr = g1_policy()->collection_set(); @@ -4052,16 +4125,6 @@ // Actually do the work... evacuate_collection_set(evacuation_info); - // We do this to mainly verify the per-thread SATB buffers - // (which have been filtered by now) since we didn't verify - // them earlier. No point in re-checking the stacks / enqueued - // buffers given that the CSet has not changed since last time - // we checked. - _cm->verify_no_cset_oops(false /* verify_stacks */, - false /* verify_enqueued_buffers */, - true /* verify_thread_buffers */, - true /* verify_fingers */); - free_collection_set(g1_policy()->collection_set(), evacuation_info); eagerly_reclaim_humongous_regions(); @@ -4144,10 +4207,7 @@ // We redo the verification but now wrt to the new CSet which // has just got initialized after the previous CSet was freed. - _cm->verify_no_cset_oops(true /* verify_stacks */, - true /* verify_enqueued_buffers */, - true /* verify_thread_buffers */, - true /* verify_fingers */); + _cm->verify_no_cset_oops(); _cm->note_end_of_gc(); // This timing is only used by the ergonomics to handle our pause target. @@ -4250,29 +4310,6 @@ return true; } -size_t G1CollectedHeap::desired_plab_sz(GCAllocPurpose purpose) -{ - size_t gclab_word_size; - switch (purpose) { - case GCAllocForSurvived: - gclab_word_size = _survivor_plab_stats.desired_plab_sz(); - break; - case GCAllocForTenured: - gclab_word_size = _old_plab_stats.desired_plab_sz(); - break; - default: - assert(false, "unknown GCAllocPurpose"); - gclab_word_size = _old_plab_stats.desired_plab_sz(); - break; - } - - // Prevent humongous PLAB sizes for two reasons: - // * PLABs are allocated using a similar paths as oops, but should - // never be in a humongous region - // * Allowing humongous PLABs needlessly churns the region free lists - return MIN2(_humongous_object_threshold_in_words, gclab_word_size); -} - void G1CollectedHeap::init_for_evac_failure(OopsInHeapRegionClosure* cl) { _drain_in_progress = false; set_evac_failure_closure(cl); @@ -4412,35 +4449,6 @@ } } -HeapWord* G1CollectedHeap::par_allocate_during_gc(GCAllocPurpose purpose, - size_t word_size, - AllocationContext_t context) { - if (purpose == GCAllocForSurvived) { - HeapWord* result = survivor_attempt_allocation(word_size, context); - if (result != NULL) { - return result; - } else { - // Let's try to allocate in the old gen in case we can fit the - // object there. - return old_attempt_allocation(word_size, context); - } - } else { - assert(purpose == GCAllocForTenured, "sanity"); - HeapWord* result = old_attempt_allocation(word_size, context); - if (result != NULL) { - return result; - } else { - // Let's try to allocate in the survivors in case we can fit the - // object there. - return survivor_attempt_allocation(word_size, context); - } - } - - ShouldNotReachHere(); - // Trying to keep some compilers happy. - return NULL; -} - void G1ParCopyHelper::mark_object(oop obj) { assert(!_g1->heap_region_containing(obj)->in_collection_set(), "should not mark objects in the CSet"); @@ -4483,14 +4491,14 @@ assert(_worker_id == _par_scan_state->queue_num(), "sanity"); - G1CollectedHeap::in_cset_state_t state = _g1->in_cset_state(obj); - - if (state == G1CollectedHeap::InCSet) { + const InCSetState state = _g1->in_cset_state(obj); + if (state.is_in_cset()) { oop forwardee; - if (obj->is_forwarded()) { - forwardee = obj->forwardee(); + markOop m = obj->mark(); + if (m->is_marked()) { + forwardee = (oop) m->decode_pointer(); } else { - forwardee = _par_scan_state->copy_to_survivor_space(obj); + forwardee = _par_scan_state->copy_to_survivor_space(state, obj, m); } assert(forwardee != NULL, "forwardee should not be NULL"); oopDesc::encode_store_heap_oop(p, forwardee); @@ -4504,7 +4512,7 @@ do_klass_barrier(p, forwardee); } } else { - if (state == G1CollectedHeap::IsHumongous) { + if (state.is_humongous()) { _g1->set_humongous_is_live(obj); } // The object is not in collection set. If we're a root scanning @@ -4589,60 +4597,11 @@ } }; -class G1CodeBlobClosure : public CodeBlobClosure { - class HeapRegionGatheringOopClosure : public OopClosure { - G1CollectedHeap* _g1h; - OopClosure* _work; - nmethod* _nm; - - template - void do_oop_work(T* p) { - _work->do_oop(p); - T oop_or_narrowoop = oopDesc::load_heap_oop(p); - if (!oopDesc::is_null(oop_or_narrowoop)) { - oop o = oopDesc::decode_heap_oop_not_null(oop_or_narrowoop); - HeapRegion* hr = _g1h->heap_region_containing_raw(o); - assert(!_g1h->obj_in_cs(o) || hr->rem_set()->strong_code_roots_list_contains(_nm), "if o still in CS then evacuation failed and nm must already be in the remset"); - hr->add_strong_code_root(_nm); - } - } - - public: - HeapRegionGatheringOopClosure(OopClosure* oc) : _g1h(G1CollectedHeap::heap()), _work(oc), _nm(NULL) {} - - void do_oop(oop* o) { - do_oop_work(o); - } - - void do_oop(narrowOop* o) { - do_oop_work(o); - } - - void set_nm(nmethod* nm) { - _nm = nm; - } - }; - - HeapRegionGatheringOopClosure _oc; -public: - G1CodeBlobClosure(OopClosure* oc) : _oc(oc) {} - - void do_code_blob(CodeBlob* cb) { - nmethod* nm = cb->as_nmethod_or_null(); - if (nm != NULL) { - if (!nm->test_set_oops_do_mark()) { - _oc.set_nm(nm); - nm->oops_do(&_oc); - nm->fix_oop_relocations(); - } - } - } -}; - class G1ParTask : public AbstractGangTask { protected: G1CollectedHeap* _g1h; RefToScanQueueSet *_queues; + G1RootProcessor* _root_processor; ParallelTaskTerminator _terminator; uint _n_workers; @@ -4650,10 +4609,11 @@ Mutex* stats_lock() { return &_stats_lock; } public: - G1ParTask(G1CollectedHeap* g1h, RefToScanQueueSet *task_queues) + G1ParTask(G1CollectedHeap* g1h, RefToScanQueueSet *task_queues, G1RootProcessor* root_processor) : AbstractGangTask("G1 collection"), _g1h(g1h), _queues(task_queues), + _root_processor(root_processor), _terminator(0, _queues), _stats_lock(Mutex::leaf, "parallel G1 stats lock", true) {} @@ -4667,13 +4627,7 @@ ParallelTaskTerminator* terminator() { return &_terminator; } virtual void set_for_termination(int active_workers) { - // This task calls set_n_termination() in par_non_clean_card_iterate_work() - // in the young space (_par_seq_tasks) in the G1 heap - // for SequentialSubTasksDone. - // This task also uses SubTasksDone in SharedHeap and G1CollectedHeap - // both of which need setting by set_n_termination(). - _g1h->SharedHeap::set_n_termination(active_workers); - _g1h->set_n_termination(active_workers); + _root_processor->set_num_workers(active_workers); terminator()->reset_for_reuse(active_workers); _n_workers = active_workers; } @@ -4710,8 +4664,7 @@ void work(uint worker_id) { if (worker_id >= _n_workers) return; // no work needed this round - double start_time_ms = os::elapsedTime() * 1000.0; - _g1h->g1_policy()->phase_times()->record_gc_worker_start_time(worker_id, start_time_ms); + _g1h->g1_policy()->phase_times()->record_time_secs(G1GCPhaseTimes::GCWorkerStart, worker_id, os::elapsedTime()); { ResourceMark rm; @@ -4743,24 +4696,21 @@ false, // Process all klasses. true); // Need to claim CLDs. - G1CodeBlobClosure scan_only_code_cl(&scan_only_root_cl); - G1CodeBlobClosure scan_mark_code_cl(&scan_mark_root_cl); - // IM Weak code roots are handled later. - OopClosure* strong_root_cl; OopClosure* weak_root_cl; CLDClosure* strong_cld_cl; CLDClosure* weak_cld_cl; - CodeBlobClosure* strong_code_cl; + + bool trace_metadata = false; if (_g1h->g1_policy()->during_initial_mark_pause()) { // We also need to mark copied objects. strong_root_cl = &scan_mark_root_cl; strong_cld_cl = &scan_mark_cld_cl; - strong_code_cl = &scan_mark_code_cl; if (ClassUnloadingWithConcurrentMark) { weak_root_cl = &scan_mark_weak_root_cl; weak_cld_cl = &scan_mark_weak_cld_cl; + trace_metadata = true; } else { weak_root_cl = &scan_mark_root_cl; weak_cld_cl = &scan_mark_cld_cl; @@ -4770,31 +4720,32 @@ weak_root_cl = &scan_only_root_cl; strong_cld_cl = &scan_only_cld_cl; weak_cld_cl = &scan_only_cld_cl; - strong_code_cl = &scan_only_code_cl; } - - G1ParPushHeapRSClosure push_heap_rs_cl(_g1h, &pss); - pss.start_strong_roots(); - _g1h->g1_process_roots(strong_root_cl, - weak_root_cl, - &push_heap_rs_cl, - strong_cld_cl, - weak_cld_cl, - strong_code_cl, - worker_id); - + + _root_processor->evacuate_roots(strong_root_cl, + weak_root_cl, + strong_cld_cl, + weak_cld_cl, + trace_metadata, + worker_id); + + G1ParPushHeapRSClosure push_heap_rs_cl(_g1h, &pss); + _root_processor->scan_remembered_sets(&push_heap_rs_cl, + weak_root_cl, + worker_id); pss.end_strong_roots(); { double start = os::elapsedTime(); G1ParEvacuateFollowersClosure evac(_g1h, &pss, _queues, &_terminator); evac.do_void(); - double elapsed_ms = (os::elapsedTime()-start)*1000.0; - double term_ms = pss.term_time()*1000.0; - _g1h->g1_policy()->phase_times()->add_obj_copy_time(worker_id, elapsed_ms-term_ms); - _g1h->g1_policy()->phase_times()->record_termination(worker_id, term_ms, pss.term_attempts()); + double elapsed_sec = os::elapsedTime() - start; + double term_sec = pss.term_time(); + _g1h->g1_policy()->phase_times()->add_time_secs(G1GCPhaseTimes::ObjCopy, worker_id, elapsed_sec - term_sec); + _g1h->g1_policy()->phase_times()->record_time_secs(G1GCPhaseTimes::Termination, worker_id, term_sec); + _g1h->g1_policy()->phase_times()->record_thread_work_item(G1GCPhaseTimes::Termination, worker_id, pss.term_attempts()); } _g1h->g1_policy()->record_thread_age_table(pss.age_table()); _g1h->update_surviving_young_words(pss.surviving_young_words()+1); @@ -4810,103 +4761,10 @@ // destructors are executed here and are included as part of the // "GC Worker Time". } - - double end_time_ms = os::elapsedTime() * 1000.0; - _g1h->g1_policy()->phase_times()->record_gc_worker_end_time(worker_id, end_time_ms); + _g1h->g1_policy()->phase_times()->record_time_secs(G1GCPhaseTimes::GCWorkerEnd, worker_id, os::elapsedTime()); } }; -// *** Common G1 Evacuation Stuff - -// This method is run in a GC worker. - -void -G1CollectedHeap:: -g1_process_roots(OopClosure* scan_non_heap_roots, - OopClosure* scan_non_heap_weak_roots, - OopsInHeapRegionClosure* scan_rs, - CLDClosure* scan_strong_clds, - CLDClosure* scan_weak_clds, - CodeBlobClosure* scan_strong_code, - uint worker_i) { - - // First scan the shared roots. - double ext_roots_start = os::elapsedTime(); - double closure_app_time_sec = 0.0; - - bool during_im = _g1h->g1_policy()->during_initial_mark_pause(); - bool trace_metadata = during_im && ClassUnloadingWithConcurrentMark; - - // Without eager nmethod unloading, we need to treat all oops in code cache as strong during the initial mark - bool trace_codecache = during_im && !ClassUnloadingWithConcurrentMark; - - BufferingOopClosure buf_scan_non_heap_roots(scan_non_heap_roots); - BufferingOopClosure buf_scan_non_heap_weak_roots(scan_non_heap_weak_roots); - - process_roots(false, // no scoping; this is parallel code - trace_codecache ? SharedHeap::SO_AllCodeCache : SharedHeap::SO_None, - &buf_scan_non_heap_roots, - &buf_scan_non_heap_weak_roots, - scan_strong_clds, - // Unloading Initial Marks handle the weak CLDs separately. - (trace_metadata ? NULL : scan_weak_clds), - scan_strong_code); - - // Now the CM ref_processor roots. - if (!_process_strong_tasks->is_task_claimed(G1H_PS_refProcessor_oops_do)) { - // We need to treat the discovered reference lists of the - // concurrent mark ref processor as roots and keep entries - // (which are added by the marking threads) on them live - // until they can be processed at the end of marking. - ref_processor_cm()->weak_oops_do(&buf_scan_non_heap_roots); - } - - if (trace_metadata) { - // Barrier to make sure all workers passed - // the strong CLD and strong nmethods phases. - active_strong_roots_scope()->wait_until_all_workers_done_with_threads(n_par_threads()); - - // Now take the complement of the strong CLDs. - ClassLoaderDataGraph::roots_cld_do(NULL, scan_weak_clds); - } - - // Finish up any enqueued closure apps (attributed as object copy time). - buf_scan_non_heap_roots.done(); - buf_scan_non_heap_weak_roots.done(); - - double obj_copy_time_sec = buf_scan_non_heap_roots.closure_app_seconds() - + buf_scan_non_heap_weak_roots.closure_app_seconds(); - - g1_policy()->phase_times()->record_obj_copy_time(worker_i, obj_copy_time_sec * 1000.0); - - double ext_root_time_ms = - ((os::elapsedTime() - ext_roots_start) - obj_copy_time_sec) * 1000.0; - - g1_policy()->phase_times()->record_ext_root_scan_time(worker_i, ext_root_time_ms); - - // During conc marking we have to filter the per-thread SATB buffers - // to make sure we remove any oops into the CSet (which will show up - // as implicitly live). - double satb_filtering_ms = 0.0; - if (!_process_strong_tasks->is_task_claimed(G1H_PS_filter_satb_buffers)) { - if (mark_in_progress()) { - double satb_filter_start = os::elapsedTime(); - - JavaThread::satb_mark_queue_set().filter_thread_buffers(); - - satb_filtering_ms = (os::elapsedTime() - satb_filter_start) * 1000.0; - } - } - g1_policy()->phase_times()->record_satb_filtering_time(worker_i, satb_filtering_ms); - - // Now scan the complement of the collection set. - G1CodeBlobClosure scavenge_cs_nmethods(scan_non_heap_weak_roots); - - g1_rem_set()->oops_into_collection_set_do(scan_rs, &scavenge_cs_nmethods, worker_i); - - _process_strong_tasks->all_tasks_completed(); -} - class G1StringSymbolTableUnlinkTask : public AbstractGangTask { private: BoolObjectClosure* _is_alive; @@ -5320,7 +5178,8 @@ G1RedirtyLoggedCardsTask(DirtyCardQueueSet* queue) : AbstractGangTask("Redirty Cards"), _queue(queue) { } virtual void work(uint worker_id) { - double start_time = os::elapsedTime(); + G1GCPhaseTimes* phase_times = G1CollectedHeap::heap()->g1_policy()->phase_times(); + G1GCParPhaseTimesTracker x(phase_times, G1GCPhaseTimes::RedirtyCards, worker_id); RedirtyLoggedCardTableEntryClosure cl; if (G1CollectedHeap::heap()->use_parallel_gc_threads()) { @@ -5329,9 +5188,7 @@ _queue->apply_closure_to_all_completed_buffers(&cl); } - G1GCPhaseTimes* timer = G1CollectedHeap::heap()->g1_policy()->phase_times(); - timer->record_redirty_logged_cards_time_ms(worker_id, (os::elapsedTime() - start_time) * 1000.0); - timer->record_redirty_logged_cards_processed_cards(worker_id, cl.num_processed()); + phase_times->record_thread_work_item(G1GCPhaseTimes::RedirtyCards, worker_id, cl.num_processed()); } }; @@ -5392,17 +5249,17 @@ oop obj = *p; assert(obj != NULL, "the caller should have filtered out NULL values"); - G1CollectedHeap::in_cset_state_t cset_state = _g1->in_cset_state(obj); - if (cset_state == G1CollectedHeap::InNeither) { + const InCSetState cset_state = _g1->in_cset_state(obj); + if (!cset_state.is_in_cset_or_humongous()) { return; } - if (cset_state == G1CollectedHeap::InCSet) { + if (cset_state.is_in_cset()) { assert( obj->is_forwarded(), "invariant" ); *p = obj->forwardee(); } else { assert(!obj->is_forwarded(), "invariant" ); - assert(cset_state == G1CollectedHeap::IsHumongous, - err_msg("Only allowed InCSet state is IsHumongous, but is %d", cset_state)); + assert(cset_state.is_humongous(), + err_msg("Only allowed InCSet state is IsHumongous, but is %d", cset_state.value())); _g1->set_humongous_is_live(obj); } } @@ -5895,7 +5752,6 @@ n_workers = 1; } - G1ParTask g1_par_task(this, _task_queues); init_for_evac_failure(NULL); @@ -5906,7 +5762,8 @@ double end_par_time_sec; { - StrongRootsScope srs(this); + G1RootProcessor root_processor(this); + G1ParTask g1_par_task(this, _task_queues, &root_processor); // InitialMark needs claim bits to keep track of the marked-through CLDs. if (g1_policy()->during_initial_mark_pause()) { ClassLoaderDataGraph::clear_claimed_marks(); @@ -5927,18 +5784,20 @@ end_par_time_sec = os::elapsedTime(); // Closing the inner scope will execute the destructor - // for the StrongRootsScope object. We record the current + // for the G1RootProcessor object. We record the current // elapsed time before closing the scope so that time - // taken for the SRS destructor is NOT included in the + // taken for the destructor is NOT included in the // reported parallel time. } + G1GCPhaseTimes* phase_times = g1_policy()->phase_times(); + double par_time_ms = (end_par_time_sec - start_par_time_sec) * 1000.0; - g1_policy()->phase_times()->record_par_time(par_time_ms); + phase_times->record_par_time(par_time_ms); double code_root_fixup_time_ms = (os::elapsedTime() - end_par_time_sec) * 1000.0; - g1_policy()->phase_times()->record_code_root_fixup_time(code_root_fixup_time_ms); + phase_times->record_code_root_fixup_time(code_root_fixup_time_ms); set_par_threads(0); @@ -5949,14 +5808,15 @@ // not copied during the pause. process_discovered_references(n_workers); - // Weak root processing. - { + if (G1StringDedup::is_enabled()) { + double fixup_start = os::elapsedTime(); + G1STWIsAliveClosure is_alive(this); G1KeepAliveClosure keep_alive(this); - JNIHandles::weak_oops_do(&is_alive, &keep_alive); - if (G1StringDedup::is_enabled()) { - G1StringDedup::unlink_or_oops_do(&is_alive, &keep_alive); - } + G1StringDedup::unlink_or_oops_do(&is_alive, &keep_alive, true, phase_times); + + double fixup_time_ms = (os::elapsedTime() - fixup_start) * 1000.0; + phase_times->record_string_dedup_fixup_time(fixup_time_ms); } _allocator->release_gc_alloc_regions(n_workers, evacuation_info); @@ -6226,6 +6086,70 @@ heap_region_iterate(&cl); guarantee(!cl.failures(), "bitmap verification"); } + +class G1CheckCSetFastTableClosure : public HeapRegionClosure { + private: + bool _failures; + public: + G1CheckCSetFastTableClosure() : HeapRegionClosure(), _failures(false) { } + + virtual bool doHeapRegion(HeapRegion* hr) { + uint i = hr->hrm_index(); + InCSetState cset_state = (InCSetState) G1CollectedHeap::heap()->_in_cset_fast_test.get_by_index(i); + if (hr->isHumongous()) { + if (hr->in_collection_set()) { + gclog_or_tty->print_cr("\n## humongous region %u in CSet", i); + _failures = true; + return true; + } + if (cset_state.is_in_cset()) { + gclog_or_tty->print_cr("\n## inconsistent cset state %d for humongous region %u", cset_state.value(), i); + _failures = true; + return true; + } + if (hr->continuesHumongous() && cset_state.is_humongous()) { + gclog_or_tty->print_cr("\n## inconsistent cset state %d for continues humongous region %u", cset_state.value(), i); + _failures = true; + return true; + } + } else { + if (cset_state.is_humongous()) { + gclog_or_tty->print_cr("\n## inconsistent cset state %d for non-humongous region %u", cset_state.value(), i); + _failures = true; + return true; + } + if (hr->in_collection_set() != cset_state.is_in_cset()) { + gclog_or_tty->print_cr("\n## in CSet %d / cset state %d inconsistency for region %u", + hr->in_collection_set(), cset_state.value(), i); + _failures = true; + return true; + } + if (cset_state.is_in_cset()) { + if (hr->is_young() != (cset_state.is_young())) { + gclog_or_tty->print_cr("\n## is_young %d / cset state %d inconsistency for region %u", + hr->is_young(), cset_state.value(), i); + _failures = true; + return true; + } + if (hr->is_old() != (cset_state.is_old())) { + gclog_or_tty->print_cr("\n## is_old %d / cset state %d inconsistency for region %u", + hr->is_old(), cset_state.value(), i); + _failures = true; + return true; + } + } + } + return false; + } + + bool failures() const { return _failures; } +}; + +bool G1CollectedHeap::check_cset_fast_test() { + G1CheckCSetFastTableClosure cl; + _hrm.iterate(&cl); + return !cl.failures(); +} #endif // PRODUCT void G1CollectedHeap::cleanUpCardTable() { @@ -6421,47 +6345,47 @@ // are completely up-to-date wrt to references to the humongous object. // // Other implementation considerations: - // - never consider object arrays: while they are a valid target, they have not - // been observed to be used as temporary objects. - // - they would also pose considerable effort for cleaning up the the remembered - // sets. - // While this cleanup is not strictly necessary to be done (or done instantly), - // given that their occurrence is very low, this saves us this additional - // complexity. + // - never consider object arrays at this time because they would pose + // considerable effort for cleaning up the the remembered sets. This is + // required because stale remembered sets might reference locations that + // are currently allocated into. uint region_idx = r->hrm_index(); - if (g1h->humongous_is_live(region_idx) || - g1h->humongous_region_is_always_live(region_idx)) { - - if (G1TraceReclaimDeadHumongousObjectsAtYoungGC) { - gclog_or_tty->print_cr("Live humongous %d region %d with remset "SIZE_FORMAT" code roots "SIZE_FORMAT" is marked %d live-other %d obj array %d", - r->isHumongous(), + if (!g1h->is_humongous_reclaim_candidate(region_idx) || + !r->rem_set()->is_empty()) { + + if (G1TraceEagerReclaimHumongousObjects) { + gclog_or_tty->print_cr("Live humongous region %u size "SIZE_FORMAT" start "PTR_FORMAT" length "UINT32_FORMAT" with remset "SIZE_FORMAT" code roots "SIZE_FORMAT" is marked %d reclaim candidate %d type array %d", region_idx, + obj->size()*HeapWordSize, + r->bottom(), + r->region_num(), r->rem_set()->occupied(), r->rem_set()->strong_code_roots_list_length(), next_bitmap->isMarked(r->bottom()), - g1h->humongous_is_live(region_idx), - obj->is_objArray() + g1h->is_humongous_reclaim_candidate(region_idx), + obj->is_typeArray() ); } return false; } - guarantee(!obj->is_objArray(), - err_msg("Eagerly reclaiming object arrays is not supported, but the object "PTR_FORMAT" is.", + guarantee(obj->is_typeArray(), + err_msg("Only eagerly reclaiming type arrays is supported, but the object " + PTR_FORMAT " is not.", r->bottom())); - if (G1TraceReclaimDeadHumongousObjectsAtYoungGC) { - gclog_or_tty->print_cr("Reclaim humongous region %d start "PTR_FORMAT" region %d length "UINT32_FORMAT" with remset "SIZE_FORMAT" code roots "SIZE_FORMAT" is marked %d live-other %d obj array %d", - r->isHumongous(), + if (G1TraceEagerReclaimHumongousObjects) { + gclog_or_tty->print_cr("Dead humongous region %u size "SIZE_FORMAT" start "PTR_FORMAT" length "UINT32_FORMAT" with remset "SIZE_FORMAT" code roots "SIZE_FORMAT" is marked %d reclaim candidate %d type array %d", + region_idx, + obj->size()*HeapWordSize, r->bottom(), - region_idx, r->region_num(), r->rem_set()->occupied(), r->rem_set()->strong_code_roots_list_length(), next_bitmap->isMarked(r->bottom()), - g1h->humongous_is_live(region_idx), - obj->is_objArray() + g1h->is_humongous_reclaim_candidate(region_idx), + obj->is_typeArray() ); } // Need to clear mark bit of the humongous object if already set. @@ -6492,7 +6416,8 @@ void G1CollectedHeap::eagerly_reclaim_humongous_regions() { assert_at_safepoint(true); - if (!G1ReclaimDeadHumongousObjectsAtYoungGC || !_has_humongous_reclaim_candidates) { + if (!G1EagerReclaimHumongousObjects || + (!_has_humongous_reclaim_candidates && !G1TraceEagerReclaimHumongousObjects)) { g1_policy()->phase_times()->record_fast_reclaim_humongous_time_ms(0.0, 0); return; } @@ -6805,20 +6730,20 @@ HeapRegion* G1CollectedHeap::new_gc_alloc_region(size_t word_size, uint count, - GCAllocPurpose ap) { + InCSetState dest) { assert(FreeList_lock->owned_by_self(), "pre-condition"); - if (count < g1_policy()->max_regions(ap)) { - bool survivor = (ap == GCAllocForSurvived); + if (count < g1_policy()->max_regions(dest)) { + const bool is_survivor = (dest.is_young()); HeapRegion* new_alloc_region = new_region(word_size, - !survivor, + !is_survivor, true /* do_expand */); if (new_alloc_region != NULL) { // We really only need to do this for old regions given that we // should never scan survivors. But it doesn't hurt to do it // for survivors too. - new_alloc_region->record_top_and_timestamp(); - if (survivor) { + new_alloc_region->record_timestamp(); + if (is_survivor) { new_alloc_region->set_survivor(); _hr_printer.alloc(new_alloc_region, G1HRPrinter::Survivor); check_bitmaps("Survivor Region Allocation", new_alloc_region); @@ -6830,8 +6755,6 @@ bool during_im = g1_policy()->during_initial_mark_pause(); new_alloc_region->note_start_of_copying(during_im); return new_alloc_region; - } else { - g1_policy()->note_alloc_region_limit_reached(ap); } } return NULL; @@ -6839,11 +6762,11 @@ void G1CollectedHeap::retire_gc_alloc_region(HeapRegion* alloc_region, size_t allocated_bytes, - GCAllocPurpose ap) { + InCSetState dest) { bool during_im = g1_policy()->during_initial_mark_pause(); alloc_region->note_end_of_copying(during_im); g1_policy()->record_bytes_copied_during_gc(allocated_bytes); - if (ap == GCAllocForSurvived) { + if (dest.is_young()) { young_list()->add_survivor_region(alloc_region); } else { _old_set.add(alloc_region); diff -r c2687aa5e5ca -r 7eb99acd567f src/share/vm/gc_implementation/g1/g1CollectedHeap.hpp --- a/src/share/vm/gc_implementation/g1/g1CollectedHeap.hpp Mon Jan 25 14:56:57 2016 -0800 +++ b/src/share/vm/gc_implementation/g1/g1CollectedHeap.hpp Mon Jan 25 14:57:27 2016 -0800 @@ -1,5 +1,5 @@ -/* - * Copyright (c) 2001, 2014, Oracle and/or its affiliates. All rights reserved. + /* + * Copyright (c) 2001, 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 @@ -32,6 +32,7 @@ #include "gc_implementation/g1/g1AllocRegion.hpp" #include "gc_implementation/g1/g1BiasedArray.hpp" #include "gc_implementation/g1/g1HRPrinter.hpp" +#include "gc_implementation/g1/g1InCSetState.hpp" #include "gc_implementation/g1/g1MonitoringSupport.hpp" #include "gc_implementation/g1/g1SATBCardTableModRefBS.hpp" #include "gc_implementation/g1/g1YCTypes.hpp" @@ -212,6 +213,9 @@ // Other related classes. friend class G1MarkSweep; + // Testing classes. + friend class G1CheckCSetFastTableClosure; + private: // The one and only G1CollectedHeap, so static functions can find it. static G1CollectedHeap* _g1h; @@ -229,7 +233,6 @@ // It keeps track of the humongous regions. HeapRegionSet _humongous_set; - void clear_humongous_is_live_table(); void eagerly_reclaim_humongous_regions(); // The number of regions we could create by expansion. @@ -299,22 +302,26 @@ // Helper for monitoring and management support. G1MonitoringSupport* _g1mm; - // Records whether the region at the given index is kept live by roots or - // references from the young generation. - class HumongousIsLiveBiasedMappedArray : public G1BiasedMappedArray { + // Records whether the region at the given index is (still) a + // candidate for eager reclaim. Only valid for humongous start + // regions; other regions have unspecified values. Humongous start + // regions are initialized at start of collection pause, with + // candidates removed from the set as they are found reachable from + // roots or the young generation. + class HumongousReclaimCandidates : public G1BiasedMappedArray { protected: bool default_value() const { return false; } public: void clear() { G1BiasedMappedArray::clear(); } - void set_live(uint region) { - set_by_index(region, true); + void set_candidate(uint region, bool value) { + set_by_index(region, value); } - bool is_live(uint region) { + bool is_candidate(uint region) { return get_by_index(region); } }; - HumongousIsLiveBiasedMappedArray _humongous_is_live; + HumongousReclaimCandidates _humongous_reclaim_candidates; // Stores whether during humongous object registration we found candidate regions. // If not, we can skip a few steps. bool _has_humongous_reclaim_candidates; @@ -339,13 +346,14 @@ // Keeps track of how many "old marking cycles" (i.e., Full GCs or // concurrent cycles) we have started. - volatile unsigned int _old_marking_cycles_started; + volatile uint _old_marking_cycles_started; // Keeps track of how many "old marking cycles" (i.e., Full GCs or // concurrent cycles) we have completed. - volatile unsigned int _old_marking_cycles_completed; + volatile uint _old_marking_cycles_completed; bool _concurrent_cycle_started; + bool _heap_summary_sent; // This is a non-product method that is helpful for testing. It is // called at the end of a GC and artificially expands the heap by @@ -362,6 +370,12 @@ // heap after a compaction. void print_hrm_post_compaction(); + // Create a memory mapper for auxiliary data structures of the given size and + // translation factor. + static G1RegionToSpaceMapper* create_aux_memory_mapper(const char* description, + size_t size, + size_t translation_factor); + double verify(bool guard, const char* msg); void verify_before_gc(); void verify_after_gc(); @@ -510,22 +524,22 @@ // the mutator alloc region without taking the Heap_lock. This // should only be used for non-humongous allocations. inline HeapWord* attempt_allocation(size_t word_size, - unsigned int* gc_count_before_ret, - int* gclocker_retry_count_ret); + uint* gc_count_before_ret, + uint* gclocker_retry_count_ret); // Second-level mutator allocation attempt: take the Heap_lock and // retry the allocation attempt, potentially scheduling a GC // pause. This should only be used for non-humongous allocations. HeapWord* attempt_allocation_slow(size_t word_size, AllocationContext_t context, - unsigned int* gc_count_before_ret, - int* gclocker_retry_count_ret); + uint* gc_count_before_ret, + uint* gclocker_retry_count_ret); // Takes the Heap_lock and attempts a humongous allocation. It can // potentially schedule a GC pause. HeapWord* attempt_allocation_humongous(size_t word_size, - unsigned int* gc_count_before_ret, - int* gclocker_retry_count_ret); + uint* gc_count_before_ret, + uint* gclocker_retry_count_ret); // Allocation attempt that should be called during safepoints (e.g., // at the end of a successful GC). expect_null_mutator_alloc_region @@ -545,15 +559,9 @@ // allocation region, either by picking one or expanding the // heap, and then allocate a block of the given size. The block // may not be a humongous - it must fit into a single heap region. - HeapWord* par_allocate_during_gc(GCAllocPurpose purpose, - size_t word_size, - AllocationContext_t context); - - HeapWord* allocate_during_gc_slow(GCAllocPurpose purpose, - HeapRegion* alloc_region, - bool par, - size_t word_size); - + inline HeapWord* par_allocate_during_gc(InCSetState dest, + size_t word_size, + AllocationContext_t context); // Ensure that no further allocations can happen in "r", bearing in mind // that parallel threads might be attempting allocations. void par_allocate_remaining_space(HeapRegion* r); @@ -575,9 +583,9 @@ // For GC alloc regions. HeapRegion* new_gc_alloc_region(size_t word_size, uint count, - GCAllocPurpose ap); + InCSetState dest); void retire_gc_alloc_region(HeapRegion* alloc_region, - size_t allocated_bytes, GCAllocPurpose ap); + size_t allocated_bytes, InCSetState dest); // - if explicit_gc is true, the GC is for a System.gc() or a heap // inspection request and should collect the entire heap @@ -638,26 +646,11 @@ // (Rounds up to a HeapRegion boundary.) bool expand(size_t expand_bytes); - // Returns the PLAB statistics given a purpose. - PLABStats* stats_for_purpose(GCAllocPurpose purpose) { - PLABStats* stats = NULL; + // Returns the PLAB statistics for a given destination. + inline PLABStats* alloc_buffer_stats(InCSetState dest); - switch (purpose) { - case GCAllocForSurvived: - stats = &_survivor_plab_stats; - break; - case GCAllocForTenured: - stats = &_old_plab_stats; - break; - default: - assert(false, "unrecognized GCAllocPurpose"); - } - - return stats; - } - - // Determines PLAB size for a particular allocation purpose. - size_t desired_plab_sz(GCAllocPurpose purpose); + // Determines PLAB size for a given destination. + inline size_t desired_plab_sz(InCSetState dest); inline AllocationContextStats& allocation_context_stats(); @@ -665,15 +658,15 @@ virtual void gc_prologue(bool full); virtual void gc_epilogue(bool full); + // Modify the reclaim candidate set and test for presence. + // These are only valid for starts_humongous regions. + inline void set_humongous_reclaim_candidate(uint region, bool value); + inline bool is_humongous_reclaim_candidate(uint region); + + // Remove from the reclaim candidate set. Also remove from the + // collection set so that later encounters avoid the slow path. inline void set_humongous_is_live(oop obj); - bool humongous_is_live(uint region) { - return _humongous_is_live.is_live(region); - } - - // Returns whether the given region (which must be a humongous (start) region) - // is to be considered conservatively live regardless of any other conditions. - bool humongous_region_is_always_live(uint index); // Register the given region to be part of the collection set. inline void register_humongous_region_with_in_cset_fast_test(uint index); // Register regions with humongous objects (actually on the start region) in @@ -681,8 +674,11 @@ void register_humongous_regions_with_in_cset_fast_test(); // We register a region with the fast "in collection set" test. We // simply set to true the array slot corresponding to this region. - void register_region_with_in_cset_fast_test(HeapRegion* r) { - _in_cset_fast_test.set_in_cset(r->hrm_index()); + void register_young_region_with_in_cset_fast_test(HeapRegion* r) { + _in_cset_fast_test.set_in_young(r->hrm_index()); + } + void register_old_region_with_in_cset_fast_test(HeapRegion* r) { + _in_cset_fast_test.set_in_old(r->hrm_index()); } // This is a fast test on whether a reference points into the @@ -714,7 +710,7 @@ // +ExplicitGCInvokesConcurrent). void increment_old_marking_cycles_completed(bool concurrent); - unsigned int old_marking_cycles_completed() { + uint old_marking_cycles_completed() { return _old_marking_cycles_completed; } @@ -773,7 +769,7 @@ // methods that call do_collection_pause() release the Heap_lock // before the call, so it's easy to read gc_count_before just before. HeapWord* do_collection_pause(size_t word_size, - unsigned int gc_count_before, + uint gc_count_before, bool* succeeded, GCCause::Cause gc_cause); @@ -812,22 +808,6 @@ // statistics or updating free lists. void abandon_collection_set(HeapRegion* cs_head); - // Applies "scan_non_heap_roots" to roots outside the heap, - // "scan_rs" to roots inside the heap (having done "set_region" to - // indicate the region in which the root resides), - // and does "scan_metadata" If "scan_rs" is - // NULL, then this step is skipped. The "worker_i" - // param is for use with parallel roots processing, and should be - // the "i" of the calling parallel worker thread's work(i) function. - // In the sequential case this param will be ignored. - void g1_process_roots(OopClosure* scan_non_heap_roots, - OopClosure* scan_non_heap_weak_roots, - OopsInHeapRegionClosure* scan_rs, - CLDClosure* scan_strong_clds, - CLDClosure* scan_weak_clds, - CodeBlobClosure* scan_strong_code, - uint worker_i); - // The concurrent marker (and the thread it runs in.) ConcurrentMark* _cm; ConcurrentMarkThread* _cmThread; @@ -1012,23 +992,12 @@ // The heap region entry for a given worker is valid iff // the associated time stamp value matches the current value // of G1CollectedHeap::_gc_time_stamp. - unsigned int* _worker_cset_start_region_time_stamp; - - enum G1H_process_roots_tasks { - G1H_PS_filter_satb_buffers, - G1H_PS_refProcessor_oops_do, - // Leave this one last. - G1H_PS_NumElements - }; - - SubTasksDone* _process_strong_tasks; + uint* _worker_cset_start_region_time_stamp; volatile bool _free_regions_coming; public: - SubTasksDone* process_strong_tasks() { return _process_strong_tasks; } - void set_refine_cte_cl_concurrency(bool concurrent); RefToScanQueue *task_queue(int i) const; @@ -1061,21 +1030,11 @@ // Initialize weak reference processing. virtual void ref_processing_init(); - void set_par_threads(uint t) { - SharedHeap::set_par_threads(t); - // Done in SharedHeap but oddly there are - // two _process_strong_tasks's in a G1CollectedHeap - // so do it here too. - _process_strong_tasks->set_n_threads(t); - } - + // Explicitly import set_par_threads into this scope + using SharedHeap::set_par_threads; // Set _n_par_threads according to a policy TBD. void set_par_threads(); - void set_n_termination(int t) { - _process_strong_tasks->set_n_threads(t); - } - virtual CollectedHeap::Name kind() const { return CollectedHeap::G1CollectedHeap; } @@ -1150,6 +1109,10 @@ // The number of regions that are completely free. uint num_free_regions() const { return _hrm.num_free_regions(); } + MemoryUsage get_auxiliary_data_memory_usage() const { + return _hrm.get_auxiliary_data_memory_usage(); + } + // The number of regions that are not completely free. uint num_used_regions() const { return num_regions() - num_free_regions(); } @@ -1182,6 +1145,9 @@ // appropriate error messages and crash. void check_bitmaps(const char* caller) PRODUCT_RETURN; + // Do sanity check on the contents of the in-cset fast test table. + bool check_cset_fast_test() PRODUCT_RETURN_( return true; ); + // verify_region_sets() performs verification over the region // lists. It will be compiled in the product code to be used when // necessary (i.e., during heap verification). @@ -1277,53 +1243,15 @@ inline bool is_in_cset_or_humongous(const oop obj); - enum in_cset_state_t { - InNeither, // neither in collection set nor humongous - InCSet, // region is in collection set only - IsHumongous // region is a humongous start region - }; private: - // Instances of this class are used for quick tests on whether a reference points - // into the collection set or is a humongous object (points into a humongous - // object). - // Each of the array's elements denotes whether the corresponding region is in - // the collection set or a humongous region. - // We use this to quickly reclaim humongous objects: by making a humongous region - // succeed this test, we sort-of add it to the collection set. During the reference - // iteration closures, when we see a humongous region, we simply mark it as - // referenced, i.e. live. - class G1FastCSetBiasedMappedArray : public G1BiasedMappedArray { - protected: - char default_value() const { return G1CollectedHeap::InNeither; } - public: - void set_humongous(uintptr_t index) { - assert(get_by_index(index) != InCSet, "Should not overwrite InCSet values"); - set_by_index(index, G1CollectedHeap::IsHumongous); - } - - void clear_humongous(uintptr_t index) { - set_by_index(index, G1CollectedHeap::InNeither); - } - - void set_in_cset(uintptr_t index) { - assert(get_by_index(index) != G1CollectedHeap::IsHumongous, "Should not overwrite IsHumongous value"); - set_by_index(index, G1CollectedHeap::InCSet); - } - - bool is_in_cset_or_humongous(HeapWord* addr) const { return get_by_address(addr) != G1CollectedHeap::InNeither; } - bool is_in_cset(HeapWord* addr) const { return get_by_address(addr) == G1CollectedHeap::InCSet; } - G1CollectedHeap::in_cset_state_t at(HeapWord* addr) const { return (G1CollectedHeap::in_cset_state_t)get_by_address(addr); } - void clear() { G1BiasedMappedArray::clear(); } - }; - // This array is used for a quick test on whether a reference points into // the collection set or not. Each of the array's elements denotes whether the // corresponding region is in the collection set or not. - G1FastCSetBiasedMappedArray _in_cset_fast_test; + G1InCSetStateFastTestBiasedMappedArray _in_cset_fast_test; public: - inline in_cset_state_t in_cset_state(const oop obj); + inline InCSetState in_cset_state(const oop obj); // Return "TRUE" iff the given object address is in the reserved // region of g1. diff -r c2687aa5e5ca -r 7eb99acd567f src/share/vm/gc_implementation/g1/g1CollectedHeap.inline.hpp --- a/src/share/vm/gc_implementation/g1/g1CollectedHeap.inline.hpp Mon Jan 25 14:56:57 2016 -0800 +++ b/src/share/vm/gc_implementation/g1/g1CollectedHeap.inline.hpp Mon Jan 25 14:57:27 2016 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 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 @@ -35,6 +35,41 @@ #include "runtime/orderAccess.inline.hpp" #include "utilities/taskqueue.hpp" +PLABStats* G1CollectedHeap::alloc_buffer_stats(InCSetState dest) { + switch (dest.value()) { + case InCSetState::Young: + return &_survivor_plab_stats; + case InCSetState::Old: + return &_old_plab_stats; + default: + ShouldNotReachHere(); + return NULL; // Keep some compilers happy + } +} + +size_t G1CollectedHeap::desired_plab_sz(InCSetState dest) { + size_t gclab_word_size = alloc_buffer_stats(dest)->desired_plab_sz(); + // Prevent humongous PLAB sizes for two reasons: + // * PLABs are allocated using a similar paths as oops, but should + // never be in a humongous region + // * Allowing humongous PLABs needlessly churns the region free lists + return MIN2(_humongous_object_threshold_in_words, gclab_word_size); +} + +HeapWord* G1CollectedHeap::par_allocate_during_gc(InCSetState dest, + size_t word_size, + AllocationContext_t context) { + switch (dest.value()) { + case InCSetState::Young: + return survivor_attempt_allocation(word_size, context); + case InCSetState::Old: + return old_attempt_allocation(word_size, context); + default: + ShouldNotReachHere(); + return NULL; // Keep some compilers happy + } +} + // Inline functions for G1CollectedHeap inline AllocationContextStats& G1CollectedHeap::allocation_context_stats() { @@ -96,8 +131,8 @@ } inline HeapWord* G1CollectedHeap::attempt_allocation(size_t word_size, - unsigned int* gc_count_before_ret, - int* gclocker_retry_count_ret) { + uint* gc_count_before_ret, + uint* gclocker_retry_count_ret) { assert_heap_not_locked_and_not_at_safepoint(); assert(!isHumongous(word_size), "attempt_allocation() should not " "be called for humongous allocation requests"); @@ -203,7 +238,7 @@ return _in_cset_fast_test.is_in_cset_or_humongous((HeapWord*)obj); } -G1CollectedHeap::in_cset_state_t G1CollectedHeap::in_cset_state(const oop obj) { +InCSetState G1CollectedHeap::in_cset_state(const oop obj) { return _in_cset_fast_test.at((HeapWord*)obj); } @@ -313,20 +348,30 @@ return is_obj_ill(obj, heap_region_containing(obj)); } +inline void G1CollectedHeap::set_humongous_reclaim_candidate(uint region, bool value) { + assert(_hrm.at(region)->startsHumongous(), "Must start a humongous object"); + _humongous_reclaim_candidates.set_candidate(region, value); +} + +inline bool G1CollectedHeap::is_humongous_reclaim_candidate(uint region) { + assert(_hrm.at(region)->startsHumongous(), "Must start a humongous object"); + return _humongous_reclaim_candidates.is_candidate(region); +} + inline void G1CollectedHeap::set_humongous_is_live(oop obj) { uint region = addr_to_region((HeapWord*)obj); - // We not only set the "live" flag in the humongous_is_live table, but also + // Clear the flag in the humongous_reclaim_candidates table. Also // reset the entry in the _in_cset_fast_test table so that subsequent references // to the same humongous object do not go into the slow path again. // This is racy, as multiple threads may at the same time enter here, but this // is benign. - // During collection we only ever set the "live" flag, and only ever clear the + // During collection we only ever clear the "candidate" flag, and only ever clear the // entry in the in_cset_fast_table. // We only ever evaluate the contents of these tables (in the VM thread) after // having synchronized the worker threads with the VM thread, or in the same // thread (i.e. within the VM thread). - if (!_humongous_is_live.is_live(region)) { - _humongous_is_live.set_live(region); + if (is_humongous_reclaim_candidate(region)) { + set_humongous_reclaim_candidate(region, false); _in_cset_fast_test.clear_humongous(region); } } diff -r c2687aa5e5ca -r 7eb99acd567f src/share/vm/gc_implementation/g1/g1CollectorPolicy.cpp --- a/src/share/vm/gc_implementation/g1/g1CollectorPolicy.cpp Mon Jan 25 14:56:57 2016 -0800 +++ b/src/share/vm/gc_implementation/g1/g1CollectorPolicy.cpp Mon Jan 25 14:57:27 2016 -0800 @@ -1084,7 +1084,7 @@ if (update_stats) { double cost_per_card_ms = 0.0; if (_pending_cards > 0) { - cost_per_card_ms = phase_times()->average_last_update_rs_time() / (double) _pending_cards; + cost_per_card_ms = phase_times()->average_time_ms(G1GCPhaseTimes::UpdateRS) / (double) _pending_cards; _cost_per_card_ms_seq->add(cost_per_card_ms); } @@ -1092,7 +1092,7 @@ double cost_per_entry_ms = 0.0; if (cards_scanned > 10) { - cost_per_entry_ms = phase_times()->average_last_scan_rs_time() / (double) cards_scanned; + cost_per_entry_ms = phase_times()->average_time_ms(G1GCPhaseTimes::ScanRS) / (double) cards_scanned; if (_last_gc_was_young) { _cost_per_entry_ms_seq->add(cost_per_entry_ms); } else { @@ -1134,7 +1134,7 @@ double cost_per_byte_ms = 0.0; if (copied_bytes > 0) { - cost_per_byte_ms = phase_times()->average_last_obj_copy_time() / (double) copied_bytes; + cost_per_byte_ms = phase_times()->average_time_ms(G1GCPhaseTimes::ObjCopy) / (double) copied_bytes; if (_in_marking_window) { _cost_per_byte_ms_during_cm_seq->add(cost_per_byte_ms); } else { @@ -1143,8 +1143,8 @@ } double all_other_time_ms = pause_time_ms - - (phase_times()->average_last_update_rs_time() + phase_times()->average_last_scan_rs_time() - + phase_times()->average_last_obj_copy_time() + phase_times()->average_last_termination_time()); + (phase_times()->average_time_ms(G1GCPhaseTimes::UpdateRS) + phase_times()->average_time_ms(G1GCPhaseTimes::ScanRS) + + phase_times()->average_time_ms(G1GCPhaseTimes::ObjCopy) + phase_times()->average_time_ms(G1GCPhaseTimes::Termination)); double young_other_time_ms = 0.0; if (young_cset_region_length() > 0) { @@ -1185,8 +1185,8 @@ // Note that _mmu_tracker->max_gc_time() returns the time in seconds. double update_rs_time_goal_ms = _mmu_tracker->max_gc_time() * MILLIUNITS * G1RSetUpdatingPauseTimePercent / 100.0; - adjust_concurrent_refinement(phase_times()->average_last_update_rs_time(), - phase_times()->sum_last_update_rs_processed_buffers(), update_rs_time_goal_ms); + adjust_concurrent_refinement(phase_times()->average_time_ms(G1GCPhaseTimes::UpdateRS), + phase_times()->sum_thread_work_items(G1GCPhaseTimes::UpdateRS), update_rs_time_goal_ms); _collectionSetChooser->verify(); } @@ -1437,18 +1437,6 @@ return young_list_length < young_list_max_length; } -uint G1CollectorPolicy::max_regions(int purpose) { - switch (purpose) { - case GCAllocForSurvived: - return _max_survivor_regions; - case GCAllocForTenured: - return REGIONS_UNLIMITED; - default: - ShouldNotReachHere(); - return REGIONS_UNLIMITED; - }; -} - void G1CollectorPolicy::update_max_gc_locker_expansion() { uint expansion_region_num = 0; if (GCLockerEdenExpansionPercent > 0) { @@ -1683,7 +1671,7 @@ hr->set_next_in_collection_set(_collection_set); _collection_set = hr; _collection_set_bytes_used_before += hr->used(); - _g1->register_region_with_in_cset_fast_test(hr); + _g1->register_old_region_with_in_cset_fast_test(hr); size_t rs_length = hr->rem_set()->occupied(); _recorded_rs_lengths += rs_length; _old_cset_region_length += 1; @@ -1816,7 +1804,7 @@ hr->set_in_collection_set(true); assert( hr->next_in_collection_set() == NULL, "invariant"); - _g1->register_region_with_in_cset_fast_test(hr); + _g1->register_young_region_with_in_cset_fast_test(hr); } // Add the region at the RHS of the incremental cset @@ -2189,19 +2177,19 @@ _other.add(pause_time_ms - phase_times->accounted_time_ms()); _root_region_scan_wait.add(phase_times->root_region_scan_wait_time_ms()); _parallel.add(phase_times->cur_collection_par_time_ms()); - _ext_root_scan.add(phase_times->average_last_ext_root_scan_time()); - _satb_filtering.add(phase_times->average_last_satb_filtering_times_ms()); - _update_rs.add(phase_times->average_last_update_rs_time()); - _scan_rs.add(phase_times->average_last_scan_rs_time()); - _obj_copy.add(phase_times->average_last_obj_copy_time()); - _termination.add(phase_times->average_last_termination_time()); + _ext_root_scan.add(phase_times->average_time_ms(G1GCPhaseTimes::ExtRootScan)); + _satb_filtering.add(phase_times->average_time_ms(G1GCPhaseTimes::SATBFiltering)); + _update_rs.add(phase_times->average_time_ms(G1GCPhaseTimes::UpdateRS)); + _scan_rs.add(phase_times->average_time_ms(G1GCPhaseTimes::ScanRS)); + _obj_copy.add(phase_times->average_time_ms(G1GCPhaseTimes::ObjCopy)); + _termination.add(phase_times->average_time_ms(G1GCPhaseTimes::Termination)); - double parallel_known_time = phase_times->average_last_ext_root_scan_time() + - phase_times->average_last_satb_filtering_times_ms() + - phase_times->average_last_update_rs_time() + - phase_times->average_last_scan_rs_time() + - phase_times->average_last_obj_copy_time() + - + phase_times->average_last_termination_time(); + double parallel_known_time = phase_times->average_time_ms(G1GCPhaseTimes::ExtRootScan) + + phase_times->average_time_ms(G1GCPhaseTimes::SATBFiltering) + + phase_times->average_time_ms(G1GCPhaseTimes::UpdateRS) + + phase_times->average_time_ms(G1GCPhaseTimes::ScanRS) + + phase_times->average_time_ms(G1GCPhaseTimes::ObjCopy) + + phase_times->average_time_ms(G1GCPhaseTimes::Termination); double parallel_other_time = phase_times->cur_collection_par_time_ms() - parallel_known_time; _parallel_other.add(parallel_other_time); diff -r c2687aa5e5ca -r 7eb99acd567f src/share/vm/gc_implementation/g1/g1CollectorPolicy.hpp --- a/src/share/vm/gc_implementation/g1/g1CollectorPolicy.hpp Mon Jan 25 14:56:57 2016 -0800 +++ b/src/share/vm/gc_implementation/g1/g1CollectorPolicy.hpp Mon Jan 25 14:57:27 2016 -0800 @@ -877,28 +877,20 @@ public: uint tenuring_threshold() const { return _tenuring_threshold; } - inline GCAllocPurpose - evacuation_destination(HeapRegion* src_region, uint age, size_t word_sz) { - if (age < _tenuring_threshold && src_region->is_young()) { - return GCAllocForSurvived; - } else { - return GCAllocForTenured; - } - } - - inline bool track_object_age(GCAllocPurpose purpose) { - return purpose == GCAllocForSurvived; - } - static const uint REGIONS_UNLIMITED = (uint) -1; - uint max_regions(int purpose); - - // The limit on regions for a particular purpose is reached. - void note_alloc_region_limit_reached(int purpose) { - if (purpose == GCAllocForSurvived) { - _tenuring_threshold = 0; + uint max_regions(InCSetState dest) { + switch (dest.value()) { + case InCSetState::Young: + return _max_survivor_regions; + case InCSetState::Old: + return REGIONS_UNLIMITED; + default: + assert(false, err_msg("Unknown dest state: " CSETSTATE_FORMAT, dest.value())); + break; } + // keep some compilers happy + return 0; } void note_start_adding_survivor_regions() { diff -r c2687aa5e5ca -r 7eb99acd567f src/share/vm/gc_implementation/g1/g1GCPhaseTimes.cpp --- a/src/share/vm/gc_implementation/g1/g1GCPhaseTimes.cpp Mon Jan 25 14:56:57 2016 -0800 +++ b/src/share/vm/gc_implementation/g1/g1GCPhaseTimes.cpp Mon Jan 25 14:57:27 2016 -0800 @@ -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 @@ -22,12 +22,13 @@ * */ - #include "precompiled.hpp" #include "gc_implementation/g1/g1CollectedHeap.inline.hpp" #include "gc_implementation/g1/g1GCPhaseTimes.hpp" #include "gc_implementation/g1/g1Log.hpp" #include "gc_implementation/g1/g1StringDedup.hpp" +#include "memory/allocation.hpp" +#include "runtime/os.hpp" // Helper class for avoiding interleaved logging class LineBuffer: public StackObj { @@ -70,184 +71,258 @@ va_end(ap); } + void print_cr() { + gclog_or_tty->print_cr("%s", _buffer); + _cur = _indent_level * INDENT_CHARS; + } + void append_and_print_cr(const char* format, ...) ATTRIBUTE_PRINTF(2, 3) { va_list ap; va_start(ap, format); vappend(format, ap); va_end(ap); - gclog_or_tty->print_cr("%s", _buffer); - _cur = _indent_level * INDENT_CHARS; + print_cr(); } }; -PRAGMA_DIAG_PUSH -PRAGMA_FORMAT_NONLITERAL_IGNORED template -void WorkerDataArray::print(int level, const char* title) { - if (_length == 1) { - // No need for min, max, average and sum for only one worker - LineBuffer buf(level); - buf.append("[%s: ", title); - buf.append(_print_format, _data[0]); - buf.append_and_print_cr("]"); - return; +class WorkerDataArray : public CHeapObj { + friend class G1GCParPhasePrinter; + T* _data; + uint _length; + const char* _title; + bool _print_sum; + int _log_level; + uint _indent_level; + bool _enabled; + + WorkerDataArray* _thread_work_items; + + NOT_PRODUCT(T uninitialized();) + + // We are caching the sum and average to only have to calculate them once. + // This is not done in an MT-safe way. It is intended to allow single + // threaded code to call sum() and average() multiple times in any order + // without having to worry about the cost. + bool _has_new_data; + T _sum; + T _min; + T _max; + double _average; + + public: + WorkerDataArray(uint length, const char* title, bool print_sum, int log_level, uint indent_level) : + _title(title), _length(0), _print_sum(print_sum), _log_level(log_level), _indent_level(indent_level), + _has_new_data(true), _thread_work_items(NULL), _enabled(true) { + assert(length > 0, "Must have some workers to store data for"); + _length = length; + _data = NEW_C_HEAP_ARRAY(T, _length, mtGC); + } + + ~WorkerDataArray() { + FREE_C_HEAP_ARRAY(T, _data, mtGC); + } + + void link_thread_work_items(WorkerDataArray* thread_work_items) { + _thread_work_items = thread_work_items; + } + + WorkerDataArray* thread_work_items() { return _thread_work_items; } + + void set(uint worker_i, T value) { + assert(worker_i < _length, err_msg("Worker %d is greater than max: %d", worker_i, _length)); + assert(_data[worker_i] == WorkerDataArray::uninitialized(), err_msg("Overwriting data for worker %d in %s", worker_i, _title)); + _data[worker_i] = value; + _has_new_data = true; + } + + void set_thread_work_item(uint worker_i, size_t value) { + assert(_thread_work_items != NULL, "No sub count"); + _thread_work_items->set(worker_i, value); } - T min = _data[0]; - T max = _data[0]; - T sum = 0; + T get(uint worker_i) { + assert(worker_i < _length, err_msg("Worker %d is greater than max: %d", worker_i, _length)); + assert(_data[worker_i] != WorkerDataArray::uninitialized(), err_msg("No data added for worker %d", worker_i)); + return _data[worker_i]; + } + + void add(uint worker_i, T value) { + assert(worker_i < _length, err_msg("Worker %d is greater than max: %d", worker_i, _length)); + assert(_data[worker_i] != WorkerDataArray::uninitialized(), err_msg("No data to add to for worker %d", worker_i)); + _data[worker_i] += value; + _has_new_data = true; + } - LineBuffer buf(level); - buf.append("[%s:", title); - for (uint i = 0; i < _length; ++i) { - T val = _data[i]; - min = MIN2(val, min); - max = MAX2(val, max); - sum += val; - if (G1Log::finest()) { - buf.append(" "); - buf.append(_print_format, val); - } + double average(){ + calculate_totals(); + return _average; + } + + T sum() { + calculate_totals(); + return _sum; + } + + T minimum() { + calculate_totals(); + return _min; } - if (G1Log::finest()) { - buf.append_and_print_cr("%s", ""); + T maximum() { + calculate_totals(); + return _max; } - double avg = (double)sum / (double)_length; - buf.append(" Min: "); - buf.append(_print_format, min); - buf.append(", Avg: "); - buf.append("%.1lf", avg); // Always print average as a double - buf.append(", Max: "); - buf.append(_print_format, max); - buf.append(", Diff: "); - buf.append(_print_format, max - min); - if (_print_sum) { - // for things like the start and end times the sum is not - // that relevant - buf.append(", Sum: "); - buf.append(_print_format, sum); + void reset() PRODUCT_RETURN; + void verify() PRODUCT_RETURN; + + void set_enabled(bool enabled) { _enabled = enabled; } + + int log_level() { return _log_level; } + + private: + + void calculate_totals(){ + if (!_has_new_data) { + return; + } + + _sum = (T)0; + _min = _data[0]; + _max = _min; + for (uint i = 0; i < _length; ++i) { + T val = _data[i]; + _sum += val; + _min = MIN2(_min, val); + _max = MAX2(_max, val); + } + _average = (double)_sum / (double)_length; + _has_new_data = false; } - buf.append_and_print_cr("]"); -} -PRAGMA_DIAG_POP +}; + #ifndef PRODUCT -template <> const int WorkerDataArray::_uninitialized = -1; -template <> const double WorkerDataArray::_uninitialized = -1.0; -template <> const size_t WorkerDataArray::_uninitialized = (size_t)-1; +template <> +size_t WorkerDataArray::uninitialized() { + return (size_t)-1; +} + +template <> +double WorkerDataArray::uninitialized() { + return -1.0; +} template void WorkerDataArray::reset() { for (uint i = 0; i < _length; i++) { - _data[i] = (T)_uninitialized; + _data[i] = WorkerDataArray::uninitialized(); + } + if (_thread_work_items != NULL) { + _thread_work_items->reset(); } } template void WorkerDataArray::verify() { + if (!_enabled) { + return; + } + for (uint i = 0; i < _length; i++) { - assert(_data[i] != _uninitialized, - err_msg("Invalid data for worker " UINT32_FORMAT ", data: %lf, uninitialized: %lf", - i, (double)_data[i], (double)_uninitialized)); + assert(_data[i] != WorkerDataArray::uninitialized(), + err_msg("Invalid data for worker %u in '%s'", i, _title)); + } + if (_thread_work_items != NULL) { + _thread_work_items->verify(); } } #endif G1GCPhaseTimes::G1GCPhaseTimes(uint max_gc_threads) : - _max_gc_threads(max_gc_threads), - _last_gc_worker_start_times_ms(_max_gc_threads, "%.1lf", false), - _last_ext_root_scan_times_ms(_max_gc_threads, "%.1lf"), - _last_satb_filtering_times_ms(_max_gc_threads, "%.1lf"), - _last_update_rs_times_ms(_max_gc_threads, "%.1lf"), - _last_update_rs_processed_buffers(_max_gc_threads, "%d"), - _last_scan_rs_times_ms(_max_gc_threads, "%.1lf"), - _last_strong_code_root_scan_times_ms(_max_gc_threads, "%.1lf"), - _last_obj_copy_times_ms(_max_gc_threads, "%.1lf"), - _last_termination_times_ms(_max_gc_threads, "%.1lf"), - _last_termination_attempts(_max_gc_threads, SIZE_FORMAT), - _last_gc_worker_end_times_ms(_max_gc_threads, "%.1lf", false), - _last_gc_worker_times_ms(_max_gc_threads, "%.1lf"), - _last_gc_worker_other_times_ms(_max_gc_threads, "%.1lf"), - _last_redirty_logged_cards_time_ms(_max_gc_threads, "%.1lf"), - _last_redirty_logged_cards_processed_cards(_max_gc_threads, SIZE_FORMAT), - _cur_string_dedup_queue_fixup_worker_times_ms(_max_gc_threads, "%.1lf"), - _cur_string_dedup_table_fixup_worker_times_ms(_max_gc_threads, "%.1lf") + _max_gc_threads(max_gc_threads) { assert(max_gc_threads > 0, "Must have some GC threads"); + + _gc_par_phases[GCWorkerStart] = new WorkerDataArray(max_gc_threads, "GC Worker Start (ms)", false, G1Log::LevelFiner, 2); + _gc_par_phases[ExtRootScan] = new WorkerDataArray(max_gc_threads, "Ext Root Scanning (ms)", true, G1Log::LevelFiner, 2); + + // Root scanning phases + _gc_par_phases[ThreadRoots] = new WorkerDataArray(max_gc_threads, "Thread Roots (ms)", true, G1Log::LevelFinest, 3); + _gc_par_phases[StringTableRoots] = new WorkerDataArray(max_gc_threads, "StringTable Roots (ms)", true, G1Log::LevelFinest, 3); + _gc_par_phases[UniverseRoots] = new WorkerDataArray(max_gc_threads, "Universe Roots (ms)", true, G1Log::LevelFinest, 3); + _gc_par_phases[JNIRoots] = new WorkerDataArray(max_gc_threads, "JNI Handles Roots (ms)", true, G1Log::LevelFinest, 3); + _gc_par_phases[ObjectSynchronizerRoots] = new WorkerDataArray(max_gc_threads, "ObjectSynchronizer Roots (ms)", true, G1Log::LevelFinest, 3); + _gc_par_phases[FlatProfilerRoots] = new WorkerDataArray(max_gc_threads, "FlatProfiler Roots (ms)", true, G1Log::LevelFinest, 3); + _gc_par_phases[ManagementRoots] = new WorkerDataArray(max_gc_threads, "Management Roots (ms)", true, G1Log::LevelFinest, 3); + _gc_par_phases[SystemDictionaryRoots] = new WorkerDataArray(max_gc_threads, "SystemDictionary Roots (ms)", true, G1Log::LevelFinest, 3); + _gc_par_phases[CLDGRoots] = new WorkerDataArray(max_gc_threads, "CLDG Roots (ms)", true, G1Log::LevelFinest, 3); + _gc_par_phases[JVMTIRoots] = new WorkerDataArray(max_gc_threads, "JVMTI Roots (ms)", true, G1Log::LevelFinest, 3); + _gc_par_phases[CodeCacheRoots] = new WorkerDataArray(max_gc_threads, "CodeCache Roots (ms)", true, G1Log::LevelFinest, 3); + _gc_par_phases[CMRefRoots] = new WorkerDataArray(max_gc_threads, "CM RefProcessor Roots (ms)", true, G1Log::LevelFinest, 3); + _gc_par_phases[WaitForStrongCLD] = new WorkerDataArray(max_gc_threads, "Wait For Strong CLD (ms)", true, G1Log::LevelFinest, 3); + _gc_par_phases[WeakCLDRoots] = new WorkerDataArray(max_gc_threads, "Weak CLD Roots (ms)", true, G1Log::LevelFinest, 3); + _gc_par_phases[SATBFiltering] = new WorkerDataArray(max_gc_threads, "SATB Filtering (ms)", true, G1Log::LevelFinest, 3); + + _gc_par_phases[UpdateRS] = new WorkerDataArray(max_gc_threads, "Update RS (ms)", true, G1Log::LevelFiner, 2); + _gc_par_phases[ScanRS] = new WorkerDataArray(max_gc_threads, "Scan RS (ms)", true, G1Log::LevelFiner, 2); + _gc_par_phases[CodeRoots] = new WorkerDataArray(max_gc_threads, "Code Root Scanning (ms)", true, G1Log::LevelFiner, 2); + _gc_par_phases[ObjCopy] = new WorkerDataArray(max_gc_threads, "Object Copy (ms)", true, G1Log::LevelFiner, 2); + _gc_par_phases[Termination] = new WorkerDataArray(max_gc_threads, "Termination (ms)", true, G1Log::LevelFiner, 2); + _gc_par_phases[GCWorkerTotal] = new WorkerDataArray(max_gc_threads, "GC Worker Total (ms)", true, G1Log::LevelFiner, 2); + _gc_par_phases[GCWorkerEnd] = new WorkerDataArray(max_gc_threads, "GC Worker End (ms)", false, G1Log::LevelFiner, 2); + _gc_par_phases[Other] = new WorkerDataArray(max_gc_threads, "GC Worker Other (ms)", true, G1Log::LevelFiner, 2); + + _update_rs_processed_buffers = new WorkerDataArray(max_gc_threads, "Processed Buffers", true, G1Log::LevelFiner, 3); + _gc_par_phases[UpdateRS]->link_thread_work_items(_update_rs_processed_buffers); + + _termination_attempts = new WorkerDataArray(max_gc_threads, "Termination Attempts", true, G1Log::LevelFinest, 3); + _gc_par_phases[Termination]->link_thread_work_items(_termination_attempts); + + _gc_par_phases[StringDedupQueueFixup] = new WorkerDataArray(max_gc_threads, "Queue Fixup (ms)", true, G1Log::LevelFiner, 2); + _gc_par_phases[StringDedupTableFixup] = new WorkerDataArray(max_gc_threads, "Table Fixup (ms)", true, G1Log::LevelFiner, 2); + + _gc_par_phases[RedirtyCards] = new WorkerDataArray(max_gc_threads, "Parallel Redirty", true, G1Log::LevelFinest, 3); + _redirtied_cards = new WorkerDataArray(max_gc_threads, "Redirtied Cards", true, G1Log::LevelFinest, 3); + _gc_par_phases[RedirtyCards]->link_thread_work_items(_redirtied_cards); } -void G1GCPhaseTimes::note_gc_start(uint active_gc_threads) { +void G1GCPhaseTimes::note_gc_start(uint active_gc_threads, bool mark_in_progress) { assert(active_gc_threads > 0, "The number of threads must be > 0"); - assert(active_gc_threads <= _max_gc_threads, "The number of active threads must be <= the max nubmer of threads"); + assert(active_gc_threads <= _max_gc_threads, "The number of active threads must be <= the max number of threads"); _active_gc_threads = active_gc_threads; - _last_gc_worker_start_times_ms.reset(); - _last_ext_root_scan_times_ms.reset(); - _last_satb_filtering_times_ms.reset(); - _last_update_rs_times_ms.reset(); - _last_update_rs_processed_buffers.reset(); - _last_scan_rs_times_ms.reset(); - _last_strong_code_root_scan_times_ms.reset(); - _last_obj_copy_times_ms.reset(); - _last_termination_times_ms.reset(); - _last_termination_attempts.reset(); - _last_gc_worker_end_times_ms.reset(); - _last_gc_worker_times_ms.reset(); - _last_gc_worker_other_times_ms.reset(); + for (int i = 0; i < GCParPhasesSentinel; i++) { + _gc_par_phases[i]->reset(); + } - _last_redirty_logged_cards_time_ms.reset(); - _last_redirty_logged_cards_processed_cards.reset(); - + _gc_par_phases[StringDedupQueueFixup]->set_enabled(G1StringDedup::is_enabled()); + _gc_par_phases[StringDedupTableFixup]->set_enabled(G1StringDedup::is_enabled()); } void G1GCPhaseTimes::note_gc_end() { - _last_gc_worker_start_times_ms.verify(); - _last_ext_root_scan_times_ms.verify(); - _last_satb_filtering_times_ms.verify(); - _last_update_rs_times_ms.verify(); - _last_update_rs_processed_buffers.verify(); - _last_scan_rs_times_ms.verify(); - _last_strong_code_root_scan_times_ms.verify(); - _last_obj_copy_times_ms.verify(); - _last_termination_times_ms.verify(); - _last_termination_attempts.verify(); - _last_gc_worker_end_times_ms.verify(); + for (uint i = 0; i < _active_gc_threads; i++) { + double worker_time = _gc_par_phases[GCWorkerEnd]->get(i) - _gc_par_phases[GCWorkerStart]->get(i); + record_time_secs(GCWorkerTotal, i , worker_time); - for (uint i = 0; i < _active_gc_threads; i++) { - double worker_time = _last_gc_worker_end_times_ms.get(i) - _last_gc_worker_start_times_ms.get(i); - _last_gc_worker_times_ms.set(i, worker_time); + double worker_known_time = + _gc_par_phases[ExtRootScan]->get(i) + + _gc_par_phases[SATBFiltering]->get(i) + + _gc_par_phases[UpdateRS]->get(i) + + _gc_par_phases[ScanRS]->get(i) + + _gc_par_phases[CodeRoots]->get(i) + + _gc_par_phases[ObjCopy]->get(i) + + _gc_par_phases[Termination]->get(i); - double worker_known_time = _last_ext_root_scan_times_ms.get(i) + - _last_satb_filtering_times_ms.get(i) + - _last_update_rs_times_ms.get(i) + - _last_scan_rs_times_ms.get(i) + - _last_strong_code_root_scan_times_ms.get(i) + - _last_obj_copy_times_ms.get(i) + - _last_termination_times_ms.get(i); - - double worker_other_time = worker_time - worker_known_time; - _last_gc_worker_other_times_ms.set(i, worker_other_time); + record_time_secs(Other, i, worker_time - worker_known_time); } - _last_gc_worker_times_ms.verify(); - _last_gc_worker_other_times_ms.verify(); - - _last_redirty_logged_cards_time_ms.verify(); - _last_redirty_logged_cards_processed_cards.verify(); -} - -void G1GCPhaseTimes::note_string_dedup_fixup_start() { - _cur_string_dedup_queue_fixup_worker_times_ms.reset(); - _cur_string_dedup_table_fixup_worker_times_ms.reset(); -} - -void G1GCPhaseTimes::note_string_dedup_fixup_end() { - _cur_string_dedup_queue_fixup_worker_times_ms.verify(); - _cur_string_dedup_table_fixup_worker_times_ms.verify(); + for (int i = 0; i < GCParPhasesSentinel; i++) { + _gc_par_phases[i]->verify(); + } } void G1GCPhaseTimes::print_stats(int level, const char* str, double value) { @@ -259,7 +334,7 @@ } void G1GCPhaseTimes::print_stats(int level, const char* str, double value, uint workers) { - LineBuffer(level).append_and_print_cr("[%s: %.1lf ms, GC Workers: " UINT32_FORMAT "]", str, value, workers); + LineBuffer(level).append_and_print_cr("[%s: %.1lf ms, GC Workers: %u]", str, value, workers); } double G1GCPhaseTimes::accounted_time_ms() { @@ -287,46 +362,172 @@ return misc_time_ms; } +// record the time a phase took in seconds +void G1GCPhaseTimes::record_time_secs(GCParPhases phase, uint worker_i, double secs) { + _gc_par_phases[phase]->set(worker_i, secs); +} + +// add a number of seconds to a phase +void G1GCPhaseTimes::add_time_secs(GCParPhases phase, uint worker_i, double secs) { + _gc_par_phases[phase]->add(worker_i, secs); +} + +void G1GCPhaseTimes::record_thread_work_item(GCParPhases phase, uint worker_i, size_t count) { + _gc_par_phases[phase]->set_thread_work_item(worker_i, count); +} + +// return the average time for a phase in milliseconds +double G1GCPhaseTimes::average_time_ms(GCParPhases phase) { + return _gc_par_phases[phase]->average() * 1000.0; +} + +double G1GCPhaseTimes::get_time_ms(GCParPhases phase, uint worker_i) { + return _gc_par_phases[phase]->get(worker_i) * 1000.0; +} + +double G1GCPhaseTimes::sum_time_ms(GCParPhases phase) { + return _gc_par_phases[phase]->sum() * 1000.0; +} + +double G1GCPhaseTimes::min_time_ms(GCParPhases phase) { + return _gc_par_phases[phase]->minimum() * 1000.0; +} + +double G1GCPhaseTimes::max_time_ms(GCParPhases phase) { + return _gc_par_phases[phase]->maximum() * 1000.0; +} + +size_t G1GCPhaseTimes::get_thread_work_item(GCParPhases phase, uint worker_i) { + assert(_gc_par_phases[phase]->thread_work_items() != NULL, "No sub count"); + return _gc_par_phases[phase]->thread_work_items()->get(worker_i); +} + +size_t G1GCPhaseTimes::sum_thread_work_items(GCParPhases phase) { + assert(_gc_par_phases[phase]->thread_work_items() != NULL, "No sub count"); + return _gc_par_phases[phase]->thread_work_items()->sum(); +} + +double G1GCPhaseTimes::average_thread_work_items(GCParPhases phase) { + assert(_gc_par_phases[phase]->thread_work_items() != NULL, "No sub count"); + return _gc_par_phases[phase]->thread_work_items()->average(); +} + +size_t G1GCPhaseTimes::min_thread_work_items(GCParPhases phase) { + assert(_gc_par_phases[phase]->thread_work_items() != NULL, "No sub count"); + return _gc_par_phases[phase]->thread_work_items()->minimum(); +} + +size_t G1GCPhaseTimes::max_thread_work_items(GCParPhases phase) { + assert(_gc_par_phases[phase]->thread_work_items() != NULL, "No sub count"); + return _gc_par_phases[phase]->thread_work_items()->maximum(); +} + +class G1GCParPhasePrinter : public StackObj { + G1GCPhaseTimes* _phase_times; + public: + G1GCParPhasePrinter(G1GCPhaseTimes* phase_times) : _phase_times(phase_times) {} + + void print(G1GCPhaseTimes::GCParPhases phase_id) { + WorkerDataArray* phase = _phase_times->_gc_par_phases[phase_id]; + + if (phase->_log_level > G1Log::level() || !phase->_enabled) { + return; + } + + if (phase->_length == 1) { + print_single_length(phase_id, phase); + } else { + print_multi_length(phase_id, phase); + } + } + + private: + + void print_single_length(G1GCPhaseTimes::GCParPhases phase_id, WorkerDataArray* phase) { + // No need for min, max, average and sum for only one worker + LineBuffer buf(phase->_indent_level); + buf.append_and_print_cr("[%s: %.1lf]", phase->_title, _phase_times->get_time_ms(phase_id, 0)); + + if (phase->_thread_work_items != NULL) { + LineBuffer buf2(phase->_thread_work_items->_indent_level); + buf2.append_and_print_cr("[%s: "SIZE_FORMAT"]", phase->_thread_work_items->_title, _phase_times->sum_thread_work_items(phase_id)); + } + } + + void print_time_values(LineBuffer& buf, G1GCPhaseTimes::GCParPhases phase_id, WorkerDataArray* phase) { + for (uint i = 0; i < phase->_length; ++i) { + buf.append(" %.1lf", _phase_times->get_time_ms(phase_id, i)); + } + buf.print_cr(); + } + + void print_count_values(LineBuffer& buf, G1GCPhaseTimes::GCParPhases phase_id, WorkerDataArray* thread_work_items) { + for (uint i = 0; i < thread_work_items->_length; ++i) { + buf.append(" " SIZE_FORMAT, _phase_times->get_thread_work_item(phase_id, i)); + } + buf.print_cr(); + } + + void print_thread_work_items(G1GCPhaseTimes::GCParPhases phase_id, WorkerDataArray* thread_work_items) { + LineBuffer buf(thread_work_items->_indent_level); + buf.append("[%s:", thread_work_items->_title); + + if (G1Log::finest()) { + print_count_values(buf, phase_id, thread_work_items); + } + + assert(thread_work_items->_print_sum, err_msg("%s does not have print sum true even though it is a count", thread_work_items->_title)); + + buf.append_and_print_cr(" Min: " SIZE_FORMAT ", Avg: %.1lf, Max: " SIZE_FORMAT ", Diff: " SIZE_FORMAT ", Sum: " SIZE_FORMAT "]", + _phase_times->min_thread_work_items(phase_id), _phase_times->average_thread_work_items(phase_id), _phase_times->max_thread_work_items(phase_id), + _phase_times->max_thread_work_items(phase_id) - _phase_times->min_thread_work_items(phase_id), _phase_times->sum_thread_work_items(phase_id)); + } + + void print_multi_length(G1GCPhaseTimes::GCParPhases phase_id, WorkerDataArray* phase) { + LineBuffer buf(phase->_indent_level); + buf.append("[%s:", phase->_title); + + if (G1Log::finest()) { + print_time_values(buf, phase_id, phase); + } + + buf.append(" Min: %.1lf, Avg: %.1lf, Max: %.1lf, Diff: %.1lf", + _phase_times->min_time_ms(phase_id), _phase_times->average_time_ms(phase_id), _phase_times->max_time_ms(phase_id), + _phase_times->max_time_ms(phase_id) - _phase_times->min_time_ms(phase_id)); + + if (phase->_print_sum) { + // for things like the start and end times the sum is not + // that relevant + buf.append(", Sum: %.1lf", _phase_times->sum_time_ms(phase_id)); + } + + buf.append_and_print_cr("]"); + + if (phase->_thread_work_items != NULL) { + print_thread_work_items(phase_id, phase->_thread_work_items); + } + } +}; + void G1GCPhaseTimes::print(double pause_time_sec) { + G1GCParPhasePrinter par_phase_printer(this); + if (_root_region_scan_wait_time_ms > 0.0) { print_stats(1, "Root Region Scan Waiting", _root_region_scan_wait_time_ms); } - if (G1CollectedHeap::use_parallel_gc_threads()) { - print_stats(1, "Parallel Time", _cur_collection_par_time_ms, _active_gc_threads); - _last_gc_worker_start_times_ms.print(2, "GC Worker Start (ms)"); - _last_ext_root_scan_times_ms.print(2, "Ext Root Scanning (ms)"); - if (_last_satb_filtering_times_ms.sum() > 0.0) { - _last_satb_filtering_times_ms.print(2, "SATB Filtering (ms)"); - } - _last_update_rs_times_ms.print(2, "Update RS (ms)"); - _last_update_rs_processed_buffers.print(3, "Processed Buffers"); - _last_scan_rs_times_ms.print(2, "Scan RS (ms)"); - _last_strong_code_root_scan_times_ms.print(2, "Code Root Scanning (ms)"); - _last_obj_copy_times_ms.print(2, "Object Copy (ms)"); - _last_termination_times_ms.print(2, "Termination (ms)"); - if (G1Log::finest()) { - _last_termination_attempts.print(3, "Termination Attempts"); - } - _last_gc_worker_other_times_ms.print(2, "GC Worker Other (ms)"); - _last_gc_worker_times_ms.print(2, "GC Worker Total (ms)"); - _last_gc_worker_end_times_ms.print(2, "GC Worker End (ms)"); - } else { - _last_ext_root_scan_times_ms.print(1, "Ext Root Scanning (ms)"); - if (_last_satb_filtering_times_ms.sum() > 0.0) { - _last_satb_filtering_times_ms.print(1, "SATB Filtering (ms)"); - } - _last_update_rs_times_ms.print(1, "Update RS (ms)"); - _last_update_rs_processed_buffers.print(2, "Processed Buffers"); - _last_scan_rs_times_ms.print(1, "Scan RS (ms)"); - _last_strong_code_root_scan_times_ms.print(1, "Code Root Scanning (ms)"); - _last_obj_copy_times_ms.print(1, "Object Copy (ms)"); + + print_stats(1, "Parallel Time", _cur_collection_par_time_ms, _active_gc_threads); + for (int i = 0; i <= GCMainParPhasesLast; i++) { + par_phase_printer.print((GCParPhases) i); } + print_stats(1, "Code Root Fixup", _cur_collection_code_root_fixup_time_ms); print_stats(1, "Code Root Purge", _cur_strong_code_root_purge_time_ms); if (G1StringDedup::is_enabled()) { print_stats(1, "String Dedup Fixup", _cur_string_dedup_fixup_time_ms, _active_gc_threads); - _cur_string_dedup_queue_fixup_worker_times_ms.print(2, "Queue Fixup (ms)"); - _cur_string_dedup_table_fixup_worker_times_ms.print(2, "Table Fixup (ms)"); + for (int i = StringDedupPhasesFirst; i <= StringDedupPhasesLast; i++) { + par_phase_printer.print((GCParPhases) i); + } } print_stats(1, "Clear CT", _cur_clear_ct_time_ms); double misc_time_ms = pause_time_sec * MILLIUNITS - accounted_time_ms(); @@ -350,15 +551,16 @@ print_stats(2, "Ref Proc", _cur_ref_proc_time_ms); print_stats(2, "Ref Enq", _cur_ref_enq_time_ms); print_stats(2, "Redirty Cards", _recorded_redirty_logged_cards_time_ms); - if (G1Log::finest()) { - _last_redirty_logged_cards_time_ms.print(3, "Parallel Redirty"); - _last_redirty_logged_cards_processed_cards.print(3, "Redirtied Cards"); - } - if (G1ReclaimDeadHumongousObjectsAtYoungGC) { - print_stats(2, "Humongous Reclaim", _cur_fast_reclaim_humongous_time_ms); + par_phase_printer.print(RedirtyCards); + + if (G1EagerReclaimHumongousObjects) { + print_stats(2, "Humongous Register", _cur_fast_reclaim_humongous_register_time_ms); if (G1Log::finest()) { print_stats(3, "Humongous Total", _cur_fast_reclaim_humongous_total); print_stats(3, "Humongous Candidate", _cur_fast_reclaim_humongous_candidates); + } + print_stats(2, "Humongous Reclaim", _cur_fast_reclaim_humongous_time_ms); + if (G1Log::finest()) { print_stats(3, "Humongous Reclaimed", _cur_fast_reclaim_humongous_reclaimed); } } @@ -373,3 +575,17 @@ print_stats(2, "Verify After", _cur_verify_after_time_ms); } } + +G1GCParPhaseTimesTracker::G1GCParPhaseTimesTracker(G1GCPhaseTimes* phase_times, G1GCPhaseTimes::GCParPhases phase, uint worker_id) : + _phase_times(phase_times), _phase(phase), _worker_id(worker_id) { + if (_phase_times != NULL) { + _start_time = os::elapsedTime(); + } +} + +G1GCParPhaseTimesTracker::~G1GCParPhaseTimesTracker() { + if (_phase_times != NULL) { + _phase_times->record_time_secs(_phase, _worker_id, os::elapsedTime() - _start_time); + } +} + diff -r c2687aa5e5ca -r 7eb99acd567f src/share/vm/gc_implementation/g1/g1GCPhaseTimes.hpp --- a/src/share/vm/gc_implementation/g1/g1GCPhaseTimes.hpp Mon Jan 25 14:56:57 2016 -0800 +++ b/src/share/vm/gc_implementation/g1/g1GCPhaseTimes.hpp Mon Jan 25 14:57:27 2016 -0800 @@ -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 @@ -26,106 +26,60 @@ #define SHARE_VM_GC_IMPLEMENTATION_G1_G1GCPHASETIMESLOG_HPP #include "memory/allocation.hpp" -#include "gc_interface/gcCause.hpp" - -template -class WorkerDataArray : public CHeapObj { - T* _data; - uint _length; - const char* _print_format; - bool _print_sum; - - NOT_PRODUCT(static const T _uninitialized;) - - // We are caching the sum and average to only have to calculate them once. - // This is not done in an MT-safe way. It is intended to allow single - // threaded code to call sum() and average() multiple times in any order - // without having to worry about the cost. - bool _has_new_data; - T _sum; - double _average; - - public: - WorkerDataArray(uint length, const char* print_format, bool print_sum = true) : - _length(length), _print_format(print_format), _print_sum(print_sum), _has_new_data(true) { - assert(length > 0, "Must have some workers to store data for"); - _data = NEW_C_HEAP_ARRAY(T, _length, mtGC); - } - - ~WorkerDataArray() { - FREE_C_HEAP_ARRAY(T, _data, mtGC); - } - - void set(uint worker_i, T value) { - assert(worker_i < _length, err_msg("Worker %d is greater than max: %d", worker_i, _length)); - assert(_data[worker_i] == (T)-1, err_msg("Overwriting data for worker %d", worker_i)); - _data[worker_i] = value; - _has_new_data = true; - } - T get(uint worker_i) { - assert(worker_i < _length, err_msg("Worker %d is greater than max: %d", worker_i, _length)); - assert(_data[worker_i] != (T)-1, err_msg("No data to add to for worker %d", worker_i)); - return _data[worker_i]; - } - - void add(uint worker_i, T value) { - assert(worker_i < _length, err_msg("Worker %d is greater than max: %d", worker_i, _length)); - assert(_data[worker_i] != (T)-1, err_msg("No data to add to for worker %d", worker_i)); - _data[worker_i] += value; - _has_new_data = true; - } - - double average(){ - if (_has_new_data) { - calculate_totals(); - } - return _average; - } +class LineBuffer; - T sum() { - if (_has_new_data) { - calculate_totals(); - } - return _sum; - } - - void print(int level, const char* title); - - void reset() PRODUCT_RETURN; - void verify() PRODUCT_RETURN; - - private: - - void calculate_totals(){ - _sum = (T)0; - for (uint i = 0; i < _length; ++i) { - _sum += _data[i]; - } - _average = (double)_sum / (double)_length; - _has_new_data = false; - } -}; +template class WorkerDataArray; class G1GCPhaseTimes : public CHeapObj { + friend class G1GCParPhasePrinter; - private: uint _active_gc_threads; uint _max_gc_threads; - WorkerDataArray _last_gc_worker_start_times_ms; - WorkerDataArray _last_ext_root_scan_times_ms; - WorkerDataArray _last_satb_filtering_times_ms; - WorkerDataArray _last_update_rs_times_ms; - WorkerDataArray _last_update_rs_processed_buffers; - WorkerDataArray _last_scan_rs_times_ms; - WorkerDataArray _last_strong_code_root_scan_times_ms; - WorkerDataArray _last_obj_copy_times_ms; - WorkerDataArray _last_termination_times_ms; - WorkerDataArray _last_termination_attempts; - WorkerDataArray _last_gc_worker_end_times_ms; - WorkerDataArray _last_gc_worker_times_ms; - WorkerDataArray _last_gc_worker_other_times_ms; + public: + enum GCParPhases { + GCWorkerStart, + ExtRootScan, + ThreadRoots, + StringTableRoots, + UniverseRoots, + JNIRoots, + ObjectSynchronizerRoots, + FlatProfilerRoots, + ManagementRoots, + SystemDictionaryRoots, + CLDGRoots, + JVMTIRoots, + CodeCacheRoots, + CMRefRoots, + WaitForStrongCLD, + WeakCLDRoots, + SATBFiltering, + UpdateRS, + ScanRS, + CodeRoots, + ObjCopy, + Termination, + Other, + GCWorkerTotal, + GCWorkerEnd, + StringDedupQueueFixup, + StringDedupTableFixup, + RedirtyCards, + GCParPhasesSentinel + }; + + private: + // Markers for grouping the phases in the GCPhases enum above + static const int GCMainParPhasesLast = GCWorkerEnd; + static const int StringDedupPhasesFirst = StringDedupQueueFixup; + static const int StringDedupPhasesLast = StringDedupTableFixup; + + WorkerDataArray* _gc_par_phases[GCParPhasesSentinel]; + WorkerDataArray* _update_rs_processed_buffers; + WorkerDataArray* _termination_attempts; + WorkerDataArray* _redirtied_cards; double _cur_collection_par_time_ms; double _cur_collection_code_root_fixup_time_ms; @@ -135,9 +89,7 @@ double _cur_evac_fail_restore_remsets; double _cur_evac_fail_remove_self_forwards; - double _cur_string_dedup_fixup_time_ms; - WorkerDataArray _cur_string_dedup_queue_fixup_worker_times_ms; - WorkerDataArray _cur_string_dedup_table_fixup_worker_times_ms; + double _cur_string_dedup_fixup_time_ms; double _cur_clear_ct_time_ms; double _cur_ref_proc_time_ms; @@ -149,14 +101,13 @@ double _recorded_young_cset_choice_time_ms; double _recorded_non_young_cset_choice_time_ms; - WorkerDataArray _last_redirty_logged_cards_time_ms; - WorkerDataArray _last_redirty_logged_cards_processed_cards; double _recorded_redirty_logged_cards_time_ms; double _recorded_young_free_cset_time_ms; double _recorded_non_young_free_cset_time_ms; double _cur_fast_reclaim_humongous_time_ms; + double _cur_fast_reclaim_humongous_register_time_ms; size_t _cur_fast_reclaim_humongous_total; size_t _cur_fast_reclaim_humongous_candidates; size_t _cur_fast_reclaim_humongous_reclaimed; @@ -171,54 +122,34 @@ public: G1GCPhaseTimes(uint max_gc_threads); - void note_gc_start(uint active_gc_threads); + void note_gc_start(uint active_gc_threads, bool mark_in_progress); void note_gc_end(); void print(double pause_time_sec); - void record_gc_worker_start_time(uint worker_i, double ms) { - _last_gc_worker_start_times_ms.set(worker_i, ms); - } - - void record_ext_root_scan_time(uint worker_i, double ms) { - _last_ext_root_scan_times_ms.set(worker_i, ms); - } + // record the time a phase took in seconds + void record_time_secs(GCParPhases phase, uint worker_i, double secs); - void record_satb_filtering_time(uint worker_i, double ms) { - _last_satb_filtering_times_ms.set(worker_i, ms); - } + // add a number of seconds to a phase + void add_time_secs(GCParPhases phase, uint worker_i, double secs); - void record_update_rs_time(uint worker_i, double ms) { - _last_update_rs_times_ms.set(worker_i, ms); - } + void record_thread_work_item(GCParPhases phase, uint worker_i, size_t count); - void record_update_rs_processed_buffers(uint worker_i, int processed_buffers) { - _last_update_rs_processed_buffers.set(worker_i, processed_buffers); - } + // return the average time for a phase in milliseconds + double average_time_ms(GCParPhases phase); - void record_scan_rs_time(uint worker_i, double ms) { - _last_scan_rs_times_ms.set(worker_i, ms); - } - - void record_strong_code_root_scan_time(uint worker_i, double ms) { - _last_strong_code_root_scan_times_ms.set(worker_i, ms); - } - - void record_obj_copy_time(uint worker_i, double ms) { - _last_obj_copy_times_ms.set(worker_i, ms); - } + size_t sum_thread_work_items(GCParPhases phase); - void add_obj_copy_time(uint worker_i, double ms) { - _last_obj_copy_times_ms.add(worker_i, ms); - } + private: + double get_time_ms(GCParPhases phase, uint worker_i); + double sum_time_ms(GCParPhases phase); + double min_time_ms(GCParPhases phase); + double max_time_ms(GCParPhases phase); + size_t get_thread_work_item(GCParPhases phase, uint worker_i); + double average_thread_work_items(GCParPhases phase); + size_t min_thread_work_items(GCParPhases phase); + size_t max_thread_work_items(GCParPhases phase); - void record_termination(uint worker_i, double ms, size_t attempts) { - _last_termination_times_ms.set(worker_i, ms); - _last_termination_attempts.set(worker_i, attempts); - } - - void record_gc_worker_end_time(uint worker_i, double ms) { - _last_gc_worker_end_times_ms.set(worker_i, ms); - } + public: void record_clear_ct_time(double ms) { _cur_clear_ct_time_ms = ms; @@ -248,21 +179,10 @@ _cur_evac_fail_remove_self_forwards = ms; } - void note_string_dedup_fixup_start(); - void note_string_dedup_fixup_end(); - void record_string_dedup_fixup_time(double ms) { _cur_string_dedup_fixup_time_ms = ms; } - void record_string_dedup_queue_fixup_worker_time(uint worker_id, double ms) { - _cur_string_dedup_queue_fixup_worker_times_ms.set(worker_id, ms); - } - - void record_string_dedup_table_fixup_worker_time(uint worker_id, double ms) { - _cur_string_dedup_table_fixup_worker_times_ms.set(worker_id, ms); - } - void record_ref_proc_time(double ms) { _cur_ref_proc_time_ms = ms; } @@ -283,7 +203,8 @@ _recorded_non_young_free_cset_time_ms = time_ms; } - void record_fast_reclaim_humongous_stats(size_t total, size_t candidates) { + void record_fast_reclaim_humongous_stats(double time_ms, size_t total, size_t candidates) { + _cur_fast_reclaim_humongous_register_time_ms = time_ms; _cur_fast_reclaim_humongous_total = total; _cur_fast_reclaim_humongous_candidates = candidates; } @@ -301,14 +222,6 @@ _recorded_non_young_cset_choice_time_ms = time_ms; } - void record_redirty_logged_cards_time_ms(uint worker_i, double time_ms) { - _last_redirty_logged_cards_time_ms.set(worker_i, time_ms); - } - - void record_redirty_logged_cards_processed_cards(uint worker_i, size_t processed_buffers) { - _last_redirty_logged_cards_processed_cards.set(worker_i, processed_buffers); - } - void record_redirty_logged_cards_time_ms(double time_ms) { _recorded_redirty_logged_cards_time_ms = time_ms; } @@ -362,38 +275,16 @@ double fast_reclaim_humongous_time_ms() { return _cur_fast_reclaim_humongous_time_ms; } - - double average_last_update_rs_time() { - return _last_update_rs_times_ms.average(); - } - - int sum_last_update_rs_processed_buffers() { - return _last_update_rs_processed_buffers.sum(); - } - - double average_last_scan_rs_time(){ - return _last_scan_rs_times_ms.average(); - } +}; - double average_last_strong_code_root_scan_time(){ - return _last_strong_code_root_scan_times_ms.average(); - } - - double average_last_obj_copy_time() { - return _last_obj_copy_times_ms.average(); - } - - double average_last_termination_time() { - return _last_termination_times_ms.average(); - } - - double average_last_ext_root_scan_time() { - return _last_ext_root_scan_times_ms.average(); - } - - double average_last_satb_filtering_times_ms() { - return _last_satb_filtering_times_ms.average(); - } +class G1GCParPhaseTimesTracker : public StackObj { + double _start_time; + G1GCPhaseTimes::GCParPhases _phase; + G1GCPhaseTimes* _phase_times; + uint _worker_id; +public: + G1GCParPhaseTimesTracker(G1GCPhaseTimes* phase_times, G1GCPhaseTimes::GCParPhases phase, uint worker_id); + ~G1GCParPhaseTimesTracker(); }; #endif // SHARE_VM_GC_IMPLEMENTATION_G1_G1GCPHASETIMESLOG_HPP diff -r c2687aa5e5ca -r 7eb99acd567f src/share/vm/gc_implementation/g1/g1HotCardCache.cpp --- a/src/share/vm/gc_implementation/g1/g1HotCardCache.cpp Mon Jan 25 14:56:57 2016 -0800 +++ b/src/share/vm/gc_implementation/g1/g1HotCardCache.cpp Mon Jan 25 14:57:27 2016 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 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 @@ -36,16 +36,13 @@ if (default_use_cache()) { _use_cache = true; - _hot_cache_size = (1 << G1ConcRSLogCacheSize); + _hot_cache_size = (size_t)1 << G1ConcRSLogCacheSize; _hot_cache = NEW_C_HEAP_ARRAY(jbyte*, _hot_cache_size, mtGC); - _n_hot = 0; - _hot_cache_idx = 0; + reset_hot_cache_internal(); // For refining the cards in the hot cache in parallel - uint n_workers = (ParallelGCThreads > 0 ? - _g1h->workers()->total_workers() : 1); - _hot_cache_par_chunk_size = MAX2(1, _hot_cache_size / (int)n_workers); + _hot_cache_par_chunk_size = (int)(ParallelGCThreads > 0 ? ClaimChunkSize : _hot_cache_size); _hot_cache_par_claimed_idx = 0; _card_counts.initialize(card_counts_storage); @@ -66,26 +63,21 @@ // return it for immediate refining. return card_ptr; } - // Otherwise, the card is hot. - jbyte* res = NULL; - MutexLockerEx x(HotCardCache_lock, Mutex::_no_safepoint_check_flag); - if (_n_hot == _hot_cache_size) { - res = _hot_cache[_hot_cache_idx]; - _n_hot--; - } + size_t index = Atomic::add_ptr((intptr_t)1, (volatile intptr_t*)&_hot_cache_idx) - 1; + size_t masked_index = index & (_hot_cache_size - 1); + jbyte* current_ptr = _hot_cache[masked_index]; - // Now _n_hot < _hot_cache_size, and we can insert at _hot_cache_idx. - _hot_cache[_hot_cache_idx] = card_ptr; - _hot_cache_idx++; - - if (_hot_cache_idx == _hot_cache_size) { - // Wrap around - _hot_cache_idx = 0; - } - _n_hot++; - - return res; + // Try to store the new card pointer into the cache. Compare-and-swap to guard + // against the unlikely event of a race resulting in another card pointer to + // have already been written to the cache. In this case we will return + // card_ptr in favor of the other option, which would be starting over. This + // should be OK since card_ptr will likely be the older card already when/if + // this ever happens. + jbyte* previous_ptr = (jbyte*)Atomic::cmpxchg_ptr(card_ptr, + &_hot_cache[masked_index], + current_ptr); + return (previous_ptr == current_ptr) ? previous_ptr : card_ptr; } void G1HotCardCache::drain(uint worker_i, @@ -98,38 +90,37 @@ assert(_hot_cache != NULL, "Logic"); assert(!use_cache(), "cache should be disabled"); - int start_idx; - - while ((start_idx = _hot_cache_par_claimed_idx) < _n_hot) { // read once - int end_idx = start_idx + _hot_cache_par_chunk_size; + while (_hot_cache_par_claimed_idx < _hot_cache_size) { + size_t end_idx = Atomic::add_ptr((intptr_t)_hot_cache_par_chunk_size, + (volatile intptr_t*)&_hot_cache_par_claimed_idx); + size_t start_idx = end_idx - _hot_cache_par_chunk_size; + // The current worker has successfully claimed the chunk [start_idx..end_idx) + end_idx = MIN2(end_idx, _hot_cache_size); + for (size_t i = start_idx; i < end_idx; i++) { + jbyte* card_ptr = _hot_cache[i]; + if (card_ptr != NULL) { + if (g1rs->refine_card(card_ptr, worker_i, true)) { + // The part of the heap spanned by the card contains references + // that point into the current collection set. + // We need to record the card pointer in the DirtyCardQueueSet + // that we use for such cards. + // + // The only time we care about recording cards that contain + // references that point into the collection set is during + // RSet updating while within an evacuation pause. + // In this case worker_i should be the id of a GC worker thread + assert(SafepointSynchronize::is_at_safepoint(), "Should be at a safepoint"); + assert(worker_i < ParallelGCThreads, + err_msg("incorrect worker id: %u", worker_i)); - if (start_idx == - Atomic::cmpxchg(end_idx, &_hot_cache_par_claimed_idx, start_idx)) { - // The current worker has successfully claimed the chunk [start_idx..end_idx) - end_idx = MIN2(end_idx, _n_hot); - for (int i = start_idx; i < end_idx; i++) { - jbyte* card_ptr = _hot_cache[i]; - if (card_ptr != NULL) { - if (g1rs->refine_card(card_ptr, worker_i, true)) { - // The part of the heap spanned by the card contains references - // that point into the current collection set. - // We need to record the card pointer in the DirtyCardQueueSet - // that we use for such cards. - // - // The only time we care about recording cards that contain - // references that point into the collection set is during - // RSet updating while within an evacuation pause. - // In this case worker_i should be the id of a GC worker thread - assert(SafepointSynchronize::is_at_safepoint(), "Should be at a safepoint"); - assert(worker_i < (ParallelGCThreads == 0 ? 1 : ParallelGCThreads), - err_msg("incorrect worker id: "UINT32_FORMAT, worker_i)); - - into_cset_dcq->enqueue(card_ptr); - } + into_cset_dcq->enqueue(card_ptr); } + } else { + break; } } } + // The existing entries in the hot card cache, which were just refined // above, are discarded prior to re-enabling the cache near the end of the GC. } diff -r c2687aa5e5ca -r 7eb99acd567f src/share/vm/gc_implementation/g1/g1HotCardCache.hpp --- a/src/share/vm/gc_implementation/g1/g1HotCardCache.hpp Mon Jan 25 14:56:57 2016 -0800 +++ b/src/share/vm/gc_implementation/g1/g1HotCardCache.hpp Mon Jan 25 14:57:27 2016 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 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 @@ -54,21 +54,33 @@ // code, increasing throughput. class G1HotCardCache: public CHeapObj { - G1CollectedHeap* _g1h; + + G1CollectedHeap* _g1h; + + bool _use_cache; + + G1CardCounts _card_counts; // The card cache table - jbyte** _hot_cache; + jbyte** _hot_cache; - int _hot_cache_size; - int _n_hot; - int _hot_cache_idx; + size_t _hot_cache_size; + + int _hot_cache_par_chunk_size; - int _hot_cache_par_chunk_size; - volatile int _hot_cache_par_claimed_idx; + // Avoids false sharing when concurrently updating _hot_cache_idx or + // _hot_cache_par_claimed_idx. These are never updated at the same time + // thus it's not necessary to separate them as well + char _pad_before[DEFAULT_CACHE_LINE_SIZE]; + + volatile size_t _hot_cache_idx; - bool _use_cache; + volatile size_t _hot_cache_par_claimed_idx; - G1CardCounts _card_counts; + char _pad_after[DEFAULT_CACHE_LINE_SIZE]; + + // The number of cached cards a thread claims when flushing the cache + static const int ClaimChunkSize = 32; bool default_use_cache() const { return (G1ConcRSLogCacheSize > 0); @@ -110,16 +122,25 @@ void reset_hot_cache() { assert(SafepointSynchronize::is_at_safepoint(), "Should be at a safepoint"); assert(Thread::current()->is_VM_thread(), "Current thread should be the VMthread"); - _hot_cache_idx = 0; _n_hot = 0; + if (default_use_cache()) { + reset_hot_cache_internal(); + } } - bool hot_cache_is_empty() { return _n_hot == 0; } - // Zeros the values in the card counts table for entire committed heap void reset_card_counts(); // Zeros the values in the card counts table for the given region void reset_card_counts(HeapRegion* hr); + + private: + void reset_hot_cache_internal() { + assert(_hot_cache != NULL, "Logic"); + _hot_cache_idx = 0; + for (size_t i = 0; i < _hot_cache_size; i++) { + _hot_cache[i] = NULL; + } + } }; #endif // SHARE_VM_GC_IMPLEMENTATION_G1_G1HOTCARDCACHE_HPP diff -r c2687aa5e5ca -r 7eb99acd567f src/share/vm/gc_implementation/g1/g1InCSetState.hpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/share/vm/gc_implementation/g1/g1InCSetState.hpp Mon Jan 25 14:57:27 2016 -0800 @@ -0,0 +1,132 @@ +/* + * 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_G1INCSETSTATE_HPP +#define SHARE_VM_GC_IMPLEMENTATION_G1_G1INCSETSTATE_HPP + +#include "gc_implementation/g1/g1BiasedArray.hpp" +#include "memory/allocation.hpp" + +// Per-region state during garbage collection. +struct InCSetState { + public: + // We use different types to represent the state value. Particularly SPARC puts + // values in structs from "left to right", i.e. MSB to LSB. This results in many + // unnecessary shift operations when loading and storing values of this type. + // This degrades performance significantly (>10%) on that platform. + // Other tested ABIs do not seem to have this problem, and actually tend to + // favor smaller types, so we use the smallest usable type there. +#ifdef SPARC + #define CSETSTATE_FORMAT INTPTR_FORMAT + typedef intptr_t in_cset_state_t; +#else + #define CSETSTATE_FORMAT "%d" + typedef int8_t in_cset_state_t; +#endif + private: + in_cset_state_t _value; + public: + enum { + // Selection of the values were driven to micro-optimize the encoding and + // frequency of the checks. + // The most common check is whether the region is in the collection set or not. + // This encoding allows us to use an != 0 check which in some architectures + // (x86*) can be encoded slightly more efficently than a normal comparison + // against zero. + // The same situation occurs when checking whether the region is humongous + // or not, which is encoded by values < 0. + // The other values are simply encoded in increasing generation order, which + // makes getting the next generation fast by a simple increment. + Humongous = -1, // The region is humongous - note that actually any value < 0 would be possible here. + NotInCSet = 0, // The region is not in the collection set. + Young = 1, // The region is in the collection set and a young region. + Old = 2, // The region is in the collection set and an old region. + Num + }; + + InCSetState(in_cset_state_t value = NotInCSet) : _value(value) { + assert(is_valid(), err_msg("Invalid state %d", _value)); + } + + in_cset_state_t value() const { return _value; } + + void set_old() { _value = Old; } + + bool is_in_cset_or_humongous() const { return _value != NotInCSet; } + bool is_in_cset() const { return _value > NotInCSet; } + bool is_humongous() const { return _value < NotInCSet; } + bool is_young() const { return _value == Young; } + bool is_old() const { return _value == Old; } + +#ifdef ASSERT + bool is_default() const { return !is_in_cset_or_humongous(); } + bool is_valid() const { return (_value >= Humongous) && (_value < Num); } + bool is_valid_gen() const { return (_value >= Young && _value <= Old); } +#endif +}; + +// Instances of this class are used for quick tests on whether a reference points +// into the collection set and into which generation or is a humongous object +// +// Each of the array's elements indicates whether the corresponding region is in +// the collection set and if so in which generation, or a humongous region. +// +// We use this to speed up reference processing during young collection and +// quickly reclaim humongous objects. For the latter, by making a humongous region +// succeed this test, we sort-of add it to the collection set. During the reference +// iteration closures, when we see a humongous region, we then simply mark it as +// referenced, i.e. live. +class G1InCSetStateFastTestBiasedMappedArray : public G1BiasedMappedArray { + protected: + InCSetState default_value() const { return InCSetState::NotInCSet; } + public: + void set_humongous(uintptr_t index) { + assert(get_by_index(index).is_default(), + err_msg("State at index " INTPTR_FORMAT" should be default but is " CSETSTATE_FORMAT, index, get_by_index(index).value())); + set_by_index(index, InCSetState::Humongous); + } + + void clear_humongous(uintptr_t index) { + set_by_index(index, InCSetState::NotInCSet); + } + + void set_in_young(uintptr_t index) { + assert(get_by_index(index).is_default(), + err_msg("State at index " INTPTR_FORMAT" should be default but is " CSETSTATE_FORMAT, index, get_by_index(index).value())); + set_by_index(index, InCSetState::Young); + } + + void set_in_old(uintptr_t index) { + assert(get_by_index(index).is_default(), + err_msg("State at index " INTPTR_FORMAT" should be default but is " CSETSTATE_FORMAT, index, get_by_index(index).value())); + set_by_index(index, InCSetState::Old); + } + + bool is_in_cset_or_humongous(HeapWord* addr) const { return at(addr).is_in_cset_or_humongous(); } + bool is_in_cset(HeapWord* addr) const { return at(addr).is_in_cset(); } + InCSetState at(HeapWord* addr) const { return get_by_address(addr); } + void clear() { G1BiasedMappedArray::clear(); } +}; + +#endif // SHARE_VM_GC_IMPLEMENTATION_G1_G1INCSETSTATE_HPP diff -r c2687aa5e5ca -r 7eb99acd567f src/share/vm/gc_implementation/g1/g1Log.hpp --- a/src/share/vm/gc_implementation/g1/g1Log.hpp Mon Jan 25 14:56:57 2016 -0800 +++ b/src/share/vm/gc_implementation/g1/g1Log.hpp Mon Jan 25 14:57:27 2016 -0800 @@ -28,6 +28,7 @@ #include "memory/allocation.hpp" class G1Log : public AllStatic { + public: typedef enum { LevelNone, LevelFine, @@ -35,6 +36,7 @@ LevelFinest } LogLevel; + private: static LogLevel _level; public: @@ -50,6 +52,10 @@ return _level == LevelFinest; } + static LogLevel level() { + return _level; + } + static void init(); }; diff -r c2687aa5e5ca -r 7eb99acd567f src/share/vm/gc_implementation/g1/g1MarkSweep.cpp --- a/src/share/vm/gc_implementation/g1/g1MarkSweep.cpp Mon Jan 25 14:56:57 2016 -0800 +++ b/src/share/vm/gc_implementation/g1/g1MarkSweep.cpp Mon Jan 25 14:57:27 2016 -0800 @@ -31,6 +31,7 @@ #include "code/icBuffer.hpp" #include "gc_implementation/g1/g1Log.hpp" #include "gc_implementation/g1/g1MarkSweep.hpp" +#include "gc_implementation/g1/g1RootProcessor.hpp" #include "gc_implementation/g1/g1StringDedup.hpp" #include "gc_implementation/shared/gcHeapSummary.hpp" #include "gc_implementation/shared/gcTimer.hpp" @@ -128,21 +129,22 @@ GCTraceTime tm("phase 1", G1Log::fine() && Verbose, true, gc_timer(), gc_tracer()->gc_id()); GenMarkSweep::trace(" 1"); - SharedHeap* sh = SharedHeap::heap(); + G1CollectedHeap* g1h = G1CollectedHeap::heap(); // Need cleared claim bits for the roots processing ClassLoaderDataGraph::clear_claimed_marks(); MarkingCodeBlobClosure follow_code_closure(&GenMarkSweep::follow_root_closure, !CodeBlobToOopClosure::FixRelocations); - sh->process_strong_roots(true, // activate StrongRootsScope - SharedHeap::SO_None, - &GenMarkSweep::follow_root_closure, - &GenMarkSweep::follow_cld_closure, - &follow_code_closure); + { + G1RootProcessor root_processor(g1h); + root_processor.process_strong_roots(&GenMarkSweep::follow_root_closure, + &GenMarkSweep::follow_cld_closure, + &follow_code_closure); + } // Process reference objects found during marking ReferenceProcessor* rp = GenMarkSweep::ref_processor(); - assert(rp == G1CollectedHeap::heap()->ref_processor_stw(), "Sanity"); + assert(rp == g1h->ref_processor_stw(), "Sanity"); rp->setup_policy(clear_all_softrefs); const ReferenceProcessorStats& stats = @@ -230,6 +232,12 @@ } }; +class G1AlwaysTrueClosure: public BoolObjectClosure { +public: + bool do_object_b(oop p) { return true; } +}; +static G1AlwaysTrueClosure always_true; + void G1MarkSweep::mark_sweep_phase3() { G1CollectedHeap* g1h = G1CollectedHeap::heap(); @@ -237,24 +245,23 @@ GCTraceTime tm("phase 3", G1Log::fine() && Verbose, true, gc_timer(), gc_tracer()->gc_id()); GenMarkSweep::trace("3"); - SharedHeap* sh = SharedHeap::heap(); - // Need cleared claim bits for the roots processing ClassLoaderDataGraph::clear_claimed_marks(); CodeBlobToOopClosure adjust_code_closure(&GenMarkSweep::adjust_pointer_closure, CodeBlobToOopClosure::FixRelocations); - sh->process_all_roots(true, // activate StrongRootsScope - SharedHeap::SO_AllCodeCache, - &GenMarkSweep::adjust_pointer_closure, - &GenMarkSweep::adjust_cld_closure, - &adjust_code_closure); + { + G1RootProcessor root_processor(g1h); + root_processor.process_all_roots(&GenMarkSweep::adjust_pointer_closure, + &GenMarkSweep::adjust_cld_closure, + &adjust_code_closure); + } assert(GenMarkSweep::ref_processor() == g1h->ref_processor_stw(), "Sanity"); g1h->ref_processor_stw()->weak_oops_do(&GenMarkSweep::adjust_pointer_closure); // Now adjust pointers in remaining weak roots. (All of which should // have been cleared if they pointed to non-surviving objects.) - sh->process_weak_roots(&GenMarkSweep::adjust_pointer_closure); + JNIHandles::weak_oops_do(&always_true, &GenMarkSweep::adjust_pointer_closure); if (G1StringDedup::is_enabled()) { G1StringDedup::oops_do(&GenMarkSweep::adjust_pointer_closure); diff -r c2687aa5e5ca -r 7eb99acd567f src/share/vm/gc_implementation/g1/g1OopClosures.hpp --- a/src/share/vm/gc_implementation/g1/g1OopClosures.hpp Mon Jan 25 14:56:57 2016 -0800 +++ b/src/share/vm/gc_implementation/g1/g1OopClosures.hpp Mon Jan 25 14:57:27 2016 -0800 @@ -26,6 +26,7 @@ #define SHARE_VM_GC_IMPLEMENTATION_G1_G1OOPCLOSURES_HPP #include "memory/iterator.hpp" +#include "oops/markOop.hpp" class HeapRegion; class G1CollectedHeap; @@ -239,14 +240,14 @@ G1CollectedHeap* _g1; G1RemSet* _g1_rem_set; HeapRegion* _from; - OopsInHeapRegionClosure* _push_ref_cl; + G1ParPushHeapRSClosure* _push_ref_cl; bool _record_refs_into_cset; uint _worker_i; public: G1UpdateRSOrPushRefOopClosure(G1CollectedHeap* g1h, G1RemSet* rs, - OopsInHeapRegionClosure* push_ref_cl, + G1ParPushHeapRSClosure* push_ref_cl, bool record_refs_into_cset, uint worker_i = 0); @@ -256,7 +257,8 @@ } bool self_forwarded(oop obj) { - bool result = (obj->is_forwarded() && (obj->forwardee()== obj)); + markOop m = obj->mark(); + bool result = (m->is_marked() && ((oop)m->decode_pointer() == obj)); return result; } diff -r c2687aa5e5ca -r 7eb99acd567f src/share/vm/gc_implementation/g1/g1OopClosures.inline.hpp --- a/src/share/vm/gc_implementation/g1/g1OopClosures.inline.hpp Mon Jan 25 14:56:57 2016 -0800 +++ b/src/share/vm/gc_implementation/g1/g1OopClosures.inline.hpp Mon Jan 25 14:57:27 2016 -0800 @@ -67,8 +67,8 @@ if (!oopDesc::is_null(heap_oop)) { oop obj = oopDesc::decode_heap_oop_not_null(heap_oop); - G1CollectedHeap::in_cset_state_t state = _g1->in_cset_state(obj); - if (state == G1CollectedHeap::InCSet) { + const InCSetState state = _g1->in_cset_state(obj); + if (state.is_in_cset()) { // We're not going to even bother checking whether the object is // already forwarded or not, as this usually causes an immediate // stall. We'll try to prefetch the object (for write, given that @@ -87,7 +87,7 @@ _par_scan_state->push_on_queue(p); } else { - if (state == G1CollectedHeap::IsHumongous) { + if (state.is_humongous()) { _g1->set_humongous_is_live(obj); } _par_scan_state->update_rs(_from, p, _worker_id); diff -r c2687aa5e5ca -r 7eb99acd567f src/share/vm/gc_implementation/g1/g1PageBasedVirtualSpace.cpp --- a/src/share/vm/gc_implementation/g1/g1PageBasedVirtualSpace.cpp Mon Jan 25 14:56:57 2016 -0800 +++ b/src/share/vm/gc_implementation/g1/g1PageBasedVirtualSpace.cpp Mon Jan 25 14:57:27 2016 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 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 @@ -44,20 +44,29 @@ #endif #include "utilities/bitMap.inline.hpp" -G1PageBasedVirtualSpace::G1PageBasedVirtualSpace() : _low_boundary(NULL), - _high_boundary(NULL), _committed(), _page_size(0), _special(false), +G1PageBasedVirtualSpace::G1PageBasedVirtualSpace(ReservedSpace rs, size_t used_size, size_t page_size) : + _low_boundary(NULL), _high_boundary(NULL), _committed(), _page_size(0), _special(false), _dirty(), _executable(false) { + initialize_with_page_size(rs, used_size, page_size); } -bool G1PageBasedVirtualSpace::initialize_with_granularity(ReservedSpace rs, size_t page_size) { - if (!rs.is_reserved()) { - return false; // Allocation failed. - } +void G1PageBasedVirtualSpace::initialize_with_page_size(ReservedSpace rs, size_t used_size, size_t page_size) { + guarantee(rs.is_reserved(), "Given reserved space must have been reserved already."); + assert(_low_boundary == NULL, "VirtualSpace already initialized"); - assert(page_size > 0, "Granularity must be non-zero."); + assert(page_size > 0, "Page size must be non-zero."); + + guarantee(is_ptr_aligned(rs.base(), page_size), + err_msg("Reserved space base " PTR_FORMAT " is not aligned to requested page size " SIZE_FORMAT, p2i(rs.base()), page_size)); + guarantee(is_size_aligned(used_size, os::vm_page_size()), + err_msg("Given used reserved space size needs to be OS page size aligned (%d bytes) but is " SIZE_FORMAT, os::vm_page_size(), used_size)); + guarantee(used_size <= rs.size(), + err_msg("Used size of reserved space " SIZE_FORMAT " bytes is smaller than reservation at " SIZE_FORMAT " bytes", used_size, rs.size())); + guarantee(is_size_aligned(rs.size(), page_size), + err_msg("Expected that the virtual space is size aligned, but " SIZE_FORMAT " is not aligned to page size " SIZE_FORMAT, rs.size(), page_size)); _low_boundary = rs.base(); - _high_boundary = _low_boundary + rs.size(); + _high_boundary = _low_boundary + used_size; _special = rs.special(); _executable = rs.executable(); @@ -65,16 +74,15 @@ _page_size = page_size; 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); + BitMap::idx_t size_in_pages = rs.size() / page_size; + _committed.resize(size_in_pages, /* in_resource_area */ false); if (_special) { - _dirty.resize(size_in_bits, /* in_resource_area */ false); + _dirty.resize(size_in_pages, /* in_resource_area */ false); } - return true; + _tail_size = used_size % _page_size; } - G1PageBasedVirtualSpace::~G1PageBasedVirtualSpace() { release(); } @@ -87,12 +95,18 @@ _special = false; _executable = false; _page_size = 0; + _tail_size = 0; _committed.resize(0, false); _dirty.resize(0, false); } size_t G1PageBasedVirtualSpace::committed_size() const { - return _committed.count_one_bits() * _page_size; + size_t result = _committed.count_one_bits() * _page_size; + // The last page might not be in full. + if (is_last_page_partial() && _committed.at(_committed.size() - 1)) { + result -= _page_size - _tail_size; + } + return result; } size_t G1PageBasedVirtualSpace::reserved_size() const { @@ -103,62 +117,134 @@ return reserved_size() - committed_size(); } -uintptr_t G1PageBasedVirtualSpace::addr_to_page_index(char* addr) const { +size_t G1PageBasedVirtualSpace::addr_to_page_index(char* addr) const { return (addr - _low_boundary) / _page_size; } -bool G1PageBasedVirtualSpace::is_area_committed(uintptr_t start, size_t size_in_pages) const { - uintptr_t end = start + size_in_pages; - return _committed.get_next_zero_offset(start, end) >= end; +bool G1PageBasedVirtualSpace::is_area_committed(size_t start_page, size_t size_in_pages) const { + size_t end_page = start_page + size_in_pages; + return _committed.get_next_zero_offset(start_page, end_page) >= end_page; } -bool G1PageBasedVirtualSpace::is_area_uncommitted(uintptr_t start, size_t size_in_pages) const { - uintptr_t end = start + size_in_pages; - return _committed.get_next_one_offset(start, end) >= end; +bool G1PageBasedVirtualSpace::is_area_uncommitted(size_t start_page, size_t size_in_pages) const { + size_t end_page = start_page + size_in_pages; + return _committed.get_next_one_offset(start_page, end_page) >= end_page; } -char* G1PageBasedVirtualSpace::page_start(uintptr_t index) { +char* G1PageBasedVirtualSpace::page_start(size_t index) const { return _low_boundary + index * _page_size; } -size_t G1PageBasedVirtualSpace::byte_size_for_pages(size_t num) { - return num * _page_size; +bool G1PageBasedVirtualSpace::is_after_last_page(size_t index) const { + guarantee(index <= _committed.size(), + err_msg("Given boundary page " SIZE_FORMAT " is beyond managed page count " SIZE_FORMAT, index, _committed.size())); + return index == _committed.size(); +} + +void G1PageBasedVirtualSpace::commit_preferred_pages(size_t start, size_t num_pages) { + assert(num_pages > 0, "No full pages to commit"); + assert(start + num_pages <= _committed.size(), + err_msg("Tried to commit area from page " SIZE_FORMAT " to page " SIZE_FORMAT " " + "that is outside of managed space of " SIZE_FORMAT " pages", + start, start + num_pages, _committed.size())); + + char* start_addr = page_start(start); + size_t size = num_pages * _page_size; + + os::commit_memory_or_exit(start_addr, size, _page_size, _executable, + err_msg("Failed to commit area from " PTR_FORMAT " to " PTR_FORMAT " of length " SIZE_FORMAT ".", + p2i(start_addr), p2i(start_addr + size), size)); +} + +void G1PageBasedVirtualSpace::commit_tail() { + assert(_tail_size > 0, "The size of the tail area must be > 0 when reaching here"); + + char* const aligned_end_address = (char*)align_ptr_down(_high_boundary, _page_size); + os::commit_memory_or_exit(aligned_end_address, _tail_size, os::vm_page_size(), _executable, + err_msg("Failed to commit tail area from " PTR_FORMAT " to " PTR_FORMAT " of length " SIZE_FORMAT ".", + p2i(aligned_end_address), p2i(_high_boundary), _tail_size)); } -bool G1PageBasedVirtualSpace::commit(uintptr_t start, size_t size_in_pages) { +void G1PageBasedVirtualSpace::commit_internal(size_t start_page, size_t end_page) { + guarantee(start_page < end_page, + err_msg("Given start page " SIZE_FORMAT " is larger or equal to end page " SIZE_FORMAT, start_page, end_page)); + guarantee(end_page <= _committed.size(), + err_msg("Given end page " SIZE_FORMAT " is beyond end of managed page amount of " SIZE_FORMAT, end_page, _committed.size())); + + size_t pages = end_page - start_page; + bool need_to_commit_tail = is_after_last_page(end_page) && is_last_page_partial(); + + // If we have to commit some (partial) tail area, decrease the amount of pages to avoid + // committing that in the full-page commit code. + if (need_to_commit_tail) { + pages--; + } + + if (pages > 0) { + commit_preferred_pages(start_page, pages); + } + + if (need_to_commit_tail) { + commit_tail(); + } +} + +char* G1PageBasedVirtualSpace::bounded_end_addr(size_t end_page) const { + return MIN2(_high_boundary, page_start(end_page)); +} + +void G1PageBasedVirtualSpace::pretouch_internal(size_t start_page, size_t end_page) { + guarantee(start_page < end_page, + err_msg("Given start page " SIZE_FORMAT " is larger or equal to end page " SIZE_FORMAT, start_page, end_page)); + + os::pretouch_memory(page_start(start_page), bounded_end_addr(end_page)); +} + +bool G1PageBasedVirtualSpace::commit(size_t start_page, 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"); + guarantee(is_area_uncommitted(start_page, size_in_pages), "Specified area is not uncommitted"); bool zero_filled = true; - uintptr_t end = start + size_in_pages; + size_t end_page = start_page + 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) { + if (_dirty.get_next_one_offset(start_page, end_page) < end_page) { zero_filled = false; - _dirty.clear_range(start, end); + _dirty.clear_range(start_page, end_page); } } 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)); + commit_internal(start_page, end_page); } - _committed.set_range(start, end); + _committed.set_range(start_page, end_page); + if (AlwaysPreTouch) { + pretouch_internal(start_page, end_page); + } return zero_filled; } -void G1PageBasedVirtualSpace::uncommit(uintptr_t start, size_t size_in_pages) { - guarantee(is_area_committed(start, size_in_pages), "checking"); +void G1PageBasedVirtualSpace::uncommit_internal(size_t start_page, size_t end_page) { + guarantee(start_page < end_page, + err_msg("Given start page " SIZE_FORMAT " is larger or equal to end page " SIZE_FORMAT, start_page, end_page)); + char* start_addr = page_start(start_page); + os::uncommit_memory(start_addr, pointer_delta(bounded_end_addr(end_page), start_addr, sizeof(char))); +} + +void G1PageBasedVirtualSpace::uncommit(size_t start_page, size_t size_in_pages) { + guarantee(is_area_committed(start_page, size_in_pages), "checking"); + + size_t end_page = start_page + size_in_pages; 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); + _dirty.set_range(start_page, end_page); } else { - os::uncommit_memory(page_start(start), byte_size_for_pages(size_in_pages)); + uncommit_internal(start_page, end_page); } - _committed.clear_range(start, start + size_in_pages); + _committed.clear_range(start_page, end_page); } bool G1PageBasedVirtualSpace::contains(const void* p) const { @@ -172,7 +258,8 @@ out->cr(); out->print_cr(" - committed: " SIZE_FORMAT, committed_size()); out->print_cr(" - reserved: " SIZE_FORMAT, reserved_size()); - out->print_cr(" - [low_b, high_b]: [" INTPTR_FORMAT ", " INTPTR_FORMAT "]", p2i(_low_boundary), p2i(_high_boundary)); + out->print_cr(" - preferred page size: " SIZE_FORMAT, _page_size); + out->print_cr(" - [low_b, high_b]: [" PTR_FORMAT ", " PTR_FORMAT "]", p2i(_low_boundary), p2i(_high_boundary)); } void G1PageBasedVirtualSpace::print() { diff -r c2687aa5e5ca -r 7eb99acd567f src/share/vm/gc_implementation/g1/g1PageBasedVirtualSpace.hpp --- a/src/share/vm/gc_implementation/g1/g1PageBasedVirtualSpace.hpp Mon Jan 25 14:56:57 2016 -0800 +++ b/src/share/vm/gc_implementation/g1/g1PageBasedVirtualSpace.hpp Mon Jan 25 14:57:27 2016 -0800 @@ -34,6 +34,12 @@ // granularity. // (De-)Allocation requests are always OS page aligned by passing a page index // and multiples of pages. +// For systems that only commits of memory in a given size (always greater than +// page size) the base address is required to be aligned to that page size. +// The actual size requested need not be aligned to that page size, but the size +// of the reservation passed may be rounded up to this page size. Any fragment +// (less than the page size) of the actual size at the tail of the request will +// be committed using OS small pages. // The implementation gives an error when trying to commit or uncommit pages that // have already been committed or uncommitted. class G1PageBasedVirtualSpace VALUE_OBJ_CLASS_SPEC { @@ -43,7 +49,11 @@ char* _low_boundary; char* _high_boundary; - // The commit/uncommit granularity in bytes. + // The size of the tail in bytes of the handled space that needs to be committed + // using small pages. + size_t _tail_size; + + // The preferred page size used for commit/uncommit in bytes. size_t _page_size; // Bitmap used for verification of commit/uncommit operations. @@ -62,30 +72,55 @@ // Indicates whether the committed space should be executable. bool _executable; + // Helper function for committing memory. Commit the given memory range by using + // _page_size pages as much as possible and the remainder with small sized pages. + void commit_internal(size_t start_page, size_t end_page); + // Commit num_pages pages of _page_size size starting from start. All argument + // checking has been performed. + void commit_preferred_pages(size_t start_page, size_t end_page); + // Commit space at the high end of the space that needs to be committed with small + // sized pages. + void commit_tail(); + + // Uncommit the given memory range. + void uncommit_internal(size_t start_page, size_t end_page); + + // Pretouch the given memory range. + void pretouch_internal(size_t start_page, size_t end_page); + // Returns the index of the page which contains the given address. uintptr_t addr_to_page_index(char* addr) const; // Returns the address of the given page index. - char* page_start(uintptr_t index); - // Returns the byte size of the given number of pages. - size_t byte_size_for_pages(size_t num); + char* page_start(size_t index) const; + + // Is the given page index the last page? + bool is_last_page(size_t index) const { return index == (_committed.size() - 1); } + // Is the given page index the first after last page? + bool is_after_last_page(size_t index) const; + // Is the last page only partially covered by this space? + bool is_last_page_partial() const { return !is_ptr_aligned(_high_boundary, _page_size); } + // Returns the end address of the given page bounded by the reserved space. + char* bounded_end_addr(size_t end_page) const; // Returns true if the entire area is backed by committed memory. - bool is_area_committed(uintptr_t start, size_t size_in_pages) const; + bool is_area_committed(size_t start_page, size_t size_in_pages) const; // Returns true if the entire area is not backed by committed memory. - bool is_area_uncommitted(uintptr_t start, size_t size_in_pages) const; + bool is_area_uncommitted(size_t start_page, size_t size_in_pages) const; + void initialize_with_page_size(ReservedSpace rs, size_t used_size, size_t page_size); public: // Commit the given area of pages starting at start being size_in_pages large. // Returns true if the given area is zero filled upon completion. - bool commit(uintptr_t start, size_t size_in_pages); + bool commit(size_t start_page, size_t size_in_pages); // Uncommit the given area of pages starting at start being size_in_pages large. - void uncommit(uintptr_t start, size_t size_in_pages); + void uncommit(size_t start_page, size_t size_in_pages); - // Initialization - G1PageBasedVirtualSpace(); - bool initialize_with_granularity(ReservedSpace rs, size_t page_size); + // Initialize the given reserved space with the given base address and the size + // actually used. + // Prefer to commit in page_size chunks. + G1PageBasedVirtualSpace(ReservedSpace rs, size_t used_size, size_t page_size); // Destruction ~G1PageBasedVirtualSpace(); diff -r c2687aa5e5ca -r 7eb99acd567f src/share/vm/gc_implementation/g1/g1ParScanThreadState.cpp --- a/src/share/vm/gc_implementation/g1/g1ParScanThreadState.cpp Mon Jan 25 14:56:57 2016 -0800 +++ b/src/share/vm/gc_implementation/g1/g1ParScanThreadState.cpp Mon Jan 25 14:57:27 2016 -0800 @@ -38,6 +38,7 @@ _g1_rem(g1h->g1_rem_set()), _hash_seed(17), _queue_num(queue_num), _term_attempts(0), + _tenuring_threshold(g1h->g1_policy()->tenuring_threshold()), _age_table(false), _scanner(g1h, rp), _strong_roots_time(0), _term_time(0) { _scanner.set_par_scan_thread_state(this); @@ -59,6 +60,12 @@ _g1_par_allocator = G1ParGCAllocator::create_allocator(_g1h); + _dest[InCSetState::NotInCSet] = InCSetState::NotInCSet; + // The dest for Young is used when the objects are aged enough to + // need to be moved to the next space. + _dest[InCSetState::Young] = InCSetState::Old; + _dest[InCSetState::Old] = InCSetState::Old; + _start = os::elapsedTime(); } @@ -150,86 +157,126 @@ } while (!_refs->is_empty()); } -oop G1ParScanThreadState::copy_to_survivor_space(oop const old) { - size_t word_sz = old->size(); - HeapRegion* from_region = _g1h->heap_region_containing_raw(old); +HeapWord* G1ParScanThreadState::allocate_in_next_plab(InCSetState const state, + InCSetState* dest, + size_t word_sz, + AllocationContext_t const context) { + assert(state.is_in_cset_or_humongous(), err_msg("Unexpected state: " CSETSTATE_FORMAT, state.value())); + assert(dest->is_in_cset_or_humongous(), err_msg("Unexpected dest: " CSETSTATE_FORMAT, dest->value())); + + // Right now we only have two types of regions (young / old) so + // let's keep the logic here simple. We can generalize it when necessary. + if (dest->is_young()) { + HeapWord* const obj_ptr = _g1_par_allocator->allocate(InCSetState::Old, + word_sz, context); + if (obj_ptr == NULL) { + return NULL; + } + // Make sure that we won't attempt to copy any other objects out + // of a survivor region (given that apparently we cannot allocate + // any new ones) to avoid coming into this slow path. + _tenuring_threshold = 0; + dest->set_old(); + return obj_ptr; + } else { + assert(dest->is_old(), err_msg("Unexpected dest: " CSETSTATE_FORMAT, dest->value())); + // no other space to try. + return NULL; + } +} + +InCSetState G1ParScanThreadState::next_state(InCSetState const state, markOop const m, uint& age) { + if (state.is_young()) { + age = !m->has_displaced_mark_helper() ? m->age() + : m->displaced_mark_helper()->age(); + if (age < _tenuring_threshold) { + return state; + } + } + return dest(state); +} + +oop G1ParScanThreadState::copy_to_survivor_space(InCSetState const state, + oop const old, + markOop const old_mark) { + const size_t word_sz = old->size(); + HeapRegion* const from_region = _g1h->heap_region_containing_raw(old); // +1 to make the -1 indexes valid... - int young_index = from_region->young_index_in_cset()+1; + const int young_index = from_region->young_index_in_cset()+1; assert( (from_region->is_young() && young_index > 0) || (!from_region->is_young() && young_index == 0), "invariant" ); - G1CollectorPolicy* g1p = _g1h->g1_policy(); - markOop m = old->mark(); - int age = m->has_displaced_mark_helper() ? m->displaced_mark_helper()->age() - : m->age(); - GCAllocPurpose alloc_purpose = g1p->evacuation_destination(from_region, age, - word_sz); - AllocationContext_t context = from_region->allocation_context(); - HeapWord* obj_ptr = _g1_par_allocator->allocate(alloc_purpose, word_sz, context); + const AllocationContext_t context = from_region->allocation_context(); + + uint age = 0; + InCSetState dest_state = next_state(state, old_mark, age); + HeapWord* obj_ptr = _g1_par_allocator->plab_allocate(dest_state, word_sz, context); + + // PLAB allocations should succeed most of the time, so we'll + // normally check against NULL once and that's it. + if (obj_ptr == NULL) { + obj_ptr = _g1_par_allocator->allocate_direct_or_new_plab(dest_state, word_sz, context); + if (obj_ptr == NULL) { + obj_ptr = allocate_in_next_plab(state, &dest_state, word_sz, context); + if (obj_ptr == NULL) { + // This will either forward-to-self, or detect that someone else has + // installed a forwarding pointer. + return _g1h->handle_evacuation_failure_par(this, old); + } + } + } + + assert(obj_ptr != NULL, "when we get here, allocation should have succeeded"); #ifndef PRODUCT // Should this evacuation fail? if (_g1h->evacuation_should_fail()) { - if (obj_ptr != NULL) { - _g1_par_allocator->undo_allocation(alloc_purpose, obj_ptr, word_sz, context); - obj_ptr = NULL; - } + // Doing this after all the allocation attempts also tests the + // undo_allocation() method too. + _g1_par_allocator->undo_allocation(dest_state, obj_ptr, word_sz, context); + return _g1h->handle_evacuation_failure_par(this, old); } #endif // !PRODUCT - if (obj_ptr == NULL) { - // This will either forward-to-self, or detect that someone else has - // installed a forwarding pointer. - return _g1h->handle_evacuation_failure_par(this, old); - } - - oop obj = oop(obj_ptr); - // We're going to allocate linearly, so might as well prefetch ahead. Prefetch::write(obj_ptr, PrefetchCopyIntervalInBytes); - oop forward_ptr = old->forward_to_atomic(obj); + const oop obj = oop(obj_ptr); + const oop forward_ptr = old->forward_to_atomic(obj); if (forward_ptr == NULL) { Copy::aligned_disjoint_words((HeapWord*) old, obj_ptr, word_sz); - // alloc_purpose is just a hint to allocate() above, recheck the type of region - // we actually allocated from and update alloc_purpose accordingly - HeapRegion* to_region = _g1h->heap_region_containing_raw(obj_ptr); - alloc_purpose = to_region->is_young() ? GCAllocForSurvived : GCAllocForTenured; - - if (g1p->track_object_age(alloc_purpose)) { - // We could simply do obj->incr_age(). However, this causes a - // performance issue. obj->incr_age() will first check whether - // the object has a displaced mark by checking its mark word; - // getting the mark word from the new location of the object - // stalls. So, given that we already have the mark word and we - // are about to install it anyway, it's better to increase the - // age on the mark word, when the object does not have a - // displaced mark word. We're not expecting many objects to have - // a displaced marked word, so that case is not optimized - // further (it could be...) and we simply call obj->incr_age(). - - if (m->has_displaced_mark_helper()) { - // in this case, we have to install the mark word first, + if (dest_state.is_young()) { + if (age < markOopDesc::max_age) { + age++; + } + if (old_mark->has_displaced_mark_helper()) { + // In this case, we have to install the mark word first, // otherwise obj looks to be forwarded (the old mark word, // which contains the forward pointer, was copied) - obj->set_mark(m); - obj->incr_age(); + obj->set_mark(old_mark); + markOop new_mark = old_mark->displaced_mark_helper()->set_age(age); + old_mark->set_displaced_mark_helper(new_mark); } else { - m = m->incr_age(); - obj->set_mark(m); + obj->set_mark(old_mark->set_age(age)); } - age_table()->add(obj, word_sz); + age_table()->add(age, word_sz); } else { - obj->set_mark(m); + obj->set_mark(old_mark); } if (G1StringDedup::is_enabled()) { - G1StringDedup::enqueue_from_evacuation(from_region->is_young(), - to_region->is_young(), + const bool is_from_young = state.is_young(); + const bool is_to_young = dest_state.is_young(); + assert(is_from_young == _g1h->heap_region_containing_raw(old)->is_young(), + "sanity"); + assert(is_to_young == _g1h->heap_region_containing_raw(obj)->is_young(), + "sanity"); + G1StringDedup::enqueue_from_evacuation(is_from_young, + is_to_young, queue_num(), obj); } - size_t* surv_young_words = surviving_young_words(); + size_t* const surv_young_words = surviving_young_words(); surv_young_words[young_index] += word_sz; if (obj->is_objArray() && arrayOop(obj)->length() >= ParGCArrayScanChunk) { @@ -240,14 +287,13 @@ oop* old_p = set_partial_array_mask(old); push_on_queue(old_p); } else { - // No point in using the slower heap_region_containing() method, - // given that we know obj is in the heap. - _scanner.set_region(_g1h->heap_region_containing_raw(obj)); + HeapRegion* const to_region = _g1h->heap_region_containing_raw(obj_ptr); + _scanner.set_region(to_region); obj->oop_iterate_backwards(&_scanner); } + return obj; } else { - _g1_par_allocator->undo_allocation(alloc_purpose, obj_ptr, word_sz, context); - obj = forward_ptr; + _g1_par_allocator->undo_allocation(dest_state, obj_ptr, word_sz, context); + return forward_ptr; } - return obj; } diff -r c2687aa5e5ca -r 7eb99acd567f src/share/vm/gc_implementation/g1/g1ParScanThreadState.hpp --- a/src/share/vm/gc_implementation/g1/g1ParScanThreadState.hpp Mon Jan 25 14:56:57 2016 -0800 +++ b/src/share/vm/gc_implementation/g1/g1ParScanThreadState.hpp Mon Jan 25 14:57:27 2016 -0800 @@ -46,14 +46,16 @@ G1SATBCardTableModRefBS* _ct_bs; G1RemSet* _g1_rem; - G1ParGCAllocator* _g1_par_allocator; - - ageTable _age_table; + G1ParGCAllocator* _g1_par_allocator; - G1ParScanClosure _scanner; + ageTable _age_table; + InCSetState _dest[InCSetState::Num]; + // Local tenuring threshold. + uint _tenuring_threshold; + G1ParScanClosure _scanner; - size_t _alloc_buffer_waste; - size_t _undo_waste; + size_t _alloc_buffer_waste; + size_t _undo_waste; OopsInHeapRegionClosure* _evac_failure_cl; @@ -82,6 +84,14 @@ DirtyCardQueue& dirty_card_queue() { return _dcq; } G1SATBCardTableModRefBS* ctbs() { return _ct_bs; } + InCSetState dest(InCSetState original) const { + assert(original.is_valid(), + err_msg("Original state invalid: " CSETSTATE_FORMAT, original.value())); + assert(_dest[original.value()].is_valid_gen(), + err_msg("Dest state is invalid: " CSETSTATE_FORMAT, _dest[original.value()].value())); + return _dest[original.value()]; + } + public: G1ParScanThreadState(G1CollectedHeap* g1h, uint queue_num, ReferenceProcessor* rp); ~G1ParScanThreadState(); @@ -112,7 +122,6 @@ } } } - public: void set_evac_failure_closure(OopsInHeapRegionClosure* evac_failure_cl) { _evac_failure_cl = evac_failure_cl; @@ -193,9 +202,20 @@ template inline void deal_with_reference(T* ref_to_scan); inline void dispatch_reference(StarTask ref); + + // Tries to allocate word_sz in the PLAB of the next "generation" after trying to + // allocate into dest. State is the original (source) cset state for the object + // that is allocated for. + // Returns a non-NULL pointer if successful, and updates dest if required. + HeapWord* allocate_in_next_plab(InCSetState const state, + InCSetState* dest, + size_t word_sz, + AllocationContext_t const context); + + inline InCSetState next_state(InCSetState const state, markOop const m, uint& age); public: - oop copy_to_survivor_space(oop const obj); + oop copy_to_survivor_space(InCSetState const state, oop const obj, markOop const old_mark); void trim_queue(); diff -r c2687aa5e5ca -r 7eb99acd567f src/share/vm/gc_implementation/g1/g1ParScanThreadState.inline.hpp --- a/src/share/vm/gc_implementation/g1/g1ParScanThreadState.inline.hpp Mon Jan 25 14:56:57 2016 -0800 +++ b/src/share/vm/gc_implementation/g1/g1ParScanThreadState.inline.hpp Mon Jan 25 14:57:27 2016 -0800 @@ -38,20 +38,21 @@ // set, due to (benign) races in the claim mechanism during RSet scanning more // than one thread might claim the same card. So the same card may be // processed multiple times. So redo this check. - G1CollectedHeap::in_cset_state_t in_cset_state = _g1h->in_cset_state(obj); - if (in_cset_state == G1CollectedHeap::InCSet) { + const InCSetState in_cset_state = _g1h->in_cset_state(obj); + if (in_cset_state.is_in_cset()) { oop forwardee; - if (obj->is_forwarded()) { - forwardee = obj->forwardee(); + markOop m = obj->mark(); + if (m->is_marked()) { + forwardee = (oop) m->decode_pointer(); } else { - forwardee = copy_to_survivor_space(obj); + forwardee = copy_to_survivor_space(in_cset_state, obj, m); } oopDesc::encode_store_heap_oop(p, forwardee); - } else if (in_cset_state == G1CollectedHeap::IsHumongous) { + } else if (in_cset_state.is_humongous()) { _g1h->set_humongous_is_live(obj); } else { - assert(in_cset_state == G1CollectedHeap::InNeither, - err_msg("In_cset_state must be InNeither here, but is %d", in_cset_state)); + assert(!in_cset_state.is_in_cset_or_humongous(), + err_msg("In_cset_state must be NotInCSet here, but is " CSETSTATE_FORMAT, in_cset_state.value())); } assert(obj != NULL, "Must be"); diff -r c2687aa5e5ca -r 7eb99acd567f src/share/vm/gc_implementation/g1/g1RegionToSpaceMapper.cpp --- a/src/share/vm/gc_implementation/g1/g1RegionToSpaceMapper.cpp Mon Jan 25 14:56:57 2016 -0800 +++ b/src/share/vm/gc_implementation/g1/g1RegionToSpaceMapper.cpp Mon Jan 25 14:57:27 2016 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 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,17 +31,16 @@ #include "utilities/bitMap.inline.hpp" G1RegionToSpaceMapper::G1RegionToSpaceMapper(ReservedSpace rs, - size_t commit_granularity, + size_t used_size, + size_t page_size, size_t region_granularity, MemoryType type) : - _storage(), - _commit_granularity(commit_granularity), + _storage(rs, used_size, page_size), _region_granularity(region_granularity), _listener(NULL), _commit_map() { - guarantee(is_power_of_2(commit_granularity), "must be"); + guarantee(is_power_of_2(page_size), "must be"); guarantee(is_power_of_2(region_granularity), "must be"); - _storage.initialize_with_granularity(rs, commit_granularity); MemTracker::record_virtual_memory_type((address)rs.base(), type); } @@ -55,25 +54,26 @@ public: G1RegionsLargerThanCommitSizeMapper(ReservedSpace rs, - size_t os_commit_granularity, + size_t actual_size, + size_t page_size, size_t alloc_granularity, size_t commit_factor, MemoryType type) : - G1RegionToSpaceMapper(rs, os_commit_granularity, alloc_granularity, type), - _pages_per_region(alloc_granularity / (os_commit_granularity * commit_factor)) { + G1RegionToSpaceMapper(rs, actual_size, page_size, alloc_granularity, type), + _pages_per_region(alloc_granularity / (page_size * commit_factor)) { - guarantee(alloc_granularity >= os_commit_granularity, "allocation granularity smaller than commit granularity"); + guarantee(alloc_granularity >= page_size, "allocation granularity smaller than commit granularity"); _commit_map.resize(rs.size() * commit_factor / alloc_granularity, /* in_resource_area */ false); } - virtual void commit_regions(uintptr_t start_idx, size_t num_regions) { - bool zero_filled = _storage.commit(start_idx * _pages_per_region, num_regions * _pages_per_region); + virtual void commit_regions(uint start_idx, size_t num_regions) { + bool zero_filled = _storage.commit((size_t)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, zero_filled); } - virtual void uncommit_regions(uintptr_t start_idx, size_t num_regions) { - _storage.uncommit(start_idx * _pages_per_region, num_regions * _pages_per_region); + virtual void uncommit_regions(uint start_idx, size_t num_regions) { + _storage.uncommit((size_t)start_idx * _pages_per_region, num_regions * _pages_per_region); _commit_map.clear_range(start_idx, start_idx + num_regions); } }; @@ -98,22 +98,23 @@ public: G1RegionsSmallerThanCommitSizeMapper(ReservedSpace rs, - size_t os_commit_granularity, + size_t actual_size, + size_t page_size, size_t alloc_granularity, size_t commit_factor, MemoryType type) : - G1RegionToSpaceMapper(rs, os_commit_granularity, alloc_granularity, type), - _regions_per_page((os_commit_granularity * commit_factor) / alloc_granularity), _refcounts() { + G1RegionToSpaceMapper(rs, actual_size, page_size, alloc_granularity, type), + _regions_per_page((page_size * commit_factor) / alloc_granularity), _refcounts() { - guarantee((os_commit_granularity * commit_factor) >= alloc_granularity, "allocation granularity smaller than commit granularity"); - _refcounts.initialize((HeapWord*)rs.base(), (HeapWord*)(rs.base() + rs.size()), os_commit_granularity); + guarantee((page_size * commit_factor) >= alloc_granularity, "allocation granularity smaller than commit granularity"); + _refcounts.initialize((HeapWord*)rs.base(), (HeapWord*)(rs.base() + align_size_up(rs.size(), page_size)), page_size); _commit_map.resize(rs.size() * commit_factor / alloc_granularity, /* in_resource_area */ false); } - virtual void commit_regions(uintptr_t start_idx, size_t num_regions) { - for (uintptr_t i = start_idx; i < start_idx + num_regions; i++) { - assert(!_commit_map.at(i), err_msg("Trying to commit storage at region "INTPTR_FORMAT" that is already committed", i)); - uintptr_t idx = region_idx_to_page_idx(i); + virtual void commit_regions(uint start_idx, size_t num_regions) { + for (uint i = start_idx; i < start_idx + num_regions; i++) { + assert(!_commit_map.at(i), err_msg("Trying to commit storage at region %u that is already committed", i)); + size_t idx = region_idx_to_page_idx(i); uint old_refcount = _refcounts.get_by_index(idx); bool zero_filled = false; if (old_refcount == 0) { @@ -125,10 +126,10 @@ } } - virtual void uncommit_regions(uintptr_t start_idx, size_t num_regions) { - for (uintptr_t i = start_idx; i < start_idx + num_regions; i++) { - assert(_commit_map.at(i), err_msg("Trying to uncommit storage at region "INTPTR_FORMAT" that is not committed", i)); - uintptr_t idx = region_idx_to_page_idx(i); + virtual void uncommit_regions(uint start_idx, size_t num_regions) { + for (uint i = start_idx; i < start_idx + num_regions; i++) { + assert(_commit_map.at(i), err_msg("Trying to uncommit storage at region %u that is not committed", i)); + size_t idx = region_idx_to_page_idx(i); uint old_refcount = _refcounts.get_by_index(idx); assert(old_refcount > 0, "must be"); if (old_refcount == 1) { @@ -147,14 +148,15 @@ } G1RegionToSpaceMapper* G1RegionToSpaceMapper::create_mapper(ReservedSpace rs, - size_t os_commit_granularity, + size_t actual_size, + size_t page_size, size_t region_granularity, size_t commit_factor, MemoryType type) { - if (region_granularity >= (os_commit_granularity * commit_factor)) { - return new G1RegionsLargerThanCommitSizeMapper(rs, os_commit_granularity, region_granularity, commit_factor, type); + if (region_granularity >= (page_size * commit_factor)) { + return new G1RegionsLargerThanCommitSizeMapper(rs, actual_size, page_size, region_granularity, commit_factor, type); } else { - return new G1RegionsSmallerThanCommitSizeMapper(rs, os_commit_granularity, region_granularity, commit_factor, type); + return new G1RegionsSmallerThanCommitSizeMapper(rs, actual_size, page_size, region_granularity, commit_factor, type); } } diff -r c2687aa5e5ca -r 7eb99acd567f src/share/vm/gc_implementation/g1/g1RegionToSpaceMapper.hpp --- a/src/share/vm/gc_implementation/g1/g1RegionToSpaceMapper.hpp Mon Jan 25 14:56:57 2016 -0800 +++ b/src/share/vm/gc_implementation/g1/g1RegionToSpaceMapper.hpp Mon Jan 25 14:57:27 2016 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 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 @@ -46,17 +46,20 @@ protected: // Backing storage. G1PageBasedVirtualSpace _storage; - size_t _commit_granularity; + size_t _region_granularity; // Mapping management BitMap _commit_map; - G1RegionToSpaceMapper(ReservedSpace rs, size_t commit_granularity, size_t region_granularity, MemoryType type); + G1RegionToSpaceMapper(ReservedSpace rs, size_t used_size, size_t page_size, size_t region_granularity, MemoryType type); void fire_on_commit(uint start_idx, size_t num_regions, bool zero_filled); public: MemRegion reserved() { return _storage.reserved(); } + size_t reserved_size() { return _storage.reserved_size(); } + size_t committed_size() { return _storage.committed_size(); } + void set_mapping_changed_listener(G1MappingChangedListener* listener) { _listener = listener; } virtual ~G1RegionToSpaceMapper() { @@ -67,16 +70,20 @@ return _commit_map.at(idx); } - virtual void commit_regions(uintptr_t start_idx, size_t num_regions = 1) = 0; - virtual void uncommit_regions(uintptr_t start_idx, size_t num_regions = 1) = 0; + virtual void commit_regions(uint start_idx, size_t num_regions = 1) = 0; + virtual void uncommit_regions(uint start_idx, size_t num_regions = 1) = 0; // Creates an appropriate G1RegionToSpaceMapper for the given parameters. + // The actual space to be used within the given reservation is given by actual_size. + // This is because some OSes need to round up the reservation size to guarantee + // alignment of page_size. // The byte_translation_factor defines how many bytes in a region correspond to // a single byte in the data structure this mapper is for. // Eg. in the card table, this value corresponds to the size a single card - // table entry corresponds to. + // table entry corresponds to in the heap. static G1RegionToSpaceMapper* create_mapper(ReservedSpace rs, - size_t os_commit_granularity, + size_t actual_size, + size_t page_size, size_t region_granularity, size_t byte_translation_factor, MemoryType type); diff -r c2687aa5e5ca -r 7eb99acd567f src/share/vm/gc_implementation/g1/g1RemSet.cpp --- a/src/share/vm/gc_implementation/g1/g1RemSet.cpp Mon Jan 25 14:56:57 2016 -0800 +++ b/src/share/vm/gc_implementation/g1/g1RemSet.cpp Mon Jan 25 14:57:27 2016 -0800 @@ -78,9 +78,8 @@ _cards_scanned(NULL), _total_cards_scanned(0), _prev_period_summary() { - _seq_task = new SubTasksDone(NumSeqTasks); guarantee(n_workers() > 0, "There should be some workers"); - _cset_rs_update_cl = NEW_C_HEAP_ARRAY(OopsInHeapRegionClosure*, n_workers(), mtGC); + _cset_rs_update_cl = NEW_C_HEAP_ARRAY(G1ParPushHeapRSClosure*, n_workers(), mtGC); for (uint i = 0; i < n_workers(); i++) { _cset_rs_update_cl[i] = NULL; } @@ -90,11 +89,10 @@ } G1RemSet::~G1RemSet() { - delete _seq_task; for (uint i = 0; i < n_workers(); i++) { assert(_cset_rs_update_cl[i] == NULL, "it should be"); } - FREE_C_HEAP_ARRAY(OopsInHeapRegionClosure*, _cset_rs_update_cl, mtGC); + FREE_C_HEAP_ARRAY(G1ParPushHeapRSClosure*, _cset_rs_update_cl, mtGC); } void CountNonCleanMemRegionClosure::do_MemRegion(MemRegion mr) { @@ -108,7 +106,7 @@ size_t _cards_done, _cards; G1CollectedHeap* _g1h; - OopsInHeapRegionClosure* _oc; + G1ParPushHeapRSClosure* _oc; CodeBlobClosure* _code_root_cl; G1BlockOffsetSharedArray* _bot_shared; @@ -120,7 +118,7 @@ bool _try_claimed; public: - ScanRSClosure(OopsInHeapRegionClosure* oc, + ScanRSClosure(G1ParPushHeapRSClosure* oc, CodeBlobClosure* code_root_cl, uint worker_i) : _oc(oc), @@ -142,16 +140,13 @@ void scanCard(size_t index, HeapRegion *r) { // Stack allocate the DirtyCardToOopClosure instance HeapRegionDCTOC cl(_g1h, r, _oc, - CardTableModRefBS::Precise, - HeapRegionDCTOC::IntoCSFilterKind); + CardTableModRefBS::Precise); // Set the "from" region in the closure. _oc->set_region(r); - HeapWord* card_start = _bot_shared->address_for_index(index); - HeapWord* card_end = card_start + G1BlockOffsetSharedArray::N_words; - Space *sp = SharedHeap::heap()->space_containing(card_start); - MemRegion sm_region = sp->used_region_at_save_marks(); - MemRegion mr = sm_region.intersection(MemRegion(card_start,card_end)); + MemRegion card_region(_bot_shared->address_for_index(index), G1BlockOffsetSharedArray::N_words); + MemRegion pre_gc_allocated(r->bottom(), r->scan_top()); + MemRegion mr = pre_gc_allocated.intersection(card_region); if (!mr.is_empty() && !_ct_bs->is_card_claimed(index)) { // We make the card as "claimed" lazily (so races are possible // but they're benign), which reduces the number of duplicate @@ -240,7 +235,7 @@ size_t cards_looked_up() { return _cards;} }; -void G1RemSet::scanRS(OopsInHeapRegionClosure* oc, +void G1RemSet::scanRS(G1ParPushHeapRSClosure* oc, CodeBlobClosure* code_root_cl, uint worker_i) { double rs_time_start = os::elapsedTime(); @@ -258,9 +253,8 @@ assert(_cards_scanned != NULL, "invariant"); _cards_scanned[worker_i] = scanRScl.cards_done(); - _g1p->phase_times()->record_scan_rs_time(worker_i, scan_rs_time_sec * 1000.0); - _g1p->phase_times()->record_strong_code_root_scan_time(worker_i, - scanRScl.strong_code_root_scan_time_sec() * 1000.0); + _g1p->phase_times()->record_time_secs(G1GCPhaseTimes::ScanRS, worker_i, scan_rs_time_sec); + _g1p->phase_times()->record_time_secs(G1GCPhaseTimes::CodeRoots, worker_i, scanRScl.strong_code_root_scan_time_sec()); } // Closure used for updating RSets and recording references that @@ -297,29 +291,18 @@ }; void G1RemSet::updateRS(DirtyCardQueue* into_cset_dcq, uint worker_i) { - double start = os::elapsedTime(); + G1GCParPhaseTimesTracker x(_g1p->phase_times(), G1GCPhaseTimes::UpdateRS, worker_i); // Apply the given closure to all remaining log entries. RefineRecordRefsIntoCSCardTableEntryClosure into_cset_update_rs_cl(_g1, into_cset_dcq); _g1->iterate_dirty_card_closure(&into_cset_update_rs_cl, into_cset_dcq, false, worker_i); - - // Now there should be no dirty cards. - if (G1RSLogCheckCardTable) { - CountNonCleanMemRegionClosure cl(_g1); - _ct_bs->mod_card_iterate(&cl); - // XXX This isn't true any more: keeping cards of young regions - // marked dirty broke it. Need some reasonable fix. - guarantee(cl.n() == 0, "Card table should be clean."); - } - - _g1p->phase_times()->record_update_rs_time(worker_i, (os::elapsedTime() - start) * 1000.0); } void G1RemSet::cleanupHRRS() { HeapRegionRemSet::cleanup(); } -void G1RemSet::oops_into_collection_set_do(OopsInHeapRegionClosure* oc, +void G1RemSet::oops_into_collection_set_do(G1ParPushHeapRSClosure* oc, CodeBlobClosure* code_root_cl, uint worker_i) { #if CARD_REPEAT_HISTO @@ -344,23 +327,8 @@ assert((ParallelGCThreads > 0) || worker_i == 0, "invariant"); - // The two flags below were introduced temporarily to serialize - // the updating and scanning of remembered sets. There are some - // race conditions when these two operations are done in parallel - // and they are causing failures. When we resolve said race - // conditions, we'll revert back to parallel remembered set - // updating and scanning. See CRs 6677707 and 6677708. - if (G1UseParallelRSetUpdating || (worker_i == 0)) { - updateRS(&into_cset_dcq, worker_i); - } else { - _g1p->phase_times()->record_update_rs_processed_buffers(worker_i, 0); - _g1p->phase_times()->record_update_rs_time(worker_i, 0.0); - } - if (G1UseParallelRSetScanning || (worker_i == 0)) { - scanRS(oc, code_root_cl, worker_i); - } else { - _g1p->phase_times()->record_scan_rs_time(worker_i, 0.0); - } + updateRS(&into_cset_dcq, worker_i); + scanRS(oc, code_root_cl, worker_i); // We now clear the cached values of _cset_rs_update_cl for this worker _cset_rs_update_cl[worker_i] = NULL; @@ -461,7 +429,7 @@ G1UpdateRSOrPushRefOopClosure:: G1UpdateRSOrPushRefOopClosure(G1CollectedHeap* g1h, G1RemSet* rs, - OopsInHeapRegionClosure* push_ref_cl, + G1ParPushHeapRSClosure* push_ref_cl, bool record_refs_into_cset, uint worker_i) : _g1(g1h), _g1_rem_set(rs), _from(NULL), @@ -562,7 +530,7 @@ ct_freq_note_card(_ct_bs->index_for(start)); #endif - OopsInHeapRegionClosure* oops_in_heap_closure = NULL; + G1ParPushHeapRSClosure* oops_in_heap_closure = NULL; if (check_for_refs_into_cset) { // ConcurrentG1RefineThreads have worker numbers larger than what // _cset_rs_update_cl[] is set up to handle. But those threads should diff -r c2687aa5e5ca -r 7eb99acd567f src/share/vm/gc_implementation/g1/g1RemSet.hpp --- a/src/share/vm/gc_implementation/g1/g1RemSet.hpp Mon Jan 25 14:56:57 2016 -0800 +++ b/src/share/vm/gc_implementation/g1/g1RemSet.hpp Mon Jan 25 14:57:27 2016 -0800 @@ -33,6 +33,7 @@ class G1CollectedHeap; class CardTableModRefBarrierSet; class ConcurrentG1Refine; +class G1ParPushHeapRSClosure; // A G1RemSet in which each heap region has a rem set that records the // external heap references into it. Uses a mod ref bs to track updates, @@ -58,7 +59,6 @@ }; CardTableModRefBS* _ct_bs; - SubTasksDone* _seq_task; G1CollectorPolicy* _g1p; ConcurrentG1Refine* _cg1r; @@ -68,7 +68,7 @@ // Used for caching the closure that is responsible for scanning // references into the collection set. - OopsInHeapRegionClosure** _cset_rs_update_cl; + G1ParPushHeapRSClosure** _cset_rs_update_cl; // Print the given summary info virtual void print_summary_info(G1RemSetSummary * summary, const char * header = NULL); @@ -95,7 +95,7 @@ // partitioning the work to be done. It should be the same as // the "i" passed to the calling thread's work(i) function. // In the sequential case this param will be ignored. - void oops_into_collection_set_do(OopsInHeapRegionClosure* blk, + void oops_into_collection_set_do(G1ParPushHeapRSClosure* blk, CodeBlobClosure* code_root_cl, uint worker_i); @@ -107,7 +107,7 @@ void prepare_for_oops_into_collection_set_do(); void cleanup_after_oops_into_collection_set_do(); - void scanRS(OopsInHeapRegionClosure* oc, + void scanRS(G1ParPushHeapRSClosure* oc, CodeBlobClosure* code_root_cl, uint worker_i); diff -r c2687aa5e5ca -r 7eb99acd567f src/share/vm/gc_implementation/g1/g1RootProcessor.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/share/vm/gc_implementation/g1/g1RootProcessor.cpp Mon Jan 25 14:57:27 2016 -0800 @@ -0,0 +1,352 @@ +/* + * Copyright (c) 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 + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +#include "precompiled.hpp" + +#include "classfile/symbolTable.hpp" +#include "classfile/systemDictionary.hpp" +#include "code/codeCache.hpp" +#include "gc_implementation/g1/bufferingOopClosure.hpp" +#include "gc_implementation/g1/g1CollectedHeap.inline.hpp" +#include "gc_implementation/g1/g1CollectorPolicy.hpp" +#include "gc_implementation/g1/g1GCPhaseTimes.hpp" +#include "gc_implementation/g1/g1RemSet.inline.hpp" +#include "gc_implementation/g1/g1RootProcessor.hpp" +#include "memory/allocation.inline.hpp" +#include "runtime/fprofiler.hpp" +#include "runtime/mutex.hpp" +#include "services/management.hpp" + +class G1CodeBlobClosure : public CodeBlobClosure { + class HeapRegionGatheringOopClosure : public OopClosure { + G1CollectedHeap* _g1h; + OopClosure* _work; + nmethod* _nm; + + template + void do_oop_work(T* p) { + _work->do_oop(p); + T oop_or_narrowoop = oopDesc::load_heap_oop(p); + if (!oopDesc::is_null(oop_or_narrowoop)) { + oop o = oopDesc::decode_heap_oop_not_null(oop_or_narrowoop); + HeapRegion* hr = _g1h->heap_region_containing_raw(o); + assert(!_g1h->obj_in_cs(o) || hr->rem_set()->strong_code_roots_list_contains(_nm), "if o still in CS then evacuation failed and nm must already be in the remset"); + hr->add_strong_code_root(_nm); + } + } + + public: + HeapRegionGatheringOopClosure(OopClosure* oc) : _g1h(G1CollectedHeap::heap()), _work(oc), _nm(NULL) {} + + void do_oop(oop* o) { + do_oop_work(o); + } + + void do_oop(narrowOop* o) { + do_oop_work(o); + } + + void set_nm(nmethod* nm) { + _nm = nm; + } + }; + + HeapRegionGatheringOopClosure _oc; +public: + G1CodeBlobClosure(OopClosure* oc) : _oc(oc) {} + + void do_code_blob(CodeBlob* cb) { + nmethod* nm = cb->as_nmethod_or_null(); + if (nm != NULL) { + if (!nm->test_set_oops_do_mark()) { + _oc.set_nm(nm); + nm->oops_do(&_oc); + nm->fix_oop_relocations(); + } + } + } +}; + + +void G1RootProcessor::worker_has_discovered_all_strong_classes() { + uint n_workers = _g1h->n_par_threads(); + assert(ClassUnloadingWithConcurrentMark, "Currently only needed when doing G1 Class Unloading"); + + if (n_workers > 0) { + uint new_value = (uint)Atomic::add(1, &_n_workers_discovered_strong_classes); + if (new_value == n_workers) { + // This thread is last. Notify the others. + MonitorLockerEx ml(&_lock, Mutex::_no_safepoint_check_flag); + _lock.notify_all(); + } + } +} + +void G1RootProcessor::wait_until_all_strong_classes_discovered() { + uint n_workers = _g1h->n_par_threads(); + assert(ClassUnloadingWithConcurrentMark, "Currently only needed when doing G1 Class Unloading"); + + if (n_workers > 0 && (uint)_n_workers_discovered_strong_classes != n_workers) { + MonitorLockerEx ml(&_lock, Mutex::_no_safepoint_check_flag); + while ((uint)_n_workers_discovered_strong_classes != n_workers) { + _lock.wait(Mutex::_no_safepoint_check_flag, 0, false); + } + } +} + +G1RootProcessor::G1RootProcessor(G1CollectedHeap* g1h) : + _g1h(g1h), + _process_strong_tasks(new SubTasksDone(G1RP_PS_NumElements)), + _srs(g1h), + _lock(Mutex::leaf, "G1 Root Scanning barrier lock", false), + _n_workers_discovered_strong_classes(0) {} + +void G1RootProcessor::evacuate_roots(OopClosure* scan_non_heap_roots, + OopClosure* scan_non_heap_weak_roots, + CLDClosure* scan_strong_clds, + CLDClosure* scan_weak_clds, + bool trace_metadata, + uint worker_i) { + // First scan the shared roots. + double ext_roots_start = os::elapsedTime(); + G1GCPhaseTimes* phase_times = _g1h->g1_policy()->phase_times(); + + BufferingOopClosure buf_scan_non_heap_roots(scan_non_heap_roots); + BufferingOopClosure buf_scan_non_heap_weak_roots(scan_non_heap_weak_roots); + + OopClosure* const weak_roots = &buf_scan_non_heap_weak_roots; + OopClosure* const strong_roots = &buf_scan_non_heap_roots; + + bool trace_codecache = false; +#if INCLUDE_JVMCI + bool during_im = _g1h->g1_policy()->during_initial_mark_pause(); + // Without eager nmethod unloading, we need to treat all oops in code cache as strong during the initial mark + trace_codecache = during_im && !ClassUnloadingWithConcurrentMark; +#endif + + // CodeBlobClosures are not interoperable with BufferingOopClosures + G1CodeBlobClosure root_code_blobs(scan_non_heap_roots); + + process_java_roots(strong_roots, + trace_metadata ? scan_strong_clds : NULL, + scan_strong_clds, + trace_metadata ? NULL : scan_weak_clds, + trace_codecache ? NULL : &root_code_blobs, + phase_times, + worker_i); + + // This is the point where this worker thread will not find more strong CLDs/nmethods. + // Report this so G1 can synchronize the strong and weak CLDs/nmethods processing. + if (trace_metadata) { + worker_has_discovered_all_strong_classes(); + } + + process_vm_roots(strong_roots, weak_roots, phase_times, worker_i); + +#if INCLUDE_JVMCI + if (trace_codecache && !_process_strong_tasks->is_task_claimed(G1RP_PS_CodeCache_oops_do)) { + CodeCache::blobs_do(&root_code_blobs); + } +#endif + + { + // Now the CM ref_processor roots. + G1GCParPhaseTimesTracker x(phase_times, G1GCPhaseTimes::CMRefRoots, worker_i); + if (!_process_strong_tasks->is_task_claimed(G1RP_PS_refProcessor_oops_do)) { + // We need to treat the discovered reference lists of the + // concurrent mark ref processor as roots and keep entries + // (which are added by the marking threads) on them live + // until they can be processed at the end of marking. + _g1h->ref_processor_cm()->weak_oops_do(&buf_scan_non_heap_roots); + } + } + + if (trace_metadata) { + { + G1GCParPhaseTimesTracker x(phase_times, G1GCPhaseTimes::WaitForStrongCLD, worker_i); + // Barrier to make sure all workers passed + // the strong CLD and strong nmethods phases. + wait_until_all_strong_classes_discovered(); + } + + // Now take the complement of the strong CLDs. + G1GCParPhaseTimesTracker x(phase_times, G1GCPhaseTimes::WeakCLDRoots, worker_i); + ClassLoaderDataGraph::roots_cld_do(NULL, scan_weak_clds); + } else { + phase_times->record_time_secs(G1GCPhaseTimes::WaitForStrongCLD, worker_i, 0.0); + phase_times->record_time_secs(G1GCPhaseTimes::WeakCLDRoots, worker_i, 0.0); + } + + // Finish up any enqueued closure apps (attributed as object copy time). + buf_scan_non_heap_roots.done(); + buf_scan_non_heap_weak_roots.done(); + + double obj_copy_time_sec = buf_scan_non_heap_roots.closure_app_seconds() + + buf_scan_non_heap_weak_roots.closure_app_seconds(); + + phase_times->record_time_secs(G1GCPhaseTimes::ObjCopy, worker_i, obj_copy_time_sec); + + double ext_root_time_sec = os::elapsedTime() - ext_roots_start - obj_copy_time_sec; + + phase_times->record_time_secs(G1GCPhaseTimes::ExtRootScan, worker_i, ext_root_time_sec); + + // During conc marking we have to filter the per-thread SATB buffers + // to make sure we remove any oops into the CSet (which will show up + // as implicitly live). + { + G1GCParPhaseTimesTracker x(phase_times, G1GCPhaseTimes::SATBFiltering, worker_i); + if (!_process_strong_tasks->is_task_claimed(G1RP_PS_filter_satb_buffers) && _g1h->mark_in_progress()) { + JavaThread::satb_mark_queue_set().filter_thread_buffers(); + } + } + + _process_strong_tasks->all_tasks_completed(); +} + +void G1RootProcessor::process_strong_roots(OopClosure* oops, + CLDClosure* clds, + CodeBlobClosure* blobs) { + + process_java_roots(oops, clds, clds, NULL, blobs, NULL, 0); + process_vm_roots(oops, NULL, NULL, 0); + + _process_strong_tasks->all_tasks_completed(); +} + +void G1RootProcessor::process_all_roots(OopClosure* oops, + CLDClosure* clds, + CodeBlobClosure* blobs) { + + process_java_roots(oops, NULL, clds, clds, NULL, NULL, 0); + process_vm_roots(oops, oops, NULL, 0); + + if (!_process_strong_tasks->is_task_claimed(G1RP_PS_CodeCache_oops_do)) { + CodeCache::blobs_do(blobs); + } + + _process_strong_tasks->all_tasks_completed(); +} + +void G1RootProcessor::process_java_roots(OopClosure* strong_roots, + CLDClosure* thread_stack_clds, + CLDClosure* strong_clds, + CLDClosure* weak_clds, + CodeBlobClosure* strong_code, + G1GCPhaseTimes* phase_times, + uint worker_i) { + assert(thread_stack_clds == NULL || weak_clds == NULL, "There is overlap between those, only one may be set"); + // Iterating over the CLDG and the Threads are done early to allow us to + // first process the strong CLDs and nmethods and then, after a barrier, + // let the thread process the weak CLDs and nmethods. + { + G1GCParPhaseTimesTracker x(phase_times, G1GCPhaseTimes::CLDGRoots, worker_i); + if (!_process_strong_tasks->is_task_claimed(G1RP_PS_ClassLoaderDataGraph_oops_do)) { + ClassLoaderDataGraph::roots_cld_do(strong_clds, weak_clds); + } + } + + { + G1GCParPhaseTimesTracker x(phase_times, G1GCPhaseTimes::ThreadRoots, worker_i); + Threads::possibly_parallel_oops_do(strong_roots, thread_stack_clds, strong_code); + } +} + +void G1RootProcessor::process_vm_roots(OopClosure* strong_roots, + OopClosure* weak_roots, + G1GCPhaseTimes* phase_times, + uint worker_i) { + { + G1GCParPhaseTimesTracker x(phase_times, G1GCPhaseTimes::UniverseRoots, worker_i); + if (!_process_strong_tasks->is_task_claimed(G1RP_PS_Universe_oops_do)) { + Universe::oops_do(strong_roots); + } + } + + { + G1GCParPhaseTimesTracker x(phase_times, G1GCPhaseTimes::JNIRoots, worker_i); + if (!_process_strong_tasks->is_task_claimed(G1RP_PS_JNIHandles_oops_do)) { + JNIHandles::oops_do(strong_roots); + } + } + + { + G1GCParPhaseTimesTracker x(phase_times, G1GCPhaseTimes::ObjectSynchronizerRoots, worker_i); + if (!_process_strong_tasks-> is_task_claimed(G1RP_PS_ObjectSynchronizer_oops_do)) { + ObjectSynchronizer::oops_do(strong_roots); + } + } + + { + G1GCParPhaseTimesTracker x(phase_times, G1GCPhaseTimes::FlatProfilerRoots, worker_i); + if (!_process_strong_tasks->is_task_claimed(G1RP_PS_FlatProfiler_oops_do)) { + FlatProfiler::oops_do(strong_roots); + } + } + + { + G1GCParPhaseTimesTracker x(phase_times, G1GCPhaseTimes::ManagementRoots, worker_i); + if (!_process_strong_tasks->is_task_claimed(G1RP_PS_Management_oops_do)) { + Management::oops_do(strong_roots); + } + } + + { + G1GCParPhaseTimesTracker x(phase_times, G1GCPhaseTimes::JVMTIRoots, worker_i); + if (!_process_strong_tasks->is_task_claimed(G1RP_PS_jvmti_oops_do)) { + JvmtiExport::oops_do(strong_roots); + } + } + + { + G1GCParPhaseTimesTracker x(phase_times, G1GCPhaseTimes::SystemDictionaryRoots, worker_i); + if (!_process_strong_tasks->is_task_claimed(G1RP_PS_SystemDictionary_oops_do)) { + SystemDictionary::roots_oops_do(strong_roots, weak_roots); + } + } + + { + G1GCParPhaseTimesTracker x(phase_times, G1GCPhaseTimes::StringTableRoots, worker_i); + // All threads execute the following. A specific chunk of buckets + // from the StringTable are the individual tasks. + if (weak_roots != NULL) { + StringTable::possibly_parallel_oops_do(weak_roots); + } + } +} + +void G1RootProcessor::scan_remembered_sets(G1ParPushHeapRSClosure* scan_rs, + OopClosure* scan_non_heap_weak_roots, + uint worker_i) { + G1GCPhaseTimes* phase_times = _g1h->g1_policy()->phase_times(); + G1GCParPhaseTimesTracker x(phase_times, G1GCPhaseTimes::CodeCacheRoots, worker_i); + + // Now scan the complement of the collection set. + G1CodeBlobClosure scavenge_cs_nmethods(scan_non_heap_weak_roots); + + _g1h->g1_rem_set()->oops_into_collection_set_do(scan_rs, &scavenge_cs_nmethods, worker_i); +} + +void G1RootProcessor::set_num_workers(int active_workers) { + _process_strong_tasks->set_n_threads(active_workers); +} diff -r c2687aa5e5ca -r 7eb99acd567f src/share/vm/gc_implementation/g1/g1RootProcessor.hpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/share/vm/gc_implementation/g1/g1RootProcessor.hpp Mon Jan 25 14:57:27 2016 -0800 @@ -0,0 +1,121 @@ +/* + * Copyright (c) 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 + * 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_ROOTPROCESSOR_HPP +#define SHARE_VM_GC_IMPLEMENTATION_G1_ROOTPROCESSOR_HPP + +#include "memory/allocation.hpp" +#include "memory/sharedHeap.hpp" +#include "runtime/mutex.hpp" + +class CLDClosure; +class CodeBlobClosure; +class G1CollectedHeap; +class G1GCPhaseTimes; +class G1ParPushHeapRSClosure; +class Monitor; +class OopClosure; +class SubTasksDone; + +// Scoped object to assist in applying oop, CLD and code blob closures to +// root locations. Handles claiming of different root scanning tasks +// and takes care of global state for root scanning via a StrongRootsScope. +// In the parallel case there is a shared G1RootProcessor object where all +// worker thread call the process_roots methods. +class G1RootProcessor : public StackObj { + G1CollectedHeap* _g1h; + SubTasksDone* _process_strong_tasks; + SharedHeap::StrongRootsScope _srs; + + // Used to implement the Thread work barrier. + Monitor _lock; + volatile jint _n_workers_discovered_strong_classes; + + enum G1H_process_roots_tasks { + G1RP_PS_Universe_oops_do, + G1RP_PS_JNIHandles_oops_do, + G1RP_PS_ObjectSynchronizer_oops_do, + G1RP_PS_FlatProfiler_oops_do, + G1RP_PS_Management_oops_do, + G1RP_PS_SystemDictionary_oops_do, + G1RP_PS_ClassLoaderDataGraph_oops_do, + G1RP_PS_jvmti_oops_do, + G1RP_PS_CodeCache_oops_do, + G1RP_PS_filter_satb_buffers, + G1RP_PS_refProcessor_oops_do, + // Leave this one last. + G1RP_PS_NumElements + }; + + void worker_has_discovered_all_strong_classes(); + void wait_until_all_strong_classes_discovered(); + + void process_java_roots(OopClosure* scan_non_heap_roots, + CLDClosure* thread_stack_clds, + CLDClosure* scan_strong_clds, + CLDClosure* scan_weak_clds, + CodeBlobClosure* scan_strong_code, + G1GCPhaseTimes* phase_times, + uint worker_i); + + void process_vm_roots(OopClosure* scan_non_heap_roots, + OopClosure* scan_non_heap_weak_roots, + G1GCPhaseTimes* phase_times, + uint worker_i); + +public: + G1RootProcessor(G1CollectedHeap* g1h); + + // Apply closures to the strongly and weakly reachable roots in the system + // in a single pass. + // Record and report timing measurements for sub phases using the worker_i + void evacuate_roots(OopClosure* scan_non_heap_roots, + OopClosure* scan_non_heap_weak_roots, + CLDClosure* scan_strong_clds, + CLDClosure* scan_weak_clds, + bool trace_metadata, + uint worker_i); + + // Apply oops, clds and blobs to all strongly reachable roots in the system + void process_strong_roots(OopClosure* oops, + CLDClosure* clds, + CodeBlobClosure* blobs); + + // Apply oops, clds and blobs to strongly and weakly reachable roots in the system + void process_all_roots(OopClosure* oops, + CLDClosure* clds, + CodeBlobClosure* blobs); + + // Apply scan_rs to all locations in the union of the remembered sets for all + // regions in the collection set + // (having done "set_region" to indicate the region in which the root resides), + void scan_remembered_sets(G1ParPushHeapRSClosure* scan_rs, + OopClosure* scan_non_heap_weak_roots, + uint worker_i); + + // Inform the root processor about the number of worker threads + void set_num_workers(int active_workers); +}; + +#endif // SHARE_VM_GC_IMPLEMENTATION_G1_ROOTPROCESSOR_HPP diff -r c2687aa5e5ca -r 7eb99acd567f src/share/vm/gc_implementation/g1/g1StringDedup.cpp --- a/src/share/vm/gc_implementation/g1/g1StringDedup.cpp Mon Jan 25 14:56:57 2016 -0800 +++ b/src/share/vm/gc_implementation/g1/g1StringDedup.cpp Mon Jan 25 14:57:27 2016 -0800 @@ -105,7 +105,7 @@ void G1StringDedup::oops_do(OopClosure* keep_alive) { assert(is_enabled(), "String deduplication not enabled"); - unlink_or_oops_do(NULL, keep_alive); + unlink_or_oops_do(NULL, keep_alive, true /* allow_resize_and_rehash */); } void G1StringDedup::unlink(BoolObjectClosure* is_alive) { @@ -122,37 +122,35 @@ class G1StringDedupUnlinkOrOopsDoTask : public AbstractGangTask { private: G1StringDedupUnlinkOrOopsDoClosure _cl; + G1GCPhaseTimes* _phase_times; public: G1StringDedupUnlinkOrOopsDoTask(BoolObjectClosure* is_alive, OopClosure* keep_alive, - bool allow_resize_and_rehash) : + bool allow_resize_and_rehash, + G1GCPhaseTimes* phase_times) : AbstractGangTask("G1StringDedupUnlinkOrOopsDoTask"), - _cl(is_alive, keep_alive, allow_resize_and_rehash) { - } + _cl(is_alive, keep_alive, allow_resize_and_rehash), _phase_times(phase_times) { } virtual void work(uint worker_id) { - double queue_fixup_start = os::elapsedTime(); - G1StringDedupQueue::unlink_or_oops_do(&_cl); - - double table_fixup_start = os::elapsedTime(); - G1StringDedupTable::unlink_or_oops_do(&_cl, worker_id); - - double queue_fixup_time_ms = (table_fixup_start - queue_fixup_start) * 1000.0; - double table_fixup_time_ms = (os::elapsedTime() - table_fixup_start) * 1000.0; - G1CollectorPolicy* g1p = G1CollectedHeap::heap()->g1_policy(); - g1p->phase_times()->record_string_dedup_queue_fixup_worker_time(worker_id, queue_fixup_time_ms); - g1p->phase_times()->record_string_dedup_table_fixup_worker_time(worker_id, table_fixup_time_ms); + { + G1GCParPhaseTimesTracker x(_phase_times, G1GCPhaseTimes::StringDedupQueueFixup, worker_id); + G1StringDedupQueue::unlink_or_oops_do(&_cl); + } + { + G1GCParPhaseTimesTracker x(_phase_times, G1GCPhaseTimes::StringDedupTableFixup, worker_id); + G1StringDedupTable::unlink_or_oops_do(&_cl, worker_id); + } } }; -void G1StringDedup::unlink_or_oops_do(BoolObjectClosure* is_alive, OopClosure* keep_alive, bool allow_resize_and_rehash) { +void G1StringDedup::unlink_or_oops_do(BoolObjectClosure* is_alive, + OopClosure* keep_alive, + bool allow_resize_and_rehash, + G1GCPhaseTimes* phase_times) { assert(is_enabled(), "String deduplication not enabled"); - G1CollectorPolicy* g1p = G1CollectedHeap::heap()->g1_policy(); - g1p->phase_times()->note_string_dedup_fixup_start(); - double fixup_start = os::elapsedTime(); - G1StringDedupUnlinkOrOopsDoTask task(is_alive, keep_alive, allow_resize_and_rehash); + G1StringDedupUnlinkOrOopsDoTask task(is_alive, keep_alive, allow_resize_and_rehash, phase_times); if (G1CollectedHeap::use_parallel_gc_threads()) { G1CollectedHeap* g1h = G1CollectedHeap::heap(); g1h->set_par_threads(); @@ -161,10 +159,6 @@ } else { task.work(0); } - - double fixup_time_ms = (os::elapsedTime() - fixup_start) * 1000.0; - g1p->phase_times()->record_string_dedup_fixup_time(fixup_time_ms); - g1p->phase_times()->note_string_dedup_fixup_end(); } void G1StringDedup::threads_do(ThreadClosure* tc) { diff -r c2687aa5e5ca -r 7eb99acd567f src/share/vm/gc_implementation/g1/g1StringDedup.hpp --- a/src/share/vm/gc_implementation/g1/g1StringDedup.hpp Mon Jan 25 14:56:57 2016 -0800 +++ b/src/share/vm/gc_implementation/g1/g1StringDedup.hpp Mon Jan 25 14:57:27 2016 -0800 @@ -90,6 +90,7 @@ class ThreadClosure; class outputStream; class G1StringDedupTable; +class G1GCPhaseTimes; // // Main interface for interacting with string deduplication. @@ -130,7 +131,7 @@ static void oops_do(OopClosure* keep_alive); static void unlink(BoolObjectClosure* is_alive); static void unlink_or_oops_do(BoolObjectClosure* is_alive, OopClosure* keep_alive, - bool allow_resize_and_rehash = true); + bool allow_resize_and_rehash, G1GCPhaseTimes* phase_times = NULL); static void threads_do(ThreadClosure* tc); static void print_worker_threads_on(outputStream* st); diff -r c2687aa5e5ca -r 7eb99acd567f src/share/vm/gc_implementation/g1/g1_globals.hpp --- a/src/share/vm/gc_implementation/g1/g1_globals.hpp Mon Jan 25 14:56:57 2016 -0800 +++ b/src/share/vm/gc_implementation/g1/g1_globals.hpp Mon Jan 25 14:57:27 2016 -0800 @@ -217,14 +217,6 @@ product(uintx, G1HeapRegionSize, 0, \ "Size of the G1 regions.") \ \ - experimental(bool, G1UseParallelRSetUpdating, true, \ - "Enables the parallelization of remembered set updating " \ - "during evacuation pauses") \ - \ - experimental(bool, G1UseParallelRSetScanning, true, \ - "Enables the parallelization of remembered set scanning " \ - "during evacuation pauses") \ - \ product(uintx, G1ConcRefinementThreads, 0, \ "If non-0 is the number of parallel rem set update threads, " \ "otherwise the value is determined ergonomically.") \ @@ -282,10 +274,14 @@ product(uintx, G1MixedGCCountTarget, 8, \ "The target number of mixed GCs after a marking cycle.") \ \ - experimental(bool, G1ReclaimDeadHumongousObjectsAtYoungGC, true, \ + experimental(bool, G1EagerReclaimHumongousObjects, true, \ "Try to reclaim dead large objects at every young GC.") \ \ - experimental(bool, G1TraceReclaimDeadHumongousObjectsAtYoungGC, false, \ + experimental(bool, G1EagerReclaimHumongousObjectsWithStaleRefs, true, \ + "Try to reclaim dead large objects that have a few stale " \ + "references at every young GC.") \ + \ + experimental(bool, G1TraceEagerReclaimHumongousObjects, false, \ "Print some information about large object liveness " \ "at every young GC.") \ \ diff -r c2687aa5e5ca -r 7eb99acd567f src/share/vm/gc_implementation/g1/heapRegion.cpp --- a/src/share/vm/gc_implementation/g1/heapRegion.cpp Mon Jan 25 14:56:57 2016 -0800 +++ b/src/share/vm/gc_implementation/g1/heapRegion.cpp Mon Jan 25 14:57:27 2016 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 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 @@ -47,93 +47,55 @@ size_t HeapRegion::CardsPerRegion = 0; HeapRegionDCTOC::HeapRegionDCTOC(G1CollectedHeap* g1, - HeapRegion* hr, ExtendedOopClosure* cl, - CardTableModRefBS::PrecisionStyle precision, - FilterKind fk) : + HeapRegion* hr, + G1ParPushHeapRSClosure* cl, + CardTableModRefBS::PrecisionStyle precision) : DirtyCardToOopClosure(hr, cl, precision, NULL), - _hr(hr), _fk(fk), _g1(g1) { } + _hr(hr), _rs_scan(cl), _g1(g1) { } FilterOutOfRegionClosure::FilterOutOfRegionClosure(HeapRegion* r, OopClosure* oc) : _r_bottom(r->bottom()), _r_end(r->end()), _oc(oc) { } -template -HeapWord* walk_mem_region_loop(ClosureType* cl, G1CollectedHeap* g1h, - HeapRegion* hr, - HeapWord* cur, HeapWord* top) { - oop cur_oop = oop(cur); - size_t oop_size = hr->block_size(cur); - HeapWord* next_obj = cur + oop_size; - while (next_obj < top) { - // Keep filtering the remembered set. - if (!g1h->is_obj_dead(cur_oop, hr)) { - // Bottom lies entirely below top, so we can call the - // non-memRegion version of oop_iterate below. - cur_oop->oop_iterate(cl); - } - cur = next_obj; - cur_oop = oop(cur); - oop_size = hr->block_size(cur); - next_obj = cur + oop_size; - } - return cur; -} - void HeapRegionDCTOC::walk_mem_region(MemRegion mr, HeapWord* bottom, HeapWord* top) { G1CollectedHeap* g1h = _g1; size_t oop_size; - ExtendedOopClosure* cl2 = NULL; - - FilterIntoCSClosure intoCSFilt(this, g1h, _cl); - FilterOutOfRegionClosure outOfRegionFilt(_hr, _cl); - - switch (_fk) { - case NoFilterKind: cl2 = _cl; break; - case IntoCSFilterKind: cl2 = &intoCSFilt; break; - case OutOfRegionFilterKind: cl2 = &outOfRegionFilt; break; - default: ShouldNotReachHere(); - } + HeapWord* cur = bottom; // Start filtering what we add to the remembered set. If the object is // not considered dead, either because it is marked (in the mark bitmap) // or it was allocated after marking finished, then we add it. Otherwise // we can safely ignore the object. - if (!g1h->is_obj_dead(oop(bottom), _hr)) { - oop_size = oop(bottom)->oop_iterate(cl2, mr); + if (!g1h->is_obj_dead(oop(cur), _hr)) { + oop_size = oop(cur)->oop_iterate(_rs_scan, mr); } else { - oop_size = _hr->block_size(bottom); + oop_size = _hr->block_size(cur); } - bottom += oop_size; - - if (bottom < top) { - // We replicate the loop below for several kinds of possible filters. - switch (_fk) { - case NoFilterKind: - bottom = walk_mem_region_loop(_cl, g1h, _hr, bottom, top); - break; + cur += oop_size; - case IntoCSFilterKind: { - FilterIntoCSClosure filt(this, g1h, _cl); - bottom = walk_mem_region_loop(&filt, g1h, _hr, bottom, top); - break; - } - - case OutOfRegionFilterKind: { - FilterOutOfRegionClosure filt(_hr, _cl); - bottom = walk_mem_region_loop(&filt, g1h, _hr, bottom, top); - break; - } - - default: - ShouldNotReachHere(); + if (cur < top) { + oop cur_oop = oop(cur); + oop_size = _hr->block_size(cur); + HeapWord* next_obj = cur + oop_size; + while (next_obj < top) { + // Keep filtering the remembered set. + if (!g1h->is_obj_dead(cur_oop, _hr)) { + // Bottom lies entirely below top, so we can call the + // non-memRegion version of oop_iterate below. + cur_oop->oop_iterate(_rs_scan); + } + cur = next_obj; + cur_oop = oop(cur); + oop_size = _hr->block_size(cur); + next_obj = cur + oop_size; } // Last object. Need to do dead-obj filtering here too. - if (!g1h->is_obj_dead(oop(bottom), _hr)) { - oop(bottom)->oop_iterate(cl2, mr); + if (!g1h->is_obj_dead(oop(cur), _hr)) { + oop(cur)->oop_iterate(_rs_scan, mr); } } } @@ -338,7 +300,7 @@ _orig_end = mr.end(); hr_clear(false /*par*/, false /*clear_space*/); set_top(bottom()); - record_top_and_timestamp(); + record_timestamp(); } CompactibleSpace* HeapRegion::next_compaction_space() const { @@ -426,9 +388,9 @@ // If we're within a stop-world GC, then we might look at a card in a // GC alloc region that extends onto a GC LAB, which may not be - // parseable. Stop such at the "saved_mark" of the region. + // parseable. Stop such at the "scan_top" of the region. if (g1h->is_gc_active()) { - mr = mr.intersection(used_region_at_save_marks()); + mr = mr.intersection(MemRegion(bottom(), scan_top())); } else { mr = mr.intersection(used_region()); } @@ -468,7 +430,7 @@ oop obj; HeapWord* next = cur; - while (next <= start) { + do { cur = next; obj = oop(cur); if (obj->klass_or_null() == NULL) { @@ -477,45 +439,38 @@ } // Otherwise... next = cur + block_size(cur); - } + } while (next <= start); // If we finish the above loop...We have a parseable object that // begins on or before the start of the memory region, and ends // inside or spans the entire region. - - assert(obj == oop(cur), "sanity"); assert(cur <= start, "Loop postcondition"); assert(obj->klass_or_null() != NULL, "Loop postcondition"); - assert((cur + block_size(cur)) > start, "Loop postcondition"); - if (!g1h->is_obj_dead(obj)) { - obj->oop_iterate(cl, mr); - } - - while (cur < end) { + do { obj = oop(cur); + assert((cur + block_size(cur)) > (HeapWord*)obj, "Loop invariant"); if (obj->klass_or_null() == NULL) { // Ran into an unparseable point. return cur; - }; + } - // Otherwise: - next = cur + block_size(cur); + // Advance the current pointer. "obj" still points to the object to iterate. + cur = cur + block_size(cur); if (!g1h->is_obj_dead(obj)) { - if (next < end || !obj->is_objArray()) { - // This object either does not span the MemRegion - // boundary, or if it does it's not an array. - // Apply closure to whole object. + // Non-objArrays are sometimes marked imprecise at the object start. We + // always need to iterate over them in full. + // We only iterate over object arrays in full if they are completely contained + // in the memory region. + if (!obj->is_objArray() || (((HeapWord*)obj) >= start && cur <= end)) { obj->oop_iterate(cl); } else { - // This obj is an array that spans the boundary. - // Stop at the boundary. obj->oop_iterate(cl, mr); } } - cur = next; - } + } while (cur < end); + return NULL; } @@ -980,7 +935,7 @@ void G1OffsetTableContigSpace::clear(bool mangle_space) { set_top(bottom()); - set_saved_mark_word(bottom()); + _scan_top = bottom(); CompactibleSpace::clear(mangle_space); reset_bot(); } @@ -1012,41 +967,42 @@ return _offsets.threshold(); } -HeapWord* G1OffsetTableContigSpace::saved_mark_word() const { +HeapWord* G1OffsetTableContigSpace::scan_top() const { G1CollectedHeap* g1h = G1CollectedHeap::heap(); - assert( _gc_time_stamp <= g1h->get_gc_time_stamp(), "invariant" ); HeapWord* local_top = top(); OrderAccess::loadload(); - if (_gc_time_stamp < g1h->get_gc_time_stamp()) { + const unsigned local_time_stamp = _gc_time_stamp; + assert(local_time_stamp <= g1h->get_gc_time_stamp(), "invariant"); + if (local_time_stamp < g1h->get_gc_time_stamp()) { return local_top; } else { - return Space::saved_mark_word(); + return _scan_top; } } -void G1OffsetTableContigSpace::record_top_and_timestamp() { +void G1OffsetTableContigSpace::record_timestamp() { G1CollectedHeap* g1h = G1CollectedHeap::heap(); unsigned curr_gc_time_stamp = g1h->get_gc_time_stamp(); if (_gc_time_stamp < curr_gc_time_stamp) { - // The order of these is important, as another thread might be - // about to start scanning this region. If it does so after - // set_saved_mark and before _gc_time_stamp = ..., then the latter - // will be false, and it will pick up top() as the high water mark - // of region. If it does so after _gc_time_stamp = ..., then it - // will pick up the right saved_mark_word() as the high water mark - // of the region. Either way, the behaviour will be correct. - Space::set_saved_mark_word(top()); - OrderAccess::storestore(); + // Setting the time stamp here tells concurrent readers to look at + // scan_top to know the maximum allowed address to look at. + + // scan_top should be bottom for all regions except for the + // retained old alloc region which should have scan_top == top + HeapWord* st = _scan_top; + guarantee(st == _bottom || st == _top, "invariant"); + _gc_time_stamp = curr_gc_time_stamp; - // No need to do another barrier to flush the writes above. If - // this is called in parallel with other threads trying to - // allocate into the region, the caller should call this while - // holding a lock and when the lock is released the writes will be - // flushed. } } +void G1OffsetTableContigSpace::record_retained_region() { + // scan_top is the maximum address where it's safe for the next gc to + // scan this region. + _scan_top = top(); +} + void G1OffsetTableContigSpace::safe_object_iterate(ObjectClosure* blk) { object_iterate(blk); } @@ -1080,6 +1036,8 @@ void G1OffsetTableContigSpace::initialize(MemRegion mr, bool clear_space, bool mangle_space) { CompactibleSpace::initialize(mr, clear_space, mangle_space); _top = bottom(); + _scan_top = bottom(); + set_saved_mark_word(NULL); reset_bot(); } diff -r c2687aa5e5ca -r 7eb99acd567f src/share/vm/gc_implementation/g1/heapRegion.hpp --- a/src/share/vm/gc_implementation/g1/heapRegion.hpp Mon Jan 25 14:56:57 2016 -0800 +++ b/src/share/vm/gc_implementation/g1/heapRegion.hpp Mon Jan 25 14:57:27 2016 -0800 @@ -67,17 +67,9 @@ // sets. class HeapRegionDCTOC : public DirtyCardToOopClosure { -public: - // Specification of possible DirtyCardToOopClosure filtering. - enum FilterKind { - NoFilterKind, - IntoCSFilterKind, - OutOfRegionFilterKind - }; - -protected: +private: HeapRegion* _hr; - FilterKind _fk; + G1ParPushHeapRSClosure* _rs_scan; G1CollectedHeap* _g1; // Walk the given memory region from bottom to (actual) top @@ -90,9 +82,9 @@ public: HeapRegionDCTOC(G1CollectedHeap* g1, - HeapRegion* hr, ExtendedOopClosure* cl, - CardTableModRefBS::PrecisionStyle precision, - FilterKind fk); + HeapRegion* hr, + G1ParPushHeapRSClosure* cl, + CardTableModRefBS::PrecisionStyle precision); }; // The complicating factor is that BlockOffsetTable diverged @@ -101,28 +93,25 @@ // OffsetTableContigSpace. If the two versions of BlockOffsetTable could // be reconciled, then G1OffsetTableContigSpace could go away. -// The idea behind time stamps is the following. Doing a save_marks on -// all regions at every GC pause is time consuming (if I remember -// well, 10ms or so). So, we would like to do that only for regions -// that are GC alloc regions. To achieve this, we use time -// stamps. For every evacuation pause, G1CollectedHeap generates a -// unique time stamp (essentially a counter that gets -// incremented). Every time we want to call save_marks on a region, -// we set the saved_mark_word to top and also copy the current GC -// time stamp to the time stamp field of the space. Reading the -// saved_mark_word involves checking the time stamp of the -// region. If it is the same as the current GC time stamp, then we -// can safely read the saved_mark_word field, as it is valid. If the -// time stamp of the region is not the same as the current GC time -// stamp, then we instead read top, as the saved_mark_word field is -// invalid. Time stamps (on the regions and also on the -// G1CollectedHeap) are reset at every cleanup (we iterate over -// the regions anyway) and at the end of a Full GC. The current scheme -// that uses sequential unsigned ints will fail only if we have 4b +// The idea behind time stamps is the following. We want to keep track of +// the highest address where it's safe to scan objects for each region. +// This is only relevant for current GC alloc regions so we keep a time stamp +// per region to determine if the region has been allocated during the current +// GC or not. If the time stamp is current we report a scan_top value which +// was saved at the end of the previous GC for retained alloc regions and which is +// equal to the bottom for all other regions. +// There is a race between card scanners and allocating gc workers where we must ensure +// that card scanners do not read the memory allocated by the gc workers. +// In order to enforce that, we must not return a value of _top which is more recent than the +// time stamp. This is due to the fact that a region may become a gc alloc region at +// some point after we've read the timestamp value as being < the current time stamp. +// The time stamps are re-initialized to zero at cleanup and at Full GCs. +// The current scheme that uses sequential unsigned ints will fail only if we have 4b // evacuation pauses between two cleanups, which is _highly_ unlikely. class G1OffsetTableContigSpace: public CompactibleSpace { friend class VMStructs; HeapWord* _top; + HeapWord* volatile _scan_top; protected: G1BlockOffsetArrayContigSpace _offsets; Mutex _par_alloc_lock; @@ -166,10 +155,11 @@ void set_bottom(HeapWord* value); void set_end(HeapWord* value); - virtual HeapWord* saved_mark_word() const; - void record_top_and_timestamp(); + HeapWord* scan_top() const; + void record_timestamp(); void reset_gc_time_stamp() { _gc_time_stamp = 0; } unsigned get_gc_time_stamp() { return _gc_time_stamp; } + void record_retained_region(); // See the comment above in the declaration of _pre_dummy_top for an // explanation of what it is. @@ -193,6 +183,8 @@ virtual HeapWord* allocate(size_t word_size); HeapWord* par_allocate(size_t word_size); + HeapWord* saved_mark_word() const { ShouldNotReachHere(); return NULL; } + // MarkSweep support phase3 virtual HeapWord* initialize_threshold(); virtual HeapWord* cross_threshold(HeapWord* start, HeapWord* end); diff -r c2687aa5e5ca -r 7eb99acd567f src/share/vm/gc_implementation/g1/heapRegionManager.cpp --- a/src/share/vm/gc_implementation/g1/heapRegionManager.cpp Mon Jan 25 14:56:57 2016 -0800 +++ b/src/share/vm/gc_implementation/g1/heapRegionManager.cpp Mon Jan 25 14:57:27 2016 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 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 @@ -145,6 +145,24 @@ } } +MemoryUsage HeapRegionManager::get_auxiliary_data_memory_usage() const { + size_t used_sz = + _prev_bitmap_mapper->committed_size() + + _next_bitmap_mapper->committed_size() + + _bot_mapper->committed_size() + + _cardtable_mapper->committed_size() + + _card_counts_mapper->committed_size(); + + size_t committed_sz = + _prev_bitmap_mapper->reserved_size() + + _next_bitmap_mapper->reserved_size() + + _bot_mapper->reserved_size() + + _cardtable_mapper->reserved_size() + + _card_counts_mapper->reserved_size(); + + return MemoryUsage(0, used_sz, committed_sz, committed_sz); +} + uint HeapRegionManager::expand_by(uint num_regions) { return expand_at(0, num_regions); } diff -r c2687aa5e5ca -r 7eb99acd567f src/share/vm/gc_implementation/g1/heapRegionManager.hpp --- a/src/share/vm/gc_implementation/g1/heapRegionManager.hpp Mon Jan 25 14:56:57 2016 -0800 +++ b/src/share/vm/gc_implementation/g1/heapRegionManager.hpp Mon Jan 25 14:57:27 2016 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 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 @@ -28,6 +28,7 @@ #include "gc_implementation/g1/g1BiasedArray.hpp" #include "gc_implementation/g1/g1RegionToSpaceMapper.hpp" #include "gc_implementation/g1/heapRegionSet.hpp" +#include "services/memoryUsage.hpp" class HeapRegion; class HeapRegionClosure; @@ -197,6 +198,8 @@ // Return the maximum number of regions in the heap. uint max_length() const { return (uint)_regions.length(); } + MemoryUsage get_auxiliary_data_memory_usage() const; + MemRegion reserved() const { return MemRegion(heap_bottom(), heap_end()); } // Expand the sequence to reflect that the heap has grown. Either create new diff -r c2687aa5e5ca -r 7eb99acd567f src/share/vm/gc_implementation/g1/heapRegionRemSet.cpp --- a/src/share/vm/gc_implementation/g1/heapRegionRemSet.cpp Mon Jan 25 14:56:57 2016 -0800 +++ b/src/share/vm/gc_implementation/g1/heapRegionRemSet.cpp Mon Jan 25 14:57:27 2016 -0800 @@ -694,6 +694,18 @@ clear_fcc(); } +bool OtherRegionsTable::occupancy_less_or_equal_than(size_t limit) const { + if (limit <= (size_t)G1RSetSparseRegionEntries) { + return occ_coarse() == 0 && _first_all_fine_prts == NULL && occ_sparse() <= limit; + } else { + // Current uses of this method may only use values less than G1RSetSparseRegionEntries + // for the limit. The solution, comparing against occupied() would be too slow + // at this time. + Unimplemented(); + return false; + } +} + bool OtherRegionsTable::is_empty() const { return occ_sparse() == 0 && occ_coarse() == 0 && _first_all_fine_prts == NULL; } diff -r c2687aa5e5ca -r 7eb99acd567f src/share/vm/gc_implementation/g1/heapRegionRemSet.hpp --- a/src/share/vm/gc_implementation/g1/heapRegionRemSet.hpp Mon Jan 25 14:56:57 2016 -0800 +++ b/src/share/vm/gc_implementation/g1/heapRegionRemSet.hpp Mon Jan 25 14:57:27 2016 -0800 @@ -181,6 +181,10 @@ // sense. void add_reference(OopOrNarrowOopStar from, int tid); + // Returns whether this remembered set (and all sub-sets) have an occupancy + // that is less or equal than the given occupancy. + bool occupancy_less_or_equal_than(size_t limit) const; + // Removes any entries shown by the given bitmaps to contain only dead // objects. void scrub(CardTableModRefBS* ctbs, BitMap* region_bm, BitMap* card_bm); @@ -278,6 +282,10 @@ return (strong_code_roots_list_length() == 0) && _other_regions.is_empty(); } + bool occupancy_less_or_equal_than(size_t occ) const { + return (strong_code_roots_list_length() == 0) && _other_regions.occupancy_less_or_equal_than(occ); + } + size_t occupied() { MutexLockerEx x(&_m, Mutex::_no_safepoint_check_flag); return occupied_locked(); diff -r c2687aa5e5ca -r 7eb99acd567f src/share/vm/gc_implementation/g1/heapRegionSet.cpp --- a/src/share/vm/gc_implementation/g1/heapRegionSet.cpp Mon Jan 25 14:56:57 2016 -0800 +++ b/src/share/vm/gc_implementation/g1/heapRegionSet.cpp Mon Jan 25 14:57:27 2016 -0800 @@ -420,6 +420,7 @@ ReservedSpace bot_rs(G1BlockOffsetSharedArray::compute_size(heap.word_size())); G1RegionToSpaceMapper* bot_storage = G1RegionToSpaceMapper::create_mapper(bot_rs, + bot_rs.size(), os::vm_page_size(), HeapRegion::GrainBytes, G1BlockOffsetSharedArray::N_bytes, diff -r c2687aa5e5ca -r 7eb99acd567f src/share/vm/gc_implementation/g1/satbQueue.cpp --- a/src/share/vm/gc_implementation/g1/satbQueue.cpp Mon Jan 25 14:56:57 2016 -0800 +++ b/src/share/vm/gc_implementation/g1/satbQueue.cpp Mon Jan 25 14:57:27 2016 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 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 @@ -29,36 +29,74 @@ #include "memory/sharedHeap.hpp" #include "oops/oop.inline.hpp" #include "runtime/mutexLocker.hpp" +#include "runtime/safepoint.hpp" #include "runtime/thread.hpp" #include "runtime/vmThread.hpp" PRAGMA_FORMAT_MUTE_WARNINGS_FOR_GCC void ObjPtrQueue::flush() { - // The buffer might contain refs into the CSet. We have to filter it - // first before we flush it, otherwise we might end up with an - // enqueued buffer with refs into the CSet which breaks our invariants. + // Filter now to possibly save work later. If filtering empties the + // buffer then flush_impl can deallocate the buffer. filter(); flush_impl(); } -// This method removes entries from an SATB buffer that will not be -// useful to the concurrent marking threads. An entry is removed if it -// satisfies one of the following conditions: +// Return true if a SATB buffer entry refers to an object that +// requires marking. +// +// The entry must point into the G1 heap. In particular, it must not +// be a NULL pointer. NULL pointers are pre-filtered and never +// inserted into a SATB buffer. +// +// An entry that is below the NTAMS pointer for the containing heap +// region requires marking. Such an entry must point to a valid object. +// +// An entry that is at least the NTAMS pointer for the containing heap +// region might be any of the following, none of which should be marked. +// +// * A reference to an object allocated since marking started. +// According to SATB, such objects are implicitly kept live and do +// not need to be dealt with via SATB buffer processing. +// +// * A reference to a young generation object. Young objects are +// handled separately and are not marked by concurrent marking. +// +// * A stale reference to a young generation object. If a young +// generation object reference is recorded and not filtered out +// before being moved by a young collection, the reference becomes +// stale. // -// * it points to an object outside the G1 heap (G1's concurrent -// marking only visits objects inside the G1 heap), -// * it points to an object that has been allocated since marking -// started (according to SATB those objects do not need to be -// visited during marking), or -// * it points to an object that has already been marked (no need to -// process it again). +// * A stale reference to an eagerly reclaimed humongous object. If a +// humongous object is recorded and then reclaimed, the reference +// becomes stale. // -// The rest of the entries will be retained and are compacted towards -// the top of the buffer. Note that, because we do not allow old -// regions in the CSet during marking, all objects on the CSet regions -// are young (eden or survivors) and therefore implicitly live. So any -// references into the CSet will be removed during filtering. +// The stale reference cases are implicitly handled by the NTAMS +// comparison. Because of the possibility of stale references, buffer +// processing must be somewhat circumspect and not assume entries +// in an unfiltered buffer refer to valid objects. + +inline bool requires_marking(const void* entry, G1CollectedHeap* heap) { + // Includes rejection of NULL pointers. + assert(heap->is_in_reserved(entry), + err_msg("Non-heap pointer in SATB buffer: " PTR_FORMAT, p2i(entry))); + + HeapRegion* region = heap->heap_region_containing_raw(entry); + assert(region != NULL, err_msg("No region for " PTR_FORMAT, p2i(entry))); + if (entry >= region->next_top_at_mark_start()) { + return false; + } + + assert(((oop)entry)->is_oop(true /* ignore mark word */), + err_msg("Invalid oop in SATB buffer: " PTR_FORMAT, p2i(entry))); + + return true; +} + +// This method removes entries from a SATB buffer that will not be +// useful to the concurrent marking threads. Entries are retained if +// they require marking and are not already marked. Retained entries +// are compacted toward the top of the buffer. void ObjPtrQueue::filter() { G1CollectedHeap* g1h = G1CollectedHeap::heap(); @@ -80,26 +118,25 @@ assert(i > 0, "we should have at least one more entry to process"); i -= oopSize; debug_only(entries += 1;) - oop* p = (oop*) &buf[byte_index_to_index((int) i)]; - oop obj = *p; + void** p = &buf[byte_index_to_index((int) i)]; + void* entry = *p; // NULL the entry so that unused parts of the buffer contain NULLs // at the end. If we are going to retain it we will copy it to its // final place. If we have retained all entries we have visited so // far, we'll just end up copying it to the same place. *p = NULL; - bool retain = g1h->is_obj_ill(obj); - if (retain) { + if (requires_marking(entry, g1h) && !g1h->isMarkedNext((oop)entry)) { assert(new_index > 0, "we should not have already filled up the buffer"); new_index -= oopSize; assert(new_index >= i, "new_index should never be below i, as we alwaysr compact 'up'"); - oop* new_p = (oop*) &buf[byte_index_to_index((int) new_index)]; + void** new_p = &buf[byte_index_to_index((int) new_index)]; assert(new_p >= p, "the destination location should never be below " "the source as we always compact 'up'"); assert(*new_p == NULL, "we should have already cleared the destination location"); - *new_p = obj; + *new_p = entry; debug_only(retained += 1;) } } @@ -126,10 +163,7 @@ assert(_lock == NULL || _lock->owned_by_self(), "we should have taken the lock before calling this"); - // Even if G1SATBBufferEnqueueingThresholdPercent == 0 we have to - // filter the buffer given that this will remove any references into - // the CSet as we currently assume that no such refs will appear in - // enqueued buffers. + // If G1SATBBufferEnqueueingThresholdPercent == 0 we could skip filtering. // This method should only be called if there is a non-NULL buffer // that is full. @@ -146,31 +180,19 @@ return should_enqueue; } -void ObjPtrQueue::apply_closure(ObjectClosure* cl) { +void ObjPtrQueue::apply_closure_and_empty(SATBBufferClosure* cl) { + assert(SafepointSynchronize::is_at_safepoint(), + "SATB queues must only be processed at safepoints"); if (_buf != NULL) { - apply_closure_to_buffer(cl, _buf, _index, _sz); - } -} - -void ObjPtrQueue::apply_closure_and_empty(ObjectClosure* cl) { - if (_buf != NULL) { - apply_closure_to_buffer(cl, _buf, _index, _sz); + assert(_index % sizeof(void*) == 0, "invariant"); + assert(_sz % sizeof(void*) == 0, "invariant"); + assert(_index <= _sz, "invariant"); + cl->do_buffer(_buf + byte_index_to_index((int)_index), + byte_index_to_index((int)(_sz - _index))); _index = _sz; } } -void ObjPtrQueue::apply_closure_to_buffer(ObjectClosure* cl, - void** buf, size_t index, size_t sz) { - if (cl == NULL) return; - for (size_t i = index; i < sz; i += oopSize) { - oop obj = (oop)buf[byte_index_to_index((int)i)]; - // There can be NULL entries because of destructors. - if (obj != NULL) { - cl->do_object(obj); - } - } -} - #ifndef PRODUCT // Helpful for debugging @@ -186,23 +208,12 @@ } #endif // PRODUCT -#ifdef ASSERT -void ObjPtrQueue::verify_oops_in_buffer() { - if (_buf == NULL) return; - for (size_t i = _index; i < _sz; i += oopSize) { - oop obj = (oop)_buf[byte_index_to_index((int)i)]; - assert(obj != NULL && obj->is_oop(true /* ignore mark word */), - "Not an oop"); - } -} -#endif - #ifdef _MSC_VER // the use of 'this' below gets a warning, make it go away #pragma warning( disable:4355 ) // 'this' : used in base member initializer list #endif // _MSC_VER SATBMarkQueueSet::SATBMarkQueueSet() : - PtrQueueSet(), _closure(NULL), _par_closures(NULL), + PtrQueueSet(), _shared_satb_queue(this, true /*perm*/) { } void SATBMarkQueueSet::initialize(Monitor* cbl_mon, Mutex* fl_lock, @@ -210,13 +221,9 @@ Mutex* lock) { PtrQueueSet::initialize(cbl_mon, fl_lock, process_completed_threshold, -1); _shared_satb_queue.set_lock(lock); - if (ParallelGCThreads > 0) { - _par_closures = NEW_C_HEAP_ARRAY(ObjectClosure*, ParallelGCThreads, mtGC); - } } void SATBMarkQueueSet::handle_zero_index_for_thread(JavaThread* t) { - DEBUG_ONLY(t->satb_mark_queue().verify_oops_in_buffer();) t->satb_mark_queue().handle_zero_index(); } @@ -276,17 +283,7 @@ shared_satb_queue()->filter(); } -void SATBMarkQueueSet::set_closure(ObjectClosure* closure) { - _closure = closure; -} - -void SATBMarkQueueSet::set_par_closure(int i, ObjectClosure* par_closure) { - assert(ParallelGCThreads > 0 && _par_closures != NULL, "Precondition"); - _par_closures[i] = par_closure; -} - -bool SATBMarkQueueSet::apply_closure_to_completed_buffer_work(bool par, - uint worker) { +bool SATBMarkQueueSet::apply_closure_to_completed_buffer(SATBBufferClosure* cl) { BufferNode* nd = NULL; { MutexLockerEx x(_cbl_mon, Mutex::_no_safepoint_check_flag); @@ -298,10 +295,20 @@ if (_n_completed_buffers == 0) _process_completed = false; } } - ObjectClosure* cl = (par ? _par_closures[worker] : _closure); if (nd != NULL) { void **buf = BufferNode::make_buffer_from_node(nd); - ObjPtrQueue::apply_closure_to_buffer(cl, buf, 0, _sz); + // Skip over NULL entries at beginning (e.g. push end) of buffer. + // Filtering can result in non-full completed buffers; see + // should_enqueue_buffer. + assert(_sz % sizeof(void*) == 0, "invariant"); + size_t limit = ObjPtrQueue::byte_index_to_index((int)_sz); + for (size_t i = 0; i < limit; ++i) { + if (buf[i] != NULL) { + // Found the end of the block of NULLs; process the remainder. + cl->do_buffer(buf + i, limit - i); + break; + } + } deallocate_buffer(buf); return true; } else { @@ -309,28 +316,6 @@ } } -void SATBMarkQueueSet::iterate_completed_buffers_read_only(ObjectClosure* cl) { - assert(SafepointSynchronize::is_at_safepoint(), "Must be at safepoint."); - assert(cl != NULL, "pre-condition"); - - BufferNode* nd = _completed_buffers_head; - while (nd != NULL) { - void** buf = BufferNode::make_buffer_from_node(nd); - ObjPtrQueue::apply_closure_to_buffer(cl, buf, 0, _sz); - nd = nd->next(); - } -} - -void SATBMarkQueueSet::iterate_thread_buffers_read_only(ObjectClosure* cl) { - assert(SafepointSynchronize::is_at_safepoint(), "Must be at safepoint."); - assert(cl != NULL, "pre-condition"); - - for (JavaThread* t = Threads::first(); t; t = t->next()) { - t->satb_mark_queue().apply_closure(cl); - } - shared_satb_queue()->apply_closure(cl); -} - #ifndef PRODUCT // Helpful for debugging diff -r c2687aa5e5ca -r 7eb99acd567f src/share/vm/gc_implementation/g1/satbQueue.hpp --- a/src/share/vm/gc_implementation/g1/satbQueue.hpp Mon Jan 25 14:56:57 2016 -0800 +++ b/src/share/vm/gc_implementation/g1/satbQueue.hpp Mon Jan 25 14:57:27 2016 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 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 @@ -25,32 +25,30 @@ #ifndef SHARE_VM_GC_IMPLEMENTATION_G1_SATBQUEUE_HPP #define SHARE_VM_GC_IMPLEMENTATION_G1_SATBQUEUE_HPP +#include "memory/allocation.hpp" #include "gc_implementation/g1/ptrQueue.hpp" -class ObjectClosure; class JavaThread; class SATBMarkQueueSet; +// Base class for processing the contents of a SATB buffer. +class SATBBufferClosure : public StackObj { +protected: + ~SATBBufferClosure() { } + +public: + // Process the SATB entries in the designated buffer range. + virtual void do_buffer(void** buffer, size_t size) = 0; +}; + // A ptrQueue whose elements are "oops", pointers to object heads. class ObjPtrQueue: public PtrQueue { - friend class Threads; friend class SATBMarkQueueSet; - friend class G1RemarkThreadsClosure; private: // Filter out unwanted entries from the buffer. void filter(); - // Apply the closure to all elements. - void apply_closure(ObjectClosure* cl); - - // Apply the closure to all elements and empty the buffer; - void apply_closure_and_empty(ObjectClosure* cl); - - // Apply the closure to all elements of "buf", down to "index" (inclusive.) - static void apply_closure_to_buffer(ObjectClosure* cl, - void** buf, size_t index, size_t sz); - public: ObjPtrQueue(PtrQueueSet* qset, bool perm = false) : // SATB queues are only active during marking cycles. We create @@ -63,6 +61,10 @@ // Process queue entries and free resources. void flush(); + // Apply cl to the active part of the buffer. + // Prerequisite: Must be at a safepoint. + void apply_closure_and_empty(SATBBufferClosure* cl); + // Overrides PtrQueue::should_enqueue_buffer(). See the method's // definition for more information. virtual bool should_enqueue_buffer(); @@ -72,21 +74,11 @@ void print(const char* name); static void print(const char* name, void** buf, size_t index, size_t sz); #endif // PRODUCT - - void verify_oops_in_buffer() NOT_DEBUG_RETURN; }; class SATBMarkQueueSet: public PtrQueueSet { - ObjectClosure* _closure; - ObjectClosure** _par_closures; // One per ParGCThread. - ObjPtrQueue _shared_satb_queue; - // Utility function to support sequential and parallel versions. If - // "par" is true, then "worker" is the par thread id; if "false", worker - // is ignored. - bool apply_closure_to_completed_buffer_work(bool par, uint worker); - #ifdef ASSERT void dump_active_states(bool expected_active); void verify_active_states(bool expected_active); @@ -110,32 +102,12 @@ // Filter all the currently-active SATB buffers. void filter_thread_buffers(); - // Register "blk" as "the closure" for all queues. Only one such closure - // is allowed. The "apply_closure_to_completed_buffer" method will apply - // this closure to a completed buffer, and "iterate_closure_all_threads" - // applies it to partially-filled buffers (the latter should only be done - // with the world stopped). - void set_closure(ObjectClosure* closure); - // Set the parallel closures: pointer is an array of pointers to - // closures, one for each parallel GC thread. - void set_par_closure(int i, ObjectClosure* closure); - - // If there exists some completed buffer, pop it, then apply the - // registered closure to all its elements, and return true. If no - // completed buffers exist, return false. - bool apply_closure_to_completed_buffer() { - return apply_closure_to_completed_buffer_work(false, 0); - } - // Parallel version of the above. - bool par_apply_closure_to_completed_buffer(uint worker) { - return apply_closure_to_completed_buffer_work(true, worker); - } - - // Apply the given closure on enqueued and currently-active buffers - // respectively. Both methods are read-only, i.e., they do not - // modify any of the buffers. - void iterate_completed_buffers_read_only(ObjectClosure* cl); - void iterate_thread_buffers_read_only(ObjectClosure* cl); + // If there exists some completed buffer, pop and process it, and + // return true. Otherwise return false. Processing a buffer + // consists of applying the closure to the buffer range starting + // with the first non-NULL entry to the end of the buffer; the + // leading entries may be NULL due to filtering. + bool apply_closure_to_completed_buffer(SATBBufferClosure* cl); #ifndef PRODUCT // Helpful for debugging diff -r c2687aa5e5ca -r 7eb99acd567f src/share/vm/gc_implementation/g1/vm_operations_g1.cpp --- a/src/share/vm/gc_implementation/g1/vm_operations_g1.cpp Mon Jan 25 14:56:57 2016 -0800 +++ b/src/share/vm/gc_implementation/g1/vm_operations_g1.cpp Mon Jan 25 14:57:27 2016 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 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 @@ -34,12 +34,11 @@ #include "gc_implementation/g1/vm_operations_g1.hpp" #include "runtime/interfaceSupport.hpp" -VM_G1CollectForAllocation::VM_G1CollectForAllocation( - unsigned int gc_count_before, - size_t word_size) +VM_G1CollectForAllocation::VM_G1CollectForAllocation(uint gc_count_before, + size_t word_size) : VM_G1OperationWithAllocRequest(gc_count_before, word_size, GCCause::_allocation_failure) { - guarantee(word_size > 0, "an allocation should always be requested"); + guarantee(word_size != 0, "An allocation should always be requested with this operation."); } void VM_G1CollectForAllocation::doit() { @@ -57,12 +56,11 @@ g1h->do_full_collection(false /* clear_all_soft_refs */); } -VM_G1IncCollectionPause::VM_G1IncCollectionPause( - unsigned int gc_count_before, - size_t word_size, - bool should_initiate_conc_mark, - double target_pause_time_ms, - GCCause::Cause gc_cause) +VM_G1IncCollectionPause::VM_G1IncCollectionPause(uint gc_count_before, + size_t word_size, + bool should_initiate_conc_mark, + double target_pause_time_ms, + GCCause::Cause gc_cause) : VM_G1OperationWithAllocRequest(gc_count_before, word_size, gc_cause), _should_initiate_conc_mark(should_initiate_conc_mark), _target_pause_time_ms(target_pause_time_ms), @@ -75,7 +73,7 @@ } bool VM_G1IncCollectionPause::doit_prologue() { - bool res = VM_GC_Operation::doit_prologue(); + bool res = VM_G1OperationWithAllocRequest::doit_prologue(); if (!res) { if (_should_initiate_conc_mark) { // The prologue can fail for a couple of reasons. The first is that another GC @@ -169,7 +167,7 @@ } void VM_G1IncCollectionPause::doit_epilogue() { - VM_GC_Operation::doit_epilogue(); + VM_G1OperationWithAllocRequest::doit_epilogue(); // If the pause was initiated by a System.gc() and // +ExplicitGCInvokesConcurrent, we have to wait here for the cycle @@ -230,7 +228,6 @@ } void VM_CGC_Operation::doit() { - gclog_or_tty->date_stamp(G1Log::fine() && PrintGCDateStamps); TraceCPUTime tcpu(G1Log::finer(), true, gclog_or_tty); GCTraceTime t(_printGCMessage, G1Log::fine(), true, G1CollectedHeap::heap()->gc_timer_cm(), G1CollectedHeap::heap()->concurrent_mark()->concurrent_gc_id()); SharedHeap* sh = SharedHeap::heap(); diff -r c2687aa5e5ca -r 7eb99acd567f src/share/vm/gc_implementation/g1/vm_operations_g1.hpp --- a/src/share/vm/gc_implementation/g1/vm_operations_g1.hpp Mon Jan 25 14:56:57 2016 -0800 +++ b/src/share/vm/gc_implementation/g1/vm_operations_g1.hpp Mon Jan 25 14:57:27 2016 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 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 @@ -36,20 +36,17 @@ // - VM_G1CollectForAllocation // - VM_G1IncCollectionPause -class VM_G1OperationWithAllocRequest: public VM_GC_Operation { +class VM_G1OperationWithAllocRequest : public VM_CollectForAllocation { protected: - size_t _word_size; - HeapWord* _result; bool _pause_succeeded; AllocationContext_t _allocation_context; public: - VM_G1OperationWithAllocRequest(unsigned int gc_count_before, - size_t word_size, + VM_G1OperationWithAllocRequest(uint gc_count_before, + size_t word_size, GCCause::Cause gc_cause) - : VM_GC_Operation(gc_count_before, gc_cause), - _word_size(word_size), _result(NULL), _pause_succeeded(false) { } - HeapWord* result() { return _result; } + : VM_CollectForAllocation(word_size, gc_count_before, gc_cause), + _pause_succeeded(false) {} bool pause_succeeded() { return _pause_succeeded; } void set_allocation_context(AllocationContext_t context) { _allocation_context = context; } AllocationContext_t allocation_context() { return _allocation_context; } @@ -57,8 +54,8 @@ class VM_G1CollectFull: public VM_GC_Operation { public: - VM_G1CollectFull(unsigned int gc_count_before, - unsigned int full_gc_count_before, + VM_G1CollectFull(uint gc_count_before, + uint full_gc_count_before, GCCause::Cause cause) : VM_GC_Operation(gc_count_before, cause, full_gc_count_before, true) { } virtual VMOp_Type type() const { return VMOp_G1CollectFull; } @@ -70,7 +67,7 @@ class VM_G1CollectForAllocation: public VM_G1OperationWithAllocRequest { public: - VM_G1CollectForAllocation(unsigned int gc_count_before, + VM_G1CollectForAllocation(uint gc_count_before, size_t word_size); virtual VMOp_Type type() const { return VMOp_G1CollectForAllocation; } virtual void doit(); @@ -84,9 +81,9 @@ bool _should_initiate_conc_mark; bool _should_retry_gc; double _target_pause_time_ms; - unsigned int _old_marking_cycles_completed_before; + uint _old_marking_cycles_completed_before; public: - VM_G1IncCollectionPause(unsigned int gc_count_before, + VM_G1IncCollectionPause(uint gc_count_before, size_t word_size, bool should_initiate_conc_mark, double target_pause_time_ms, diff -r c2687aa5e5ca -r 7eb99acd567f src/share/vm/gc_implementation/parNew/parNewGeneration.cpp --- a/src/share/vm/gc_implementation/parNew/parNewGeneration.cpp Mon Jan 25 14:56:57 2016 -0800 +++ b/src/share/vm/gc_implementation/parNew/parNewGeneration.cpp Mon Jan 25 14:57:27 2016 -0800 @@ -622,7 +622,7 @@ true, // Process younger gens, if any, // as strong roots. false, // no scope; this is parallel code - SharedHeap::SO_ScavengeCodeCache, + GenCollectedHeap::SO_ScavengeCodeCache, GenCollectedHeap::StrongAndWeakRoots, &par_scan_state.to_space_root_closure(), &par_scan_state.older_gen_closure(), @@ -1197,8 +1197,10 @@ return real_forwardee(old); } - new_obj = _next_gen->par_promote(par_scan_state->thread_num(), - old, m, sz); + if (!_promotion_failed) { + new_obj = _next_gen->par_promote(par_scan_state->thread_num(), + old, m, sz); + } if (new_obj == NULL) { // promotion failed, forward to self diff -r c2687aa5e5ca -r 7eb99acd567f src/share/vm/gc_implementation/parallelScavenge/generationSizer.cpp --- a/src/share/vm/gc_implementation/parallelScavenge/generationSizer.cpp Mon Jan 25 14:56:57 2016 -0800 +++ b/src/share/vm/gc_implementation/parallelScavenge/generationSizer.cpp Mon Jan 25 14:57:27 2016 -0800 @@ -66,9 +66,10 @@ void GenerationSizer::initialize_size_info() { trace_gen_sizes("ps heap raw"); - const size_t page_sz = os::page_size_for_region(_min_heap_byte_size, - _max_heap_byte_size, - 8); + const size_t max_page_sz = os::page_size_for_region_aligned(_max_heap_byte_size, 8); + const size_t min_pages = 4; // 1 for eden + 1 for each survivor + 1 for old + const size_t min_page_sz = os::page_size_for_region_aligned(_min_heap_byte_size, min_pages); + const size_t page_sz = MIN2(max_page_sz, min_page_sz); // Can a page size be something else than a power of two? assert(is_power_of_2((intptr_t)page_sz), "must be a power of 2"); diff -r c2687aa5e5ca -r 7eb99acd567f src/share/vm/gc_implementation/parallelScavenge/parMarkBitMap.cpp --- a/src/share/vm/gc_implementation/parallelScavenge/parMarkBitMap.cpp Mon Jan 25 14:56:57 2016 -0800 +++ b/src/share/vm/gc_implementation/parallelScavenge/parMarkBitMap.cpp Mon Jan 25 14:57:27 2016 -0800 @@ -55,7 +55,7 @@ const size_t words = bits / BitsPerWord; const size_t raw_bytes = words * sizeof(idx_t); - const size_t page_sz = os::page_size_for_region(raw_bytes, raw_bytes, 10); + const size_t page_sz = os::page_size_for_region_aligned(raw_bytes, 10); const size_t granularity = os::vm_allocation_granularity(); _reserved_byte_size = align_size_up(raw_bytes, MAX2(page_sz, granularity)); diff -r c2687aa5e5ca -r 7eb99acd567f src/share/vm/gc_implementation/parallelScavenge/parallelScavengeHeap.cpp --- a/src/share/vm/gc_implementation/parallelScavenge/parallelScavengeHeap.cpp Mon Jan 25 14:56:57 2016 -0800 +++ b/src/share/vm/gc_implementation/parallelScavenge/parallelScavengeHeap.cpp Mon Jan 25 14:57:27 2016 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 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 @@ -261,7 +261,7 @@ uint loop_count = 0; uint gc_count = 0; - int gclocker_stalled_count = 0; + uint gclocker_stalled_count = 0; while (result == NULL) { // We don't want to have multiple collections for a single filled generation. @@ -521,8 +521,8 @@ assert(!Heap_lock->owned_by_self(), "this thread should not own the Heap_lock"); - unsigned int gc_count = 0; - unsigned int full_gc_count = 0; + uint gc_count = 0; + uint full_gc_count = 0; { MutexLocker ml(Heap_lock); // This value is guarded by the Heap_lock diff -r c2687aa5e5ca -r 7eb99acd567f src/share/vm/gc_implementation/parallelScavenge/psMarkSweep.cpp --- a/src/share/vm/gc_implementation/parallelScavenge/psMarkSweep.cpp Mon Jan 25 14:56:57 2016 -0800 +++ b/src/share/vm/gc_implementation/parallelScavenge/psMarkSweep.cpp Mon Jan 25 14:57:27 2016 -0800 @@ -167,7 +167,6 @@ { HandleMark hm; - gclog_or_tty->date_stamp(PrintGC && PrintGCDateStamps); TraceCPUTime tcpu(PrintGCDetails, true, gclog_or_tty); GCTraceTime t1(GCCauseString("Full GC", gc_cause), PrintGC, !PrintGCDetails, NULL, _gc_tracer->gc_id()); TraceCollectorStats tcs(counters()); diff -r c2687aa5e5ca -r 7eb99acd567f src/share/vm/gc_implementation/parallelScavenge/psParallelCompact.cpp --- a/src/share/vm/gc_implementation/parallelScavenge/psParallelCompact.cpp Mon Jan 25 14:56:57 2016 -0800 +++ b/src/share/vm/gc_implementation/parallelScavenge/psParallelCompact.cpp Mon Jan 25 14:57:27 2016 -0800 @@ -401,7 +401,7 @@ ParallelCompactData::create_vspace(size_t count, size_t element_size) { const size_t raw_bytes = count * element_size; - const size_t page_sz = os::page_size_for_region(raw_bytes, raw_bytes, 10); + const size_t page_sz = os::page_size_for_region_aligned(raw_bytes, 10); const size_t granularity = os::vm_allocation_granularity(); _reserved_byte_size = align_size_up(raw_bytes, MAX2(page_sz, granularity)); @@ -2056,7 +2056,6 @@ gc_task_manager()->task_idle_workers(); heap->set_par_threads(gc_task_manager()->active_workers()); - gclog_or_tty->date_stamp(PrintGC && PrintGCDateStamps); TraceCPUTime tcpu(PrintGCDetails, true, gclog_or_tty); GCTraceTime t1(GCCauseString("Full GC", gc_cause), PrintGC, !PrintGCDetails, NULL, _gc_tracer.gc_id()); TraceCollectorStats tcs(counters()); diff -r c2687aa5e5ca -r 7eb99acd567f src/share/vm/gc_implementation/parallelScavenge/psScavenge.cpp --- a/src/share/vm/gc_implementation/parallelScavenge/psScavenge.cpp Mon Jan 25 14:56:57 2016 -0800 +++ b/src/share/vm/gc_implementation/parallelScavenge/psScavenge.cpp Mon Jan 25 14:57:27 2016 -0800 @@ -329,7 +329,6 @@ ResourceMark rm; HandleMark hm; - gclog_or_tty->date_stamp(PrintGC && PrintGCDateStamps); TraceCPUTime tcpu(PrintGCDetails, true, gclog_or_tty); GCTraceTime t1(GCCauseString("GC", gc_cause), PrintGC, !PrintGCDetails, NULL, _gc_tracer.gc_id()); TraceCollectorStats tcs(counters()); diff -r c2687aa5e5ca -r 7eb99acd567f src/share/vm/gc_implementation/parallelScavenge/vmPSOperations.cpp --- a/src/share/vm/gc_implementation/parallelScavenge/vmPSOperations.cpp Mon Jan 25 14:56:57 2016 -0800 +++ b/src/share/vm/gc_implementation/parallelScavenge/vmPSOperations.cpp Mon Jan 25 14:57:27 2016 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2007, 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 @@ -32,12 +32,10 @@ #include "utilities/dtrace.hpp" // The following methods are used by the parallel scavenge collector -VM_ParallelGCFailedAllocation::VM_ParallelGCFailedAllocation(size_t size, - unsigned int gc_count) : - VM_GC_Operation(gc_count, GCCause::_allocation_failure), - _size(size), - _result(NULL) -{ +VM_ParallelGCFailedAllocation::VM_ParallelGCFailedAllocation(size_t word_size, + uint gc_count) : + VM_CollectForAllocation(word_size, gc_count, GCCause::_allocation_failure) { + assert(word_size != 0, "An allocation should always be requested with this operation."); } void VM_ParallelGCFailedAllocation::doit() { @@ -47,7 +45,7 @@ assert(heap->kind() == CollectedHeap::ParallelScavengeHeap, "must be a ParallelScavengeHeap"); GCCauseSetter gccs(heap, _gc_cause); - _result = heap->failed_mem_allocate(_size); + _result = heap->failed_mem_allocate(_word_size); if (_result == NULL && GC_locker::is_active_and_needs_gc()) { set_gc_locked(); @@ -55,8 +53,8 @@ } // Only used for System.gc() calls -VM_ParallelGCSystemGC::VM_ParallelGCSystemGC(unsigned int gc_count, - unsigned int full_gc_count, +VM_ParallelGCSystemGC::VM_ParallelGCSystemGC(uint gc_count, + uint full_gc_count, GCCause::Cause gc_cause) : VM_GC_Operation(gc_count, gc_cause, full_gc_count, true /* full */) { diff -r c2687aa5e5ca -r 7eb99acd567f src/share/vm/gc_implementation/parallelScavenge/vmPSOperations.hpp --- a/src/share/vm/gc_implementation/parallelScavenge/vmPSOperations.hpp Mon Jan 25 14:56:57 2016 -0800 +++ b/src/share/vm/gc_implementation/parallelScavenge/vmPSOperations.hpp Mon Jan 25 14:57:27 2016 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2007, 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 @@ -29,26 +29,19 @@ #include "gc_implementation/shared/vmGCOperations.hpp" #include "gc_interface/gcCause.hpp" -class VM_ParallelGCFailedAllocation: public VM_GC_Operation { - private: - size_t _size; - HeapWord* _result; - +class VM_ParallelGCFailedAllocation : public VM_CollectForAllocation { public: - VM_ParallelGCFailedAllocation(size_t size, unsigned int gc_count); + VM_ParallelGCFailedAllocation(size_t word_size, uint gc_count); virtual VMOp_Type type() const { return VMOp_ParallelGCFailedAllocation; } virtual void doit(); - - HeapWord* result() const { return _result; } }; class VM_ParallelGCSystemGC: public VM_GC_Operation { public: - VM_ParallelGCSystemGC(unsigned int gc_count, unsigned int full_gc_count, - GCCause::Cause gc_cause); + VM_ParallelGCSystemGC(uint gc_count, uint full_gc_count, GCCause::Cause gc_cause); virtual VMOp_Type type() const { return VMOp_ParallelGCSystemGC; } virtual void doit(); }; diff -r c2687aa5e5ca -r 7eb99acd567f src/share/vm/gc_implementation/shared/ageTable.hpp --- a/src/share/vm/gc_implementation/shared/ageTable.hpp Mon Jan 25 14:56:57 2016 -0800 +++ b/src/share/vm/gc_implementation/shared/ageTable.hpp Mon Jan 25 14:57:27 2016 -0800 @@ -55,7 +55,10 @@ // add entry void add(oop p, size_t oop_size) { - uint age = p->age(); + add(p->age(), oop_size); + } + + void add(uint age, size_t oop_size) { assert(age > 0 && age < table_size, "invalid age of object"); sizes[age] += oop_size; } diff -r c2687aa5e5ca -r 7eb99acd567f src/share/vm/gc_implementation/shared/gcTraceTime.cpp --- a/src/share/vm/gc_implementation/shared/gcTraceTime.cpp Mon Jan 25 14:56:57 2016 -0800 +++ b/src/share/vm/gc_implementation/shared/gcTraceTime.cpp Mon Jan 25 14:57:27 2016 -0800 @@ -49,10 +49,8 @@ } if (_doit) { - if (PrintGCTimeStamps) { - gclog_or_tty->stamp(); - gclog_or_tty->print(": "); - } + gclog_or_tty->date_stamp(PrintGCDateStamps); + gclog_or_tty->stamp(PrintGCTimeStamps); if (PrintGCID) { gclog_or_tty->print("#%u: ", gc_id.id()); } diff -r c2687aa5e5ca -r 7eb99acd567f src/share/vm/gc_implementation/shared/mutableSpace.cpp --- a/src/share/vm/gc_implementation/shared/mutableSpace.cpp Mon Jan 25 14:56:57 2016 -0800 +++ b/src/share/vm/gc_implementation/shared/mutableSpace.cpp Mon Jan 25 14:57:27 2016 -0800 @@ -62,9 +62,7 @@ } void MutableSpace::pretouch_pages(MemRegion mr) { - for (volatile char *p = (char*)mr.start(); p < (char*)mr.end(); p += os::vm_page_size()) { - char t = *p; *p = t; - } + os::pretouch_memory((char*)mr.start(), (char*)mr.end()); } void MutableSpace::initialize(MemRegion mr, diff -r c2687aa5e5ca -r 7eb99acd567f src/share/vm/gc_implementation/shared/vmGCOperations.cpp --- a/src/share/vm/gc_implementation/shared/vmGCOperations.cpp Mon Jan 25 14:56:57 2016 -0800 +++ b/src/share/vm/gc_implementation/shared/vmGCOperations.cpp Mon Jan 25 14:57:27 2016 -0800 @@ -193,10 +193,10 @@ GenCollectedHeap* gch = GenCollectedHeap::heap(); GCCauseSetter gccs(gch, _gc_cause); - _res = gch->satisfy_failed_allocation(_size, _tlab); - assert(gch->is_in_reserved_or_null(_res), "result not in heap"); + _result = gch->satisfy_failed_allocation(_word_size, _tlab); + assert(gch->is_in_reserved_or_null(_result), "result not in heap"); - if (_res == NULL && GC_locker::is_active_and_needs_gc()) { + if (_result == NULL && GC_locker::is_active_and_needs_gc()) { set_gc_locked(); } } @@ -209,6 +209,18 @@ gch->do_full_collection(gch->must_clear_all_soft_refs(), _max_level); } +VM_CollectForMetadataAllocation::VM_CollectForMetadataAllocation(ClassLoaderData* loader_data, + size_t size, + Metaspace::MetadataType mdtype, + uint gc_count_before, + uint full_gc_count_before, + GCCause::Cause gc_cause) + : VM_GC_Operation(gc_count_before, gc_cause, full_gc_count_before, true), + _loader_data(loader_data), _size(size), _mdtype(mdtype), _result(NULL) { + assert(_size != 0, "An allocation should always be requested with this operation."); + AllocTracer::send_allocation_requiring_gc_event(_size * HeapWordSize, GCId::peek()); +} + // Returns true iff concurrent GCs unloads metadata. bool VM_CollectForMetadataAllocation::initiate_concurrent_GC() { #if INCLUDE_ALL_GCS @@ -313,3 +325,11 @@ set_gc_locked(); } } + +VM_CollectForAllocation::VM_CollectForAllocation(size_t word_size, uint gc_count_before, GCCause::Cause cause) + : VM_GC_Operation(gc_count_before, cause), _result(NULL), _word_size(word_size) { + // Only report if operation was really caused by an allocation. + if (_word_size != 0) { + AllocTracer::send_allocation_requiring_gc_event(_word_size * HeapWordSize, GCId::peek()); + } +} diff -r c2687aa5e5ca -r 7eb99acd567f src/share/vm/gc_implementation/shared/vmGCOperations.hpp --- a/src/share/vm/gc_implementation/shared/vmGCOperations.hpp Mon Jan 25 14:56:57 2016 -0800 +++ b/src/share/vm/gc_implementation/shared/vmGCOperations.hpp Mon Jan 25 14:57:27 2016 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 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 @@ -25,6 +25,7 @@ #ifndef SHARE_VM_GC_IMPLEMENTATION_SHARED_VMGCOPERATIONS_HPP #define SHARE_VM_GC_IMPLEMENTATION_SHARED_VMGCOPERATIONS_HPP +#include "gc_implementation/shared/gcId.hpp" #include "memory/heapInspection.hpp" #include "runtime/handles.hpp" #include "runtime/jniHandles.hpp" @@ -38,11 +39,12 @@ // VM_Operation // VM_GC_Operation // VM_GC_HeapInspection -// VM_GenCollectForAllocation // VM_GenCollectFull // VM_GenCollectFullConcurrent -// VM_ParallelGCFailedAllocation // VM_ParallelGCSystemGC +// VM_CollectForAllocation +// VM_GenCollectForAllocation +// VM_ParallelGCFailedAllocation // VM_GC_Operation // - implements methods common to all classes in the hierarchy: // prevents multiple gc requests and manages lock on heap; @@ -51,6 +53,7 @@ // - prints class histogram on SIGBREAK if PrintClassHistogram // is specified; and also the attach "inspectheap" operation // +// VM_CollectForAllocation // VM_GenCollectForAllocation // VM_ParallelGCFailedAllocation // - this operation is invoked when allocation is failed; @@ -66,13 +69,13 @@ class VM_GC_Operation: public VM_Operation { protected: - BasicLock _pending_list_basic_lock; // for refs pending list notification (PLL) - unsigned int _gc_count_before; // gc count before acquiring PLL - unsigned int _full_gc_count_before; // full gc count before acquiring PLL - bool _full; // whether a "full" collection - bool _prologue_succeeded; // whether doit_prologue succeeded + BasicLock _pending_list_basic_lock; // for refs pending list notification (PLL) + uint _gc_count_before; // gc count before acquiring PLL + uint _full_gc_count_before; // full gc count before acquiring PLL + bool _full; // whether a "full" collection + bool _prologue_succeeded; // whether doit_prologue succeeded GCCause::Cause _gc_cause; // the putative cause for this gc op - bool _gc_locked; // will be set if gc was locked + bool _gc_locked; // will be set if gc was locked virtual bool skip_operation() const; @@ -81,9 +84,9 @@ void release_and_notify_pending_list_lock(); public: - VM_GC_Operation(unsigned int gc_count_before, + VM_GC_Operation(uint gc_count_before, GCCause::Cause _cause, - unsigned int full_gc_count_before = 0, + uint full_gc_count_before = 0, bool full = false) { _full = full; _prologue_succeeded = false; @@ -160,38 +163,45 @@ bool collect(); }; +class VM_CollectForAllocation : public VM_GC_Operation { + protected: + size_t _word_size; // Size of object to be allocated (in number of words) + HeapWord* _result; // Allocation result (NULL if allocation failed) -class VM_GenCollectForAllocation: public VM_GC_Operation { + public: + VM_CollectForAllocation(size_t word_size, uint gc_count_before, GCCause::Cause cause); + + HeapWord* result() const { + return _result; + } +}; + +class VM_GenCollectForAllocation : public VM_CollectForAllocation { private: - HeapWord* _res; - size_t _size; // size of object to be allocated. bool _tlab; // alloc is of a tlab. public: - VM_GenCollectForAllocation(size_t size, + VM_GenCollectForAllocation(size_t word_size, bool tlab, - unsigned int gc_count_before) - : VM_GC_Operation(gc_count_before, GCCause::_allocation_failure), - _size(size), + uint gc_count_before) + : VM_CollectForAllocation(word_size, gc_count_before, GCCause::_allocation_failure), _tlab(tlab) { - _res = NULL; + assert(word_size != 0, "An allocation should always be requested with this operation."); } ~VM_GenCollectForAllocation() {} virtual VMOp_Type type() const { return VMOp_GenCollectForAllocation; } virtual void doit(); - HeapWord* result() const { return _res; } }; - // VM operation to invoke a collection of the heap as a // GenCollectedHeap heap. class VM_GenCollectFull: public VM_GC_Operation { private: int _max_level; public: - VM_GenCollectFull(unsigned int gc_count_before, - unsigned int full_gc_count_before, + VM_GenCollectFull(uint gc_count_before, + uint full_gc_count_before, GCCause::Cause gc_cause, - int max_level) + int max_level) : VM_GC_Operation(gc_count_before, gc_cause, full_gc_count_before, true /* full */), _max_level(max_level) { } ~VM_GenCollectFull() {} @@ -208,12 +218,9 @@ public: VM_CollectForMetadataAllocation(ClassLoaderData* loader_data, size_t size, Metaspace::MetadataType mdtype, - unsigned int gc_count_before, - unsigned int full_gc_count_before, - GCCause::Cause gc_cause) - : VM_GC_Operation(gc_count_before, gc_cause, full_gc_count_before, true), - _loader_data(loader_data), _size(size), _mdtype(mdtype), _result(NULL) { - } + uint gc_count_before, + uint full_gc_count_before, + GCCause::Cause gc_cause); virtual VMOp_Type type() const { return VMOp_CollectForMetadataAllocation; } virtual void doit(); MetaWord* result() const { return _result; } diff -r c2687aa5e5ca -r 7eb99acd567f src/share/vm/gc_interface/allocTracer.cpp --- a/src/share/vm/gc_interface/allocTracer.cpp Mon Jan 25 14:56:57 2016 -0800 +++ b/src/share/vm/gc_interface/allocTracer.cpp Mon Jan 25 14:57:27 2016 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 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 @@ -23,6 +23,7 @@ */ #include "precompiled.hpp" +#include "gc_implementation/shared/gcId.hpp" #include "gc_interface/allocTracer.hpp" #include "trace/tracing.hpp" #include "runtime/handles.hpp" @@ -46,3 +47,12 @@ event.commit(); } } + +void AllocTracer::send_allocation_requiring_gc_event(size_t size, const GCId& gcId) { + EventAllocationRequiringGC event; + if (event.should_commit()) { + event.set_gcId(gcId.id()); + event.set_size(size); + event.commit(); + } +} diff -r c2687aa5e5ca -r 7eb99acd567f src/share/vm/gc_interface/allocTracer.hpp --- a/src/share/vm/gc_interface/allocTracer.hpp Mon Jan 25 14:56:57 2016 -0800 +++ b/src/share/vm/gc_interface/allocTracer.hpp Mon Jan 25 14:57:27 2016 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 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 @@ -32,6 +32,7 @@ public: static void send_allocation_outside_tlab_event(KlassHandle klass, size_t alloc_size); static void send_allocation_in_new_tlab_event(KlassHandle klass, size_t tlab_size, size_t alloc_size); + static void send_allocation_requiring_gc_event(size_t size, const GCId& gcId); }; #endif /* SHARE_VM_GC_INTERFACE_ALLOCTRACER_HPP */ diff -r c2687aa5e5ca -r 7eb99acd567f src/share/vm/interpreter/abstractInterpreter.hpp --- a/src/share/vm/interpreter/abstractInterpreter.hpp Mon Jan 25 14:56:57 2016 -0800 +++ b/src/share/vm/interpreter/abstractInterpreter.hpp Mon Jan 25 14:57:27 2016 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 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 @@ -30,22 +30,15 @@ #include "runtime/thread.inline.hpp" #include "runtime/vmThread.hpp" #include "utilities/top.hpp" -#ifdef TARGET_ARCH_x86 +#if defined INTERP_MASM_MD_HPP +# include INTERP_MASM_MD_HPP +#elif defined TARGET_ARCH_x86 # include "interp_masm_x86.hpp" -#endif -#ifdef TARGET_ARCH_MODEL_sparc +#elif defined TARGET_ARCH_MODEL_sparc # include "interp_masm_sparc.hpp" -#endif -#ifdef TARGET_ARCH_MODEL_zero +#elif defined TARGET_ARCH_MODEL_zero # include "interp_masm_zero.hpp" -#endif -#ifdef TARGET_ARCH_MODEL_arm -# include "interp_masm_arm.hpp" -#endif -#ifdef TARGET_ARCH_MODEL_ppc_32 -# include "interp_masm_ppc_32.hpp" -#endif -#ifdef TARGET_ARCH_MODEL_ppc_64 +#elif defined TARGET_ARCH_MODEL_ppc_64 # include "interp_masm_ppc_64.hpp" #endif diff -r c2687aa5e5ca -r 7eb99acd567f src/share/vm/interpreter/bytecodeInterpreter.cpp --- a/src/share/vm/interpreter/bytecodeInterpreter.cpp Mon Jan 25 14:56:57 2016 -0800 +++ b/src/share/vm/interpreter/bytecodeInterpreter.cpp Mon Jan 25 14:57:27 2016 -0800 @@ -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, (uintptr_t) this->_oop_temp); + tty->print_cr("native_mirror: " INTPTR_FORMAT, (uintptr_t) p2i(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); diff -r c2687aa5e5ca -r 7eb99acd567f src/share/vm/interpreter/bytecodes.hpp --- a/src/share/vm/interpreter/bytecodes.hpp Mon Jan 25 14:56:57 2016 -0800 +++ b/src/share/vm/interpreter/bytecodes.hpp Mon Jan 25 14:57:27 2016 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 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 @@ -420,6 +420,7 @@ static bool is_astore (Code code) { return (code == _astore || code == _astore_0 || code == _astore_1 || code == _astore_2 || code == _astore_3); } + static bool is_store_into_local(Code code){ return (_istore <= code && 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); } diff -r c2687aa5e5ca -r 7eb99acd567f src/share/vm/interpreter/interpreterRuntime.cpp --- a/src/share/vm/interpreter/interpreterRuntime.cpp Mon Jan 25 14:56:57 2016 -0800 +++ b/src/share/vm/interpreter/interpreterRuntime.cpp Mon Jan 25 14:57:27 2016 -0800 @@ -407,7 +407,11 @@ // during deoptimization so the interpreter needs to skip it when // the frame is popped. thread->set_do_not_unlock_if_synchronized(true); +#ifdef CC_INTERP + return (address) -1; +#else return Interpreter::remove_activation_entry(); +#endif } // Need to do this check first since when _do_not_unlock_if_synchronized @@ -1313,6 +1317,8 @@ member_name_oop = java_lang_invoke_DirectMethodHandle::member(member_name_oop); } thread->set_vm_result(member_name_oop); + } else { + thread->set_vm_result(NULL); } IRT_END #endif // INCLUDE_JVMTI diff -r c2687aa5e5ca -r 7eb99acd567f src/share/vm/interpreter/linkResolver.cpp --- a/src/share/vm/interpreter/linkResolver.cpp Mon Jan 25 14:56:57 2016 -0800 +++ b/src/share/vm/interpreter/linkResolver.cpp Mon Jan 25 14:57:27 2016 -0800 @@ -1414,10 +1414,11 @@ KlassHandle resolved_klass, Symbol* name, Symbol* signature, - KlassHandle current_klass) { + KlassHandle current_klass, + bool check_access) { EXCEPTION_MARK; CallInfo info; - resolve_virtual_call(info, Handle(), receiver_klass, resolved_klass, name, signature, current_klass, true, false, THREAD); + resolve_virtual_call(info, Handle(), receiver_klass, resolved_klass, name, signature, current_klass, check_access, false, THREAD); if (HAS_PENDING_EXCEPTION) { CLEAR_PENDING_EXCEPTION; return methodHandle(); @@ -1430,10 +1431,11 @@ KlassHandle resolved_klass, Symbol* name, Symbol* signature, - KlassHandle current_klass) { + KlassHandle current_klass, + bool check_access) { EXCEPTION_MARK; CallInfo info; - resolve_interface_call(info, Handle(), receiver_klass, resolved_klass, name, signature, current_klass, true, false, THREAD); + resolve_interface_call(info, Handle(), receiver_klass, resolved_klass, name, signature, current_klass, check_access, false, THREAD); if (HAS_PENDING_EXCEPTION) { CLEAR_PENDING_EXCEPTION; return methodHandle(); @@ -1461,10 +1463,11 @@ KlassHandle resolved_klass, Symbol* name, Symbol* signature, - KlassHandle current_klass) { + KlassHandle current_klass, + bool check_access) { EXCEPTION_MARK; CallInfo info; - resolve_static_call(info, resolved_klass, name, signature, current_klass, true, false, THREAD); + resolve_static_call(info, resolved_klass, name, signature, current_klass, check_access, false, THREAD); if (HAS_PENDING_EXCEPTION) { CLEAR_PENDING_EXCEPTION; return methodHandle(); @@ -1472,11 +1475,15 @@ return info.selected_method(); } -methodHandle LinkResolver::resolve_special_call_or_null(KlassHandle resolved_klass, Symbol* name, Symbol* signature, - KlassHandle current_klass) { +methodHandle LinkResolver::resolve_special_call_or_null( + KlassHandle resolved_klass, + Symbol* name, + Symbol* signature, + KlassHandle current_klass, + bool check_access) { EXCEPTION_MARK; CallInfo info; - resolve_special_call(info, resolved_klass, name, signature, current_klass, true, THREAD); + resolve_special_call(info, resolved_klass, name, signature, current_klass, check_access, THREAD); if (HAS_PENDING_EXCEPTION) { CLEAR_PENDING_EXCEPTION; return methodHandle(); @@ -1589,6 +1596,26 @@ result.set_handle(resolved_method, resolved_appendix, resolved_method_type, CHECK); } +static void wrap_invokedynamic_exception(TRAPS) { + if (HAS_PENDING_EXCEPTION) { + if (TraceMethodHandles) { + tty->print_cr("invokedynamic throws BSME for " INTPTR_FORMAT, p2i((void *)PENDING_EXCEPTION)); + PENDING_EXCEPTION->print(); + } + if (PENDING_EXCEPTION->is_a(SystemDictionary::BootstrapMethodError_klass())) { + // throw these guys, since they are already wrapped + return; + } + if (!PENDING_EXCEPTION->is_a(SystemDictionary::LinkageError_klass())) { + // intercept only LinkageErrors which might have failed to wrap + return; + } + // See the "Linking Exceptions" section for the invokedynamic instruction in the JVMS. + Handle nested_exception(THREAD, PENDING_EXCEPTION); + CLEAR_PENDING_EXCEPTION; + THROW_CAUSE(vmSymbols::java_lang_BootstrapMethodError(), nested_exception) + } +} void LinkResolver::resolve_invokedynamic(CallInfo& result, constantPoolHandle pool, int index, TRAPS) { assert(EnableInvokeDynamic, ""); @@ -1604,7 +1631,8 @@ ConstantPoolCacheEntry* cpce = pool->invokedynamic_cp_cache_entry_at(index); if (cpce->is_f1_null()) { int pool_index = cpce->constant_pool_index(); - oop bsm_info = pool->resolve_bootstrap_specifier_at(pool_index, CHECK); + oop bsm_info = pool->resolve_bootstrap_specifier_at(pool_index, THREAD); + wrap_invokedynamic_exception(CHECK); assert(bsm_info != NULL, ""); // FIXME: Cache this once per BootstrapMethods entry, not once per CONSTANT_InvokeDynamic. bootstrap_specifier = Handle(THREAD, bsm_info); @@ -1613,7 +1641,8 @@ methodHandle method( THREAD, cpce->f1_as_method()); Handle appendix( THREAD, cpce->appendix_if_resolved(pool)); Handle method_type(THREAD, cpce->method_type_if_resolved(pool)); - result.set_handle(method, appendix, method_type, CHECK); + result.set_handle(method, appendix, method_type, THREAD); + wrap_invokedynamic_exception(CHECK); return; } @@ -1644,25 +1673,9 @@ &resolved_appendix, &resolved_method_type, THREAD); - if (HAS_PENDING_EXCEPTION) { - if (TraceMethodHandles) { - tty->print_cr("invokedynamic throws BSME for " INTPTR_FORMAT, p2i((void *)PENDING_EXCEPTION)); - PENDING_EXCEPTION->print(); - } - if (PENDING_EXCEPTION->is_a(SystemDictionary::BootstrapMethodError_klass())) { - // throw these guys, since they are already wrapped - return; - } - if (!PENDING_EXCEPTION->is_a(SystemDictionary::LinkageError_klass())) { - // intercept only LinkageErrors which might have failed to wrap - return; - } - // See the "Linking Exceptions" section for the invokedynamic instruction in the JVMS. - Handle nested_exception(THREAD, PENDING_EXCEPTION); - CLEAR_PENDING_EXCEPTION; - THROW_CAUSE(vmSymbols::java_lang_BootstrapMethodError(), nested_exception) - } - result.set_handle(resolved_method, resolved_appendix, resolved_method_type, CHECK); + wrap_invokedynamic_exception(CHECK); + result.set_handle(resolved_method, resolved_appendix, resolved_method_type, THREAD); + wrap_invokedynamic_exception(CHECK); } //------------------------------------------------------------------------------------------------------------------------ diff -r c2687aa5e5ca -r 7eb99acd567f src/share/vm/interpreter/linkResolver.hpp --- a/src/share/vm/interpreter/linkResolver.hpp Mon Jan 25 14:56:57 2016 -0800 +++ b/src/share/vm/interpreter/linkResolver.hpp Mon Jan 25 14:57:27 2016 -0800 @@ -186,10 +186,10 @@ // same as above for compile-time resolution; but returns null handle instead of throwing an exception on error // also, does not initialize klass (i.e., no side effects) - static methodHandle resolve_virtual_call_or_null (KlassHandle receiver_klass, KlassHandle resolved_klass, Symbol* method_name, Symbol* method_signature, KlassHandle current_klass); - static methodHandle resolve_interface_call_or_null(KlassHandle receiver_klass, KlassHandle resolved_klass, Symbol* method_name, Symbol* method_signature, KlassHandle current_klass); - static methodHandle resolve_static_call_or_null (KlassHandle resolved_klass, Symbol* method_name, Symbol* method_signature, KlassHandle current_klass); - static methodHandle resolve_special_call_or_null (KlassHandle resolved_klass, Symbol* method_name, Symbol* method_signature, KlassHandle current_klass); + static methodHandle resolve_virtual_call_or_null (KlassHandle receiver_klass, KlassHandle resolved_klass, Symbol* method_name, Symbol* method_signature, KlassHandle current_klass, bool check_access = true); + static methodHandle resolve_interface_call_or_null(KlassHandle receiver_klass, KlassHandle resolved_klass, Symbol* method_name, Symbol* method_signature, KlassHandle current_klass, bool check_access = true); + static methodHandle resolve_static_call_or_null (KlassHandle resolved_klass, Symbol* method_name, Symbol* method_signature, KlassHandle current_klass, bool check_access = true); + static methodHandle resolve_special_call_or_null (KlassHandle resolved_klass, Symbol* method_name, Symbol* method_signature, KlassHandle current_klass, bool check_access = true); static int vtable_index_of_interface_method(KlassHandle klass, methodHandle resolved_method); // same as above for compile-time resolution; returns vtable_index if current_klass if linked diff -r c2687aa5e5ca -r 7eb99acd567f src/share/vm/interpreter/oopMapCache.cpp --- a/src/share/vm/interpreter/oopMapCache.cpp Mon Jan 25 14:56:57 2016 -0800 +++ b/src/share/vm/interpreter/oopMapCache.cpp Mon Jan 25 14:57:27 2016 -0800 @@ -244,10 +244,8 @@ method()->print_value(); tty->print(" @ %d = [%d] { ", bci(), n); for (int i = 0; i < n; i++) { -#ifdef ENABLE_ZAP_DEAD_LOCALS if (is_dead(i)) tty->print("%d+ ", i); else -#endif if (is_oop(i)) tty->print("%d ", i); } tty->print_cr("}"); @@ -402,13 +400,11 @@ value |= (mask << oop_bit_number ); } - #ifdef ENABLE_ZAP_DEAD_LOCALS // set dead bit if (!cell->is_live()) { value |= (mask << dead_bit_number); assert(!cell->is_reference(), "dead value marked as oop"); } - #endif } // make sure last word is stored diff -r c2687aa5e5ca -r 7eb99acd567f src/share/vm/interpreter/oopMapCache.hpp --- a/src/share/vm/interpreter/oopMapCache.hpp Mon Jan 25 14:56:57 2016 -0800 +++ b/src/share/vm/interpreter/oopMapCache.hpp Mon Jan 25 14:57:27 2016 -0800 @@ -66,19 +66,15 @@ public: enum { - N = 2, // the number of words reserved + N = 4, // the number of words reserved // for inlined mask storage small_mask_limit = N * BitsPerWord, // the maximum number of bits // available for small masks, // small_mask_limit can be set to 0 // for testing bit_mask allocation -#ifdef ENABLE_ZAP_DEAD_LOCALS bits_per_entry = 2, dead_bit_number = 1, -#else - bits_per_entry = 1, -#endif oop_bit_number = 0 }; @@ -119,10 +115,6 @@ void set_expression_stack_size(int sz) { _expression_stack_size = sz; } -#ifdef ENABLE_ZAP_DEAD_LOCALS - bool is_dead(int offset) const { return (entry_at(offset) & (1 << dead_bit_number)) != 0; } -#endif - // Lookup bool match(methodHandle method, int bci) const { return _method == method() && _bci == bci; } bool is_empty() const; @@ -144,6 +136,7 @@ void print() const; int number_of_entries() const { return mask_size() / bits_per_entry; } + bool is_dead(int offset) const { return (entry_at(offset) & (1 << dead_bit_number)) != 0; } bool is_oop (int offset) const { return (entry_at(offset) & (1 << oop_bit_number )) != 0; } int expression_stack_size() const { return _expression_stack_size; } diff -r c2687aa5e5ca -r 7eb99acd567f src/share/vm/interpreter/templateTable.hpp --- a/src/share/vm/interpreter/templateTable.hpp Mon Jan 25 14:56:57 2016 -0800 +++ b/src/share/vm/interpreter/templateTable.hpp Mon Jan 25 14:57:27 2016 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 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 @@ -28,22 +28,15 @@ #include "interpreter/bytecodes.hpp" #include "memory/allocation.hpp" #include "runtime/frame.hpp" -#ifdef TARGET_ARCH_x86 +#if defined INTERP_MASM_MD_HPP +# include INTERP_MASM_MD_HPP +#elif defined TARGET_ARCH_x86 # include "interp_masm_x86.hpp" -#endif -#ifdef TARGET_ARCH_MODEL_sparc +#elif defined TARGET_ARCH_MODEL_sparc # include "interp_masm_sparc.hpp" -#endif -#ifdef TARGET_ARCH_MODEL_zero +#elif defined TARGET_ARCH_MODEL_zero # include "interp_masm_zero.hpp" -#endif -#ifdef TARGET_ARCH_MODEL_arm -# include "interp_masm_arm.hpp" -#endif -#ifdef TARGET_ARCH_MODEL_ppc_32 -# include "interp_masm_ppc_32.hpp" -#endif -#ifdef TARGET_ARCH_MODEL_ppc_64 +#elif defined TARGET_ARCH_MODEL_ppc_64 # include "interp_masm_ppc_64.hpp" #endif @@ -358,25 +351,17 @@ static Template* template_for_wide(Bytecodes::Code code) { Bytecodes::wide_check(code); return &_template_table_wide[code]; } // Platform specifics -#ifdef TARGET_ARCH_MODEL_x86_32 +#if defined TEMPLATETABLE_MD_HPP +# include TEMPLATETABLE_MD_HPP +#elif defined TARGET_ARCH_MODEL_x86_32 # include "templateTable_x86_32.hpp" -#endif -#ifdef TARGET_ARCH_MODEL_x86_64 +#elif defined TARGET_ARCH_MODEL_x86_64 # include "templateTable_x86_64.hpp" -#endif -#ifdef TARGET_ARCH_MODEL_sparc +#elif defined TARGET_ARCH_MODEL_sparc # include "templateTable_sparc.hpp" -#endif -#ifdef TARGET_ARCH_MODEL_zero +#elif defined TARGET_ARCH_MODEL_zero # include "templateTable_zero.hpp" -#endif -#ifdef TARGET_ARCH_MODEL_arm -# include "templateTable_arm.hpp" -#endif -#ifdef TARGET_ARCH_MODEL_ppc_32 -# include "templateTable_ppc_32.hpp" -#endif -#ifdef TARGET_ARCH_MODEL_ppc_64 +#elif defined TARGET_ARCH_MODEL_ppc_64 # include "templateTable_ppc_64.hpp" #endif diff -r c2687aa5e5ca -r 7eb99acd567f src/share/vm/memory/allocation.inline.hpp --- a/src/share/vm/memory/allocation.inline.hpp Mon Jan 25 14:56:57 2016 -0800 +++ b/src/share/vm/memory/allocation.inline.hpp Mon Jan 25 14:57:27 2016 -0800 @@ -62,11 +62,18 @@ } return p; } + +#ifdef __GNUC__ +__attribute__((always_inline)) +#endif inline char* AllocateHeap(size_t size, MEMFLAGS flags, AllocFailType alloc_failmode = AllocFailStrategy::EXIT_OOM) { return AllocateHeap(size, flags, CURRENT_PC, alloc_failmode); } +#ifdef __GNUC__ +__attribute__((always_inline)) +#endif inline char* ReallocateHeap(char *old, size_t size, MEMFLAGS flag, AllocFailType alloc_failmode = AllocFailStrategy::EXIT_OOM) { char* p = (char*) os::realloc(old, size, flag, CURRENT_PC); diff -r c2687aa5e5ca -r 7eb99acd567f src/share/vm/memory/collectorPolicy.cpp --- a/src/share/vm/memory/collectorPolicy.cpp Mon Jan 25 14:56:57 2016 -0800 +++ b/src/share/vm/memory/collectorPolicy.cpp Mon Jan 25 14:57:27 2016 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 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 @@ -656,7 +656,7 @@ // Loop until the allocation is satisified, // or unsatisfied after GC. - for (int try_count = 1, gclocker_stalled_count = 0; /* return or throw */; try_count += 1) { + for (uint try_count = 1, gclocker_stalled_count = 0; /* return or throw */; try_count += 1) { HandleMark hm; // discard any handles allocated in each iteration // First allocation attempt is lock-free. @@ -670,7 +670,7 @@ return result; } } - unsigned int gc_count_before; // read inside the Heap_lock locked region + uint gc_count_before; // read inside the Heap_lock locked region { MutexLocker ml(Heap_lock); if (PrintGC && Verbose) { diff -r c2687aa5e5ca -r 7eb99acd567f src/share/vm/memory/defNewGeneration.cpp --- a/src/share/vm/memory/defNewGeneration.cpp Mon Jan 25 14:56:57 2016 -0800 +++ b/src/share/vm/memory/defNewGeneration.cpp Mon Jan 25 14:57:27 2016 -0800 @@ -629,7 +629,7 @@ true, // Process younger gens, if any, // as strong roots. true, // activate StrongRootsScope - SharedHeap::SO_ScavengeCodeCache, + GenCollectedHeap::SO_ScavengeCodeCache, GenCollectedHeap::StrongAndWeakRoots, &fsc_with_no_gc_barrier, &fsc_with_gc_barrier, diff -r c2687aa5e5ca -r 7eb99acd567f src/share/vm/memory/genCollectedHeap.cpp --- a/src/share/vm/memory/genCollectedHeap.cpp Mon Jan 25 14:56:57 2016 -0800 +++ b/src/share/vm/memory/genCollectedHeap.cpp Mon Jan 25 14:57:27 2016 -0800 @@ -26,6 +26,7 @@ #include "classfile/symbolTable.hpp" #include "classfile/systemDictionary.hpp" #include "classfile/vmSymbols.hpp" +#include "code/codeCache.hpp" #include "code/icBuffer.hpp" #include "gc_implementation/shared/collectorCounters.hpp" #include "gc_implementation/shared/gcTrace.hpp" @@ -49,6 +50,7 @@ #include "runtime/handles.inline.hpp" #include "runtime/java.hpp" #include "runtime/vmThread.hpp" +#include "services/management.hpp" #include "services/memoryService.hpp" #include "utilities/vmError.hpp" #include "utilities/workgroup.hpp" @@ -63,7 +65,15 @@ // The set of potentially parallel tasks in root scanning. enum GCH_strong_roots_tasks { - // We probably want to parallelize both of these internally, but for now... + GCH_PS_Universe_oops_do, + GCH_PS_JNIHandles_oops_do, + GCH_PS_ObjectSynchronizer_oops_do, + GCH_PS_FlatProfiler_oops_do, + GCH_PS_Management_oops_do, + GCH_PS_SystemDictionary_oops_do, + GCH_PS_ClassLoaderDataGraph_oops_do, + GCH_PS_jvmti_oops_do, + GCH_PS_CodeCache_oops_do, GCH_PS_younger_gens, // Leave this one last. GCH_PS_NumElements @@ -72,13 +82,9 @@ GenCollectedHeap::GenCollectedHeap(GenCollectorPolicy *policy) : SharedHeap(policy), _gen_policy(policy), - _gen_process_roots_tasks(new SubTasksDone(GCH_PS_NumElements)), + _process_strong_tasks(new SubTasksDone(GCH_PS_NumElements)), _full_collections_completed(0) { - if (_gen_process_roots_tasks == NULL || - !_gen_process_roots_tasks->valid()) { - vm_exit_during_initialization("Failed necessary allocation."); - } assert(policy != NULL, "Sanity check"); } @@ -384,7 +390,6 @@ bool complete = full && (max_level == (n_gens()-1)); const char* gc_cause_prefix = complete ? "Full GC" : "GC"; - gclog_or_tty->date_stamp(PrintGC && PrintGCDateStamps); TraceCPUTime tcpu(PrintGCDetails, true, gclog_or_tty); // The PrintGCDetails logging starts before we have incremented the GC id. We will do that later // so we can assume here that the next GC id is what we want. @@ -594,29 +599,137 @@ void GenCollectedHeap::set_par_threads(uint t) { SharedHeap::set_par_threads(t); - _gen_process_roots_tasks->set_n_threads(t); + set_n_termination(t); +} + +void GenCollectedHeap::set_n_termination(uint t) { + _process_strong_tasks->set_n_threads(t); } -void GenCollectedHeap:: -gen_process_roots(int level, - bool younger_gens_as_roots, - bool activate_scope, - SharedHeap::ScanningOption so, - OopsInGenClosure* not_older_gens, - OopsInGenClosure* weak_roots, - OopsInGenClosure* older_gens, - CLDClosure* cld_closure, - CLDClosure* weak_cld_closure, - CodeBlobClosure* code_closure) { +#ifdef ASSERT +class AssertNonScavengableClosure: public OopClosure { +public: + virtual void do_oop(oop* p) { + assert(!Universe::heap()->is_in_partial_collection(*p), + "Referent should not be scavengable."); } + virtual void do_oop(narrowOop* p) { ShouldNotReachHere(); } +}; +static AssertNonScavengableClosure assert_is_non_scavengable_closure; +#endif + +void GenCollectedHeap::process_roots(bool activate_scope, + ScanningOption so, + OopClosure* strong_roots, + OopClosure* weak_roots, + CLDClosure* strong_cld_closure, + CLDClosure* weak_cld_closure, + CodeBlobClosure* code_roots) { + StrongRootsScope srs(this, activate_scope); // General roots. - SharedHeap::process_roots(activate_scope, so, - not_older_gens, weak_roots, - cld_closure, weak_cld_closure, - code_closure); + assert(_strong_roots_parity != 0, "must have called prologue code"); + assert(code_roots != NULL, "code root closure should always be set"); + // _n_termination for _process_strong_tasks should be set up stream + // in a method not running in a GC worker. Otherwise the GC worker + // could be trying to change the termination condition while the task + // is executing in another GC worker. + + if (!_process_strong_tasks->is_task_claimed(GCH_PS_ClassLoaderDataGraph_oops_do)) { + ClassLoaderDataGraph::roots_cld_do(strong_cld_closure, weak_cld_closure); + } + + // Some CLDs contained in the thread frames should be considered strong. + // Don't process them if they will be processed during the ClassLoaderDataGraph phase. + CLDClosure* roots_from_clds_p = (strong_cld_closure != weak_cld_closure) ? strong_cld_closure : NULL; + // Only process code roots from thread stacks if we aren't visiting the entire CodeCache anyway + CodeBlobClosure* roots_from_code_p = (so & SO_AllCodeCache) ? NULL : code_roots; + + Threads::possibly_parallel_oops_do(strong_roots, roots_from_clds_p, roots_from_code_p); + + if (!_process_strong_tasks->is_task_claimed(GCH_PS_Universe_oops_do)) { + Universe::oops_do(strong_roots); + } + // Global (strong) JNI handles + if (!_process_strong_tasks->is_task_claimed(GCH_PS_JNIHandles_oops_do)) { + JNIHandles::oops_do(strong_roots); + } + + if (!_process_strong_tasks->is_task_claimed(GCH_PS_ObjectSynchronizer_oops_do)) { + ObjectSynchronizer::oops_do(strong_roots); + } + if (!_process_strong_tasks->is_task_claimed(GCH_PS_FlatProfiler_oops_do)) { + FlatProfiler::oops_do(strong_roots); + } + if (!_process_strong_tasks->is_task_claimed(GCH_PS_Management_oops_do)) { + Management::oops_do(strong_roots); + } + if (!_process_strong_tasks->is_task_claimed(GCH_PS_jvmti_oops_do)) { + JvmtiExport::oops_do(strong_roots); + } + + if (!_process_strong_tasks->is_task_claimed(GCH_PS_SystemDictionary_oops_do)) { + SystemDictionary::roots_oops_do(strong_roots, weak_roots); + } + + // All threads execute the following. A specific chunk of buckets + // from the StringTable are the individual tasks. + if (weak_roots != NULL) { + if (CollectedHeap::use_parallel_gc_threads()) { + StringTable::possibly_parallel_oops_do(weak_roots); + } else { + StringTable::oops_do(weak_roots); + } + } + + if (!_process_strong_tasks->is_task_claimed(GCH_PS_CodeCache_oops_do)) { + if (so & SO_ScavengeCodeCache) { + assert(code_roots != NULL, "must supply closure for code cache"); + + // We only visit parts of the CodeCache when scavenging. + CodeCache::scavenge_root_nmethods_do(code_roots); + } + if (so & SO_AllCodeCache) { + assert(code_roots != NULL, "must supply closure for code cache"); + + // CMSCollector uses this to do intermediate-strength collections. + // We scan the entire code cache, since CodeCache::do_unloading is not called. + CodeCache::blobs_do(code_roots); + } + // Verify that the code cache contents are not subject to + // movement by a scavenging collection. + DEBUG_ONLY(CodeBlobToOopClosure assert_code_is_non_scavengable(&assert_is_non_scavengable_closure, !CodeBlobToOopClosure::FixRelocations)); + DEBUG_ONLY(CodeCache::asserted_non_scavengable_nmethods_do(&assert_code_is_non_scavengable)); + } + +} + +void GenCollectedHeap::gen_process_roots(int level, + bool younger_gens_as_roots, + bool activate_scope, + ScanningOption so, + bool only_strong_roots, + OopsInGenClosure* not_older_gens, + OopsInGenClosure* older_gens, + CLDClosure* cld_closure) { + const bool is_adjust_phase = !only_strong_roots && !younger_gens_as_roots; + + bool is_moving_collection = false; + if (level == 0 || is_adjust_phase) { + // young collections are always moving + is_moving_collection = true; + } + + MarkingCodeBlobClosure mark_code_closure(not_older_gens, is_moving_collection); + OopsInGenClosure* weak_roots = only_strong_roots ? NULL : not_older_gens; + CLDClosure* weak_cld_closure = only_strong_roots ? NULL : cld_closure; + + process_roots(activate_scope, so, + not_older_gens, weak_roots, + cld_closure, weak_cld_closure, + &mark_code_closure); if (younger_gens_as_roots) { - if (!_gen_process_roots_tasks->is_task_claimed(GCH_PS_younger_gens)) { + if (!_process_strong_tasks->is_task_claimed(GCH_PS_younger_gens)) { for (int i = 0; i < level; i++) { not_older_gens->set_generation(_gens[i]); _gens[i]->oop_iterate(not_older_gens); @@ -632,43 +745,18 @@ older_gens->reset_generation(); } - _gen_process_roots_tasks->all_tasks_completed(); + _process_strong_tasks->all_tasks_completed(); } -void GenCollectedHeap:: -gen_process_roots(int level, - bool younger_gens_as_roots, - bool activate_scope, - SharedHeap::ScanningOption so, - bool only_strong_roots, - OopsInGenClosure* not_older_gens, - OopsInGenClosure* older_gens, - CLDClosure* cld_closure) { - const bool is_adjust_phase = !only_strong_roots && !younger_gens_as_roots; - - bool is_moving_collection = false; - if (level == 0 || is_adjust_phase) { - // young collections are always moving - is_moving_collection = true; - } - - MarkingCodeBlobClosure mark_code_closure(not_older_gens, is_moving_collection); - CodeBlobClosure* code_closure = &mark_code_closure; - - gen_process_roots(level, - younger_gens_as_roots, - activate_scope, so, - not_older_gens, only_strong_roots ? NULL : not_older_gens, - older_gens, - cld_closure, only_strong_roots ? NULL : cld_closure, - code_closure); - -} +class AlwaysTrueClosure: public BoolObjectClosure { +public: + bool do_object_b(oop p) { return true; } +}; +static AlwaysTrueClosure always_true; void GenCollectedHeap::gen_process_weak_roots(OopClosure* root_closure) { - SharedHeap::process_weak_roots(root_closure); - // "Local" "weak" refs + JNIHandles::weak_oops_do(&always_true, root_closure); for (int i = 0; i < _n_gens; i++) { _gens[i]->ref_processor()->weak_oops_do(root_closure); } diff -r c2687aa5e5ca -r 7eb99acd567f src/share/vm/memory/genCollectedHeap.hpp --- a/src/share/vm/memory/genCollectedHeap.hpp Mon Jan 25 14:56:57 2016 -0800 +++ b/src/share/vm/memory/genCollectedHeap.hpp Mon Jan 25 14:57:27 2016 -0800 @@ -79,8 +79,7 @@ // Data structure for claiming the (potentially) parallel tasks in // (gen-specific) roots processing. - SubTasksDone* _gen_process_roots_tasks; - SubTasksDone* gen_process_roots_tasks() { return _gen_process_roots_tasks; } + SubTasksDone* _process_strong_tasks; // In block contents verification, the number of header words to skip NOT_PRODUCT(static size_t _skip_header_HeapWords;) @@ -390,6 +389,7 @@ static GenCollectedHeap* heap(); void set_par_threads(uint t); + void set_n_termination(uint t); // Invoke the "do_oop" method of one of the closures "not_older_gens" // or "older_gens" on root locations for the generation at @@ -403,11 +403,25 @@ // The "so" argument determines which of the roots // the closure is applied to: // "SO_None" does none; + enum ScanningOption { + SO_None = 0x0, + SO_AllCodeCache = 0x8, + SO_ScavengeCodeCache = 0x10 + }; + private: + void process_roots(bool activate_scope, + ScanningOption so, + OopClosure* strong_roots, + OopClosure* weak_roots, + CLDClosure* strong_cld_closure, + CLDClosure* weak_cld_closure, + CodeBlobClosure* code_roots); + void gen_process_roots(int level, bool younger_gens_as_roots, bool activate_scope, - SharedHeap::ScanningOption so, + ScanningOption so, OopsInGenClosure* not_older_gens, OopsInGenClosure* weak_roots, OopsInGenClosure* older_gens, @@ -422,7 +436,7 @@ void gen_process_roots(int level, bool younger_gens_as_roots, bool activate_scope, - SharedHeap::ScanningOption so, + ScanningOption so, bool only_strong_roots, OopsInGenClosure* not_older_gens, OopsInGenClosure* older_gens, diff -r c2687aa5e5ca -r 7eb99acd567f src/share/vm/memory/genMarkSweep.cpp --- a/src/share/vm/memory/genMarkSweep.cpp Mon Jan 25 14:56:57 2016 -0800 +++ b/src/share/vm/memory/genMarkSweep.cpp Mon Jan 25 14:57:27 2016 -0800 @@ -212,8 +212,8 @@ gch->gen_process_roots(level, false, // Younger gens are not roots. true, // activate StrongRootsScope - SharedHeap::SO_None, - GenCollectedHeap::StrongRootsOnly, + GenCollectedHeap::SO_None, + ClassUnloading, &follow_root_closure, &follow_root_closure, &follow_cld_closure); @@ -297,7 +297,7 @@ gch->gen_process_roots(level, false, // Younger gens are not roots. true, // activate StrongRootsScope - SharedHeap::SO_AllCodeCache, + GenCollectedHeap::SO_AllCodeCache, GenCollectedHeap::StrongAndWeakRoots, &adjust_pointer_closure, &adjust_pointer_closure, diff -r c2687aa5e5ca -r 7eb99acd567f src/share/vm/memory/generation.hpp --- a/src/share/vm/memory/generation.hpp Mon Jan 25 14:56:57 2016 -0800 +++ b/src/share/vm/memory/generation.hpp Mon Jan 25 14:57:27 2016 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 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 @@ -145,7 +145,7 @@ // GenGrain. // Note: on ARM we add 1 bit for card_table_base to be properly aligned // (we expect its low byte to be zero - see implementation of post_barrier) - LogOfGenGrain = 16 ARM_ONLY(+1), + LogOfGenGrain = 16 ARM32_ONLY(+1), GenGrain = 1 << LogOfGenGrain }; diff -r c2687aa5e5ca -r 7eb99acd567f src/share/vm/memory/guardedMemory.hpp --- a/src/share/vm/memory/guardedMemory.hpp Mon Jan 25 14:56:57 2016 -0800 +++ b/src/share/vm/memory/guardedMemory.hpp Mon Jan 25 14:57:27 2016 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 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 @@ -235,7 +235,7 @@ * @return the size of the user data. */ size_t get_user_size() const { - assert(_base_addr, "Not wrapping any memory"); + assert(_base_addr != NULL, "Not wrapping any memory"); return get_head_guard()->get_user_size(); } @@ -245,7 +245,7 @@ * @return the user data pointer. */ u_char* get_user_ptr() const { - assert(_base_addr, "Not wrapping any memory"); + assert(_base_addr != NULL, "Not wrapping any memory"); return _base_addr + sizeof(GuardHeader); } @@ -281,7 +281,7 @@ memset(get_user_ptr(), ch, get_user_size()); } -public: + public: /** * Return the total size required for wrapping the given user size. * diff -r c2687aa5e5ca -r 7eb99acd567f src/share/vm/memory/heap.cpp --- a/src/share/vm/memory/heap.cpp Mon Jan 25 14:56:57 2016 -0800 +++ b/src/share/vm/memory/heap.cpp Mon Jan 25 14:57:27 2016 -0800 @@ -97,9 +97,11 @@ _log2_segment_size = exact_log2(segment_size); // Reserve and initialize space for _memory. - const size_t page_size = os::can_execute_large_page_memory() ? - os::page_size_for_region(committed_size, reserved_size, 8) : - os::vm_page_size(); + size_t page_size = os::vm_page_size(); + if (os::can_execute_large_page_memory()) { + page_size = os::page_size_for_region_unaligned(reserved_size, 8); + } + const size_t granularity = os::vm_allocation_granularity(); const size_t r_align = MAX2(page_size, granularity); const size_t r_size = align_size_up(reserved_size, r_align); diff -r c2687aa5e5ca -r 7eb99acd567f src/share/vm/memory/metaspace.cpp diff -r c2687aa5e5ca -r 7eb99acd567f src/share/vm/memory/sharedHeap.cpp --- a/src/share/vm/memory/sharedHeap.cpp Mon Jan 25 14:56:57 2016 -0800 +++ b/src/share/vm/memory/sharedHeap.cpp Mon Jan 25 14:57:27 2016 -0800 @@ -32,7 +32,6 @@ #include "runtime/atomic.inline.hpp" #include "runtime/fprofiler.hpp" #include "runtime/java.hpp" -#include "services/management.hpp" #include "utilities/copy.hpp" #include "utilities/workgroup.hpp" @@ -40,33 +39,13 @@ SharedHeap* SharedHeap::_sh; -// The set of potentially parallel tasks in root scanning. -enum SH_process_roots_tasks { - SH_PS_Universe_oops_do, - SH_PS_JNIHandles_oops_do, - SH_PS_ObjectSynchronizer_oops_do, - SH_PS_FlatProfiler_oops_do, - SH_PS_Management_oops_do, - SH_PS_SystemDictionary_oops_do, - SH_PS_ClassLoaderDataGraph_oops_do, - SH_PS_jvmti_oops_do, - SH_PS_CodeCache_oops_do, - // Leave this one last. - SH_PS_NumElements -}; - SharedHeap::SharedHeap(CollectorPolicy* policy_) : CollectedHeap(), _collector_policy(policy_), _rem_set(NULL), - _strong_roots_scope(NULL), _strong_roots_parity(0), - _process_strong_tasks(new SubTasksDone(SH_PS_NumElements)), _workers(NULL) { - if (_process_strong_tasks == NULL || !_process_strong_tasks->valid()) { - vm_exit_during_initialization("Failed necessary allocation."); - } _sh = this; // ch is static, should be set only once. if ((UseParNewGC || (UseConcMarkSweepGC && (CMSParallelInitialMarkEnabled || @@ -84,14 +63,6 @@ } } -int SharedHeap::n_termination() { - return _process_strong_tasks->n_threads(); -} - -void SharedHeap::set_n_termination(int t) { - _process_strong_tasks->set_n_threads(t); -} - bool SharedHeap::heap_lock_held_for_gc() { Thread* t = Thread::current(); return Heap_lock->owned_by_self() @@ -102,31 +73,6 @@ void SharedHeap::set_par_threads(uint t) { assert(t == 0 || !UseSerialGC, "Cannot have parallel threads"); _n_par_threads = t; - _process_strong_tasks->set_n_threads(t); -} - -#ifdef ASSERT -class AssertNonScavengableClosure: public OopClosure { -public: - virtual void do_oop(oop* p) { - assert(!Universe::heap()->is_in_partial_collection(*p), - "Referent should not be scavengable."); } - virtual void do_oop(narrowOop* p) { ShouldNotReachHere(); } -}; -static AssertNonScavengableClosure assert_is_non_scavengable_closure; -#endif - -SharedHeap::StrongRootsScope* SharedHeap::active_strong_roots_scope() const { - return _strong_roots_scope; -} -void SharedHeap::register_strong_roots_scope(SharedHeap::StrongRootsScope* scope) { - assert(_strong_roots_scope == NULL, "Should only have one StrongRootsScope active"); - assert(scope != NULL, "Illegal argument"); - _strong_roots_scope = scope; -} -void SharedHeap::unregister_strong_roots_scope(SharedHeap::StrongRootsScope* scope) { - assert(_strong_roots_scope == scope, "Wrong scope unregistered"); - _strong_roots_scope = NULL; } void SharedHeap::change_strong_roots_parity() { @@ -140,174 +86,15 @@ } SharedHeap::StrongRootsScope::StrongRootsScope(SharedHeap* heap, bool activate) - : MarkScope(activate), _sh(heap), _n_workers_done_with_threads(0) + : MarkScope(activate), _sh(heap) { if (_active) { - _sh->register_strong_roots_scope(this); _sh->change_strong_roots_parity(); // Zero the claimed high water mark in the StringTable StringTable::clear_parallel_claimed_index(); } } -SharedHeap::StrongRootsScope::~StrongRootsScope() { - if (_active) { - _sh->unregister_strong_roots_scope(this); - } -} - -Monitor* SharedHeap::StrongRootsScope::_lock = new Monitor(Mutex::leaf, "StrongRootsScope lock", false); - -void SharedHeap::StrongRootsScope::mark_worker_done_with_threads(uint n_workers) { - // The Thread work barrier is only needed by G1 Class Unloading. - // No need to use the barrier if this is single-threaded code. - if (UseG1GC && ClassUnloadingWithConcurrentMark && n_workers > 0) { - uint new_value = (uint)Atomic::add(1, &_n_workers_done_with_threads); - if (new_value == n_workers) { - // This thread is last. Notify the others. - MonitorLockerEx ml(_lock, Mutex::_no_safepoint_check_flag); - _lock->notify_all(); - } - } -} - -void SharedHeap::StrongRootsScope::wait_until_all_workers_done_with_threads(uint n_workers) { - assert(UseG1GC, "Currently only used by G1"); - assert(ClassUnloadingWithConcurrentMark, "Currently only needed when doing G1 Class Unloading"); - - // No need to use the barrier if this is single-threaded code. - if (n_workers > 0 && (uint)_n_workers_done_with_threads != n_workers) { - MonitorLockerEx ml(_lock, Mutex::_no_safepoint_check_flag); - while ((uint)_n_workers_done_with_threads != n_workers) { - _lock->wait(Mutex::_no_safepoint_check_flag, 0, false); - } - } -} - -void SharedHeap::process_roots(bool activate_scope, - ScanningOption so, - OopClosure* strong_roots, - OopClosure* weak_roots, - CLDClosure* strong_cld_closure, - CLDClosure* weak_cld_closure, - CodeBlobClosure* code_roots) { - StrongRootsScope srs(this, activate_scope); - - // General roots. - assert(_strong_roots_parity != 0, "must have called prologue code"); - assert(code_roots != NULL, "code root closure should always be set"); - // _n_termination for _process_strong_tasks should be set up stream - // in a method not running in a GC worker. Otherwise the GC worker - // could be trying to change the termination condition while the task - // is executing in another GC worker. - - // Iterating over the CLDG and the Threads are done early to allow G1 to - // first process the strong CLDs and nmethods and then, after a barrier, - // let the thread process the weak CLDs and nmethods. - - if (!_process_strong_tasks->is_task_claimed(SH_PS_ClassLoaderDataGraph_oops_do)) { - ClassLoaderDataGraph::roots_cld_do(strong_cld_closure, weak_cld_closure); - } - - // Some CLDs contained in the thread frames should be considered strong. - // Don't process them if they will be processed during the ClassLoaderDataGraph phase. - CLDClosure* roots_from_clds_p = (strong_cld_closure != weak_cld_closure) ? strong_cld_closure : NULL; - // Only process code roots from thread stacks if we aren't visiting the entire CodeCache anyway - CodeBlobClosure* roots_from_code_p = (so & SO_AllCodeCache) ? NULL : code_roots; - - Threads::possibly_parallel_oops_do(strong_roots, roots_from_clds_p, roots_from_code_p); - - // This is the point where this worker thread will not find more strong CLDs/nmethods. - // Report this so G1 can synchronize the strong and weak CLDs/nmethods processing. - active_strong_roots_scope()->mark_worker_done_with_threads(n_par_threads()); - - if (!_process_strong_tasks->is_task_claimed(SH_PS_Universe_oops_do)) { - Universe::oops_do(strong_roots); - } - // Global (strong) JNI handles - if (!_process_strong_tasks->is_task_claimed(SH_PS_JNIHandles_oops_do)) - JNIHandles::oops_do(strong_roots); - - if (!_process_strong_tasks-> is_task_claimed(SH_PS_ObjectSynchronizer_oops_do)) - ObjectSynchronizer::oops_do(strong_roots); - if (!_process_strong_tasks->is_task_claimed(SH_PS_FlatProfiler_oops_do)) - FlatProfiler::oops_do(strong_roots); - if (!_process_strong_tasks->is_task_claimed(SH_PS_Management_oops_do)) - Management::oops_do(strong_roots); - if (!_process_strong_tasks->is_task_claimed(SH_PS_jvmti_oops_do)) - JvmtiExport::oops_do(strong_roots); - - if (!_process_strong_tasks->is_task_claimed(SH_PS_SystemDictionary_oops_do)) { - SystemDictionary::roots_oops_do(strong_roots, weak_roots); - } - - // All threads execute the following. A specific chunk of buckets - // from the StringTable are the individual tasks. - if (weak_roots != NULL) { - if (CollectedHeap::use_parallel_gc_threads()) { - StringTable::possibly_parallel_oops_do(weak_roots); - } else { - StringTable::oops_do(weak_roots); - } - } - - if (!_process_strong_tasks->is_task_claimed(SH_PS_CodeCache_oops_do)) { - if (so & SO_ScavengeCodeCache) { - assert(code_roots != NULL, "must supply closure for code cache"); - - // We only visit parts of the CodeCache when scavenging. - CodeCache::scavenge_root_nmethods_do(code_roots); - } - if (so & SO_AllCodeCache) { - assert(code_roots != NULL, "must supply closure for code cache"); - - // CMSCollector uses this to do intermediate-strength collections. - // We scan the entire code cache, since CodeCache::do_unloading is not called. - CodeCache::blobs_do(code_roots); - } - // Verify that the code cache contents are not subject to - // movement by a scavenging collection. - DEBUG_ONLY(CodeBlobToOopClosure assert_code_is_non_scavengable(&assert_is_non_scavengable_closure, !CodeBlobToOopClosure::FixRelocations)); - DEBUG_ONLY(CodeCache::asserted_non_scavengable_nmethods_do(&assert_code_is_non_scavengable)); - } - - _process_strong_tasks->all_tasks_completed(); -} - -void SharedHeap::process_all_roots(bool activate_scope, - ScanningOption so, - OopClosure* roots, - CLDClosure* cld_closure, - CodeBlobClosure* code_closure) { - process_roots(activate_scope, so, - roots, roots, - cld_closure, cld_closure, - code_closure); -} - -void SharedHeap::process_strong_roots(bool activate_scope, - ScanningOption so, - OopClosure* roots, - CLDClosure* cld_closure, - CodeBlobClosure* code_closure) { - process_roots(activate_scope, so, - roots, NULL, - cld_closure, NULL, - code_closure); -} - - -class AlwaysTrueClosure: public BoolObjectClosure { -public: - bool do_object_b(oop p) { return true; } -}; -static AlwaysTrueClosure always_true; - -void SharedHeap::process_weak_roots(OopClosure* root_closure) { - // Global (weak) JNI handles - JNIHandles::weak_oops_do(&always_true, root_closure); -} - void SharedHeap::set_barrier_set(BarrierSet* bs) { _barrier_set = bs; // Cached barrier set for fast access in oops diff -r c2687aa5e5ca -r 7eb99acd567f src/share/vm/memory/sharedHeap.hpp --- a/src/share/vm/memory/sharedHeap.hpp Mon Jan 25 14:56:57 2016 -0800 +++ b/src/share/vm/memory/sharedHeap.hpp Mon Jan 25 14:57:27 2016 -0800 @@ -61,18 +61,18 @@ // counts the number of tasks that have been done and then reset // the SubTasksDone so that it can be used again. When the number of // tasks is set to the number of GC workers, then _n_threads must -// be set to the number of active GC workers. G1CollectedHeap, -// HRInto_G1RemSet, GenCollectedHeap and SharedHeap have SubTasksDone. -// This seems too many. +// be set to the number of active GC workers. G1RootProcessor and +// GenCollectedHeap have SubTasksDone. // 3) SequentialSubTasksDone has an _n_threads that is used in // a way similar to SubTasksDone and has the same dependency on the // number of active GC workers. CompactibleFreeListSpace and Space // have SequentialSubTasksDone's. -// Example of using SubTasksDone and SequentialSubTasksDone -// G1CollectedHeap::g1_process_roots() -// to SharedHeap::process_roots() and uses -// SubTasksDone* _process_strong_tasks to claim tasks. -// process_roots() calls +// +// Examples of using SubTasksDone and SequentialSubTasksDone: +// G1RootProcessor and GenCollectedHeap::process_roots() use +// SubTasksDone* _process_strong_tasks to claim tasks for workers +// +// GenCollectedHeap::gen_process_roots() calls // rem_set()->younger_refs_iterate() // to scan the card table and which eventually calls down into // CardTableModRefBS::par_non_clean_card_iterate_work(). This method @@ -104,10 +104,6 @@ friend class VM_GC_Operation; friend class VM_CGC_Operation; -private: - // For claiming strong_roots tasks. - SubTasksDone* _process_strong_tasks; - protected: // There should be only a single instance of "SharedHeap" in a program. // This is enforced with the protected constructor below, which will also @@ -144,7 +140,6 @@ static SharedHeap* heap() { return _sh; } void set_barrier_set(BarrierSet* bs); - SubTasksDone* process_strong_tasks() { return _process_strong_tasks; } // Does operations required after initialization has been done. virtual void post_initialize(); @@ -201,69 +196,19 @@ // strong_roots_prologue calls change_strong_roots_parity, if // parallel tasks are enabled. class StrongRootsScope : public MarkingCodeBlobClosure::MarkScope { - // Used to implement the Thread work barrier. - static Monitor* _lock; - SharedHeap* _sh; - volatile jint _n_workers_done_with_threads; public: StrongRootsScope(SharedHeap* heap, bool activate = true); - ~StrongRootsScope(); - - // Mark that this thread is done with the Threads work. - void mark_worker_done_with_threads(uint n_workers); - // Wait until all n_workers are done with the Threads work. - void wait_until_all_workers_done_with_threads(uint n_workers); }; friend class StrongRootsScope; - // The current active StrongRootScope - StrongRootsScope* _strong_roots_scope; - - StrongRootsScope* active_strong_roots_scope() const; - private: - void register_strong_roots_scope(StrongRootsScope* scope); - void unregister_strong_roots_scope(StrongRootsScope* scope); void change_strong_roots_parity(); public: - enum ScanningOption { - SO_None = 0x0, - SO_AllCodeCache = 0x8, - SO_ScavengeCodeCache = 0x10 - }; - FlexibleWorkGang* workers() const { return _workers; } - // Invoke the "do_oop" method the closure "roots" on all root locations. - // The "so" argument determines which roots the closure is applied to: - // "SO_None" does none; - // "SO_AllCodeCache" applies the closure to all elements of the CodeCache. - // "SO_ScavengeCodeCache" applies the closure to elements on the scavenge root list in the CodeCache. - void process_roots(bool activate_scope, - ScanningOption so, - OopClosure* strong_roots, - OopClosure* weak_roots, - CLDClosure* strong_cld_closure, - CLDClosure* weak_cld_closure, - CodeBlobClosure* code_roots); - void process_all_roots(bool activate_scope, - ScanningOption so, - OopClosure* roots, - CLDClosure* cld_closure, - CodeBlobClosure* code_roots); - void process_strong_roots(bool activate_scope, - ScanningOption so, - OopClosure* roots, - CLDClosure* cld_closure, - CodeBlobClosure* code_roots); - - - // Apply "root_closure" to the JNI weak roots.. - void process_weak_roots(OopClosure* root_closure); - // The functions below are helper functions that a subclass of // "SharedHeap" can use in the implementation of its virtual // functions. @@ -278,9 +223,6 @@ // (such as process roots) subsequently. virtual void set_par_threads(uint t); - int n_termination(); - void set_n_termination(int t); - // // New methods from CollectedHeap // @@ -292,8 +234,4 @@ size_t capacity); }; -inline SharedHeap::ScanningOption operator|(SharedHeap::ScanningOption so0, SharedHeap::ScanningOption so1) { - return static_cast(static_cast(so0) | static_cast(so1)); -} - #endif // SHARE_VM_MEMORY_SHAREDHEAP_HPP diff -r c2687aa5e5ca -r 7eb99acd567f src/share/vm/memory/tenuredGeneration.cpp --- a/src/share/vm/memory/tenuredGeneration.cpp Mon Jan 25 14:56:57 2016 -0800 +++ b/src/share/vm/memory/tenuredGeneration.cpp Mon Jan 25 14:57:27 2016 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 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 @@ -24,7 +24,6 @@ #include "precompiled.hpp" #include "gc_implementation/shared/collectorCounters.hpp" -#include "gc_implementation/shared/parGCAllocBuffer.hpp" #include "memory/allocation.inline.hpp" #include "memory/blockOffsetTable.inline.hpp" #include "memory/generation.inline.hpp" @@ -34,6 +33,9 @@ #include "oops/oop.inline.hpp" #include "runtime/java.hpp" #include "utilities/macros.hpp" +#if INCLUDE_ALL_GCS +#include "gc_implementation/shared/parGCAllocBuffer.hpp" +#endif TenuredGeneration::TenuredGeneration(ReservedSpace rs, size_t initial_byte_size, int level, diff -r c2687aa5e5ca -r 7eb99acd567f src/share/vm/oops/constMethod.hpp --- a/src/share/vm/oops/constMethod.hpp Mon Jan 25 14:56:57 2016 -0800 +++ b/src/share/vm/oops/constMethod.hpp Mon Jan 25 14:57:27 2016 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 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 @@ -222,6 +222,7 @@ u2 _max_stack; // Maximum number of entries on the expression stack u2 _max_locals; // Number of local variables used by this method u2 _size_of_parameters; // size of the parameter block (receiver + arguments) in words + u2 _orig_method_idnum; // Original unique identification number for the method // Constructor ConstMethod(int byte_code_size, @@ -475,6 +476,9 @@ u2 method_idnum() const { return _method_idnum; } void set_method_idnum(u2 idnum) { _method_idnum = idnum; } + u2 orig_method_idnum() const { return _orig_method_idnum; } + void set_orig_method_idnum(u2 idnum) { _orig_method_idnum = idnum; } + // max stack int max_stack() const { return _max_stack; } void set_max_stack(int size) { _max_stack = size; } diff -r c2687aa5e5ca -r 7eb99acd567f src/share/vm/oops/cpCache.cpp --- a/src/share/vm/oops/cpCache.cpp Mon Jan 25 14:56:57 2016 -0800 +++ b/src/share/vm/oops/cpCache.cpp Mon Jan 25 14:57:27 2016 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 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 @@ -449,7 +449,6 @@ new_method->name()->as_C_string(), new_method->signature()->as_C_string())); } - return true; } @@ -477,7 +476,6 @@ new_method->name()->as_C_string(), new_method->signature()->as_C_string())); } - return true; } @@ -498,41 +496,39 @@ // _f1 == NULL || !_f1->is_method() are OK here return true; } - // return false if _f1 refers to an old or an obsolete method + // return false if _f1 refers to a non-deleted old or obsolete method return (NOT_PRODUCT(_f1->is_valid() &&) _f1->is_method() && - !((Method*)_f1)->is_old() && !((Method*)_f1)->is_obsolete()); + (f1_as_method()->is_deleted() || + (!f1_as_method()->is_old() && !f1_as_method()->is_obsolete()))); } -bool ConstantPoolCacheEntry::is_interesting_method_entry(Klass* k) { +Method* ConstantPoolCacheEntry::get_interesting_method_entry(Klass* k) { if (!is_method_entry()) { // not a method entry so not interesting by default - return false; + return NULL; } - Method* m = NULL; if (is_vfinal()) { // virtual and final so _f2 contains method ptr instead of vtable index m = f2_as_vfinal_method(); } else if (is_f1_null()) { // NULL _f1 means this is a virtual entry so also not interesting - return false; + return NULL; } else { if (!(_f1->is_method())) { // _f1 can also contain a Klass* for an interface - return false; + return NULL; } m = f1_as_method(); } - assert(m != NULL && m->is_method(), "sanity check"); if (m == NULL || !m->is_method() || (k != NULL && m->method_holder() != k)) { // robustness for above sanity checks or method is not in // the interesting class - return false; + return NULL; } - // the method is in the interesting class so the entry is interesting - return true; + return m; } #endif // INCLUDE_JVMTI @@ -608,46 +604,31 @@ // RedefineClasses() API support: // If any entry of this ConstantPoolCache points to any of // old_methods, replace it with the corresponding new_method. -void ConstantPoolCache::adjust_method_entries(Method** old_methods, Method** new_methods, - int methods_length, bool * trace_name_printed) { - - if (methods_length == 0) { - // nothing to do if there are no methods - return; - } - - // get shorthand for the interesting class - Klass* old_holder = old_methods[0]->method_holder(); - +void ConstantPoolCache::adjust_method_entries(InstanceKlass* holder, bool * trace_name_printed) { for (int i = 0; i < length(); i++) { - if (!entry_at(i)->is_interesting_method_entry(old_holder)) { - // skip uninteresting methods + ConstantPoolCacheEntry* entry = entry_at(i); + Method* old_method = entry->get_interesting_method_entry(holder); + if (old_method == NULL || !old_method->is_old()) { + continue; // skip uninteresting entries + } + if (old_method->is_deleted()) { + // clean up entries with deleted methods + entry->initialize_entry(entry->constant_pool_index()); continue; } - - // The ConstantPoolCache contains entries for several different - // things, but we only care about methods. In fact, we only care - // about methods in the same class as the one that contains the - // old_methods. At this point, we have an interesting entry. + Method* new_method = holder->method_with_idnum(old_method->orig_method_idnum()); - for (int j = 0; j < methods_length; j++) { - Method* old_method = old_methods[j]; - Method* new_method = new_methods[j]; + assert(new_method != NULL, "method_with_idnum() should not be NULL"); + assert(old_method != new_method, "sanity check"); - if (entry_at(i)->adjust_method_entry(old_method, new_method, - trace_name_printed)) { - // current old_method matched this entry and we updated it so - // break out and get to the next interesting entry if there one - break; - } - } + entry_at(i)->adjust_method_entry(old_method, new_method, trace_name_printed); } } // the constant pool cache should never contain old or obsolete methods bool ConstantPoolCache::check_no_old_or_obsolete_entries() { for (int i = 1; i < length(); i++) { - if (entry_at(i)->is_interesting_method_entry(NULL) && + if (entry_at(i)->get_interesting_method_entry(NULL) != NULL && !entry_at(i)->check_no_old_or_obsolete_entries()) { return false; } @@ -657,7 +638,7 @@ void ConstantPoolCache::dump_cache() { for (int i = 1; i < length(); i++) { - if (entry_at(i)->is_interesting_method_entry(NULL)) { + if (entry_at(i)->get_interesting_method_entry(NULL) != NULL) { entry_at(i)->print(tty, i); } } diff -r c2687aa5e5ca -r 7eb99acd567f src/share/vm/oops/cpCache.hpp --- a/src/share/vm/oops/cpCache.hpp Mon Jan 25 14:56:57 2016 -0800 +++ b/src/share/vm/oops/cpCache.hpp Mon Jan 25 14:57:27 2016 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 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 @@ -378,9 +378,9 @@ // printed the klass name so that other routines in the adjust_* // group don't print the klass name. bool adjust_method_entry(Method* old_method, Method* new_method, - bool * trace_name_printed); + bool* trace_name_printed); bool check_no_old_or_obsolete_entries(); - bool is_interesting_method_entry(Klass* k); + Method* get_interesting_method_entry(Klass* k); #endif // INCLUDE_JVMTI // Debugging & Printing @@ -476,8 +476,7 @@ // trace_name_printed is set to true if the current call has // printed the klass name so that other routines in the adjust_* // group don't print the klass name. - void adjust_method_entries(Method** old_methods, Method** new_methods, - int methods_length, bool * trace_name_printed); + void adjust_method_entries(InstanceKlass* holder, bool* trace_name_printed); bool check_no_old_or_obsolete_entries(); void dump_cache(); #endif // INCLUDE_JVMTI diff -r c2687aa5e5ca -r 7eb99acd567f src/share/vm/oops/instanceKlass.cpp --- a/src/share/vm/oops/instanceKlass.cpp Mon Jan 25 14:56:57 2016 -0800 +++ b/src/share/vm/oops/instanceKlass.cpp Mon Jan 25 14:57:27 2016 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 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 @@ -50,6 +50,7 @@ #include "prims/jvmtiExport.hpp" #include "prims/jvmtiRedefineClassesTrace.hpp" #include "prims/jvmtiRedefineClasses.hpp" +#include "prims/jvmtiThreadState.hpp" #include "prims/methodComparator.hpp" #include "runtime/fieldDescriptor.hpp" #include "runtime/handles.inline.hpp" @@ -441,6 +442,9 @@ if (!constants()->is_shared()) { MetadataFactory::free_metadata(loader_data, constants()); } + // Delete any cached resolution errors for the constant pool + SystemDictionary::delete_resolution_error(constants()); + set_constants(NULL); } @@ -931,10 +935,16 @@ // Step 10 and 11 Handle e(THREAD, PENDING_EXCEPTION); CLEAR_PENDING_EXCEPTION; + // JVMTI has already reported the pending exception + // JVMTI internal flag reset is needed in order to report ExceptionInInitializerError + JvmtiExport::clear_detected_exception((JavaThread*)THREAD); { EXCEPTION_MARK; this_oop->set_initialization_state_and_notify(initialization_error, THREAD); CLEAR_PENDING_EXCEPTION; // ignore any exception thrown, class initialization error is thrown below + // JVMTI has already reported the pending exception + // JVMTI internal flag reset is needed in order to report ExceptionInInitializerError + JvmtiExport::clear_detected_exception((JavaThread*)THREAD); } DTRACE_CLASSINIT_PROBE_WAIT(error, InstanceKlass::cast(this_oop()), -1,wait); if (e->is_a(SystemDictionary::Error_klass())) { @@ -1566,6 +1576,21 @@ return NULL; } +#ifdef ASSERT +// search through class hierarchy and return true if this class or +// one of the superclasses was redefined +bool InstanceKlass::has_redefined_this_or_super() const { + const InstanceKlass* klass = this; + while (klass != NULL) { + if (klass->has_been_redefined()) { + return true; + } + klass = InstanceKlass::cast(klass->super()); + } + return false; +} +#endif + // lookup a method in the default methods list then in all transitive interfaces // Do NOT return private or static methods Method* InstanceKlass::lookup_method_in_ordered_interfaces(Symbol* name, @@ -2802,30 +2827,33 @@ // not yet in the vtable due to concurrent subclass define and superinterface // redefinition // Note: those in the vtable, should have been updated via adjust_method_entries -void InstanceKlass::adjust_default_methods(Method** old_methods, Method** new_methods, - int methods_length, bool* trace_name_printed) { +void InstanceKlass::adjust_default_methods(InstanceKlass* holder, bool* trace_name_printed) { // search the default_methods for uses of either obsolete or EMCP methods if (default_methods() != NULL) { - for (int j = 0; j < methods_length; j++) { - Method* old_method = old_methods[j]; - Method* new_method = new_methods[j]; - - for (int index = 0; index < default_methods()->length(); index ++) { - if (default_methods()->at(index) == old_method) { - default_methods()->at_put(index, 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: klassname=%s default methods from name=%s", - external_name(), - old_method->method_holder()->external_name())); - *trace_name_printed = true; - } - RC_TRACE(0x00100000, ("default method update: %s(%s) ", - new_method->name()->as_C_string(), - new_method->signature()->as_C_string())); - } + for (int index = 0; index < default_methods()->length(); index ++) { + Method* old_method = default_methods()->at(index); + if (old_method == NULL || old_method->method_holder() != holder || !old_method->is_old()) { + continue; // skip uninteresting entries + } + assert(!old_method->is_deleted(), "default methods may not be deleted"); + + Method* new_method = holder->method_with_idnum(old_method->orig_method_idnum()); + + assert(new_method != NULL, "method_with_idnum() should not be NULL"); + assert(old_method != new_method, "sanity check"); + + default_methods()->at_put(index, 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: klassname=%s default methods from name=%s", + external_name(), + old_method->method_holder()->external_name())); + *trace_name_printed = true; } + RC_TRACE(0x00100000, ("default method update: %s(%s) ", + new_method->name()->as_C_string(), + new_method->signature()->as_C_string())); } } } @@ -3761,6 +3789,22 @@ } // end has_previous_version() +InstanceKlass* InstanceKlass::get_klass_version(int version) { + if (constants()->version() == version) { + return this; + } + PreviousVersionWalker pvw(Thread::current(), (InstanceKlass*)this); + for (PreviousVersionNode * pv_node = pvw.next_previous_version(); + pv_node != NULL; pv_node = pvw.next_previous_version()) { + ConstantPool* prev_cp = pv_node->prev_constant_pool(); + if (prev_cp->version() == version) { + return prev_cp->pool_holder(); + } + } + return NULL; // None found +} + + Method* InstanceKlass::method_with_idnum(int idnum) { Method* m = NULL; if (idnum < methods()->length()) { @@ -3779,6 +3823,37 @@ return m; } + +Method* InstanceKlass::method_with_orig_idnum(int idnum) { + if (idnum >= methods()->length()) { + return NULL; + } + Method* m = methods()->at(idnum); + if (m != NULL && m->orig_method_idnum() == idnum) { + return m; + } + // Obsolete method idnum does not match the original idnum + for (int index = 0; index < methods()->length(); ++index) { + m = methods()->at(index); + if (m->orig_method_idnum() == idnum) { + return m; + } + } + // None found, return null for the caller to handle. + return NULL; +} + + +Method* InstanceKlass::method_with_orig_idnum(int idnum, int version) { + InstanceKlass* holder = get_klass_version(version); + if (holder == NULL) { + return NULL; // The version of klass is gone, no method is found + } + Method* method = holder->method_with_orig_idnum(idnum); + return method; +} + + jint InstanceKlass::get_cached_class_file_len() { return VM_RedefineClasses::get_cached_class_file_len(_cached_class_file); } diff -r c2687aa5e5ca -r 7eb99acd567f src/share/vm/oops/instanceKlass.hpp --- a/src/share/vm/oops/instanceKlass.hpp Mon Jan 25 14:56:57 2016 -0800 +++ b/src/share/vm/oops/instanceKlass.hpp Mon Jan 25 14:57:27 2016 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 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 @@ -358,6 +358,8 @@ Array* methods() const { return _methods; } void set_methods(Array* a) { _methods = a; } Method* method_with_idnum(int idnum); + Method* method_with_orig_idnum(int idnum); + Method* method_with_orig_idnum(int idnum, int version); // method ordering Array* method_ordering() const { return _method_ordering; } @@ -658,6 +660,7 @@ return _previous_versions; } + InstanceKlass* get_klass_version(int version); static void purge_previous_versions(InstanceKlass* ik); // JVMTI: Support for caching a class file before it is modified by an agent that can do retransformation @@ -805,6 +808,11 @@ bool implements_interface(Klass* k) const; bool is_same_or_direct_interface(Klass* k) const; +#ifdef ASSERT + // check whether this class or one of its superclasses was redefined + bool has_redefined_this_or_super() const; +#endif + // Access to the implementor of an interface. Klass* implementor() const { @@ -862,8 +870,8 @@ // Casting from Klass* static InstanceKlass* cast(Klass* k) { - assert(k->is_klass(), "must be"); - assert(k->oop_is_instance(), "cast to InstanceKlass"); + assert(k == NULL || k->is_klass(), "must be"); + assert(k == NULL || k->oop_is_instance(), "cast to InstanceKlass"); return (InstanceKlass*) k; } @@ -959,8 +967,7 @@ Method* method_at_itable(Klass* holder, int index, TRAPS); #if INCLUDE_JVMTI - void adjust_default_methods(Method** old_methods, Method** new_methods, - int methods_length, bool* trace_name_printed); + void adjust_default_methods(InstanceKlass* holder, bool* trace_name_printed); #endif // INCLUDE_JVMTI // Garbage collection diff -r c2687aa5e5ca -r 7eb99acd567f src/share/vm/oops/klassVtable.cpp --- a/src/share/vm/oops/klassVtable.cpp Mon Jan 25 14:56:57 2016 -0800 +++ b/src/share/vm/oops/klassVtable.cpp Mon Jan 25 14:57:27 2016 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 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 @@ -881,44 +881,43 @@ } return updated; } -void klassVtable::adjust_method_entries(Method** old_methods, Method** new_methods, - int methods_length, bool * trace_name_printed) { - // search the vtable for uses of either obsolete or EMCP methods - for (int j = 0; j < methods_length; j++) { - Method* old_method = old_methods[j]; - Method* new_method = new_methods[j]; + +// search the vtable for uses of either obsolete or EMCP methods +void klassVtable::adjust_method_entries(InstanceKlass* holder, bool * trace_name_printed) { + int prn_enabled = 0; + for (int index = 0; index < length(); index++) { + Method* old_method = unchecked_method_at(index); + if (old_method == NULL || old_method->method_holder() != holder || !old_method->is_old()) { + continue; // skip uninteresting entries + } + assert(!old_method->is_deleted(), "vtable methods may not be deleted"); + + Method* new_method = holder->method_with_idnum(old_method->orig_method_idnum()); + + assert(new_method != NULL, "method_with_idnum() should not be NULL"); + assert(old_method != new_method, "sanity check"); - // In the vast majority of cases we could get the vtable index - // by using: old_method->vtable_index() - // However, there are rare cases, eg. sun.awt.X11.XDecoratedPeer.getX() - // in sun.awt.X11.XFramePeer where methods occur more than once in the - // vtable, so, alas, we must do an exhaustive search. - for (int index = 0; index < length(); index++) { - if (unchecked_method_at(index) == old_method) { - put_method_at(new_method, index); - // For default methods, need to update the _default_methods array - // which can only have one method entry for a given signature - bool updated_default = false; - if (old_method->is_default_method()) { - updated_default = adjust_default_method(index, old_method, new_method); - } + put_method_at(new_method, index); + // For default methods, need to update the _default_methods array + // which can only have one method entry for a given signature + bool updated_default = false; + if (old_method->is_default_method()) { + updated_default = adjust_default_method(index, old_method, 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: klassname=%s for methods from name=%s", - klass()->external_name(), - old_method->method_holder()->external_name())); - *trace_name_printed = true; - } - // RC_TRACE macro has an embedded ResourceMark - RC_TRACE(0x00100000, ("vtable method update: %s(%s), updated default = %s", - new_method->name()->as_C_string(), - new_method->signature()->as_C_string(), - updated_default ? "true" : "false")); - } - // cannot 'break' here; see for-loop comment above. + if (RC_TRACE_IN_RANGE(0x00100000, 0x00400000)) { + if (!(*trace_name_printed)) { + // RC_TRACE_MESG macro has an embedded ResourceMark + RC_TRACE_MESG(("adjust: klassname=%s for methods from name=%s", + klass()->external_name(), + old_method->method_holder()->external_name())); + *trace_name_printed = true; } + // RC_TRACE macro has an embedded ResourceMark + RC_TRACE(0x00100000, ("vtable method update: %s(%s), updated default = %s", + new_method->name()->as_C_string(), + new_method->signature()->as_C_string(), + updated_default ? "true" : "false")); } } } @@ -1211,37 +1210,35 @@ } #if INCLUDE_JVMTI -void klassItable::adjust_method_entries(Method** old_methods, Method** new_methods, - int methods_length, bool * trace_name_printed) { - // search the itable for uses of either obsolete or EMCP methods - for (int j = 0; j < methods_length; j++) { - Method* old_method = old_methods[j]; - Method* new_method = new_methods[j]; - itableMethodEntry* ime = method_entry(0); +// search the itable for uses of either obsolete or EMCP methods +void klassItable::adjust_method_entries(InstanceKlass* holder, bool * trace_name_printed) { - // The itable can describe more than one interface and the same - // method signature can be specified by more than one interface. - // This means we have to do an exhaustive search to find all the - // old_method references. - for (int i = 0; i < _size_method_table; i++) { - if (ime->method() == old_method) { - ime->initialize(new_method); + itableMethodEntry* ime = method_entry(0); + for (int i = 0; i < _size_method_table; i++, ime++) { + Method* old_method = ime->method(); + if (old_method == NULL || old_method->method_holder() != holder || !old_method->is_old()) { + continue; // skip uninteresting entries + } + assert(!old_method->is_deleted(), "itable methods may not be deleted"); + + Method* new_method = holder->method_with_idnum(old_method->orig_method_idnum()); - 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(0x00200000, ("itable method update: %s(%s)", - new_method->name()->as_C_string(), - new_method->signature()->as_C_string())); - } - // cannot 'break' here; see for-loop comment above. + assert(new_method != NULL, "method_with_idnum() should not be NULL"); + assert(old_method != new_method, "sanity check"); + + ime->initialize(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; } - ime++; + // RC_TRACE macro has an embedded ResourceMark + RC_TRACE(0x00200000, ("itable method update: %s(%s)", + new_method->name()->as_C_string(), + new_method->signature()->as_C_string())); } } } diff -r c2687aa5e5ca -r 7eb99acd567f src/share/vm/oops/klassVtable.hpp --- a/src/share/vm/oops/klassVtable.hpp Mon Jan 25 14:56:57 2016 -0800 +++ b/src/share/vm/oops/klassVtable.hpp Mon Jan 25 14:57:27 2016 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 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 @@ -98,8 +98,7 @@ // printed the klass name so that other routines in the adjust_* // group don't print the klass name. bool adjust_default_method(int vtable_index, Method* old_method, Method* new_method); - void adjust_method_entries(Method** old_methods, Method** new_methods, - int methods_length, bool * trace_name_printed); + void adjust_method_entries(InstanceKlass* holder, bool * trace_name_printed); bool check_no_old_or_obsolete_entries(); void dump_vtable(); #endif // INCLUDE_JVMTI @@ -288,8 +287,7 @@ // trace_name_printed is set to true if the current call has // printed the klass name so that other routines in the adjust_* // group don't print the klass name. - void adjust_method_entries(Method** old_methods, Method** new_methods, - int methods_length, bool * trace_name_printed); + void adjust_method_entries(InstanceKlass* holder, bool * trace_name_printed); bool check_no_old_or_obsolete_entries(); void dump_itable(); #endif // INCLUDE_JVMTI diff -r c2687aa5e5ca -r 7eb99acd567f src/share/vm/oops/markOop.cpp --- a/src/share/vm/oops/markOop.cpp Mon Jan 25 14:56:57 2016 -0800 +++ b/src/share/vm/oops/markOop.cpp Mon Jan 25 14:57:27 2016 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 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 @@ -25,17 +25,40 @@ #include "precompiled.hpp" #include "oops/markOop.hpp" #include "runtime/thread.inline.hpp" +#include "runtime/objectMonitor.inline.hpp" PRAGMA_FORMAT_MUTE_WARNINGS_FOR_GCC void markOopDesc::print_on(outputStream* st) const { - if (is_locked()) { - st->print("locked(" INTPTR_FORMAT ")->", value()); - markOop(*(markOop*)value())->print_on(st); + if (is_marked()) { + st->print(" marked(" INTPTR_FORMAT ")", value()); + } else if (is_locked()) { + st->print(" locked(" INTPTR_FORMAT ")->", value()); + if (is_neutral()) { + st->print("is_neutral"); + if (has_no_hash()) st->print(" no_hash"); + else st->print(" hash=" INTPTR_FORMAT, hash()); + st->print(" age=%d", age()); + } else if (has_bias_pattern()) { + st->print("is_biased"); + JavaThread* jt = biased_locker(); + st->print(" biased_locker=" INTPTR_FORMAT, p2i(jt)); + } else if (has_monitor()) { + ObjectMonitor* mon = monitor(); + if (mon == NULL) + st->print("monitor=NULL"); + else { + BasicLock * bl = (BasicLock *) mon->owner(); + st->print("monitor={count="INTPTR_FORMAT",waiters="INTPTR_FORMAT",recursions="INTPTR_FORMAT",owner="INTPTR_FORMAT"}", + mon->count(), mon->waiters(), mon->recursions(), p2i(bl)); + } + } else { + st->print("??"); + } } else { assert(is_unlocked() || has_bias_pattern(), "just checking"); st->print("mark("); - if (has_bias_pattern()) st->print("biased,"); + if (has_bias_pattern()) st->print("biased,"); st->print("hash %#lx,", hash()); st->print("age %d)", age()); } diff -r c2687aa5e5ca -r 7eb99acd567f src/share/vm/oops/method.cpp --- a/src/share/vm/oops/method.cpp Mon Jan 25 14:56:57 2016 -0800 +++ b/src/share/vm/oops/method.cpp Mon Jan 25 14:57:27 2016 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 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 @@ -92,6 +92,7 @@ set_force_inline(false); set_hidden(false); set_dont_inline(false); + set_has_injected_profile(false); set_method_data(NULL); clear_method_counters(); set_vtable_index(Method::garbage_vtable_index); @@ -1419,6 +1420,7 @@ for (int i = 0; i < length; i++) { Method* m = methods->at(i); m->set_method_idnum(i); + m->set_orig_method_idnum(i); } } } diff -r c2687aa5e5ca -r 7eb99acd567f src/share/vm/oops/method.hpp --- a/src/share/vm/oops/method.hpp Mon Jan 25 14:56:57 2016 -0800 +++ b/src/share/vm/oops/method.hpp Mon Jan 25 14:57:27 2016 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 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 @@ -113,11 +113,12 @@ // Flags enum Flags { - _jfr_towrite = 1 << 0, - _caller_sensitive = 1 << 1, - _force_inline = 1 << 2, - _dont_inline = 1 << 3, - _hidden = 1 << 4 + _jfr_towrite = 1 << 0, + _caller_sensitive = 1 << 1, + _force_inline = 1 << 2, + _dont_inline = 1 << 3, + _hidden = 1 << 4, + _has_injected_profile = 1 << 5 }; u1 _flags; @@ -269,6 +270,9 @@ u2 method_idnum() const { return constMethod()->method_idnum(); } void set_method_idnum(u2 idnum) { constMethod()->set_method_idnum(idnum); } + u2 orig_method_idnum() const { return constMethod()->orig_method_idnum(); } + void set_orig_method_idnum(u2 idnum) { constMethod()->set_orig_method_idnum(idnum); } + // code size int code_size() const { return constMethod()->code_size(); } @@ -718,6 +722,8 @@ void set_is_old() { _access_flags.set_is_old(); } bool is_obsolete() const { return access_flags().is_obsolete(); } void set_is_obsolete() { _access_flags.set_is_obsolete(); } + bool is_deleted() const { return access_flags().is_deleted(); } + void set_is_deleted() { _access_flags.set_is_deleted(); } bool on_stack() const { return access_flags().on_stack(); } void set_on_stack(const bool value); @@ -815,6 +821,13 @@ _flags = x ? (_flags | _hidden) : (_flags & ~_hidden); } + bool has_injected_profile() { + return (_flags & _has_injected_profile) != 0; + } + void set_has_injected_profile(bool x) { + _flags = x ? (_flags | _has_injected_profile) : (_flags & ~_has_injected_profile); + } + ConstMethod::MethodType method_type() const { return _constMethod->method_type(); } diff -r c2687aa5e5ca -r 7eb99acd567f src/share/vm/opto/bytecodeInfo.cpp --- a/src/share/vm/opto/bytecodeInfo.cpp Mon Jan 25 14:56:57 2016 -0800 +++ b/src/share/vm/opto/bytecodeInfo.cpp Mon Jan 25 14:57:27 2016 -0800 @@ -608,11 +608,11 @@ } int max_inline_level_adjust = 0; if (caller_jvms->method() != NULL) { - if (caller_jvms->method()->is_compiled_lambda_form()) + if (caller_jvms->method()->is_compiled_lambda_form()) { max_inline_level_adjust += 1; // don't count actions in MH or indy adapter frames - else if (callee_method->is_method_handle_intrinsic() || - callee_method->is_compiled_lambda_form()) { - max_inline_level_adjust += 1; // don't count method handle calls from java.lang.invoke implem + } else if (callee_method->is_method_handle_intrinsic() || + callee_method->is_compiled_lambda_form()) { + max_inline_level_adjust += 1; // don't count method handle calls from java.lang.invoke implementation } if (max_inline_level_adjust != 0 && C->print_inlining() && (Verbose || WizardMode)) { CompileTask::print_inline_indent(inline_level()); diff -r c2687aa5e5ca -r 7eb99acd567f src/share/vm/opto/c2compiler.cpp --- a/src/share/vm/opto/c2compiler.cpp Mon Jan 25 14:56:57 2016 -0800 +++ b/src/share/vm/opto/c2compiler.cpp Mon Jan 25 14:57:27 2016 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 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 @@ -25,25 +25,17 @@ #include "precompiled.hpp" #include "opto/c2compiler.hpp" #include "opto/runtime.hpp" -#ifdef TARGET_ARCH_MODEL_x86_32 +#if defined AD_MD_HPP +# include AD_MD_HPP +#elif defined TARGET_ARCH_MODEL_x86_32 # include "adfiles/ad_x86_32.hpp" -#endif -#ifdef TARGET_ARCH_MODEL_x86_64 +#elif defined TARGET_ARCH_MODEL_x86_64 # include "adfiles/ad_x86_64.hpp" -#endif -#ifdef TARGET_ARCH_MODEL_sparc +#elif defined TARGET_ARCH_MODEL_sparc # include "adfiles/ad_sparc.hpp" -#endif -#ifdef TARGET_ARCH_MODEL_zero +#elif defined TARGET_ARCH_MODEL_zero # include "adfiles/ad_zero.hpp" -#endif -#ifdef TARGET_ARCH_MODEL_arm -# include "adfiles/ad_arm.hpp" -#endif -#ifdef TARGET_ARCH_MODEL_ppc_32 -# include "adfiles/ad_ppc_32.hpp" -#endif -#ifdef TARGET_ARCH_MODEL_ppc_64 +#elif defined TARGET_ARCH_MODEL_ppc_64 # include "adfiles/ad_ppc_64.hpp" #endif diff -r c2687aa5e5ca -r 7eb99acd567f src/share/vm/opto/callGenerator.cpp --- a/src/share/vm/opto/callGenerator.cpp Mon Jan 25 14:56:57 2016 -0800 +++ b/src/share/vm/opto/callGenerator.cpp Mon Jan 25 14:57:27 2016 -0800 @@ -859,7 +859,8 @@ // Parse::do_call()) target = C->optimize_virtual_call(caller, jvms->bci(), klass, klass, target, receiver_type, is_virtual, - call_does_dispatch, vtable_index); // out-parameters + call_does_dispatch, vtable_index, // out-parameters + /*check_access=*/false); // We lack profiling at this call but type speculation may // provide us with a type speculative_receiver_type = (receiver_type != NULL) ? receiver_type->speculative_type() : NULL; diff -r c2687aa5e5ca -r 7eb99acd567f src/share/vm/opto/callnode.cpp --- a/src/share/vm/opto/callnode.cpp Mon Jan 25 14:56:57 2016 -0800 +++ b/src/share/vm/opto/callnode.cpp Mon Jan 25 14:57:27 2016 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 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 @@ -23,6 +23,7 @@ */ #include "precompiled.hpp" +#include "compiler/compileLog.hpp" #include "ci/bcEscapeAnalyzer.hpp" #include "compiler/oopMap.hpp" #include "opto/callGenerator.hpp" @@ -1670,6 +1671,9 @@ // The lock could be marked eliminated by lock coarsening // code during first IGVN before EA. Replace coarsened flag // to eliminate all associated locks/unlocks. +#ifdef ASSERT + this->log_lock_optimization(phase->C,"eliminate_lock_set_non_esc1"); +#endif this->set_non_esc_obj(); return result; } @@ -1731,6 +1735,9 @@ AbstractLockNode* lock = lock_ops.at(i); // Mark it eliminated by coarsening and update any counters +#ifdef ASSERT + lock->log_lock_optimization(phase->C, "eliminate_lock_set_coarsened"); +#endif lock->set_coarsened(); } } else if (ctrl->is_Region() && @@ -1749,16 +1756,33 @@ //============================================================================= bool LockNode::is_nested_lock_region() { + return is_nested_lock_region(NULL); +} + +// p is used for access to compilation log; no logging if NULL +bool LockNode::is_nested_lock_region(Compile * c) { BoxLockNode* box = box_node()->as_BoxLock(); int stk_slot = box->stack_slot(); - if (stk_slot <= 0) + if (stk_slot <= 0) { +#ifdef ASSERT + this->log_lock_optimization(c, "eliminate_lock_INLR_1"); +#endif return false; // External lock or it is not Box (Phi node). + } // Ignore complex cases: merged locks or multiple locks. Node* obj = obj_node(); LockNode* unique_lock = NULL; - if (!box->is_simple_lock_region(&unique_lock, obj) || - (unique_lock != this)) { + if (!box->is_simple_lock_region(&unique_lock, obj)) { +#ifdef ASSERT + this->log_lock_optimization(c, "eliminate_lock_INLR_2a"); +#endif + return false; + } + if (unique_lock != this) { +#ifdef ASSERT + this->log_lock_optimization(c, "eliminate_lock_INLR_2b"); +#endif return false; } @@ -1778,6 +1802,9 @@ } } } +#ifdef ASSERT + this->log_lock_optimization(c, "eliminate_lock_INLR_3"); +#endif return false; } @@ -1809,8 +1836,40 @@ // The lock could be marked eliminated by lock coarsening // code during first IGVN before EA. Replace coarsened flag // to eliminate all associated locks/unlocks. +#ifdef ASSERT + this->log_lock_optimization(phase->C, "eliminate_lock_set_non_esc2"); +#endif this->set_non_esc_obj(); } } return result; } + +const char * AbstractLockNode::kind_as_string() const { + return is_coarsened() ? "coarsened" : + is_nested() ? "nested" : + is_non_esc_obj() ? "non_escaping" : + "?"; +} + +void AbstractLockNode::log_lock_optimization(Compile *C, const char * tag) const { + if (C == NULL) { + return; + } + CompileLog* log = C->log(); + if (log != NULL) { + log->begin_head("%s lock='%d' compile_id='%d' class_id='%s' kind='%s'", + tag, is_Lock(), C->compile_id(), + is_Unlock() ? "unlock" : is_Lock() ? "lock" : "?", + kind_as_string()); + log->stamp(); + log->end_head(); + JVMState* p = is_Unlock() ? (as_Unlock()->dbg_jvms()) : jvms(); + while (p != NULL) { + log->elem("jvms bci='%d' method='%d'", p->bci(), log->identify(p->method())); + p = p->caller(); + } + log->tail(tag); + } +} + diff -r c2687aa5e5ca -r 7eb99acd567f src/share/vm/opto/callnode.hpp --- a/src/share/vm/opto/callnode.hpp Mon Jan 25 14:56:57 2016 -0800 +++ b/src/share/vm/opto/callnode.hpp Mon Jan 25 14:57:27 2016 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 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 @@ -985,6 +985,9 @@ bool is_coarsened() const { return (_kind == Coarsened); } bool is_nested() const { return (_kind == Nested); } + const char * kind_as_string() const; + void log_lock_optimization(Compile* c, const char * tag) const; + void set_non_esc_obj() { _kind = NonEscObj; set_eliminated_lock_counter(); } void set_coarsened() { _kind = Coarsened; set_eliminated_lock_counter(); } void set_nested() { _kind = Nested; set_eliminated_lock_counter(); } @@ -1045,15 +1048,24 @@ } bool is_nested_lock_region(); // Is this Lock nested? + bool is_nested_lock_region(Compile * c); // Why isn't this Lock nested? }; //------------------------------Unlock--------------------------------------- // High-level unlock operation class UnlockNode : public AbstractLockNode { +private: +#ifdef ASSERT + JVMState* const _dbg_jvms; // Pointer to list of JVM State objects +#endif public: virtual int Opcode() const; virtual uint size_of() const; // Size is bigger - UnlockNode(Compile* C, const TypeFunc *tf) : AbstractLockNode( tf ) { + UnlockNode(Compile* C, const TypeFunc *tf) : AbstractLockNode( tf ) +#ifdef ASSERT + , _dbg_jvms(NULL) +#endif + { init_class_id(Class_Unlock); init_flags(Flag_is_macro); C->add_macro_node(this); @@ -1061,6 +1073,14 @@ virtual Node *Ideal(PhaseGVN *phase, bool can_reshape); // unlock is never a safepoint virtual bool guaranteed_safepoint() { return false; } +#ifdef ASSERT + void set_dbg_jvms(JVMState* s) { + *(JVMState**)&_dbg_jvms = s; // override const attribute in the accessor + } + JVMState* dbg_jvms() const { return _dbg_jvms; } +#else + JVMState* dbg_jvms() const { return NULL; } +#endif }; #endif // SHARE_VM_OPTO_CALLNODE_HPP diff -r c2687aa5e5ca -r 7eb99acd567f src/share/vm/opto/chaitin.cpp --- a/src/share/vm/opto/chaitin.cpp Mon Jan 25 14:56:57 2016 -0800 +++ b/src/share/vm/opto/chaitin.cpp Mon Jan 25 14:57:27 2016 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 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 @@ -575,6 +575,9 @@ // Peephole remove copies post_allocate_copy_removal(); + // Merge multidefs if multiple defs representing the same value are used in a single block. + merge_multidefs(); + #ifdef ASSERT // Veify the graph after RA. verify(&live_arena); @@ -837,7 +840,7 @@ case Op_RegD: lrg.set_num_regs(2); // Define platform specific register pressure -#if defined(SPARC) || defined(ARM) +#if defined(SPARC) || defined(ARM32) lrg.set_reg_pressure(2); #elif defined(IA32) if( ireg == Op_RegL ) { diff -r c2687aa5e5ca -r 7eb99acd567f src/share/vm/opto/chaitin.hpp --- a/src/share/vm/opto/chaitin.hpp Mon Jan 25 14:56:57 2016 -0800 +++ b/src/share/vm/opto/chaitin.hpp Mon Jan 25 14:57:27 2016 -0800 @@ -578,6 +578,32 @@ // Extend the node to LRG mapping void add_reference( const Node *node, const Node *old_node); + // Record the first use of a def in the block for a register. + class RegDefUse { + Node* _def; + Node* _first_use; + public: + RegDefUse() : _def(NULL), _first_use(NULL) { } + Node* def() const { return _def; } + Node* first_use() const { return _first_use; } + + void update(Node* def, Node* use) { + if (_def != def) { + _def = def; + _first_use = use; + } + } + void clear() { + _def = NULL; + _first_use = NULL; + } + }; + typedef GrowableArray RegToDefUseMap; + int possibly_merge_multidef(Node *n, uint k, Block *block, RegToDefUseMap& reg2defuse); + + // Merge nodes that are a part of a multidef lrg and produce the same value within a block. + void merge_multidefs(); + private: static int _final_loads, _final_stores, _final_copies, _final_memoves; diff -r c2687aa5e5ca -r 7eb99acd567f src/share/vm/opto/classes.hpp --- a/src/share/vm/opto/classes.hpp Mon Jan 25 14:56:57 2016 -0800 +++ b/src/share/vm/opto/classes.hpp Mon Jan 25 14:57:27 2016 -0800 @@ -199,6 +199,7 @@ macro(Opaque1) macro(Opaque2) macro(Opaque3) +macro(ProfileBoolean) macro(OrI) macro(OrL) macro(OverflowAddI) diff -r c2687aa5e5ca -r 7eb99acd567f src/share/vm/opto/compile.cpp --- a/src/share/vm/opto/compile.cpp Mon Jan 25 14:56:57 2016 -0800 +++ b/src/share/vm/opto/compile.cpp Mon Jan 25 14:57:27 2016 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 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 @@ -67,25 +67,17 @@ #include "runtime/timer.hpp" #include "trace/tracing.hpp" #include "utilities/copy.hpp" -#ifdef TARGET_ARCH_MODEL_x86_32 +#if defined AD_MD_HPP +# include AD_MD_HPP +#elif defined TARGET_ARCH_MODEL_x86_32 # include "adfiles/ad_x86_32.hpp" -#endif -#ifdef TARGET_ARCH_MODEL_x86_64 +#elif defined TARGET_ARCH_MODEL_x86_64 # include "adfiles/ad_x86_64.hpp" -#endif -#ifdef TARGET_ARCH_MODEL_sparc +#elif defined TARGET_ARCH_MODEL_sparc # include "adfiles/ad_sparc.hpp" -#endif -#ifdef TARGET_ARCH_MODEL_zero +#elif defined TARGET_ARCH_MODEL_zero # include "adfiles/ad_zero.hpp" -#endif -#ifdef TARGET_ARCH_MODEL_arm -# include "adfiles/ad_arm.hpp" -#endif -#ifdef TARGET_ARCH_MODEL_ppc_32 -# include "adfiles/ad_ppc_32.hpp" -#endif -#ifdef TARGET_ARCH_MODEL_ppc_64 +#elif defined TARGET_ARCH_MODEL_ppc_64 # include "adfiles/ad_ppc_64.hpp" #endif @@ -3085,6 +3077,7 @@ default: assert( !n->is_Call(), "" ); assert( !n->is_Mem(), "" ); + assert( nop != Op_ProfileBoolean, "should be eliminated during IGVN"); break; } diff -r c2687aa5e5ca -r 7eb99acd567f src/share/vm/opto/compile.hpp --- a/src/share/vm/opto/compile.hpp Mon Jan 25 14:56:57 2016 -0800 +++ b/src/share/vm/opto/compile.hpp Mon Jan 25 14:57:27 2016 -0800 @@ -861,9 +861,11 @@ ciMethod* optimize_virtual_call(ciMethod* caller, int bci, ciInstanceKlass* klass, ciKlass* holder, ciMethod* callee, const TypeOopPtr* receiver_type, bool is_virtual, - bool &call_does_dispatch, int &vtable_index); + bool &call_does_dispatch, int &vtable_index, + bool check_access = true); ciMethod* optimize_inlining(ciMethod* caller, int bci, ciInstanceKlass* klass, - ciMethod* callee, const TypeOopPtr* receiver_type); + ciMethod* callee, const TypeOopPtr* receiver_type, + bool check_access = true); // Report if there were too many traps at a current method and bci. // Report if a trap was recorded, and/or PerMethodTrapLimit was exceeded. diff -r c2687aa5e5ca -r 7eb99acd567f src/share/vm/opto/connode.cpp --- a/src/share/vm/opto/connode.cpp Mon Jan 25 14:56:57 2016 -0800 +++ b/src/share/vm/opto/connode.cpp Mon Jan 25 14:57:27 2016 -0800 @@ -1338,6 +1338,30 @@ return (&n == this); // Always fail except on self } +//============================================================================= + +uint ProfileBooleanNode::hash() const { return NO_HASH; } +uint ProfileBooleanNode::cmp( const Node &n ) const { + return (&n == this); +} + +Node *ProfileBooleanNode::Ideal(PhaseGVN *phase, bool can_reshape) { + if (can_reshape && _delay_removal) { + _delay_removal = false; + return this; + } else { + return NULL; + } +} + +Node *ProfileBooleanNode::Identity( PhaseTransform *phase ) { + if (_delay_removal) { + return this; + } else { + assert(_consumed, "profile should be consumed before elimination"); + return in(1); + } +} //------------------------------Value------------------------------------------ const Type *MoveL2DNode::Value( PhaseTransform *phase ) const { diff -r c2687aa5e5ca -r 7eb99acd567f src/share/vm/opto/connode.hpp --- a/src/share/vm/opto/connode.hpp Mon Jan 25 14:56:57 2016 -0800 +++ b/src/share/vm/opto/connode.hpp Mon Jan 25 14:57:27 2016 -0800 @@ -669,6 +669,31 @@ bool rtm_opt() const { return (_opt == RTM_OPT); } }; +//------------------------------ProfileBooleanNode------------------------------- +// A node represents value profile for a boolean during parsing. +// Once parsing is over, the node goes away (during IGVN). +// It is used to override branch frequencies from MDO (see has_injected_profile in parse2.cpp). +class ProfileBooleanNode : public Node { + uint _false_cnt; + uint _true_cnt; + bool _consumed; + bool _delay_removal; + virtual uint hash() const ; // { return NO_HASH; } + virtual uint cmp( const Node &n ) const; + public: + ProfileBooleanNode(Node *n, uint false_cnt, uint true_cnt) : Node(0, n), + _false_cnt(false_cnt), _true_cnt(true_cnt), _delay_removal(true), _consumed(false) {} + + uint false_count() const { return _false_cnt; } + uint true_count() const { return _true_cnt; } + + void consume() { _consumed = true; } + + virtual int Opcode() const; + virtual Node *Ideal(PhaseGVN *phase, bool can_reshape); + virtual Node *Identity(PhaseTransform *phase); + virtual const Type *bottom_type() const { return TypeInt::BOOL; } +}; //----------------------PartialSubtypeCheckNode-------------------------------- // The 2nd slow-half of a subtype check. Scan the subklass's 2ndary superklass diff -r c2687aa5e5ca -r 7eb99acd567f src/share/vm/opto/doCall.cpp --- a/src/share/vm/opto/doCall.cpp Mon Jan 25 14:56:57 2016 -0800 +++ b/src/share/vm/opto/doCall.cpp Mon Jan 25 14:57:27 2016 -0800 @@ -956,13 +956,15 @@ ciMethod* Compile::optimize_virtual_call(ciMethod* caller, int bci, ciInstanceKlass* klass, ciKlass* holder, ciMethod* callee, const TypeOopPtr* receiver_type, bool is_virtual, - bool& call_does_dispatch, int& vtable_index) { + bool& call_does_dispatch, int& vtable_index, + bool check_access) { // Set default values for out-parameters. call_does_dispatch = true; vtable_index = Method::invalid_vtable_index; // Choose call strategy. - ciMethod* optimized_virtual_method = optimize_inlining(caller, bci, klass, callee, receiver_type); + ciMethod* optimized_virtual_method = optimize_inlining(caller, bci, klass, callee, + receiver_type, check_access); // Have the call been sufficiently improved such that it is no longer a virtual? if (optimized_virtual_method != NULL) { @@ -977,7 +979,8 @@ // Identify possible target method and inlining style ciMethod* Compile::optimize_inlining(ciMethod* caller, int bci, ciInstanceKlass* klass, - ciMethod* callee, const TypeOopPtr* receiver_type) { + ciMethod* callee, const TypeOopPtr* receiver_type, + bool check_access) { // only use for virtual or interface calls // If it is obviously final, do not bother to call find_monomorphic_target, @@ -1017,7 +1020,7 @@ } ciInstanceKlass* calling_klass = caller->holder(); - ciMethod* cha_monomorphic_target = callee->find_monomorphic_target(calling_klass, klass, actual_receiver); + ciMethod* cha_monomorphic_target = callee->find_monomorphic_target(calling_klass, klass, actual_receiver, check_access); if (cha_monomorphic_target != NULL) { assert(!cha_monomorphic_target->is_abstract(), ""); // Look at the method-receiver type. Does it add "too much information"? diff -r c2687aa5e5ca -r 7eb99acd567f src/share/vm/opto/escape.cpp --- a/src/share/vm/opto/escape.cpp Mon Jan 25 14:56:57 2016 -0800 +++ b/src/share/vm/opto/escape.cpp Mon Jan 25 14:57:27 2016 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 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 @@ -205,6 +205,11 @@ _verify = false; } #endif + // Bytecode analyzer BCEscapeAnalyzer, used for Call nodes + // processing, calls to CI to resolve symbols (types, fields, methods) + // referenced in bytecode. During symbol resolution VM may throw + // an exception which CI cleans and converts to compilation failure. + if (C->failing()) return false; // 2. Finish Graph construction by propagating references to all // java objects through graph. @@ -1789,6 +1794,9 @@ // The lock could be marked eliminated by lock coarsening // code during first IGVN before EA. Replace coarsened flag // to eliminate all associated locks/unlocks. +#ifdef ASSERT + alock->log_lock_optimization(C, "eliminate_lock_set_non_esc3"); +#endif alock->set_non_esc_obj(); } } diff -r c2687aa5e5ca -r 7eb99acd567f src/share/vm/opto/gcm.cpp --- a/src/share/vm/opto/gcm.cpp Mon Jan 25 14:56:57 2016 -0800 +++ b/src/share/vm/opto/gcm.cpp Mon Jan 25 14:57:27 2016 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 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 @@ -35,25 +35,17 @@ #include "opto/rootnode.hpp" #include "opto/runtime.hpp" #include "runtime/deoptimization.hpp" -#ifdef TARGET_ARCH_MODEL_x86_32 +#if defined AD_MD_HPP +# include AD_MD_HPP +#elif defined TARGET_ARCH_MODEL_x86_32 # include "adfiles/ad_x86_32.hpp" -#endif -#ifdef TARGET_ARCH_MODEL_x86_64 +#elif defined TARGET_ARCH_MODEL_x86_64 # include "adfiles/ad_x86_64.hpp" -#endif -#ifdef TARGET_ARCH_MODEL_sparc +#elif defined TARGET_ARCH_MODEL_sparc # include "adfiles/ad_sparc.hpp" -#endif -#ifdef TARGET_ARCH_MODEL_zero +#elif defined TARGET_ARCH_MODEL_zero # include "adfiles/ad_zero.hpp" -#endif -#ifdef TARGET_ARCH_MODEL_arm -# include "adfiles/ad_arm.hpp" -#endif -#ifdef TARGET_ARCH_MODEL_ppc_32 -# include "adfiles/ad_ppc_32.hpp" -#endif -#ifdef TARGET_ARCH_MODEL_ppc_64 +#elif defined TARGET_ARCH_MODEL_ppc_64 # include "adfiles/ad_ppc_64.hpp" #endif diff -r c2687aa5e5ca -r 7eb99acd567f src/share/vm/opto/graphKit.cpp --- a/src/share/vm/opto/graphKit.cpp Mon Jan 25 14:56:57 2016 -0800 +++ b/src/share/vm/opto/graphKit.cpp Mon Jan 25 14:57:27 2016 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 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 @@ -1452,16 +1452,18 @@ // factory methods in "int adr_idx" Node* GraphKit::make_load(Node* ctl, Node* adr, const Type* t, BasicType bt, int adr_idx, - MemNode::MemOrd mo, bool require_atomic_access) { + MemNode::MemOrd mo, LoadNode::ControlDependency control_dependency, bool require_atomic_access) { assert(adr_idx != Compile::AliasIdxTop, "use other make_load factory" ); const TypePtr* adr_type = NULL; // debug-mode-only argument debug_only(adr_type = C->get_adr_type(adr_idx)); Node* mem = memory(adr_idx); Node* ld; if (require_atomic_access && bt == T_LONG) { - ld = LoadLNode::make_atomic(C, ctl, mem, adr, adr_type, t, mo); + ld = LoadLNode::make_atomic(C, ctl, mem, adr, adr_type, t, mo, control_dependency); + } else if (require_atomic_access && bt == T_DOUBLE) { + ld = LoadDNode::make_atomic(C, ctl, mem, adr, adr_type, t, mo, control_dependency); } else { - ld = LoadNode::make(_gvn, ctl, mem, adr, adr_type, t, bt, mo); + ld = LoadNode::make(_gvn, ctl, mem, adr, adr_type, t, bt, mo, control_dependency); } ld = _gvn.transform(ld); if ((bt == T_OBJECT) && C->do_escape_analysis() || C->eliminate_boxing()) { @@ -1482,6 +1484,8 @@ Node* st; if (require_atomic_access && bt == T_LONG) { st = StoreLNode::make_atomic(C, ctl, mem, adr, adr_type, val, mo); + } else if (require_atomic_access && bt == T_DOUBLE) { + st = StoreDNode::make_atomic(C, ctl, mem, adr, adr_type, val, mo); } else { st = StoreNode::make(_gvn, ctl, mem, adr, adr_type, val, bt, mo); } @@ -1980,6 +1984,11 @@ Deoptimization::trap_request_index(trap_request) < 0 && too_many_recompiles(reason)) { // This BCI is causing too many recompilations. + if (C->log() != NULL) { + C->log()->elem("observe that='trap_action_change' reason='%s' from='%s' to='none'", + Deoptimization::trap_reason_name(reason), + Deoptimization::trap_action_name(action)); + } action = Deoptimization::Action_none; trap_request = Deoptimization::make_trap_request(reason, action); } else { @@ -2742,7 +2751,7 @@ Deoptimization::DeoptReason reason = spec_klass == NULL ? Deoptimization::Reason_class_check : Deoptimization::Reason_speculate_class_check; // Make sure we haven't already deoptimized from this tactic. - if (too_many_traps(reason)) + if (too_many_traps(reason) || too_many_recompiles(reason)) return NULL; // (No, this isn't a call, but it's enough like a virtual call @@ -2764,8 +2773,7 @@ &exact_obj); { PreserveJVMState pjvms(this); set_control(slow_ctl); - uncommon_trap(reason, - Deoptimization::Action_maybe_recompile); + uncommon_trap_exact(reason, Deoptimization::Action_maybe_recompile); } if (safe_for_replace) { replace_in_map(not_null_obj, exact_obj); @@ -2793,8 +2801,8 @@ if (type != NULL) { Deoptimization::DeoptReason class_reason = Deoptimization::Reason_speculate_class_check; Deoptimization::DeoptReason null_reason = Deoptimization::Reason_null_check; - if (!too_many_traps(null_reason) && - !too_many_traps(class_reason)) { + if (!too_many_traps(null_reason) && !too_many_recompiles(null_reason) && + !too_many_traps(class_reason) && !too_many_recompiles(class_reason)) { Node* not_null_obj = NULL; // not_null is true if we know the object is not null and // there's no need for a null check @@ -2813,14 +2821,14 @@ { PreserveJVMState pjvms(this); set_control(slow_ctl); - uncommon_trap(class_reason, - Deoptimization::Action_maybe_recompile); + uncommon_trap_exact(class_reason, Deoptimization::Action_maybe_recompile); } replace_in_map(not_null_obj, exact_obj); obj = exact_obj; } } else { - if (!too_many_traps(Deoptimization::Reason_null_assert)) { + if (!too_many_traps(Deoptimization::Reason_null_assert) && + !too_many_recompiles(Deoptimization::Reason_null_assert)) { Node* exact_obj = null_assert(obj); replace_in_map(obj, exact_obj); obj = exact_obj; @@ -3211,6 +3219,9 @@ const TypeFunc *tf = OptoRuntime::complete_monitor_exit_Type(); UnlockNode *unlock = new (C) UnlockNode(C, tf); +#ifdef ASSERT + unlock->set_dbg_jvms(sync_jvms()); +#endif uint raw_idx = Compile::AliasIdxRaw; unlock->init_req( TypeFunc::Control, control() ); unlock->init_req( TypeFunc::Memory , memory(raw_idx) ); diff -r c2687aa5e5ca -r 7eb99acd567f src/share/vm/opto/graphKit.hpp --- a/src/share/vm/opto/graphKit.hpp Mon Jan 25 14:56:57 2016 -0800 +++ b/src/share/vm/opto/graphKit.hpp Mon Jan 25 14:57:27 2016 -0800 @@ -516,21 +516,24 @@ // adapted the `do_put_xxx' and `do_get_xxx' procedures for the case // of volatile fields. Node* make_load(Node* ctl, Node* adr, const Type* t, BasicType bt, - MemNode::MemOrd mo, bool require_atomic_access = false) { + MemNode::MemOrd mo, LoadNode::ControlDependency control_dependency = LoadNode::DependsOnlyOnTest, + bool require_atomic_access = false) { // This version computes alias_index from bottom_type return make_load(ctl, adr, t, bt, adr->bottom_type()->is_ptr(), - mo, require_atomic_access); + mo, control_dependency, require_atomic_access); } Node* make_load(Node* ctl, Node* adr, const Type* t, BasicType bt, const TypePtr* adr_type, - MemNode::MemOrd mo, bool require_atomic_access = false) { + MemNode::MemOrd mo, LoadNode::ControlDependency control_dependency = LoadNode::DependsOnlyOnTest, + bool require_atomic_access = false) { // This version computes alias_index from an address type assert(adr_type != NULL, "use other make_load factory"); return make_load(ctl, adr, t, bt, C->get_alias_index(adr_type), - mo, require_atomic_access); + mo, control_dependency, require_atomic_access); } // This is the base version which is given an alias index. Node* make_load(Node* ctl, Node* adr, const Type* t, BasicType bt, int adr_idx, - MemNode::MemOrd mo, bool require_atomic_access = false); + MemNode::MemOrd mo, LoadNode::ControlDependency control_dependency = LoadNode::DependsOnlyOnTest, + bool require_atomic_access = false); // Create & transform a StoreNode and store the effect into the // parser's memory state. @@ -708,6 +711,15 @@ klass, reason_string, must_throw, keep_exact_action); } + // Bail out to the interpreter and keep exact action (avoid switching to Action_none). + void uncommon_trap_exact(Deoptimization::DeoptReason reason, + Deoptimization::DeoptAction action, + ciKlass* klass = NULL, const char* reason_string = NULL, + bool must_throw = false) { + uncommon_trap(Deoptimization::make_trap_request(reason, action), + klass, reason_string, must_throw, /*keep_exact_action=*/true); + } + // SP when bytecode needs to be reexecuted. virtual int reexecute_sp() { return sp(); } diff -r c2687aa5e5ca -r 7eb99acd567f src/share/vm/opto/lcm.cpp --- a/src/share/vm/opto/lcm.cpp Mon Jan 25 14:56:57 2016 -0800 +++ b/src/share/vm/opto/lcm.cpp Mon Jan 25 14:57:27 2016 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 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 @@ -30,25 +30,17 @@ #include "opto/cfgnode.hpp" #include "opto/machnode.hpp" #include "opto/runtime.hpp" -#ifdef TARGET_ARCH_MODEL_x86_32 +#if defined AD_MD_HPP +# include AD_MD_HPP +#elif defined TARGET_ARCH_MODEL_x86_32 # include "adfiles/ad_x86_32.hpp" -#endif -#ifdef TARGET_ARCH_MODEL_x86_64 +#elif defined TARGET_ARCH_MODEL_x86_64 # include "adfiles/ad_x86_64.hpp" -#endif -#ifdef TARGET_ARCH_MODEL_sparc +#elif defined TARGET_ARCH_MODEL_sparc # include "adfiles/ad_sparc.hpp" -#endif -#ifdef TARGET_ARCH_MODEL_zero +#elif defined TARGET_ARCH_MODEL_zero # include "adfiles/ad_zero.hpp" -#endif -#ifdef TARGET_ARCH_MODEL_arm -# include "adfiles/ad_arm.hpp" -#endif -#ifdef TARGET_ARCH_MODEL_ppc_32 -# include "adfiles/ad_ppc_32.hpp" -#endif -#ifdef TARGET_ARCH_MODEL_ppc_64 +#elif defined TARGET_ARCH_MODEL_ppc_64 # include "adfiles/ad_ppc_64.hpp" #endif @@ -437,8 +429,15 @@ for (DUIterator_Last i2min, i2 = old_tst->last_outs(i2min); i2 >= i2min; --i2) old_tst->last_out(i2)->set_req(0, nul_chk); // Clean-up any dead code - for (uint i3 = 0; i3 < old_tst->req(); i3++) + for (uint i3 = 0; i3 < old_tst->req(); i3++) { + Node* in = old_tst->in(i3); old_tst->set_req(i3, NULL); + if (in->outcnt() == 0) { + // Remove dead input node + in->disconnect_inputs(NULL, C); + block->find_remove(in); + } + } latency_from_uses(nul_chk); latency_from_uses(best); diff -r c2687aa5e5ca -r 7eb99acd567f src/share/vm/opto/library_call.cpp --- a/src/share/vm/opto/library_call.cpp Mon Jan 25 14:56:57 2016 -0800 +++ b/src/share/vm/opto/library_call.cpp Mon Jan 25 14:57:27 2016 -0800 @@ -31,6 +31,7 @@ #include "opto/addnode.hpp" #include "opto/callGenerator.hpp" #include "opto/cfgnode.hpp" +#include "opto/connode.hpp" #include "opto/idealKit.hpp" #include "opto/mathexactnode.hpp" #include "opto/mulnode.hpp" @@ -323,6 +324,8 @@ bool inline_updateBytesCRC32(); bool inline_updateByteBufferCRC32(); bool inline_multiplyToLen(); + + bool inline_profileBoolean(); }; @@ -934,6 +937,9 @@ case vmIntrinsics::_updateByteBufferCRC32: return inline_updateByteBufferCRC32(); + case vmIntrinsics::_profileBoolean: + return inline_profileBoolean(); + default: // If you get here, it may be that someone has added a new intrinsic // to the list in vmSymbols.hpp without implementing it here. @@ -2663,7 +2669,9 @@ if (!is_store) { MemNode::MemOrd mo = is_volatile ? MemNode::acquire : MemNode::unordered; - Node* p = make_load(control(), adr, value_type, type, adr_type, mo, is_volatile); + // To be valid, unsafe loads may depend on other conditions than + // the one that guards them: pin the Load node + Node* p = make_load(control(), adr, value_type, type, adr_type, mo, LoadNode::Pinned, is_volatile); // load value switch (type) { case T_BOOLEAN: @@ -6032,7 +6040,7 @@ } // Build the load. MemNode::MemOrd mo = is_vol ? MemNode::acquire : MemNode::unordered; - Node* loadedField = make_load(NULL, adr, type, bt, adr_type, mo, is_vol); + Node* loadedField = make_load(NULL, adr, type, bt, adr_type, mo, LoadNode::DependsOnlyOnTest, is_vol); // If reference is volatile, prevent following memory ops from // floating up past the volatile read. Also prevents commoning // another volatile read. @@ -6544,3 +6552,79 @@ return instof_false; // even if it is NULL } + +bool LibraryCallKit::inline_profileBoolean() { + Node* counts = argument(1); + const TypeAryPtr* ary = NULL; + ciArray* aobj = NULL; + if (counts->is_Con() + && (ary = counts->bottom_type()->isa_aryptr()) != NULL + && (aobj = ary->const_oop()->as_array()) != NULL + && (aobj->length() == 2)) { + // Profile is int[2] where [0] and [1] correspond to false and true value occurrences respectively. + jint false_cnt = aobj->element_value(0).as_int(); + jint true_cnt = aobj->element_value(1).as_int(); + + if (C->log() != NULL) { + C->log()->elem("observe source='profileBoolean' false='%d' true='%d'", + false_cnt, true_cnt); + } + + if (false_cnt + true_cnt == 0) { + // According to profile, never executed. + uncommon_trap_exact(Deoptimization::Reason_intrinsic, + Deoptimization::Action_reinterpret); + return true; + } + + // result is a boolean (0 or 1) and its profile (false_cnt & true_cnt) + // is a number of each value occurrences. + Node* result = argument(0); + if (false_cnt == 0 || true_cnt == 0) { + // According to profile, one value has been never seen. + int expected_val = (false_cnt == 0) ? 1 : 0; + + Node* cmp = _gvn.transform(new (C) CmpINode(result, intcon(expected_val))); + Node* test = _gvn.transform(new (C) BoolNode(cmp, BoolTest::eq)); + + IfNode* check = create_and_map_if(control(), test, PROB_ALWAYS, COUNT_UNKNOWN); + Node* fast_path = _gvn.transform(new (C) IfTrueNode(check)); + Node* slow_path = _gvn.transform(new (C) IfFalseNode(check)); + + { // Slow path: uncommon trap for never seen value and then reexecute + // MethodHandleImpl::profileBoolean() to bump the count, so JIT knows + // the value has been seen at least once. + PreserveJVMState pjvms(this); + PreserveReexecuteState preexecs(this); + jvms()->set_should_reexecute(true); + + set_control(slow_path); + set_i_o(i_o()); + + uncommon_trap_exact(Deoptimization::Reason_intrinsic, + Deoptimization::Action_reinterpret); + } + // The guard for never seen value enables sharpening of the result and + // returning a constant. It allows to eliminate branches on the same value + // later on. + set_control(fast_path); + result = intcon(expected_val); + } + // Stop profiling. + // MethodHandleImpl::profileBoolean() has profiling logic in its bytecode. + // By replacing method body with profile data (represented as ProfileBooleanNode + // on IR level) we effectively disable profiling. + // It enables full speed execution once optimized code is generated. + Node* profile = _gvn.transform(new (C) ProfileBooleanNode(result, false_cnt, true_cnt)); + C->record_for_igvn(profile); + set_result(profile); + return true; + } else { + // Continue profiling. + // Profile data isn't available at the moment. So, execute method's bytecode version. + // Usually, when GWT LambdaForms are profiled it means that a stand-alone nmethod + // is compiled and counters aren't available since corresponding MethodHandle + // isn't a compile-time constant. + return false; + } +} diff -r c2687aa5e5ca -r 7eb99acd567f src/share/vm/opto/locknode.hpp --- a/src/share/vm/opto/locknode.hpp Mon Jan 25 14:56:57 2016 -0800 +++ b/src/share/vm/opto/locknode.hpp Mon Jan 25 14:57:27 2016 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 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 @@ -28,25 +28,17 @@ #include "opto/node.hpp" #include "opto/opcodes.hpp" #include "opto/subnode.hpp" -#ifdef TARGET_ARCH_MODEL_x86_32 +#if defined AD_MD_HPP +# include AD_MD_HPP +#elif defined TARGET_ARCH_MODEL_x86_32 # include "adfiles/ad_x86_32.hpp" -#endif -#ifdef TARGET_ARCH_MODEL_x86_64 +#elif defined TARGET_ARCH_MODEL_x86_64 # include "adfiles/ad_x86_64.hpp" -#endif -#ifdef TARGET_ARCH_MODEL_sparc +#elif defined TARGET_ARCH_MODEL_sparc # include "adfiles/ad_sparc.hpp" -#endif -#ifdef TARGET_ARCH_MODEL_zero +#elif defined TARGET_ARCH_MODEL_zero # include "adfiles/ad_zero.hpp" -#endif -#ifdef TARGET_ARCH_MODEL_arm -# include "adfiles/ad_arm.hpp" -#endif -#ifdef TARGET_ARCH_MODEL_ppc_32 -# include "adfiles/ad_ppc_32.hpp" -#endif -#ifdef TARGET_ARCH_MODEL_ppc_64 +#elif defined TARGET_ARCH_MODEL_ppc_64 # include "adfiles/ad_ppc_64.hpp" #endif diff -r c2687aa5e5ca -r 7eb99acd567f src/share/vm/opto/loopPredicate.cpp --- a/src/share/vm/opto/loopPredicate.cpp Mon Jan 25 14:56:57 2016 -0800 +++ b/src/share/vm/opto/loopPredicate.cpp Mon Jan 25 14:57:27 2016 -0800 @@ -438,7 +438,13 @@ } } if (all_inputs_invariant) { - _invariant.set(n->_idx); // I am a invariant too + // If n's control is a predicate that was moved out of the + // loop, it was marked invariant but n is only invariant if + // it depends only on that test. Otherwise, unless that test + // is out of the loop, it's not invariant. + if (n->is_CFG() || n->depends_only_on_test() || n->in(0) == NULL || !_phase->is_member(_lpt, n->in(0))) { + _invariant.set(n->_idx); // I am a invariant too + } } } else { // process next input _stack.set_index(idx + 1); diff -r c2687aa5e5ca -r 7eb99acd567f src/share/vm/opto/loopTransform.cpp --- a/src/share/vm/opto/loopTransform.cpp Mon Jan 25 14:56:57 2016 -0800 +++ b/src/share/vm/opto/loopTransform.cpp Mon Jan 25 14:57:27 2016 -0800 @@ -1821,7 +1821,10 @@ // Find the pre-loop limit; we will expand it's iterations to // not ever trip low tests. Node *p_f = iffm->in(0); - assert(p_f->Opcode() == Op_IfFalse, ""); + // pre loop may have been optimized out + if (p_f->Opcode() != Op_IfFalse) { + return; + } CountedLoopEndNode *pre_end = p_f->in(0)->as_CountedLoopEnd(); assert(pre_end->loopnode()->is_pre_loop(), ""); Node *pre_opaq1 = pre_end->limit(); diff -r c2687aa5e5ca -r 7eb99acd567f src/share/vm/opto/loopnode.cpp --- a/src/share/vm/opto/loopnode.cpp Mon Jan 25 14:56:57 2016 -0800 +++ b/src/share/vm/opto/loopnode.cpp Mon Jan 25 14:57:27 2016 -0800 @@ -436,6 +436,19 @@ return false; // cyclic loop or this loop trips only once } + if (phi_incr != NULL) { + // check if there is a possiblity of IV overflowing after the first increment + if (stride_con > 0) { + if (init_t->_hi > max_jint - stride_con) { + return false; + } + } else { + if (init_t->_lo < min_jint - stride_con) { + return false; + } + } + } + // ================================================= // ---- SUCCESS! Found A Trip-Counted Loop! ----- // diff -r c2687aa5e5ca -r 7eb99acd567f src/share/vm/opto/machnode.hpp --- a/src/share/vm/opto/machnode.hpp Mon Jan 25 14:56:57 2016 -0800 +++ b/src/share/vm/opto/machnode.hpp Mon Jan 25 14:57:27 2016 -0800 @@ -558,6 +558,29 @@ #endif }; +// MachMergeNode is similar to a PhiNode in a sense it merges multiple values, +// however it doesn't have a control input and is more like a MergeMem. +// It is inserted after the register allocation is done to ensure that nodes use single +// definition of a multidef lrg in a block. +class MachMergeNode : public MachIdealNode { +public: + MachMergeNode(Node *n1) { + init_class_id(Class_MachMerge); + add_req(NULL); + add_req(n1); + } + virtual const RegMask &out_RegMask() const { return in(1)->out_RegMask(); } + virtual const RegMask &in_RegMask(uint idx) const { return in(1)->in_RegMask(idx); } + virtual const class Type *bottom_type() const { return in(1)->bottom_type(); } + virtual uint ideal_reg() const { return bottom_type()->ideal_reg(); } + virtual uint oper_input_base() const { return 1; } + virtual void emit(CodeBuffer &cbuf, PhaseRegAlloc *ra_) const { } + virtual uint size(PhaseRegAlloc *ra_) const { return 0; } +#ifndef PRODUCT + virtual const char *Name() const { return "MachMerge"; } +#endif +}; + //------------------------------MachBranchNode-------------------------------- // Abstract machine branch Node class MachBranchNode : public MachIdealNode { diff -r c2687aa5e5ca -r 7eb99acd567f src/share/vm/opto/macro.cpp --- a/src/share/vm/opto/macro.cpp Mon Jan 25 14:56:57 2016 -0800 +++ b/src/share/vm/opto/macro.cpp Mon Jan 25 14:57:27 2016 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 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 @@ -1890,7 +1890,7 @@ // Box is used only in one lock region. Mark this box as eliminated. _igvn.hash_delete(oldbox); oldbox->as_BoxLock()->set_eliminated(); // This changes box's hash value - _igvn.hash_insert(oldbox); + _igvn.hash_insert(oldbox); for (uint i = 0; i < oldbox->outcnt(); i++) { Node* u = oldbox->raw_out(i); @@ -1899,6 +1899,9 @@ // Check lock's box since box could be referenced by Lock's debug info. if (alock->box_node() == oldbox) { // Mark eliminated all related locks and unlocks. +#ifdef ASSERT + alock->log_lock_optimization(C, "eliminate_lock_set_non_esc4"); +#endif alock->set_non_esc_obj(); } } @@ -1925,6 +1928,9 @@ AbstractLockNode* alock = u->as_AbstractLock(); if (alock->box_node() == oldbox && alock->obj_node()->eqv_uncast(obj)) { // Replace Box and mark eliminated all related locks and unlocks. +#ifdef ASSERT + alock->log_lock_optimization(C, "eliminate_lock_set_non_esc5"); +#endif alock->set_non_esc_obj(); _igvn.rehash_node_delayed(alock); alock->set_box_node(newbox); @@ -1971,26 +1977,38 @@ return; } else if (!alock->is_non_esc_obj()) { // Not eliminated or coarsened // Only Lock node has JVMState needed here. - if (alock->jvms() != NULL && alock->as_Lock()->is_nested_lock_region()) { - // Mark eliminated related nested locks and unlocks. - Node* obj = alock->obj_node(); - BoxLockNode* box_node = alock->box_node()->as_BoxLock(); - assert(!box_node->is_eliminated(), "should not be marked yet"); - // Note: BoxLock node is marked eliminated only here - // and it is used to indicate that all associated lock - // and unlock nodes are marked for elimination. - box_node->set_eliminated(); // Box's hash is always NO_HASH here - for (uint i = 0; i < box_node->outcnt(); i++) { - Node* u = box_node->raw_out(i); - if (u->is_AbstractLock()) { - alock = u->as_AbstractLock(); - if (alock->box_node() == box_node) { - // Verify that this Box is referenced only by related locks. - assert(alock->obj_node()->eqv_uncast(obj), ""); - // Mark all related locks and unlocks. - alock->set_nested(); + // Not that preceding claim is documented anywhere else. + if (alock->jvms() != NULL) { + if (alock->as_Lock()->is_nested_lock_region()) { + // Mark eliminated related nested locks and unlocks. + Node* obj = alock->obj_node(); + BoxLockNode* box_node = alock->box_node()->as_BoxLock(); + assert(!box_node->is_eliminated(), "should not be marked yet"); + // Note: BoxLock node is marked eliminated only here + // and it is used to indicate that all associated lock + // and unlock nodes are marked for elimination. + box_node->set_eliminated(); // Box's hash is always NO_HASH here + for (uint i = 0; i < box_node->outcnt(); i++) { + Node* u = box_node->raw_out(i); + if (u->is_AbstractLock()) { + alock = u->as_AbstractLock(); + if (alock->box_node() == box_node) { + // Verify that this Box is referenced only by related locks. + assert(alock->obj_node()->eqv_uncast(obj), ""); + // Mark all related locks and unlocks. +#ifdef ASSERT + alock->log_lock_optimization(C, "eliminate_lock_set_nested"); +#endif + alock->set_nested(); + } } } + } else { +#ifdef ASSERT + alock->log_lock_optimization(C, "eliminate_lock_NOT_nested_lock_region"); + if (C->log() != NULL) + alock->as_Lock()->is_nested_lock_region(C); // rerun for debugging output +#endif } } return; @@ -2035,19 +2053,10 @@ assert(oldbox->is_eliminated(), "should be done already"); } #endif - CompileLog* log = C->log(); - if (log != NULL) { - log->head("eliminate_lock lock='%d'", - alock->is_Lock()); - JVMState* p = alock->jvms(); - while (p != NULL) { - log->elem("jvms bci='%d' method='%d'", p->bci(), log->identify(p->method())); - p = p->caller(); - } - log->tail("eliminate_lock"); - } - #ifndef PRODUCT + alock->log_lock_optimization(C, "eliminate_lock"); + +#ifndef PRODUCT if (PrintEliminateLocks) { if (alock->is_Lock()) { tty->print_cr("++++ Eliminated: %d Lock", alock->_idx); @@ -2055,7 +2064,7 @@ tty->print_cr("++++ Eliminated: %d Unlock", alock->_idx); } } - #endif +#endif Node* mem = alock->in(TypeFunc::Memory); Node* ctrl = alock->in(TypeFunc::Control); diff -r c2687aa5e5ca -r 7eb99acd567f src/share/vm/opto/matcher.cpp --- a/src/share/vm/opto/matcher.cpp Mon Jan 25 14:56:57 2016 -0800 +++ b/src/share/vm/opto/matcher.cpp Mon Jan 25 14:57:27 2016 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 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 @@ -38,25 +38,17 @@ #include "opto/vectornode.hpp" #include "runtime/atomic.hpp" #include "runtime/os.hpp" -#ifdef TARGET_ARCH_MODEL_x86_32 +#if defined AD_MD_HPP +# include AD_MD_HPP +#elif defined TARGET_ARCH_MODEL_x86_32 # include "adfiles/ad_x86_32.hpp" -#endif -#ifdef TARGET_ARCH_MODEL_x86_64 +#elif defined TARGET_ARCH_MODEL_x86_64 # include "adfiles/ad_x86_64.hpp" -#endif -#ifdef TARGET_ARCH_MODEL_sparc +#elif defined TARGET_ARCH_MODEL_sparc # include "adfiles/ad_sparc.hpp" -#endif -#ifdef TARGET_ARCH_MODEL_zero +#elif defined TARGET_ARCH_MODEL_zero # include "adfiles/ad_zero.hpp" -#endif -#ifdef TARGET_ARCH_MODEL_arm -# include "adfiles/ad_arm.hpp" -#endif -#ifdef TARGET_ARCH_MODEL_ppc_32 -# include "adfiles/ad_ppc_32.hpp" -#endif -#ifdef TARGET_ARCH_MODEL_ppc_64 +#elif defined TARGET_ARCH_MODEL_ppc_64 # include "adfiles/ad_ppc_64.hpp" #endif @@ -848,7 +840,7 @@ MachNode *spillCP = match_tree(new (C) LoadNNode(NULL,mem,fp,atp,TypeInstPtr::BOTTOM,MemNode::unordered)); #endif MachNode *spillI = match_tree(new (C) LoadINode(NULL,mem,fp,atp,TypeInt::INT,MemNode::unordered)); - MachNode *spillL = match_tree(new (C) LoadLNode(NULL,mem,fp,atp,TypeLong::LONG,MemNode::unordered,false)); + MachNode *spillL = match_tree(new (C) LoadLNode(NULL,mem,fp,atp,TypeLong::LONG,MemNode::unordered, LoadNode::DependsOnlyOnTest,false)); MachNode *spillF = match_tree(new (C) LoadFNode(NULL,mem,fp,atp,Type::FLOAT,MemNode::unordered)); MachNode *spillD = match_tree(new (C) LoadDNode(NULL,mem,fp,atp,Type::DOUBLE,MemNode::unordered)); MachNode *spillP = match_tree(new (C) LoadPNode(NULL,mem,fp,atp,TypeInstPtr::BOTTOM,MemNode::unordered)); diff -r c2687aa5e5ca -r 7eb99acd567f src/share/vm/opto/memnode.cpp --- a/src/share/vm/opto/memnode.cpp Mon Jan 25 14:56:57 2016 -0800 +++ b/src/share/vm/opto/memnode.cpp Mon Jan 25 14:57:27 2016 -0800 @@ -878,6 +878,9 @@ // standard dump does this in Verbose and WizardMode st->print(" #"); _type->dump_on(st); } + if (!_depends_only_on_test) { + st->print(" (does not depend only on test)"); + } } #endif @@ -894,7 +897,7 @@ //----------------------------LoadNode::make----------------------------------- // Polymorphic factory method: -Node *LoadNode::make(PhaseGVN& gvn, Node *ctl, Node *mem, Node *adr, const TypePtr* adr_type, const Type *rt, BasicType bt, MemOrd mo) { +Node *LoadNode::make(PhaseGVN& gvn, Node *ctl, Node *mem, Node *adr, const TypePtr* adr_type, const Type *rt, BasicType bt, MemOrd mo, ControlDependency control_dependency) { Compile* C = gvn.C; // sanity check the alias category against the created node type @@ -910,36 +913,40 @@ rt->isa_oopptr() || is_immutable_value(adr), "raw memory operations should have control edge"); switch (bt) { - case T_BOOLEAN: return new (C) LoadUBNode(ctl, mem, adr, adr_type, rt->is_int(), mo); - case T_BYTE: return new (C) LoadBNode (ctl, mem, adr, adr_type, rt->is_int(), mo); - case T_INT: return new (C) LoadINode (ctl, mem, adr, adr_type, rt->is_int(), mo); - case T_CHAR: return new (C) LoadUSNode(ctl, mem, adr, adr_type, rt->is_int(), mo); - case T_SHORT: return new (C) LoadSNode (ctl, mem, adr, adr_type, rt->is_int(), mo); - case T_LONG: return new (C) LoadLNode (ctl, mem, adr, adr_type, rt->is_long(), mo); - case T_FLOAT: return new (C) LoadFNode (ctl, mem, adr, adr_type, rt, mo); - case T_DOUBLE: return new (C) LoadDNode (ctl, mem, adr, adr_type, rt, mo); - case T_ADDRESS: return new (C) LoadPNode (ctl, mem, adr, adr_type, rt->is_ptr(), mo); + case T_BOOLEAN: return new (C) LoadUBNode(ctl, mem, adr, adr_type, rt->is_int(), mo, control_dependency); + case T_BYTE: return new (C) LoadBNode (ctl, mem, adr, adr_type, rt->is_int(), mo, control_dependency); + case T_INT: return new (C) LoadINode (ctl, mem, adr, adr_type, rt->is_int(), mo, control_dependency); + case T_CHAR: return new (C) LoadUSNode(ctl, mem, adr, adr_type, rt->is_int(), mo, control_dependency); + case T_SHORT: return new (C) LoadSNode (ctl, mem, adr, adr_type, rt->is_int(), mo, control_dependency); + case T_LONG: return new (C) LoadLNode (ctl, mem, adr, adr_type, rt->is_long(), mo, control_dependency); + case T_FLOAT: return new (C) LoadFNode (ctl, mem, adr, adr_type, rt, mo, control_dependency); + case T_DOUBLE: return new (C) LoadDNode (ctl, mem, adr, adr_type, rt, mo, control_dependency); + case T_ADDRESS: return new (C) LoadPNode (ctl, mem, adr, adr_type, rt->is_ptr(), mo, control_dependency); case T_OBJECT: #ifdef _LP64 if (adr->bottom_type()->is_ptr_to_narrowoop()) { - Node* load = gvn.transform(new (C) LoadNNode(ctl, mem, adr, adr_type, rt->make_narrowoop(), mo)); + Node* load = gvn.transform(new (C) LoadNNode(ctl, mem, adr, adr_type, rt->make_narrowoop(), mo, control_dependency)); return new (C) DecodeNNode(load, load->bottom_type()->make_ptr()); } else #endif { assert(!adr->bottom_type()->is_ptr_to_narrowoop() && !adr->bottom_type()->is_ptr_to_narrowklass(), "should have got back a narrow oop"); - return new (C) LoadPNode(ctl, mem, adr, adr_type, rt->is_oopptr(), mo); + return new (C) LoadPNode(ctl, mem, adr, adr_type, rt->is_oopptr(), mo, control_dependency); } } ShouldNotReachHere(); return (LoadNode*)NULL; } -LoadLNode* LoadLNode::make_atomic(Compile *C, Node* ctl, Node* mem, Node* adr, const TypePtr* adr_type, const Type* rt, MemOrd mo) { +LoadLNode* LoadLNode::make_atomic(Compile *C, Node* ctl, Node* mem, Node* adr, const TypePtr* adr_type, const Type* rt, MemOrd mo, ControlDependency control_dependency) { bool require_atomic = true; - return new (C) LoadLNode(ctl, mem, adr, adr_type, rt->is_long(), mo, require_atomic); + return new (C) LoadLNode(ctl, mem, adr, adr_type, rt->is_long(), mo, control_dependency, require_atomic); } +LoadDNode* LoadDNode::make_atomic(Compile *C, Node* ctl, Node* mem, Node* adr, const TypePtr* adr_type, const Type* rt, MemOrd mo, ControlDependency control_dependency) { + bool require_atomic = true; + return new (C) LoadDNode(ctl, mem, adr, adr_type, rt, mo, control_dependency, require_atomic); +} @@ -2398,6 +2405,11 @@ return new (C) StoreLNode(ctl, mem, adr, adr_type, val, mo, require_atomic); } +StoreDNode* StoreDNode::make_atomic(Compile *C, Node* ctl, Node* mem, Node* adr, const TypePtr* adr_type, Node* val, MemOrd mo) { + bool require_atomic = true; + return new (C) StoreDNode(ctl, mem, adr, adr_type, val, mo, require_atomic); +} + //--------------------------bottom_type---------------------------------------- const Type *StoreNode::bottom_type() const { diff -r c2687aa5e5ca -r 7eb99acd567f src/share/vm/opto/memnode.hpp --- a/src/share/vm/opto/memnode.hpp Mon Jan 25 14:56:57 2016 -0800 +++ b/src/share/vm/opto/memnode.hpp Mon Jan 25 14:57:27 2016 -0800 @@ -138,7 +138,33 @@ //------------------------------LoadNode--------------------------------------- // Load value; requires Memory and Address class LoadNode : public MemNode { +public: + // Some loads (from unsafe) should be pinned: they don't depend only + // on the dominating test. The boolean field _depends_only_on_test + // below records whether that node depends only on the dominating + // test. + // Methods used to build LoadNodes pass an argument of type enum + // ControlDependency instead of a boolean because those methods + // typically have multiple boolean parameters with default values: + // passing the wrong boolean to one of these parameters by mistake + // goes easily unnoticed. Using an enum, the compiler can check that + // the type of a value and the type of the parameter match. + enum ControlDependency { + Pinned, + DependsOnlyOnTest + }; private: + // LoadNode::hash() doesn't take the _depends_only_on_test field + // into account: If the graph already has a non-pinned LoadNode and + // we add a pinned LoadNode with the same inputs, it's safe for GVN + // to replace the pinned LoadNode with the non-pinned LoadNode, + // otherwise it wouldn't be safe to have a non pinned LoadNode with + // those inputs in the first place. If the graph already has a + // pinned LoadNode and we add a non pinned LoadNode with the same + // inputs, it's safe (but suboptimal) for GVN to replace the + // non-pinned LoadNode by the pinned LoadNode. + bool _depends_only_on_test; + // On platforms with weak memory ordering (e.g., PPC, Ia64) we distinguish // loads that can be reordered, and such requiring acquire semantics to // adhere to the Java specification. The required behaviour is stored in @@ -153,8 +179,8 @@ const Type* const _type; // What kind of value is loaded? public: - LoadNode(Node *c, Node *mem, Node *adr, const TypePtr* at, const Type *rt, MemOrd mo) - : MemNode(c,mem,adr,at), _type(rt), _mo(mo) { + LoadNode(Node *c, Node *mem, Node *adr, const TypePtr* at, const Type *rt, MemOrd mo, ControlDependency control_dependency) + : MemNode(c,mem,adr,at), _type(rt), _mo(mo), _depends_only_on_test(control_dependency == DependsOnlyOnTest) { init_class_id(Class_Load); } inline bool is_unordered() const { return !is_acquire(); } @@ -165,7 +191,8 @@ // Polymorphic factory method: static Node* make(PhaseGVN& gvn, Node *c, Node *mem, Node *adr, - const TypePtr* at, const Type *rt, BasicType bt, MemOrd mo); + const TypePtr* at, const Type *rt, BasicType bt, + MemOrd mo, ControlDependency control_dependency = DependsOnlyOnTest); virtual uint hash() const; // Check the type @@ -233,16 +260,15 @@ // which produce results (new raw memory state) inside of loops preventing all // manner of other optimizations). Basically, it's ugly but so is the alternative. // See comment in macro.cpp, around line 125 expand_allocate_common(). - virtual bool depends_only_on_test() const { return adr_type() != TypeRawPtr::BOTTOM; } - + virtual bool depends_only_on_test() const { return adr_type() != TypeRawPtr::BOTTOM && _depends_only_on_test; } }; //------------------------------LoadBNode-------------------------------------- // Load a byte (8bits signed) from memory class LoadBNode : public LoadNode { public: - LoadBNode(Node *c, Node *mem, Node *adr, const TypePtr* at, const TypeInt *ti, MemOrd mo) - : LoadNode(c, mem, adr, at, ti, mo) {} + LoadBNode(Node *c, Node *mem, Node *adr, const TypePtr* at, const TypeInt *ti, MemOrd mo, ControlDependency control_dependency = DependsOnlyOnTest) + : LoadNode(c, mem, adr, at, ti, mo, control_dependency) {} virtual int Opcode() const; virtual uint ideal_reg() const { return Op_RegI; } virtual Node *Ideal(PhaseGVN *phase, bool can_reshape); @@ -255,8 +281,8 @@ // Load a unsigned byte (8bits unsigned) from memory class LoadUBNode : public LoadNode { public: - LoadUBNode(Node* c, Node* mem, Node* adr, const TypePtr* at, const TypeInt* ti, MemOrd mo) - : LoadNode(c, mem, adr, at, ti, mo) {} + LoadUBNode(Node* c, Node* mem, Node* adr, const TypePtr* at, const TypeInt* ti, MemOrd mo, ControlDependency control_dependency = DependsOnlyOnTest) + : LoadNode(c, mem, adr, at, ti, mo, control_dependency) {} virtual int Opcode() const; virtual uint ideal_reg() const { return Op_RegI; } virtual Node* Ideal(PhaseGVN *phase, bool can_reshape); @@ -269,8 +295,8 @@ // Load an unsigned short/char (16bits unsigned) from memory class LoadUSNode : public LoadNode { public: - LoadUSNode(Node *c, Node *mem, Node *adr, const TypePtr* at, const TypeInt *ti, MemOrd mo) - : LoadNode(c, mem, adr, at, ti, mo) {} + LoadUSNode(Node *c, Node *mem, Node *adr, const TypePtr* at, const TypeInt *ti, MemOrd mo, ControlDependency control_dependency = DependsOnlyOnTest) + : LoadNode(c, mem, adr, at, ti, mo, control_dependency) {} virtual int Opcode() const; virtual uint ideal_reg() const { return Op_RegI; } virtual Node *Ideal(PhaseGVN *phase, bool can_reshape); @@ -283,8 +309,8 @@ // Load a short (16bits signed) from memory class LoadSNode : public LoadNode { public: - LoadSNode(Node *c, Node *mem, Node *adr, const TypePtr* at, const TypeInt *ti, MemOrd mo) - : LoadNode(c, mem, adr, at, ti, mo) {} + LoadSNode(Node *c, Node *mem, Node *adr, const TypePtr* at, const TypeInt *ti, MemOrd mo, ControlDependency control_dependency = DependsOnlyOnTest) + : LoadNode(c, mem, adr, at, ti, mo, control_dependency) {} virtual int Opcode() const; virtual uint ideal_reg() const { return Op_RegI; } virtual Node *Ideal(PhaseGVN *phase, bool can_reshape); @@ -297,8 +323,8 @@ // Load an integer from memory class LoadINode : public LoadNode { public: - LoadINode(Node *c, Node *mem, Node *adr, const TypePtr* at, const TypeInt *ti, MemOrd mo) - : LoadNode(c, mem, adr, at, ti, mo) {} + LoadINode(Node *c, Node *mem, Node *adr, const TypePtr* at, const TypeInt *ti, MemOrd mo, ControlDependency control_dependency = DependsOnlyOnTest) + : LoadNode(c, mem, adr, at, ti, mo, control_dependency) {} virtual int Opcode() const; virtual uint ideal_reg() const { return Op_RegI; } virtual int store_Opcode() const { return Op_StoreI; } @@ -330,15 +356,15 @@ public: LoadLNode(Node *c, Node *mem, Node *adr, const TypePtr* at, const TypeLong *tl, - MemOrd mo, bool require_atomic_access = false) - : LoadNode(c, mem, adr, at, tl, mo), _require_atomic_access(require_atomic_access) {} + MemOrd mo, ControlDependency control_dependency = DependsOnlyOnTest, bool require_atomic_access = false) + : LoadNode(c, mem, adr, at, tl, mo, control_dependency), _require_atomic_access(require_atomic_access) {} virtual int Opcode() const; virtual uint ideal_reg() const { return Op_RegL; } virtual int store_Opcode() const { return Op_StoreL; } virtual BasicType memory_type() const { return T_LONG; } - bool require_atomic_access() { return _require_atomic_access; } + bool require_atomic_access() const { return _require_atomic_access; } static LoadLNode* make_atomic(Compile *C, Node* ctl, Node* mem, Node* adr, const TypePtr* adr_type, - const Type* rt, MemOrd mo); + const Type* rt, MemOrd mo, ControlDependency control_dependency = DependsOnlyOnTest); #ifndef PRODUCT virtual void dump_spec(outputStream *st) const { LoadNode::dump_spec(st); @@ -351,8 +377,8 @@ // Load a long from unaligned memory class LoadL_unalignedNode : public LoadLNode { public: - LoadL_unalignedNode(Node *c, Node *mem, Node *adr, const TypePtr* at, MemOrd mo) - : LoadLNode(c, mem, adr, at, TypeLong::LONG, mo) {} + LoadL_unalignedNode(Node *c, Node *mem, Node *adr, const TypePtr* at, MemOrd mo, ControlDependency control_dependency = DependsOnlyOnTest) + : LoadLNode(c, mem, adr, at, TypeLong::LONG, mo, control_dependency) {} virtual int Opcode() const; }; @@ -360,8 +386,8 @@ // Load a float (64 bits) from memory class LoadFNode : public LoadNode { public: - LoadFNode(Node *c, Node *mem, Node *adr, const TypePtr* at, const Type *t, MemOrd mo) - : LoadNode(c, mem, adr, at, t, mo) {} + LoadFNode(Node *c, Node *mem, Node *adr, const TypePtr* at, const Type *t, MemOrd mo, ControlDependency control_dependency = DependsOnlyOnTest) + : LoadNode(c, mem, adr, at, t, mo, control_dependency) {} virtual int Opcode() const; virtual uint ideal_reg() const { return Op_RegF; } virtual int store_Opcode() const { return Op_StoreF; } @@ -371,21 +397,39 @@ //------------------------------LoadDNode-------------------------------------- // Load a double (64 bits) from memory class LoadDNode : public LoadNode { + virtual uint hash() const { return LoadNode::hash() + _require_atomic_access; } + virtual uint cmp( const Node &n ) const { + return _require_atomic_access == ((LoadDNode&)n)._require_atomic_access + && LoadNode::cmp(n); + } + virtual uint size_of() const { return sizeof(*this); } + const bool _require_atomic_access; // is piecewise load forbidden? + public: - LoadDNode(Node *c, Node *mem, Node *adr, const TypePtr* at, const Type *t, MemOrd mo) - : LoadNode(c, mem, adr, at, t, mo) {} + LoadDNode(Node *c, Node *mem, Node *adr, const TypePtr* at, const Type *t, + MemOrd mo, ControlDependency control_dependency = DependsOnlyOnTest, bool require_atomic_access = false) + : LoadNode(c, mem, adr, at, t, mo, control_dependency), _require_atomic_access(require_atomic_access) {} virtual int Opcode() const; virtual uint ideal_reg() const { return Op_RegD; } virtual int store_Opcode() const { return Op_StoreD; } virtual BasicType memory_type() const { return T_DOUBLE; } + bool require_atomic_access() const { return _require_atomic_access; } + static LoadDNode* make_atomic(Compile *C, Node* ctl, Node* mem, Node* adr, const TypePtr* adr_type, + const Type* rt, MemOrd mo, ControlDependency control_dependency = DependsOnlyOnTest); +#ifndef PRODUCT + virtual void dump_spec(outputStream *st) const { + LoadNode::dump_spec(st); + if (_require_atomic_access) st->print(" Atomic!"); + } +#endif }; //------------------------------LoadD_unalignedNode---------------------------- // Load a double from unaligned memory class LoadD_unalignedNode : public LoadDNode { public: - LoadD_unalignedNode(Node *c, Node *mem, Node *adr, const TypePtr* at, MemOrd mo) - : LoadDNode(c, mem, adr, at, Type::DOUBLE, mo) {} + LoadD_unalignedNode(Node *c, Node *mem, Node *adr, const TypePtr* at, MemOrd mo, ControlDependency control_dependency = DependsOnlyOnTest) + : LoadDNode(c, mem, adr, at, Type::DOUBLE, mo, control_dependency) {} virtual int Opcode() const; }; @@ -393,8 +437,8 @@ // Load a pointer from memory (either object or array) class LoadPNode : public LoadNode { public: - LoadPNode(Node *c, Node *mem, Node *adr, const TypePtr *at, const TypePtr* t, MemOrd mo) - : LoadNode(c, mem, adr, at, t, mo) {} + LoadPNode(Node *c, Node *mem, Node *adr, const TypePtr *at, const TypePtr* t, MemOrd mo, ControlDependency control_dependency = DependsOnlyOnTest) + : LoadNode(c, mem, adr, at, t, mo, control_dependency) {} virtual int Opcode() const; virtual uint ideal_reg() const { return Op_RegP; } virtual int store_Opcode() const { return Op_StoreP; } @@ -406,8 +450,8 @@ // Load a narrow oop from memory (either object or array) class LoadNNode : public LoadNode { public: - LoadNNode(Node *c, Node *mem, Node *adr, const TypePtr *at, const Type* t, MemOrd mo) - : LoadNode(c, mem, adr, at, t, mo) {} + LoadNNode(Node *c, Node *mem, Node *adr, const TypePtr *at, const Type* t, MemOrd mo, ControlDependency control_dependency = DependsOnlyOnTest) + : LoadNode(c, mem, adr, at, t, mo, control_dependency) {} virtual int Opcode() const; virtual uint ideal_reg() const { return Op_RegN; } virtual int store_Opcode() const { return Op_StoreN; } @@ -582,7 +626,7 @@ : StoreNode(c, mem, adr, at, val, mo), _require_atomic_access(require_atomic_access) {} virtual int Opcode() const; virtual BasicType memory_type() const { return T_LONG; } - bool require_atomic_access() { return _require_atomic_access; } + bool require_atomic_access() const { return _require_atomic_access; } static StoreLNode* make_atomic(Compile *C, Node* ctl, Node* mem, Node* adr, const TypePtr* adr_type, Node* val, MemOrd mo); #ifndef PRODUCT virtual void dump_spec(outputStream *st) const { @@ -605,11 +649,28 @@ //------------------------------StoreDNode------------------------------------- // Store double to memory class StoreDNode : public StoreNode { + virtual uint hash() const { return StoreNode::hash() + _require_atomic_access; } + virtual uint cmp( const Node &n ) const { + return _require_atomic_access == ((StoreDNode&)n)._require_atomic_access + && StoreNode::cmp(n); + } + virtual uint size_of() const { return sizeof(*this); } + const bool _require_atomic_access; // is piecewise store forbidden? public: - StoreDNode(Node *c, Node *mem, Node *adr, const TypePtr* at, Node *val, MemOrd mo) - : StoreNode(c, mem, adr, at, val, mo) {} + StoreDNode(Node *c, Node *mem, Node *adr, const TypePtr* at, Node *val, + MemOrd mo, bool require_atomic_access = false) + : StoreNode(c, mem, adr, at, val, mo), _require_atomic_access(require_atomic_access) {} virtual int Opcode() const; virtual BasicType memory_type() const { return T_DOUBLE; } + bool require_atomic_access() const { return _require_atomic_access; } + static StoreDNode* make_atomic(Compile *C, Node* ctl, Node* mem, Node* adr, const TypePtr* adr_type, Node* val, MemOrd mo); +#ifndef PRODUCT + virtual void dump_spec(outputStream *st) const { + StoreNode::dump_spec(st); + if (_require_atomic_access) st->print(" Atomic!"); + } +#endif + }; //------------------------------StorePNode------------------------------------- diff -r c2687aa5e5ca -r 7eb99acd567f src/share/vm/opto/node.hpp --- a/src/share/vm/opto/node.hpp Mon Jan 25 14:56:57 2016 -0800 +++ b/src/share/vm/opto/node.hpp Mon Jan 25 14:57:27 2016 -0800 @@ -98,6 +98,7 @@ class MachSafePointNode; class MachSpillCopyNode; class MachTempNode; +class MachMergeNode; class Matcher; class MemBarNode; class MemBarStoreStoreNode; @@ -591,6 +592,7 @@ DEFINE_CLASS_ID(MachTemp, Mach, 3) DEFINE_CLASS_ID(MachConstantBase, Mach, 4) DEFINE_CLASS_ID(MachConstant, Mach, 5) + DEFINE_CLASS_ID(MachMerge, Mach, 6) DEFINE_CLASS_ID(Type, Node, 2) DEFINE_CLASS_ID(Phi, Type, 0) @@ -761,6 +763,7 @@ DEFINE_CLASS_QUERY(MachSafePoint) DEFINE_CLASS_QUERY(MachSpillCopy) DEFINE_CLASS_QUERY(MachTemp) + DEFINE_CLASS_QUERY(MachMerge) DEFINE_CLASS_QUERY(Mem) DEFINE_CLASS_QUERY(MemBar) DEFINE_CLASS_QUERY(MemBarStoreStore) diff -r c2687aa5e5ca -r 7eb99acd567f src/share/vm/opto/output.cpp --- a/src/share/vm/opto/output.cpp Mon Jan 25 14:56:57 2016 -0800 +++ b/src/share/vm/opto/output.cpp Mon Jan 25 14:57:27 2016 -0800 @@ -2476,7 +2476,7 @@ if( iop == Op_Con ) continue; // Do not schedule Top if( iop == Op_Node && // Do not schedule PhiNodes, ProjNodes mach->pipeline() == MachNode::pipeline_class() && - !n->is_SpillCopy() ) // Breakpoints, Prolog, etc + !n->is_SpillCopy() && !n->is_MachMerge() ) // Breakpoints, Prolog, etc continue; break; // Funny loop structure to be sure... } diff -r c2687aa5e5ca -r 7eb99acd567f src/share/vm/opto/output.hpp --- a/src/share/vm/opto/output.hpp Mon Jan 25 14:56:57 2016 -0800 +++ b/src/share/vm/opto/output.hpp Mon Jan 25 14:57:27 2016 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 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 @@ -27,25 +27,17 @@ #include "opto/block.hpp" #include "opto/node.hpp" -#ifdef TARGET_ARCH_MODEL_x86_32 +#if defined AD_MD_HPP +# include AD_MD_HPP +#elif defined TARGET_ARCH_MODEL_x86_32 # include "adfiles/ad_x86_32.hpp" -#endif -#ifdef TARGET_ARCH_MODEL_x86_64 +#elif defined TARGET_ARCH_MODEL_x86_64 # include "adfiles/ad_x86_64.hpp" -#endif -#ifdef TARGET_ARCH_MODEL_sparc +#elif defined TARGET_ARCH_MODEL_sparc # include "adfiles/ad_sparc.hpp" -#endif -#ifdef TARGET_ARCH_MODEL_zero +#elif defined TARGET_ARCH_MODEL_zero # include "adfiles/ad_zero.hpp" -#endif -#ifdef TARGET_ARCH_MODEL_arm -# include "adfiles/ad_arm.hpp" -#endif -#ifdef TARGET_ARCH_MODEL_ppc_32 -# include "adfiles/ad_ppc_32.hpp" -#endif -#ifdef TARGET_ARCH_MODEL_ppc_64 +#elif defined TARGET_ARCH_MODEL_ppc_64 # include "adfiles/ad_ppc_64.hpp" #endif diff -r c2687aa5e5ca -r 7eb99acd567f src/share/vm/opto/parse.hpp --- a/src/share/vm/opto/parse.hpp Mon Jan 25 14:56:57 2016 -0800 +++ b/src/share/vm/opto/parse.hpp Mon Jan 25 14:57:27 2016 -0800 @@ -549,8 +549,8 @@ void do_jsr(); void do_ret(); - float dynamic_branch_prediction(float &cnt); - float branch_prediction(float &cnt, BoolTest::mask btest, int target_bci); + float dynamic_branch_prediction(float &cnt, BoolTest::mask btest, Node* test); + float branch_prediction(float &cnt, BoolTest::mask btest, int target_bci, Node* test); bool seems_never_taken(float prob) const; bool path_is_suitable_for_uncommon_trap(float prob) const; bool seems_stable_comparison() const; diff -r c2687aa5e5ca -r 7eb99acd567f src/share/vm/opto/parse2.cpp --- a/src/share/vm/opto/parse2.cpp Mon Jan 25 14:56:57 2016 -0800 +++ b/src/share/vm/opto/parse2.cpp Mon Jan 25 14:57:27 2016 -0800 @@ -761,35 +761,64 @@ merge_common(target, pnum); } +static bool has_injected_profile(BoolTest::mask btest, Node* test, int& taken, int& not_taken) { + if (btest != BoolTest::eq && btest != BoolTest::ne) { + // Only ::eq and ::ne are supported for profile injection. + return false; + } + if (test->is_Cmp() && + test->in(1)->Opcode() == Op_ProfileBoolean) { + ProfileBooleanNode* profile = (ProfileBooleanNode*)test->in(1); + int false_cnt = profile->false_count(); + int true_cnt = profile->true_count(); + + // Counts matching depends on the actual test operation (::eq or ::ne). + // No need to scale the counts because profile injection was designed + // to feed exact counts into VM. + taken = (btest == BoolTest::eq) ? false_cnt : true_cnt; + not_taken = (btest == BoolTest::eq) ? true_cnt : false_cnt; + + profile->consume(); + return true; + } + return false; +} //--------------------------dynamic_branch_prediction-------------------------- // Try to gather dynamic branch prediction behavior. Return a probability // of the branch being taken and set the "cnt" field. Returns a -1.0 // if we need to use static prediction for some reason. -float Parse::dynamic_branch_prediction(float &cnt) { +float Parse::dynamic_branch_prediction(float &cnt, BoolTest::mask btest, Node* test) { ResourceMark rm; cnt = COUNT_UNKNOWN; - // Use MethodData information if it is available - // FIXME: free the ProfileData structure - ciMethodData* methodData = method()->method_data(); - if (!methodData->is_mature()) return PROB_UNKNOWN; - ciProfileData* data = methodData->bci_to_data(bci()); - if (!data->is_JumpData()) return PROB_UNKNOWN; + int taken = 0; + int not_taken = 0; + + bool use_mdo = !has_injected_profile(btest, test, taken, not_taken); - // get taken and not taken values - int taken = data->as_JumpData()->taken(); - int not_taken = 0; - if (data->is_BranchData()) { - not_taken = data->as_BranchData()->not_taken(); + if (use_mdo) { + // Use MethodData information if it is available + // FIXME: free the ProfileData structure + ciMethodData* methodData = method()->method_data(); + if (!methodData->is_mature()) return PROB_UNKNOWN; + ciProfileData* data = methodData->bci_to_data(bci()); + if (!data->is_JumpData()) return PROB_UNKNOWN; + + // get taken and not taken values + taken = data->as_JumpData()->taken(); + not_taken = 0; + if (data->is_BranchData()) { + not_taken = data->as_BranchData()->not_taken(); + } + + // scale the counts to be commensurate with invocation counts: + taken = method()->scale_count(taken); + not_taken = method()->scale_count(not_taken); } - // scale the counts to be commensurate with invocation counts: - taken = method()->scale_count(taken); - not_taken = method()->scale_count(not_taken); - // Give up if too few (or too many, in which case the sum will overflow) counts to be meaningful. - // We also check that individual counters are positive first, overwise the sum can become positive. + // We also check that individual counters are positive first, otherwise the sum can become positive. if (taken < 0 || not_taken < 0 || taken + not_taken < 40) { if (C->log() != NULL) { C->log()->elem("branch target_bci='%d' taken='%d' not_taken='%d'", iter().get_dest(), taken, not_taken); @@ -839,8 +868,9 @@ //-----------------------------branch_prediction------------------------------- float Parse::branch_prediction(float& cnt, BoolTest::mask btest, - int target_bci) { - float prob = dynamic_branch_prediction(cnt); + int target_bci, + Node* test) { + float prob = dynamic_branch_prediction(cnt, btest, test); // If prob is unknown, switch to static prediction if (prob != PROB_UNKNOWN) return prob; @@ -930,7 +960,7 @@ Block* next_block = successor_for_bci(iter().next_bci()); float cnt; - float prob = branch_prediction(cnt, btest, target_bci); + float prob = branch_prediction(cnt, btest, target_bci, c); if (prob == PROB_UNKNOWN) { // (An earlier version of do_ifnull omitted this trap for OSR methods.) #ifndef PRODUCT @@ -1011,7 +1041,7 @@ Block* next_block = successor_for_bci(iter().next_bci()); float cnt; - float prob = branch_prediction(cnt, btest, target_bci); + float prob = branch_prediction(cnt, btest, target_bci, c); float untaken_prob = 1.0 - prob; if (prob == PROB_UNKNOWN) { diff -r c2687aa5e5ca -r 7eb99acd567f src/share/vm/opto/parse3.cpp --- a/src/share/vm/opto/parse3.cpp Mon Jan 25 14:56:57 2016 -0800 +++ b/src/share/vm/opto/parse3.cpp Mon Jan 25 14:57:27 2016 -0800 @@ -233,7 +233,7 @@ // Build the load. // MemNode::MemOrd mo = is_vol ? MemNode::acquire : MemNode::unordered; - Node* ld = make_load(NULL, adr, type, bt, adr_type, mo, is_vol); + Node* ld = make_load(NULL, adr, type, bt, adr_type, mo, LoadNode::DependsOnlyOnTest, is_vol); // Adjust Java stack if (type2size[bt] == 1) diff -r c2687aa5e5ca -r 7eb99acd567f src/share/vm/opto/phase.cpp --- a/src/share/vm/opto/phase.cpp Mon Jan 25 14:56:57 2016 -0800 +++ b/src/share/vm/opto/phase.cpp Mon Jan 25 14:57:27 2016 -0800 @@ -74,6 +74,7 @@ elapsedTimer Phase::_t_computeLive; elapsedTimer Phase::_t_regAllocSplit; elapsedTimer Phase::_t_postAllocCopyRemoval; +elapsedTimer Phase::_t_mergeMultidefs; elapsedTimer Phase::_t_fixupSpills; // Subtimers for _t_output @@ -136,11 +137,12 @@ tty->print_cr (" computeLive : %3.3f sec", Phase::_t_computeLive.seconds()); tty->print_cr (" regAllocSplit : %3.3f sec", Phase::_t_regAllocSplit.seconds()); tty->print_cr (" postAllocCopyRemoval: %3.3f sec", Phase::_t_postAllocCopyRemoval.seconds()); + tty->print_cr (" mergeMultidefs: %3.3f sec", Phase::_t_mergeMultidefs.seconds()); tty->print_cr (" fixupSpills : %3.3f sec", Phase::_t_fixupSpills.seconds()); double regalloc_subtotal = Phase::_t_ctorChaitin.seconds() + Phase::_t_buildIFGphysical.seconds() + Phase::_t_computeLive.seconds() + Phase::_t_regAllocSplit.seconds() + Phase::_t_fixupSpills.seconds() + - Phase::_t_postAllocCopyRemoval.seconds(); + Phase::_t_postAllocCopyRemoval.seconds() + Phase::_t_mergeMultidefs.seconds(); double percent_of_regalloc = ((regalloc_subtotal == 0.0) ? 0.0 : (regalloc_subtotal / Phase::_t_registerAllocation.seconds() * 100.0)); tty->print_cr (" subtotal : %3.3f sec, %3.2f %%", regalloc_subtotal, percent_of_regalloc); } diff -r c2687aa5e5ca -r 7eb99acd567f src/share/vm/opto/phase.hpp --- a/src/share/vm/opto/phase.hpp Mon Jan 25 14:56:57 2016 -0800 +++ b/src/share/vm/opto/phase.hpp Mon Jan 25 14:57:27 2016 -0800 @@ -109,6 +109,7 @@ static elapsedTimer _t_computeLive; static elapsedTimer _t_regAllocSplit; static elapsedTimer _t_postAllocCopyRemoval; + static elapsedTimer _t_mergeMultidefs; static elapsedTimer _t_fixupSpills; // Subtimers for _t_output diff -r c2687aa5e5ca -r 7eb99acd567f src/share/vm/opto/phaseX.cpp --- a/src/share/vm/opto/phaseX.cpp Mon Jan 25 14:56:57 2016 -0800 +++ b/src/share/vm/opto/phaseX.cpp Mon Jan 25 14:57:27 2016 -0800 @@ -1521,11 +1521,12 @@ set_type(n, t); for (DUIterator_Fast imax, i = n->fast_outs(imax); i < imax; i++) { Node* m = n->fast_out(i); // Get user - if( m->is_Region() ) { // New path to Region? Must recheck Phis too + if (m->is_Region()) { // New path to Region? Must recheck Phis too for (DUIterator_Fast i2max, i2 = m->fast_outs(i2max); i2 < i2max; i2++) { Node* p = m->fast_out(i2); // Propagate changes to uses - if( p->bottom_type() != type(p) ) // If not already bottomed out + if (p->bottom_type() != type(p)) { // If not already bottomed out worklist.push(p); // Propagate change to user + } } } // If we changed the receiver type to a call, we need to revisit @@ -1535,12 +1536,31 @@ if (m->is_Call()) { for (DUIterator_Fast i2max, i2 = m->fast_outs(i2max); i2 < i2max; i2++) { Node* p = m->fast_out(i2); // Propagate changes to uses - if (p->is_Proj() && p->as_Proj()->_con == TypeFunc::Control && p->outcnt() == 1) + if (p->is_Proj() && p->as_Proj()->_con == TypeFunc::Control && p->outcnt() == 1) { worklist.push(p->unique_out()); + } } } - if( m->bottom_type() != type(m) ) // If not already bottomed out + if (m->bottom_type() != type(m)) { // If not already bottomed out worklist.push(m); // Propagate change to user + } + + // CmpU nodes can get their type information from two nodes up in the + // graph (instead of from the nodes immediately above). Make sure they + // are added to the worklist if nodes they depend on are updated, since + // they could be missed and get wrong types otherwise. + uint m_op = m->Opcode(); + if (m_op == Op_AddI || m_op == Op_SubI) { + for (DUIterator_Fast i2max, i2 = m->fast_outs(i2max); i2 < i2max; i2++) { + Node* p = m->fast_out(i2); // Propagate changes to uses + if (p->Opcode() == Op_CmpU) { + // Got a CmpU which might need the new type information from node n. + if(p->bottom_type() != type(p)) { // If not already bottomed out + worklist.push(p); // Propagate change to user + } + } + } + } } } } diff -r c2687aa5e5ca -r 7eb99acd567f src/share/vm/opto/postaloc.cpp --- a/src/share/vm/opto/postaloc.cpp Mon Jan 25 14:56:57 2016 -0800 +++ b/src/share/vm/opto/postaloc.cpp Mon Jan 25 14:57:27 2016 -0800 @@ -263,20 +263,6 @@ // intermediate copies might be illegal, i.e., value is stored down to stack // then reloaded BUT survives in a register the whole way. Node *val = skip_copies(n->in(k)); - - if (val == x && nk_idx != 0 && - regnd[nk_reg] != NULL && regnd[nk_reg] != x && - _lrg_map.live_range_id(x) == _lrg_map.live_range_id(regnd[nk_reg])) { - // When rematerialzing nodes and stretching lifetimes, the - // allocator will reuse the original def for multidef LRG instead - // of the current reaching def because it can't know it's safe to - // do so. After allocation completes if they are in the same LRG - // then it should use the current reaching def instead. - n->set_req(k, regnd[nk_reg]); - blk_adjust += yank_if_dead(val, current_block, &value, ®nd); - val = skip_copies(n->in(k)); - } - if (val == x) return blk_adjust; // No progress? int n_regs = RegMask::num_registers(val->ideal_reg()); @@ -382,6 +368,95 @@ return false; } +// The algorithms works as follows: +// We traverse the block top to bottom. possibly_merge_multidef() is invoked for every input edge k +// of the instruction n. We check to see if the input is a multidef lrg. If it is, we record the fact that we've +// seen a definition (coming as an input) and add that fact to the reg2defuse array. The array maps registers to their +// current reaching definitions (we track only multidefs though). With each definition we also associate the first +// instruction we saw use it. If we encounter the situation when we observe an def (an input) that is a part of the +// same lrg but is different from the previous seen def we merge the two with a MachMerge node and substitute +// all the uses that we've seen so far to use the merge. After that we keep replacing the new defs in the same lrg +// as they get encountered with the merge node and keep adding these defs to the merge inputs. +void PhaseChaitin::merge_multidefs() { + NOT_PRODUCT( Compile::TracePhase t3("mergeMultidefs", &_t_mergeMultidefs, TimeCompiler); ) + ResourceMark rm; + // Keep track of the defs seen in registers and collect their uses in the block. + RegToDefUseMap reg2defuse(_max_reg, _max_reg, RegDefUse()); + for (uint i = 0; i < _cfg.number_of_blocks(); i++) { + Block* block = _cfg.get_block(i); + for (uint j = 1; j < block->number_of_nodes(); j++) { + Node* n = block->get_node(j); + if (n->is_Phi()) continue; + for (uint k = 1; k < n->req(); k++) { + j += possibly_merge_multidef(n, k, block, reg2defuse); + } + // Null out the value produced by the instruction itself, since we're only interested in defs + // implicitly defined by the uses. We are actually interested in tracking only redefinitions + // of the multidef lrgs in the same register. For that matter it's enough to track changes in + // the base register only and ignore other effects of multi-register lrgs and fat projections. + // It is also ok to ignore defs coming from singledefs. After an implicit overwrite by one of + // those our register is guaranteed to be used by another lrg and we won't attempt to merge it. + uint lrg = _lrg_map.live_range_id(n); + if (lrg > 0 && lrgs(lrg).is_multidef()) { + OptoReg::Name reg = lrgs(lrg).reg(); + reg2defuse.at(reg).clear(); + } + } + // Clear reg->def->use tracking for the next block + for (int j = 0; j < reg2defuse.length(); j++) { + reg2defuse.at(j).clear(); + } + } +} + +int PhaseChaitin::possibly_merge_multidef(Node *n, uint k, Block *block, RegToDefUseMap& reg2defuse) { + int blk_adjust = 0; + + uint lrg = _lrg_map.live_range_id(n->in(k)); + if (lrg > 0 && lrgs(lrg).is_multidef()) { + OptoReg::Name reg = lrgs(lrg).reg(); + + Node* def = reg2defuse.at(reg).def(); + if (def != NULL && lrg == _lrg_map.live_range_id(def) && def != n->in(k)) { + // Same lrg but different node, we have to merge. + MachMergeNode* merge; + if (def->is_MachMerge()) { // is it already a merge? + merge = def->as_MachMerge(); + } else { + merge = new (C) MachMergeNode(def); + + // Insert the merge node into the block before the first use. + uint use_index = block->find_node(reg2defuse.at(reg).first_use()); + block->insert_node(merge, use_index++); + _cfg.map_node_to_block(merge, block); + + // Let the allocator know about the new node, use the same lrg + _lrg_map.extend(merge->_idx, lrg); + blk_adjust++; + + // Fixup all the uses (there is at least one) that happened between the first + // use and before the current one. + for (; use_index < block->number_of_nodes(); use_index++) { + Node* use = block->get_node(use_index); + if (use == n) { + break; + } + use->replace_edge(def, merge); + } + } + if (merge->find_edge(n->in(k)) == -1) { + merge->add_req(n->in(k)); + } + n->set_req(k, merge); + } + + // update the uses + reg2defuse.at(reg).update(n->in(k), n); + } + + return blk_adjust; +} + //------------------------------post_allocate_copy_removal--------------------- // Post-Allocation peephole copy removal. We do this in 1 pass over the diff -r c2687aa5e5ca -r 7eb99acd567f src/share/vm/opto/regmask.cpp --- a/src/share/vm/opto/regmask.cpp Mon Jan 25 14:56:57 2016 -0800 +++ b/src/share/vm/opto/regmask.cpp Mon Jan 25 14:57:27 2016 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 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 @@ -25,25 +25,17 @@ #include "precompiled.hpp" #include "opto/compile.hpp" #include "opto/regmask.hpp" -#ifdef TARGET_ARCH_MODEL_x86_32 +#if defined AD_MD_HPP +# include AD_MD_HPP +#elif defined TARGET_ARCH_MODEL_x86_32 # include "adfiles/ad_x86_32.hpp" -#endif -#ifdef TARGET_ARCH_MODEL_x86_64 +#elif defined TARGET_ARCH_MODEL_x86_64 # include "adfiles/ad_x86_64.hpp" -#endif -#ifdef TARGET_ARCH_MODEL_sparc +#elif defined TARGET_ARCH_MODEL_sparc # include "adfiles/ad_sparc.hpp" -#endif -#ifdef TARGET_ARCH_MODEL_zero +#elif defined TARGET_ARCH_MODEL_zero # include "adfiles/ad_zero.hpp" -#endif -#ifdef TARGET_ARCH_MODEL_arm -# include "adfiles/ad_arm.hpp" -#endif -#ifdef TARGET_ARCH_MODEL_ppc_32 -# include "adfiles/ad_ppc_32.hpp" -#endif -#ifdef TARGET_ARCH_MODEL_ppc_64 +#elif defined TARGET_ARCH_MODEL_ppc_64 # include "adfiles/ad_ppc_64.hpp" #endif diff -r c2687aa5e5ca -r 7eb99acd567f src/share/vm/opto/regmask.hpp --- a/src/share/vm/opto/regmask.hpp Mon Jan 25 14:56:57 2016 -0800 +++ b/src/share/vm/opto/regmask.hpp Mon Jan 25 14:57:27 2016 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 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 @@ -28,25 +28,17 @@ #include "code/vmreg.hpp" #include "libadt/port.hpp" #include "opto/optoreg.hpp" -#ifdef TARGET_ARCH_MODEL_x86_32 +#if defined ADGLOBALS_MD_HPP +# include ADGLOBALS_MD_HPP +#elif defined TARGET_ARCH_MODEL_x86_32 # include "adfiles/adGlobals_x86_32.hpp" -#endif -#ifdef TARGET_ARCH_MODEL_x86_64 +#elif defined TARGET_ARCH_MODEL_x86_64 # include "adfiles/adGlobals_x86_64.hpp" -#endif -#ifdef TARGET_ARCH_MODEL_sparc +#elif defined TARGET_ARCH_MODEL_sparc # include "adfiles/adGlobals_sparc.hpp" -#endif -#ifdef TARGET_ARCH_MODEL_zero +#elif defined TARGET_ARCH_MODEL_zero # include "adfiles/adGlobals_zero.hpp" -#endif -#ifdef TARGET_ARCH_MODEL_arm -# include "adfiles/adGlobals_arm.hpp" -#endif -#ifdef TARGET_ARCH_MODEL_ppc_32 -# include "adfiles/adGlobals_ppc_32.hpp" -#endif -#ifdef TARGET_ARCH_MODEL_ppc_64 +#elif defined TARGET_ARCH_MODEL_ppc_64 # include "adfiles/adGlobals_ppc_64.hpp" #endif diff -r c2687aa5e5ca -r 7eb99acd567f src/share/vm/opto/runtime.cpp --- a/src/share/vm/opto/runtime.cpp Mon Jan 25 14:56:57 2016 -0800 +++ b/src/share/vm/opto/runtime.cpp Mon Jan 25 14:57:27 2016 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 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 @@ -68,25 +68,17 @@ #include "runtime/vframe_hp.hpp" #include "utilities/copy.hpp" #include "utilities/preserveException.hpp" -#ifdef TARGET_ARCH_MODEL_x86_32 +#if defined AD_MD_HPP +# include AD_MD_HPP +#elif defined TARGET_ARCH_MODEL_x86_32 # include "adfiles/ad_x86_32.hpp" -#endif -#ifdef TARGET_ARCH_MODEL_x86_64 +#elif defined TARGET_ARCH_MODEL_x86_64 # include "adfiles/ad_x86_64.hpp" -#endif -#ifdef TARGET_ARCH_MODEL_sparc +#elif defined TARGET_ARCH_MODEL_sparc # include "adfiles/ad_sparc.hpp" -#endif -#ifdef TARGET_ARCH_MODEL_zero +#elif defined TARGET_ARCH_MODEL_zero # include "adfiles/ad_zero.hpp" -#endif -#ifdef TARGET_ARCH_MODEL_arm -# include "adfiles/ad_arm.hpp" -#endif -#ifdef TARGET_ARCH_MODEL_ppc_32 -# include "adfiles/ad_ppc_32.hpp" -#endif -#ifdef TARGET_ARCH_MODEL_ppc_64 +#elif defined TARGET_ARCH_MODEL_ppc_64 # include "adfiles/ad_ppc_64.hpp" #endif diff -r c2687aa5e5ca -r 7eb99acd567f src/share/vm/opto/stringopts.cpp --- a/src/share/vm/opto/stringopts.cpp Mon Jan 25 14:56:57 2016 -0800 +++ b/src/share/vm/opto/stringopts.cpp Mon Jan 25 14:57:27 2016 -0800 @@ -1507,10 +1507,12 @@ } case StringConcat::StringMode: { const Type* type = kit.gvn().type(arg); + Node* count = NULL; if (type == TypePtr::NULL_PTR) { // replace the argument with the null checked version arg = null_string; sc->set_argument(argi, arg); + count = kit.load_String_length(kit.control(), arg); } else if (!type->higher_equal(TypeInstPtr::NOTNULL)) { // s = s != null ? s : "null"; // length = length + (s.count - s.offset); @@ -1533,10 +1535,13 @@ // replace the argument with the null checked version arg = phi; sc->set_argument(argi, arg); + count = kit.load_String_length(kit.control(), arg); + } else { + // A corresponding nullcheck will be connected during IGVN MemNode::Ideal_common_DU_postCCP + // kit.control might be a different test, that can be hoisted above the actual nullcheck + // in case, that the control input is not null, Ideal_common_DU_postCCP will not look for a nullcheck. + count = kit.load_String_length(NULL, arg); } - - Node* count = kit.load_String_length(kit.control(), arg); - length = __ AddI(length, count); string_sizes->init_req(argi, NULL); break; diff -r c2687aa5e5ca -r 7eb99acd567f src/share/vm/opto/superword.cpp --- a/src/share/vm/opto/superword.cpp Mon Jan 25 14:56:57 2016 -0800 +++ b/src/share/vm/opto/superword.cpp Mon Jan 25 14:57:27 2016 -0800 @@ -232,6 +232,13 @@ // if unaligned memory access is not allowed because number of // iterations in pre-loop will be not enough to align it. create_pack = false; + } else { + SWPointer p2(best_align_to_mem_ref, this); + if (align_to_ref_p.invar() != p2.invar()) { + // Do not vectorize memory accesses with different invariants + // if unaligned memory accesses are not allowed. + create_pack = false; + } } } } else { @@ -445,29 +452,57 @@ int preloop_stride = pre_end->stride_con(); int span = preloop_stride * p.scale_in_bytes(); - - // Stride one accesses are alignable. - if (ABS(span) == p.memory_size()) + int mem_size = p.memory_size(); + int offset = p.offset_in_bytes(); + // Stride one accesses are alignable if offset is aligned to memory operation size. + // Offset can be unaligned when UseUnalignedAccesses is used. + if (ABS(span) == mem_size && (ABS(offset) % mem_size) == 0) { return true; - - // If initial offset from start of object is computable, - // compute alignment within the vector. + } + // If the initial offset from start of the object is computable, + // check if the pre-loop can align the final offset accordingly. + // + // In other words: Can we find an i such that the offset + // after i pre-loop iterations is aligned to vw? + // (init_offset + pre_loop) % vw == 0 (1) + // where + // pre_loop = i * span + // is the number of bytes added to the offset by i pre-loop iterations. + // + // For this to hold we need pre_loop to increase init_offset by + // pre_loop = vw - (init_offset % vw) + // + // This is only possible if pre_loop is divisible by span because each + // pre-loop iteration increases the initial offset by 'span' bytes: + // (vw - (init_offset % vw)) % span == 0 + // int vw = vector_width_in_bytes(p.mem()); assert(vw > 1, "sanity"); - if (vw % span == 0) { - Node* init_nd = pre_end->init_trip(); - if (init_nd->is_Con() && p.invar() == NULL) { - int init = init_nd->bottom_type()->is_int()->get_con(); - - int init_offset = init * p.scale_in_bytes() + p.offset_in_bytes(); - assert(init_offset >= 0, "positive offset from object start"); - + Node* init_nd = pre_end->init_trip(); + if (init_nd->is_Con() && p.invar() == NULL) { + int init = init_nd->bottom_type()->is_int()->get_con(); + int init_offset = init * p.scale_in_bytes() + offset; + assert(init_offset >= 0, "positive offset from object start"); + if (vw % span == 0) { + // If vm is a multiple of span, we use formula (1). if (span > 0) { return (vw - (init_offset % vw)) % span == 0; } else { assert(span < 0, "nonzero stride * scale"); return (init_offset % vw) % -span == 0; } + } else if (span % vw == 0) { + // If span is a multiple of vw, we can simplify formula (1) to: + // (init_offset + i * span) % vw == 0 + // => + // (init_offset % vw) + ((i * span) % vw) == 0 + // => + // init_offset % vw == 0 + // + // Because we add a multiple of vw to the initial offset, the final + // offset is a multiple of vw if and only if init_offset is a multiple. + // + return (init_offset % vw) == 0; } } return false; @@ -479,17 +514,23 @@ SWPointer align_to_ref_p(mem_ref, this); int offset = align_to_ref_p.offset_in_bytes(); int scale = align_to_ref_p.scale_in_bytes(); + int elt_size = align_to_ref_p.memory_size(); int vw = vector_width_in_bytes(mem_ref); assert(vw > 1, "sanity"); - int stride_sign = (scale * iv_stride()) > 0 ? 1 : -1; - // At least one iteration is executed in pre-loop by default. As result - // several iterations are needed to align memory operations in main-loop even - // if offset is 0. - int iv_adjustment_in_bytes = (stride_sign * vw - (offset % vw)); - int elt_size = align_to_ref_p.memory_size(); - assert(((ABS(iv_adjustment_in_bytes) % elt_size) == 0), - err_msg_res("(%d) should be divisible by (%d)", iv_adjustment_in_bytes, elt_size)); - int iv_adjustment = iv_adjustment_in_bytes/elt_size; + int iv_adjustment; + if (scale != 0) { + int stride_sign = (scale * iv_stride()) > 0 ? 1 : -1; + // At least one iteration is executed in pre-loop by default. As result + // several iterations are needed to align memory operations in main-loop even + // if offset is 0. + int iv_adjustment_in_bytes = (stride_sign * vw - (offset % vw)); + assert(((ABS(iv_adjustment_in_bytes) % elt_size) == 0), + err_msg_res("(%d) should be divisible by (%d)", iv_adjustment_in_bytes, elt_size)); + iv_adjustment = iv_adjustment_in_bytes/elt_size; + } else { + // This memory op is not dependent on iv (scale == 0) + iv_adjustment = 0; + } #ifndef PRODUCT if (TraceSuperWord) @@ -1390,7 +1431,7 @@ } Node* adr = low_adr->in(MemNode::Address); const TypePtr* atyp = n->adr_type(); - vn = LoadVectorNode::make(C, opc, ctl, mem, adr, atyp, vlen, velt_basic_type(n)); + vn = LoadVectorNode::make(C, opc, ctl, mem, adr, atyp, vlen, velt_basic_type(n), control_dependency(p)); vlen_in_bytes = vn->as_LoadVector()->memory_size(); } else if (n->is_Store()) { // Promote value to be stored to vector @@ -1988,6 +2029,19 @@ return n; } +LoadNode::ControlDependency SuperWord::control_dependency(Node_List* p) { + LoadNode::ControlDependency dep = LoadNode::DependsOnlyOnTest; + for (uint i = 0; i < p->size(); i++) { + Node* n = p->at(i); + assert(n->is_Load(), "only meaningful for loads"); + if (!n->depends_only_on_test()) { + dep = LoadNode::Pinned; + } + } + return dep; +} + + //----------------------------align_initial_loop_index--------------------------- // Adjust pre-loop limit so that in main loop, a load/store reference // to align_to_ref will be a position zero in the vector. @@ -2247,6 +2301,11 @@ } // Match AddP(base, AddP(ptr, k*iv [+ invariant]), constant) Node* base = adr->in(AddPNode::Base); + // The base address should be loop invariant + if (!invariant(base)) { + assert(!valid(), "base address is loop variant"); + return; + } //unsafe reference could not be aligned appropriately without runtime checking if (base == NULL || base->bottom_type() == Type::TOP) { assert(!valid(), "unsafe access"); diff -r c2687aa5e5ca -r 7eb99acd567f src/share/vm/opto/superword.hpp --- a/src/share/vm/opto/superword.hpp Mon Jan 25 14:56:57 2016 -0800 +++ b/src/share/vm/opto/superword.hpp Mon Jan 25 14:57:27 2016 -0800 @@ -41,7 +41,7 @@ // Exploiting SuperWord Level Parallelism with // Multimedia Instruction Sets // by -// Samuel Larsen and Saman Amarasighe +// Samuel Larsen and Saman Amarasinghe // MIT Laboratory for Computer Science // date // May 2000 @@ -424,6 +424,7 @@ Node* executed_first(Node_List* p); // Return the node executed last in pack p. Node* executed_last(Node_List* p); + static LoadNode::ControlDependency control_dependency(Node_List* p); // Alignment within a vector memory reference int memory_alignment(MemNode* s, int iv_adjust); // (Start, end] half-open range defining which operands are vector @@ -457,7 +458,7 @@ Node* _base; // NULL if unsafe nonheap reference Node* _adr; // address pointer - jint _scale; // multipler for iv (in bytes), 0 if no loop iv + jint _scale; // multiplier for iv (in bytes), 0 if no loop iv jint _offset; // constant offset (in bytes) Node* _invar; // invariant offset (in bytes), NULL if none bool _negate_invar; // if true then use: (0 - _invar) diff -r c2687aa5e5ca -r 7eb99acd567f src/share/vm/opto/type.cpp --- a/src/share/vm/opto/type.cpp Mon Jan 25 14:56:57 2016 -0800 +++ b/src/share/vm/opto/type.cpp Mon Jan 25 14:57:27 2016 -0800 @@ -3952,7 +3952,9 @@ (tap->_klass_is_exact && !tap->klass()->is_subtype_of(klass())) || // 'this' is exact and super or unrelated: (this->_klass_is_exact && !klass()->is_subtype_of(tap->klass())))) { - tary = TypeAry::make(Type::BOTTOM, tary->_size, tary->_stable); + if (above_centerline(ptr)) { + tary = TypeAry::make(Type::BOTTOM, tary->_size, tary->_stable); + } return make(NotNull, NULL, tary, lazy_klass, false, off, InstanceBot); } diff -r c2687aa5e5ca -r 7eb99acd567f src/share/vm/opto/vectornode.cpp --- a/src/share/vm/opto/vectornode.cpp Mon Jan 25 14:56:57 2016 -0800 +++ b/src/share/vm/opto/vectornode.cpp Mon Jan 25 14:57:27 2016 -0800 @@ -403,9 +403,10 @@ // Return the vector version of a scalar load node. LoadVectorNode* LoadVectorNode::make(Compile* C, int opc, Node* ctl, Node* mem, - Node* adr, const TypePtr* atyp, uint vlen, BasicType bt) { + Node* adr, const TypePtr* atyp, uint vlen, BasicType bt, + ControlDependency control_dependency) { const TypeVect* vt = TypeVect::make(bt, vlen); - return new (C) LoadVectorNode(ctl, mem, adr, atyp, vt); + return new (C) LoadVectorNode(ctl, mem, adr, atyp, vt, control_dependency); } // Return the vector version of a scalar store node. diff -r c2687aa5e5ca -r 7eb99acd567f src/share/vm/opto/vectornode.hpp --- a/src/share/vm/opto/vectornode.hpp Mon Jan 25 14:56:57 2016 -0800 +++ b/src/share/vm/opto/vectornode.hpp Mon Jan 25 14:57:27 2016 -0800 @@ -355,8 +355,8 @@ // Load Vector from memory class LoadVectorNode : public LoadNode { public: - LoadVectorNode(Node* c, Node* mem, Node* adr, const TypePtr* at, const TypeVect* vt) - : LoadNode(c, mem, adr, at, vt, MemNode::unordered) { + LoadVectorNode(Node* c, Node* mem, Node* adr, const TypePtr* at, const TypeVect* vt, ControlDependency control_dependency = LoadNode::DependsOnlyOnTest) + : LoadNode(c, mem, adr, at, vt, MemNode::unordered, control_dependency) { init_class_id(Class_LoadVector); } @@ -372,7 +372,8 @@ virtual int store_Opcode() const { return Op_StoreVector; } static LoadVectorNode* make(Compile* C, int opc, Node* ctl, Node* mem, - Node* adr, const TypePtr* atyp, uint vlen, BasicType bt); + Node* adr, const TypePtr* atyp, uint vlen, BasicType bt, + ControlDependency control_dependency = LoadNode::DependsOnlyOnTest); }; //------------------------------StoreVectorNode-------------------------------- diff -r c2687aa5e5ca -r 7eb99acd567f src/share/vm/prims/forte.cpp --- a/src/share/vm/prims/forte.cpp Mon Jan 25 14:56:57 2016 -0800 +++ b/src/share/vm/prims/forte.cpp Mon Jan 25 14:57:27 2016 -0800 @@ -172,8 +172,27 @@ // Now do we have a useful PcDesc? if (pc_desc == NULL || pc_desc->scope_decode_offset() == DebugInformationRecorder::serialized_null) { - // No debug information available for this pc - // vframeStream would explode if we try and walk the frames. + // No debug information is available for this PC. + // + // vframeStreamCommon::fill_from_frame() will decode the frame depending + // on the state of the thread. + // + // Case #1: If the thread is in Java (state == _thread_in_Java), then + // the vframeStreamCommon object will be filled as if the frame were a native + // compiled frame. Therefore, no debug information is needed. + // + // Case #2: If the thread is in any other state, then two steps will be performed: + // - if asserts are enabled, found_bad_method_frame() will be called and + // the assert in found_bad_method_frame() will be triggered; + // - if asserts are disabled, the vframeStreamCommon object will be filled + // as if it were a native compiled frame. + // + // Case (2) is similar to the way interpreter frames are processed in + // vframeStreamCommon::fill_from_interpreter_frame in case no valid BCI + // was found for an interpreted frame. If asserts are enabled, the assert + // in found_bad_method_frame() will be triggered. If asserts are disabled, + // the vframeStreamCommon object will be filled afterwards as if the + // interpreter were at the point of entering into the method. return false; } @@ -230,9 +249,10 @@ // a valid method. Then again we may have caught an interpreter // frame in the middle of construction and the bci field is // not yet valid. - - *method_p = method; if (!method->is_valid_method()) return false; + *method_p = method; // If the Method* found is invalid, it is + // ignored by forte_fill_call_trace_given_top(). + // So set method_p only if the Method is valid. intptr_t bcx = fr->interpreter_frame_bcx(); @@ -247,18 +267,33 @@ } -// Determine if 'fr' can be used to find an initial Java frame. -// Return false if it can not find a fully decipherable Java frame -// (in other words a frame that isn't safe to use in a vframe stream). -// Obviously if it can't even find a Java frame false will also be returned. +// Determine if a Java frame can be found starting with the frame 'fr'. +// +// Check the return value of find_initial_Java_frame and the value of +// 'method_p' to decide on how use the results returned by this method. +// +// If 'method_p' is not NULL, an initial Java frame has been found and +// the stack can be walked starting from that initial frame. In this case, +// 'method_p' points to the Method that the initial frame belongs to and +// the initial Java frame is returned in initial_frame_p. +// +// find_initial_Java_frame() returns true if a Method has been found (i.e., +// 'method_p' is not NULL) and the initial frame that belongs to that Method +// is decipherable. // -// If we find a Java frame decipherable or not then by definition we have -// identified a method and that will be returned to the caller via method_p. -// If we can determine a bci that is returned also. (Hmm is it possible -// to return a method and bci and still return false? ) +// A frame is considered to be decipherable: +// +// - if the frame is a compiled frame and a PCDesc is available; +// +// - if the frame is an interpreter frame that is valid or the thread is +// state (_thread_in_native || state == _thread_in_vm || state == _thread_blocked). // -// The initial Java frame we find (if any) is return via initial_frame_p. +// Note that find_initial_Java_frame() can return false even if an initial +// Java method was found (e.g., there is no PCDesc available for the method). // +// If 'method_p' is NULL, it was not possible to find a Java frame when +// walking the stack starting from 'fr'. In this case find_initial_Java_frame +// returns false. static bool find_initial_Java_frame(JavaThread* thread, frame* fr, @@ -278,8 +313,6 @@ // recognizable to us. This should only happen if we are in a JRT_LEAF // or something called by a JRT_LEAF method. - - frame candidate = *fr; // If the starting frame we were given has no codeBlob associated with @@ -334,9 +367,11 @@ nmethod* nm = (nmethod*) candidate.cb(); *method_p = nm->method(); - // If the frame isn't fully decipherable then the default - // value for the bci is a signal that we don't have a bci. - // If we have a decipherable frame this bci value will + // If the frame is not decipherable, then the value of -1 + // for the BCI is used to signal that no BCI is available. + // Furthermore, the method returns false in this case. + // + // If a decipherable frame is available, the BCI value will // not be used. *bci_p = -1; @@ -347,9 +382,9 @@ if (nm->is_native_method()) return true; - // If it isn't decipherable then we have found a pc that doesn't - // have a PCDesc that can get us a bci however we did find - // a method + // If the frame is not decipherable, then a PC was found + // that does not have a PCDesc from which a BCI can be obtained. + // Nevertheless, a Method was found. if (!is_decipherable_compiled_frame(thread, &candidate, nm)) { return false; @@ -358,7 +393,7 @@ // is_decipherable_compiled_frame may modify candidate's pc *initial_frame_p = candidate; - assert(nm->pc_desc_at(candidate.pc()) != NULL, "if it's decipherable then pc must be valid"); + assert(nm->pc_desc_at(candidate.pc()) != NULL, "debug information must be available if the frame is decipherable"); return true; } @@ -388,17 +423,17 @@ frame initial_Java_frame; Method* method; - int bci; + int bci = -1; // assume BCI is not available for method + // update with correct information if available int count; count = 0; assert(trace->frames != NULL, "trace->frames must be non-NULL"); - bool fully_decipherable = find_initial_Java_frame(thd, &top_frame, &initial_Java_frame, &method, &bci); + // Walk the stack starting from 'top_frame' and search for an initial Java frame. + find_initial_Java_frame(thd, &top_frame, &initial_Java_frame, &method, &bci); - // The frame might not be walkable but still recovered a method - // (e.g. an nmethod with no scope info for the pc) - + // Check if a Java Method has been found. if (method == NULL) return; if (!method->is_valid_method()) { @@ -406,29 +441,6 @@ return; } - // We got a Java frame however it isn't fully decipherable - // so it won't necessarily be safe to use it for the - // initial frame in the vframe stream. - - if (!fully_decipherable) { - // Take whatever method the top-frame decoder managed to scrape up. - // We look further at the top frame only if non-safepoint - // debugging information is available. - count++; - trace->num_frames = count; - trace->frames[0].method_id = method->find_jmethod_id_or_null(); - if (!method->is_native()) { - trace->frames[0].lineno = bci; - } else { - trace->frames[0].lineno = -3; - } - - if (!initial_Java_frame.safe_for_sender(thd)) return; - - RegisterMap map(thd, false); - initial_Java_frame = initial_Java_frame.sender(&map); - } - vframeStreamForte st(thd, initial_Java_frame, false); for (; !st.at_end() && count < depth; st.forte_next(), count++) { diff -r c2687aa5e5ca -r 7eb99acd567f src/share/vm/prims/jni.cpp --- a/src/share/vm/prims/jni.cpp Mon Jan 25 14:56:57 2016 -0800 +++ b/src/share/vm/prims/jni.cpp Mon Jan 25 14:57:27 2016 -0800 @@ -1329,39 +1329,32 @@ Method* m = Method::resolve_jmethod_id(method_id); number_of_parameters = m->size_of_parameters(); Klass* holder = m->method_holder(); - if (!(holder)->is_interface()) { + if (call_type != JNI_VIRTUAL) { + selected_method = m; + } else if (!m->has_itable_index()) { // non-interface call -- for that little speed boost, don't handlize debug_only(No_Safepoint_Verifier nosafepoint;) - if (call_type == JNI_VIRTUAL) { - // jni_GetMethodID makes sure class is linked and initialized - // so m should have a valid vtable index. - assert(!m->has_itable_index(), ""); - int vtbl_index = m->vtable_index(); - if (vtbl_index != Method::nonvirtual_vtable_index) { - Klass* k = h_recv->klass(); - // k might be an arrayKlassOop but all vtables start at - // the same place. The cast is to avoid virtual call and assertion. - InstanceKlass *ik = (InstanceKlass*)k; - selected_method = ik->method_at_vtable(vtbl_index); - } else { - // final method - selected_method = m; - } + // jni_GetMethodID makes sure class is linked and initialized + // so m should have a valid vtable index. + assert(m->valid_vtable_index(), "no valid vtable index"); + int vtbl_index = m->vtable_index(); + if (vtbl_index != Method::nonvirtual_vtable_index) { + Klass* k = h_recv->klass(); + // k might be an arrayKlassOop but all vtables start at + // the same place. The cast is to avoid virtual call and assertion. + InstanceKlass *ik = (InstanceKlass*)k; + selected_method = ik->method_at_vtable(vtbl_index); } else { - // JNI_NONVIRTUAL call + // final method selected_method = m; } } else { // interface call KlassHandle h_holder(THREAD, holder); - if (call_type == JNI_VIRTUAL) { - int itbl_index = m->itable_index(); - Klass* k = h_recv->klass(); - selected_method = InstanceKlass::cast(k)->method_at_itable(h_holder(), itbl_index, CHECK); - } else { - selected_method = m; - } + int itbl_index = m->itable_index(); + Klass* k = h_recv->klass(); + selected_method = InstanceKlass::cast(k)->method_at_itable(h_holder(), itbl_index, CHECK); } } @@ -5075,6 +5068,7 @@ unit_test_function_call // Forward declaration +void TestOS_test(); void TestReservedSpace_test(); void TestReserveMemorySpecial_test(); void TestVirtualSpace_test(); @@ -5096,6 +5090,7 @@ void execute_internal_vm_tests() { if (ExecuteInternalVMTests) { tty->print_cr("Running internal VM tests"); + run_unit_test(TestOS_test()); run_unit_test(TestReservedSpace_test()); run_unit_test(TestReserveMemorySpecial_test()); run_unit_test(TestVirtualSpace_test()); diff -r c2687aa5e5ca -r 7eb99acd567f src/share/vm/prims/jniCheck.cpp --- a/src/share/vm/prims/jniCheck.cpp Mon Jan 25 14:56:57 2016 -0800 +++ b/src/share/vm/prims/jniCheck.cpp Mon Jan 25 14:57:27 2016 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 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 @@ -53,6 +53,8 @@ # include "jniTypes_ppc.hpp" #endif +// Complain every extra number of unplanned local refs +#define CHECK_JNI_LOCAL_REF_CAP_WARN_THRESHOLD 32 // Heap objects are allowed to be directly referenced only in VM code, // not in native code. @@ -168,12 +170,55 @@ * SUPPORT FUNCTIONS */ +/** + * Check whether or not a programmer has actually checked for exceptions. According + * to the JNI Specification ("jni/spec/design.html#java_exceptions"): + * + * There are two cases where the programmer needs to check for exceptions without + * being able to first check an error code: + * + * - The JNI functions that invoke a Java method return the result of the Java method. + * The programmer must call ExceptionOccurred() to check for possible exceptions + * that occurred during the execution of the Java method. + * + * - Some of the JNI array access functions do not return an error code, but may + * throw an ArrayIndexOutOfBoundsException or ArrayStoreException. + * + * In all other cases, a non-error return value guarantees that no exceptions have been thrown. + * + * Programmers often defend against ArrayIndexOutOfBoundsException, so warning + * for these functions would be pedantic. + */ +static inline void +check_pending_exception(JavaThread* thr) { + if (thr->has_pending_exception()) { + NativeReportJNIWarning(thr, "JNI call made with exception pending"); + } + if (thr->is_pending_jni_exception_check()) { + IN_VM( + tty->print_cr("WARNING in native method: JNI call made without checking exceptions when required to from %s", + thr->get_pending_jni_exception_check()); + thr->print_stack(); + ) + thr->clear_pending_jni_exception_check(); // Just complain once + } +} + +/** + * Add to the planned number of handles. I.e. plus current live & warning threshold + */ +static inline void +add_planned_handle_capacity(JNIHandleBlock* handles, size_t capacity) { + handles->set_planned_capacity(capacity + + handles->get_number_of_live_handles() + + CHECK_JNI_LOCAL_REF_CAP_WARN_THRESHOLD); +} + + static inline void functionEnterCritical(JavaThread* thr) { - if (thr->has_pending_exception()) { - NativeReportJNIWarning(thr, "JNI call made with exception pending"); - } + check_pending_exception(thr); } static inline void @@ -187,9 +232,7 @@ if (thr->in_critical()) { tty->print_cr("%s", warn_other_function_in_critical); } - if (thr->has_pending_exception()) { - NativeReportJNIWarning(thr, "JNI call made with exception pending"); - } + check_pending_exception(thr); } static inline void @@ -201,9 +244,20 @@ } static inline void -functionExit(JNIEnv *env) +functionExit(JavaThread* thr) { - /* nothing to do at this time */ + JNIHandleBlock* handles = thr->active_handles(); + size_t planned_capacity = handles->get_planned_capacity(); + size_t live_handles = handles->get_number_of_live_handles(); + if (live_handles > planned_capacity) { + IN_VM( + tty->print_cr("WARNING: JNI local refs: %zu, exceeds capacity: %zu", + live_handles, planned_capacity); + thr->print_stack(); + ) + // Complain just the once, reset to current + warn threshold + add_planned_handle_capacity(handles, 0); + } } static inline void @@ -508,7 +562,7 @@ jniCheck::validate_object(thr, loader); ) jclass result = UNCHECKED()->DefineClass(env, name, loader, buf, len); - functionExit(env); + functionExit(thr); return result; JNI_END @@ -520,7 +574,7 @@ jniCheck::validate_class_descriptor(thr, name); ) jclass result = UNCHECKED()->FindClass(env, name); - functionExit(env); + functionExit(thr); return result; JNI_END @@ -532,7 +586,7 @@ jniCheck::validate_object(thr, method); ) jmethodID result = UNCHECKED()->FromReflectedMethod(env, method); - functionExit(env); + functionExit(thr); return result; JNI_END @@ -544,7 +598,7 @@ jniCheck::validate_object(thr, field); ) jfieldID result = UNCHECKED()->FromReflectedField(env, field); - functionExit(env); + functionExit(thr); return result; JNI_END @@ -560,7 +614,7 @@ ) jobject result = UNCHECKED()->ToReflectedMethod(env, cls, methodID, isStatic); - functionExit(env); + functionExit(thr); return result; JNI_END @@ -572,7 +626,7 @@ jniCheck::validate_class(thr, sub, true); ) jclass result = UNCHECKED()->GetSuperclass(env, sub); - functionExit(env); + functionExit(thr); return result; JNI_END @@ -586,7 +640,7 @@ jniCheck::validate_class(thr, sup, true); ) jboolean result = UNCHECKED()->IsAssignableFrom(env, sub, sup); - functionExit(env); + functionExit(thr); return result; JNI_END @@ -601,7 +655,7 @@ ) jobject result = UNCHECKED()->ToReflectedField(env, cls, fieldID, isStatic); - functionExit(env); + functionExit(thr); return result; JNI_END @@ -619,7 +673,7 @@ } ) jint result = UNCHECKED()->Throw(env, obj); - functionExit(env); + functionExit(thr); return result; JNI_END @@ -634,15 +688,16 @@ jniCheck::validate_throwable_klass(thr, k); ) jint result = UNCHECKED()->ThrowNew(env, clazz, msg); - functionExit(env); + functionExit(thr); return result; JNI_END JNI_ENTRY_CHECKED(jthrowable, checked_jni_ExceptionOccurred(JNIEnv *env)) + thr->clear_pending_jni_exception_check(); functionEnterExceptionAllowed(thr); jthrowable result = UNCHECKED()->ExceptionOccurred(env); - functionExit(env); + functionExit(thr); return result; JNI_END @@ -650,22 +705,24 @@ checked_jni_ExceptionDescribe(JNIEnv *env)) functionEnterExceptionAllowed(thr); UNCHECKED()->ExceptionDescribe(env); - functionExit(env); + functionExit(thr); JNI_END JNI_ENTRY_CHECKED(void, checked_jni_ExceptionClear(JNIEnv *env)) + thr->clear_pending_jni_exception_check(); functionEnterExceptionAllowed(thr); UNCHECKED()->ExceptionClear(env); - functionExit(env); + functionExit(thr); JNI_END JNI_ENTRY_CHECKED(void, checked_jni_FatalError(JNIEnv *env, const char *msg)) + thr->clear_pending_jni_exception_check(); functionEnter(thr); UNCHECKED()->FatalError(env, msg); - functionExit(env); + functionExit(thr); JNI_END JNI_ENTRY_CHECKED(jint, @@ -675,7 +732,10 @@ if (capacity < 0) NativeReportJNIFatalError(thr, "negative capacity"); jint result = UNCHECKED()->PushLocalFrame(env, capacity); - functionExit(env); + if (result == JNI_OK) { + add_planned_handle_capacity(thr->active_handles(), capacity); + } + functionExit(thr); return result; JNI_END @@ -684,7 +744,7 @@ jobject result)) functionEnterExceptionAllowed(thr); jobject res = UNCHECKED()->PopLocalFrame(env, result); - functionExit(env); + functionExit(thr); return res; JNI_END @@ -698,7 +758,7 @@ } ) jobject result = UNCHECKED()->NewGlobalRef(env,lobj); - functionExit(env); + functionExit(thr); return result; JNI_END @@ -714,7 +774,7 @@ } ) UNCHECKED()->DeleteGlobalRef(env,gref); - functionExit(env); + functionExit(thr); JNI_END JNI_ENTRY_CHECKED(void, @@ -729,7 +789,7 @@ "Invalid local JNI handle passed to DeleteLocalRef"); ) UNCHECKED()->DeleteLocalRef(env, obj); - functionExit(env); + functionExit(thr); JNI_END JNI_ENTRY_CHECKED(jboolean, @@ -750,7 +810,7 @@ } ) jboolean result = UNCHECKED()->IsSameObject(env,obj1,obj2); - functionExit(env); + functionExit(thr); return result; JNI_END @@ -764,7 +824,7 @@ } ) jobject result = UNCHECKED()->NewLocalRef(env, ref); - functionExit(env); + functionExit(thr); return result; JNI_END @@ -776,7 +836,10 @@ NativeReportJNIFatalError(thr, "negative capacity"); } jint result = UNCHECKED()->EnsureLocalCapacity(env, capacity); - functionExit(env); + if (result == JNI_OK) { + add_planned_handle_capacity(thr->active_handles(), capacity); + } + functionExit(thr); return result; JNI_END @@ -788,7 +851,7 @@ jniCheck::validate_class(thr, clazz, false); ) jobject result = UNCHECKED()->AllocObject(env,clazz); - functionExit(env); + functionExit(thr); return result; JNI_END @@ -806,7 +869,7 @@ va_start(args, methodID); jobject result = UNCHECKED()->NewObjectV(env,clazz,methodID,args); va_end(args); - functionExit(env); + functionExit(thr); return result; JNI_END @@ -821,7 +884,7 @@ jniCheck::validate_jmethod_id(thr, methodID); ) jobject result = UNCHECKED()->NewObjectV(env,clazz,methodID,args); - functionExit(env); + functionExit(thr); return result; JNI_END @@ -836,7 +899,7 @@ jniCheck::validate_jmethod_id(thr, methodID); ) jobject result = UNCHECKED()->NewObjectA(env,clazz,methodID,args); - functionExit(env); + functionExit(thr); return result; JNI_END @@ -848,7 +911,7 @@ jniCheck::validate_object(thr, obj); ) jclass result = UNCHECKED()->GetObjectClass(env,obj); - functionExit(env); + functionExit(thr); return result; JNI_END @@ -862,7 +925,7 @@ jniCheck::validate_class(thr, clazz, true); ) jboolean result = UNCHECKED()->IsInstanceOf(env,obj,clazz); - functionExit(env); + functionExit(thr); return result; JNI_END @@ -876,7 +939,7 @@ jniCheck::validate_class(thr, clazz, false); ) jmethodID result = UNCHECKED()->GetMethodID(env,clazz,name,sig); - functionExit(env); + functionExit(thr); return result; JNI_END @@ -895,7 +958,8 @@ ResultType result =UNCHECKED()->Call##Result##MethodV(env, obj, methodID, \ args); \ va_end(args); \ - functionExit(env); \ + thr->set_pending_jni_exception_check("Call"#Result"Method"); \ + functionExit(thr); \ return result; \ JNI_END \ \ @@ -910,7 +974,8 @@ ) \ ResultType result = UNCHECKED()->Call##Result##MethodV(env, obj, methodID,\ args); \ - functionExit(env); \ + thr->set_pending_jni_exception_check("Call"#Result"MethodV"); \ + functionExit(thr); \ return result; \ JNI_END \ \ @@ -925,7 +990,8 @@ ) \ ResultType result = UNCHECKED()->Call##Result##MethodA(env, obj, methodID,\ args); \ - functionExit(env); \ + thr->set_pending_jni_exception_check("Call"#Result"MethodA"); \ + functionExit(thr); \ return result; \ JNI_END @@ -952,7 +1018,8 @@ va_start(args,methodID); UNCHECKED()->CallVoidMethodV(env,obj,methodID,args); va_end(args); - functionExit(env); + thr->set_pending_jni_exception_check("CallVoidMethod"); + functionExit(thr); JNI_END JNI_ENTRY_CHECKED(void, @@ -965,7 +1032,8 @@ jniCheck::validate_call_object(thr, obj, methodID); ) UNCHECKED()->CallVoidMethodV(env,obj,methodID,args); - functionExit(env); + thr->set_pending_jni_exception_check("CallVoidMethodV"); + functionExit(thr); JNI_END JNI_ENTRY_CHECKED(void, @@ -978,7 +1046,8 @@ jniCheck::validate_call_object(thr, obj, methodID); ) UNCHECKED()->CallVoidMethodA(env,obj,methodID,args); - functionExit(env); + thr->set_pending_jni_exception_check("CallVoidMethodA"); + functionExit(thr); JNI_END #define WRAPPER_CallNonvirtualMethod(ResultType, Result) \ @@ -1001,7 +1070,8 @@ methodID,\ args); \ va_end(args); \ - functionExit(env); \ + thr->set_pending_jni_exception_check("CallNonvirtual"#Result"Method"); \ + functionExit(thr); \ return result; \ JNI_END \ \ @@ -1021,7 +1091,8 @@ clazz, \ methodID,\ args); \ - functionExit(env); \ + thr->set_pending_jni_exception_check("CallNonvirtual"#Result"MethodV"); \ + functionExit(thr); \ return result; \ JNI_END \ \ @@ -1041,7 +1112,8 @@ clazz, \ methodID,\ args); \ - functionExit(env); \ + thr->set_pending_jni_exception_check("CallNonvirtual"#Result"MethodA"); \ + functionExit(thr); \ return result; \ JNI_END @@ -1070,7 +1142,8 @@ va_start(args,methodID); UNCHECKED()->CallNonvirtualVoidMethodV(env,obj,clazz,methodID,args); va_end(args); - functionExit(env); + thr->set_pending_jni_exception_check("CallNonvirtualVoidMethod"); + functionExit(thr); JNI_END JNI_ENTRY_CHECKED(void, @@ -1085,7 +1158,8 @@ jniCheck::validate_call_class(thr, clazz, methodID); ) UNCHECKED()->CallNonvirtualVoidMethodV(env,obj,clazz,methodID,args); - functionExit(env); + thr->set_pending_jni_exception_check("CallNonvirtualVoidMethodV"); + functionExit(thr); JNI_END JNI_ENTRY_CHECKED(void, @@ -1100,7 +1174,8 @@ jniCheck::validate_call_class(thr, clazz, methodID); ) UNCHECKED()->CallNonvirtualVoidMethodA(env,obj,clazz,methodID,args); - functionExit(env); + thr->set_pending_jni_exception_check("CallNonvirtualVoidMethodA"); + functionExit(thr); JNI_END JNI_ENTRY_CHECKED(jfieldID, @@ -1113,7 +1188,7 @@ jniCheck::validate_class(thr, clazz, false); ) jfieldID result = UNCHECKED()->GetFieldID(env,clazz,name,sig); - functionExit(env); + functionExit(thr); return result; JNI_END @@ -1127,7 +1202,7 @@ checkInstanceFieldID(thr, fieldID, obj, FieldType); \ ) \ ReturnType result = UNCHECKED()->Get##Result##Field(env,obj,fieldID); \ - functionExit(env); \ + functionExit(thr); \ return result; \ JNI_END @@ -1152,7 +1227,7 @@ checkInstanceFieldID(thr, fieldID, obj, FieldType); \ ) \ UNCHECKED()->Set##Result##Field(env,obj,fieldID,val); \ - functionExit(env); \ + functionExit(thr); \ JNI_END WRAPPER_SetField(jobject, Object, T_OBJECT) @@ -1176,7 +1251,7 @@ jniCheck::validate_class(thr, clazz, false); ) jmethodID result = UNCHECKED()->GetStaticMethodID(env,clazz,name,sig); - functionExit(env); + functionExit(thr); return result; JNI_END @@ -1198,7 +1273,8 @@ methodID, \ args); \ va_end(args); \ - functionExit(env); \ + thr->set_pending_jni_exception_check("CallStatic"#Result"Method"); \ + functionExit(thr); \ return result; \ JNI_END \ \ @@ -1216,7 +1292,8 @@ clazz, \ methodID, \ args); \ - functionExit(env); \ + thr->set_pending_jni_exception_check("CallStatic"#Result"MethodV"); \ + functionExit(thr); \ return result; \ JNI_END \ \ @@ -1234,7 +1311,8 @@ clazz, \ methodID, \ args); \ - functionExit(env); \ + thr->set_pending_jni_exception_check("CallStatic"#Result"MethodA"); \ + functionExit(thr); \ return result; \ JNI_END @@ -1262,7 +1340,8 @@ va_start(args,methodID); UNCHECKED()->CallStaticVoidMethodV(env,cls,methodID,args); va_end(args); - functionExit(env); + thr->set_pending_jni_exception_check("CallStaticVoidMethod"); + functionExit(thr); JNI_END JNI_ENTRY_CHECKED(void, @@ -1276,7 +1355,8 @@ jniCheck::validate_class(thr, cls, false); ) UNCHECKED()->CallStaticVoidMethodV(env,cls,methodID,args); - functionExit(env); + thr->set_pending_jni_exception_check("CallStaticVoidMethodV"); + functionExit(thr); JNI_END JNI_ENTRY_CHECKED(void, @@ -1290,7 +1370,8 @@ jniCheck::validate_class(thr, cls, false); ) UNCHECKED()->CallStaticVoidMethodA(env,cls,methodID,args); - functionExit(env); + thr->set_pending_jni_exception_check("CallStaticVoidMethodA"); + functionExit(thr); JNI_END JNI_ENTRY_CHECKED(jfieldID, @@ -1303,7 +1384,7 @@ jniCheck::validate_class(thr, clazz, false); ) jfieldID result = UNCHECKED()->GetStaticFieldID(env,clazz,name,sig); - functionExit(env); + functionExit(thr); return result; JNI_END @@ -1320,7 +1401,7 @@ ReturnType result = UNCHECKED()->GetStatic##Result##Field(env, \ clazz, \ fieldID); \ - functionExit(env); \ + functionExit(thr); \ return result; \ JNI_END @@ -1346,7 +1427,7 @@ checkStaticFieldID(thr, fieldID, clazz, FieldType); \ ) \ UNCHECKED()->SetStatic##Result##Field(env,clazz,fieldID,value); \ - functionExit(env); \ + functionExit(thr); \ JNI_END WRAPPER_SetStaticField(jobject, Object, T_OBJECT) @@ -1366,7 +1447,7 @@ jsize len)) functionEnter(thr); jstring result = UNCHECKED()->NewString(env,unicode,len); - functionExit(env); + functionExit(thr); return result; JNI_END @@ -1378,7 +1459,7 @@ checkString(thr, str); ) jsize result = UNCHECKED()->GetStringLength(env,str); - functionExit(env); + functionExit(thr); return result; JNI_END @@ -1407,7 +1488,7 @@ // Note that the dtrace arguments for the allocated memory will not match up with this solution. FreeHeap((char*)result); } - functionExit(env); + functionExit(thr); return new_result; JNI_END @@ -1442,7 +1523,7 @@ UNCHECKED()->ReleaseStringChars(env, str, (const jchar*) guarded.release_for_freeing()); } - functionExit(env); + functionExit(thr); JNI_END JNI_ENTRY_CHECKED(jstring, @@ -1450,7 +1531,7 @@ const char *utf)) functionEnter(thr); jstring result = UNCHECKED()->NewStringUTF(env,utf); - functionExit(env); + functionExit(thr); return result; JNI_END @@ -1462,7 +1543,7 @@ checkString(thr, str); ) jsize result = UNCHECKED()->GetStringUTFLength(env,str); - functionExit(env); + functionExit(thr); return result; JNI_END @@ -1490,7 +1571,7 @@ // Note that the dtrace arguments for the allocated memory will not match up with this solution. FreeHeap((char*)result, mtInternal); } - functionExit(env); + functionExit(thr); return new_result; JNI_END @@ -1525,7 +1606,7 @@ UNCHECKED()->ReleaseStringUTFChars(env, str, (const char*) guarded.release_for_freeing()); } - functionExit(env); + functionExit(thr); JNI_END JNI_ENTRY_CHECKED(jsize, @@ -1536,7 +1617,7 @@ check_is_array(thr, array); ) jsize result = UNCHECKED()->GetArrayLength(env,array); - functionExit(env); + functionExit(thr); return result; JNI_END @@ -1547,7 +1628,7 @@ jobject init)) functionEnter(thr); jobjectArray result = UNCHECKED()->NewObjectArray(env,len,clazz,init); - functionExit(env); + functionExit(thr); return result; JNI_END @@ -1560,7 +1641,7 @@ check_is_obj_array(thr, array); ) jobject result = UNCHECKED()->GetObjectArrayElement(env,array,index); - functionExit(env); + functionExit(thr); return result; JNI_END @@ -1574,7 +1655,7 @@ check_is_obj_array(thr, array); ) UNCHECKED()->SetObjectArrayElement(env,array,index,val); - functionExit(env); + functionExit(thr); JNI_END #define WRAPPER_NewScalarArray(Return, Result) \ @@ -1583,7 +1664,7 @@ jsize len)) \ functionEnter(thr); \ Return result = UNCHECKED()->New##Result##Array(env,len); \ - functionExit(env); \ + functionExit(thr); \ return (Return) result; \ JNI_END @@ -1611,7 +1692,7 @@ if (result != NULL) { \ result = (ElementType *) check_jni_wrap_copy_array(thr, array, result); \ } \ - functionExit(env); \ + functionExit(thr); \ return result; \ JNI_END @@ -1639,7 +1720,7 @@ ElementType* orig_result = (ElementType *) check_wrapped_array_release( \ thr, "checked_jni_Release"#Result"ArrayElements", array, elems, mode); \ UNCHECKED()->Release##Result##ArrayElements(env, array, orig_result, mode); \ - functionExit(env); \ + functionExit(thr); \ JNI_END WRAPPER_ReleaseScalarArrayElements(T_BOOLEAN,jboolean, Boolean, bool) @@ -1663,7 +1744,7 @@ check_primitive_array_type(thr, array, ElementTag); \ ) \ UNCHECKED()->Get##Result##ArrayRegion(env,array,start,len,buf); \ - functionExit(env); \ + functionExit(thr); \ JNI_END WRAPPER_GetScalarArrayRegion(T_BOOLEAN, jboolean, Boolean) @@ -1687,7 +1768,7 @@ check_primitive_array_type(thr, array, ElementTag); \ ) \ UNCHECKED()->Set##Result##ArrayRegion(env,array,start,len,buf); \ - functionExit(env); \ + functionExit(thr); \ JNI_END WRAPPER_SetScalarArrayRegion(T_BOOLEAN, jboolean, Boolean) @@ -1706,7 +1787,7 @@ jint nMethods)) functionEnter(thr); jint result = UNCHECKED()->RegisterNatives(env,clazz,methods,nMethods); - functionExit(env); + functionExit(thr); return result; JNI_END @@ -1715,7 +1796,7 @@ jclass clazz)) functionEnter(thr); jint result = UNCHECKED()->UnregisterNatives(env,clazz); - functionExit(env); + functionExit(thr); return result; JNI_END @@ -1727,7 +1808,7 @@ jniCheck::validate_object(thr, obj); ) jint result = UNCHECKED()->MonitorEnter(env,obj); - functionExit(env); + functionExit(thr); return result; JNI_END @@ -1739,7 +1820,7 @@ jniCheck::validate_object(thr, obj); ) jint result = UNCHECKED()->MonitorExit(env,obj); - functionExit(env); + functionExit(thr); return result; JNI_END @@ -1748,7 +1829,7 @@ JavaVM **vm)) functionEnter(thr); jint result = UNCHECKED()->GetJavaVM(env,vm); - functionExit(env); + functionExit(thr); return result; JNI_END @@ -1763,7 +1844,7 @@ checkString(thr, str); ) UNCHECKED()->GetStringRegion(env, str, start, len, buf); - functionExit(env); + functionExit(thr); JNI_END JNI_ENTRY_CHECKED(void, @@ -1777,7 +1858,7 @@ checkString(thr, str); ) UNCHECKED()->GetStringUTFRegion(env, str, start, len, buf); - functionExit(env); + functionExit(thr); JNI_END JNI_ENTRY_CHECKED(void *, @@ -1792,7 +1873,7 @@ if (result != NULL) { result = check_jni_wrap_copy_array(thr, array, result); } - functionExit(env); + functionExit(thr); return result; JNI_END @@ -1808,7 +1889,7 @@ // Check the element array... void* orig_result = check_wrapped_array_release(thr, "ReleasePrimitiveArrayCritical", array, carray, mode); UNCHECKED()->ReleasePrimitiveArrayCritical(env, array, orig_result, mode); - functionExit(env); + functionExit(thr); JNI_END JNI_ENTRY_CHECKED(const jchar*, @@ -1820,7 +1901,7 @@ checkString(thr, string); ) const jchar *result = UNCHECKED()->GetStringCritical(env, string, isCopy); - functionExit(env); + functionExit(thr); return result; JNI_END @@ -1836,7 +1917,7 @@ * string parameter as a minor sanity check */ UNCHECKED()->ReleaseStringCritical(env, str, chars); - functionExit(env); + functionExit(thr); JNI_END JNI_ENTRY_CHECKED(jweak, @@ -1849,7 +1930,7 @@ } ) jweak result = UNCHECKED()->NewWeakGlobalRef(env, obj); - functionExit(env); + functionExit(thr); return result; JNI_END @@ -1858,14 +1939,15 @@ jweak ref)) functionEnterExceptionAllowed(thr); UNCHECKED()->DeleteWeakGlobalRef(env, ref); - functionExit(env); + functionExit(thr); JNI_END JNI_ENTRY_CHECKED(jboolean, checked_jni_ExceptionCheck(JNIEnv *env)) + thr->clear_pending_jni_exception_check(); functionEnterExceptionAllowed(thr); jboolean result = UNCHECKED()->ExceptionCheck(env); - functionExit(env); + functionExit(thr); return result; JNI_END @@ -1875,7 +1957,7 @@ jlong capacity)) functionEnter(thr); jobject result = UNCHECKED()->NewDirectByteBuffer(env, address, capacity); - functionExit(env); + functionExit(thr); return result; JNI_END @@ -1884,7 +1966,7 @@ jobject buf)) functionEnter(thr); void* result = UNCHECKED()->GetDirectBufferAddress(env, buf); - functionExit(env); + functionExit(thr); return result; JNI_END @@ -1893,7 +1975,7 @@ jobject buf)) functionEnter(thr); jlong result = UNCHECKED()->GetDirectBufferCapacity(env, buf); - functionExit(env); + functionExit(thr); return result; JNI_END @@ -1906,7 +1988,7 @@ jniCheck::validate_object(thr, obj); ) jobjectRefType result = UNCHECKED()->GetObjectRefType(env, obj); - functionExit(env); + functionExit(thr); return result; JNI_END @@ -1915,7 +1997,7 @@ checked_jni_GetVersion(JNIEnv *env)) functionEnter(thr); jint result = UNCHECKED()->GetVersion(env); - functionExit(env); + functionExit(thr); return result; JNI_END diff -r c2687aa5e5ca -r 7eb99acd567f src/share/vm/prims/jvm.cpp --- a/src/share/vm/prims/jvm.cpp Mon Jan 25 14:56:57 2016 -0800 +++ b/src/share/vm/prims/jvm.cpp Mon Jan 25 14:57:27 2016 -0800 @@ -1374,7 +1374,11 @@ if (HAS_PENDING_EXCEPTION) { pending_exception = Handle(THREAD, PENDING_EXCEPTION); CLEAR_PENDING_EXCEPTION; - + // JVMTI has already reported the pending exception + // JVMTI internal flag reset is needed in order to report PrivilegedActionException + if (THREAD->is_Java_thread()) { + JvmtiExport::clear_detected_exception((JavaThread*) THREAD); + } if ( pending_exception->is_a(SystemDictionary::Exception_klass()) && !pending_exception->is_a(SystemDictionary::RuntimeException_klass())) { // Throw a java.security.PrivilegedActionException(Exception e) exception diff -r c2687aa5e5ca -r 7eb99acd567f src/share/vm/prims/jvmtiClassFileReconstituter.hpp --- a/src/share/vm/prims/jvmtiClassFileReconstituter.hpp Mon Jan 25 14:56:57 2016 -0800 +++ b/src/share/vm/prims/jvmtiClassFileReconstituter.hpp Mon Jan 25 14:57:27 2016 -0800 @@ -68,11 +68,11 @@ ~JvmtiConstantPoolReconstituter() { if (_symmap != NULL) { - os::free(_symmap, mtClass); + delete _symmap; _symmap = NULL; } if (_classmap != NULL) { - os::free(_classmap, mtClass); + delete _classmap; _classmap = NULL; } } diff -r c2687aa5e5ca -r 7eb99acd567f src/share/vm/prims/jvmtiExport.cpp --- a/src/share/vm/prims/jvmtiExport.cpp Mon Jan 25 14:56:57 2016 -0800 +++ b/src/share/vm/prims/jvmtiExport.cpp Mon Jan 25 14:57:27 2016 -0800 @@ -2163,6 +2163,15 @@ } } +void JvmtiExport::clear_detected_exception(JavaThread* thread) { + assert(JavaThread::current() == thread, "thread is not current"); + + JvmtiThreadState* state = thread->jvmti_thread_state(); + if (state != NULL) { + state->clear_exception_detected(); + } +} + void JvmtiExport::oops_do(OopClosure* f) { JvmtiCurrentBreakpoints::oops_do(f); JvmtiVMObjectAllocEventCollector::oops_do_for_all_threads(f); diff -r c2687aa5e5ca -r 7eb99acd567f src/share/vm/prims/jvmtiExport.hpp --- a/src/share/vm/prims/jvmtiExport.hpp Mon Jan 25 14:56:57 2016 -0800 +++ b/src/share/vm/prims/jvmtiExport.hpp Mon Jan 25 14:57:27 2016 -0800 @@ -363,6 +363,7 @@ } static void cleanup_thread (JavaThread* thread) NOT_JVMTI_RETURN; + static void clear_detected_exception (JavaThread* thread) NOT_JVMTI_RETURN; static void oops_do(OopClosure* f) NOT_JVMTI_RETURN; static void weak_oops_do(BoolObjectClosure* b, OopClosure* f) NOT_JVMTI_RETURN; diff -r c2687aa5e5ca -r 7eb99acd567f src/share/vm/prims/jvmtiImpl.cpp --- a/src/share/vm/prims/jvmtiImpl.cpp Mon Jan 25 14:56:57 2016 -0800 +++ b/src/share/vm/prims/jvmtiImpl.cpp Mon Jan 25 14:57:27 2016 -0800 @@ -25,6 +25,7 @@ #include "precompiled.hpp" #include "classfile/systemDictionary.hpp" #include "interpreter/interpreter.hpp" +#include "interpreter/oopMapCache.hpp" #include "jvmtifiles/jvmtiEnv.hpp" #include "memory/resourceArea.hpp" #include "oops/instanceKlass.hpp" @@ -744,6 +745,13 @@ } void VM_GetOrSetLocal::doit() { + InterpreterOopMap oop_mask; + _jvf->method()->mask_for(_jvf->bci(), &oop_mask); + if (oop_mask.is_dead(_index)) { + // The local can be invalid and uninitialized in the scope of current bci + _result = JVMTI_ERROR_INVALID_SLOT; + return; + } if (_set) { // Force deoptimization of frame if compiled because it's // possible the compiler emitted some locals as constant values, diff -r c2687aa5e5ca -r 7eb99acd567f src/share/vm/prims/jvmtiRedefineClasses.cpp --- a/src/share/vm/prims/jvmtiRedefineClasses.cpp Mon Jan 25 14:56:57 2016 -0800 +++ b/src/share/vm/prims/jvmtiRedefineClasses.cpp Mon Jan 25 14:57:27 2016 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 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 @@ -777,9 +777,13 @@ Method* idnum_owner = scratch_class->method_with_idnum(old_num); if (idnum_owner != NULL) { // There is already a method assigned this idnum -- switch them + // Take current and original idnum from the new_method idnum_owner->set_method_idnum(new_num); + idnum_owner->set_orig_method_idnum(k_new_method->orig_method_idnum()); } + // Take current and original idnum from the old_method k_new_method->set_method_idnum(old_num); + k_new_method->set_orig_method_idnum(k_old_method->orig_method_idnum()); if (thread->has_pending_exception()) { return JVMTI_ERROR_OUT_OF_MEMORY; } @@ -812,9 +816,12 @@ Method* idnum_owner = scratch_class->method_with_idnum(num); if (idnum_owner != NULL) { // There is already a method assigned this idnum -- switch them + // Take current and original idnum from the new_method idnum_owner->set_method_idnum(new_num); + idnum_owner->set_orig_method_idnum(k_new_method->orig_method_idnum()); } k_new_method->set_method_idnum(num); + k_new_method->set_orig_method_idnum(num); if (thread->has_pending_exception()) { return JVMTI_ERROR_OUT_OF_MEMORY; } @@ -3322,6 +3329,7 @@ // This is a very busy routine. We don't want too much tracing // printed out. bool trace_name_printed = false; + InstanceKlass *the_class = InstanceKlass::cast(_the_class_oop); // Very noisy: only enable this call if you are trying to determine // that a specific class gets found by this routine. @@ -3333,10 +3341,8 @@ // If the class being redefined is java.lang.Object, we need to fix all // array class vtables also if (k->oop_is_array() && _the_class_oop == SystemDictionary::Object_klass()) { - k->vtable()->adjust_method_entries(_matching_old_methods, - _matching_new_methods, - _matching_methods_length, - &trace_name_printed); + k->vtable()->adjust_method_entries(the_class, &trace_name_printed); + } else if (k->oop_is_instance()) { HandleMark hm(_thread); InstanceKlass *ik = InstanceKlass::cast(k); @@ -3376,14 +3382,9 @@ || ik->is_subtype_of(_the_class_oop))) { // ik->vtable() creates a wrapper object; rm cleans it up ResourceMark rm(_thread); - ik->vtable()->adjust_method_entries(_matching_old_methods, - _matching_new_methods, - _matching_methods_length, - &trace_name_printed); - ik->adjust_default_methods(_matching_old_methods, - _matching_new_methods, - _matching_methods_length, - &trace_name_printed); + + ik->vtable()->adjust_method_entries(the_class, &trace_name_printed); + ik->adjust_default_methods(the_class, &trace_name_printed); } // If the current class has an itable and we are either redefining an @@ -3396,10 +3397,8 @@ || ik->is_subclass_of(_the_class_oop))) { // ik->itable() creates a wrapper object; rm cleans it up ResourceMark rm(_thread); - ik->itable()->adjust_method_entries(_matching_old_methods, - _matching_new_methods, - _matching_methods_length, - &trace_name_printed); + + ik->itable()->adjust_method_entries(the_class, &trace_name_printed); } // The constant pools in other classes (other_cp) can refer to @@ -3423,10 +3422,7 @@ other_cp = constantPoolHandle(ik->constants()); cp_cache = other_cp->cache(); if (cp_cache != NULL) { - cp_cache->adjust_method_entries(_matching_old_methods, - _matching_new_methods, - _matching_methods_length, - &trace_name_printed); + cp_cache->adjust_method_entries(the_class, &trace_name_printed); } } @@ -3437,10 +3433,7 @@ other_cp = pv_node->prev_constant_pool(); cp_cache = other_cp->cache(); if (cp_cache != NULL) { - cp_cache->adjust_method_entries(_matching_old_methods, - _matching_new_methods, - _matching_methods_length, - &trace_name_printed); + cp_cache->adjust_method_entries(other_cp->pool_holder(), &trace_name_printed); } } } @@ -3555,6 +3548,7 @@ // obsolete methods need a unique idnum so they become new entries in // the jmethodID cache in InstanceKlass + assert(old_method->method_idnum() == new_method->method_idnum(), "must match"); u2 num = InstanceKlass::cast(_the_class_oop)->next_method_idnum(); if (num != ConstMethod::UNSET_IDNUM) { old_method->set_method_idnum(num); @@ -3575,7 +3569,8 @@ assert(!old_method->has_vtable_index(), "cannot delete methods with vtable entries");; - // Mark all deleted methods as old and obsolete + // Mark all deleted methods as old, obsolete and deleted + old_method->set_is_deleted(); old_method->set_is_old(); old_method->set_is_obsolete(); ++obsolete_count; @@ -3981,14 +3976,13 @@ // the_class doesn't have a cache yet so copy it the_class->set_cached_class_file(scratch_class->get_cached_class_file()); } -#ifndef PRODUCT - else { - assert(the_class->get_cached_class_file_bytes() == - scratch_class->get_cached_class_file_bytes(), "cache ptrs must match"); - assert(the_class->get_cached_class_file_len() == - scratch_class->get_cached_class_file_len(), "cache lens must match"); + else if (scratch_class->get_cached_class_file_bytes() != + the_class->get_cached_class_file_bytes()) { + // The same class can be present twice in the scratch classes list or there + // are multiple concurrent RetransformClasses calls on different threads. + // In such cases we have to deallocate scratch_class cached_class_file. + os::free(scratch_class->get_cached_class_file()); } -#endif // NULL out in scratch class to not delete twice. The class to be redefined // always owns these bytes. @@ -4074,15 +4068,9 @@ MemberNameTable* mnt = the_class->member_names(); if (mnt != NULL) { bool trace_name_printed = false; - mnt->adjust_method_entries(_matching_old_methods, - _matching_new_methods, - _matching_methods_length, - &trace_name_printed); + mnt->adjust_method_entries(the_class(), &trace_name_printed); } - // Fix Resolution Error table also to remove old constant pools - SystemDictionary::delete_resolution_error(old_constants); - if (the_class->oop_map_cache() != NULL) { // Flush references to any obsolete methods from the oop map cache // so that obsolete methods are not pinned. @@ -4164,7 +4152,7 @@ no_old_methods = false; } - // the constant pool cache should never contain old or obsolete methods + // the constant pool cache should never contain non-deleted old or obsolete methods if (ik->constants() != NULL && ik->constants()->cache() != NULL && !ik->constants()->cache()->check_no_old_or_obsolete_entries()) { diff -r c2687aa5e5ca -r 7eb99acd567f src/share/vm/prims/jvmtiTagMap.cpp --- a/src/share/vm/prims/jvmtiTagMap.cpp Mon Jan 25 14:56:57 2016 -0800 +++ b/src/share/vm/prims/jvmtiTagMap.cpp Mon Jan 25 14:57:27 2016 -0800 @@ -1045,10 +1045,16 @@ { assert(str->klass() == SystemDictionary::String_klass(), "not a string"); + typeArrayOop s_value = java_lang_String::value(str); + + // JDK-6584008: the value field may be null if a String instance is + // partially constructed. + if (s_value == NULL) { + return 0; + } // get the string value and length // (string value may be offset from the base) int s_len = java_lang_String::length(str); - typeArrayOop s_value = java_lang_String::value(str); int s_offset = java_lang_String::offset(str); jchar* value; if (s_len > 0) { diff -r c2687aa5e5ca -r 7eb99acd567f src/share/vm/prims/methodHandles.cpp --- a/src/share/vm/prims/methodHandles.cpp Mon Jan 25 14:56:57 2016 -0800 +++ b/src/share/vm/prims/methodHandles.cpp Mon Jan 25 14:57:27 2016 -0800 @@ -30,6 +30,7 @@ #include "memory/allocation.inline.hpp" #include "memory/oopFactory.hpp" #include "prims/methodHandles.hpp" +#include "prims/jvmtiRedefineClassesTrace.hpp" #include "runtime/compilationPolicy.hpp" #include "runtime/javaCalls.hpp" #include "runtime/reflection.hpp" @@ -955,21 +956,41 @@ #if INCLUDE_JVMTI // 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) { +void MemberNameTable::adjust_method_entries(InstanceKlass* holder, bool * trace_name_printed) { assert(SafepointSynchronize::is_at_safepoint(), "only called at safepoint"); // For each redefined method - for (int j = 0; j < methods_length; j++) { - Method* old_method = old_methods[j]; - Method* new_method = new_methods[j]; + for (int idx = 0; idx < length(); idx++) { + oop mem_name = JNIHandles::resolve(this->at(idx)); + if (mem_name == NULL) { + continue; + } + Method* old_method = (Method*)java_lang_invoke_MemberName::vmtarget(mem_name); + + if (old_method == NULL || !old_method->is_old()) { + continue; // skip uninteresting entries + } + if (old_method->is_deleted()) { + // skip entries with deleted methods + continue; + } + Method* new_method = holder->method_with_idnum(old_method->orig_method_idnum()); - // 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); + assert(new_method != NULL, "method_with_idnum() should not be NULL"); + assert(old_method != new_method, "sanity check"); + + java_lang_invoke_MemberName::set_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())); } } } diff -r c2687aa5e5ca -r 7eb99acd567f src/share/vm/prims/methodHandles.hpp --- a/src/share/vm/prims/methodHandles.hpp Mon Jan 25 14:56:57 2016 -0800 +++ b/src/share/vm/prims/methodHandles.hpp Mon Jan 25 14:57:27 2016 -0800 @@ -240,10 +240,8 @@ #if INCLUDE_JVMTI // 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); + // If a MemberName refers to old_method then update it to refer to new_method. + void adjust_method_entries(InstanceKlass* holder, bool * trace_name_printed); #endif // INCLUDE_JVMTI }; diff -r c2687aa5e5ca -r 7eb99acd567f src/share/vm/prims/unsafe.cpp --- a/src/share/vm/prims/unsafe.cpp Mon Jan 25 14:56:57 2016 -0800 +++ b/src/share/vm/prims/unsafe.cpp Mon Jan 25 14:57:27 2016 -0800 @@ -322,10 +322,33 @@ UNSAFE_END #ifndef SUPPORTS_NATIVE_CX8 -// Keep old code for platforms which may not have atomic jlong (8 bytes) instructions -// Volatile long versions must use locks if !VM_Version::supports_cx8(). -// support_cx8 is a surrogate for 'supports atomic long memory ops'. +// VM_Version::supports_cx8() is a surrogate for 'supports atomic long memory ops'. +// +// On platforms which do not support atomic compare-and-swap of jlong (8 byte) +// values we have to use a lock-based scheme to enforce atomicity. This has to be +// applied to all Unsafe operations that set the value of a jlong field. Even so +// the compareAndSwapLong operation will not be atomic with respect to direct stores +// to the field from Java code. It is important therefore that any Java code that +// utilizes these Unsafe jlong operations does not perform direct stores. To permit +// direct loads of the field from Java code we must also use Atomic::store within the +// locked regions. And for good measure, in case there are direct stores, we also +// employ Atomic::load within those regions. Note that the field in question must be +// volatile and so must have atomic load/store accesses applied at the Java level. +// +// The locking scheme could utilize a range of strategies for controlling the locking +// granularity: from a lock per-field through to a single global lock. The latter is +// the simplest and is used for the current implementation. Note that the Java object +// that contains the field, can not, in general, be used for locking. To do so can lead +// to deadlocks as we may introduce locking into what appears to the Java code to be a +// lock-free path. +// +// As all the locked-regions are very short and themselves non-blocking we can treat +// them as leaf routines and elide safepoint checks (ie we don't perform any thread +// state transitions even when blocking for the lock). Note that if we do choose to +// add safepoint checks and thread state transitions, we must ensure that we calculate +// the address of the field _after_ we have acquired the lock, else the object may have +// been moved by the GC UNSAFE_ENTRY(jlong, Unsafe_GetLongVolatile(JNIEnv *env, jobject unsafe, jobject obj, jlong offset)) UnsafeWrapper("Unsafe_GetLongVolatile"); @@ -337,8 +360,8 @@ else { Handle p (THREAD, JNIHandles::resolve(obj)); jlong* addr = (jlong*)(index_oop_from_field_offset_long(p(), offset)); - ObjectLocker ol(p, THREAD); - jlong value = *addr; + MutexLockerEx mu(UnsafeJlong_lock, Mutex::_no_safepoint_check_flag); + jlong value = Atomic::load(addr); return value; } } @@ -353,8 +376,8 @@ else { Handle p (THREAD, JNIHandles::resolve(obj)); jlong* addr = (jlong*)(index_oop_from_field_offset_long(p(), offset)); - ObjectLocker ol(p, THREAD); - *addr = x; + MutexLockerEx mu(UnsafeJlong_lock, Mutex::_no_safepoint_check_flag); + Atomic::store(x, addr); } } UNSAFE_END @@ -463,8 +486,8 @@ else { Handle p (THREAD, JNIHandles::resolve(obj)); jlong* addr = (jlong*)(index_oop_from_field_offset_long(p(), offset)); - ObjectLocker ol(p, THREAD); - *addr = x; + MutexLockerEx mu(UnsafeJlong_lock, Mutex::_no_safepoint_check_flag); + Atomic::store(x, addr); } } #endif @@ -1213,14 +1236,19 @@ UnsafeWrapper("Unsafe_CompareAndSwapLong"); Handle p (THREAD, JNIHandles::resolve(obj)); jlong* addr = (jlong*)(index_oop_from_field_offset_long(p(), offset)); +#ifdef SUPPORTS_NATIVE_CX8 + return (jlong)(Atomic::cmpxchg(x, addr, e)) == e; +#else if (VM_Version::supports_cx8()) return (jlong)(Atomic::cmpxchg(x, addr, e)) == e; else { jboolean success = false; - ObjectLocker ol(p, THREAD); - if (*addr == e) { *addr = x; success = true; } + MutexLockerEx mu(UnsafeJlong_lock, Mutex::_no_safepoint_check_flag); + jlong val = Atomic::load(addr); + if (val == e) { Atomic::store(x, addr); success = true; } return success; } +#endif UNSAFE_END UNSAFE_ENTRY(void, Unsafe_Park(JNIEnv *env, jobject unsafe, jboolean isAbsolute, jlong time)) diff -r c2687aa5e5ca -r 7eb99acd567f src/share/vm/prims/whitebox.cpp --- a/src/share/vm/prims/whitebox.cpp Mon Jan 25 14:56:57 2016 -0800 +++ b/src/share/vm/prims/whitebox.cpp Mon Jan 25 14:57:27 2016 -0800 @@ -73,6 +73,13 @@ return heapOopSize; WB_END +WB_ENTRY(jint, WB_GetVMPageSize(JNIEnv* env, jobject o)) + return os::vm_page_size(); +WB_END + +WB_ENTRY(jlong, WB_GetVMLargePageSize(JNIEnv* env, jobject o)) + return os::large_page_size(); +WB_END class WBIsKlassAliveClosure : public KlassClosure { Symbol* _name; @@ -302,6 +309,12 @@ return hr->isHumongous(); WB_END +WB_ENTRY(jlong, WB_G1NumMaxRegions(JNIEnv* env, jobject o)) + G1CollectedHeap* g1 = G1CollectedHeap::heap(); + size_t nr = g1->max_regions(); + return (jlong)nr; +WB_END + WB_ENTRY(jlong, WB_G1NumFreeRegions(JNIEnv* env, jobject o)) G1CollectedHeap* g1 = G1CollectedHeap::heap(); size_t nr = g1->num_free_regions(); @@ -317,6 +330,14 @@ WB_ENTRY(jint, WB_G1RegionSize(JNIEnv* env, jobject o)) return (jint)HeapRegion::GrainBytes; WB_END + +WB_ENTRY(jobject, WB_G1AuxiliaryMemoryUsage(JNIEnv* env)) + ResourceMark rm(THREAD); + G1CollectedHeap* g1h = G1CollectedHeap::heap(); + MemoryUsage usage = g1h->get_auxiliary_data_memory_usage(); + Handle h = MemoryService::create_MemoryUsage_obj(usage, CHECK_NULL); + return JNIHandles::make_local(env, h()); +WB_END #endif // INCLUDE_ALL_GCS #if INCLUDE_NMT @@ -884,6 +905,16 @@ return (jlong) MetaspaceGC::capacity_until_GC(); WB_END +WB_ENTRY(jboolean, WB_IsMonitorInflated(JNIEnv* env, jobject wb, jobject obj)) + oop obj_oop = JNIHandles::resolve(obj); + return (jboolean) obj_oop->mark()->has_monitor(); +WB_END + +WB_ENTRY(void, WB_ForceSafepoint(JNIEnv* env, jobject wb)) + VM_ForceSafepoint force_safepoint_op; + VMThread::execute(&force_safepoint_op); +WB_END + //Some convenience methods to deal with objects from java int WhiteBox::offset_for_field(const char* field_name, oop object, Symbol* signature_symbol) { @@ -906,7 +937,7 @@ if (res == NULL) { tty->print_cr("Invalid layout of %s at %s", ik->external_name(), name_symbol->as_C_string()); - fatal("Invalid layout of preloaded class"); + vm_exit_during_initialization("Invalid layout of preloaded class: use -XX:+TraceClassLoading to see the origin of the problem class"); } //fetch the field at the offset we've found @@ -972,6 +1003,8 @@ {CC"getObjectSize", CC"(Ljava/lang/Object;)J", (void*)&WB_GetObjectSize }, {CC"isObjectInOldGen", CC"(Ljava/lang/Object;)Z", (void*)&WB_isObjectInOldGen }, {CC"getHeapOopSize", CC"()I", (void*)&WB_GetHeapOopSize }, + {CC"getVMPageSize", CC"()I", (void*)&WB_GetVMPageSize }, + {CC"getVMLargePageSize", CC"()J", (void*)&WB_GetVMLargePageSize}, {CC"isClassAlive0", CC"(Ljava/lang/String;)Z", (void*)&WB_IsClassAlive }, {CC"classKnownToNotExist", CC"(Ljava/lang/ClassLoader;Ljava/lang/String;)Z",(void*)&WB_ClassKnownToNotExist}, @@ -995,8 +1028,11 @@ #if INCLUDE_ALL_GCS {CC"g1InConcurrentMark", CC"()Z", (void*)&WB_G1InConcurrentMark}, {CC"g1IsHumongous", CC"(Ljava/lang/Object;)Z", (void*)&WB_G1IsHumongous }, + {CC"g1NumMaxRegions", CC"()J", (void*)&WB_G1NumMaxRegions }, {CC"g1NumFreeRegions", CC"()J", (void*)&WB_G1NumFreeRegions }, {CC"g1RegionSize", CC"()I", (void*)&WB_G1RegionSize }, + {CC"g1AuxiliaryMemoryUsage", CC"()Ljava/lang/management/MemoryUsage;", + (void*)&WB_G1AuxiliaryMemoryUsage }, #endif // INCLUDE_ALL_GCS #if INCLUDE_NMT {CC"NMTMalloc", CC"(J)J", (void*)&WB_NMTMalloc }, @@ -1067,6 +1103,8 @@ {CC"getCPUFeatures", CC"()Ljava/lang/String;", (void*)&WB_GetCPUFeatures }, {CC"getNMethod", CC"(Ljava/lang/reflect/Executable;Z)[Ljava/lang/Object;", (void*)&WB_GetNMethod }, + {CC"isMonitorInflated", CC"(Ljava/lang/Object;)Z", (void*)&WB_IsMonitorInflated }, + {CC"forceSafepoint", CC"()V", (void*)&WB_ForceSafepoint }, }; #undef CC diff -r c2687aa5e5ca -r 7eb99acd567f src/share/vm/runtime/arguments.cpp --- a/src/share/vm/runtime/arguments.cpp Mon Jan 25 14:56:57 2016 -0800 +++ b/src/share/vm/runtime/arguments.cpp Mon Jan 25 14:57:27 2016 -0800 @@ -1379,6 +1379,12 @@ if (!FLAG_IS_DEFAULT(CMSParPromoteBlocksToClaim) || !FLAG_IS_DEFAULT(OldPLABWeight)) { CFLS_LAB::modify_initialization(OldPLABSize, OldPLABWeight); } + + if (!ClassUnloading) { + FLAG_SET_CMDLINE(bool, CMSClassUnloadingEnabled, false); + FLAG_SET_CMDLINE(bool, ExplicitGCInvokesConcurrentAndUnloadsClasses, false); + } + if (PrintGCDetails && Verbose) { tty->print_cr("MarkStackSize: %uk MarkStackSizeMax: %uk", (unsigned int) (MarkStackSize / K), (uint) (MarkStackSizeMax / K)); @@ -1579,7 +1585,7 @@ void Arguments::select_gc() { if (!gc_selected()) { - ArgumentsExt::select_gc_ergonomically(); + select_gc_ergonomically(); } } @@ -2074,7 +2080,7 @@ } // Check consistency of GC selection -bool Arguments::check_gc_consistency_user() { +bool Arguments::check_gc_consistency() { check_gclog_consistency(); bool status = true; // Ensure that the user has not selected conflicting sets @@ -2240,7 +2246,7 @@ FLAG_SET_DEFAULT(UseGCOverheadLimit, false); } - status = status && check_gc_consistency_user(); + status = status && check_gc_consistency(); status = status && check_stack_pages(); if (CMSIncrementalMode) { @@ -3883,8 +3889,8 @@ CommandLineFlags::printFlags(tty, false); vm_exit(0); } + if (match_option(option, "-XX:NativeMemoryTracking", &tail)) { #if INCLUDE_NMT - if (match_option(option, "-XX:NativeMemoryTracking", &tail)) { // The launcher did not setup nmt environment variable properly. if (!MemTracker::check_launcher_nmt_support(tail)) { warning("Native Memory Tracking did not setup properly, using wrong launcher?"); @@ -3899,8 +3905,12 @@ } else { vm_exit_during_initialization("Syntax error, expecting -XX:NativeMemoryTracking=[off|summary|detail]", NULL); } +#else + jio_fprintf(defaultStream::error_stream(), + "Native Memory Tracking is not supported in this VM\n"); + return JNI_ERR; +#endif } -#endif #ifndef PRODUCT @@ -4052,7 +4062,7 @@ set_shared_spaces_flags(); // Check the GC selections again. - if (!ArgumentsExt::check_gc_consistency_ergo()) { + if (!check_gc_consistency()) { return JNI_EINVAL; } diff -r c2687aa5e5ca -r 7eb99acd567f src/share/vm/runtime/arguments.hpp --- a/src/share/vm/runtime/arguments.hpp Mon Jan 25 14:56:57 2016 -0800 +++ b/src/share/vm/runtime/arguments.hpp Mon Jan 25 14:57:27 2016 -0800 @@ -466,8 +466,7 @@ static bool verify_MaxHeapFreeRatio(FormatBuffer<80>& err_msg, uintx max_heap_free_ratio); // Check for consistency in the selection of the garbage collector. - static bool check_gc_consistency_user(); // Check user-selected gc - static inline bool check_gc_consistency_ergo(); // Check ergonomic-selected gc + static bool check_gc_consistency(); // Check user-selected gc static void check_deprecated_gcs(); static void check_deprecated_gc_flags(); // Check consistecy or otherwise of VM argument settings @@ -615,8 +614,4 @@ UseParNewGC || UseSerialGC; } -bool Arguments::check_gc_consistency_ergo() { - return check_gc_consistency_user(); -} - #endif // SHARE_VM_RUNTIME_ARGUMENTS_HPP diff -r c2687aa5e5ca -r 7eb99acd567f src/share/vm/runtime/arguments_ext.hpp --- a/src/share/vm/runtime/arguments_ext.hpp Mon Jan 25 14:56:57 2016 -0800 +++ b/src/share/vm/runtime/arguments_ext.hpp Mon Jan 25 14:57:27 2016 -0800 @@ -30,22 +30,12 @@ class ArgumentsExt: AllStatic { public: - static inline void select_gc_ergonomically(); static inline void set_gc_specific_flags(); - static inline bool check_gc_consistency_ergo(); static void process_options(const JavaVMInitArgs* args) {} }; -void ArgumentsExt::select_gc_ergonomically() { - Arguments::select_gc_ergonomically(); -} - void ArgumentsExt::set_gc_specific_flags() { Arguments::set_gc_specific_flags(); } -bool ArgumentsExt::check_gc_consistency_ergo() { - return Arguments::check_gc_consistency_ergo(); -} - #endif // SHARE_VM_RUNTIME_ARGUMENTS_EXT_HPP diff -r c2687aa5e5ca -r 7eb99acd567f src/share/vm/runtime/basicLock.cpp --- a/src/share/vm/runtime/basicLock.cpp Mon Jan 25 14:56:57 2016 -0800 +++ b/src/share/vm/runtime/basicLock.cpp Mon Jan 25 14:57:27 2016 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 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 @@ -28,6 +28,9 @@ void BasicLock::print_on(outputStream* st) const { st->print("monitor"); + markOop moop = displaced_header(); + if (moop != NULL) + moop->print_on(st); } void BasicLock::move_to(oop obj, BasicLock* dest) { diff -r c2687aa5e5ca -r 7eb99acd567f src/share/vm/runtime/deoptimization.cpp --- a/src/share/vm/runtime/deoptimization.cpp Mon Jan 25 14:56:57 2016 -0800 +++ b/src/share/vm/runtime/deoptimization.cpp Mon Jan 25 14:57:27 2016 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 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 @@ -67,25 +67,17 @@ # include "vmreg_ppc.inline.hpp" #endif #ifdef COMPILER2 -#ifdef TARGET_ARCH_MODEL_x86_32 +#if defined AD_MD_HPP +# include AD_MD_HPP +#elif defined TARGET_ARCH_MODEL_x86_32 # include "adfiles/ad_x86_32.hpp" -#endif -#ifdef TARGET_ARCH_MODEL_x86_64 +#elif defined TARGET_ARCH_MODEL_x86_64 # include "adfiles/ad_x86_64.hpp" -#endif -#ifdef TARGET_ARCH_MODEL_sparc +#elif defined TARGET_ARCH_MODEL_sparc # include "adfiles/ad_sparc.hpp" -#endif -#ifdef TARGET_ARCH_MODEL_zero +#elif defined TARGET_ARCH_MODEL_zero # include "adfiles/ad_zero.hpp" -#endif -#ifdef TARGET_ARCH_MODEL_arm -# include "adfiles/ad_arm.hpp" -#endif -#ifdef TARGET_ARCH_MODEL_ppc_32 -# include "adfiles/ad_ppc_32.hpp" -#endif -#ifdef TARGET_ARCH_MODEL_ppc_64 +#elif defined TARGET_ARCH_MODEL_ppc_64 # include "adfiles/ad_ppc_64.hpp" #endif #endif // COMPILER2 @@ -1710,7 +1702,10 @@ // // The other actions cause immediate removal of the present code. - bool update_trap_state = true; + // Traps caused by injected profile shouldn't pollute trap counts. + bool injected_profile_trap = trap_method->has_injected_profile() && + (reason == Reason_intrinsic || reason == Reason_unreached); + bool update_trap_state = !injected_profile_trap; bool make_not_entrant = false; bool make_not_compilable = false; bool reprofile = false; diff -r c2687aa5e5ca -r 7eb99acd567f src/share/vm/runtime/frame.hpp --- a/src/share/vm/runtime/frame.hpp Mon Jan 25 14:56:57 2016 -0800 +++ b/src/share/vm/runtime/frame.hpp Mon Jan 25 14:57:27 2016 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 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,25 +31,17 @@ #include "runtime/registerMap.hpp" #include "utilities/top.hpp" #ifdef COMPILER2 -#ifdef TARGET_ARCH_MODEL_x86_32 +#if defined ADGLOBALS_MD_HPP +# include ADGLOBALS_MD_HPP +#elif defined TARGET_ARCH_MODEL_x86_32 # include "adfiles/adGlobals_x86_32.hpp" -#endif -#ifdef TARGET_ARCH_MODEL_x86_64 +#elif defined TARGET_ARCH_MODEL_x86_64 # include "adfiles/adGlobals_x86_64.hpp" -#endif -#ifdef TARGET_ARCH_MODEL_sparc +#elif defined TARGET_ARCH_MODEL_sparc # include "adfiles/adGlobals_sparc.hpp" -#endif -#ifdef TARGET_ARCH_MODEL_zero +#elif defined TARGET_ARCH_MODEL_zero # include "adfiles/adGlobals_zero.hpp" -#endif -#ifdef TARGET_ARCH_MODEL_arm -# include "adfiles/adGlobals_arm.hpp" -#endif -#ifdef TARGET_ARCH_MODEL_ppc_32 -# include "adfiles/adGlobals_ppc_32.hpp" -#endif -#ifdef TARGET_ARCH_MODEL_ppc_64 +#elif defined TARGET_ARCH_MODEL_ppc_64 # include "adfiles/adGlobals_ppc_64.hpp" #endif #endif // COMPILER2 @@ -91,6 +83,15 @@ // Constructors frame(); +#ifndef PRODUCT + // This is a generic constructor which is only used by pns() in debug.cpp. + // pns (i.e. print native stack) uses this constructor to create a starting + // frame for stack walking. The implementation of this constructor is platform + // dependent (i.e. SPARC doesn't need an 'fp' argument an will ignore it) but + // we want to keep the signature generic because pns() is shared code. + frame(void* sp, void* fp, void* pc); +#endif + // Accessors // pc: Returns the pc at which this frame will continue normally. diff -r c2687aa5e5ca -r 7eb99acd567f src/share/vm/runtime/globals.hpp --- a/src/share/vm/runtime/globals.hpp Mon Jan 25 14:56:57 2016 -0800 +++ b/src/share/vm/runtime/globals.hpp Mon Jan 25 14:57:27 2016 -0800 @@ -1518,7 +1518,7 @@ "How much the GC can expand the eden by while the GC locker " \ "is active (as a percentage)") \ \ - diagnostic(intx, GCLockerRetryAllocationCount, 2, \ + diagnostic(uintx, GCLockerRetryAllocationCount, 2, \ "Number of times to retry allocations when " \ "blocked by the GC locker") \ \ @@ -2072,9 +2072,6 @@ "Provide more detailed and expensive TLAB statistics " \ "(with PrintTLAB)") \ \ - EMBEDDED_ONLY(product(bool, LowMemoryProtection, true, \ - "Enable LowMemoryProtection")) \ - \ product_pd(bool, NeverActAsServerClassMachine, \ "Never act like a server-class machine") \ \ @@ -3973,7 +3970,11 @@ "Enable event-based tracing") \ \ product(bool, UseLockedTracing, false, \ - "Use locked-tracing when doing event-based tracing") + "Use locked-tracing when doing event-based tracing") \ + \ + product_pd(bool, PreserveFramePointer, \ + "Use the FP register for holding the frame pointer " \ + "and not as a general purpose register.") /* * Macros for factoring of globals diff -r c2687aa5e5ca -r 7eb99acd567f src/share/vm/runtime/interfaceSupport.cpp --- a/src/share/vm/runtime/interfaceSupport.cpp Mon Jan 25 14:56:57 2016 -0800 +++ b/src/share/vm/runtime/interfaceSupport.cpp Mon Jan 25 14:57:27 2016 -0800 @@ -185,19 +185,22 @@ # endif - +// invocation counter for InterfaceSupport::deoptimizeAll/zombieAll functions int deoptimizeAllCounter = 0; int zombieAllCounter = 0; - void InterfaceSupport::zombieAll() { - if (is_init_completed() && zombieAllCounter > ZombieALotInterval) { + // This method is called by all threads when a thread make + // transition to VM state (for example, runtime calls). + // Divide number of calls by number of threads to avoid + // dependence of ZombieAll events frequency on number of threads. + int value = zombieAllCounter / Threads::number_of_threads(); + if (is_init_completed() && value > ZombieALotInterval) { zombieAllCounter = 0; VM_ZombieAll op; VMThread::execute(&op); - } else { - zombieAllCounter++; } + zombieAllCounter++; } void InterfaceSupport::unlinkSymbols() { @@ -206,12 +209,17 @@ } void InterfaceSupport::deoptimizeAll() { - if (is_init_completed() ) { - if (DeoptimizeALot && deoptimizeAllCounter > DeoptimizeALotInterval) { + // This method is called by all threads when a thread make + // transition to VM state (for example, runtime calls). + // Divide number of calls by number of threads to avoid + // dependence of DeoptimizeAll events frequency on number of threads. + int value = deoptimizeAllCounter / Threads::number_of_threads(); + if (is_init_completed()) { + if (DeoptimizeALot && value > DeoptimizeALotInterval) { deoptimizeAllCounter = 0; VM_DeoptimizeAll op; VMThread::execute(&op); - } else if (DeoptimizeRandom && (deoptimizeAllCounter & 0x1f) == (os::random() & 0x1f)) { + } else if (DeoptimizeRandom && (value & 0x1F) == (os::random() & 0x1F)) { VM_DeoptimizeAll op; VMThread::execute(&op); } diff -r c2687aa5e5ca -r 7eb99acd567f src/share/vm/runtime/jniHandles.cpp --- a/src/share/vm/runtime/jniHandles.cpp Mon Jan 25 14:56:57 2016 -0800 +++ b/src/share/vm/runtime/jniHandles.cpp Mon Jan 25 14:57:27 2016 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 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 @@ -296,6 +296,7 @@ block->_top = 0; block->_next = NULL; block->_pop_frame_link = NULL; + block->_planned_capacity = block_size_in_oops; // _last, _free_list & _allocate_before_rebuild initialized in allocate_handle debug_only(block->_last = NULL); debug_only(block->_free_list = NULL); @@ -529,6 +530,12 @@ return result; } +const size_t JNIHandleBlock::get_number_of_live_handles() { + CountHandleClosure counter; + oops_do(&counter); + return counter.count(); +} + // This method is not thread-safe, i.e., must be called whule holding a lock on the // structure. long JNIHandleBlock::memory_usage() const { diff -r c2687aa5e5ca -r 7eb99acd567f src/share/vm/runtime/jniHandles.hpp --- a/src/share/vm/runtime/jniHandles.hpp Mon Jan 25 14:56:57 2016 -0800 +++ b/src/share/vm/runtime/jniHandles.hpp Mon Jan 25 14:57:27 2016 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 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 @@ -112,6 +112,9 @@ oop* _free_list; // Handle free list int _allocate_before_rebuild; // Number of blocks to allocate before rebuilding free list + // Check JNI, "planned capacity" for current frame (or push/ensure) + size_t _planned_capacity; + #ifndef PRODUCT JNIHandleBlock* _block_list_link; // Link for list below static JNIHandleBlock* _block_list; // List of all allocated blocks (for debugging only) @@ -152,6 +155,11 @@ // Traversal of weak handles. Unreachable oops are cleared. void weak_oops_do(BoolObjectClosure* is_alive, OopClosure* f); + // Checked JNI support + void set_planned_capacity(size_t planned_capacity) { _planned_capacity = planned_capacity; } + const size_t get_planned_capacity() { return _planned_capacity; } + const size_t get_number_of_live_handles(); + // Debugging bool chain_contains(jobject handle) const; // Does this block or following blocks contain handle bool contains(jobject handle) const; // Does this block contain handle diff -r c2687aa5e5ca -r 7eb99acd567f src/share/vm/runtime/mutexLocker.cpp --- a/src/share/vm/runtime/mutexLocker.cpp Mon Jan 25 14:56:57 2016 -0800 +++ b/src/share/vm/runtime/mutexLocker.cpp Mon Jan 25 14:57:27 2016 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 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 @@ -119,7 +119,6 @@ Mutex* OldSets_lock = NULL; Monitor* RootRegionScan_lock = NULL; Mutex* MMUTracker_lock = NULL; -Mutex* HotCardCache_lock = NULL; Monitor* GCTaskManager_lock = NULL; @@ -135,6 +134,10 @@ Mutex* JfrThreadGroups_lock = NULL; #endif +#ifndef SUPPORTS_NATIVE_CX8 +Mutex* UnsafeJlong_lock = NULL; +#endif + #define MAX_NUM_MUTEX 128 static Monitor * _mutex_array[MAX_NUM_MUTEX]; static int _num_mutex; @@ -196,7 +199,6 @@ def(OldSets_lock , Mutex , leaf , true ); def(RootRegionScan_lock , Monitor, leaf , true ); def(MMUTracker_lock , Mutex , leaf , true ); - def(HotCardCache_lock , Mutex , special , true ); def(EvacFailureStack_lock , Mutex , nonleaf , true ); def(StringDedupQueue_lock , Monitor, leaf, true ); @@ -280,12 +282,15 @@ #ifdef INCLUDE_TRACE def(JfrMsg_lock , Monitor, leaf, true); - def(JfrBuffer_lock , Mutex, nonleaf+1, true); - def(JfrThreadGroups_lock , Mutex, nonleaf+1, true); - def(JfrStream_lock , Mutex, nonleaf+2, true); - def(JfrStacktrace_lock , Mutex, special, true ); + def(JfrBuffer_lock , Mutex, leaf, true); + def(JfrThreadGroups_lock , Mutex, leaf, true); + def(JfrStream_lock , Mutex, nonleaf, true); + def(JfrStacktrace_lock , Mutex, special, true); #endif +#ifndef SUPPORTS_NATIVE_CX8 + def(UnsafeJlong_lock , Mutex, special, false); +#endif } GCMutexLocker::GCMutexLocker(Monitor * mutex) { diff -r c2687aa5e5ca -r 7eb99acd567f src/share/vm/runtime/mutexLocker.hpp --- a/src/share/vm/runtime/mutexLocker.hpp Mon Jan 25 14:56:57 2016 -0800 +++ b/src/share/vm/runtime/mutexLocker.hpp Mon Jan 25 14:57:27 2016 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 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 @@ -137,7 +137,6 @@ extern Monitor* RootRegionScan_lock; // used to notify that the CM threads have finished scanning the IM snapshot regions extern Mutex* MMUTracker_lock; // protects the MMU // tracker data structures -extern Mutex* HotCardCache_lock; // protects the hot card cache extern Mutex* Management_lock; // a lock used to serialize JVM management extern Monitor* Service_lock; // a lock used for service thread operation @@ -151,6 +150,10 @@ extern Mutex* JfrThreadGroups_lock; // protects JFR access to Thread Groups #endif +#ifndef SUPPORTS_NATIVE_CX8 +extern Mutex* UnsafeJlong_lock; // provides Unsafe atomic updates to jlongs on platforms that don't support cx8 +#endif + // A MutexLocker provides mutual exclusion with respect to a given mutex // for the scope which contains the locker. The lock is an OS lock, not // an object lock, and the two do not interoperate. Do not use Mutex-based diff -r c2687aa5e5ca -r 7eb99acd567f src/share/vm/runtime/os.cpp --- a/src/share/vm/runtime/os.cpp Mon Jan 25 14:56:57 2016 -0800 +++ b/src/share/vm/runtime/os.cpp Mon Jan 25 14:57:27 2016 -0800 @@ -1318,24 +1318,17 @@ return (sp > (stack_limit + reserved_area)); } -size_t os::page_size_for_region(size_t region_min_size, size_t region_max_size, - uint min_pages) -{ +size_t os::page_size_for_region(size_t region_size, size_t min_pages, bool must_be_aligned) { assert(min_pages > 0, "sanity"); if (UseLargePages) { - const size_t max_page_size = region_max_size / min_pages; + const size_t max_page_size = region_size / min_pages; - for (unsigned int i = 0; _page_sizes[i] != 0; ++i) { - const size_t sz = _page_sizes[i]; - const size_t mask = sz - 1; - if ((region_min_size & mask) == 0 && (region_max_size & mask) == 0) { - // The largest page size with no fragmentation. - return sz; - } - - if (sz <= max_page_size) { - // The largest page size that satisfies the min_pages requirement. - return sz; + for (size_t i = 0; _page_sizes[i] != 0; ++i) { + const size_t page_size = _page_sizes[i]; + if (page_size <= max_page_size) { + if (!must_be_aligned || is_size_aligned(region_size, page_size)) { + return page_size; + } } } } @@ -1343,6 +1336,14 @@ return vm_page_size(); } +size_t os::page_size_for_region_aligned(size_t region_size, size_t min_pages) { + return page_size_for_region(region_size, min_pages, true); +} + +size_t os::page_size_for_region_unaligned(size_t region_size, size_t min_pages) { + return page_size_for_region(region_size, min_pages, false); +} + #ifndef PRODUCT void os::trace_page_sizes(const char* str, const size_t* page_sizes, int count) { @@ -1516,6 +1517,11 @@ return res; } +void os::pretouch_memory(char* start, char* end) { + for (volatile char *p = start; p < end; p += os::vm_page_size()) { + *p = 0; + } +} char* os::map_memory(int fd, const char* file_name, size_t file_offset, char *addr, size_t bytes, bool read_only, @@ -1572,3 +1578,95 @@ return result; } #endif + +/////////////// Unit tests /////////////// + +#ifndef PRODUCT + +#define assert_eq(a,b) assert(a == b, err_msg(SIZE_FORMAT " != " SIZE_FORMAT, a, b)) + +class TestOS : AllStatic { + static size_t small_page_size() { + return os::vm_page_size(); + } + + static size_t large_page_size() { + const size_t large_page_size_example = 4 * M; + return os::page_size_for_region_aligned(large_page_size_example, 1); + } + + static void test_page_size_for_region_aligned() { + if (UseLargePages) { + const size_t small_page = small_page_size(); + const size_t large_page = large_page_size(); + + if (large_page > small_page) { + size_t num_small_pages_in_large = large_page / small_page; + size_t page = os::page_size_for_region_aligned(large_page, num_small_pages_in_large); + + assert_eq(page, small_page); + } + } + } + + static void test_page_size_for_region_alignment() { + if (UseLargePages) { + const size_t small_page = small_page_size(); + const size_t large_page = large_page_size(); + if (large_page > small_page) { + const size_t unaligned_region = large_page + 17; + size_t page = os::page_size_for_region_aligned(unaligned_region, 1); + assert_eq(page, small_page); + + const size_t num_pages = 5; + const size_t aligned_region = large_page * num_pages; + page = os::page_size_for_region_aligned(aligned_region, num_pages); + assert_eq(page, large_page); + } + } + } + + static void test_page_size_for_region_unaligned() { + if (UseLargePages) { + // Given exact page size, should return that page size. + for (size_t i = 0; os::_page_sizes[i] != 0; i++) { + size_t expected = os::_page_sizes[i]; + size_t actual = os::page_size_for_region_unaligned(expected, 1); + assert_eq(expected, actual); + } + + // Given slightly larger size than a page size, return the page size. + for (size_t i = 0; os::_page_sizes[i] != 0; i++) { + size_t expected = os::_page_sizes[i]; + size_t actual = os::page_size_for_region_unaligned(expected + 17, 1); + assert_eq(expected, actual); + } + + // Given a slightly smaller size than a page size, + // return the next smaller page size. + if (os::_page_sizes[1] > os::_page_sizes[0]) { + size_t expected = os::_page_sizes[0]; + size_t actual = os::page_size_for_region_unaligned(os::_page_sizes[1] - 17, 1); + assert_eq(actual, expected); + } + + // Return small page size for values less than a small page. + size_t small_page = small_page_size(); + size_t actual = os::page_size_for_region_unaligned(small_page - 17, 1); + assert_eq(small_page, actual); + } + } + + public: + static void run_tests() { + test_page_size_for_region_aligned(); + test_page_size_for_region_alignment(); + test_page_size_for_region_unaligned(); + } +}; + +void TestOS_test() { + TestOS::run_tests(); +} + +#endif // PRODUCT diff -r c2687aa5e5ca -r 7eb99acd567f src/share/vm/runtime/os.hpp --- a/src/share/vm/runtime/os.hpp Mon Jan 25 14:56:57 2016 -0800 +++ b/src/share/vm/runtime/os.hpp Mon Jan 25 14:57:27 2016 -0800 @@ -153,6 +153,7 @@ static void pd_free_memory(char *addr, size_t bytes, size_t alignment_hint); static void pd_realign_memory(char *addr, size_t bytes, size_t alignment_hint); + static size_t page_size_for_region(size_t region_size, size_t min_pages, bool must_be_aligned); public: static void init(void); // Called before command line parsing @@ -163,7 +164,6 @@ static void init_globals(void) { // Called from init_globals() in init.cpp init_globals_ext(); } - static void init_3(void); // Called at the end of vm init // File names are case-insensitive on windows only // Override me as needed @@ -270,19 +270,16 @@ // Return the default page size. static int vm_page_size(); - // Return the page size to use for a region of memory. The min_pages argument - // is a hint intended to limit fragmentation; it says the returned page size - // should be <= region_max_size / min_pages. Because min_pages is a hint, - // this routine may return a size larger than region_max_size / min_pages. - // - // The current implementation ignores min_pages if a larger page size is an - // exact multiple of both region_min_size and region_max_size. This allows - // larger pages to be used when doing so would not cause fragmentation; in - // particular, a single page can be used when region_min_size == - // region_max_size == a supported page size. - static size_t page_size_for_region(size_t region_min_size, - size_t region_max_size, - uint min_pages); + // Returns the page size to use for a region of memory. + // region_size / min_pages will always be greater than or equal to the + // returned value. The returned value will divide region_size. + static size_t page_size_for_region_aligned(size_t region_size, size_t min_pages); + + // Returns the page size to use for a region of memory. + // region_size / min_pages will always be greater than or equal to the + // returned value. The returned value might not divide region_size. + static size_t page_size_for_region_unaligned(size_t region_size, size_t min_pages); + // Return the largest page size that can be used static size_t max_page_size() { // The _page_sizes array is sorted in descending order. @@ -324,6 +321,12 @@ static bool uncommit_memory(char* addr, size_t bytes); static bool release_memory(char* addr, size_t bytes); + // Touch memory pages that cover the memory range from start to end (exclusive) + // to make the OS back the memory range with actual memory. + // Current implementation may not touch the last page if unaligned addresses + // are passed. + static void pretouch_memory(char* start, char* end); + enum ProtType { MEM_PROT_NONE, MEM_PROT_READ, MEM_PROT_RW, MEM_PROT_RWX }; static bool protect_memory(char* addr, size_t bytes, ProtType prot, bool is_committed = true); diff -r c2687aa5e5ca -r 7eb99acd567f src/share/vm/runtime/reflection.cpp --- a/src/share/vm/runtime/reflection.cpp Mon Jan 25 14:56:57 2016 -0800 +++ b/src/share/vm/runtime/reflection.cpp Mon Jan 25 14:57:27 2016 -0800 @@ -36,6 +36,7 @@ #include "oops/objArrayKlass.hpp" #include "oops/objArrayOop.hpp" #include "prims/jvm.h" +#include "prims/jvmtiExport.hpp" #include "runtime/arguments.hpp" #include "runtime/handles.inline.hpp" #include "runtime/javaCalls.hpp" @@ -942,6 +943,11 @@ // Method resolution threw an exception; wrap it in an InvocationTargetException oop resolution_exception = PENDING_EXCEPTION; CLEAR_PENDING_EXCEPTION; + // JVMTI has already reported the pending exception + // JVMTI internal flag reset is needed in order to report InvocationTargetException + if (THREAD->is_Java_thread()) { + JvmtiExport::clear_detected_exception((JavaThread*) THREAD); + } JavaCallArguments args(Handle(THREAD, resolution_exception)); THROW_ARG_0(vmSymbols::java_lang_reflect_InvocationTargetException(), vmSymbols::throwable_void_signature(), @@ -1074,6 +1080,12 @@ // Method threw an exception; wrap it in an InvocationTargetException oop target_exception = PENDING_EXCEPTION; CLEAR_PENDING_EXCEPTION; + // JVMTI has already reported the pending exception + // JVMTI internal flag reset is needed in order to report InvocationTargetException + if (THREAD->is_Java_thread()) { + JvmtiExport::clear_detected_exception((JavaThread*) THREAD); + } + JavaCallArguments args(Handle(THREAD, target_exception)); THROW_ARG_0(vmSymbols::java_lang_reflect_InvocationTargetException(), vmSymbols::throwable_void_signature(), diff -r c2687aa5e5ca -r 7eb99acd567f src/share/vm/runtime/sharedRuntime.cpp --- a/src/share/vm/runtime/sharedRuntime.cpp Mon Jan 25 14:56:57 2016 -0800 +++ b/src/share/vm/runtime/sharedRuntime.cpp Mon Jan 25 14:57:27 2016 -0800 @@ -1308,7 +1308,7 @@ #endif // JSR 292 key invariant: - // If the resolved method is a MethodHandle invoke target the call + // If the resolved method is a MethodHandle invoke target, the call // site must be a MethodHandle call site, because the lambda form might tail-call // leaving the stack in a state unknown to either caller or callee // TODO detune for now but we might need it again diff -r c2687aa5e5ca -r 7eb99acd567f src/share/vm/runtime/stubRoutines.hpp --- a/src/share/vm/runtime/stubRoutines.hpp Mon Jan 25 14:56:57 2016 -0800 +++ b/src/share/vm/runtime/stubRoutines.hpp Mon Jan 25 14:57:27 2016 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 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 @@ -99,29 +99,20 @@ // Dependencies friend class StubGenerator; -#ifdef TARGET_ARCH_MODEL_x86_32 +#if defined STUBROUTINES_MD_HPP +# include STUBROUTINES_MD_HPP +#elif defined TARGET_ARCH_MODEL_x86_32 # include "stubRoutines_x86_32.hpp" -#endif -#ifdef TARGET_ARCH_MODEL_x86_64 +#elif defined TARGET_ARCH_MODEL_x86_64 # include "stubRoutines_x86_64.hpp" -#endif -#ifdef TARGET_ARCH_MODEL_sparc +#elif defined TARGET_ARCH_MODEL_sparc # include "stubRoutines_sparc.hpp" -#endif -#ifdef TARGET_ARCH_MODEL_zero +#elif defined TARGET_ARCH_MODEL_zero # include "stubRoutines_zero.hpp" -#endif -#ifdef TARGET_ARCH_MODEL_arm -# include "stubRoutines_arm.hpp" -#endif -#ifdef TARGET_ARCH_MODEL_ppc_32 -# include "stubRoutines_ppc_32.hpp" -#endif -#ifdef TARGET_ARCH_MODEL_ppc_64 +#elif defined TARGET_ARCH_MODEL_ppc_64 # include "stubRoutines_ppc_64.hpp" #endif - static jint _verify_oop_count; static address _verify_oop_subroutine_entry; diff -r c2687aa5e5ca -r 7eb99acd567f src/share/vm/runtime/thread.cpp --- a/src/share/vm/runtime/thread.cpp Mon Jan 25 14:56:57 2016 -0800 +++ b/src/share/vm/runtime/thread.cpp Mon Jan 25 14:57:27 2016 -0800 @@ -1510,6 +1510,7 @@ _thread_stat = new ThreadStatistics(); _blocked_on_compilation = false; _jni_active_critical = 0; + _pending_jni_exception_check_fn = NULL; _do_not_unlock_if_synchronized = false; _cached_monitor_info = NULL; _parker = Parker::Allocate(this) ; @@ -3372,6 +3373,9 @@ extern void JDK_Version_init(); + // Preinitialize version info. + VM_Version::early_initialize(); + // Check version if (!is_supported_jni_version(args->version)) return JNI_EVERSION; @@ -3768,9 +3772,6 @@ } } - // Give os specific code one last chance to start - os::init_3(); - create_vm_timer.end(); #ifdef ASSERT _vm_complete = true; diff -r c2687aa5e5ca -r 7eb99acd567f src/share/vm/runtime/thread.hpp --- a/src/share/vm/runtime/thread.hpp Mon Jan 25 14:56:57 2016 -0800 +++ b/src/share/vm/runtime/thread.hpp Mon Jan 25 14:57:27 2016 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 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 @@ -969,6 +969,9 @@ // support for JNI critical regions jint _jni_active_critical; // count of entries into JNI critical region + // Checked JNI: function name requires exception check + char* _pending_jni_exception_check_fn; + // For deadlock detection. int _depth_first_number; @@ -1478,6 +1481,12 @@ assert(_jni_active_critical >= 0, "JNI critical nesting problem?"); } + // Checked JNI, is the programmer required to check for exceptions, specify which function name + bool is_pending_jni_exception_check() const { return _pending_jni_exception_check_fn != NULL; } + void clear_pending_jni_exception_check() { _pending_jni_exception_check_fn = NULL; } + const char* get_pending_jni_exception_check() const { return _pending_jni_exception_check_fn; } + void set_pending_jni_exception_check(const char* fn_name) { _pending_jni_exception_check_fn = (char*) fn_name; } + // For deadlock detection int depth_first_number() { return _depth_first_number; } void set_depth_first_number(int dfn) { _depth_first_number = dfn; } diff -r c2687aa5e5ca -r 7eb99acd567f src/share/vm/runtime/vframe.cpp --- a/src/share/vm/runtime/vframe.cpp Mon Jan 25 14:56:57 2016 -0800 +++ b/src/share/vm/runtime/vframe.cpp Mon Jan 25 14:57:27 2016 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 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 @@ -148,8 +148,7 @@ if (obj.not_null()) { st->print("\t- %s <" INTPTR_FORMAT "> ", lock_state, (address)obj()); if (obj->klass() == SystemDictionary::Class_klass()) { - Klass* target_klass = java_lang_Class::as_Klass(obj()); - st->print_cr("(a java.lang.Class for %s)", InstanceKlass::cast(target_klass)->external_name()); + st->print_cr("(a java.lang.Class for %s)", java_lang_Class::as_external_name(obj())); } else { Klass* k = obj->klass(); st->print_cr("(a %s)", k->external_name()); @@ -189,6 +188,7 @@ if (monitor->eliminated() && is_compiled_frame()) { // Eliminated in compiled code if (monitor->owner_is_scalar_replaced()) { Klass* k = java_lang_Class::as_Klass(monitor->owner_klass()); + // format below for lockbits matches this one. st->print("\t- eliminated (a %s)", k->external_name()); } else { oop obj = monitor->owner(); @@ -206,9 +206,10 @@ // see if we have completed the lock or we are blocked trying to // acquire it - we can only be blocked if the monitor is inflated + markOop mark = NULL; const char *lock_state = "locked"; // assume we have the monitor locked if (!found_first_monitor && frame_count == 0) { - markOop mark = monitor->owner()->mark(); + mark = monitor->owner()->mark(); if (mark->has_monitor() && ( // we have marked ourself as pending on this monitor mark->monitor() == thread()->current_pending_monitor() || @@ -216,11 +217,19 @@ !mark->monitor()->is_entered(thread()) )) { lock_state = "waiting to lock"; + } else { + mark = NULL; // Disable printing below } } + print_locked_object_class_name(st, monitor->owner(), lock_state); + if (Verbose && mark != NULL) { + // match with format above, replacing "-" with " ". + st->print("\t lockbits="); + mark->print_on(st); + st->cr(); + } found_first_monitor = true; - print_locked_object_class_name(st, monitor->owner(), lock_state); } } } @@ -578,10 +587,15 @@ tty->print("( null )"); } else { monitor->owner()->print_value(); - tty->print("(" INTPTR_FORMAT ")", (address)monitor->owner()); + tty->print("(owner=" INTPTR_FORMAT ")", (address)monitor->owner()); } - if (monitor->eliminated() && is_compiled_frame()) - tty->print(" ( lock is eliminated )"); + if (monitor->eliminated()) { + if(is_compiled_frame()) { + tty->print(" ( lock is eliminated in compiled frame )"); + } else { + tty->print(" ( lock is eliminated, frame not compiled )"); + } + } tty->cr(); tty->print("\t "); monitor->lock()->print_on(tty); diff -r c2687aa5e5ca -r 7eb99acd567f src/share/vm/runtime/vframe.hpp --- a/src/share/vm/runtime/vframe.hpp Mon Jan 25 14:56:57 2016 -0800 +++ b/src/share/vm/runtime/vframe.hpp Mon Jan 25 14:57:27 2016 -0800 @@ -389,12 +389,12 @@ decode_offset < 0 || decode_offset >= nm()->scopes_data_size()) { // 6379830 AsyncGetCallTrace sometimes feeds us wild frames. - // If we attempt to read nmethod::scopes_data at serialized_null (== 0), - // or if we read some at other crazy offset, - // we will decode garbage and make wild references into the heap, - // leading to crashes in product mode. - // (This isn't airtight, of course, since there are internal - // offsets which are also crazy.) + // If we read nmethod::scopes_data at serialized_null (== 0) + // or if read some at other invalid offset, invalid values will be decoded. + // Based on these values, invalid heap locations could be referenced + // that could lead to crashes in product mode. + // Therefore, do not use the decode offset if invalid, but fill the frame + // as it were a native compiled frame (no Java-level assumptions). #ifdef ASSERT if (WizardMode) { tty->print_cr("Error in fill_from_frame: pc_desc for " @@ -514,9 +514,15 @@ intptr_t bcx = _frame.interpreter_frame_bcx(); int bci = method->validate_bci_from_bcx(bcx); // 6379830 AsyncGetCallTrace sometimes feeds us wild frames. + // AsyncGetCallTrace interrupts the VM asynchronously. As a result + // it is possible to access an interpreter frame for which + // no Java-level information is yet available (e.g., becasue + // the frame was being created when the VM interrupted it). + // In this scenario, pretend that the interpreter is at the point + // of entering the method. if (bci < 0) { found_bad_method_frame(); - bci = 0; // pretend it's on the point of entering + bci = 0; } _mode = interpreted_mode; _method = method; diff -r c2687aa5e5ca -r 7eb99acd567f src/share/vm/runtime/virtualspace.cpp --- a/src/share/vm/runtime/virtualspace.cpp Mon Jan 25 14:56:57 2016 -0800 +++ b/src/share/vm/runtime/virtualspace.cpp Mon Jan 25 14:57:27 2016 -0800 @@ -52,12 +52,22 @@ _alignment(0), _special(false), _executable(false) { } -ReservedSpace::ReservedSpace(size_t size) { - size_t page_size = os::page_size_for_region(size, size, 1); +ReservedSpace::ReservedSpace(size_t size, size_t preferred_page_size) { + bool has_preferred_page_size = preferred_page_size != 0; + // Want to use large pages where possible and pad with small pages. + size_t page_size = has_preferred_page_size ? preferred_page_size : os::page_size_for_region_unaligned(size, 1); bool large_pages = page_size != (size_t)os::vm_page_size(); - // Don't force the alignment to be large page aligned, - // since that will waste memory. - size_t alignment = os::vm_allocation_granularity(); + size_t alignment; + if (large_pages && has_preferred_page_size) { + alignment = MAX2(page_size, (size_t)os::vm_allocation_granularity()); + // ReservedSpace initialization requires size to be aligned to the given + // alignment. Align the size up. + size = align_size_up(size, alignment); + } else { + // Don't force the alignment to be large page aligned, + // since that will waste memory. + alignment = os::vm_allocation_granularity(); + } initialize(size, alignment, large_pages, NULL, 0, false); } @@ -372,7 +382,7 @@ bool VirtualSpace::initialize(ReservedSpace rs, size_t committed_size) { - const size_t max_commit_granularity = os::page_size_for_region(rs.size(), rs.size(), 1); + const size_t max_commit_granularity = os::page_size_for_region_unaligned(rs.size(), 1); return initialize_with_granularity(rs, committed_size, max_commit_granularity); } @@ -630,19 +640,7 @@ } if (pre_touch || AlwaysPreTouch) { - int vm_ps = os::vm_page_size(); - for (char* curr = previous_high; - curr < unaligned_new_high; - curr += vm_ps) { - // Note the use of a write here; originally we tried just a read, but - // since the value read was unused, the optimizer removed the read. - // If we ever have a concurrent touchahead thread, we'll want to use - // a read, to avoid the potential of overwriting data (if a mutator - // thread beats the touchahead thread to a page). There are various - // ways of making sure this read is not optimized away: for example, - // generating the code for a read procedure at runtime. - *curr = 0; - } + os::pretouch_memory(previous_high, unaligned_new_high); } _high += bytes; @@ -1007,7 +1005,7 @@ case Disable: return vs.initialize_with_granularity(rs, 0, os::vm_page_size()); case Commit: - return vs.initialize_with_granularity(rs, 0, os::page_size_for_region(rs.size(), rs.size(), 1)); + return vs.initialize_with_granularity(rs, 0, os::page_size_for_region_unaligned(rs.size(), 1)); } } diff -r c2687aa5e5ca -r 7eb99acd567f src/share/vm/runtime/virtualspace.hpp --- a/src/share/vm/runtime/virtualspace.hpp Mon Jan 25 14:56:57 2016 -0800 +++ b/src/share/vm/runtime/virtualspace.hpp Mon Jan 25 14:57:27 2016 -0800 @@ -54,7 +54,11 @@ public: // Constructor ReservedSpace(); - ReservedSpace(size_t size); + // Initialize the reserved space with the given size. If preferred_page_size + // is set, use this as minimum page size/alignment. This may waste some space + // if the given size is not aligned to that value, as the reservation will be + // aligned up to the final alignment in this case. + ReservedSpace(size_t size, size_t preferred_page_size = 0); ReservedSpace(size_t size, size_t alignment, bool large, char* requested_address = NULL, const size_t noaccess_prefix = 0); diff -r c2687aa5e5ca -r 7eb99acd567f src/share/vm/runtime/vmStructs.cpp --- a/src/share/vm/runtime/vmStructs.cpp Mon Jan 25 14:56:57 2016 -0800 +++ b/src/share/vm/runtime/vmStructs.cpp Mon Jan 25 14:57:27 2016 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 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 @@ -110,6 +110,7 @@ # include "jvmci/jvmciRuntime.hpp" # include "jvmci/vmStructs_jvmci.hpp" #endif + #ifdef TARGET_ARCH_x86 # include "vmStructs_x86.hpp" #endif @@ -174,6 +175,11 @@ #include "gc_implementation/parallelScavenge/vmStructs_parallelgc.hpp" #include "gc_implementation/g1/vmStructs_g1.hpp" #endif // INCLUDE_ALL_GCS + +#if INCLUDE_TRACE + #include "runtime/vmStructs_trace.hpp" +#endif + #ifdef COMPILER2 #include "opto/addnode.hpp" #include "opto/block.hpp" @@ -193,25 +199,17 @@ #include "opto/rootnode.hpp" #include "opto/subnode.hpp" #include "opto/vectornode.hpp" -#ifdef TARGET_ARCH_MODEL_x86_32 +#if defined ADGLOBALS_MD_HPP +# include ADGLOBALS_MD_HPP +#elif defined TARGET_ARCH_MODEL_x86_32 # include "adfiles/adGlobals_x86_32.hpp" -#endif -#ifdef TARGET_ARCH_MODEL_x86_64 +#elif defined TARGET_ARCH_MODEL_x86_64 # include "adfiles/adGlobals_x86_64.hpp" -#endif -#ifdef TARGET_ARCH_MODEL_sparc +#elif defined TARGET_ARCH_MODEL_sparc # include "adfiles/adGlobals_sparc.hpp" -#endif -#ifdef TARGET_ARCH_MODEL_zero +#elif defined TARGET_ARCH_MODEL_zero # include "adfiles/adGlobals_zero.hpp" -#endif -#ifdef TARGET_ARCH_MODEL_arm -# include "adfiles/adGlobals_arm.hpp" -#endif -#ifdef TARGET_ARCH_MODEL_ppc_32 -# include "adfiles/adGlobals_ppc_32.hpp" -#endif -#ifdef TARGET_ARCH_MODEL_ppc_64 +#elif defined TARGET_ARCH_MODEL_ppc_64 # include "adfiles/adGlobals_ppc_64.hpp" #endif #endif // COMPILER2 @@ -255,7 +253,6 @@ typedef Hashtable KlassHashtable; typedef HashtableEntry KlassHashtableEntry; typedef TwoOopHashtable SymbolTwoOopHashtable; -typedef BinaryTreeDictionary > MetablockTreeDictionary; //-------------------------------------------------------------------------------- // VM_STRUCTS @@ -1341,11 +1338,8 @@ volatile_nonstatic_field(FreeChunk, _size, size_t) \ nonstatic_field(FreeChunk, _next, FreeChunk*) \ nonstatic_field(FreeChunk, _prev, FreeChunk*) \ - nonstatic_field(FreeList, _size, size_t) \ - nonstatic_field(FreeList, _size, size_t) \ - nonstatic_field(FreeList, _count, ssize_t) \ - nonstatic_field(FreeList, _count, ssize_t) \ - nonstatic_field(MetablockTreeDictionary, _total_size, size_t) + nonstatic_field(AdaptiveFreeList, _size, size_t) \ + nonstatic_field(AdaptiveFreeList, _count, ssize_t) //-------------------------------------------------------------------------------- @@ -1437,6 +1431,8 @@ /* unsigned short on Win32 */ \ declare_unsigned_integer_type(u1) \ declare_unsigned_integer_type(u2) \ + declare_unsigned_integer_type(u4) \ + declare_unsigned_integer_type(u8) \ declare_unsigned_integer_type(unsigned) \ \ /*****************************/ \ @@ -2218,14 +2214,8 @@ \ /* freelist */ \ declare_toplevel_type(FreeChunk*) \ - declare_toplevel_type(Metablock*) \ - declare_toplevel_type(FreeBlockDictionary*) \ - declare_toplevel_type(FreeList*) \ - declare_toplevel_type(FreeList) \ - declare_toplevel_type(FreeBlockDictionary*) \ - declare_toplevel_type(FreeList*) \ - declare_toplevel_type(FreeList) \ - declare_type(MetablockTreeDictionary, FreeBlockDictionary) + declare_toplevel_type(AdaptiveFreeList*) \ + declare_toplevel_type(AdaptiveFreeList) //-------------------------------------------------------------------------------- @@ -3048,6 +3038,11 @@ GENERATE_STATIC_VM_STRUCT_ENTRY) #endif // INCLUDE_ALL_GCS +#if INCLUDE_TRACE + VM_STRUCTS_TRACE(GENERATE_NONSTATIC_VM_STRUCT_ENTRY, + GENERATE_STATIC_VM_STRUCT_ENTRY) +#endif + VM_STRUCTS_CPU(GENERATE_NONSTATIC_VM_STRUCT_ENTRY, GENERATE_STATIC_VM_STRUCT_ENTRY, GENERATE_UNCHECKED_NONSTATIC_VM_STRUCT_ENTRY, @@ -3098,6 +3093,11 @@ GENERATE_TOPLEVEL_VM_TYPE_ENTRY) #endif // INCLUDE_ALL_GCS +#if INCLUDE_TRACE + VM_TYPES_TRACE(GENERATE_VM_TYPE_ENTRY, + GENERATE_TOPLEVEL_VM_TYPE_ENTRY) +#endif + VM_TYPES_CPU(GENERATE_VM_TYPE_ENTRY, GENERATE_TOPLEVEL_VM_TYPE_ENTRY, GENERATE_OOP_VM_TYPE_ENTRY, @@ -3139,6 +3139,10 @@ VM_INT_CONSTANTS_PARNEW(GENERATE_VM_INT_CONSTANT_ENTRY) #endif // INCLUDE_ALL_GCS +#if INCLUDE_TRACE + VM_INT_CONSTANTS_TRACE(GENERATE_VM_INT_CONSTANT_ENTRY) +#endif + VM_INT_CONSTANTS_CPU(GENERATE_VM_INT_CONSTANT_ENTRY, GENERATE_PREPROCESSOR_VM_INT_CONSTANT_ENTRY, GENERATE_C1_VM_INT_CONSTANT_ENTRY, @@ -3201,8 +3205,14 @@ VM_STRUCTS_G1(CHECK_NONSTATIC_VM_STRUCT_ENTRY, CHECK_STATIC_VM_STRUCT_ENTRY); + #endif // INCLUDE_ALL_GCS +#if INCLUDE_TRACE + VM_STRUCTS_TRACE(CHECK_NONSTATIC_VM_STRUCT_ENTRY, + CHECK_STATIC_VM_STRUCT_ENTRY); +#endif + VM_STRUCTS_CPU(CHECK_NONSTATIC_VM_STRUCT_ENTRY, CHECK_STATIC_VM_STRUCT_ENTRY, CHECK_NO_OP, @@ -3241,8 +3251,14 @@ VM_TYPES_G1(CHECK_VM_TYPE_ENTRY, CHECK_SINGLE_ARG_VM_TYPE_NO_OP); + #endif // INCLUDE_ALL_GCS +#if INCLUDE_TRACE + VM_TYPES_TRACE(CHECK_VM_TYPE_ENTRY, + CHECK_SINGLE_ARG_VM_TYPE_NO_OP); +#endif + VM_TYPES_CPU(CHECK_VM_TYPE_ENTRY, CHECK_SINGLE_ARG_VM_TYPE_NO_OP, CHECK_SINGLE_ARG_VM_TYPE_NO_OP, @@ -3305,6 +3321,12 @@ debug_only(VM_STRUCTS_G1(ENSURE_FIELD_TYPE_PRESENT, ENSURE_FIELD_TYPE_PRESENT)); #endif // INCLUDE_ALL_GCS + +#if INCLUDE_TRACE + debug_only(VM_STRUCTS_TRACE(ENSURE_FIELD_TYPE_PRESENT, + ENSURE_FIELD_TYPE_PRESENT)); +#endif + debug_only(VM_STRUCTS_CPU(ENSURE_FIELD_TYPE_PRESENT, ENSURE_FIELD_TYPE_PRESENT, CHECK_NO_OP, diff -r c2687aa5e5ca -r 7eb99acd567f src/share/vm/runtime/vmStructs_trace.hpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/share/vm/runtime/vmStructs_trace.hpp Mon Jan 25 14:57:27 2016 -0800 @@ -0,0 +1,35 @@ +/* + * Copyright (c) 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 + * 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_RUNTIME_VMSTRUCTS_TRACE_HPP +#define SHARE_VM_RUNTIME_VMSTRUCTS_TRACE_HPP + +#define VM_INT_CONSTANTS_TRACE(a) + +#define VM_STRUCTS_TRACE(a, b) + +#define VM_TYPES_TRACE(a, b) + + +#endif // SHARE_VM_RUNTIME_VMSTRUCTS_TRACE_HPP diff -r c2687aa5e5ca -r 7eb99acd567f src/share/vm/runtime/vm_version.cpp --- a/src/share/vm/runtime/vm_version.cpp Mon Jan 25 14:56:57 2016 -0800 +++ b/src/share/vm/runtime/vm_version.cpp Mon Jan 25 14:57:27 2016 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 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 @@ -185,17 +185,17 @@ AIX_ONLY("aix") \ BSD_ONLY("bsd") +#ifndef CPU #ifdef ZERO #define CPU ZERO_LIBARCH #else #define CPU IA32_ONLY("x86") \ IA64_ONLY("ia64") \ AMD64_ONLY("amd64") \ - ARM_ONLY("arm") \ - PPC32_ONLY("ppc") \ PPC64_ONLY("ppc64") \ SPARC_ONLY("sparc") #endif // ZERO +#endif const char *Abstract_VM_Version::vm_platform_string() { return OS "-" CPU; @@ -256,12 +256,6 @@ #ifndef FLOAT_ARCH #if defined(__SOFTFP__) #define FLOAT_ARCH_STR "-sflt" - #elif defined(E500V2) - #define FLOAT_ARCH_STR "-e500v2" - #elif defined(ARM) - #define FLOAT_ARCH_STR "-vfp" - #elif defined(PPC32) - #define FLOAT_ARCH_STR "-hflt" #else #define FLOAT_ARCH_STR "" #endif diff -r c2687aa5e5ca -r 7eb99acd567f src/share/vm/runtime/vm_version.hpp --- a/src/share/vm/runtime/vm_version.hpp Mon Jan 25 14:56:57 2016 -0800 +++ b/src/share/vm/runtime/vm_version.hpp Mon Jan 25 14:57:27 2016 -0800 @@ -56,6 +56,13 @@ public: static void initialize(); + // This allows for early initialization of VM_Version information + // that may be needed later in the initialization sequence but before + // full VM_Version initialization is possible. It can not depend on any + // other part of the VM being initialized when called. Platforms that + // need to specialize this define VM_Version::early_initialize(). + static void early_initialize() { } + // Name static const char* vm_name(); // Vendor diff -r c2687aa5e5ca -r 7eb99acd567f src/share/vm/services/classLoadingService.cpp diff -r c2687aa5e5ca -r 7eb99acd567f src/share/vm/services/management.cpp --- a/src/share/vm/services/management.cpp Mon Jan 25 14:56:57 2016 -0800 +++ b/src/share/vm/services/management.cpp Mon Jan 25 14:57:27 2016 -0800 @@ -155,11 +155,14 @@ // Load and initialize the sun.management.Agent class // invoke startAgent method to start the management server Handle loader = Handle(THREAD, SystemDictionary::java_system_loader()); - Klass* k = SystemDictionary::resolve_or_fail(vmSymbols::sun_management_Agent(), + Klass* k = SystemDictionary::resolve_or_null(vmSymbols::sun_management_Agent(), loader, Handle(), - true, - CHECK); + THREAD); + if (k == NULL) { + vm_exit_during_initialization("Management agent initialization failure: " + "class sun.management.Agent not found."); + } instanceKlassHandle ik (THREAD, k); JavaValue result(T_VOID); diff -r c2687aa5e5ca -r 7eb99acd567f src/share/vm/trace/trace.xml --- a/src/share/vm/trace/trace.xml Mon Jan 25 14:56:57 2016 -0800 +++ b/src/share/vm/trace/trace.xml Mon Jan 25 14:57:27 2016 -0800 @@ -1,6 +1,6 @@ print_cr(" pm(int pc) - print Method* given compiled PC"); tty->print_cr(" findm(intptr_t pc) - finds Method*"); tty->print_cr(" find(intptr_t x) - finds & prints nmethod/stub/bytecode/oop based on pointer into it"); + tty->print_cr(" pns(void* sp, void* fp, void* pc) - print native (i.e. mixed) stack trace. E.g."); + tty->print_cr(" pns($sp, $rbp, $pc) on Linux/amd64 and Solaris/amd64 or"); + tty->print_cr(" pns($sp, $ebp, $pc) on Linux/x86 or"); + tty->print_cr(" pns($sp, 0, $pc) on Linux/ppc64 or"); + tty->print_cr(" pns($sp + 0x7ff, 0, $pc) on Solaris/SPARC"); + tty->print_cr(" - in gdb do 'set overload-resolution off' before calling pns()"); + tty->print_cr(" - in dbx do 'frame 1' before calling pns()"); tty->print_cr("misc."); tty->print_cr(" flush() - flushes the log file"); @@ -678,3 +685,56 @@ } #endif // !PRODUCT + +void print_native_stack(outputStream* st, frame fr, Thread* t, char* buf, int buf_size) { + + // see if it's a valid frame + if (fr.pc()) { + st->print_cr("Native frames: (J=compiled Java code, j=interpreted, Vv=VM code, C=native code)"); + + int count = 0; + while (count++ < StackPrintLimit) { + fr.print_on_error(st, buf, buf_size); + st->cr(); + // Compiled code may use EBP register on x86 so it looks like + // non-walkable C frame. Use frame.sender() for java frames. + if (t && t->is_Java_thread()) { + // Catch very first native frame by using stack address. + // For JavaThread stack_base and stack_size should be set. + if (!t->on_local_stack((address)(fr.real_fp() + 1))) { + break; + } + if (fr.is_java_frame() || fr.is_native_frame() || fr.is_runtime_frame()) { + RegisterMap map((JavaThread*)t, false); // No update + fr = fr.sender(&map); + } else { + fr = os::get_sender_for_C_frame(&fr); + } + } else { + // is_first_C_frame() does only simple checks for frame pointer, + // it will pass if java compiled code has a pointer in EBP. + if (os::is_first_C_frame(&fr)) break; + fr = os::get_sender_for_C_frame(&fr); + } + } + + if (count > StackPrintLimit) { + st->print_cr("......"); + } + + st->cr(); + } +} + +#ifndef PRODUCT + +extern "C" void pns(void* sp, void* fp, void* pc) { // print native stack + Command c("pns"); + static char buf[O_BUFLEN]; + Thread* t = ThreadLocalStorage::get_thread_slow(); + // Call generic frame constructor (certain arguments may be ignored) + frame fr(sp, fp, pc); + print_native_stack(tty, fr, t, buf, sizeof(buf)); +} + +#endif // !PRODUCT diff -r c2687aa5e5ca -r 7eb99acd567f src/share/vm/utilities/debug.hpp --- a/src/share/vm/utilities/debug.hpp Mon Jan 25 14:56:57 2016 -0800 +++ b/src/share/vm/utilities/debug.hpp Mon Jan 25 14:57:27 2016 -0800 @@ -265,4 +265,7 @@ void pd_ps(frame f); void pd_obfuscate_location(char *buf, size_t buflen); +class outputStream; +void print_native_stack(outputStream* st, frame fr, Thread* t, char* buf, int buf_size); + #endif // SHARE_VM_UTILITIES_DEBUG_HPP diff -r c2687aa5e5ca -r 7eb99acd567f src/share/vm/utilities/elfFile.cpp --- a/src/share/vm/utilities/elfFile.cpp Mon Jan 25 14:56:57 2016 -0800 +++ b/src/share/vm/utilities/elfFile.cpp Mon Jan 25 14:57:27 2016 -0800 @@ -261,7 +261,12 @@ } } } +// AARCH64 defaults to noexecstack. All others default to execstack. +#ifdef AARCH64 + return true; +#else return false; +#endif } #endif diff -r c2687aa5e5ca -r 7eb99acd567f src/share/vm/utilities/globalDefinitions_gcc.hpp --- a/src/share/vm/utilities/globalDefinitions_gcc.hpp Mon Jan 25 14:56:57 2016 -0800 +++ b/src/share/vm/utilities/globalDefinitions_gcc.hpp Mon Jan 25 14:57:27 2016 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 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 @@ -44,14 +44,6 @@ #endif // SOLARIS #include -#ifndef FP_PZERO -// Linux doesn't have positive/negative zero -#define FP_PZERO FP_ZERO -#endif -#if (!defined fpclass) && ((!defined SPARC) || (!defined SOLARIS)) -#define fpclass fpclassify -#endif - #include #include #include @@ -220,7 +212,7 @@ #define DEBUG_EXCEPTION ::abort(); -#ifdef ARM +#ifdef ARM32 #ifdef SOLARIS #define BREAKPOINT __asm__ volatile (".long 0xe1200070") #else diff -r c2687aa5e5ca -r 7eb99acd567f src/share/vm/utilities/globalDefinitions_sparcWorks.hpp --- a/src/share/vm/utilities/globalDefinitions_sparcWorks.hpp Mon Jan 25 14:56:57 2016 -0800 +++ b/src/share/vm/utilities/globalDefinitions_sparcWorks.hpp Mon Jan 25 14:57:27 2016 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2011, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 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 @@ -48,15 +48,6 @@ # include #endif # include -#ifdef LINUX -#ifndef FP_PZERO - // Linux doesn't have positive/negative zero - #define FP_PZERO FP_ZERO -#endif -#ifndef fpclass - #define fpclass fpclassify -#endif -#endif # include # include # include diff -r c2687aa5e5ca -r 7eb99acd567f src/share/vm/utilities/globalDefinitions_xlc.hpp --- a/src/share/vm/utilities/globalDefinitions_xlc.hpp Mon Jan 25 14:56:57 2016 -0800 +++ b/src/share/vm/utilities/globalDefinitions_xlc.hpp Mon Jan 25 14:57:27 2016 -0800 @@ -41,14 +41,6 @@ #include #include -#ifndef FP_PZERO -// Linux doesn't have positive/negative zero -#define FP_PZERO FP_ZERO -#endif -#if (!defined fpclass) -#define fpclass fpclassify -#endif - #include #include #include diff -r c2687aa5e5ca -r 7eb99acd567f src/share/vm/utilities/macros.hpp --- a/src/share/vm/utilities/macros.hpp Mon Jan 25 14:56:57 2016 -0800 +++ b/src/share/vm/utilities/macros.hpp Mon Jan 25 14:57:27 2016 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 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 @@ -422,7 +422,6 @@ #define NOT_E500V2(code) code #endif - #ifdef ARM #define ARM_ONLY(code) code #define NOT_ARM(code) @@ -431,6 +430,14 @@ #define NOT_ARM(code) code #endif +#ifdef ARM32 +#define ARM32_ONLY(code) code +#define NOT_ARM32(code) +#else +#define ARM32_ONLY(code) +#define NOT_ARM32(code) code +#endif + #ifdef JAVASE_EMBEDDED #define EMBEDDED_ONLY(code) code #define NOT_EMBEDDED(code) diff -r c2687aa5e5ca -r 7eb99acd567f src/share/vm/utilities/vmError.cpp --- a/src/share/vm/utilities/vmError.cpp Mon Jan 25 14:56:57 2016 -0800 +++ b/src/share/vm/utilities/vmError.cpp Mon Jan 25 14:57:27 2016 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 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 @@ -602,7 +602,7 @@ STEP(120, "(printing native stack)" ) - if (_verbose) { + if (_verbose) { if (os::platform_print_native_stack(st, _context, buf, sizeof(buf))) { // We have printed the native stack in platform-specific code // Windows/x64 needs special handling. @@ -610,43 +610,7 @@ frame fr = _context ? os::fetch_frame_from_context(_context) : os::current_frame(); - // see if it's a valid frame - if (fr.pc()) { - st->print_cr("Native frames: (J=compiled Java code, j=interpreted, Vv=VM code, C=native code)"); - - - int count = 0; - while (count++ < StackPrintLimit) { - fr.print_on_error(st, buf, sizeof(buf)); - st->cr(); - // Compiled code may use EBP register on x86 so it looks like - // non-walkable C frame. Use frame.sender() for java frames. - if (_thread && _thread->is_Java_thread()) { - // Catch very first native frame by using stack address. - // For JavaThread stack_base and stack_size should be set. - if (!_thread->on_local_stack((address)(fr.sender_sp() + 1))) { - break; - } - if (fr.is_java_frame()) { - RegisterMap map((JavaThread*)_thread, false); // No update - fr = fr.sender(&map); - } else { - fr = os::get_sender_for_C_frame(&fr); - } - } else { - // is_first_C_frame() does only simple checks for frame pointer, - // it will pass if java compiled code has a pointer in EBP. - if (os::is_first_C_frame(&fr)) break; - fr = os::get_sender_for_C_frame(&fr); - } - } - - if (count > StackPrintLimit) { - st->print_cr("......"); - } - - st->cr(); - } + print_native_stack(st, fr, _thread, buf, sizeof(buf)); } } @@ -1075,7 +1039,9 @@ out.print_raw (cmd); out.print_raw_cr("\" ..."); - os::fork_and_exec(cmd); + if (os::fork_and_exec(cmd) < 0) { + out.print_cr("os::fork_and_exec failed: %s (%d)", strerror(errno), errno); + } } // done with OnError @@ -1160,7 +1126,9 @@ #endif tty->print_cr("\"%s\"...", cmd); - os::fork_and_exec(cmd); + if (os::fork_and_exec(cmd) < 0) { + tty->print_cr("os::fork_and_exec failed: %s (%d)", strerror(errno), errno); + } } } diff -r c2687aa5e5ca -r 7eb99acd567f test/TEST.groups --- a/test/TEST.groups Mon Jan 25 14:56:57 2016 -0800 +++ b/test/TEST.groups Mon Jan 25 14:57:27 2016 -0800 @@ -132,7 +132,8 @@ sanity/ExecuteInternalVMTests.java hotspot_gc = \ - sanity/ExecuteInternalVMTests.java + sanity/ExecuteInternalVMTests.java \ + -gc/g1/TestGreyReclaimedHumongousObjects.java hotspot_runtime = \ sanity/ExecuteInternalVMTests.java @@ -148,6 +149,8 @@ # Tests that require compact3 API's # needs_compact3 = \ + compiler/jsr292/RedefineMethodUsedByMultipleMethodHandles.java \ + compiler/rangechecks/TestRangeCheckSmearing.java \ compiler/whitebox/DeoptimizeMethodTest.java \ compiler/whitebox/SetForceInlineMethodTest.java \ compiler/whitebox/SetDontInlineMethodTest.java \ @@ -158,6 +161,7 @@ compiler/whitebox/IsMethodCompilableTest.java \ gc/6581734/Test6581734.java \ gc/7072527/TestFullGCCount.java \ + gc/TestGCLogRotationViaJcmd.java \ gc/g1/TestHumongousAllocInitialMark.java \ gc/g1/TestHumongousShrinkHeap.java \ gc/arguments/TestG1HeapRegionSize.java \ @@ -176,6 +180,7 @@ serviceability/threads/TestFalseDeadLock.java \ serviceability/jvmti/GetObjectSizeOverflow.java \ serviceability/jvmti/TestRedefineWithUnresolvedClass.java \ + serviceability/sa/jmap-hashcode/Test8028623.java \ compiler/tiered/NonTieredLevelsTest.java \ compiler/tiered/TieredLevelsTest.java \ compiler/intrinsics/bmi/verifycode diff -r c2687aa5e5ca -r 7eb99acd567f test/compiler/codegen/IntRotateWithImmediate.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/compiler/codegen/IntRotateWithImmediate.java Mon Jan 25 14:57:27 2016 -0800 @@ -0,0 +1,64 @@ +/* + * Copyright 2015 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 + * 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 8080190 + * @key regression + * @summary Test that the rotate distance used in the rotate instruction is properly masked with 0x1f + * @run main/othervm -Xbatch -XX:-UseOnStackReplacement IntRotateWithImmediate + * @author volker.simonis@gmail.com + */ + +public class IntRotateWithImmediate { + + // This is currently the same as Integer.rotateRight() + static int rotateRight(int i, int distance) { + // On some architectures (i.e. x86_64 and ppc64) the following computation is + // matched in the .ad file into a single MachNode which emmits a single rotate + // machine instruction. It is important that the shift amount is masked to match + // corresponding immediate width in the native instruction. On x86_64 the rotate + // left instruction ('rol') encodes an 8-bit immediate while the corresponding + // 'rotlwi' instruction on Power only encodes a 5-bit immediate. + return ((i >>> distance) | (i << -distance)); + } + + static int compute(int x) { + return rotateRight(x, 3); + } + + public static void main(String args[]) { + int val = 4096; + + int firstResult = compute(val); + + for (int i = 0; i < 100000; i++) { + int newResult = compute(val); + if (firstResult != newResult) { + throw new InternalError(firstResult + " != " + newResult); + } + } + System.out.println("OK"); + } + +} diff -r c2687aa5e5ca -r 7eb99acd567f test/compiler/codegen/LoadWithMask.java --- a/test/compiler/codegen/LoadWithMask.java Mon Jan 25 14:56:57 2016 -0800 +++ b/test/compiler/codegen/LoadWithMask.java Mon Jan 25 14:57:27 2016 -0800 @@ -25,7 +25,7 @@ * @test * @bug 8032207 * @summary Invalid node sizing for loadUS2L_immI16 and loadI2L_immI - * @run main/othervm -server -Xbatch -XX:-TieredCompilation -XX:CompileCommand=compileonly,LoadWithMask.foo LoadWithMask + * @run main/othervm -Xbatch -XX:CompileCommand=compileonly,LoadWithMask.foo LoadWithMask * */ public class LoadWithMask { diff -r c2687aa5e5ca -r 7eb99acd567f test/compiler/codegen/LoadWithMask2.java --- a/test/compiler/codegen/LoadWithMask2.java Mon Jan 25 14:56:57 2016 -0800 +++ b/test/compiler/codegen/LoadWithMask2.java Mon Jan 25 14:57:27 2016 -0800 @@ -25,7 +25,7 @@ * @test * @bug 8031743 * @summary loadI2L_immI broken for negative memory values - * @run main/othervm -server -Xbatch -XX:-TieredCompilation -XX:CompileCommand=compileonly,*.foo* LoadWithMask2 + * @run main/othervm -Xbatch -XX:CompileCommand=compileonly,*.foo* LoadWithMask2 * */ public class LoadWithMask2 { diff -r c2687aa5e5ca -r 7eb99acd567f test/compiler/escapeAnalysis/TestEscapeThroughInvoke.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/compiler/escapeAnalysis/TestEscapeThroughInvoke.java Mon Jan 25 14:57:27 2016 -0800 @@ -0,0 +1,74 @@ +/* + * Copyright (c) 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 + * 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 8073956 + * @summary Tests C2 EA with allocated object escaping through a call. + * @run main/othervm -XX:CompileCommand=dontinline,TestEscapeThroughInvoke::create TestEscapeThroughInvoke + */ +public class TestEscapeThroughInvoke { + private A a; + + public static void main(String[] args) { + TestEscapeThroughInvoke test = new TestEscapeThroughInvoke(); + test.a = new A(42); + // Make sure run gets compiled by C2 + for (int i = 0; i < 100_000; ++i) { + test.run(); + } + } + + private void run() { + // Allocate something to trigger EA + new Object(); + // Create a new escaping instance of A and + // verify that it is always equal to 'a.saved'. + A escapingA = create(42); + a.check(escapingA); + } + + // Create and return a new instance of A that escaped through 'A::saveInto'. + // The 'dummy' parameters are needed to avoid EA skipping the methods. + private A create(Integer dummy) { + A result = new A(dummy); + result.saveInto(a, dummy); // result escapes into 'a' here + return result; + } +} + +class A { + private A saved; + + public A(Integer dummy) { } + + public void saveInto(A other, Integer dummy) { + other.saved = this; + } + + public void check(A other) { + if (this.saved != other) { + throw new RuntimeException("TEST FAILED: Objects not equal."); + } + } +} diff -r c2687aa5e5ca -r 7eb99acd567f test/compiler/jsr292/MHInlineTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/compiler/jsr292/MHInlineTest.java Mon Jan 25 14:57:27 2016 -0800 @@ -0,0 +1,207 @@ +/* + * Copyright (c) 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 + * 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 8062280 + * @summary C2: inlining failure due to access checks being too strict + * @library /testlibrary + * @run main/othervm MHInlineTest + */ +import java.lang.invoke.*; +import com.oracle.java.testlibrary.*; +import static com.oracle.java.testlibrary.Asserts.*; + +public class MHInlineTest { + public static void main(String[] args) throws Exception { + ProcessBuilder pb = ProcessTools.createJavaProcessBuilder( + "-XX:+IgnoreUnrecognizedVMOptions", "-showversion", + "-server", "-XX:-TieredCompilation", "-Xbatch", + "-XX:+PrintCompilation", "-XX:+UnlockDiagnosticVMOptions", "-XX:+PrintInlining", + "-XX:CompileCommand=dontinline,MHInlineTest::test*", + "MHInlineTest$Launcher"); + + OutputAnalyzer analyzer = new OutputAnalyzer(pb.start()); + + analyzer.shouldHaveExitValue(0); + + // The test is applicable only to C2 (present in Server VM). + if (analyzer.getStderr().contains("Server VM")) { + analyzer.shouldContain("MHInlineTest$B::public_x (3 bytes) inline (hot)"); + analyzer.shouldContain( "MHInlineTest$B::protected_x (3 bytes) inline (hot)"); + analyzer.shouldContain( "MHInlineTest$B::package_x (3 bytes) inline (hot)"); + analyzer.shouldContain("MHInlineTest$A::package_final_x (3 bytes) inline (hot)"); + analyzer.shouldContain("MHInlineTest$B::private_x (3 bytes) inline (hot)"); + analyzer.shouldContain("MHInlineTest$B::private_static_x (3 bytes) inline (hot)"); + analyzer.shouldContain("MHInlineTest$A::package_static_x (3 bytes) inline (hot)"); + + analyzer.shouldNotContain("MHInlineTest$A::protected_x (3 bytes) virtual call"); + analyzer.shouldNotContain("MHInlineTest$A::package_x (3 bytes) virtual call"); + } + } + + static class A { + public static final MethodHandles.Lookup LOOKUP = MethodHandles.lookup(); + + public Class public_x() { return A.class; } + protected Class protected_x() { return A.class; } + Class package_x() { return A.class; } + final Class package_final_x() { return A.class; } + + static Class package_static_x() { return A.class; } + } + + static class B extends A { + public static final MethodHandles.Lookup LOOKUP = MethodHandles.lookup(); + + @Override public Class public_x() { return B.class; } + @Override protected Class protected_x() { return B.class; } + @Override Class package_x() { return B.class; } + + private Class private_x() { return B.class; } + static Class private_static_x() { return B.class; } + } + + static final MethodHandle A_PUBLIC_X; + static final MethodHandle A_PROTECTED_X; + static final MethodHandle A_PACKAGE_X; + static final MethodHandle A_PACKAGE_STATIC_X; + static final MethodHandle A_PACKAGE_FINAL_X; + + static final MethodHandle B_PRIVATE_X; + static final MethodHandle B_PRIVATE_STATIC_X; + + static { + try { + MethodHandles.Lookup LOOKUP = MethodHandles.lookup(); + + A_PUBLIC_X = LOOKUP.findVirtual( + A.class, "public_x", MethodType.methodType(Class.class)); + A_PROTECTED_X = LOOKUP.findVirtual( + A.class, "protected_x", MethodType.methodType(Class.class)); + A_PACKAGE_X = LOOKUP.findVirtual( + A.class, "package_x", MethodType.methodType(Class.class)); + A_PACKAGE_FINAL_X = LOOKUP.findVirtual( + A.class, "package_final_x", MethodType.methodType(Class.class)); + A_PACKAGE_STATIC_X = LOOKUP.findStatic( + A.class, "package_static_x", MethodType.methodType(Class.class)); + + B_PRIVATE_X = B.LOOKUP.findVirtual( + B.class, "private_x", MethodType.methodType(Class.class)); + B_PRIVATE_STATIC_X = B.LOOKUP.findStatic( + B.class, "private_static_x", MethodType.methodType(Class.class)); + } catch (Exception e) { + throw new Error(e); + } + } + + static final A a = new B(); + + private static void testPublicMH() { + try { + Class r = (Class)A_PUBLIC_X.invokeExact(a); + assertEquals(r, B.class); + } catch (Throwable throwable) { + throw new Error(throwable); + } + } + + private static void testProtectedMH() { + try { + Class r = (Class)A_PROTECTED_X.invokeExact(a); + assertEquals(r, B.class); + } catch (Throwable throwable) { + throw new Error(throwable); + } + } + + private static void testPackageMH() { + try { + Class r = (Class)A_PACKAGE_X.invokeExact(a); + assertEquals(r, B.class); + } catch (Throwable throwable) { + throw new Error(throwable); + } + } + + private static void testPackageFinalMH() { + try { + Class r = (Class)A_PACKAGE_FINAL_X.invokeExact(a); + assertEquals(r, A.class); + } catch (Throwable throwable) { + throw new Error(throwable); + } + } + + private static void testPackageStaticMH() { + try { + Class r = (Class)A_PACKAGE_STATIC_X.invokeExact(); + assertEquals(r, A.class); + } catch (Throwable throwable) { + throw new Error(throwable); + } + } + + private static void testPrivateMH() { + try { + Class r = (Class)B_PRIVATE_X.invokeExact((B)a); + assertEquals(r, B.class); + } catch (Throwable throwable) { + throw new Error(throwable); + } + } + + private static void testPrivateStaticMH() { + try { + Class r = (Class)B_PRIVATE_STATIC_X.invokeExact(); + assertEquals(r, B.class); + } catch (Throwable throwable) { + throw new Error(throwable); + } + } + static class Launcher { + public static void main(String[] args) throws Exception { + for (int i = 0; i < 20_000; i++) { + testPublicMH(); + } + for (int i = 0; i < 20_000; i++) { + testProtectedMH(); + } + for (int i = 0; i < 20_000; i++) { + testPackageMH(); + } + for (int i = 0; i < 20_000; i++) { + testPackageFinalMH(); + } + for (int i = 0; i < 20_000; i++) { + testPackageStaticMH(); + } + for (int i = 0; i < 20_000; i++) { + testPrivateMH(); + } + for (int i = 0; i < 20_000; i++) { + testPrivateStaticMH(); + } + } + } +} diff -r c2687aa5e5ca -r 7eb99acd567f test/compiler/jsr292/PollutedTrapCounts.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/compiler/jsr292/PollutedTrapCounts.java Mon Jan 25 14:57:27 2016 -0800 @@ -0,0 +1,109 @@ +/* + * Copyright (c) 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 + * 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 8074551 + * @library /testlibrary + * @run main PollutedTrapCounts + */ +import java.lang.invoke.*; +import com.oracle.java.testlibrary.*; + +public class PollutedTrapCounts { + public static void main(String[] args) throws Exception { + ProcessBuilder pb = ProcessTools.createJavaProcessBuilder( + "-XX:+IgnoreUnrecognizedVMOptions", + "-XX:-TieredCompilation", "-Xbatch", + "-XX:PerBytecodeRecompilationCutoff=10", "-XX:PerMethodRecompilationCutoff=10", + "-XX:+PrintCompilation", "-XX:+UnlockDiagnosticVMOptions", "-XX:+PrintInlining", + "PollutedTrapCounts$Test"); + + OutputAnalyzer analyzer = new OutputAnalyzer(pb.start()); + + analyzer.shouldHaveExitValue(0); + + analyzer.shouldNotContain("not compilable (disabled)"); + } + + static class Test { + public static final MethodHandle test1; + public static final MethodHandle test2; + public static final MethodHandle empty; + + static { + try { + Class THIS_CLASS = Test.class; + MethodHandles.Lookup LOOKUP = MethodHandles.lookup(); + test1 = LOOKUP.findStatic(THIS_CLASS, "test1", MethodType.methodType(boolean.class, boolean.class)); + test2 = LOOKUP.findStatic(THIS_CLASS, "test2", MethodType.methodType(boolean.class, boolean.class)); + empty = LOOKUP.findStatic(THIS_CLASS, "empty", MethodType.methodType(void.class, boolean.class)); + } catch(Throwable e) { + throw new Error(e); + } + } + + static boolean test1(boolean b) { + return b; + } + static boolean test2(boolean b) { + return true; + } + static void empty(boolean b) {} + + static void test(boolean freqValue, boolean removeInlineBlocker) throws Throwable { + MethodHandle innerGWT = MethodHandles.guardWithTest(test1, empty, empty); + MethodHandle outerGWT = MethodHandles.guardWithTest(test2, innerGWT, innerGWT); + + // Trigger compilation + for (int i = 0; i < 20_000; i++) { + outerGWT.invokeExact(freqValue); + } + + // Trigger deopt & nmethod invalidation + outerGWT.invokeExact(!freqValue); + + // Force inline blocker removal on rare-taken path + if (removeInlineBlocker) { + for (int i = 0; i < 100; i++) { + outerGWT.invokeExact(!freqValue); + } + } + + // Trigger recompilation + for (int i = 0; i < 20_000; i++) { + outerGWT.invokeExact(freqValue); + } + } + + public static void main(String[] args) throws Throwable { + boolean freqValue = true; + boolean removeInlineBlocker = false; + for (int i = 0; i < 20; i++) { + test(freqValue, removeInlineBlocker); + freqValue = !freqValue; + removeInlineBlocker = !removeInlineBlocker; + } + } + } +} diff -r c2687aa5e5ca -r 7eb99acd567f test/compiler/loopopts/ConstFPVectorization.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/compiler/loopopts/ConstFPVectorization.java Mon Jan 25 14:57:27 2016 -0800 @@ -0,0 +1,63 @@ +/* + * Copyright (c) 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 + * 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 8074869 + * @summary C2 code generator can replace -0.0f with +0.0f on Linux + * @run main ConstFPVectorization 8 + * @author volker.simonis@gmail.com + * + */ + +public class ConstFPVectorization { + + static float[] f = new float[16]; + static double[] d = new double[16]; + + static void floatLoop(int count) { + for (int i = 0; i < count; i++) { + f[i] = -0.0f; + } + } + + static void doubleLoop(int count) { + for (int i = 0; i < count; i++) { + d[i] = -0.0d; + } + } + + public static void main(String args[]) { + for (int i = 0; i < 10_000; i++) { + floatLoop(Integer.parseInt(args[0])); + doubleLoop(Integer.parseInt(args[0])); + } + for (int i = 0; i < Integer.parseInt(args[0]); i++) { + if (Float.floatToRawIntBits(f[i]) != Float.floatToRawIntBits(-0.0f)) + throw new Error("Float error at index " + i); + if (Double.doubleToRawLongBits(d[i]) != Double.doubleToRawLongBits(-0.0d)) + throw new Error("Double error at index " + i); + } + } +} diff -r c2687aa5e5ca -r 7eb99acd567f test/compiler/loopopts/CountedLoopProblem.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/compiler/loopopts/CountedLoopProblem.java Mon Jan 25 14:57:27 2016 -0800 @@ -0,0 +1,54 @@ +/* + * Copyright (c) 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 + * 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 8072753 + * @summary Inner loop induction variable increment occurs before compare which causes integer overflow + * @run main/othervm CountedLoopProblem + * + */ + +import java.util.*; + +public class CountedLoopProblem { + public static void main(String[] args) throws Exception { + Random r = new Random(42); + int x = 0; + StringBuilder sb = new StringBuilder(); + for(int i = 0; i < 1000000; ++i) { + int v = Math.abs(r.nextInt()); + sb.append('+').append(v).append('\n'); + x += v; + // To trigger the problem we must OSR in the following loop + // To make the problem 100% reproducible run with -XX:-TieredCompilation -XX:OSROnlyBCI=62 + while(x < 0) x += 1000000000; + sb.append('=').append(x).append('\n'); + } + if (sb.toString().hashCode() != 0xaba94591) { + throw new Exception("Unexpected result"); + } + } +} + diff -r c2687aa5e5ca -r 7eb99acd567f test/compiler/loopopts/superword/TestVectorizationWithInvariant.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/compiler/loopopts/superword/TestVectorizationWithInvariant.java Mon Jan 25 14:57:27 2016 -0800 @@ -0,0 +1,144 @@ +/* + * Copyright (c) 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 + * 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.*; +import sun.misc.Unsafe; + +/** + * @test + * @bug 8078497 + * @summary Tests correct alignment of vectors with loop invariant offset. + * @library /testlibrary + * @run main TestVectorizationWithInvariant + */ +public class TestVectorizationWithInvariant { + + private static Unsafe unsafe; + private static final long BYTE_ARRAY_OFFSET; + private static final long CHAR_ARRAY_OFFSET; + + static { + unsafe = Utils.getUnsafe(); + BYTE_ARRAY_OFFSET = unsafe.arrayBaseOffset(byte[].class); + CHAR_ARRAY_OFFSET = unsafe.arrayBaseOffset(char[].class); + } + + public static void main(String[] args) throws Exception { + byte[] byte_array1 = new byte[1000]; + byte[] byte_array2 = new byte[1000]; + char[] char_array = new char[1000]; + + for (int i = 0; i < 20_000; ++i) { + copyByteToChar(byte_array1, byte_array2, char_array, 1); + copyCharToByte(char_array, byte_array1, 1); + copyCharToByteAligned(char_array, byte_array1); + copyCharToByteUnaligned(char_array, byte_array1); + } + } + + /* + * Copy multiple consecutive chars from a byte array to a given offset in a char array + * to trigger C2's superword optimization. The offset in the byte array is independent + * of the loop induction variable and can be set to an arbitrary value. It may then not + * be possible to both align the LoadUS and the StoreC operations. Therefore, vectorization + * should only be done in this case if unaligned memory accesses are allowed. + */ + public static void copyByteToChar(byte[] src1, byte[] src2, char[] dst, int off) { + off = (int) BYTE_ARRAY_OFFSET + (off << 1); + byte[] src = src1; + for (int i = (int) CHAR_ARRAY_OFFSET; i < 100; i = i + 8) { + // Copy 8 chars from src to dst + unsafe.putChar(dst, i + 0, unsafe.getChar(src, off + 0)); + unsafe.putChar(dst, i + 2, unsafe.getChar(src, off + 2)); + unsafe.putChar(dst, i + 4, unsafe.getChar(src, off + 4)); + unsafe.putChar(dst, i + 6, unsafe.getChar(src, off + 6)); + unsafe.putChar(dst, i + 8, unsafe.getChar(src, off + 8)); + unsafe.putChar(dst, i + 10, unsafe.getChar(src, off + 10)); + unsafe.putChar(dst, i + 12, unsafe.getChar(src, off + 12)); + unsafe.putChar(dst, i + 14, unsafe.getChar(src, off + 14)); + + // Prevent loop invariant code motion of char read. + src = (src == src1) ? src2 : src1; + } + } + + /* + * Copy multiple consecutive chars from a char array to a given offset in a byte array + * to trigger C2's superword optimization. Checks for similar problems as 'copyByteToChar'. + */ + public static void copyCharToByte(char[] src, byte[] dst, int off) { + off = (int) BYTE_ARRAY_OFFSET + (off << 1); + for (int i = 0; i < 100; i = i + 8) { + // Copy 8 chars from src to dst + unsafe.putChar(dst, off + 0, src[i + 0]); + unsafe.putChar(dst, off + 2, src[i + 1]); + unsafe.putChar(dst, off + 4, src[i + 2]); + unsafe.putChar(dst, off + 6, src[i + 3]); + unsafe.putChar(dst, off + 8, src[i + 4]); + unsafe.putChar(dst, off + 10, src[i + 5]); + unsafe.putChar(dst, off + 12, src[i + 6]); + unsafe.putChar(dst, off + 14, src[i + 7]); + } + } + + /* + * Variant of copyCharToByte with a constant destination array offset. + * The loop should always be vectorized because both the LoadUS and StoreC + * operations can be aligned. + */ + public static void copyCharToByteAligned(char[] src, byte[] dst) { + final int off = (int) BYTE_ARRAY_OFFSET; + for (int i = 8; i < 100; i = i + 8) { + // Copy 8 chars from src to dst + unsafe.putChar(dst, off + 0, src[i + 0]); + unsafe.putChar(dst, off + 2, src[i + 1]); + unsafe.putChar(dst, off + 4, src[i + 2]); + unsafe.putChar(dst, off + 6, src[i + 3]); + unsafe.putChar(dst, off + 8, src[i + 4]); + unsafe.putChar(dst, off + 10, src[i + 5]); + unsafe.putChar(dst, off + 12, src[i + 6]); + unsafe.putChar(dst, off + 14, src[i + 7]); + } + } + + /* + * Variant of copyCharToByte with a constant destination array offset. The + * loop should only be vectorized if unaligned memory operations are allowed + * because not both the LoadUS and the StoreC can be aligned. + */ + public static void copyCharToByteUnaligned(char[] src, byte[] dst) { + final int off = (int) BYTE_ARRAY_OFFSET + 2; + for (int i = 0; i < 100; i = i + 8) { + // Copy 8 chars from src to dst + unsafe.putChar(dst, off + 0, src[i + 0]); + unsafe.putChar(dst, off + 2, src[i + 1]); + unsafe.putChar(dst, off + 4, src[i + 2]); + unsafe.putChar(dst, off + 6, src[i + 3]); + unsafe.putChar(dst, off + 8, src[i + 4]); + unsafe.putChar(dst, off + 10, src[i + 5]); + unsafe.putChar(dst, off + 12, src[i + 6]); + unsafe.putChar(dst, off + 14, src[i + 7]); + } + } +} diff -r c2687aa5e5ca -r 7eb99acd567f test/compiler/regalloc/C1ObjectSpillInLogicOp.java --- a/test/compiler/regalloc/C1ObjectSpillInLogicOp.java Mon Jan 25 14:56:57 2016 -0800 +++ b/test/compiler/regalloc/C1ObjectSpillInLogicOp.java Mon Jan 25 14:57:27 2016 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 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,6 +24,7 @@ /* * @test * @bug 8027751 + * @requires vm.gc=="G1" | vm.gc=="null" * @summary C1 crashes generating G1 post-barrier in Unsafe.getAndSetObject() intrinsic because of the new value spill * @run main/othervm -XX:+UseG1GC C1ObjectSpillInLogicOp * diff -r c2687aa5e5ca -r 7eb99acd567f test/compiler/rtm/locking/TestRTMAbortRatio.java --- a/test/compiler/rtm/locking/TestRTMAbortRatio.java Mon Jan 25 14:56:57 2016 -0800 +++ b/test/compiler/rtm/locking/TestRTMAbortRatio.java Mon Jan 25 14:57:27 2016 -0800 @@ -126,10 +126,7 @@ @Override public String[] getMethodsToCompileNames() { - return new String[] { - getMethodWithLockName(), - Unsafe.class.getName() + "::addressSize" - }; + return new String[] { getMethodWithLockName() }; } public void lock(boolean abort) { @@ -147,10 +144,12 @@ public static void main(String args[]) throws Throwable { Asserts.assertGTE(args.length, 1, "One argument required."); Test t = new Test(); - if (Boolean.valueOf(args[0])) { + boolean shouldBeInflated = Boolean.valueOf(args[0]); + if (shouldBeInflated) { AbortProvoker.inflateMonitor(t.monitor); } for (int i = 0; i < Test.TOTAL_ITERATIONS; i++) { + AbortProvoker.verifyMonitorState(t.monitor, shouldBeInflated); t.lock(i >= Test.WARMUP_ITERATIONS); } } diff -r c2687aa5e5ca -r 7eb99acd567f test/compiler/rtm/locking/TestRTMAfterNonRTMDeopt.java --- a/test/compiler/rtm/locking/TestRTMAfterNonRTMDeopt.java Mon Jan 25 14:56:57 2016 -0800 +++ b/test/compiler/rtm/locking/TestRTMAfterNonRTMDeopt.java Mon Jan 25 14:57:27 2016 -0800 @@ -156,10 +156,7 @@ @Override public String[] getMethodsToCompileNames() { - return new String[] { - getMethodWithLockName(), - sun.misc.Unsafe.class.getName() + "::forceAbort" - }; + return new String[] { getMethodWithLockName() }; } public void forceAbort(int a[], boolean abort) { @@ -182,13 +179,15 @@ public static void main(String args[]) throws Throwable { Test t = new Test(); - if (Boolean.valueOf(args[0])) { + boolean shouldBeInflated = Boolean.valueOf(args[0]); + if (shouldBeInflated) { AbortProvoker.inflateMonitor(t.monitor); } int tmp[] = new int[1]; for (int i = 0; i < Test.ITERATIONS; i++ ) { + AbortProvoker.verifyMonitorState(t.monitor, shouldBeInflated); if (i == Test.RANGE_CHECK_AT) { t.forceAbort(new int[0], false); } else { diff -r c2687aa5e5ca -r 7eb99acd567f test/compiler/rtm/locking/TestRTMDeoptOnLowAbortRatio.java --- a/test/compiler/rtm/locking/TestRTMDeoptOnLowAbortRatio.java Mon Jan 25 14:56:57 2016 -0800 +++ b/test/compiler/rtm/locking/TestRTMDeoptOnLowAbortRatio.java Mon Jan 25 14:57:27 2016 -0800 @@ -129,10 +129,7 @@ @Override public String[] getMethodsToCompileNames() { - return new String[] { - getMethodWithLockName(), - sun.misc.Unsafe.class.getName() + "::addressSize" - }; + return new String[] { getMethodWithLockName() }; } public void forceAbort(boolean abort) { @@ -150,11 +147,12 @@ public static void main(String args[]) throws Throwable { Asserts.assertGTE(args.length, 1, "One argument required."); Test t = new Test(); - - if (Boolean.valueOf(args[0])) { + boolean shouldBeInflated = Boolean.valueOf(args[0]); + if (shouldBeInflated) { AbortProvoker.inflateMonitor(t.monitor); } for (int i = 0; i < AbortProvoker.DEFAULT_ITERATIONS; i++) { + AbortProvoker.verifyMonitorState(t.monitor, shouldBeInflated); t.forceAbort( i == TestRTMDeoptOnLowAbortRatio.LOCKING_THRESHOLD); } diff -r c2687aa5e5ca -r 7eb99acd567f test/compiler/rtm/locking/TestRTMLockingThreshold.java --- a/test/compiler/rtm/locking/TestRTMLockingThreshold.java Mon Jan 25 14:56:57 2016 -0800 +++ b/test/compiler/rtm/locking/TestRTMLockingThreshold.java Mon Jan 25 14:57:27 2016 -0800 @@ -142,10 +142,7 @@ @Override public String[] getMethodsToCompileNames() { - return new String[] { - getMethodWithLockName(), - sun.misc.Unsafe.class.getName() + "::addressSize" - }; + return new String[] { getMethodWithLockName() }; } public void lock(boolean abort) { @@ -163,11 +160,12 @@ public static void main(String args[]) throws Throwable { Asserts.assertGTE(args.length, 1, "One argument required."); Test t = new Test(); - - if (Boolean.valueOf(args[0])) { + boolean shouldBeInflated = Boolean.valueOf(args[0]); + if (shouldBeInflated) { AbortProvoker.inflateMonitor(t.monitor); } for (int i = 0; i < Test.TOTAL_ITERATIONS; i++) { + AbortProvoker.verifyMonitorState(t.monitor, shouldBeInflated); t.lock(i % 2 == 1); } } diff -r c2687aa5e5ca -r 7eb99acd567f test/compiler/rtm/locking/TestRTMTotalCountIncrRate.java --- a/test/compiler/rtm/locking/TestRTMTotalCountIncrRate.java Mon Jan 25 14:56:57 2016 -0800 +++ b/test/compiler/rtm/locking/TestRTMTotalCountIncrRate.java Mon Jan 25 14:57:27 2016 -0800 @@ -116,9 +116,7 @@ @Override public String[] getMethodsToCompileNames() { - return new String[] { - getMethodWithLockName() - }; + return new String[] { getMethodWithLockName() }; } public void lock() { @@ -134,11 +132,13 @@ public static void main(String args[]) throws Throwable { Asserts.assertGTE(args.length, 1, "One argument required."); Test test = new Test(); - - if (Boolean.valueOf(args[0])) { + boolean shouldBeInflated = Boolean.valueOf(args[0]); + if (shouldBeInflated) { AbortProvoker.inflateMonitor(test.monitor); } for (long i = 0L; i < Test.TOTAL_ITERATIONS; i++) { + AbortProvoker.verifyMonitorState(test.monitor, + shouldBeInflated); test.lock(); } } diff -r c2687aa5e5ca -r 7eb99acd567f test/compiler/rtm/locking/TestUseRTMAfterLockInflation.java --- a/test/compiler/rtm/locking/TestUseRTMAfterLockInflation.java Mon Jan 25 14:56:57 2016 -0800 +++ b/test/compiler/rtm/locking/TestUseRTMAfterLockInflation.java Mon Jan 25 14:57:27 2016 -0800 @@ -51,7 +51,7 @@ * Compiled method invoked {@code AbortProvoker.DEFAULT_ITERATIONS} times before * lock inflation and the same amount of times after inflation. * As a result total locks count should be equal to - * {@code 2*AbortProvoker.DEFAULT_ITERATIONS}. + * {@code 2 * AbortProvoker.DEFAULT_ITERATIONS}. * It is a pretty strict assertion which could fail if some retriable abort * happened: it could be {@code AbortType.RETRIABLE} or * {@code AbortType.MEM_CONFLICT}, but unfortunately abort can has both these @@ -100,7 +100,6 @@ } public static class Test { - /** * Usage: * Test <provoker type> @@ -112,10 +111,12 @@ AbortProvoker provoker = AbortType.lookup(Integer.valueOf(args[0])).provoker(); for (int i = 0; i < AbortProvoker.DEFAULT_ITERATIONS; i++) { + AbortProvoker.verifyMonitorState(provoker, false /*deflated*/); provoker.forceAbort(); } provoker.inflateMonitor(); for (int i = 0; i < AbortProvoker.DEFAULT_ITERATIONS; i++) { + AbortProvoker.verifyMonitorState(provoker, true /*inflated*/); provoker.forceAbort(); } } diff -r c2687aa5e5ca -r 7eb99acd567f test/compiler/stable/TestStableBoolean.java --- a/test/compiler/stable/TestStableBoolean.java Mon Jan 25 14:56:57 2016 -0800 +++ b/test/compiler/stable/TestStableBoolean.java Mon Jan 25 14:57:27 2016 -0800 @@ -53,44 +53,32 @@ * java/lang/invoke/TestStableBoolean$DefaultStaticValue * java/lang/invoke/TestStableBoolean$ObjectArrayLowerDim2 * - * @run main/othervm -Xbootclasspath/a:. -XX:+IgnoreUnrecognizedVMOptions + * @run main/othervm -Xbootclasspath/a:. * -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xcomp - * -server -XX:-TieredCompilation + * -XX:-TieredCompilation * -XX:+FoldStableValues * -XX:CompileOnly=::get,::get1,::get2,::get3,::get4 * java.lang.invoke.TestStableBoolean - * @run main/othervm -Xbootclasspath/a:. -XX:+IgnoreUnrecognizedVMOptions + * @run main/othervm -Xbootclasspath/a:. * -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xcomp - * -server -XX:-TieredCompilation + * -XX:-TieredCompilation * -XX:-FoldStableValues * -XX:CompileOnly=::get,::get1,::get2,::get3,::get4 * java.lang.invoke.TestStableBoolean * - * @run main/othervm -Xbootclasspath/a:. -XX:+IgnoreUnrecognizedVMOptions + * @run main/othervm -Xbootclasspath/a:. * -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xcomp - * -server -XX:+TieredCompilation -XX:TieredStopAtLevel=1 + * -XX:+TieredCompilation -XX:TieredStopAtLevel=1 * -XX:+FoldStableValues * -XX:CompileOnly=::get,::get1,::get2,::get3,::get4 * java.lang.invoke.TestStableBoolean - * @run main/othervm -Xbootclasspath/a:. -XX:+IgnoreUnrecognizedVMOptions + * @run main/othervm -Xbootclasspath/a:. * -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xcomp - * -server -XX:+TieredCompilation -XX:TieredStopAtLevel=1 + * -XX:+TieredCompilation -XX:TieredStopAtLevel=1 * -XX:-FoldStableValues * -XX:CompileOnly=::get,::get1,::get2,::get3,::get4 * java.lang.invoke.TestStableBoolean * - * @run main/othervm -Xbootclasspath/a:. -XX:+IgnoreUnrecognizedVMOptions - * -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xcomp - * -client -XX:-TieredCompilation - * -XX:+FoldStableValues - * -XX:CompileOnly=::get,::get1,::get2,::get3,::get4 - * java.lang.invoke.TestStableBoolean - * @run main/othervm -Xbootclasspath/a:. -XX:+IgnoreUnrecognizedVMOptions - * -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xcomp - * -client -XX:-TieredCompilation - * -XX:-FoldStableValues - * -XX:CompileOnly=::get,::get1,::get2,::get3,::get4 - * java.lang.invoke.TestStableBoolean */ package java.lang.invoke; diff -r c2687aa5e5ca -r 7eb99acd567f test/compiler/stable/TestStableByte.java --- a/test/compiler/stable/TestStableByte.java Mon Jan 25 14:56:57 2016 -0800 +++ b/test/compiler/stable/TestStableByte.java Mon Jan 25 14:57:27 2016 -0800 @@ -53,44 +53,32 @@ * java/lang/invoke/TestStableByte$DefaultStaticValue * java/lang/invoke/TestStableByte$ObjectArrayLowerDim2 * - * @run main/othervm -Xbootclasspath/a:. -XX:+IgnoreUnrecognizedVMOptions + * @run main/othervm -Xbootclasspath/a:. * -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xcomp - * -server -XX:-TieredCompilation + * -XX:-TieredCompilation * -XX:+FoldStableValues * -XX:CompileOnly=::get,::get1,::get2,::get3,::get4 * java.lang.invoke.TestStableByte - * @run main/othervm -Xbootclasspath/a:. -XX:+IgnoreUnrecognizedVMOptions + * @run main/othervm -Xbootclasspath/a:. * -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xcomp - * -server -XX:-TieredCompilation + * -XX:-TieredCompilation * -XX:-FoldStableValues * -XX:CompileOnly=::get,::get1,::get2,::get3,::get4 * java.lang.invoke.TestStableByte * - * @run main/othervm -Xbootclasspath/a:. -XX:+IgnoreUnrecognizedVMOptions + * @run main/othervm -Xbootclasspath/a:. * -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xcomp - * -server -XX:+TieredCompilation -XX:TieredStopAtLevel=1 + * -XX:+TieredCompilation -XX:TieredStopAtLevel=1 * -XX:+FoldStableValues * -XX:CompileOnly=::get,::get1,::get2,::get3,::get4 * java.lang.invoke.TestStableByte - * @run main/othervm -Xbootclasspath/a:. -XX:+IgnoreUnrecognizedVMOptions + * @run main/othervm -Xbootclasspath/a:. * -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xcomp - * -server -XX:+TieredCompilation -XX:TieredStopAtLevel=1 + * -XX:+TieredCompilation -XX:TieredStopAtLevel=1 * -XX:-FoldStableValues * -XX:CompileOnly=::get,::get1,::get2,::get3,::get4 * java.lang.invoke.TestStableByte * - * @run main/othervm -Xbootclasspath/a:. -XX:+IgnoreUnrecognizedVMOptions - * -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xcomp - * -client -XX:-TieredCompilation - * -XX:+FoldStableValues - * -XX:CompileOnly=::get,::get1,::get2,::get3,::get4 - * java.lang.invoke.TestStableByte - * @run main/othervm -Xbootclasspath/a:. -XX:+IgnoreUnrecognizedVMOptions - * -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xcomp - * -client -XX:-TieredCompilation - * -XX:-FoldStableValues - * -XX:CompileOnly=::get,::get1,::get2,::get3,::get4 - * java.lang.invoke.TestStableByte */ package java.lang.invoke; diff -r c2687aa5e5ca -r 7eb99acd567f test/compiler/stable/TestStableChar.java --- a/test/compiler/stable/TestStableChar.java Mon Jan 25 14:56:57 2016 -0800 +++ b/test/compiler/stable/TestStableChar.java Mon Jan 25 14:57:27 2016 -0800 @@ -53,44 +53,32 @@ * java/lang/invoke/TestStableChar$DefaultStaticValue * java/lang/invoke/TestStableChar$ObjectArrayLowerDim2 * - * @run main/othervm -Xbootclasspath/a:. -XX:+IgnoreUnrecognizedVMOptions + * @run main/othervm -Xbootclasspath/a:. * -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xcomp - * -server -XX:-TieredCompilation + * -XX:-TieredCompilation * -XX:+FoldStableValues * -XX:CompileOnly=::get,::get1,::get2,::get3,::get4 * java.lang.invoke.TestStableChar - * @run main/othervm -Xbootclasspath/a:. -XX:+IgnoreUnrecognizedVMOptions + * @run main/othervm -Xbootclasspath/a:. * -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xcomp - * -server -XX:-TieredCompilation + * -XX:-TieredCompilation * -XX:-FoldStableValues * -XX:CompileOnly=::get,::get1,::get2,::get3,::get4 * java.lang.invoke.TestStableChar * - * @run main/othervm -Xbootclasspath/a:. -XX:+IgnoreUnrecognizedVMOptions + * @run main/othervm -Xbootclasspath/a:. * -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xcomp - * -server -XX:+TieredCompilation -XX:TieredStopAtLevel=1 + * -XX:+TieredCompilation -XX:TieredStopAtLevel=1 * -XX:+FoldStableValues * -XX:CompileOnly=::get,::get1,::get2,::get3,::get4 * java.lang.invoke.TestStableChar - * @run main/othervm -Xbootclasspath/a:. -XX:+IgnoreUnrecognizedVMOptions + * @run main/othervm -Xbootclasspath/a:. * -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xcomp - * -server -XX:+TieredCompilation -XX:TieredStopAtLevel=1 + * -XX:+TieredCompilation -XX:TieredStopAtLevel=1 * -XX:-FoldStableValues * -XX:CompileOnly=::get,::get1,::get2,::get3,::get4 * java.lang.invoke.TestStableChar * - * @run main/othervm -Xbootclasspath/a:. -XX:+IgnoreUnrecognizedVMOptions - * -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xcomp - * -client -XX:-TieredCompilation - * -XX:+FoldStableValues - * -XX:CompileOnly=::get,::get1,::get2,::get3,::get4 - * java.lang.invoke.TestStableChar - * @run main/othervm -Xbootclasspath/a:. -XX:+IgnoreUnrecognizedVMOptions - * -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xcomp - * -client -XX:-TieredCompilation - * -XX:-FoldStableValues - * -XX:CompileOnly=::get,::get1,::get2,::get3,::get4 - * java.lang.invoke.TestStableChar */ package java.lang.invoke; diff -r c2687aa5e5ca -r 7eb99acd567f test/compiler/stable/TestStableDouble.java --- a/test/compiler/stable/TestStableDouble.java Mon Jan 25 14:56:57 2016 -0800 +++ b/test/compiler/stable/TestStableDouble.java Mon Jan 25 14:57:27 2016 -0800 @@ -53,44 +53,32 @@ * java/lang/invoke/TestStableDouble$DefaultStaticValue * java/lang/invoke/TestStableDouble$ObjectArrayLowerDim2 * - * @run main/othervm -Xbootclasspath/a:. -XX:+IgnoreUnrecognizedVMOptions + * @run main/othervm -Xbootclasspath/a:. * -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xcomp - * -server -XX:-TieredCompilation + * -XX:-TieredCompilation * -XX:+FoldStableValues * -XX:CompileOnly=::get,::get1,::get2,::get3,::get4 * java.lang.invoke.TestStableDouble - * @run main/othervm -Xbootclasspath/a:. -XX:+IgnoreUnrecognizedVMOptions + * @run main/othervm -Xbootclasspath/a:. * -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xcomp - * -server -XX:-TieredCompilation + * -XX:-TieredCompilation * -XX:-FoldStableValues * -XX:CompileOnly=::get,::get1,::get2,::get3,::get4 * java.lang.invoke.TestStableDouble * - * @run main/othervm -Xbootclasspath/a:. -XX:+IgnoreUnrecognizedVMOptions + * @run main/othervm -Xbootclasspath/a:. * -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xcomp - * -server -XX:+TieredCompilation -XX:TieredStopAtLevel=1 + * -XX:+TieredCompilation -XX:TieredStopAtLevel=1 * -XX:+FoldStableValues * -XX:CompileOnly=::get,::get1,::get2,::get3,::get4 * java.lang.invoke.TestStableDouble - * @run main/othervm -Xbootclasspath/a:. -XX:+IgnoreUnrecognizedVMOptions + * @run main/othervm -Xbootclasspath/a:. * -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xcomp - * -server -XX:+TieredCompilation -XX:TieredStopAtLevel=1 + * -XX:+TieredCompilation -XX:TieredStopAtLevel=1 * -XX:-FoldStableValues * -XX:CompileOnly=::get,::get1,::get2,::get3,::get4 * java.lang.invoke.TestStableDouble * - * @run main/othervm -Xbootclasspath/a:. -XX:+IgnoreUnrecognizedVMOptions - * -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xcomp - * -client -XX:-TieredCompilation - * -XX:+FoldStableValues - * -XX:CompileOnly=::get,::get1,::get2,::get3,::get4 - * java.lang.invoke.TestStableDouble - * @run main/othervm -Xbootclasspath/a:. -XX:+IgnoreUnrecognizedVMOptions - * -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xcomp - * -client -XX:-TieredCompilation - * -XX:-FoldStableValues - * -XX:CompileOnly=::get,::get1,::get2,::get3,::get4 - * java.lang.invoke.TestStableDouble */ package java.lang.invoke; diff -r c2687aa5e5ca -r 7eb99acd567f test/compiler/stable/TestStableFloat.java --- a/test/compiler/stable/TestStableFloat.java Mon Jan 25 14:56:57 2016 -0800 +++ b/test/compiler/stable/TestStableFloat.java Mon Jan 25 14:57:27 2016 -0800 @@ -53,44 +53,32 @@ * java/lang/invoke/TestStableFloat$DefaultStaticValue * java/lang/invoke/TestStableFloat$ObjectArrayLowerDim2 * - * @run main/othervm -Xbootclasspath/a:. -XX:+IgnoreUnrecognizedVMOptions + * @run main/othervm -Xbootclasspath/a:. * -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xcomp - * -server -XX:-TieredCompilation + * -XX:-TieredCompilation * -XX:+FoldStableValues * -XX:CompileOnly=::get,::get1,::get2,::get3,::get4 * java.lang.invoke.TestStableFloat - * @run main/othervm -Xbootclasspath/a:. -XX:+IgnoreUnrecognizedVMOptions + * @run main/othervm -Xbootclasspath/a:. * -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xcomp - * -server -XX:-TieredCompilation + * -XX:-TieredCompilation * -XX:-FoldStableValues * -XX:CompileOnly=::get,::get1,::get2,::get3,::get4 * java.lang.invoke.TestStableFloat * - * @run main/othervm -Xbootclasspath/a:. -XX:+IgnoreUnrecognizedVMOptions + * @run main/othervm -Xbootclasspath/a:. * -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xcomp - * -server -XX:+TieredCompilation -XX:TieredStopAtLevel=1 + * -XX:+TieredCompilation -XX:TieredStopAtLevel=1 * -XX:+FoldStableValues * -XX:CompileOnly=::get,::get1,::get2,::get3,::get4 * java.lang.invoke.TestStableFloat - * @run main/othervm -Xbootclasspath/a:. -XX:+IgnoreUnrecognizedVMOptions + * @run main/othervm -Xbootclasspath/a:. * -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xcomp - * -server -XX:+TieredCompilation -XX:TieredStopAtLevel=1 + * -XX:+TieredCompilation -XX:TieredStopAtLevel=1 * -XX:-FoldStableValues * -XX:CompileOnly=::get,::get1,::get2,::get3,::get4 * java.lang.invoke.TestStableFloat * - * @run main/othervm -Xbootclasspath/a:. -XX:+IgnoreUnrecognizedVMOptions - * -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xcomp - * -client -XX:-TieredCompilation - * -XX:+FoldStableValues - * -XX:CompileOnly=::get,::get1,::get2,::get3,::get4 - * java.lang.invoke.TestStableFloat - * @run main/othervm -Xbootclasspath/a:. -XX:+IgnoreUnrecognizedVMOptions - * -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xcomp - * -client -XX:-TieredCompilation - * -XX:-FoldStableValues - * -XX:CompileOnly=::get,::get1,::get2,::get3,::get4 - * java.lang.invoke.TestStableFloat */ package java.lang.invoke; diff -r c2687aa5e5ca -r 7eb99acd567f test/compiler/stable/TestStableInt.java --- a/test/compiler/stable/TestStableInt.java Mon Jan 25 14:56:57 2016 -0800 +++ b/test/compiler/stable/TestStableInt.java Mon Jan 25 14:57:27 2016 -0800 @@ -53,44 +53,32 @@ * java/lang/invoke/TestStableInt$DefaultStaticValue * java/lang/invoke/TestStableInt$ObjectArrayLowerDim2 * - * @run main/othervm -Xbootclasspath/a:. -XX:+IgnoreUnrecognizedVMOptions + * @run main/othervm -Xbootclasspath/a:. * -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xcomp - * -server -XX:-TieredCompilation + * -XX:-TieredCompilation * -XX:+FoldStableValues * -XX:CompileOnly=::get,::get1,::get2,::get3,::get4 * java.lang.invoke.TestStableInt - * @run main/othervm -Xbootclasspath/a:. -XX:+IgnoreUnrecognizedVMOptions + * @run main/othervm -Xbootclasspath/a:. * -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xcomp - * -server -XX:-TieredCompilation + * -XX:-TieredCompilation * -XX:-FoldStableValues * -XX:CompileOnly=::get,::get1,::get2,::get3,::get4 * java.lang.invoke.TestStableInt * - * @run main/othervm -Xbootclasspath/a:. -XX:+IgnoreUnrecognizedVMOptions + * @run main/othervm -Xbootclasspath/a:. * -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xcomp - * -server -XX:+TieredCompilation -XX:TieredStopAtLevel=1 + * -XX:+TieredCompilation -XX:TieredStopAtLevel=1 * -XX:+FoldStableValues * -XX:CompileOnly=::get,::get1,::get2,::get3,::get4 * java.lang.invoke.TestStableInt - * @run main/othervm -Xbootclasspath/a:. -XX:+IgnoreUnrecognizedVMOptions + * @run main/othervm -Xbootclasspath/a:. * -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xcomp - * -server -XX:+TieredCompilation -XX:TieredStopAtLevel=1 + * -XX:+TieredCompilation -XX:TieredStopAtLevel=1 * -XX:-FoldStableValues * -XX:CompileOnly=::get,::get1,::get2,::get3,::get4 * java.lang.invoke.TestStableInt * - * @run main/othervm -Xbootclasspath/a:. -XX:+IgnoreUnrecognizedVMOptions - * -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xcomp - * -client -XX:-TieredCompilation - * -XX:+FoldStableValues - * -XX:CompileOnly=::get,::get1,::get2,::get3,::get4 - * java.lang.invoke.TestStableInt - * @run main/othervm -Xbootclasspath/a:. -XX:+IgnoreUnrecognizedVMOptions - * -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xcomp - * -client -XX:-TieredCompilation - * -XX:-FoldStableValues - * -XX:CompileOnly=::get,::get1,::get2,::get3,::get4 - * java.lang.invoke.TestStableInt */ package java.lang.invoke; diff -r c2687aa5e5ca -r 7eb99acd567f test/compiler/stable/TestStableLong.java --- a/test/compiler/stable/TestStableLong.java Mon Jan 25 14:56:57 2016 -0800 +++ b/test/compiler/stable/TestStableLong.java Mon Jan 25 14:57:27 2016 -0800 @@ -53,44 +53,32 @@ * java/lang/invoke/TestStableLong$DefaultStaticValue * java/lang/invoke/TestStableLong$ObjectArrayLowerDim2 * - * @run main/othervm -Xbootclasspath/a:. -XX:+IgnoreUnrecognizedVMOptions + * @run main/othervm -Xbootclasspath/a:. * -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xcomp - * -server -XX:-TieredCompilation + * -XX:-TieredCompilation * -XX:+FoldStableValues * -XX:CompileOnly=::get,::get1,::get2,::get3,::get4 * java.lang.invoke.TestStableLong - * @run main/othervm -Xbootclasspath/a:. -XX:+IgnoreUnrecognizedVMOptions + * @run main/othervm -Xbootclasspath/a:. * -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xcomp - * -server -XX:-TieredCompilation + * -XX:-TieredCompilation * -XX:-FoldStableValues * -XX:CompileOnly=::get,::get1,::get2,::get3,::get4 * java.lang.invoke.TestStableLong * - * @run main/othervm -Xbootclasspath/a:. -XX:+IgnoreUnrecognizedVMOptions + * @run main/othervm -Xbootclasspath/a:. * -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xcomp - * -server -XX:+TieredCompilation -XX:TieredStopAtLevel=1 + * -XX:+TieredCompilation -XX:TieredStopAtLevel=1 * -XX:+FoldStableValues * -XX:CompileOnly=::get,::get1,::get2,::get3,::get4 * java.lang.invoke.TestStableLong - * @run main/othervm -Xbootclasspath/a:. -XX:+IgnoreUnrecognizedVMOptions + * @run main/othervm -Xbootclasspath/a:. * -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xcomp - * -server -XX:+TieredCompilation -XX:TieredStopAtLevel=1 + * -XX:+TieredCompilation -XX:TieredStopAtLevel=1 * -XX:-FoldStableValues * -XX:CompileOnly=::get,::get1,::get2,::get3,::get4 * java.lang.invoke.TestStableLong * - * @run main/othervm -Xbootclasspath/a:. -XX:+IgnoreUnrecognizedVMOptions - * -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xcomp - * -client -XX:-TieredCompilation - * -XX:+FoldStableValues - * -XX:CompileOnly=::get,::get1,::get2,::get3,::get4 - * java.lang.invoke.TestStableLong - * @run main/othervm -Xbootclasspath/a:. -XX:+IgnoreUnrecognizedVMOptions - * -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xcomp - * -client -XX:-TieredCompilation - * -XX:-FoldStableValues - * -XX:CompileOnly=::get,::get1,::get2,::get3,::get4 - * java.lang.invoke.TestStableLong */ package java.lang.invoke; diff -r c2687aa5e5ca -r 7eb99acd567f test/compiler/stable/TestStableObject.java --- a/test/compiler/stable/TestStableObject.java Mon Jan 25 14:56:57 2016 -0800 +++ b/test/compiler/stable/TestStableObject.java Mon Jan 25 14:57:27 2016 -0800 @@ -54,44 +54,32 @@ * java/lang/invoke/TestStableObject$DefaultStaticValue * java/lang/invoke/TestStableObject$ObjectArrayLowerDim2 * - * @run main/othervm -Xbootclasspath/a:. -XX:+IgnoreUnrecognizedVMOptions + * @run main/othervm -Xbootclasspath/a:. * -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xcomp - * -server -XX:-TieredCompilation + * -XX:-TieredCompilation * -XX:+FoldStableValues * -XX:CompileOnly=::get,::get1,::get2,::get3,::get4 * java.lang.invoke.TestStableObject - * @run main/othervm -Xbootclasspath/a:. -XX:+IgnoreUnrecognizedVMOptions + * @run main/othervm -Xbootclasspath/a:. * -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xcomp - * -server -XX:-TieredCompilation + * -XX:-TieredCompilation * -XX:-FoldStableValues * -XX:CompileOnly=::get,::get1,::get2,::get3,::get4 * java.lang.invoke.TestStableObject * - * @run main/othervm -Xbootclasspath/a:. -XX:+IgnoreUnrecognizedVMOptions + * @run main/othervm -Xbootclasspath/a:. * -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xcomp - * -server -XX:+TieredCompilation -XX:TieredStopAtLevel=1 + * -XX:+TieredCompilation -XX:TieredStopAtLevel=1 * -XX:+FoldStableValues * -XX:CompileOnly=::get,::get1,::get2,::get3,::get4 * java.lang.invoke.TestStableObject - * @run main/othervm -Xbootclasspath/a:. -XX:+IgnoreUnrecognizedVMOptions + * @run main/othervm -Xbootclasspath/a:. * -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xcomp - * -server -XX:+TieredCompilation -XX:TieredStopAtLevel=1 + * -XX:+TieredCompilation -XX:TieredStopAtLevel=1 * -XX:-FoldStableValues * -XX:CompileOnly=::get,::get1,::get2,::get3,::get4 * java.lang.invoke.TestStableObject * - * @run main/othervm -Xbootclasspath/a:. -XX:+IgnoreUnrecognizedVMOptions - * -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xcomp - * -client -XX:-TieredCompilation - * -XX:+FoldStableValues - * -XX:CompileOnly=::get,::get1,::get2,::get3,::get4 - * java.lang.invoke.TestStableObject - * @run main/othervm -Xbootclasspath/a:. -XX:+IgnoreUnrecognizedVMOptions - * -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xcomp - * -client -XX:-TieredCompilation - * -XX:-FoldStableValues - * -XX:CompileOnly=::get,::get1,::get2,::get3,::get4 - * java.lang.invoke.TestStableObject */ package java.lang.invoke; diff -r c2687aa5e5ca -r 7eb99acd567f test/compiler/stable/TestStableShort.java --- a/test/compiler/stable/TestStableShort.java Mon Jan 25 14:56:57 2016 -0800 +++ b/test/compiler/stable/TestStableShort.java Mon Jan 25 14:57:27 2016 -0800 @@ -53,44 +53,32 @@ * java/lang/invoke/TestStableShort$DefaultStaticValue * java/lang/invoke/TestStableShort$ObjectArrayLowerDim2 * - * @run main/othervm -Xbootclasspath/a:. -XX:+IgnoreUnrecognizedVMOptions + * @run main/othervm -Xbootclasspath/a:. * -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xcomp - * -server -XX:-TieredCompilation + * -XX:-TieredCompilation * -XX:+FoldStableValues * -XX:CompileOnly=::get,::get1,::get2,::get3,::get4 * java.lang.invoke.TestStableShort - * @run main/othervm -Xbootclasspath/a:. -XX:+IgnoreUnrecognizedVMOptions + * @run main/othervm -Xbootclasspath/a:. * -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xcomp - * -server -XX:-TieredCompilation + * -XX:-TieredCompilation * -XX:-FoldStableValues * -XX:CompileOnly=::get,::get1,::get2,::get3,::get4 * java.lang.invoke.TestStableShort * - * @run main/othervm -Xbootclasspath/a:. -XX:+IgnoreUnrecognizedVMOptions + * @run main/othervm -Xbootclasspath/a:. * -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xcomp - * -server -XX:+TieredCompilation -XX:TieredStopAtLevel=1 + * -XX:+TieredCompilation -XX:TieredStopAtLevel=1 * -XX:+FoldStableValues * -XX:CompileOnly=::get,::get1,::get2,::get3,::get4 * java.lang.invoke.TestStableShort - * @run main/othervm -Xbootclasspath/a:. -XX:+IgnoreUnrecognizedVMOptions + * @run main/othervm -Xbootclasspath/a:. * -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xcomp - * -server -XX:+TieredCompilation -XX:TieredStopAtLevel=1 + * -XX:+TieredCompilation -XX:TieredStopAtLevel=1 * -XX:-FoldStableValues * -XX:CompileOnly=::get,::get1,::get2,::get3,::get4 * java.lang.invoke.TestStableShort * - * @run main/othervm -Xbootclasspath/a:. -XX:+IgnoreUnrecognizedVMOptions - * -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xcomp - * -client -XX:-TieredCompilation - * -XX:+FoldStableValues - * -XX:CompileOnly=::get,::get1,::get2,::get3,::get4 - * java.lang.invoke.TestStableShort - * @run main/othervm -Xbootclasspath/a:. -XX:+IgnoreUnrecognizedVMOptions - * -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xcomp - * -client -XX:-TieredCompilation - * -XX:-FoldStableValues - * -XX:CompileOnly=::get,::get1,::get2,::get3,::get4 - * java.lang.invoke.TestStableShort */ package java.lang.invoke; diff -r c2687aa5e5ca -r 7eb99acd567f test/compiler/stringopts/TestOptimizeStringConcat.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/compiler/stringopts/TestOptimizeStringConcat.java Mon Jan 25 14:57:27 2016 -0800 @@ -0,0 +1,89 @@ +/* + * Copyright 2015 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 + * 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 8068909 + * @key regression + * @summary test that string optimizations produce code, that doesn't lead to a crash. + * @run main/othervm -XX:-BackgroundCompilation -XX:-UseOnStackReplacement TestOptimizeStringConcat + * @author axel.siebenborn@sap.com + */ +public class TestOptimizeStringConcat { + + static boolean checkArgumentSyntax(String value, String allowedchars, String notallowedchars, String logmsg) { + String rc = null; + + int maxchar = 99999; + int minchar = 1; + if ((allowedchars != null && notallowedchars != null) || minchar > maxchar) { + rc = "internal error"; + } else { + if (value == null) { + rc = "the value null is not allowed, it is missing"; + } else if (value != null && minchar > 0 && value.trim().equals("")) { + rc = "the value must not be empty"; + } else if (value != null) { + if (value.length() < minchar || value.length() > maxchar) { + if (rc == null) { + rc = "the value length must be between +minchar+ and +maxchar"; + } + } + char[] _value = value.toCharArray(); + boolean dotfound = false; + int i = 1; + if (_value[i] == '.' && !dotfound) { + dotfound = true; + } else if (allowedchars != null && allowedchars.indexOf(_value[i]) == -1) { + if (rc == null) { + rc = "the value contains an illegal character: '" + _value[i] + "', only following characters are allowed: '+allowedchars+'"; + } else { + rc += " / the value contains an illegal character: '" + _value[i] + "', only following characters are allowed: '+allowedchars+'"; + } + } else if (notallowedchars != null && notallowedchars.indexOf(_value[i]) != -1) { + if (rc == null) { + rc = "the value contains an illegal character: '" + _value[i] + "', following characters are not allowed '+notallowedchars+'"; + } else { + rc += " / the value contains an illegal character: '" + _value[i] + "', following characters are not allowed '+notallowedchars+'"; + } + } + } + } + + if (rc != null) { + System.out.println(logmsg + " ==> " + rc); + return false; + } + return true; + } + + public static void main(String[] args) { + boolean failed = false; + for (int i = 0; i < 10000; i++) { + failed |= !checkArgumentSyntax("theName", null, "\"<&", "Error consistencyCheck: name in component definition"); + failed |= !checkArgumentSyntax(null, null, "\"<&", "Error consistencyCheck: name in component definition"); + failed |= !checkArgumentSyntax("42", "0123456789.", null, "Error consistencyCheck: counter in component definition"); + } + System.out.println(failed); + } +} diff -r c2687aa5e5ca -r 7eb99acd567f test/compiler/testlibrary/rtm/AbortProvoker.java --- a/test/compiler/testlibrary/rtm/AbortProvoker.java Mon Jan 25 14:56:57 2016 -0800 +++ b/test/compiler/testlibrary/rtm/AbortProvoker.java Mon Jan 25 14:57:27 2016 -0800 @@ -29,8 +29,7 @@ import java.util.concurrent.CyclicBarrier; import com.oracle.java.testlibrary.Asserts; -import com.oracle.java.testlibrary.Utils; -import sun.misc.Unsafe; +import sun.hotspot.WhiteBox; /** * Base class for different transactional execution abortion @@ -38,6 +37,9 @@ */ public abstract class AbortProvoker implements CompilableTest { public static final long DEFAULT_ITERATIONS = 10000L; + private static final WhiteBox WHITE_BOX = WhiteBox.getWhiteBox(); + @SuppressWarnings("unused") + private static int sharedState = 0; /** * Inflates monitor associated with object {@code monitor}. * Inflation is forced by entering the same monitor from @@ -48,36 +50,76 @@ * @throws Exception if something went wrong. */ public static Object inflateMonitor(Object monitor) throws Exception { - Unsafe unsafe = Utils.getUnsafe(); CyclicBarrier barrier = new CyclicBarrier(2); Runnable inflatingRunnable = () -> { - unsafe.monitorEnter(monitor); - try { - barrier.await(); - barrier.await(); - } catch (InterruptedException | BrokenBarrierException e) { - throw new RuntimeException( - "Synchronization issue occurred.", e); - } finally { - unsafe.monitorExit(monitor); + synchronized (monitor) { + try { + barrier.await(); + } catch (BrokenBarrierException | InterruptedException e) { + throw new RuntimeException( + "Synchronization issue occurred.", e); + } + try { + monitor.wait(); + } catch (InterruptedException e) { + throw new AssertionError("The thread waiting on an" + + " inflated monitor was interrupted, thus test" + + " results may be incorrect.", e); + } } }; Thread t = new Thread(inflatingRunnable); + t.setDaemon(true); t.start(); // Wait until thread t enters the monitor. barrier.await(); - // At this point monitor will be owned by thread t, - // so our attempt to enter the same monitor will force - // monitor inflation. - Asserts.assertFalse(unsafe.tryMonitorEnter(monitor), - "Not supposed to enter the monitor first"); - barrier.await(); - t.join(); + synchronized (monitor) { + // At this point thread t is already waiting on the monitor. + // Modifying static field just to avoid lock's elimination. + sharedState++; + } + verifyMonitorState(monitor, true /* inflated */); return monitor; } + /** + * Verifies that {@code monitor} is a stack-lock or inflated lock depending + * on {@code shouldBeInflated} value. If {@code monitor} is inflated while + * it is expected that it should be a stack-lock, then this method attempts + * to deflate it by forcing a safepoint and then verifies the state once + * again. + * + * @param monitor monitor to be verified. + * @param shouldBeInflated flag indicating whether or not monitor is + * expected to be inflated. + * @throws RuntimeException if the {@code monitor} in a wrong state. + */ + public static void verifyMonitorState(Object monitor, + boolean shouldBeInflated) { + if (!shouldBeInflated && WHITE_BOX.isMonitorInflated(monitor)) { + WHITE_BOX.forceSafepoint(); + } + Asserts.assertEQ(WHITE_BOX.isMonitorInflated(monitor), shouldBeInflated, + "Monitor in a wrong state."); + } + /** + * Verifies that monitor used by the {@code provoker} is a stack-lock or + * inflated lock depending on {@code shouldBeInflated} value. If such + * monitor is inflated while it is expected that it should be a stack-lock, + * then this method attempts to deflate it by forcing a safepoint and then + * verifies the state once again. + * + * @param provoker AbortProvoker whose monitor's state should be verified. + * @param shouldBeInflated flag indicating whether or not monitor is + * expected to be inflated. + * @throws RuntimeException if the {@code monitor} in a wrong state. + */ + public static void verifyMonitorState(AbortProvoker provoker, + boolean shouldBeInflated) { + verifyMonitorState(provoker.monitor, shouldBeInflated); + } /** * Get instance of specified AbortProvoker, inflate associated monitor @@ -120,6 +162,7 @@ } for (long i = 0; i < iterations; i++) { + AbortProvoker.verifyMonitorState(provoker, monitorShouldBeInflated); provoker.forceAbort(); } } diff -r c2687aa5e5ca -r 7eb99acd567f test/compiler/testlibrary/rtm/BusyLock.java --- a/test/compiler/testlibrary/rtm/BusyLock.java Mon Jan 25 14:56:57 2016 -0800 +++ b/test/compiler/testlibrary/rtm/BusyLock.java Mon Jan 25 14:57:27 2016 -0800 @@ -77,7 +77,7 @@ } } - public void test() { + public void syncAndTest() { try { barrier.await(); // wait until monitor is locked by a ::run method @@ -85,6 +85,10 @@ } catch (InterruptedException | BrokenBarrierException e) { throw new RuntimeException("Synchronization error happened.", e); } + test(); + } + + public void test() { synchronized(monitor) { BusyLock.field++; } @@ -130,7 +134,7 @@ Thread t = new Thread(busyLock); t.start(); - busyLock.test(); + busyLock.syncAndTest(); t.join(); } } diff -r c2687aa5e5ca -r 7eb99acd567f test/compiler/testlibrary/rtm/MemoryConflictProvoker.java --- a/test/compiler/testlibrary/rtm/MemoryConflictProvoker.java Mon Jan 25 14:56:57 2016 -0800 +++ b/test/compiler/testlibrary/rtm/MemoryConflictProvoker.java Mon Jan 25 14:57:27 2016 -0800 @@ -69,11 +69,6 @@ * Accesses and modifies memory region from within the transaction. */ public void transactionalRegion() { - try { - barrier.await(); - } catch (InterruptedException | BrokenBarrierException e) { - throw new RuntimeException(e); - } for (int i = 0; i < MemoryConflictProvoker.INNER_ITERATIONS; i++) { synchronized(monitor) { MemoryConflictProvoker.field--; @@ -86,6 +81,11 @@ try { Thread t = new Thread(conflictingThread); t.start(); + try { + barrier.await(); + } catch (InterruptedException | BrokenBarrierException e) { + throw new RuntimeException(e); + } transactionalRegion(); t.join(); } catch (Exception e) { diff -r c2687aa5e5ca -r 7eb99acd567f test/compiler/testlibrary/rtm/RTMTestBase.java --- a/test/compiler/testlibrary/rtm/RTMTestBase.java Mon Jan 25 14:56:57 2016 -0800 +++ b/test/compiler/testlibrary/rtm/RTMTestBase.java Mon Jan 25 14:57:27 2016 -0800 @@ -238,10 +238,10 @@ String[] filteredVMOpts = Utils.getFilteredTestJavaOpts(filters); Collections.addAll(finalVMOpts, filteredVMOpts); Collections.addAll(finalVMOpts, "-Xcomp", "-server", - "-XX:-TieredCompilation", + "-XX:-TieredCompilation", "-XX:+UseRTMLocking", CommandLineOptionTest.UNLOCK_DIAGNOSTIC_VM_OPTIONS, CommandLineOptionTest.UNLOCK_EXPERIMENTAL_VM_OPTIONS, - "-XX:+UseRTMLocking"); + "-Xbootclasspath/a:.", "-XX:+WhiteBoxAPI"); if (test != null) { for (String method : test.getMethodsToCompileNames()) { diff -r c2687aa5e5ca -r 7eb99acd567f test/compiler/types/TestMeetExactConstantArrays.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/compiler/types/TestMeetExactConstantArrays.java Mon Jan 25 14:57:27 2016 -0800 @@ -0,0 +1,70 @@ +/* + * Copyright (c) 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 + * 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 8075587 + * @summary meet of 2 constant arrays result in bottom + * @run main/othervm TestMeetExactConstantArrays + * + */ + +public class TestMeetExactConstantArrays { + public abstract static class NumbersHolder { + public Number[] getNumbers() { + return null; + } + } + + public static class IntegersHolder extends NumbersHolder { + private final static Integer integers[] = { new Integer(1) }; + + public Number[] getNumbers() { + return integers; + } + } + + public static class LongsHolder extends NumbersHolder { + private final static Long longs[] = { new Long(1) }; + + public Number[] getNumbers() { + return longs; + } + } + + public static final void loopNumbers(NumbersHolder numbersHolder) { + Number[] numbers = numbersHolder.getNumbers(); + for (int i = 0; i < numbers.length; i++) { + numbers[i].longValue(); + } + } + + public static void main(String[] args) throws Exception { + for (int i = 0; i < 10000; i++) { + IntegersHolder integersHolder = new IntegersHolder(); + LongsHolder longsHolder = new LongsHolder(); + loopNumbers(integersHolder); + loopNumbers(longsHolder); + } + } +} diff -r c2687aa5e5ca -r 7eb99acd567f test/compiler/types/TestTypePropagationToCmpU.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/compiler/types/TestTypePropagationToCmpU.java Mon Jan 25 14:57:27 2016 -0800 @@ -0,0 +1,59 @@ +/* + * Copyright (c) 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 + * 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 8080156 8060036 + * @summary Test correctness of type propagation to CmpUNodes. + * @run main TestTypePropagationToCmpU + */ +public class TestTypePropagationToCmpU { + public static void main(String[] args) { + try { + // Trigger compilation + for (int i = 0; i < 100_000; ++i) { + test(); + } + } catch (NullPointerException e) { + // Test should never throw a NullPointerException + throw new RuntimeException("Test failed"); + } + } + + static int global = 42; + + public static void test() { + int a = Integer.MIN_VALUE; + int b = global; + char[] buf = { 0 }; + for (int i = 0; i <= b; ++i) { + a = i - b; + } + // C2 adds a range check and an uncommon trap here to ensure that the array index + // is in bounds. If type information is not propagated correctly to the corresponding + // CmpUNode, this trap may be always taken. Because C2 also removes the unnecessary + // allocation of 'buf', a NullPointerException is thrown in this case. + char c = buf[(a * 11) / 2 - a]; // a is 0 here if global >= 0 + buf[0] = 0; + } +} diff -r c2687aa5e5ca -r 7eb99acd567f test/compiler/uncommontrap/UncommonTrapStackBang.java --- a/test/compiler/uncommontrap/UncommonTrapStackBang.java Mon Jan 25 14:56:57 2016 -0800 +++ b/test/compiler/uncommontrap/UncommonTrapStackBang.java Mon Jan 25 14:57:27 2016 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 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 @@ -27,9 +27,7 @@ * @bug 8026775 * @summary Uncommon trap blob did not bang all the stack shadow pages * - * @run main/othervm -server -XX:+IgnoreUnrecognizedVMOptions -XX:+TieredCompilation UncommonTrapStackBang - * @run main/othervm -server -XX:+IgnoreUnrecognizedVMOptions -XX:-TieredCompilation UncommonTrapStackBang - * + * @run main/othervm UncommonTrapStackBang * * Note: This test does not reproduce the problem with absolute * certainty. Empirically the bug reproduces on Windows some 80+% of diff -r c2687aa5e5ca -r 7eb99acd567f test/compiler/unsafe/TestUnsafeLoadControl.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/compiler/unsafe/TestUnsafeLoadControl.java Mon Jan 25 14:57:27 2016 -0800 @@ -0,0 +1,103 @@ +/* + * Copyright (c) 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 + * 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 8077504 + * @summary Unsafe load can loose control dependency and cause crash + * @run main/othervm -XX:-BackgroundCompilation -XX:-UseOnStackReplacement TestUnsafeLoadControl + * + */ + +import java.lang.reflect.Field; +import sun.misc.Unsafe; + +public class TestUnsafeLoadControl { + + private static final Unsafe UNSAFE; + + static { + try { + Field unsafeField = Unsafe.class.getDeclaredField("theUnsafe"); + unsafeField.setAccessible(true); + UNSAFE = (Unsafe) unsafeField.get(null); + } catch(Exception e) { + throw new RuntimeException(e); + } + } + + static int val; + static void test1(int[] a, boolean[] flags, boolean flag, long j) { + for (int i = 0; i < 10; i++) { + if (flags[i]) { + if (flag) { + long address = (j << 2) + UNSAFE.ARRAY_INT_BASE_OFFSET; + int v = UNSAFE.getInt(a, address); + val = v; + } + } + } + } + + static int test2(int[] a, boolean[] flags, boolean flag, long j) { + int sum = 0; + for (int i = 0; i < 10; i++) { + if (flags[i]) { + if (flag) { + long address = (j << 2) + UNSAFE.ARRAY_INT_BASE_OFFSET; + int v = UNSAFE.getInt(a, address); + if (v == 0) { + sum++; + } + } + } + } + return sum; + } + + static public void main(String[] args) { + boolean[] flags = new boolean[10]; + for (int i = 0; i < flags.length; i++) { + flags[i] = true; + } + int[] array = new int[10]; + for (int i = 0; i < 20000; i++) { + test1(array, flags, true, 0); + } + for (int i = 0; i < flags.length; i++) { + flags[i] = false; + } + test1(array, flags, true, Long.MAX_VALUE/4); + + for (int i = 0; i < flags.length; i++) { + flags[i] = true; + } + for (int i = 0; i < 20000; i++) { + test2(array, flags, true, 0); + } + for (int i = 0; i < flags.length; i++) { + flags[i] = false; + } + test2(array, flags, true, Long.MAX_VALUE/4); + } +} diff -r c2687aa5e5ca -r 7eb99acd567f test/gc/6581734/Test6581734.java --- a/test/gc/6581734/Test6581734.java Mon Jan 25 14:56:57 2016 -0800 +++ b/test/gc/6581734/Test6581734.java Mon Jan 25 14:57:27 2016 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2010, 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,6 +24,7 @@ /* * @test Test6581734.java * @bug 6581734 + * @requires vm.gc=="ConcMarkSweep" | vm.gc=="null" * @summary CMS Old Gen's collection usage is zero after GC which is incorrect * @run main/othervm -Xmx512m -verbose:gc -XX:+UseConcMarkSweepGC Test6581734 * diff -r c2687aa5e5ca -r 7eb99acd567f test/gc/TestSystemGC.java --- a/test/gc/TestSystemGC.java Mon Jan 25 14:56:57 2016 -0800 +++ b/test/gc/TestSystemGC.java Mon Jan 25 14:57:27 2016 -0800 @@ -1,5 +1,5 @@ /* -* Copyright (c) 2013, 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,6 +24,7 @@ /* * @test TestSystemGC * @key gc + * @requires vm.gc=="null" * @summary Runs System.gc() with different flags. * @run main/othervm TestSystemGC * @run main/othervm -XX:+UseSerialGC TestSystemGC diff -r c2687aa5e5ca -r 7eb99acd567f test/gc/arguments/TestAlignmentToUseLargePages.java --- a/test/gc/arguments/TestAlignmentToUseLargePages.java Mon Jan 25 14:56:57 2016 -0800 +++ b/test/gc/arguments/TestAlignmentToUseLargePages.java Mon Jan 25 14:57:27 2016 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 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 @@ -28,6 +28,7 @@ * @bug 8024396 * @key gc * @key regression + * @requires vm.gc=="null" * @run main/othervm -Xms7M -Xmx9M -XX:+UseParallelGC -XX:-UseParallelOldGC -XX:+UseLargePages TestAlignmentToUseLargePages * @run main/othervm -Xms7M -Xmx9M -XX:+UseParallelGC -XX:-UseParallelOldGC -XX:-UseLargePages TestAlignmentToUseLargePages * @run main/othervm -Xms7M -Xmx9M -XX:+UseParallelGC -XX:+UseParallelOldGC -XX:+UseLargePages TestAlignmentToUseLargePages diff -r c2687aa5e5ca -r 7eb99acd567f test/gc/arguments/TestG1HeapRegionSize.java --- a/test/gc/arguments/TestG1HeapRegionSize.java Mon Jan 25 14:56:57 2016 -0800 +++ b/test/gc/arguments/TestG1HeapRegionSize.java Mon Jan 25 14:57:27 2016 -0800 @@ -1,5 +1,5 @@ /* -* Copyright (c) 2013, 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 @@ -25,11 +25,12 @@ * @test TestG1HeapRegionSize * @key gc * @bug 8021879 + * @requires vm.gc=="G1" | vm.gc=="null" * @summary Verify that the flag G1HeapRegionSize is updated properly * @run main/othervm -Xmx64m TestG1HeapRegionSize 1048576 - * @run main/othervm -XX:G1HeapRegionSize=2m -Xmx64m TestG1HeapRegionSize 2097152 - * @run main/othervm -XX:G1HeapRegionSize=3m -Xmx64m TestG1HeapRegionSize 2097152 - * @run main/othervm -XX:G1HeapRegionSize=64m -Xmx256m TestG1HeapRegionSize 33554432 + * @run main/othervm -XX:G1HeapRegionSize=2m -Xmx64m -XX:+UseG1GC TestG1HeapRegionSize 2097152 + * @run main/othervm -XX:G1HeapRegionSize=3m -Xmx64m -XX:+UseG1GC TestG1HeapRegionSize 2097152 + * @run main/othervm -XX:G1HeapRegionSize=64m -Xmx256m -XX:+UseG1GC TestG1HeapRegionSize 33554432 */ import sun.management.ManagementFactoryHelper; @@ -41,14 +42,8 @@ public static void main(String[] args) { HotSpotDiagnosticMXBean diagnostic = ManagementFactoryHelper.getDiagnosticMXBean(); - VMOption option = diagnostic.getVMOption("UseG1GC"); - if (option.getValue().equals("false")) { - System.out.println("Skipping this test. It is only a G1 test."); - return; - } - String expectedValue = getExpectedValue(args); - option = diagnostic.getVMOption("G1HeapRegionSize"); + VMOption option = diagnostic.getVMOption("G1HeapRegionSize"); if (!expectedValue.equals(option.getValue())) { throw new RuntimeException("Wrong value for G1HeapRegionSize. Expected " + expectedValue + " but got " + option.getValue()); } diff -r c2687aa5e5ca -r 7eb99acd567f test/gc/concurrentMarkSweep/DisableResizePLAB.java --- a/test/gc/concurrentMarkSweep/DisableResizePLAB.java Mon Jan 25 14:56:57 2016 -0800 +++ b/test/gc/concurrentMarkSweep/DisableResizePLAB.java Mon Jan 25 14:57:27 2016 -0800 @@ -26,6 +26,7 @@ * @key gc * @bug 8060467 * @author filipp.zhinkin@oracle.com, john.coomes@oracle.com + * @requires vm.gc=="ConcMarkSweep" | vm.gc=="null" * @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 */ diff -r c2687aa5e5ca -r 7eb99acd567f test/gc/g1/Test2GbHeap.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/gc/g1/Test2GbHeap.java Mon Jan 25 14:57:27 2016 -0800 @@ -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 Test2GbHeap + * @bug 8031686 + * @summary Regression test to ensure we can start G1 with 2gb heap. + * @key gc + * @key regression + * @library /testlibrary + */ + +import java.util.ArrayList; + +import com.oracle.java.testlibrary.OutputAnalyzer; +import com.oracle.java.testlibrary.ProcessTools; + +public class Test2GbHeap { + public static void main(String[] args) throws Exception { + ArrayList testArguments = new ArrayList(); + + testArguments.add("-XX:+UseG1GC"); + testArguments.add("-Xmx2g"); + testArguments.add("-version"); + + ProcessBuilder pb = ProcessTools.createJavaProcessBuilder(testArguments.toArray(new String[0])); + + OutputAnalyzer output = new OutputAnalyzer(pb.start()); + + // Avoid failing test for setups not supported. + if (output.getOutput().contains("Could not reserve enough space for 2097152KB object heap")) { + // Will fail on machines with too little memory (and Windows 32-bit VM), ignore such failures. + output.shouldHaveExitValue(1); + } else if (output.getOutput().contains("G1 GC is disabled in this release")) { + // G1 is not supported on embedded, ignore such failures. + output.shouldHaveExitValue(1); + } else { + // Normally everything should be fine. + output.shouldHaveExitValue(0); + } + } +} diff -r c2687aa5e5ca -r 7eb99acd567f test/gc/g1/TestEagerReclaimHumongousRegions2.java --- a/test/gc/g1/TestEagerReclaimHumongousRegions2.java Mon Jan 25 14:56:57 2016 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,131 +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 TestEagerReclaimHumongousRegions2 - * @bug 8051973 - * @summary Test to make sure that eager reclaim of humongous objects correctly clears - * mark bitmaps at reclaim. - * @key gc - * @library /testlibrary - */ - -import java.util.ArrayList; -import java.util.LinkedList; -import java.util.Random; - -import com.oracle.java.testlibrary.OutputAnalyzer; -import com.oracle.java.testlibrary.ProcessTools; - -// An object that has a few references to other instances to slow down marking. -class ObjectWithSomeRefs { - public ObjectWithSomeRefs other1; - public ObjectWithSomeRefs other2; - public ObjectWithSomeRefs other3; - public ObjectWithSomeRefs other4; -} - -class ReclaimRegionFast { - public static final long MAX_MILLIS_FOR_RUN = 50 * 1000; // The maximum runtime for the actual test. - - public static final int M = 1024*1024; - - public static LinkedList garbageList = new LinkedList(); - - public static void genGarbage(Object large) { - for (int i = 0; i < 64*1024; i++) { - Object[] garbage = new Object[50]; - garbage[0] = large; - garbageList.add(garbage); - } - garbageList.clear(); - } - - public static ArrayList longList = new ArrayList(); - - public static void main(String[] args) { - - for (int i = 0; i < 16*1024; i++) { - longList.add(new ObjectWithSomeRefs()); - } - - Random rnd = new Random(); - for (int i = 0; i < longList.size(); i++) { - int len = longList.size(); - longList.get(i).other1 = longList.get(rnd.nextInt(len)); - longList.get(i).other2 = longList.get(rnd.nextInt(len)); - longList.get(i).other3 = longList.get(rnd.nextInt(len)); - longList.get(i).other4 = longList.get(rnd.nextInt(len)); - } - - int[] large1 = new int[M]; - int[] large2 = null; - int[] large3 = null; - int[] large4 = null; - - Object ref_from_stack = large1; - - long start_millis = System.currentTimeMillis(); - - for (int i = 0; i < 20; i++) { - long current_millis = System.currentTimeMillis(); - if ((current_millis - start_millis) > MAX_MILLIS_FOR_RUN) { - System.out.println("Finishing test because maximum runtime exceeded"); - break; - } - // A set of large objects that will be reclaimed eagerly - and hopefully marked. - large1 = new int[M - 20]; - large2 = new int[M - 20]; - large3 = new int[M - 20]; - large4 = new int[M - 20]; - genGarbage(large1); - // Make sure that the compiler cannot completely remove - // the allocation of the large object until here. - System.out.println(large1 + " " + large2 + " " + large3 + " " + large4); - } - - // Keep the reference to the first object alive. - System.out.println(ref_from_stack); - } -} - -public class TestEagerReclaimHumongousRegions2 { - public static void main(String[] args) throws Exception { - ProcessBuilder pb = ProcessTools.createJavaProcessBuilder( - "-XX:+UseG1GC", - "-Xms128M", - "-Xmx128M", - "-Xmn2M", - "-XX:G1HeapRegionSize=1M", - "-XX:InitiatingHeapOccupancyPercent=0", // Want to have as much as possible initial marks. - "-XX:+PrintGC", - "-XX:+VerifyAfterGC", - "-XX:ConcGCThreads=1", // Want to make marking as slow as possible. - "-XX:+IgnoreUnrecognizedVMOptions", // G1VerifyBitmaps is develop only. - "-XX:+G1VerifyBitmaps", - ReclaimRegionFast.class.getName()); - OutputAnalyzer output = new OutputAnalyzer(pb.start()); - output.shouldHaveExitValue(0); - } -} - diff -r c2687aa5e5ca -r 7eb99acd567f test/gc/g1/TestEagerReclaimHumongousRegionsClearMarkBits.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/gc/g1/TestEagerReclaimHumongousRegionsClearMarkBits.java Mon Jan 25 14:57:27 2016 -0800 @@ -0,0 +1,131 @@ +/* + * 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 TestEagerReclaimHumongousRegionsClearMarkBits + * @bug 8051973 + * @summary Test to make sure that eager reclaim of humongous objects correctly clears + * mark bitmaps at reclaim. + * @key gc + * @library /testlibrary + */ + +import java.util.ArrayList; +import java.util.LinkedList; +import java.util.Random; + +import com.oracle.java.testlibrary.OutputAnalyzer; +import com.oracle.java.testlibrary.ProcessTools; + +// An object that has a few references to other instances to slow down marking. +class ObjectWithSomeRefs { + public ObjectWithSomeRefs other1; + public ObjectWithSomeRefs other2; + public ObjectWithSomeRefs other3; + public ObjectWithSomeRefs other4; +} + +class ReclaimRegionFast { + public static final long MAX_MILLIS_FOR_RUN = 50 * 1000; // The maximum runtime for the actual test. + + public static final int M = 1024*1024; + + public static LinkedList garbageList = new LinkedList(); + + public static void genGarbage(Object large) { + for (int i = 0; i < 64*1024; i++) { + Object[] garbage = new Object[50]; + garbage[0] = large; + garbageList.add(garbage); + } + garbageList.clear(); + } + + public static ArrayList longList = new ArrayList(); + + public static void main(String[] args) { + + for (int i = 0; i < 16*1024; i++) { + longList.add(new ObjectWithSomeRefs()); + } + + Random rnd = new Random(); + for (int i = 0; i < longList.size(); i++) { + int len = longList.size(); + longList.get(i).other1 = longList.get(rnd.nextInt(len)); + longList.get(i).other2 = longList.get(rnd.nextInt(len)); + longList.get(i).other3 = longList.get(rnd.nextInt(len)); + longList.get(i).other4 = longList.get(rnd.nextInt(len)); + } + + int[] large1 = new int[M]; + int[] large2 = null; + int[] large3 = null; + int[] large4 = null; + + Object ref_from_stack = large1; + + long start_millis = System.currentTimeMillis(); + + for (int i = 0; i < 20; i++) { + long current_millis = System.currentTimeMillis(); + if ((current_millis - start_millis) > MAX_MILLIS_FOR_RUN) { + System.out.println("Finishing test because maximum runtime exceeded"); + break; + } + // A set of large objects that will be reclaimed eagerly - and hopefully marked. + large1 = new int[M - 20]; + large2 = new int[M - 20]; + large3 = new int[M - 20]; + large4 = new int[M - 20]; + genGarbage(large1); + // Make sure that the compiler cannot completely remove + // the allocation of the large object until here. + System.out.println(large1 + " " + large2 + " " + large3 + " " + large4); + } + + // Keep the reference to the first object alive. + System.out.println(ref_from_stack); + } +} + +public class TestEagerReclaimHumongousRegionsClearMarkBits { + public static void main(String[] args) throws Exception { + ProcessBuilder pb = ProcessTools.createJavaProcessBuilder( + "-XX:+UseG1GC", + "-Xms128M", + "-Xmx128M", + "-Xmn2M", + "-XX:G1HeapRegionSize=1M", + "-XX:InitiatingHeapOccupancyPercent=0", // Want to have as much as possible initial marks. + "-XX:+PrintGC", + "-XX:+VerifyAfterGC", + "-XX:ConcGCThreads=1", // Want to make marking as slow as possible. + "-XX:+IgnoreUnrecognizedVMOptions", // G1VerifyBitmaps is develop only. + "-XX:+G1VerifyBitmaps", + ReclaimRegionFast.class.getName()); + OutputAnalyzer output = new OutputAnalyzer(pb.start()); + output.shouldHaveExitValue(0); + } +} + diff -r c2687aa5e5ca -r 7eb99acd567f test/gc/g1/TestEagerReclaimHumongousRegionsWithRefs.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/gc/g1/TestEagerReclaimHumongousRegionsWithRefs.java Mon Jan 25 14:57:27 2016 -0800 @@ -0,0 +1,113 @@ +/* + * 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 TestEagerReclaimHumongousRegionsWithRefs + * @bug 8048179 + * @summary Test to make sure that eager reclaim of humongous objects that have previously + * been referenced by other old gen regions work. We simply try to fill + * up the heap with humongous objects and create a remembered set entry from an object by + * referencing that we know is in the old gen. After changing this reference, the object + * should still be eagerly reclaimable to avoid Full GC. + * @key gc + * @library /testlibrary + */ + +import java.util.regex.Pattern; +import java.util.regex.Matcher; +import java.util.LinkedList; + +import com.oracle.java.testlibrary.OutputAnalyzer; +import com.oracle.java.testlibrary.ProcessTools; +import static com.oracle.java.testlibrary.Asserts.*; + +class RefHolder { + Object ref; +} + +class ReclaimRegionFast { + + public static final int M = 1024*1024; + + public static LinkedList garbageList = new LinkedList(); + + public static void genGarbage() { + for (int i = 0; i < 32*1024; i++) { + garbageList.add(new int[100]); + } + garbageList.clear(); + } + + + // A large object referenced by a static. + static int[] filler = new int[10 * M]; + + // Old gen object referencing the large object, generating remembered + // set entries. + static RefHolder fromOld = new RefHolder(); + + public static void main(String[] args) { + + int[] large = new int[M]; + + Object ref_from_stack = large; + + for (int i = 0; i < 100; i++) { + // A large object that will be reclaimed eagerly. + large = new int[6*M]; + fromOld.ref = large; + genGarbage(); + } + + // Keep the reference to the first object alive. + System.out.println(ref_from_stack); + } +} + +public class TestEagerReclaimHumongousRegionsWithRefs { + + public static void main(String[] args) throws Exception { + ProcessBuilder pb = ProcessTools.createJavaProcessBuilder( + "-XX:+UseG1GC", + "-Xms128M", + "-Xmx128M", + "-Xmn16M", + "-XX:+PrintGC", + ReclaimRegionFast.class.getName()); + + Pattern p = Pattern.compile("Full GC"); + + OutputAnalyzer output = new OutputAnalyzer(pb.start()); + + int found = 0; + Matcher m = p.matcher(output.getStdout()); + while (m.find()) { + found++; + } + System.out.println("Issued " + found + " Full GCs"); + + assertLessThan(found, 10, "Found that " + found + " Full GCs were issued. This is larger than the bound. Eager reclaim of objects once referenced from old gen seems to not work at all"); + output.shouldHaveExitValue(0); + } +} + diff -r c2687aa5e5ca -r 7eb99acd567f test/gc/g1/TestG1TraceEagerReclaimHumongousObjects.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/gc/g1/TestG1TraceEagerReclaimHumongousObjects.java Mon Jan 25 14:57:27 2016 -0800 @@ -0,0 +1,142 @@ +/* + * 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 TestG1TraceEagerReclaimHumongousObjects + * @bug 8058801 8048179 + * @summary Ensure that the output for a G1TraceEagerReclaimHumongousObjects + * includes the expected necessary messages. + * @key gc + * @library /testlibrary + */ + +import com.oracle.java.testlibrary.ProcessTools; +import com.oracle.java.testlibrary.OutputAnalyzer; +import java.util.LinkedList; + +public class TestG1TraceEagerReclaimHumongousObjects { + public static void main(String[] args) throws Exception { + testGCLogs(); + testHumongousObjectGCLogs(); + } + + private static void testGCLogs() throws Exception { + + ProcessBuilder pb = ProcessTools.createJavaProcessBuilder("-XX:+UseG1GC", + "-Xms128M", + "-Xmx128M", + "-Xmn16M", + "-XX:G1HeapRegionSize=1M", + "-XX:+PrintGC", + "-XX:+UnlockExperimentalVMOptions", + "-XX:G1LogLevel=finest", + "-XX:+G1TraceEagerReclaimHumongousObjects", + GCTest.class.getName()); + + OutputAnalyzer output = new OutputAnalyzer(pb.start()); + + // As G1EagerReclaimHumongousObjects is set(default), below logs should be displayed. + // And GCTest doesn't have humongous objects, so values should be zero. + output.shouldContain("[Humongous Reclaim"); + output.shouldContain("[Humongous Total: 0]"); + output.shouldContain("[Humongous Candidate: 0]"); + output.shouldContain("[Humongous Reclaimed: 0]"); + + output.shouldHaveExitValue(0); + } + + private static void testHumongousObjectGCLogs() throws Exception { + ProcessBuilder pb = ProcessTools.createJavaProcessBuilder("-XX:+UseG1GC", + "-Xms128M", + "-Xmx128M", + "-Xmn16M", + "-XX:G1HeapRegionSize=1M", + "-XX:+PrintGC", + "-XX:+UnlockExperimentalVMOptions", + "-XX:G1LogLevel=finest", + "-XX:+G1TraceEagerReclaimHumongousObjects", + GCWithHumongousObjectTest.class.getName()); + + OutputAnalyzer output = new OutputAnalyzer(pb.start()); + + // As G1ReclaimDeadHumongousObjectsAtYoungGC is set(default), below logs should be displayed. + output.shouldContain("[Humongous Reclaim"); + output.shouldContain("[Humongous Total"); + output.shouldContain("[Humongous Candidate"); + output.shouldContain("[Humongous Reclaimed"); + + // As G1TraceReclaimDeadHumongousObjectsAtYoungGC is set and GCWithHumongousObjectTest has humongous objects, + // these logs should be displayed. + output.shouldContain("Live humongous"); + output.shouldContain("Dead humongous region"); + output.shouldHaveExitValue(0); + } + + static class GCTest { + private static byte[] garbage; + + public static void main(String [] args) { + System.out.println("Creating garbage"); + // create 128MB of garbage. This should result in at least one GC + for (int i = 0; i < 1024; i++) { + garbage = new byte[128 * 1024]; + } + System.out.println("Done"); + } + } + + static class GCWithHumongousObjectTest { + + public static final int M = 1024*1024; + public static LinkedList garbageList = new LinkedList(); + // A large object referenced by a static. + static int[] filler = new int[10 * M]; + + public static void genGarbage() { + for (int i = 0; i < 32*1024; i++) { + garbageList.add(new int[100]); + } + garbageList.clear(); + } + + public static void main(String[] args) { + + int[] large = new int[M]; + Object ref = large; + + System.out.println("Creating garbage"); + for (int i = 0; i < 100; i++) { + // A large object that will be reclaimed eagerly. + large = new int[6*M]; + genGarbage(); + // Make sure that the compiler cannot completely remove + // the allocation of the large object until here. + System.out.println(large); + } + + // Keep the reference to the first object alive. + System.out.println(ref); + System.out.println("Done"); + } + } +} diff -r c2687aa5e5ca -r 7eb99acd567f test/gc/g1/TestGCLogMessages.java --- a/test/gc/g1/TestGCLogMessages.java Mon Jan 25 14:56:57 2016 -0800 +++ b/test/gc/g1/TestGCLogMessages.java Mon Jan 25 14:57:27 2016 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 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 @@ -23,7 +23,7 @@ /* * @test TestGCLogMessages - * @bug 8035406 8027295 8035398 8019342 8027959 + * @bug 8035406 8027295 8035398 8019342 8027959 8048179 8027962 * @summary Ensure that the PrintGCDetails output for a minor GC with G1 * includes the expected necessary messages. * @key gc @@ -34,128 +34,159 @@ import com.oracle.java.testlibrary.OutputAnalyzer; public class TestGCLogMessages { - public static void main(String[] args) throws Exception { - testNormalLogs(); - testWithToSpaceExhaustionLogs(); - } - private static void testNormalLogs() throws Exception { - - ProcessBuilder pb = ProcessTools.createJavaProcessBuilder("-XX:+UseG1GC", - "-Xmx10M", - GCTest.class.getName()); + private enum Level { + OFF, FINER, FINEST; + public boolean lessOrEqualTo(Level other) { + return this.compareTo(other) < 0; + } + } - OutputAnalyzer output = new OutputAnalyzer(pb.start()); + private class LogMessageWithLevel { + String message; + Level level; - output.shouldNotContain("[Redirty Cards"); - output.shouldNotContain("[Parallel Redirty"); - output.shouldNotContain("[Redirtied Cards"); - output.shouldNotContain("[Code Root Purge"); - output.shouldNotContain("[String Dedup Fixup"); - output.shouldNotContain("[Young Free CSet"); - output.shouldNotContain("[Non-Young Free CSet"); - output.shouldNotContain("[Humongous Reclaim"); - output.shouldHaveExitValue(0); + public LogMessageWithLevel(String message, Level level) { + this.message = message; + this.level = level; + } + }; - pb = ProcessTools.createJavaProcessBuilder("-XX:+UseG1GC", - "-XX:+UseStringDeduplication", - "-Xmx10M", - "-XX:+PrintGCDetails", - GCTest.class.getName()); - - output = new OutputAnalyzer(pb.start()); + private LogMessageWithLevel allLogMessages[] = new LogMessageWithLevel[] { + // Ext Root Scan + new LogMessageWithLevel("Thread Roots (ms)", Level.FINEST), + new LogMessageWithLevel("StringTable Roots (ms)", Level.FINEST), + new LogMessageWithLevel("Universe Roots (ms)", Level.FINEST), + new LogMessageWithLevel("JNI Handles Roots (ms)", Level.FINEST), + new LogMessageWithLevel("ObjectSynchronizer Roots (ms)", Level.FINEST), + new LogMessageWithLevel("FlatProfiler Roots", Level.FINEST), + new LogMessageWithLevel("Management Roots", Level.FINEST), + new LogMessageWithLevel("SystemDictionary Roots", Level.FINEST), + new LogMessageWithLevel("CLDG Roots", Level.FINEST), + new LogMessageWithLevel("JVMTI Roots", Level.FINEST), + new LogMessageWithLevel("CodeCache Roots", Level.FINEST), + new LogMessageWithLevel("SATB Filtering", Level.FINEST), + new LogMessageWithLevel("CM RefProcessor Roots", Level.FINEST), + new LogMessageWithLevel("Wait For Strong CLD", Level.FINEST), + new LogMessageWithLevel("Weak CLD Roots", Level.FINEST), + // Redirty Cards + new LogMessageWithLevel("Redirty Cards", Level.FINER), + new LogMessageWithLevel("Parallel Redirty", Level.FINEST), + new LogMessageWithLevel("Redirtied Cards", Level.FINEST), + // Misc Top-level + new LogMessageWithLevel("Code Root Purge", Level.FINER), + new LogMessageWithLevel("String Dedup Fixup", Level.FINER), + // Free CSet + new LogMessageWithLevel("Young Free CSet", Level.FINEST), + new LogMessageWithLevel("Non-Young Free CSet", Level.FINEST), + // Humongous Eager Reclaim + new LogMessageWithLevel("Humongous Reclaim", Level.FINER), + new LogMessageWithLevel("Humongous Register", Level.FINER), + }; - output.shouldContain("[Redirty Cards"); - output.shouldNotContain("[Parallel Redirty"); - output.shouldNotContain("[Redirtied Cards"); - output.shouldContain("[Code Root Purge"); - output.shouldContain("[String Dedup Fixup"); - output.shouldNotContain("[Young Free CSet"); - output.shouldNotContain("[Non-Young Free CSet"); - output.shouldContain("[Humongous Reclaim"); - output.shouldNotContain("[Humongous Total"); - output.shouldNotContain("[Humongous Candidate"); - output.shouldNotContain("[Humongous Reclaimed"); - output.shouldHaveExitValue(0); + void checkMessagesAtLevel(OutputAnalyzer output, LogMessageWithLevel messages[], Level level) throws Exception { + for (LogMessageWithLevel l : messages) { + if (level.lessOrEqualTo(l.level)) { + output.shouldNotContain(l.message); + } else { + output.shouldContain(l.message); + } + } + } - pb = ProcessTools.createJavaProcessBuilder("-XX:+UseG1GC", - "-XX:+UseStringDeduplication", - "-Xmx10M", - "-XX:+PrintGCDetails", - "-XX:+UnlockExperimentalVMOptions", - "-XX:G1LogLevel=finest", - GCTest.class.getName()); + public static void main(String[] args) throws Exception { + new TestGCLogMessages().testNormalLogs(); + new TestGCLogMessages().testWithToSpaceExhaustionLogs(); + } + + private void testNormalLogs() throws Exception { - output = new OutputAnalyzer(pb.start()); + ProcessBuilder pb = ProcessTools.createJavaProcessBuilder("-XX:+UseG1GC", + "-Xmx10M", + GCTest.class.getName()); + + OutputAnalyzer output = new OutputAnalyzer(pb.start()); + checkMessagesAtLevel(output, allLogMessages, Level.OFF); + output.shouldHaveExitValue(0); - output.shouldContain("[Redirty Cards"); - output.shouldContain("[Parallel Redirty"); - output.shouldContain("[Redirtied Cards"); - output.shouldContain("[Code Root Purge"); - output.shouldContain("[String Dedup Fixup"); - output.shouldContain("[Young Free CSet"); - output.shouldContain("[Non-Young Free CSet"); - output.shouldContain("[Humongous Reclaim"); - output.shouldContain("[Humongous Total"); - output.shouldContain("[Humongous Candidate"); - output.shouldContain("[Humongous Reclaimed"); - output.shouldHaveExitValue(0); - } + pb = ProcessTools.createJavaProcessBuilder("-XX:+UseG1GC", + "-XX:+UseStringDeduplication", + "-Xmx10M", + "-XX:+PrintGCDetails", + GCTest.class.getName()); + + output = new OutputAnalyzer(pb.start()); + checkMessagesAtLevel(output, allLogMessages, Level.FINER); + + pb = ProcessTools.createJavaProcessBuilder("-XX:+UseG1GC", + "-XX:+UseStringDeduplication", + "-Xmx10M", + "-XX:+PrintGCDetails", + "-XX:+UnlockExperimentalVMOptions", + "-XX:G1LogLevel=finest", + GCTest.class.getName()); - private static void testWithToSpaceExhaustionLogs() throws Exception { - ProcessBuilder pb = ProcessTools.createJavaProcessBuilder("-XX:+UseG1GC", - "-Xmx10M", - "-Xmn5M", - "-XX:+PrintGCDetails", - GCTestWithToSpaceExhaustion.class.getName()); + output = new OutputAnalyzer(pb.start()); + checkMessagesAtLevel(output, allLogMessages, Level.FINEST); + output.shouldHaveExitValue(0); + } - OutputAnalyzer output = new OutputAnalyzer(pb.start()); - output.shouldContain("[Evacuation Failure"); - output.shouldNotContain("[Recalculate Used"); - output.shouldNotContain("[Remove Self Forwards"); - output.shouldNotContain("[Restore RemSet"); - output.shouldHaveExitValue(0); + LogMessageWithLevel exhFailureMessages[] = new LogMessageWithLevel[] { + new LogMessageWithLevel("Evacuation Failure", Level.FINER), + new LogMessageWithLevel("Recalculate Used", Level.FINEST), + new LogMessageWithLevel("Remove Self Forwards", Level.FINEST), + new LogMessageWithLevel("Restore RemSet", Level.FINEST), + }; - pb = ProcessTools.createJavaProcessBuilder("-XX:+UseG1GC", - "-Xmx10M", - "-Xmn5M", - "-XX:+PrintGCDetails", - "-XX:+UnlockExperimentalVMOptions", - "-XX:G1LogLevel=finest", - GCTestWithToSpaceExhaustion.class.getName()); + private void testWithToSpaceExhaustionLogs() throws Exception { + ProcessBuilder pb = ProcessTools.createJavaProcessBuilder("-XX:+UseG1GC", + "-Xmx32M", + "-Xmn16M", + "-XX:+PrintGCDetails", + GCTestWithToSpaceExhaustion.class.getName()); + + OutputAnalyzer output = new OutputAnalyzer(pb.start()); + checkMessagesAtLevel(output, exhFailureMessages, Level.FINER); + output.shouldHaveExitValue(0); - output = new OutputAnalyzer(pb.start()); - output.shouldContain("[Evacuation Failure"); - output.shouldContain("[Recalculate Used"); - output.shouldContain("[Remove Self Forwards"); - output.shouldContain("[Restore RemSet"); - output.shouldHaveExitValue(0); - } + pb = ProcessTools.createJavaProcessBuilder("-XX:+UseG1GC", + "-Xmx32M", + "-Xmn16M", + "-XX:+PrintGCDetails", + "-XX:+UnlockExperimentalVMOptions", + "-XX:G1LogLevel=finest", + GCTestWithToSpaceExhaustion.class.getName()); - static class GCTest { - private static byte[] garbage; - public static void main(String [] args) { - System.out.println("Creating garbage"); - // create 128MB of garbage. This should result in at least one GC - for (int i = 0; i < 1024; i++) { - garbage = new byte[128 * 1024]; - } - System.out.println("Done"); + output = new OutputAnalyzer(pb.start()); + checkMessagesAtLevel(output, exhFailureMessages, Level.FINEST); + output.shouldHaveExitValue(0); } - } + + static class GCTest { + private static byte[] garbage; + public static void main(String [] args) { + System.out.println("Creating garbage"); + // create 128MB of garbage. This should result in at least one GC + for (int i = 0; i < 1024; i++) { + garbage = new byte[128 * 1024]; + } + System.out.println("Done"); + } + } - static class GCTestWithToSpaceExhaustion { - private static byte[] garbage; - private static byte[] largeObject; - public static void main(String [] args) { - largeObject = new byte[5*1024*1024]; - System.out.println("Creating garbage"); - // create 128MB of garbage. This should result in at least one GC, - // some of them with to-space exhaustion. - for (int i = 0; i < 1024; i++) { - garbage = new byte[128 * 1024]; - } - System.out.println("Done"); + static class GCTestWithToSpaceExhaustion { + private static byte[] garbage; + private static byte[] largeObject; + public static void main(String [] args) { + largeObject = new byte[16*1024*1024]; + System.out.println("Creating garbage"); + // create 128MB of garbage. This should result in at least one GC, + // some of them with to-space exhaustion. + for (int i = 0; i < 1024; i++) { + garbage = new byte[128 * 1024]; + } + System.out.println("Done"); + } } - } } + diff -r c2687aa5e5ca -r 7eb99acd567f test/gc/g1/TestGreyReclaimedHumongousObjects.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/gc/g1/TestGreyReclaimedHumongousObjects.java Mon Jan 25 14:57:27 2016 -0800 @@ -0,0 +1,176 @@ +/* + * Copyright (c) 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 + * 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 TestGreyReclaimedHumongousObjects.java + * @bug 8069367 + * @requires vm.gc == "G1" | vm.gc == "null" + * @summary Test handling of marked but unscanned reclaimed humongous objects. + * @key gc + * @run main/othervm -XX:+UseG1GC -Xss32m -Xmx128m -XX:G1HeapRegionSize=1m + * -XX:+UnlockExperimentalVMOptions + * -XX:+G1EagerReclaimHumongousObjects + * -XX:+G1EagerReclaimHumongousObjectsWithStaleRefs + * TestGreyReclaimedHumongousObjects 1048576 90 + */ + +// This test spawns a bunch of threads, each of them rapidly +// allocating large objects and storing them into a circular buffer +// associated with the thread. The circular buffer results in these +// objects becoming dead in fairly short order. +// +// The situation we're trying to provoke is +// +// (1) A humongous object H is marked and added to the mark stack. +// +// (2) An evacuation pause determines H is no longer live, and +// reclaims it. This occurs before concurrent marking has gotten +// around to processing the mark stack entry for H. +// +// (3) Concurrent marking processes the mark stack entry for H. The +// bug is that it would attempt to scan the now dead object. +// +// Unfortunately, this test is *very* sensitive to configuration. +// Among the parameters that affect whether / how often we'll get into +// the desired situation within a reasonable amount of time are: +// +// - THREAD_COUNT: The number of allocating threads. +// +// - OLD_COUNT: The number of objects each thread keeps. +// +// - MAX_MEMORY: The maximum heap size. +// +// - G1HeapRegionSize +// +// - The size of the objects being allocated. +// +// The parameter values specified here: +// +// - THREAD_COUNT = 12 +// - OLD_COUNT == 4 +// - MAX_MEMORY == 128m +// - G1HeapRegionSize = 1m +// - Object size = 1048576 (2 regions after header overhead and roundup) +// +// seems to work well at provoking the desired state fairly quickly. +// Even relatively small perturbations may change that. The key +// factors seem to be keeping the heap mostly full of live objects but +// having them become dead fairly quickly. + +import java.util.Date; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.ThreadFactory; +import java.util.concurrent.TimeUnit; +import sun.management.ManagementFactoryHelper; +import com.sun.management.HotSpotDiagnosticMXBean; +import com.sun.management.VMOption; + +public class TestGreyReclaimedHumongousObjects { + + static class NamedThreadFactory implements ThreadFactory { + private int threadNum = 0; + + @Override + public Thread newThread(Runnable r) { + return new Thread(r, THREAD_NAME + (threadNum++)); + } + } + + static class Runner extends Thread { + private final Date startDate = new Date(); + private final int obj_size; + private final Object[] old_garbage; + private int old_index = 0; + + public Runner(int obj_size) { + this.obj_size = obj_size; + old_garbage = new Object[OLD_COUNT]; + } + + private void allocate_garbage() { + byte[] garbage = new byte[obj_size]; + old_garbage[Math.abs(++old_index % OLD_COUNT)] = garbage; + } + + @Override + public void run() { + try { + while (!isInterrupted()) { + allocate_garbage(); + Thread.sleep(0); // Yield, to ensure interruptable. + } + } catch (InterruptedException e) { + System.out.println("Aborted after " + + (new Date().getTime() - startDate.getTime()) + + " ms"); + interrupt(); + } + } + } + + public static void main(String[] args) throws Exception { + HotSpotDiagnosticMXBean diagnostic = ManagementFactoryHelper.getDiagnosticMXBean(); + + System.out.println("Max memory= " + MAX_MEMORY + " bytes"); + + int obj_size = 0; + long seconds_to_run = 0; + if (args.length != 2) { + throw new RuntimeException("Object size argument must be supplied"); + } else { + obj_size = Integer.parseInt(args[0]); + seconds_to_run = Integer.parseInt(args[1]); + } + System.out.println("Objects size= " + obj_size + " bytes"); + System.out.println("Seconds to run=" + seconds_to_run); + + int region_size = + Integer.parseInt(diagnostic.getVMOption("G1HeapRegionSize").getValue()); + if (obj_size < (region_size / 2)) { + throw new RuntimeException("Object size " + obj_size + + " is not humongous with region size " + region_size); + } + + ExecutorService executor = + Executors.newFixedThreadPool(THREAD_COUNT, new NamedThreadFactory()); + System.out.println("Starting " + THREAD_COUNT + " threads"); + + for (int i = 0; i < THREAD_COUNT; i++) { + executor.execute(new Runner(obj_size)); + } + + Thread.sleep(seconds_to_run * 1000); + executor.shutdownNow(); + + if (!executor.awaitTermination(10, TimeUnit.SECONDS)) { + System.err.println("Thread pool did not terminate after 10 seconds after shutdown"); + } + } + + private static final long MAX_MEMORY = Runtime.getRuntime().maxMemory(); + private static final int OLD_COUNT = 4; + private static final int THREAD_COUNT = 12; + private static final String THREAD_NAME = "TestGreyRH-"; +} + diff -r c2687aa5e5ca -r 7eb99acd567f test/gc/g1/TestHumongousShrinkHeap.java --- a/test/gc/g1/TestHumongousShrinkHeap.java Mon Jan 25 14:56:57 2016 -0800 +++ b/test/gc/g1/TestHumongousShrinkHeap.java Mon Jan 25 14:57:27 2016 -0800 @@ -24,6 +24,7 @@ /** * @test TestHumongousShrinkHeap * @bug 8036025 8056043 + * @requires vm.gc=="G1" | vm.gc=="null" * @summary Verify that heap shrinks after GC in the presence of fragmentation * due to humongous objects * @library /testlibrary diff -r c2687aa5e5ca -r 7eb99acd567f test/gc/g1/TestLargePageUseForAuxMemory.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/gc/g1/TestLargePageUseForAuxMemory.java Mon Jan 25 14:57:27 2016 -0800 @@ -0,0 +1,129 @@ +/* + * Copyright (c) 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 + * 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 TestLargePageUseForAuxMemory.java + * @bug 8058354 + * @key gc + * @library /testlibrary /testlibrary/whitebox + * @requires (vm.gc=="G1" | vm.gc=="null") + * @build TestLargePageUseForAuxMemory + * @run main ClassFileInstaller sun.hotspot.WhiteBox + * sun.hotspot.WhiteBox$WhiteBoxPermission + * @summary Test that auxiliary data structures are allocated using large pages if available. + * @run main/othervm -Xbootclasspath/a:. -XX:+UseG1GC -XX:+WhiteBoxAPI -XX:+IgnoreUnrecognizedVMOptions -XX:+UseLargePages TestLargePageUseForAuxMemory + */ + +import com.oracle.java.testlibrary.*; +import sun.hotspot.WhiteBox; + +public class TestLargePageUseForAuxMemory { + static final int HEAP_REGION_SIZE = 4 * 1024 * 1024; + static long largePageSize; + static long smallPageSize; + + static void checkSmallTables(OutputAnalyzer output, long expectedPageSize) throws Exception { + output.shouldContain("G1 'Block offset table': pg_sz=" + expectedPageSize); + output.shouldContain("G1 'Card counts table': pg_sz=" + expectedPageSize); + } + + static void checkBitmaps(OutputAnalyzer output, long expectedPageSize) throws Exception { + output.shouldContain("G1 'Prev Bitmap': pg_sz=" + expectedPageSize); + output.shouldContain("G1 'Next Bitmap': pg_sz=" + expectedPageSize); + } + + static void testVM(long heapsize, boolean cardsShouldUseLargePages, boolean bitmapShouldUseLargePages) throws Exception { + ProcessBuilder pb; + // Test with large page enabled. + pb = ProcessTools.createJavaProcessBuilder("-XX:+UseG1GC", + "-XX:G1HeapRegionSize=" + HEAP_REGION_SIZE, + "-Xms" + 10 * HEAP_REGION_SIZE, + "-Xmx" + heapsize, + "-XX:+TracePageSizes", + "-XX:+UseLargePages", + "-XX:+IgnoreUnrecognizedVMOptions", // there is on ObjectAlignmentInBytes in 32 bit builds + "-XX:ObjectAlignmentInBytes=8", + "-version"); + + OutputAnalyzer output = new OutputAnalyzer(pb.start()); + checkSmallTables(output, (cardsShouldUseLargePages ? largePageSize : smallPageSize)); + checkBitmaps(output, (bitmapShouldUseLargePages ? largePageSize : smallPageSize)); + output.shouldHaveExitValue(0); + + // Test with large page disabled. + pb = ProcessTools.createJavaProcessBuilder("-XX:+UseG1GC", + "-XX:G1HeapRegionSize=" + HEAP_REGION_SIZE, + "-Xms" + 10 * HEAP_REGION_SIZE, + "-Xmx" + heapsize, + "-XX:+TracePageSizes", + "-XX:-UseLargePages", + "-XX:+IgnoreUnrecognizedVMOptions", // there is on ObjectAlignmentInBytes in 32 bit builds + "-XX:ObjectAlignmentInBytes=8", + "-version"); + + output = new OutputAnalyzer(pb.start()); + checkSmallTables(output, smallPageSize); + checkBitmaps(output, smallPageSize); + output.shouldHaveExitValue(0); + } + + public static void main(String[] args) throws Exception { + if (!Platform.isDebugBuild()) { + System.out.println("Skip tests on non-debug builds because the required option TracePageSizes is a debug-only option."); + return; + } + + WhiteBox wb = WhiteBox.getWhiteBox(); + smallPageSize = wb.getVMPageSize(); + largePageSize = wb.getVMLargePageSize(); + + if (largePageSize == 0) { + System.out.println("Skip tests because large page support does not seem to be available on this platform."); + return; + } + + // To get large pages for the card table etc. we need at least a 1G heap (with 4k page size). + // 32 bit systems will have problems reserving such an amount of contiguous space, so skip the + // test there. + if (!Platform.is32bit()) { + // Size that a single card covers. + final int cardSize = 512; + + final long heapSizeForCardTableUsingLargePages = largePageSize * cardSize; + + testVM(heapSizeForCardTableUsingLargePages, true, true); + testVM(heapSizeForCardTableUsingLargePages + HEAP_REGION_SIZE, true, true); + testVM(heapSizeForCardTableUsingLargePages - HEAP_REGION_SIZE, false, true); + } + + // Minimum heap requirement to get large pages for bitmaps is 128M heap. This seems okay to test + // everywhere. + final int bitmapTranslationFactor = 8 * 8; // ObjectAlignmentInBytes * BitsPerByte + final long heapSizeForBitmapUsingLargePages = largePageSize * bitmapTranslationFactor; + + testVM(heapSizeForBitmapUsingLargePages, false, true); + testVM(heapSizeForBitmapUsingLargePages + HEAP_REGION_SIZE, false, true); + testVM(heapSizeForBitmapUsingLargePages - HEAP_REGION_SIZE, false, false); + } +} + diff -r c2687aa5e5ca -r 7eb99acd567f test/gc/g1/TestRegionAlignment.java --- a/test/gc/g1/TestRegionAlignment.java Mon Jan 25 14:56:57 2016 -0800 +++ b/test/gc/g1/TestRegionAlignment.java Mon Jan 25 14:57:27 2016 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 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,6 +24,7 @@ /* * @test TestRegionAlignment.java * @bug 8013791 + * @requires vm.gc=="G1" | vm.gc=="null" * @summary Make sure that G1 ergonomics pick a heap size that is aligned with the region size * @run main/othervm -XX:+UseG1GC -XX:G1HeapRegionSize=32m -XX:MaxRAM=555m TestRegionAlignment * diff -r c2687aa5e5ca -r 7eb99acd567f test/gc/g1/TestShrinkAuxiliaryData.java --- a/test/gc/g1/TestShrinkAuxiliaryData.java Mon Jan 25 14:56:57 2016 -0800 +++ b/test/gc/g1/TestShrinkAuxiliaryData.java Mon Jan 25 14:57:27 2016 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 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 @@ -21,7 +21,7 @@ * questions. */ -import static com.oracle.java.testlibrary.Asserts.assertLessThanOrEqual; +import com.oracle.java.testlibrary.Asserts; import com.oracle.java.testlibrary.OutputAnalyzer; import com.oracle.java.testlibrary.Platform; import com.oracle.java.testlibrary.ProcessTools; @@ -36,23 +36,29 @@ import java.util.Collections; import java.util.LinkedList; import java.util.List; -import sun.misc.Unsafe; +import sun.misc.Unsafe; // for ADDRESS_SIZE +import sun.hotspot.WhiteBox; public class TestShrinkAuxiliaryData { + private static final int REGION_SIZE = 1024 * 1024; + private final static String[] initialOpts = new String[]{ "-XX:MinHeapFreeRatio=10", "-XX:MaxHeapFreeRatio=11", "-XX:+UseG1GC", - "-XX:G1HeapRegionSize=1m", + "-XX:G1HeapRegionSize=" + REGION_SIZE, "-XX:-ExplicitGCInvokesConcurrent", - "-XX:+PrintGCDetails" + "-XX:+PrintGCDetails", + "-XX:+UnlockDiagnosticVMOptions", + "-XX:+WhiteBoxAPI", + "-Xbootclasspath/a:.", }; - private final int RSetCacheSize; + private final int hotCardTableSize; - protected TestShrinkAuxiliaryData(int RSetCacheSize) { - this.RSetCacheSize = RSetCacheSize; + protected TestShrinkAuxiliaryData(int hotCardTableSize) { + this.hotCardTableSize = hotCardTableSize; } protected void test() throws Exception { @@ -60,19 +66,17 @@ Collections.addAll(vmOpts, initialOpts); int maxCacheSize = Math.max(0, Math.min(31, getMaxCacheSize())); - if (maxCacheSize < RSetCacheSize) { + if (maxCacheSize < hotCardTableSize) { System.out.format("Skiping test for %d cache size due max cache size %d", - RSetCacheSize, maxCacheSize + hotCardTableSize, maxCacheSize ); return; } printTestInfo(maxCacheSize); - vmOpts.add("-XX:G1ConcRSLogCacheSize=" + RSetCacheSize); - - vmOpts.addAll(Arrays.asList(Utils.getFilteredTestJavaOpts( - ShrinkAuxiliaryDataTest.prohibitedVmOptions))); + vmOpts.add("-XX:G1ConcRSLogCacheSize=" + hotCardTableSize); + vmOpts.addAll(Arrays.asList(Utils.getTestJavaOpts())); // for 32 bits ObjectAlignmentInBytes is not a option if (Platform.is32bit()) { @@ -94,11 +98,13 @@ private void performTest(List opts) throws Exception { ProcessBuilder pb - = ProcessTools.createJavaProcessBuilder( - opts.toArray(new String[opts.size()]) - ); + = ProcessTools.createJavaProcessBuilder( + opts.toArray(new String[opts.size()]) + ); OutputAnalyzer output = new OutputAnalyzer(pb.start()); + System.out.println(output.getStdout()); + System.err.println(output.getStderr()); output.shouldHaveExitValue(0); } @@ -109,12 +115,13 @@ formatSymbols.setGroupingSeparator(' '); grouped.setDecimalFormatSymbols(formatSymbols); - System.out.format("Test will use %s bytes of memory of %s available%n" + System.out.format( + "Test will use %s bytes of memory of %s available%n" + "Available memory is %s with %d bytes pointer size - can save %s pointers%n" + "Max cache size: 2^%d = %s elements%n", grouped.format(ShrinkAuxiliaryDataTest.getMemoryUsedByTest()), - grouped.format(Runtime.getRuntime().freeMemory()), - grouped.format(Runtime.getRuntime().freeMemory() + grouped.format(Runtime.getRuntime().maxMemory()), + grouped.format(Runtime.getRuntime().maxMemory() - ShrinkAuxiliaryDataTest.getMemoryUsedByTest()), Unsafe.ADDRESS_SIZE, grouped.format((Runtime.getRuntime().freeMemory() @@ -137,6 +144,7 @@ if (availableMemory <= 0) { return 0; } + long availablePointersCount = availableMemory / Unsafe.ADDRESS_SIZE; return (63 - (int) Long.numberOfLeadingZeros(availablePointersCount)); } @@ -144,17 +152,48 @@ static class ShrinkAuxiliaryDataTest { public static void main(String[] args) throws IOException { - int iterateCount = DEFAULT_ITERATION_COUNT; + + ShrinkAuxiliaryDataTest testCase = new ShrinkAuxiliaryDataTest(); - if (args.length > 0) { - try { - iterateCount = Integer.parseInt(args[0]); - } catch (NumberFormatException e) { - //num_iterate remains default - } + if (!testCase.checkEnvApplicability()) { + return; } - new ShrinkAuxiliaryDataTest().test(iterateCount); + testCase.test(); + } + + /** + * Checks is this environment suitable to run this test + * - memory is enough to decommit (page size is not big) + * - RSet cache size is not too big + * + * @return true if test could run, false if test should be skipped + */ + protected boolean checkEnvApplicability() { + + int pageSize = WhiteBox.getWhiteBox().getVMPageSize(); + System.out.println( "Page size = " + pageSize + + " region size = " + REGION_SIZE + + " aux data ~= " + (REGION_SIZE * 3 / 100)); + // If auxdata size will be less than page size it wouldn't decommit. + // Auxiliary data size is about ~3.6% of heap size. + if (pageSize >= REGION_SIZE * 3 / 100) { + System.out.format("Skipping test for too large page size = %d", + pageSize + ); + return false; + } + + if (REGION_SIZE * REGIONS_TO_ALLOCATE > Runtime.getRuntime().maxMemory()) { + System.out.format("Skipping test for too low available memory. " + + "Need %d, available %d", + REGION_SIZE * REGIONS_TO_ALLOCATE, + Runtime.getRuntime().maxMemory() + ); + return false; + } + + return true; } class GarbageObject { @@ -179,41 +218,54 @@ private final List garbage = new ArrayList(); - public void test(int num_iterate) throws IOException { + public void test() throws IOException { + + MemoryUsage muFull, muFree, muAuxDataFull, muAuxDataFree; + float auxFull, auxFree; allocate(); link(); mutate(); - deallocate(); + + muFull = ManagementFactory.getMemoryMXBean().getHeapMemoryUsage(); + long numUsedRegions = WhiteBox.getWhiteBox().g1NumMaxRegions() + - WhiteBox.getWhiteBox().g1NumFreeRegions(); + muAuxDataFull = WhiteBox.getWhiteBox().g1AuxiliaryMemoryUsage(); + auxFull = (float)muAuxDataFull.getUsed() / numUsedRegions; - MemoryUsage muBeforeHeap - = ManagementFactory.getMemoryMXBean().getHeapMemoryUsage(); - MemoryUsage muBeforeNonHeap - = ManagementFactory.getMemoryMXBean().getNonHeapMemoryUsage(); + System.out.format("Full aux data ratio= %f, regions max= %d, used= %d\n", + auxFull, WhiteBox.getWhiteBox().g1NumMaxRegions(), numUsedRegions + ); + + deallocate(); + System.gc(); - for (int i = 0; i < num_iterate; i++) { - allocate(); - link(); - mutate(); - deallocate(); - } + muFree = ManagementFactory.getMemoryMXBean().getHeapMemoryUsage(); + muAuxDataFree = WhiteBox.getWhiteBox().g1AuxiliaryMemoryUsage(); + + numUsedRegions = WhiteBox.getWhiteBox().g1NumMaxRegions() + - WhiteBox.getWhiteBox().g1NumFreeRegions(); + auxFree = (float)muAuxDataFree.getUsed() / numUsedRegions; - System.gc(); - MemoryUsage muAfterHeap - = ManagementFactory.getMemoryMXBean().getHeapMemoryUsage(); - MemoryUsage muAfterNonHeap - = ManagementFactory.getMemoryMXBean().getNonHeapMemoryUsage(); + System.out.format("Free aux data ratio= %f, regions max= %d, used= %d\n", + auxFree, WhiteBox.getWhiteBox().g1NumMaxRegions(), numUsedRegions + ); - assertLessThanOrEqual(muAfterHeap.getCommitted(), muBeforeHeap.getCommitted(), - String.format("heap decommit failed - after > before: %d > %d", - muAfterHeap.getCommitted(), muBeforeHeap.getCommitted() + Asserts.assertLessThanOrEqual(muFree.getCommitted(), muFull.getCommitted(), + String.format("heap decommit failed - full > free: %d > %d", + muFree.getCommitted(), muFull.getCommitted() ) ); - if (muAfterHeap.getCommitted() < muBeforeHeap.getCommitted()) { - assertLessThanOrEqual(muAfterNonHeap.getCommitted(), muBeforeNonHeap.getCommitted(), - String.format("non-heap decommit failed - after > before: %d > %d", - muAfterNonHeap.getCommitted(), muBeforeNonHeap.getCommitted() + System.out.format("State used committed\n"); + System.out.format("Full aux data: %10d %10d\n", muAuxDataFull.getUsed(), muAuxDataFull.getCommitted()); + System.out.format("Free aux data: %10d %10d\n", muAuxDataFree.getUsed(), muAuxDataFree.getCommitted()); + + // if decommited check that aux data has same ratio + if (muFree.getCommitted() < muFull.getCommitted()) { + Asserts.assertLessThanOrEqual(auxFree, auxFull, + String.format("auxiliary data decommit failed - full > free: %f > %f", + auxFree, auxFull ) ); } @@ -240,8 +292,7 @@ for (int i = 0; i < NUM_LINKS; i++) { int regionToLink; do { - regionToLink = (int) (Math.random() - * REGIONS_TO_ALLOCATE); + regionToLink = (int) (Math.random() * REGIONS_TO_ALLOCATE); } while (regionToLink == regionNumber); // get random garbage object from random region @@ -267,21 +318,8 @@ return REGIONS_TO_ALLOCATE * REGION_SIZE; } - private static final int REGION_SIZE = 1024 * 1024; - private static final int DEFAULT_ITERATION_COUNT = 1; // iterate main scenario - private static final int REGIONS_TO_ALLOCATE = 5; + private static final int REGIONS_TO_ALLOCATE = 100; private static final int NUM_OBJECTS_PER_REGION = 10; private static final int NUM_LINKS = 20; // how many links create for each object - - private static final String[] prohibitedVmOptions = { - // remove this when @requires option will be on duty - "-XX:\\+UseParallelGC", - "-XX:\\+UseSerialGC", - "-XX:\\+UseConcMarkSweepGC", - "-XX:\\+UseParallelOldGC", - "-XX:\\+UseParNewGC", - "-Xconcgc", - "-Xincgc" - }; } } diff -r c2687aa5e5ca -r 7eb99acd567f test/gc/g1/TestShrinkAuxiliaryData00.java --- a/test/gc/g1/TestShrinkAuxiliaryData00.java Mon Jan 25 14:56:57 2016 -0800 +++ b/test/gc/g1/TestShrinkAuxiliaryData00.java Mon Jan 25 14:57:27 2016 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 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 @@ -23,11 +23,15 @@ /** * @test TestShrinkAuxiliaryData00 - * @bug 8038423 + * @bug 8038423 8061715 * @summary Checks that decommitment occurs for JVM with different * G1ConcRSLogCacheSize and ObjectAlignmentInBytes options values + * @requires vm.gc=="G1" | vm.gc=="null" * @library /testlibrary /testlibrary/whitebox - * @build TestShrinkAuxiliaryData TestShrinkAuxiliaryData00 + * @build com.oracle.java.testlibrary.* sun.hotspot.WhiteBox + * TestShrinkAuxiliaryData TestShrinkAuxiliaryData00 + * @run main ClassFileInstaller sun.hotspot.WhiteBox + * sun.hotspot.WhiteBox$WhiteBoxPermission * @run driver/timeout=720 TestShrinkAuxiliaryData00 */ public class TestShrinkAuxiliaryData00 { diff -r c2687aa5e5ca -r 7eb99acd567f test/gc/g1/TestShrinkAuxiliaryData05.java --- a/test/gc/g1/TestShrinkAuxiliaryData05.java Mon Jan 25 14:56:57 2016 -0800 +++ b/test/gc/g1/TestShrinkAuxiliaryData05.java Mon Jan 25 14:57:27 2016 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 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 @@ -23,11 +23,15 @@ /** * @test TestShrinkAuxiliaryData05 - * @bug 8038423 + * @bug 8038423 8061715 * @summary Checks that decommitment occurs for JVM with different * G1ConcRSLogCacheSize and ObjectAlignmentInBytes options values + * @requires vm.gc=="G1" | vm.gc=="null" * @library /testlibrary /testlibrary/whitebox - * @build TestShrinkAuxiliaryData TestShrinkAuxiliaryData05 + * @build com.oracle.java.testlibrary.* sun.hotspot.WhiteBox + * TestShrinkAuxiliaryData TestShrinkAuxiliaryData05 + * @run main ClassFileInstaller sun.hotspot.WhiteBox + * sun.hotspot.WhiteBox$WhiteBoxPermission * @run driver/timeout=720 TestShrinkAuxiliaryData05 */ public class TestShrinkAuxiliaryData05 { diff -r c2687aa5e5ca -r 7eb99acd567f test/gc/g1/TestShrinkAuxiliaryData10.java --- a/test/gc/g1/TestShrinkAuxiliaryData10.java Mon Jan 25 14:56:57 2016 -0800 +++ b/test/gc/g1/TestShrinkAuxiliaryData10.java Mon Jan 25 14:57:27 2016 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 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 @@ -23,11 +23,15 @@ /** * @test TestShrinkAuxiliaryData10 - * @bug 8038423 + * @bug 8038423 8061715 * @summary Checks that decommitment occurs for JVM with different * G1ConcRSLogCacheSize and ObjectAlignmentInBytes options values + * @requires vm.gc=="G1" | vm.gc=="null" * @library /testlibrary /testlibrary/whitebox + * @build com.oracle.java.testlibrary.* sun.hotspot.WhiteBox * @build TestShrinkAuxiliaryData TestShrinkAuxiliaryData10 + * @run main ClassFileInstaller sun.hotspot.WhiteBox + * sun.hotspot.WhiteBox$WhiteBoxPermission * @run driver/timeout=720 TestShrinkAuxiliaryData10 */ public class TestShrinkAuxiliaryData10 { diff -r c2687aa5e5ca -r 7eb99acd567f test/gc/g1/TestShrinkAuxiliaryData15.java --- a/test/gc/g1/TestShrinkAuxiliaryData15.java Mon Jan 25 14:56:57 2016 -0800 +++ b/test/gc/g1/TestShrinkAuxiliaryData15.java Mon Jan 25 14:57:27 2016 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 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 @@ -23,11 +23,15 @@ /** * @test TestShrinkAuxiliaryData15 - * @bug 8038423 + * @bug 8038423 8061715 * @summary Checks that decommitment occurs for JVM with different * G1ConcRSLogCacheSize and ObjectAlignmentInBytes options values + * @requires vm.gc=="G1" | vm.gc=="null" * @library /testlibrary /testlibrary/whitebox + * @build com.oracle.java.testlibrary.* sun.hotspot.WhiteBox * @build TestShrinkAuxiliaryData TestShrinkAuxiliaryData15 + * @run main ClassFileInstaller sun.hotspot.WhiteBox + * sun.hotspot.WhiteBox$WhiteBoxPermission * @run driver/timeout=720 TestShrinkAuxiliaryData15 */ public class TestShrinkAuxiliaryData15 { diff -r c2687aa5e5ca -r 7eb99acd567f test/gc/g1/TestShrinkAuxiliaryData20.java --- a/test/gc/g1/TestShrinkAuxiliaryData20.java Mon Jan 25 14:56:57 2016 -0800 +++ b/test/gc/g1/TestShrinkAuxiliaryData20.java Mon Jan 25 14:57:27 2016 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 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 @@ -23,11 +23,15 @@ /** * @test TestShrinkAuxiliaryData20 - * @bug 8038423 + * @bug 8038423 8061715 * @summary Checks that decommitment occurs for JVM with different * G1ConcRSLogCacheSize and ObjectAlignmentInBytes options values + * @requires vm.gc=="G1" | vm.gc=="null" * @library /testlibrary /testlibrary/whitebox + * @build com.oracle.java.testlibrary.* sun.hotspot.WhiteBox * @build TestShrinkAuxiliaryData TestShrinkAuxiliaryData20 + * @run main ClassFileInstaller sun.hotspot.WhiteBox + * sun.hotspot.WhiteBox$WhiteBoxPermission * @run driver/timeout=720 TestShrinkAuxiliaryData20 */ public class TestShrinkAuxiliaryData20 { diff -r c2687aa5e5ca -r 7eb99acd567f test/gc/g1/TestShrinkAuxiliaryData25.java --- a/test/gc/g1/TestShrinkAuxiliaryData25.java Mon Jan 25 14:56:57 2016 -0800 +++ b/test/gc/g1/TestShrinkAuxiliaryData25.java Mon Jan 25 14:57:27 2016 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 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 @@ -23,11 +23,15 @@ /** * @test TestShrinkAuxiliaryData25 - * @bug 8038423 + * @bug 8038423 8061715 * @summary Checks that decommitment occurs for JVM with different * G1ConcRSLogCacheSize and ObjectAlignmentInBytes options values + * @requires vm.gc=="G1" | vm.gc=="null" * @library /testlibrary /testlibrary/whitebox + * @build com.oracle.java.testlibrary.* sun.hotspot.WhiteBox * @build TestShrinkAuxiliaryData TestShrinkAuxiliaryData25 + * @run main ClassFileInstaller sun.hotspot.WhiteBox + * sun.hotspot.WhiteBox$WhiteBoxPermission * @run driver/timeout=720 TestShrinkAuxiliaryData25 */ public class TestShrinkAuxiliaryData25 { diff -r c2687aa5e5ca -r 7eb99acd567f test/gc/g1/TestShrinkAuxiliaryData30.java --- a/test/gc/g1/TestShrinkAuxiliaryData30.java Mon Jan 25 14:56:57 2016 -0800 +++ b/test/gc/g1/TestShrinkAuxiliaryData30.java Mon Jan 25 14:57:27 2016 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 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 @@ -23,11 +23,15 @@ /** * @test TestShrinkAuxiliaryData30 - * @bug 8038423 + * @bug 8038423 8061715 * @summary Checks that decommitment occurs for JVM with different * G1ConcRSLogCacheSize and ObjectAlignmentInBytes options values + * @requires vm.gc=="G1" | vm.gc=="null" * @library /testlibrary /testlibrary/whitebox + * @build com.oracle.java.testlibrary.* sun.hotspot.WhiteBox * @build TestShrinkAuxiliaryData TestShrinkAuxiliaryData30 + * @run main ClassFileInstaller sun.hotspot.WhiteBox + * sun.hotspot.WhiteBox$WhiteBoxPermission * @run driver/timeout=720 TestShrinkAuxiliaryData30 */ public class TestShrinkAuxiliaryData30 { diff -r c2687aa5e5ca -r 7eb99acd567f test/gc/g1/TestShrinkToOneRegion.java --- a/test/gc/g1/TestShrinkToOneRegion.java Mon Jan 25 14:56:57 2016 -0800 +++ b/test/gc/g1/TestShrinkToOneRegion.java Mon Jan 25 14:57:27 2016 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 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,6 +24,7 @@ /* * @test TestShrinkToOneRegion.java * @bug 8013872 + * @requires vm.gc=="G1" | vm.gc=="null" * @summary Shrinking the heap down to one region used to hit an assert * @run main/othervm -XX:+UseG1GC -XX:G1HeapRegionSize=32m -Xmx256m TestShrinkToOneRegion * diff -r c2687aa5e5ca -r 7eb99acd567f test/gc/metaspace/G1AddMetaspaceDependency.java --- a/test/gc/metaspace/G1AddMetaspaceDependency.java Mon Jan 25 14:56:57 2016 -0800 +++ b/test/gc/metaspace/G1AddMetaspaceDependency.java Mon Jan 25 14:57:27 2016 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 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,6 +24,7 @@ /* * @test G1AddMetaspaceDependency * @bug 8010196 + * @requires vm.gc=="G1" | vm.gc=="null" * @summary Checks that we don't get locking problems when adding metaspace dependencies with the G1 update buffer monitor * @run main/othervm -XX:+UseG1GC -XX:G1UpdateBufferSize=1 G1AddMetaspaceDependency */ diff -r c2687aa5e5ca -r 7eb99acd567f test/gc/metaspace/TestMetaspacePerfCounters.java --- a/test/gc/metaspace/TestMetaspacePerfCounters.java Mon Jan 25 14:56:57 2016 -0800 +++ b/test/gc/metaspace/TestMetaspacePerfCounters.java Mon Jan 25 14:57:27 2016 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 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 @@ -29,6 +29,7 @@ /* @test TestMetaspacePerfCounters * @bug 8014659 + * @requires vm.gc=="null" * @library /testlibrary * @summary Tests that performance counters for metaspace and compressed class * space exists and works. diff -r c2687aa5e5ca -r 7eb99acd567f test/gc/metaspace/TestPerfCountersAndMemoryPools.java --- a/test/gc/metaspace/TestPerfCountersAndMemoryPools.java Mon Jan 25 14:56:57 2016 -0800 +++ b/test/gc/metaspace/TestPerfCountersAndMemoryPools.java Mon Jan 25 14:57:27 2016 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 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 @@ -30,6 +30,7 @@ /* @test TestPerfCountersAndMemoryPools * @bug 8023476 * @library /testlibrary + * @requires vm.gc=="Serial" | vm.gc=="null" * @summary Tests that a MemoryPoolMXBeans and PerfCounters for metaspace * report the same data. * @run main/othervm -XX:+IgnoreUnrecognizedVMOptions -XX:-UseCompressedOops -XX:-UseCompressedKlassPointers -XX:+UseSerialGC -XX:+UsePerfData -Xint TestPerfCountersAndMemoryPools diff -r c2687aa5e5ca -r 7eb99acd567f test/runtime/6888954/vmerrors.sh --- a/test/runtime/6888954/vmerrors.sh Mon Jan 25 14:56:57 2016 -0800 +++ b/test/runtime/6888954/vmerrors.sh Mon Jan 25 14:57:27 2016 -0800 @@ -1,4 +1,4 @@ -# Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2013, 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 @@ -61,11 +61,12 @@ # EXCEPTION_ACCESS_VIOLATION - Win-* # SIGBUS - Solaris SPARC-64 # SIGSEGV - Linux-*, Solaris SPARC-32, Solaris X86-* +# SIGILL - Aix # # Note: would like to use "pc=0x00*0f," in the pattern, but Solaris SPARC-* # gets its signal at a PC in test_error_handler(). # -bad_func_ptr_re='(SIGBUS|SIGSEGV|EXCEPTION_ACCESS_VIOLATION).* at pc=' +bad_func_ptr_re='(SIGBUS|SIGSEGV|SIGILL|EXCEPTION_ACCESS_VIOLATION).* at pc=' guarantee_re='guarantee[(](str|num).*failed: *' fatal_re='fatal error: *' tail_1='.*expected null' diff -r c2687aa5e5ca -r 7eb99acd567f test/runtime/ErrorHandling/TestOnError.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/runtime/ErrorHandling/TestOnError.java Mon Jan 25 14:57:27 2016 -0800 @@ -0,0 +1,66 @@ +/* + * Copyright (c) 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 + * 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 TestOnError + * @summary Test using -XX:OnError= + * @library /testlibrary + * @build TestOnError com.oracle.java.testlibrary.* + * @run main TestOnError + * @bug 8078470 + */ + +import com.oracle.java.testlibrary.*; + +public class TestOnError { + + public static void main(String[] args) throws Exception { + if (!Platform.isDebugBuild()) { + System.out.println("Test requires a non-product build - skipping"); + return; + } + + String msg = "Test Succeeded"; + + // Execute the VM so that a + ProcessBuilder pb = ProcessTools.createJavaProcessBuilder( + "-XX:-TransmitErrorReport", + "-XX:ErrorHandlerTest=12", // trigger potential SEGV + "-XX:OnError=echo " + msg, + TestOnError.class.getName()); + + OutputAnalyzer output = new OutputAnalyzer(pb.start()); + + /* Actual output will include: + # + # -XX:OnError="echo Test Succeeded" + # Executing /bin/sh -c "echo Test Succeeded"... + Test Succeeded + + So we don't want to match on the "# Executing ..." line, and they + both get written to stdout. + */ + output.stdoutShouldMatch("^" + msg); // match start of line only + System.out.println("PASSED"); + } +} diff -r c2687aa5e5ca -r 7eb99acd567f test/runtime/ErrorHandling/TestOnOutOfMemoryError.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/runtime/ErrorHandling/TestOnOutOfMemoryError.java Mon Jan 25 14:57:27 2016 -0800 @@ -0,0 +1,70 @@ +/* + * Copyright (c) 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 + * 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 TestOnOutOfMemoryError + * @summary Test using -XX:OnOutOfMemoryError= + * @library /testlibrary + * @build TestOnOutOfMemoryError com.oracle.java.testlibrary.* + * @run main TestOnOutOfMemoryError + * @bug 8078470 + */ + +import com.oracle.java.testlibrary.*; + +public class TestOnOutOfMemoryError { + + public static void main(String[] args) throws Exception { + if (args.length == 1) { + // This should guarantee to throw: + // java.lang.OutOfMemoryError: Requested array size exceeds VM limit + Object[] oa = new Object[Integer.MAX_VALUE]; + return; + } + + // else this is the main test + String msg = "Test Succeeded"; + ProcessBuilder pb = ProcessTools.createJavaProcessBuilder( + "-XX:OnOutOfMemoryError=echo " + msg, + TestOnOutOfMemoryError.class.getName(), + "throwOOME"); + + OutputAnalyzer output = new OutputAnalyzer(pb.start()); + + /* Actual output should look like this: + # + # java.lang.OutOfMemoryError: Requested array size exceeds VM limit + # -XX:OnOutOfMemoryError="echo Test Succeeded" + # Executing /bin/sh -c "echo Test Succeeded"... + Test Succeeded + Exception in thread "main" java.lang.OutOfMemoryError: Requested array size exceeds VM limit + at OOME.main(OOME.java:3) + + So we don't want to match on the "# Executing ..." line, and they + both get written to stdout. + */ + output.shouldContain("Requested array size exceeds VM limit"); + output.stdoutShouldMatch("^" + msg); // match start of line only + System.out.println("PASSED"); + } +} diff -r c2687aa5e5ca -r 7eb99acd567f test/runtime/InitialThreadOverflow/testme.sh --- a/test/runtime/InitialThreadOverflow/testme.sh Mon Jan 25 14:56:57 2016 -0800 +++ b/test/runtime/InitialThreadOverflow/testme.sh Mon Jan 25 14:57:27 2016 -0800 @@ -1,6 +1,6 @@ #!/bin/sh -# Copyright (c) 2013 Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 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 diff -r c2687aa5e5ca -r 7eb99acd567f test/runtime/RedefineFinalizer/RedefineFinalizer.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/runtime/RedefineFinalizer/RedefineFinalizer.java Mon Jan 25 14:57:27 2016 -0800 @@ -0,0 +1,64 @@ +/* + * 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 6904403 + * @summary Don't assert if we redefine finalize method + * @library /testlibrary + * @build RedefineClassHelper + * @run main RedefineClassHelper + * @run main/othervm -javaagent:redefineagent.jar RedefineFinalizer + */ + +/* + * Regression test for hitting: + * + * assert(f == k->has_finalizer()) failed: inconsistent has_finalizer + * + * when redefining finalizer method + */ +public class RedefineFinalizer { + + public static String newB = + "class RedefineFinalizer$B {" + + " protected void finalize() { " + + " System.out.println(\"Finalizer called\");" + + " }" + + "}"; + + public static void main(String[] args) throws Exception { + RedefineClassHelper.redefineClass(B.class, newB); + + A a = new A(); + } + + static class A extends B { + } + + static class B { + protected void finalize() { + // should be empty + } + } +} diff -r c2687aa5e5ca -r 7eb99acd567f test/runtime/RedefineTests/RedefineRunningMethodsWithResolutionErrors.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/runtime/RedefineTests/RedefineRunningMethodsWithResolutionErrors.java Mon Jan 25 14:57:27 2016 -0800 @@ -0,0 +1,143 @@ +/* + * Copyright (c) 2014, 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 + * 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 8076110 + * @summary Redefine running methods that have cached resolution errors + * @library /testlibrary + * @modules java.instrument + * java.base/jdk.internal.org.objectweb.asm + * @build RedefineClassHelper + * @run main RedefineClassHelper + * @run main/othervm -javaagent:redefineagent.jar RedefineRunningMethodsWithResolutionErrors + */ + +import jdk.internal.org.objectweb.asm.ClassWriter; +import jdk.internal.org.objectweb.asm.Label; +import jdk.internal.org.objectweb.asm.MethodVisitor; +import jdk.internal.org.objectweb.asm.Opcodes; + +import java.lang.reflect.InvocationTargetException; + +public class RedefineRunningMethodsWithResolutionErrors extends ClassLoader implements Opcodes { + + @Override + protected Class findClass(String name) throws ClassNotFoundException { + if (name.equals("C")) { + byte[] b = loadC(false); + return defineClass(name, b, 0, b.length); + } else { + return super.findClass(name); + } + } + + private static byte[] loadC(boolean redefine) { + ClassWriter cw = new ClassWriter(0); + + cw.visit(52, ACC_SUPER | ACC_PUBLIC, "C", null, "java/lang/Object", null); + { + MethodVisitor mv; + + mv = cw.visitMethod(ACC_PUBLIC | ACC_STATIC, "m", "()V", null, null); + mv.visitCode(); + + // First time we run we will: + // 1) Cache resolution errors + // 2) Redefine the class / method + // 3) Try to read the resolution errors that were cached + // + // The redefined method will never run, throw error to be sure + if (redefine) { + createThrowRuntimeExceptionCode(mv, "The redefined method was called"); + } else { + createMethodBody(mv); + } + mv.visitMaxs(3, 0); + mv.visitEnd(); + } + cw.visitEnd(); + return cw.toByteArray(); + } + + private static void createMethodBody(MethodVisitor mv) { + Label classExists = new Label(); + + // Cache resolution errors + createLoadNonExistentClassCode(mv, classExists); + + // Redefine our own class and method + mv.visitMethodInsn(INVOKESTATIC, "RedefineRunningMethodsWithResolutionErrors", "redefine", "()V"); + + // Provoke the same error again to make sure the resolution error cache works + createLoadNonExistentClassCode(mv, classExists); + + // Test passed + mv.visitInsn(RETURN); + + mv.visitFrame(F_SAME, 0, new Object[0], 0, new Object[0]); + mv.visitLabel(classExists); + + createThrowRuntimeExceptionCode(mv, "Loaded class that shouldn't exist (\"NonExistentClass\")"); + } + + private static void createLoadNonExistentClassCode(MethodVisitor mv, Label classExists) { + Label tryLoadBegin = new Label(); + Label tryLoadEnd = new Label(); + Label catchLoadBlock = new Label(); + mv.visitTryCatchBlock(tryLoadBegin, tryLoadEnd, catchLoadBlock, "java/lang/NoClassDefFoundError"); + + // Try to load a class that does not exist to provoke resolution errors + mv.visitLabel(tryLoadBegin); + mv.visitMethodInsn(INVOKESTATIC, "NonExistentClass", "nonExistentMethod", "()V"); + mv.visitLabel(tryLoadEnd); + + // No NoClassDefFoundError means NonExistentClass existed, which shouldn't happen + mv.visitJumpInsn(GOTO, classExists); + + mv.visitFrame(F_SAME1, 0, new Object[0], 1, new Object[] { "java/lang/NoClassDefFoundError" }); + mv.visitLabel(catchLoadBlock); + + // Ignore the expected NoClassDefFoundError + mv.visitInsn(POP); + } + + private static void createThrowRuntimeExceptionCode(MethodVisitor mv, String msg) { + mv.visitTypeInsn(NEW, "java/lang/RuntimeException"); + mv.visitInsn(DUP); + mv.visitLdcInsn(msg); + mv.visitMethodInsn(INVOKESPECIAL, "java/lang/RuntimeException", "", "(Ljava/lang/String;)V"); + mv.visitInsn(ATHROW); + } + + private static Class c; + + public static void redefine() throws Exception { + RedefineClassHelper.redefineClass(c, loadC(true)); + } + + public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException { + c = Class.forName("C", true, new RedefineRunningMethodsWithResolutionErrors()); + c.getMethod("m").invoke(null); + } +} diff -r c2687aa5e5ca -r 7eb99acd567f test/runtime/handlerInTry/HandlerInTry.jasm --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/runtime/handlerInTry/HandlerInTry.jasm Mon Jan 25 14:57:27 2016 -0800 @@ -0,0 +1,115 @@ +/* + * Copyright (c) 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 + * 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. + */ + +/* + * HandlerInTry contains a try block in a ctor whose handler is inside + * the same try block. The try block starts at line 74 (try t2;), ends at + * line 106 (endtry t2;), but its handler starts at line 101 (catch t2 #0;). + */ +super public class HandlerInTry + version 51:0 +{ + +public static final synthetic Field ___transactionFactory_2002349702336125:"Ljava/lang/Object;"; + +public Method "":"(Ljava/lang/Object;)V" + stack 5 locals 5 +{ + invokestatic Method ThreadLocalTransaction.getThreadLocalTransaction:"()Ljava/lang/Object;"; + checkcast class java/lang/Object; + astore_2; + aload_2; + invokestatic Method TransactionLogicDonor.isActiveTransaction:"(Ljava/lang/Object;)Z"; + ifeq L21; + aload_0; + aload_1; + aload_2; + invokespecial Method "":"(Ljava/lang/Object;Ljava/lang/Object;)V"; + return; + L21: stack_frame_type append; + locals_map class java/lang/Object; + aload_2; + getstatic Field ___transactionFactory_2002349702336125:"Ljava/lang/Object;"; + invokestatic Method TransactionLogicDonor.createTransaction:"(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;"; + astore_2; + aload_2; + iconst_1; + pop; + aload_2; + invokestatic Method ThreadLocalTransaction.setThreadLocalTransaction:"(Ljava/lang/Object;)V"; + try t0, t1; + aload_0; + aload_1; + aload_2; + invokespecial Method "":"(Ljava/lang/Object;Ljava/lang/Object;)V"; + aload_2; + pop; + aconst_null; + astore_2; + endtry t0, t1; + invokestatic Method ThreadLocalTransaction.clearThreadLocalTransaction:"()V"; + pop; + goto L107; + catch t0 java/lang/Throwable; + try t2; + stack_frame_type full; + locals_map bogus, class java/lang/Object, class java/lang/Object; + stack_map class java/lang/Throwable; + astore_3; + aload_2; + pop; + aload_3; + instanceof class ControlFlowError; + ifeq L82; + new class java/lang/NullPointerException; + dup; + invokespecial Method java/lang/NullPointerException."":"()V"; + athrow; + L82: stack_frame_type append; + locals_map class java/lang/Throwable; + aload_3; + instanceof class java/lang/Error; + ifeq L94; + aload_3; + checkcast class java/lang/Error; + athrow; + L94: stack_frame_type same; + aload_3; + checkcast class java/lang/Exception; + athrow; + catch t1 #0; + catch t2 #0; + stack_frame_type full; + locals_map bogus, class java/lang/Object, class java/lang/Object; + stack_map class java/lang/Throwable; + astore 4; + endtry t2; + invokestatic Method ThreadLocalTransaction.clearThreadLocalTransaction:"()V"; + aload 4; + athrow; + L107: stack_frame_type full; + locals_map class HandlerInTry, class java/lang/Object, null; + return; +} + +} // end Class HandlerInTry diff -r c2687aa5e5ca -r 7eb99acd567f test/runtime/handlerInTry/IsolatedHandlerInTry.jasm --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/runtime/handlerInTry/IsolatedHandlerInTry.jasm Mon Jan 25 14:57:27 2016 -0800 @@ -0,0 +1,124 @@ +/* + * Copyright (c) 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 + * 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. + */ + +/* + * IsolatedHandlerInTry contains a try block in a ctor whose handler is inside + * the same try block but the handler can only be reached if an exception + * occurs. The handler does a return. So, a VerifyException should be thrown. + * The try block starts at line 77 (try t2;) and ends at line 113 (endtry t2;). + * Its handler starts at line 107 (catch t2 #0;). The handler can only be reached + * by exception because of the athrow at line 106. + */ +super public class IsolatedHandlerInTry + version 51:0 +{ + +public static final synthetic Field ___transactionFactory_2002349702336125:"Ljava/lang/Object;"; + +public Method "":"(Ljava/lang/Object;)V" + stack 5 locals 5 +{ + invokestatic Method ThreadLocalTransaction.getThreadLocalTransaction:"()Ljava/lang/Object;"; + checkcast class java/lang/Object; + astore_2; + aload_2; + invokestatic Method TransactionLogicDonor.isActiveTransaction:"(Ljava/lang/Object;)Z"; + ifeq L21; + aload_0; + aload_1; + aload_2; + invokespecial Method "":"(Ljava/lang/Object;Ljava/lang/Object;)V"; + return; + L21: stack_frame_type append; + locals_map class java/lang/Object; + aload_2; + getstatic Field ___transactionFactory_2002349702336125:"Ljava/lang/Object;"; + invokestatic Method TransactionLogicDonor.createTransaction:"(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;"; + astore_2; + aload_2; + iconst_1; + pop; + aload_2; + invokestatic Method ThreadLocalTransaction.setThreadLocalTransaction:"(Ljava/lang/Object;)V"; + try t0, t1; + aload_0; + aload_1; + aload_2; + invokespecial Method "":"(Ljava/lang/Object;Ljava/lang/Object;)V"; + aload_2; + pop; + aconst_null; + astore_2; + endtry t0, t1; + invokestatic Method ThreadLocalTransaction.clearThreadLocalTransaction:"()V"; + pop; + goto L107; + catch t0 java/lang/Throwable; + try t2; + stack_frame_type full; + locals_map bogus, class java/lang/Object, class java/lang/Object; + stack_map class java/lang/Throwable; + astore_3; + aload_2; + pop; + aload_3; + instanceof class ControlFlowError; + ifeq L82; + new class java/lang/NullPointerException; + dup; + invokespecial Method java/lang/NullPointerException."":"()V"; + athrow; + L82: stack_frame_type append; + locals_map class java/lang/Throwable; + aload_3; + instanceof class java/lang/Error; + ifeq L94; + aload_3; + checkcast class java/lang/Error; + athrow; + L94: stack_frame_type same; + aload_3; + checkcast class java/lang/Exception; + catch t1 #0; + stack_frame_type full; + locals_map bogus, class java/lang/Object, class java/lang/Object; + stack_map class java/lang/Throwable; + athrow; + catch t2 #0; + stack_frame_type full; + locals_map bogus, class java/lang/Object, class java/lang/Object; + stack_map class java/lang/Throwable; + astore 4; + return; + endtry t2; + stack_frame_type full; + locals_map bogus, class java/lang/Object, class java/lang/Object, class java/lang/Object; + stack_map class java/lang/Throwable; + invokestatic Method ThreadLocalTransaction.clearThreadLocalTransaction:"()V"; + athrow; + L107: stack_frame_type full; + locals_map class IsolatedHandlerInTry, class java/lang/Object, null; + return; +} + +} // end Class IsolatedHandlerInTry diff -r c2687aa5e5ca -r 7eb99acd567f test/runtime/handlerInTry/LoadHandlerInTry.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/runtime/handlerInTry/LoadHandlerInTry.java Mon Jan 25 14:57:27 2016 -0800 @@ -0,0 +1,86 @@ +/* + * Copyright (c) 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 + * 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 8075118 + * @summary Allow a ctor to call super() from a switch bytecode. + * @compile HandlerInTry.jasm + * @compile IsolatedHandlerInTry.jasm + * @run main/othervm -Xverify:all LoadHandlerInTry + */ + +/* + * This test has two cases: + * + * 1. class HandlerInTry: Class HandlerInTry contains a TRY block in a + * constructor whose handler is inside the same TRY block. The last + * few bytecodes and exception table look like this: + * + * ... + * 87: athrow + * 88: astore 4 + * 90: invokestatic #9 + * 93: aload 4 + * 95: athrow + * 96: return + * Exception table: + * from to target type + * 36 46 53 Class java/lang/Throwable + * 36 46 88 any + * 53 90 88 any + * + * Note that the target for the third handler in the Exception table is + * inside its TRY block. + * Without the fix for bug JDK-8075118, this test will time out. + * + * + * 2. class IsolatedHandlerInTry: Class IsolatedHandlerInTry also contains + * a TRY block in a constructoer whose handler is inside its TRY block. + * But the handler is only reachable if an exception is thrown. The + * handler's bytecodes will not get parsed as part of parsing the TRY + * block. They will only get parsed as a handler for the TRY block. + * Since the isolated handler does a 'return', a VerifyError exception + * should get thrown. + */ + +public class LoadHandlerInTry { + + public static void main(String[] args) throws Exception { + System.out.println("Regression test for bug 8075118"); + try { + Class newClass = Class.forName("HandlerInTry"); + } catch (Exception e) { + System.out.println("Failed: Exception was thrown: " + e.toString()); + throw e; + } + + try { + Class newClass = Class.forName("IsolatedHandlerInTry"); + throw new RuntimeException( + "Failed to throw VerifyError for IsolatedHandlerInTry"); + } catch (java.lang.VerifyError e) { + System.out.println("Passed: VerifyError exception was thrown"); + } + } +} diff -r c2687aa5e5ca -r 7eb99acd567f test/runtime/invokedynamic/BootstrapMethodErrorTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/runtime/invokedynamic/BootstrapMethodErrorTest.java Mon Jan 25 14:57:27 2016 -0800 @@ -0,0 +1,115 @@ +/* + * Copyright (c) 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 + * 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 8051045 + * @summary Test that exceptions from invokedynamic are wrapped in BootstrapMethodError + * @modules java.base/jdk.internal.org.objectweb.asm + * @run main BootstrapMethodErrorTest + */ + +import java.lang.reflect.Method; +import java.lang.invoke.MethodHandle; +import java.lang.invoke.MethodHandles; +import static java.lang.invoke.MethodHandles.*; +import static java.lang.invoke.MethodType.*; + +import jdk.internal.org.objectweb.asm.ClassWriter; +import jdk.internal.org.objectweb.asm.Handle; +import jdk.internal.org.objectweb.asm.MethodVisitor; +import jdk.internal.org.objectweb.asm.Opcodes; + +public class BootstrapMethodErrorTest extends ClassLoader implements Opcodes { + + @Override + public Class findClass(String name) throws ClassNotFoundException { + byte[] b; + try { + b = loadClassData(name); + } catch (Throwable th) { + throw new ClassNotFoundException("Loading error", th); + } + return defineClass(name, b, 0, b.length); + } + + private byte[] loadClassData(String name) throws Exception { + ClassWriter cw = new ClassWriter(0); + MethodVisitor mv; + + if (name.equals("C")) { + cw.visit(52, ACC_SUPER | ACC_PUBLIC, "C", null, "java/lang/Object", null); + { + mv = cw.visitMethod(ACC_PRIVATE | ACC_STATIC, "m", "()V", null, null); + mv.visitCode(); + mv.visitInsn(RETURN); + mv.visitMaxs(0, 1); + mv.visitEnd(); + } + cw.visitEnd(); + return cw.toByteArray(); + } else if (name.equals("Exec")) { + cw.visit(52, ACC_SUPER | ACC_PUBLIC, "Exec", null, "java/lang/Object", null); + { + mv = cw.visitMethod(ACC_PUBLIC | ACC_STATIC, "invokeRef", "()V", null, null); + mv.visitCode(); + Handle h = new Handle(H_INVOKESTATIC, "C", "m", "()V"); + mv.visitInvokeDynamicInsn("C", "()V", h); + mv.visitInsn(RETURN); + mv.visitMaxs(0, 0); + mv.visitEnd(); + } + cw.visitEnd(); + return cw.toByteArray(); + } + return null; + } + + public static void main(String[] args) throws ClassNotFoundException, IllegalAccessException, NoSuchMethodException { + new BootstrapMethodErrorTest().test(); + } + + public void test() throws ClassNotFoundException, IllegalAccessException, NoSuchMethodException { + Class.forName("C", true, this); + Class exec = Class.forName("Exec", true, this); + + try { + exec.getMethod("invokeRef").invoke(null); + } catch (Throwable e) { + Throwable c = e.getCause(); + if (c == null) { + throw new RuntimeException( + "Expected BootstrapMethodError wrapped in an InvocationTargetException but it wasn't wrapped", e); + } else if (c instanceof BootstrapMethodError) { + // Only way to pass test, all else should throw + return; + } else { + throw new RuntimeException( + "Expected BootstrapMethodError but got another Error: " + + c.getClass().getName(), + c); + } + } + throw new RuntimeException("Expected BootstrapMethodError but no Error at all was thrown"); + } +} diff -r c2687aa5e5ca -r 7eb99acd567f test/runtime/lambda-features/InvokespecialInterface.java --- a/test/runtime/lambda-features/InvokespecialInterface.java Mon Jan 25 14:56:57 2016 -0800 +++ b/test/runtime/lambda-features/InvokespecialInterface.java Mon Jan 25 14:57:27 2016 -0800 @@ -28,7 +28,7 @@ * @bug 8025937 * @bug 8033528 * @summary [JDK 8] Test invokespecial and invokeinterface with the same JVM_CONSTANT_InterfaceMethodref - * @run main/othervm -XX:+StressRewriter InvokespecialInterface + * @run main/othervm -XX:+IgnoreUnrecognizedVMOptions -XX:+StressRewriter InvokespecialInterface */ import java.util.function.*; import java.util.*; diff -r c2687aa5e5ca -r 7eb99acd567f test/runtime/memory/LargePages/TestLargePageSizeInBytes.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/runtime/memory/LargePages/TestLargePageSizeInBytes.java Mon Jan 25 14:57:27 2016 -0800 @@ -0,0 +1,61 @@ +/* + * 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 TestLargePageSizeInBytes + * @summary Tests that the flag -XX:LargePageSizeInBytes does not cause warnings on Solaris + * @bug 8049536 + * @library /testlibrary + * @run driver TestLargePageSizeInBytes + */ + +import com.oracle.java.testlibrary.OutputAnalyzer; +import com.oracle.java.testlibrary.Platform; +import com.oracle.java.testlibrary.ProcessTools; + +public class TestLargePageSizeInBytes { + private static long M = 1024L * 1024L; + private static long G = 1024L * M; + + public static void main(String[] args) throws Exception { + if (!Platform.isSolaris()) { + // We only use the syscall mencntl on Solaris + return; + } + + testLargePageSizeInBytes(4 * M); + testLargePageSizeInBytes(256 * M); + testLargePageSizeInBytes(512 * M); + testLargePageSizeInBytes(2 * G); + } + + private static void testLargePageSizeInBytes(long size) throws Exception { + ProcessBuilder pb = + ProcessTools.createJavaProcessBuilder("-XX:+UseLargePages", + "-XX:LargePageSizeInBytes=" + size, + "-version"); + + OutputAnalyzer out = new OutputAnalyzer(pb.start()); + out.shouldNotContain("Attempt to use MPSS failed."); + out.shouldHaveExitValue(0); + } +} diff -r c2687aa5e5ca -r 7eb99acd567f test/runtime/memory/ReadVMPageSize.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/runtime/memory/ReadVMPageSize.java Mon Jan 25 14:57:27 2016 -0800 @@ -0,0 +1,46 @@ +/* + * 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 + * @summary Using WhiteBox to get VM page size + * @library /testlibrary /testlibrary/whitebox + * @build ReadVMPageSize + * @run main ClassFileInstaller sun.hotspot.WhiteBox + * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI ReadVMPageSize + */ + +import com.oracle.java.testlibrary.*; +import sun.hotspot.WhiteBox; + +public class ReadVMPageSize { + public static void main(String args[]) throws Exception { + WhiteBox wb = WhiteBox.getWhiteBox(); + int pageSize = wb.getVMPageSize(); + if (pageSize < 0) { + throw new Exception("pageSize < 0"); + } else { + System.out.println("Page size = " + pageSize); + } + } +} diff -r c2687aa5e5ca -r 7eb99acd567f test/runtime/stackMapCheck/BadMap.jasm --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/runtime/stackMapCheck/BadMap.jasm Mon Jan 25 14:57:27 2016 -0800 @@ -0,0 +1,152 @@ + /* + * Copyright (c) 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 + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +/* + * This class should throw VerifyError because the StackMap for bytecode index + * 45 (astore_2, line 123) is incorrect. The stack maps for bytecode indexes 45 + * and 49 (astore, line 133) do not match because 45 does not supply enough + * locals to satisfy 49. + * + * The astore_2 bytecode at bytecode index 45 changes the type state, + * preventing the stackmap mismatch. But, if the incoming type state is used, + * as required by JVM Spec 8, then the verifier will detected the stackmap + * mismatch, and throw VerifyError. + */ + +super public class BadMap + version 51:0 +{ + + +public Method "":"()V" + stack 1 locals 1 +{ + aload_0; + invokespecial Method java/lang/Object."":"()V"; + return; +} + +public static Method main:"([Ljava/lang/String;)V" + throws java/lang/Throwable + stack 0 locals 1 +{ + return; +} + +public static Method foo:"()V" + stack 3 locals 5 +{ + iconst_0; + ifne L5; + nop; + try t7; + L5: stack_frame_type full; + aconst_null; + dup; + astore_0; + astore_1; + try t0; + aconst_null; + astore_0; + endtry t0; + goto L19; + catch t0 java/io/IOException; + stack_frame_type full; + locals_map class java/lang/Object, null; + stack_map class java/io/IOException; + astore_2; + aconst_null; + dup; + astore_1; + astore_0; + try t1; + L19: stack_frame_type full; + locals_map class java/lang/Object, class java/lang/Object; + aconst_null; + astore_2; + endtry t1; + aload_1; + ifnonnull L37; + nop; + goto L37; + catch t1 #0; + catch t2 #0; + try t2; + stack_frame_type full; + locals_map class java/lang/Object, class java/lang/Object; + stack_map class java/lang/Throwable; + astore_3; + endtry t2; + aload_1; + ifnonnull L35; + nop; + L35: stack_frame_type full; + locals_map class java/lang/Object, class java/lang/Object, bogus, class java/lang/Throwable; + aload_3; + athrow; + try t3, t4; + L37: stack_frame_type full; + locals_map class java/lang/Object, class java/lang/Object, class java/lang/Object; + aload_1; + ifnonnull L42; + nop; + endtry t3, t4; + L42: stack_frame_type full; + locals_map class java/lang/Object, class java/lang/Object, class java/lang/Object; + goto L54; + catch t3 java/lang/Exception; + try t5; + stack_frame_type full; + locals_map class java/lang/Object, class java/lang/Object; + stack_map class java/lang/Exception; + astore_2; // astore_2, at bci 45, that changes the type state. + endtry t5; + goto L54; + catch t4 #0; + catch t5 #0; + catch t6 #0; + try t6; + stack_frame_type full; + locals_map class java/lang/Object, class java/lang/Object, class java/lang/Object; + stack_map class java/lang/Throwable; + astore 4; + endtry t6; + aload 4; + athrow; + L54: stack_frame_type full; + locals_map class java/lang/Object, class java/lang/Object, class java/lang/Object; + goto L57; + L57: stack_frame_type full; + locals_map class java/lang/Object, class java/lang/Object, class java/lang/Object; + nop; + endtry t7; + return; + catch t7 #0; + stack_frame_type full; + stack_map class java/lang/Throwable; + nop; + athrow; +} + +} // end Class BadMap diff -r c2687aa5e5ca -r 7eb99acd567f test/runtime/stackMapCheck/BadMapDstore.jasm --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/runtime/stackMapCheck/BadMapDstore.jasm Mon Jan 25 14:57:27 2016 -0800 @@ -0,0 +1,79 @@ + /* + * Copyright (c) 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 + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +/* + * This class should throw VerifyError because the StackMap for bytecode index + * 9 (dstore_2, line 60) is incorrect. The stack maps for bytecode indexes 9 + * and 18 (astore_2, line 70) do not match because 9 does not supply enough + * locals to satisfy 18. + * + * The dstore_2 bytecode at bytecode index 9 changes the type state, + * preventing the stackmap mismatch. But, if the incoming type state is used, + * as required by JVM Spec 8, then the verifier will detected the stackmap + * mismatch, and throw VerifyError. + */ + +super public class BadMapDstore + version 51:0 +{ + +Field blah:I; + +public Method "":"()V" + stack 1 locals 1 +{ + aload_0; + invokespecial Method java/lang/Object."":"()V"; + return; +} + +public static Method main:"([Ljava/lang/String;)V" + stack 4 locals 4 +{ + new class BadMapDstore; + dup; + invokespecial Method "":"()V"; + astore_1; + dconst_1; + try t0; + dstore_2; + aload_1; + iconst_5; + putfield Field blah:"I"; + endtry t0; + goto L22; + catch t0 java/lang/Throwable; + stack_frame_type full; + locals_map class "[Ljava/lang/String;", class BadMapDstore, double; + stack_map class java/lang/Throwable; + astore_2; + aload_1; + dconst_0; + dstore_2; + pop; + L22: stack_frame_type same; + return; +} + +} // end Class BadMapDstore diff -r c2687aa5e5ca -r 7eb99acd567f test/runtime/stackMapCheck/BadMapIstore.jasm --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/runtime/stackMapCheck/BadMapIstore.jasm Mon Jan 25 14:57:27 2016 -0800 @@ -0,0 +1,79 @@ + /* + * Copyright (c) 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 + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +/* + * This class should throw VerifyError because the StackMap for bytecode index + * 9 (istore_2, line 60) is incorrect. The stack maps for bytecode indexes 9 + * and 18 (astore_2, line 70) do not match because 9 does not supply enough + * locals to satisfy 18. + * + * The istore_2 bytecode at bytecode index 9 changes the type state, + * preventing the stackmap mismatch. But, if the incoming type state is used, + * as required by JVM Spec 8, then the verifier will detected the stackmap + * mismatch, and throw VerifyError. + */ + +super public class BadMapIstore + version 51:0 +{ + +Field blah:I; + +public Method "":"()V" + stack 1 locals 1 +{ + aload_0; + invokespecial Method java/lang/Object."":"()V"; + return; +} + +public static Method main:"([Ljava/lang/String;)V" + stack 2 locals 3 +{ + new class BadMapIstore; + dup; + invokespecial Method "":"()V"; + astore_1; + iconst_2; + try t0; + istore_2; + aload_1; + iconst_5; + putfield Field blah:"I"; + endtry t0; + goto L22; + catch t0 java/lang/Throwable; + stack_frame_type full; + locals_map class "[Ljava/lang/String;", class BadMapIstore, int; + stack_map class java/lang/Throwable; + astore_2; + aload_1; + iconst_4; + istore_2; + pop; + L22: stack_frame_type same; + return; +} + +} // end Class BadMapIstore diff -r c2687aa5e5ca -r 7eb99acd567f test/runtime/stackMapCheck/StackMapCheck.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/runtime/stackMapCheck/StackMapCheck.java Mon Jan 25 14:57:27 2016 -0800 @@ -0,0 +1,63 @@ + /* + * Copyright (c) 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 + * 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 7127066 + * @summary Class verifier accepts an invalid class file + * @compile BadMap.jasm + * @compile BadMapDstore.jasm + * @compile BadMapIstore.jasm + * @run main/othervm -Xverify:all StackMapCheck + */ + +public class StackMapCheck { + public static void main(String args[]) throws Throwable { + + System.out.println("Regression test for bug 7127066"); + try { + Class newClass = Class.forName("BadMap"); + throw new RuntimeException( + "StackMapCheck failed, BadMap did not throw VerifyError"); + } catch (java.lang.VerifyError e) { + System.out.println("BadMap passed, VerifyError was thrown"); + } + + try { + Class newClass = Class.forName("BadMapDstore"); + throw new RuntimeException( + "StackMapCheck failed, BadMapDstore did not throw VerifyError"); + } catch (java.lang.VerifyError e) { + System.out.println("BadMapDstore passed, VerifyError was thrown"); + } + + try { + Class newClass = Class.forName("BadMapIstore"); + throw new RuntimeException( + "StackMapCheck failed, BadMapIstore did not throw VerifyError"); + } catch (java.lang.VerifyError e) { + System.out.println("BadMapIstore passed, VerifyError was thrown"); + } + } +} diff -r c2687aa5e5ca -r 7eb99acd567f test/serviceability/jvmti/GetObjectSizeOverflow.java --- a/test/serviceability/jvmti/GetObjectSizeOverflow.java Mon Jan 25 14:56:57 2016 -0800 +++ b/test/serviceability/jvmti/GetObjectSizeOverflow.java Mon Jan 25 14:57:27 2016 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014 Oracle and/or its affiliates. All rights reserved. + * 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 diff -r c2687aa5e5ca -r 7eb99acd567f test/serviceability/sa/jmap-hashcode/Test8028623.java --- a/test/serviceability/sa/jmap-hashcode/Test8028623.java Mon Jan 25 14:56:57 2016 -0800 +++ b/test/serviceability/sa/jmap-hashcode/Test8028623.java Mon Jan 25 14:57:27 2016 -0800 @@ -33,20 +33,25 @@ import com.oracle.java.testlibrary.JDKToolLauncher; import com.oracle.java.testlibrary.OutputBuffer; +import com.oracle.java.testlibrary.Platform; import com.oracle.java.testlibrary.ProcessTools; import java.io.File; public class Test8028623 { - public static int à = 1; + public static int \u00CB = 1; public static String dumpFile = "heap.out"; public static void main (String[] args) { - System.out.println(Ã); + System.out.println(\u00CB); try { + if (!Platform.shouldSAAttach()) { + System.out.println("SA attach not expected to work - test skipped."); + return; + } int pid = ProcessTools.getProcessId(); JDKToolLauncher jmap = JDKToolLauncher.create("jmap") .addToolArg("-F") diff -r c2687aa5e5ca -r 7eb99acd567f test/test_env.sh --- a/test/test_env.sh Mon Jan 25 14:56:57 2016 -0800 +++ b/test/test_env.sh Mon Jan 25 14:57:27 2016 -0800 @@ -1,6 +1,6 @@ #!/bin/sh # -# Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2013, 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 @@ -53,7 +53,7 @@ # set platform-dependent variables OS=`uname -s` case "$OS" in - SunOS | Linux | Darwin ) + AIX | Darwin | Linux | SunOS ) NULL=/dev/null PS=":" FS="/" @@ -130,26 +130,31 @@ fi VM_OS="unknown" -grep "solaris" vm_version.out > ${NULL} +grep "aix" vm_version.out > ${NULL} if [ $? = 0 ] then - VM_OS="solaris" + VM_OS="aix" +fi +grep "bsd" vm_version.out > ${NULL} +if [ $? = 0 ] +then + VM_OS="bsd" fi grep "linux" vm_version.out > ${NULL} if [ $? = 0 ] then VM_OS="linux" fi +grep "solaris" vm_version.out > ${NULL} +if [ $? = 0 ] +then + VM_OS="solaris" +fi grep "windows" vm_version.out > ${NULL} if [ $? = 0 ] then VM_OS="windows" fi -grep "bsd" vm_version.out > ${NULL} -if [ $? = 0 ] -then - VM_OS="bsd" -fi VM_CPU="unknown" grep "sparc" vm_version.out > ${NULL} @@ -186,6 +191,11 @@ then VM_CPU="ia64" fi +grep "aarch64" vm_version.out > ${NULL} +if [ $? = 0 ] +then + VM_CPU="aarch64" +fi export VM_TYPE VM_BITS VM_OS VM_CPU echo "VM_TYPE=${VM_TYPE}" echo "VM_BITS=${VM_BITS}" diff -r c2687aa5e5ca -r 7eb99acd567f test/testlibrary/RedefineClassHelper.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/testlibrary/RedefineClassHelper.java Mon Jan 25 14:57:27 2016 -0800 @@ -0,0 +1,79 @@ +/* + * 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.PrintWriter; +import java.lang.instrument.*; +import com.oracle.java.testlibrary.*; + +/* + * Helper class to write tests that redefine classes. + * When main method is run, it will create a redefineagent.jar that can be used + * with the -javaagent option to support redefining classes in jtreg tests. + * + * See sample test in test/testlibrary_tests/RedefineClassTest.java + */ +public class RedefineClassHelper { + + public static Instrumentation instrumentation; + public static void premain(String agentArgs, Instrumentation inst) { + instrumentation = inst; + } + + /** + * Redefine a class + * + * @param clazz Class to redefine + * @param javacode String with the new java code for the class to be redefined + */ + public static void redefineClass(Class clazz, String javacode) throws Exception { + byte[] bytecode = InMemoryJavaCompiler.compile(clazz.getName(), javacode); + redefineClass(clazz, bytecode); + } + + /** + * Redefine a class + * + * @param clazz Class to redefine + * @param bytecode byte[] with the new class + */ + public static void redefineClass(Class clazz, byte[] bytecode) throws Exception { + instrumentation.redefineClasses(new ClassDefinition(clazz, bytecode)); + } + + /** + * Main method to be invoked before test to create the redefineagent.jar + */ + public static void main(String[] args) throws Exception { + ClassFileInstaller.main("RedefineClassHelper"); + + PrintWriter pw = new PrintWriter("MANIFEST.MF"); + pw.println("Premain-Class: RedefineClassHelper"); + pw.println("Can-Redefine-Classes: true"); + pw.close(); + + 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", "RedefineClassHelper.class" })) { + throw new Exception("jar operation failed"); + } + } +} diff -r c2687aa5e5ca -r 7eb99acd567f test/testlibrary/com/oracle/java/testlibrary/Platform.java --- a/test/testlibrary/com/oracle/java/testlibrary/Platform.java Mon Jan 25 14:56:57 2016 -0800 +++ b/test/testlibrary/com/oracle/java/testlibrary/Platform.java Mon Jan 25 14:57:27 2016 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 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 @@ -23,12 +23,17 @@ package com.oracle.java.testlibrary; +import java.util.regex.Pattern; + +import com.oracle.java.testlibrary.Utils; + public class Platform { private static final String osName = System.getProperty("os.name"); private static final String dataModel = System.getProperty("sun.arch.data.model"); private static final String vmVersion = System.getProperty("java.vm.version"); private static final String osArch = System.getProperty("os.arch"); private static final String vmName = System.getProperty("java.vm.name"); + private static final String userName = System.getProperty("user.name"); public static boolean isClient() { return vmName.endsWith(" Client VM"); @@ -58,6 +63,18 @@ return dataModel.equals("64"); } + public static boolean isAix() { + return isOs("aix"); + } + + public static boolean isLinux() { + return isOs("linux"); + } + + public static boolean isOSX() { + return isOs("mac"); + } + public static boolean isSolaris() { return isOs("sunos"); } @@ -66,14 +83,6 @@ return isOs("win"); } - public static boolean isOSX() { - return isOs("mac"); - } - - public static boolean isLinux() { - return isOs("linux"); - } - private static boolean isOs(String osname) { return osName.toLowerCase().startsWith(osname.toLowerCase()); } @@ -92,33 +101,93 @@ // Returns true for sparc and sparcv9. public static boolean isSparc() { - return isArch("sparc"); + return isArch("sparc.*"); } public static boolean isARM() { - return isArch("arm"); + return isArch("arm.*"); } public static boolean isPPC() { - return isArch("ppc"); + return isArch("ppc.*"); } public static boolean isX86() { - // On Linux it's 'i386', Windows 'x86' - return (isArch("i386") || isArch("x86")); + // On Linux it's 'i386', Windows 'x86' without '_64' suffix. + return isArch("(i386)|(x86(?!_64))"); } public static boolean isX64() { // On OSX it's 'x86_64' and on other (Linux, Windows and Solaris) platforms it's 'amd64' - return (isArch("amd64") || isArch("x86_64")); + return isArch("(amd64)|(x86_64)"); } - private static boolean isArch(String archname) { - return osArch.toLowerCase().startsWith(archname.toLowerCase()); + public static boolean isAArch64() { + return isArch("aarch64"); + } + + private static boolean isArch(String archnameRE) { + return Pattern.compile(archnameRE, Pattern.CASE_INSENSITIVE) + .matcher(osArch) + .matches(); } public static String getOsArch() { return osArch; } + /** + * Return a boolean for whether we expect to be able to attach + * the SA to our own processes on this system. + */ + public static boolean shouldSAAttach() throws Exception { + + if (isAix()) { + return false; // SA not implemented. + } else if (isLinux()) { + return canPtraceAttachLinux(); + } else if (isOSX()) { + return canAttachOSX(); + } else { + // Other platforms expected to work: + return true; + } + } + + /** + * On Linux, first check the SELinux boolean "deny_ptrace" and return false + * as we expect to be denied if that is "1". Then expect permission to attach + * if we are root, so return true. Then return false for an expected denial + * if "ptrace_scope" is 1, and true otherwise. + */ + public static boolean canPtraceAttachLinux() throws Exception { + + // SELinux deny_ptrace: + String deny_ptrace = Utils.fileAsString("/sys/fs/selinux/booleans/deny_ptrace"); + if (deny_ptrace != null && deny_ptrace.contains("1")) { + // ptrace will be denied: + return false; + } + + if (userName.equals("root")) { + return true; + } + + // ptrace_scope: + String ptrace_scope = Utils.fileAsString("/proc/sys/kernel/yama/ptrace_scope"); + if (ptrace_scope != null && ptrace_scope.contains("1")) { + // ptrace will be denied: + return false; + } + + // Otherwise expect to be permitted: + return true; + } + + /** + * On OSX, expect permission to attach only if we are root. + */ + public static boolean canAttachOSX() throws Exception { + return userName.equals("root"); + } } diff -r c2687aa5e5ca -r 7eb99acd567f test/testlibrary/com/oracle/java/testlibrary/Utils.java --- a/test/testlibrary/com/oracle/java/testlibrary/Utils.java Mon Jan 25 14:56:57 2016 -0800 +++ b/test/testlibrary/com/oracle/java/testlibrary/Utils.java Mon Jan 25 14:57:27 2016 -0800 @@ -299,6 +299,35 @@ } /** + * Return the contents of the named file as a single String, + * or null if not found. + * @param filename name of the file to read + * @return String contents of file, or null if file not found. + */ + public static String fileAsString(String filename) { + StringBuilder result = new StringBuilder(); + try { + File file = new File(filename); + if (file.exists()) { + BufferedReader reader = new BufferedReader(new FileReader(file)); + while (true) { + String line = reader.readLine(); + if (line == null) { + break; + } + result.append(line).append("\n"); + } + } else { + // Does not exist: + return null; + } + } catch (Exception e) { + e.printStackTrace(); + } + return result.toString(); + } + + /** * @return Unsafe instance. */ public static synchronized Unsafe getUnsafe() { diff -r c2687aa5e5ca -r 7eb99acd567f test/testlibrary/ctw/Makefile --- a/test/testlibrary/ctw/Makefile Mon Jan 25 14:56:57 2016 -0800 +++ b/test/testlibrary/ctw/Makefile Mon Jan 25 14:57:27 2016 -0800 @@ -8,7 +8,7 @@ # # 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 +# 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). # diff -r c2687aa5e5ca -r 7eb99acd567f test/testlibrary/ctw/README --- a/test/testlibrary/ctw/README Mon Jan 25 14:56:57 2016 -0800 +++ b/test/testlibrary/ctw/README Mon Jan 25 14:57:27 2016 -0800 @@ -1,26 +1,26 @@ -# -# Copyright (c) 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. -# -# + +Copyright (c) 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. + + DESCRIPTION diff -r c2687aa5e5ca -r 7eb99acd567f test/testlibrary/whitebox/Makefile --- a/test/testlibrary/whitebox/Makefile Mon Jan 25 14:56:57 2016 -0800 +++ b/test/testlibrary/whitebox/Makefile Mon Jan 25 14:57:27 2016 -0800 @@ -8,7 +8,7 @@ # # 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 +# 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). # diff -r c2687aa5e5ca -r 7eb99acd567f test/testlibrary/whitebox/sun/hotspot/WhiteBox.java --- a/test/testlibrary/whitebox/sun/hotspot/WhiteBox.java Mon Jan 25 14:56:57 2016 -0800 +++ b/test/testlibrary/whitebox/sun/hotspot/WhiteBox.java Mon Jan 25 14:57:27 2016 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 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 @@ -24,6 +24,7 @@ package sun.hotspot; +import java.lang.management.MemoryUsage; import java.lang.reflect.Executable; import java.util.Arrays; import java.util.List; @@ -75,6 +76,9 @@ // Memory public native long getObjectAddress(Object o); public native int getHeapOopSize(); + public native int getVMPageSize(); + public native long getVMLargePageSize(); + public native boolean isObjectInOldGen(Object o); public native long getObjectSize(Object o); @@ -84,6 +88,8 @@ return isClassAlive0(name.replace('.', '/')); } private native boolean isClassAlive0(String name); + public native boolean isMonitorInflated(Object obj); + public native void forceSafepoint(); // Resource/Class Lookup Cache public native boolean classKnownToNotExist(ClassLoader loader, String name); @@ -97,8 +103,10 @@ // G1 public native boolean g1InConcurrentMark(); public native boolean g1IsHumongous(Object o); + public native long g1NumMaxRegions(); public native long g1NumFreeRegions(); public native int g1RegionSize(); + public native MemoryUsage g1AuxiliaryMemoryUsage(); public native Object[] parseCommandLine(String commandline, DiagnosticCommand[] args); // NMT diff -r c2687aa5e5ca -r 7eb99acd567f test/testlibrary_tests/RedefineClassTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/testlibrary_tests/RedefineClassTest.java Mon Jan 25 14:57:27 2016 -0800 @@ -0,0 +1,54 @@ +/* + * 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 Proof of concept test for RedefineClassHelper + * @build RedefineClassHelper + * @run main RedefineClassHelper + * @run main/othervm -javaagent:redefineagent.jar RedefineClassTest + */ + +import static com.oracle.java.testlibrary.Asserts.*; +import com.oracle.java.testlibrary.*; + +/* + * Proof of concept test for the test utility class RedefineClassHelper + */ +public class RedefineClassTest { + + public static String newClass = "class RedefineClassTest$A { public int Method() { return 2; } }"; + public static void main(String[] args) throws Exception { + A a = new A(); + assertTrue(a.Method() == 1); + RedefineClassHelper.redefineClass(A.class, newClass); + assertTrue(a.Method() == 2); + } + + static class A { + public int Method() { + return 1; + } + } +} diff -r c2687aa5e5ca -r 7eb99acd567f test/testlibrary_tests/TestMutuallyExclusivePlatformPredicates.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/testlibrary_tests/TestMutuallyExclusivePlatformPredicates.java Mon Jan 25 14:57:27 2016 -0800 @@ -0,0 +1,135 @@ +/* + * Copyright (c) 2014, 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 + * 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.Asserts; +import com.oracle.java.testlibrary.Platform; + +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.util.Arrays; +import java.util.Collections; +import java.util.EnumSet; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +/** + * @test + * @summary Verify that for each group of mutually exclusive predicates defined + * in com.oracle.java.testlibrary.Platform one and only one predicate + * evaluates to true. + * @library /testlibrary + * @run main TestMutuallyExclusivePlatformPredicates + */ +public class TestMutuallyExclusivePlatformPredicates { + private static enum MethodGroup { + ARCH("isARM", "isPPC", "isSparc", "isX86", "isX64", "isAArch64"), + BITNESS("is32bit", "is64bit"), + OS("isAix", "isLinux", "isSolaris", "isWindows", "isOSX"), + VM_TYPE("isClient", "isServer", "isGraal", "isMinimal"), + IGNORED("isEmbedded", "isDebugBuild", "shouldSAAttach", + "canPtraceAttachLinux", "canAttachOSX"); + + public final List methodNames; + + private MethodGroup(String... methodNames) { + this.methodNames = Collections.unmodifiableList( + Arrays.asList(methodNames)); + } + } + + public static void main(String args[]) { + EnumSet notIgnoredMethodGroups + = EnumSet.complementOf(EnumSet.of(MethodGroup.IGNORED)); + + notIgnoredMethodGroups.forEach( + TestMutuallyExclusivePlatformPredicates::verifyPredicates); + + TestMutuallyExclusivePlatformPredicates.verifyCoverage(); + } + + /** + * Verifies that one and only one predicate method defined in + * {@link com.oracle.java.testlibrary.Platform}, whose name included into + * methodGroup will return {@code true}. + * @param methodGroup The group of methods that should be tested. + */ + private static void verifyPredicates(MethodGroup methodGroup) { + System.out.println("Verifying method group: " + methodGroup.name()); + long truePredicatesCount = methodGroup.methodNames.stream() + .filter(TestMutuallyExclusivePlatformPredicates + ::evaluatePredicate) + .count(); + + Asserts.assertEQ(truePredicatesCount, 1L, String.format( + "Only one predicate from group %s should be evaluated to true " + + "(Actually %d predicates were evaluated to true).", + methodGroup.name(), truePredicatesCount)); + } + + /** + * Verifies that all predicates defined in + * {@link com.oracle.java.testlibrary.Platform} were either tested or + * explicitly ignored. + */ + private static void verifyCoverage() { + Set allMethods = new HashSet<>(); + for (MethodGroup group : MethodGroup.values()) { + allMethods.addAll(group.methodNames); + } + + for (Method m : Platform.class.getMethods()) { + if (m.getParameterCount() == 0 + && m.getReturnType() == boolean.class) { + Asserts.assertTrue(allMethods.contains(m.getName()), + "All Platform's methods with signature '():Z' should " + + "be tested "); + } + } + } + + /** + * Evaluates predicate method with name {@code name} defined in + * {@link com.oracle.java.testlibrary.Platform}. + * + * @param name The name of a predicate to be evaluated. + * @return evaluated predicate's value. + * @throws java.lang.Error if predicate is not defined or could not be + * evaluated. + */ + private static boolean evaluatePredicate(String name) { + try { + System.out.printf("Trying to evaluate predicate with name %s%n", + name); + boolean value + = (Boolean) Platform.class.getMethod(name).invoke(null); + System.out.printf("Predicate evaluated to: %s%n", value); + return value; + } catch (NoSuchMethodException e) { + throw new Error("Predicate with name " + name + + " is not defined in " + Platform.class.getName(), e); + } catch (IllegalAccessException | InvocationTargetException e) { + throw new Error("Unable to evaluate predicate " + name, e); + } + } +}