# HG changeset patch # User michaelm # Date 1575021727 0 # Node ID cfe31d2f935cd10955fdf3969c23b3efa1924835 # Parent bfc8074ea4ef5f99f7d1a42d4e02db9ea91af775# Parent 5775e4825e5893a7affab3948b56315008e10c76 Merge diff -r bfc8074ea4ef -r cfe31d2f935c .hgtags --- a/.hgtags Tue Nov 26 10:22:13 2019 +0000 +++ b/.hgtags Fri Nov 29 10:02:07 2019 +0000 @@ -597,3 +597,4 @@ 83810b7d12e7ff761ad3dd91f323a22dad96f108 jdk-14+22 15936b142f86731afa4b1a2c0fe4a01e806c4944 jdk-14+23 438337c846fb071900ddb6922bddf8b3e895a514 jdk-14+24 +17d242844fc9e7d18b3eac97426490a9c246119e jdk-14+25 diff -r bfc8074ea4ef -r cfe31d2f935c make/autoconf/flags-cflags.m4 --- a/make/autoconf/flags-cflags.m4 Tue Nov 26 10:22:13 2019 +0000 +++ b/make/autoconf/flags-cflags.m4 Fri Nov 29 10:02:07 2019 +0000 @@ -190,20 +190,7 @@ WARNINGS_ENABLE_ALL_CXXFLAGS="$WARNINGS_ENABLE_ALL_CFLAGS $WARNINGS_ENABLE_ADDITIONAL_CXX" DISABLED_WARNINGS="unused-parameter unused" - - # Repeate the check for the BUILD_CC and BUILD_CXX. Need to also reset - # CFLAGS since any target specific flags will likely not work with the - # build compiler - CC_OLD="$CC" - CXX_OLD="$CXX" - CC="$BUILD_CC" - CXX="$BUILD_CXX" - CFLAGS_OLD="$CFLAGS" - CFLAGS="" BUILD_CC_DISABLE_WARNING_PREFIX="-Wno-" - CC="$CC_OLD" - CXX="$CXX_OLD" - CFLAGS="$CFLAGS_OLD" ;; clang) @@ -420,6 +407,17 @@ FLAGS_SETUP_CFLAGS_CPU_DEP([TARGET]) + # Repeat the check for the BUILD_CC and BUILD_CXX. Need to also reset CFLAGS + # since any target specific flags will likely not work with the build compiler. + CC_OLD="$CC" + CXX_OLD="$CXX" + CFLAGS_OLD="$CFLAGS" + CXXFLAGS_OLD="$CXXFLAGS" + CC="$BUILD_CC" + CXX="$BUILD_CXX" + CFLAGS="" + CXXFLAGS="" + FLAGS_OS=$OPENJDK_BUILD_OS FLAGS_OS_TYPE=$OPENJDK_BUILD_OS_TYPE FLAGS_CPU=$OPENJDK_BUILD_CPU @@ -430,6 +428,11 @@ FLAGS_CPU_LEGACY_LIB=$OPENJDK_BUILD_CPU_LEGACY_LIB FLAGS_SETUP_CFLAGS_CPU_DEP([BUILD], [OPENJDK_BUILD_], [BUILD_]) + + CC="$CC_OLD" + CXX="$CXX_OLD" + CFLAGS="$CFLAGS_OLD" + CXXFLAGS="$CXXFLAGS_OLD" ]) ################################################################################ @@ -529,6 +532,11 @@ if test "x$TOOLCHAIN_TYPE" = xgcc; then TOOLCHAIN_CFLAGS_JVM="$TOOLCHAIN_CFLAGS_JVM -fcheck-new -fstack-protector" TOOLCHAIN_CFLAGS_JDK="-pipe -fstack-protector" + # reduce lib size on s390x in link step, this needs also special compile flags + if test "x$OPENJDK_TARGET_CPU" = xs390x; then + TOOLCHAIN_CFLAGS_JVM="$TOOLCHAIN_CFLAGS_JVM -ffunction-sections -fdata-sections" + TOOLCHAIN_CFLAGS_JDK="$TOOLCHAIN_CFLAGS_JDK -ffunction-sections -fdata-sections" + fi # technically NOT for CXX (but since this gives *worse* performance, use # no-strict-aliasing everywhere!) TOOLCHAIN_CFLAGS_JDK_CONLY="-fno-strict-aliasing" diff -r bfc8074ea4ef -r cfe31d2f935c make/autoconf/flags-ldflags.m4 --- a/make/autoconf/flags-ldflags.m4 Tue Nov 26 10:22:13 2019 +0000 +++ b/make/autoconf/flags-ldflags.m4 Fri Nov 29 10:02:07 2019 +0000 @@ -70,10 +70,14 @@ fi # Add -z defs, to forbid undefined symbols in object files. - BASIC_LDFLAGS="$BASIC_LDFLAGS -Wl,-z,defs" + # add relro (mark relocations read only) for all libs + BASIC_LDFLAGS="$BASIC_LDFLAGS -Wl,-z,defs -Wl,-z,relro" + # s390x : remove unused code+data in link step + if test "x$OPENJDK_TARGET_CPU" = xs390x; then + BASIC_LDFLAGS="$BASIC_LDFLAGS -Wl,--gc-sections -Wl,--print-gc-sections" + fi - BASIC_LDFLAGS_JVM_ONLY="-Wl,-O1 -Wl,-z,relro" - + BASIC_LDFLAGS_JVM_ONLY="-Wl,-O1" elif test "x$TOOLCHAIN_TYPE" = xclang; then BASIC_LDFLAGS_JVM_ONLY="-mno-omit-leaf-frame-pointer -mstack-alignment=16 \ @@ -120,9 +124,6 @@ if test "x$OPENJDK_TARGET_OS" = xlinux; then if test x$DEBUG_LEVEL = xrelease; then DEBUGLEVEL_LDFLAGS_JDK_ONLY="$DEBUGLEVEL_LDFLAGS_JDK_ONLY -Wl,-O1" - else - # mark relocations read only on (fast/slow) debug builds - DEBUGLEVEL_LDFLAGS_JDK_ONLY="-Wl,-z,relro" fi if test x$DEBUG_LEVEL = xslowdebug; then # do relocations at load diff -r bfc8074ea4ef -r cfe31d2f935c make/data/cacerts/amazonrootca1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/make/data/cacerts/amazonrootca1 Fri Nov 29 10:02:07 2019 +0000 @@ -0,0 +1,27 @@ +Owner: CN=Amazon Root CA 1, O=Amazon, C=US +Issuer: CN=Amazon Root CA 1, O=Amazon, C=US +Serial number: 66c9fcf99bf8c0a39e2f0788a43e696365bca +Valid from: Tue May 26 00:00:00 GMT 2015 until: Sun Jan 17 00:00:00 GMT 2038 +Signature algorithm name: SHA256withRSA +Subject Public Key Algorithm: 2048-bit RSA key +Version: 3 +-----BEGIN CERTIFICATE----- +MIIDQTCCAimgAwIBAgITBmyfz5m/jAo54vB4ikPmljZbyjANBgkqhkiG9w0BAQsF +ADA5MQswCQYDVQQGEwJVUzEPMA0GA1UEChMGQW1hem9uMRkwFwYDVQQDExBBbWF6 +b24gUm9vdCBDQSAxMB4XDTE1MDUyNjAwMDAwMFoXDTM4MDExNzAwMDAwMFowOTEL +MAkGA1UEBhMCVVMxDzANBgNVBAoTBkFtYXpvbjEZMBcGA1UEAxMQQW1hem9uIFJv +b3QgQ0EgMTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALJ4gHHKeNXj +ca9HgFB0fW7Y14h29Jlo91ghYPl0hAEvrAIthtOgQ3pOsqTQNroBvo3bSMgHFzZM +9O6II8c+6zf1tRn4SWiw3te5djgdYZ6k/oI2peVKVuRF4fn9tBb6dNqcmzU5L/qw +IFAGbHrQgLKm+a/sRxmPUDgH3KKHOVj4utWp+UhnMJbulHheb4mjUcAwhmahRWa6 +VOujw5H5SNz/0egwLX0tdHA114gk957EWW67c4cX8jJGKLhD+rcdqsq08p8kDi1L +93FcXmn/6pUCyziKrlA4b9v7LWIbxcceVOF34GfID5yHI9Y/QCB/IIDEgEw+OyQm +jgSubJrIqg0CAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMC +AYYwHQYDVR0OBBYEFIQYzIU07LwMlJQuCFmcx7IQTgoIMA0GCSqGSIb3DQEBCwUA +A4IBAQCY8jdaQZChGsV2USggNiMOruYou6r4lK5IpDB/G/wkjUu0yKGX9rbxenDI +U5PMCCjjmCXPI6T53iHTfIUJrU6adTrCC2qJeHZERxhlbI1Bjjt/msv0tadQ1wUs +N+gDS63pYaACbvXy8MWy7Vu33PqUXHeeE6V/Uq2V8viTO96LXFvKWlJbYK8U90vv +o/ufQJVtMVT8QtPHRh8jrdkPSHCa2XV4cdFyQzR1bldZwgJcJmApzyMZFo6IQ6XU +5MsI+yMRQ+hDKXJioaldXgjUkK642M4UwtBV8ob2xJNDd2ZhwLnoQdeXeGADbkpy +rqXRfboQnoZsG4q5WTP468SQvvG5 +-----END CERTIFICATE----- diff -r bfc8074ea4ef -r cfe31d2f935c make/data/cacerts/amazonrootca2 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/make/data/cacerts/amazonrootca2 Fri Nov 29 10:02:07 2019 +0000 @@ -0,0 +1,38 @@ +Owner: CN=Amazon Root CA 2, O=Amazon, C=US +Issuer: CN=Amazon Root CA 2, O=Amazon, C=US +Serial number: 66c9fd29635869f0a0fe58678f85b26bb8a37 +Valid from: Tue May 26 00:00:00 GMT 2015 until: Sat May 26 00:00:00 GMT 2040 +Signature algorithm name: SHA384withRSA +Subject Public Key Algorithm: 4096-bit RSA key +Version: 3 +-----BEGIN CERTIFICATE----- +MIIFQTCCAymgAwIBAgITBmyf0pY1hp8KD+WGePhbJruKNzANBgkqhkiG9w0BAQwF +ADA5MQswCQYDVQQGEwJVUzEPMA0GA1UEChMGQW1hem9uMRkwFwYDVQQDExBBbWF6 +b24gUm9vdCBDQSAyMB4XDTE1MDUyNjAwMDAwMFoXDTQwMDUyNjAwMDAwMFowOTEL +MAkGA1UEBhMCVVMxDzANBgNVBAoTBkFtYXpvbjEZMBcGA1UEAxMQQW1hem9uIFJv +b3QgQ0EgMjCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAK2Wny2cSkxK +gXlRmeyKy2tgURO8TW0G/LAIjd0ZEGrHJgw12MBvIITplLGbhQPDW9tK6Mj4kHbZ +W0/jTOgGNk3Mmqw9DJArktQGGWCsN0R5hYGCrVo34A3MnaZMUnbqQ523BNFQ9lXg +1dKmSYXpN+nKfq5clU1Imj+uIFptiJXZNLhSGkOQsL9sBbm2eLfq0OQ6PBJTYv9K +8nu+NQWpEjTj82R0Yiw9AElaKP4yRLuH3WUnAnE72kr3H9rN9yFVkE8P7K6C4Z9r +2UXTu/Bfh+08LDmG2j/e7HJV63mjrdvdfLC6HM783k81ds8P+HgfajZRRidhW+me +z/CiVX18JYpvL7TFz4QuK/0NURBs+18bvBt+xa47mAExkv8LV/SasrlX6avvDXbR +8O70zoan4G7ptGmh32n2M8ZpLpcTnqWHsFcQgTfJU7O7f/aS0ZzQGPSSbtqDT6Zj +mUyl+17vIWR6IF9sZIUVyzfpYgwLKhbcAS4y2j5L9Z469hdAlO+ekQiG+r5jqFoz +7Mt0Q5X5bGlSNscpb/xVA1wf+5+9R+vnSUeVC06JIglJ4PVhHvG/LopyboBZ/1c6 ++XUyo05f7O0oYtlNc/LMgRdg7c3r3NunysV+Ar3yVAhU/bQtCSwXVEqY0VThUWcI +0u1ufm8/0i2BWSlmy5A5lREedCf+3euvAgMBAAGjQjBAMA8GA1UdEwEB/wQFMAMB +Af8wDgYDVR0PAQH/BAQDAgGGMB0GA1UdDgQWBBSwDPBMMPQFWAJI/TPlUq9LhONm +UjANBgkqhkiG9w0BAQwFAAOCAgEAqqiAjw54o+Ci1M3m9Zh6O+oAA7CXDpO8Wqj2 +LIxyh6mx/H9z/WNxeKWHWc8w4Q0QshNabYL1auaAn6AFC2jkR2vHat+2/XcycuUY ++gn0oJMsXdKMdYV2ZZAMA3m3MSNjrXiDCYZohMr/+c8mmpJ5581LxedhpxfL86kS +k5Nrp+gvU5LEYFiwzAJRGFuFjWJZY7attN6a+yb3ACfAXVU3dJnJUH/jWS5E4ywl +7uxMMne0nxrpS10gxdr9HIcWxkPo1LsmmkVwXqkLN1PiRnsn/eBG8om3zEK2yygm +btmlyTrIQRNg91CMFa6ybRoVGld45pIq2WWQgj9sAq+uEjonljYE1x2igGOpm/Hl +urR8FLBOybEfdF849lHqm/osohHUqS0nGkWxr7JOcQ3AWEbWaQbLU8uz/mtBzUF+ +fUwPfHJ5elnNXkoOrJupmHN5fLT0zLm4BwyydFy4x2+IoZCn9Kr5v2c69BoVYh63 +n749sSmvZ6ES8lgQGVMDMBu4Gon2nL2XA46jCfMdiyHxtN/kHNGfZQIG6lzWE7OE +76KlXIx3KadowGuuQNKotOrN8I1LOJwZmhsoVLiJkO/KdYE+HvJkJMcYr07/R54H +9jVlpNMKVv/1F2Rs76giJUmTtt8AF9pYfl3uxRuw0dFfIRDH+fO6AgonB8Xx1sfT +4PsJYGw= +-----END CERTIFICATE----- diff -r bfc8074ea4ef -r cfe31d2f935c make/data/cacerts/amazonrootca3 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/make/data/cacerts/amazonrootca3 Fri Nov 29 10:02:07 2019 +0000 @@ -0,0 +1,19 @@ +Owner: CN=Amazon Root CA 3, O=Amazon, C=US +Issuer: CN=Amazon Root CA 3, O=Amazon, C=US +Serial number: 66c9fd5749736663f3b0b9ad9e89e7603f24a +Valid from: Tue May 26 00:00:00 GMT 2015 until: Sat May 26 00:00:00 GMT 2040 +Signature algorithm name: SHA256withECDSA +Subject Public Key Algorithm: 256-bit EC key +Version: 3 +-----BEGIN CERTIFICATE----- +MIIBtjCCAVugAwIBAgITBmyf1XSXNmY/Owua2eiedgPySjAKBggqhkjOPQQDAjA5 +MQswCQYDVQQGEwJVUzEPMA0GA1UEChMGQW1hem9uMRkwFwYDVQQDExBBbWF6b24g +Um9vdCBDQSAzMB4XDTE1MDUyNjAwMDAwMFoXDTQwMDUyNjAwMDAwMFowOTELMAkG +A1UEBhMCVVMxDzANBgNVBAoTBkFtYXpvbjEZMBcGA1UEAxMQQW1hem9uIFJvb3Qg +Q0EgMzBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABCmXp8ZBf8ANm+gBG1bG8lKl +ui2yEujSLtf6ycXYqm0fc4E7O5hrOXwzpcVOho6AF2hiRVd9RFgdszflZwjrZt6j +QjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgGGMB0GA1UdDgQWBBSr +ttvXBp43rDCGB5Fwx5zEGbF4wDAKBggqhkjOPQQDAgNJADBGAiEA4IWSoxe3jfkr +BqWTrBqYaGFy+uGh0PsceGCmQ5nFuMQCIQCcAu/xlJyzlvnrxir4tiz+OpAUFteM +YyRIHN8wfdVoOw== +-----END CERTIFICATE----- diff -r bfc8074ea4ef -r cfe31d2f935c make/data/cacerts/amazonrootca4 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/make/data/cacerts/amazonrootca4 Fri Nov 29 10:02:07 2019 +0000 @@ -0,0 +1,20 @@ +Owner: CN=Amazon Root CA 4, O=Amazon, C=US +Issuer: CN=Amazon Root CA 4, O=Amazon, C=US +Serial number: 66c9fd7c1bb104c2943e5717b7b2cc81ac10e +Valid from: Tue May 26 00:00:00 GMT 2015 until: Sat May 26 00:00:00 GMT 2040 +Signature algorithm name: SHA384withECDSA +Subject Public Key Algorithm: 384-bit EC key +Version: 3 +-----BEGIN CERTIFICATE----- +MIIB8jCCAXigAwIBAgITBmyf18G7EEwpQ+Vxe3ssyBrBDjAKBggqhkjOPQQDAzA5 +MQswCQYDVQQGEwJVUzEPMA0GA1UEChMGQW1hem9uMRkwFwYDVQQDExBBbWF6b24g +Um9vdCBDQSA0MB4XDTE1MDUyNjAwMDAwMFoXDTQwMDUyNjAwMDAwMFowOTELMAkG +A1UEBhMCVVMxDzANBgNVBAoTBkFtYXpvbjEZMBcGA1UEAxMQQW1hem9uIFJvb3Qg +Q0EgNDB2MBAGByqGSM49AgEGBSuBBAAiA2IABNKrijdPo1MN/sGKe0uoe0ZLY7Bi +9i0b2whxIdIA6GO9mif78DluXeo9pcmBqqNbIJhFXRbb/egQbeOc4OO9X4Ri83Bk +M6DLJC9wuoihKqB1+IGuYgbEgds5bimwHvouXKNCMEAwDwYDVR0TAQH/BAUwAwEB +/zAOBgNVHQ8BAf8EBAMCAYYwHQYDVR0OBBYEFNPsxzplbszh2naaVvuc84ZtV+WB +MAoGCCqGSM49BAMDA2gAMGUCMDqLIfG9fhGt0O9Yli/W651+kI0rz2ZVwyzjKKlw +CkcO8DdZEv8tmZQoTipPNU0zWgIxAOp1AE47xDqUEpHJWEadIRNyp4iciuRMStuW +1KyLa2tJElMzrdfkviT8tQp21KW8EA== +-----END CERTIFICATE----- diff -r bfc8074ea4ef -r cfe31d2f935c src/hotspot/cpu/aarch64/aarch64.ad --- a/src/hotspot/cpu/aarch64/aarch64.ad Tue Nov 26 10:22:13 2019 +0000 +++ b/src/hotspot/cpu/aarch64/aarch64.ad Fri Nov 29 10:02:07 2019 +0000 @@ -5639,7 +5639,6 @@ operand cmpOpEqNe() %{ match(Bool); - match(CmpOp); op_cost(0); predicate(n->as_Bool()->_test._test == BoolTest::ne || n->as_Bool()->_test._test == BoolTest::eq); @@ -5663,7 +5662,6 @@ operand cmpOpLtGe() %{ match(Bool); - match(CmpOp); op_cost(0); predicate(n->as_Bool()->_test._test == BoolTest::lt @@ -5688,7 +5686,6 @@ operand cmpOpUEqNeLtGe() %{ match(Bool); - match(CmpOp); op_cost(0); predicate(n->as_Bool()->_test._test == BoolTest::eq diff -r bfc8074ea4ef -r cfe31d2f935c src/hotspot/cpu/aarch64/nativeInst_aarch64.cpp --- a/src/hotspot/cpu/aarch64/nativeInst_aarch64.cpp Tue Nov 26 10:22:13 2019 +0000 +++ b/src/hotspot/cpu/aarch64/nativeInst_aarch64.cpp Fri Nov 29 10:02:07 2019 +0000 @@ -30,6 +30,7 @@ #include "nativeInst_aarch64.hpp" #include "oops/oop.inline.hpp" #include "runtime/handles.hpp" +#include "runtime/orderAccess.hpp" #include "runtime/sharedRuntime.hpp" #include "runtime/stubRoutines.hpp" #include "utilities/ostream.hpp" diff -r bfc8074ea4ef -r cfe31d2f935c src/hotspot/cpu/aarch64/templateInterpreterGenerator_aarch64.cpp --- a/src/hotspot/cpu/aarch64/templateInterpreterGenerator_aarch64.cpp Tue Nov 26 10:22:13 2019 +0000 +++ b/src/hotspot/cpu/aarch64/templateInterpreterGenerator_aarch64.cpp Fri Nov 29 10:02:07 2019 +0000 @@ -443,7 +443,6 @@ Register obj = r0; Register mdp = r1; Register tmp = r2; - __ ldr(mdp, Address(rmethod, Method::method_data_offset())); __ profile_return_type(mdp, obj, tmp); } @@ -1633,13 +1632,8 @@ __ mov(rscratch2, true); __ strb(rscratch2, do_not_unlock_if_synchronized); - Label no_mdp; Register mdp = r3; - __ ldr(mdp, Address(rmethod, Method::method_data_offset())); - __ cbz(mdp, no_mdp); - __ add(mdp, mdp, in_bytes(MethodData::data_offset())); __ profile_parameters_type(mdp, r1, r2); - __ bind(no_mdp); // increment invocation count & check for overflow Label invocation_counter_overflow; diff -r bfc8074ea4ef -r cfe31d2f935c src/hotspot/cpu/arm/arm.ad --- a/src/hotspot/cpu/arm/arm.ad Tue Nov 26 10:22:13 2019 +0000 +++ b/src/hotspot/cpu/arm/arm.ad Fri Nov 29 10:02:07 2019 +0000 @@ -2204,6 +2204,30 @@ interface(REG_INTER); %} +operand R8RegP() %{ + constraint(ALLOC_IN_RC(R8_regP)); + match(iRegP); + + format %{ %} + interface(REG_INTER); +%} + +operand R9RegP() %{ + constraint(ALLOC_IN_RC(R9_regP)); + match(iRegP); + + format %{ %} + interface(REG_INTER); +%} + +operand R12RegP() %{ + constraint(ALLOC_IN_RC(R12_regP)); + match(iRegP); + + format %{ %} + interface(REG_INTER); +%} + operand R2RegP() %{ constraint(ALLOC_IN_RC(R2_regP)); match(iRegP); @@ -2236,6 +2260,14 @@ interface(REG_INTER); %} +operand SPRegP() %{ + constraint(ALLOC_IN_RC(SP_regP)); + match(iRegP); + + format %{ %} + interface(REG_INTER); +%} + operand LRRegP() %{ constraint(ALLOC_IN_RC(LR_regP)); match(iRegP); diff -r bfc8074ea4ef -r cfe31d2f935c src/hotspot/cpu/arm/arm_32.ad --- a/src/hotspot/cpu/arm/arm_32.ad Tue Nov 26 10:22:13 2019 +0000 +++ b/src/hotspot/cpu/arm/arm_32.ad Fri Nov 29 10:02:07 2019 +0000 @@ -232,11 +232,15 @@ reg_class R1_regP(R_R1); reg_class R2_regP(R_R2); reg_class R4_regP(R_R4); +reg_class R8_regP(R_R8); +reg_class R9_regP(R_R9); +reg_class R12_regP(R_R12); reg_class Rexception_regP(R_Rexception_obj); reg_class Ricklass_regP(R_Ricklass); reg_class Rmethod_regP(R_Rmethod); reg_class Rthread_regP(R_Rthread); reg_class IP_regP(R_R12); +reg_class SP_regP(R_R13); reg_class LR_regP(R_R14); reg_class FP_regP(R_R11); diff -r bfc8074ea4ef -r cfe31d2f935c src/hotspot/cpu/arm/c1_LIRAssembler_arm.cpp --- a/src/hotspot/cpu/arm/c1_LIRAssembler_arm.cpp Tue Nov 26 10:22:13 2019 +0000 +++ b/src/hotspot/cpu/arm/c1_LIRAssembler_arm.cpp Fri Nov 29 10:02:07 2019 +0000 @@ -581,6 +581,7 @@ base_reg = Rtemp; __ str(from_lo, Address(Rtemp)); if (patch != NULL) { + __ nop(); // see comment before patching_epilog for 2nd str patching_epilog(patch, lir_patch_low, base_reg, info); patch = new PatchingStub(_masm, PatchingStub::access_field_id); patch_code = lir_patch_high; @@ -589,6 +590,7 @@ } else if (base_reg == from_lo) { __ str(from_hi, as_Address_hi(to_addr)); if (patch != NULL) { + __ nop(); // see comment before patching_epilog for 2nd str patching_epilog(patch, lir_patch_high, base_reg, info); patch = new PatchingStub(_masm, PatchingStub::access_field_id); patch_code = lir_patch_low; @@ -597,6 +599,7 @@ } else { __ str(from_lo, as_Address_lo(to_addr)); if (patch != NULL) { + __ nop(); // see comment before patching_epilog for 2nd str patching_epilog(patch, lir_patch_low, base_reg, info); patch = new PatchingStub(_masm, PatchingStub::access_field_id); patch_code = lir_patch_high; @@ -640,7 +643,7 @@ } if (patch != NULL) { - // Offset embeedded into LDR/STR instruction may appear not enough + // Offset embedded into LDR/STR instruction may appear not enough // to address a field. So, provide a space for one more instruction // that will deal with larger offsets. __ nop(); @@ -791,6 +794,7 @@ base_reg = Rtemp; __ ldr(to_lo, Address(Rtemp)); if (patch != NULL) { + __ nop(); // see comment before patching_epilog for 2nd ldr patching_epilog(patch, lir_patch_low, base_reg, info); patch = new PatchingStub(_masm, PatchingStub::access_field_id); patch_code = lir_patch_high; @@ -799,6 +803,7 @@ } else if (base_reg == to_lo) { __ ldr(to_hi, as_Address_hi(addr)); if (patch != NULL) { + __ nop(); // see comment before patching_epilog for 2nd ldr patching_epilog(patch, lir_patch_high, base_reg, info); patch = new PatchingStub(_masm, PatchingStub::access_field_id); patch_code = lir_patch_low; @@ -807,6 +812,7 @@ } else { __ ldr(to_lo, as_Address_lo(addr)); if (patch != NULL) { + __ nop(); // see comment before patching_epilog for 2nd ldr patching_epilog(patch, lir_patch_low, base_reg, info); patch = new PatchingStub(_masm, PatchingStub::access_field_id); patch_code = lir_patch_high; @@ -846,7 +852,7 @@ } if (patch != NULL) { - // Offset embeedded into LDR/STR instruction may appear not enough + // Offset embedded into LDR/STR instruction may appear not enough // to address a field. So, provide a space for one more instruction // that will deal with larger offsets. __ nop(); diff -r bfc8074ea4ef -r cfe31d2f935c src/hotspot/cpu/arm/nativeInst_arm_32.hpp --- a/src/hotspot/cpu/arm/nativeInst_arm_32.hpp Tue Nov 26 10:22:13 2019 +0000 +++ b/src/hotspot/cpu/arm/nativeInst_arm_32.hpp Fri Nov 29 10:02:07 2019 +0000 @@ -28,6 +28,7 @@ #include "asm/macroAssembler.hpp" #include "code/codeCache.hpp" #include "runtime/icache.hpp" +#include "runtime/orderAccess.hpp" #include "runtime/os.hpp" #include "runtime/thread.hpp" #include "register_arm.hpp" diff -r bfc8074ea4ef -r cfe31d2f935c src/hotspot/cpu/arm/relocInfo_arm.cpp --- a/src/hotspot/cpu/arm/relocInfo_arm.cpp Tue Nov 26 10:22:13 2019 +0000 +++ b/src/hotspot/cpu/arm/relocInfo_arm.cpp Fri Nov 29 10:02:07 2019 +0000 @@ -29,7 +29,6 @@ #include "nativeInst_arm.hpp" #include "oops/compressedOops.inline.hpp" #include "oops/oop.hpp" -#include "runtime/orderAccess.hpp" #include "runtime/safepoint.hpp" void Relocation::pd_set_data_value(address x, intptr_t o, bool verify_only) { diff -r bfc8074ea4ef -r cfe31d2f935c src/hotspot/cpu/x86/gc/shared/barrierSetAssembler_x86.cpp --- a/src/hotspot/cpu/x86/gc/shared/barrierSetAssembler_x86.cpp Tue Nov 26 10:22:13 2019 +0000 +++ b/src/hotspot/cpu/x86/gc/shared/barrierSetAssembler_x86.cpp Fri Nov 29 10:02:07 2019 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2019, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -327,24 +327,42 @@ #endif } +#ifdef _LP64 void BarrierSetAssembler::nmethod_entry_barrier(MacroAssembler* masm) { BarrierSetNMethod* bs_nm = BarrierSet::barrier_set()->barrier_set_nmethod(); if (bs_nm == NULL) { return; } -#ifndef _LP64 - ShouldNotReachHere(); -#else Label continuation; - Register thread = LP64_ONLY(r15_thread); + Register thread = r15_thread; Address disarmed_addr(thread, in_bytes(bs_nm->thread_disarmed_offset())); __ align(8); __ cmpl(disarmed_addr, 0); __ jcc(Assembler::equal, continuation); __ call(RuntimeAddress(StubRoutines::x86::method_entry_barrier())); __ bind(continuation); +} +#else +void BarrierSetAssembler::nmethod_entry_barrier(MacroAssembler* masm) { + BarrierSetNMethod* bs_nm = BarrierSet::barrier_set()->barrier_set_nmethod(); + if (bs_nm == NULL) { + return; + } + + Label continuation; + + Register tmp = rdi; + __ push(tmp); + __ movptr(tmp, (intptr_t)bs_nm->disarmed_value_address()); + Address disarmed_addr(tmp, 0); + __ align(4); + __ cmpl(disarmed_addr, 0); + __ pop(tmp); + __ jcc(Assembler::equal, continuation); + __ call(RuntimeAddress(StubRoutines::x86::method_entry_barrier())); + __ bind(continuation); +} #endif -} void BarrierSetAssembler::c2i_entry_barrier(MacroAssembler* masm) { BarrierSetNMethod* bs = BarrierSet::barrier_set()->barrier_set_nmethod(); diff -r bfc8074ea4ef -r cfe31d2f935c src/hotspot/cpu/x86/gc/shared/barrierSetNMethod_x86.cpp --- a/src/hotspot/cpu/x86/gc/shared/barrierSetNMethod_x86.cpp Tue Nov 26 10:22:13 2019 +0000 +++ b/src/hotspot/cpu/x86/gc/shared/barrierSetNMethod_x86.cpp Fri Nov 29 10:02:07 2019 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2019, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -35,6 +35,7 @@ class NativeNMethodCmpBarrier: public NativeInstruction { public: +#ifdef _LP64 enum Intel_specific_constants { instruction_code = 0x81, instruction_size = 8, @@ -42,6 +43,14 @@ instruction_rex_prefix = Assembler::REX | Assembler::REX_B, instruction_modrm = 0x7f // [r15 + offset] }; +#else + enum Intel_specific_constants { + instruction_code = 0x81, + instruction_size = 7, + imm_offset = 2, + instruction_modrm = 0x3f // [rdi] + }; +#endif address instruction_address() const { return addr_at(0); } address immediate_address() const { return addr_at(imm_offset); } @@ -51,6 +60,7 @@ void verify() const; }; +#ifdef _LP64 void NativeNMethodCmpBarrier::verify() const { if (((uintptr_t) instruction_address()) & 0x7) { fatal("Not properly aligned"); @@ -77,6 +87,27 @@ fatal("not a cmp barrier"); } } +#else +void NativeNMethodCmpBarrier::verify() const { + if (((uintptr_t) instruction_address()) & 0x3) { + fatal("Not properly aligned"); + } + + int inst = ubyte_at(0); + if (inst != instruction_code) { + tty->print_cr("Addr: " INTPTR_FORMAT " Code: 0x%x", p2i(instruction_address()), + inst); + fatal("not a cmp barrier"); + } + + int modrm = ubyte_at(1); + if (modrm != instruction_modrm) { + tty->print_cr("Addr: " INTPTR_FORMAT " mod/rm: 0x%x", p2i(instruction_address()), + modrm); + fatal("not a cmp barrier"); + } +} +#endif // _LP64 void BarrierSetNMethod::deoptimize(nmethod* nm, address* return_address_ptr) { /* @@ -127,7 +158,7 @@ // NativeNMethodCmpBarrier::verify() will immediately complain when it does // not find the expected native instruction at this offset, which needs updating. // Note that this offset is invariant of PreserveFramePointer. -static const int entry_barrier_offset = -19; +static const int entry_barrier_offset = LP64_ONLY(-19) NOT_LP64(-18); static NativeNMethodCmpBarrier* native_nmethod_barrier(nmethod* nm) { address barrier_address = nm->code_begin() + nm->frame_complete_offset() + entry_barrier_offset; diff -r bfc8074ea4ef -r cfe31d2f935c src/hotspot/cpu/x86/gc/shenandoah/shenandoahBarrierSetAssembler_x86.cpp --- a/src/hotspot/cpu/x86/gc/shenandoah/shenandoahBarrierSetAssembler_x86.cpp Tue Nov 26 10:22:13 2019 +0000 +++ b/src/hotspot/cpu/x86/gc/shenandoah/shenandoahBarrierSetAssembler_x86.cpp Fri Nov 29 10:02:07 2019 +0000 @@ -395,6 +395,52 @@ __ block_comment("load_reference_barrier_native { "); } +#ifdef _LP64 +void ShenandoahBarrierSetAssembler::c2i_entry_barrier(MacroAssembler* masm) { + // Use default version + BarrierSetAssembler::c2i_entry_barrier(masm); +} +#else +void ShenandoahBarrierSetAssembler::c2i_entry_barrier(MacroAssembler* masm) { + BarrierSetNMethod* bs = BarrierSet::barrier_set()->barrier_set_nmethod(); + if (bs == NULL) { + return; + } + + Label bad_call; + __ cmpptr(rbx, 0); // rbx contains the incoming method for c2i adapters. + __ jcc(Assembler::equal, bad_call); + + Register tmp1 = rax; + Register tmp2 = rcx; + + __ push(tmp1); + __ push(tmp2); + + // Pointer chase to the method holder to find out if the method is concurrently unloading. + Label method_live; + __ load_method_holder_cld(tmp1, rbx); + + // Is it a strong CLD? + __ cmpl(Address(tmp1, ClassLoaderData::keep_alive_offset()), 0); + __ jcc(Assembler::greater, method_live); + + // Is it a weak but alive CLD? + __ movptr(tmp1, Address(tmp1, ClassLoaderData::holder_offset())); + __ resolve_weak_handle(tmp1, tmp2); + __ cmpptr(tmp1, 0); + __ jcc(Assembler::notEqual, method_live); + __ pop(tmp2); + __ pop(tmp1); + + __ bind(bad_call); + __ jump(RuntimeAddress(SharedRuntime::get_handle_wrong_method_stub())); + __ bind(method_live); + __ pop(tmp2); + __ pop(tmp1); +} +#endif + void ShenandoahBarrierSetAssembler::storeval_barrier(MacroAssembler* masm, Register dst, Register tmp) { if (ShenandoahStoreValEnqueueBarrier) { storeval_barrier_impl(masm, dst, tmp); @@ -511,8 +557,12 @@ // 3: apply keep-alive barrier if needed if (ShenandoahBarrierSet::need_keep_alive_barrier(decorators, type)) { - const Register thread = NOT_LP64(tmp_thread) LP64_ONLY(r15_thread); + __ push_IU_state(); + Register thread = NOT_LP64(tmp_thread) LP64_ONLY(r15_thread); assert_different_registers(dst, tmp1, tmp_thread); + if (!thread->is_valid()) { + thread = rdx; + } NOT_LP64(__ get_thread(thread)); // Generate the SATB pre-barrier code to log the value of // the referent field in an SATB buffer. @@ -523,6 +573,7 @@ tmp1 /* tmp */, true /* tosca_live */, true /* expand_call */); + __ pop_IU_state(); } } diff -r bfc8074ea4ef -r cfe31d2f935c src/hotspot/cpu/x86/gc/shenandoah/shenandoahBarrierSetAssembler_x86.hpp --- a/src/hotspot/cpu/x86/gc/shenandoah/shenandoahBarrierSetAssembler_x86.hpp Tue Nov 26 10:22:13 2019 +0000 +++ b/src/hotspot/cpu/x86/gc/shenandoah/shenandoahBarrierSetAssembler_x86.hpp Fri Nov 29 10:02:07 2019 +0000 @@ -86,6 +86,7 @@ Address dst, Register val, Register tmp1, Register tmp2); virtual void try_resolve_jobject_in_native(MacroAssembler* masm, Register jni_env, Register obj, Register tmp, Label& slowpath); + virtual void c2i_entry_barrier(MacroAssembler* masm); virtual void barrier_stubs_init(); diff -r bfc8074ea4ef -r cfe31d2f935c src/hotspot/cpu/x86/rdtsc_x86.cpp --- a/src/hotspot/cpu/x86/rdtsc_x86.cpp Tue Nov 26 10:22:13 2019 +0000 +++ b/src/hotspot/cpu/x86/rdtsc_x86.cpp Fri Nov 29 10:02:07 2019 +0000 @@ -24,6 +24,7 @@ #include "precompiled.hpp" #include "rdtsc_x86.hpp" +#include "runtime/orderAccess.hpp" #include "runtime/thread.inline.hpp" #include "vm_version_ext_x86.hpp" diff -r bfc8074ea4ef -r cfe31d2f935c src/hotspot/cpu/x86/sharedRuntime_x86_32.cpp --- a/src/hotspot/cpu/x86/sharedRuntime_x86_32.cpp Tue Nov 26 10:22:13 2019 +0000 +++ b/src/hotspot/cpu/x86/sharedRuntime_x86_32.cpp Fri Nov 29 10:02:07 2019 +0000 @@ -975,6 +975,9 @@ address c2i_entry = __ pc(); + BarrierSetAssembler* bs = BarrierSet::barrier_set()->barrier_set_assembler(); + bs->c2i_entry_barrier(masm); + gen_c2i_adapter(masm, total_args_passed, comp_args_on_stack, sig_bt, regs, skip_fixup); __ flush(); @@ -1886,6 +1889,10 @@ // -2 because return address is already present and so is saved rbp __ subptr(rsp, stack_size - 2*wordSize); + + BarrierSetAssembler* bs = BarrierSet::barrier_set()->barrier_set_assembler(); + bs->nmethod_entry_barrier(masm); + // Frame is now completed as far as size and linkage. int frame_complete = ((intptr_t)__ pc()) - start; @@ -1921,12 +1928,12 @@ // if we load it once it is usable thru the entire wrapper const Register thread = rdi; - // We use rsi as the oop handle for the receiver/klass - // It is callee save so it survives the call to native - - const Register oop_handle_reg = rsi; - - __ get_thread(thread); + // We use rsi as the oop handle for the receiver/klass + // It is callee save so it survives the call to native + + const Register oop_handle_reg = rsi; + + __ get_thread(thread); if (is_critical_native && !Universe::heap()->supports_object_pinning()) { check_needs_gc_for_critical_native(masm, thread, stack_slots, total_c_args, total_in_args, diff -r bfc8074ea4ef -r cfe31d2f935c src/hotspot/cpu/x86/stubGenerator_x86_32.cpp --- a/src/hotspot/cpu/x86/stubGenerator_x86_32.cpp Tue Nov 26 10:22:13 2019 +0000 +++ b/src/hotspot/cpu/x86/stubGenerator_x86_32.cpp Fri Nov 29 10:02:07 2019 +0000 @@ -27,6 +27,7 @@ #include "asm/macroAssembler.inline.hpp" #include "gc/shared/barrierSet.hpp" #include "gc/shared/barrierSetAssembler.hpp" +#include "gc/shared/barrierSetNMethod.hpp" #include "interpreter/interpreter.hpp" #include "memory/universe.hpp" #include "nativeInst_x86.hpp" @@ -3663,6 +3664,68 @@ __ ret(0); } + address generate_method_entry_barrier() { + __ align(CodeEntryAlignment); + StubCodeMark mark(this, "StubRoutines", "nmethod_entry_barrier"); + + Label deoptimize_label; + + address start = __ pc(); + + __ push(-1); // cookie, this is used for writing the new rsp when deoptimizing + + BLOCK_COMMENT("Entry:"); + __ enter(); // save rbp + + // save rbx, because we want to use that value. + // We could do without it but then we depend on the number of slots used by pusha + __ push(rbx); + + __ lea(rbx, Address(rsp, wordSize * 3)); // 1 for cookie, 1 for rbp, 1 for rbx - this should be the return address + + __ pusha(); + + // xmm0 and xmm1 may be used for passing float/double arguments + const int xmm_size = wordSize * 2; + const int xmm_spill_size = xmm_size * 2; + __ subptr(rsp, xmm_spill_size); + __ movdqu(Address(rsp, xmm_size * 1), xmm1); + __ movdqu(Address(rsp, xmm_size * 0), xmm0); + + __ call_VM_leaf(CAST_FROM_FN_PTR(address, static_cast(BarrierSetNMethod::nmethod_stub_entry_barrier)), rbx); + + __ movdqu(xmm0, Address(rsp, xmm_size * 0)); + __ movdqu(xmm1, Address(rsp, xmm_size * 1)); + __ addptr(rsp, xmm_spill_size); + + __ cmpl(rax, 1); // 1 means deoptimize + __ jcc(Assembler::equal, deoptimize_label); + + __ popa(); + __ pop(rbx); + + __ leave(); + + __ addptr(rsp, 1 * wordSize); // cookie + __ ret(0); + + __ BIND(deoptimize_label); + + __ popa(); + __ pop(rbx); + + __ leave(); + + // this can be taken out, but is good for verification purposes. getting a SIGSEGV + // here while still having a correct stack is valuable + __ testptr(rsp, Address(rsp, 0)); + + __ movptr(rsp, Address(rsp, 0)); // new rsp was written in the barrier + __ jmp(Address(rsp, -1 * wordSize)); // jmp target should be callers verified_entry_point + + return start; + } + public: // Information about frame layout at time of blocking runtime call. // Note that we only have to preserve callee-saved registers since @@ -3959,6 +4022,11 @@ StubRoutines::_safefetchN_entry = StubRoutines::_safefetch32_entry; StubRoutines::_safefetchN_fault_pc = StubRoutines::_safefetch32_fault_pc; StubRoutines::_safefetchN_continuation_pc = StubRoutines::_safefetch32_continuation_pc; + + BarrierSetNMethod* bs_nm = BarrierSet::barrier_set()->barrier_set_nmethod(); + if (bs_nm != NULL) { + StubRoutines::x86::_method_entry_barrier = generate_method_entry_barrier(); + } } diff -r bfc8074ea4ef -r cfe31d2f935c src/hotspot/cpu/x86/stubRoutines_x86.hpp --- a/src/hotspot/cpu/x86/stubRoutines_x86.hpp Tue Nov 26 10:22:13 2019 +0000 +++ b/src/hotspot/cpu/x86/stubRoutines_x86.hpp Fri Nov 29 10:02:07 2019 +0000 @@ -55,14 +55,8 @@ static address _double_sign_mask; static address _double_sign_flip; - static address _method_entry_barrier; - public: - static address method_entry_barrier() { - return _method_entry_barrier; - } - static address get_previous_fp_entry() { return _get_previous_fp_entry; } @@ -121,6 +115,8 @@ //shuffle mask for big-endian 128-bit integers static address _counter_shuffle_mask_addr; + static address _method_entry_barrier; + // masks and table for CRC32 static uint64_t _crc_by128_masks[]; static juint _crc_table[]; @@ -221,6 +217,7 @@ static address upper_word_mask_addr() { return _upper_word_mask_addr; } static address shuffle_byte_flip_mask_addr() { return _shuffle_byte_flip_mask_addr; } static address k256_addr() { return _k256_adr; } + static address method_entry_barrier() { return _method_entry_barrier; } static address vector_short_to_byte_mask() { return _vector_short_to_byte_mask; diff -r bfc8074ea4ef -r cfe31d2f935c src/hotspot/cpu/x86/stubRoutines_x86_32.cpp --- a/src/hotspot/cpu/x86/stubRoutines_x86_32.cpp Tue Nov 26 10:22:13 2019 +0000 +++ b/src/hotspot/cpu/x86/stubRoutines_x86_32.cpp Fri Nov 29 10:02:07 2019 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2019, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -32,3 +32,5 @@ // a description of how to extend it, see the stubRoutines.hpp file. address StubRoutines::x86::_verify_fpu_cntrl_wrd_entry = NULL; +address StubRoutines::x86::_method_entry_barrier = NULL; + diff -r bfc8074ea4ef -r cfe31d2f935c src/hotspot/cpu/x86/vm_version_x86.cpp --- a/src/hotspot/cpu/x86/vm_version_x86.cpp Tue Nov 26 10:22:13 2019 +0000 +++ b/src/hotspot/cpu/x86/vm_version_x86.cpp Fri Nov 29 10:02:07 2019 +0000 @@ -367,26 +367,29 @@ // intx saved_useavx = UseAVX; intx saved_usesse = UseSSE; - // check _cpuid_info.sef_cpuid7_ebx.bits.avx512f - __ lea(rsi, Address(rbp, in_bytes(VM_Version::sef_cpuid7_offset()))); - __ movl(rax, 0x10000); - __ andl(rax, Address(rsi, 4)); // xcr0 bits sse | ymm - __ cmpl(rax, 0x10000); - __ jccb(Assembler::notEqual, legacy_setup); // jump if EVEX is not supported - // check _cpuid_info.xem_xcr0_eax.bits.opmask - // check _cpuid_info.xem_xcr0_eax.bits.zmm512 - // check _cpuid_info.xem_xcr0_eax.bits.zmm32 - __ movl(rax, 0xE0); - __ andl(rax, Address(rbp, in_bytes(VM_Version::xem_xcr0_offset()))); // xcr0 bits sse | ymm - __ cmpl(rax, 0xE0); - __ jccb(Assembler::notEqual, legacy_setup); // jump if EVEX is not supported - __ lea(rsi, Address(rbp, in_bytes(VM_Version::std_cpuid1_offset()))); - __ movl(rax, Address(rsi, 0)); - __ cmpl(rax, 0x50654); // If it is Skylake - __ jcc(Assembler::equal, legacy_setup); // If UseAVX is unitialized or is set by the user to include EVEX if (use_evex) { + // check _cpuid_info.sef_cpuid7_ebx.bits.avx512f + __ lea(rsi, Address(rbp, in_bytes(VM_Version::sef_cpuid7_offset()))); + __ movl(rax, 0x10000); + __ andl(rax, Address(rsi, 4)); // xcr0 bits sse | ymm + __ cmpl(rax, 0x10000); + __ jccb(Assembler::notEqual, legacy_setup); // jump if EVEX is not supported + // check _cpuid_info.xem_xcr0_eax.bits.opmask + // check _cpuid_info.xem_xcr0_eax.bits.zmm512 + // check _cpuid_info.xem_xcr0_eax.bits.zmm32 + __ movl(rax, 0xE0); + __ andl(rax, Address(rbp, in_bytes(VM_Version::xem_xcr0_offset()))); // xcr0 bits sse | ymm + __ cmpl(rax, 0xE0); + __ jccb(Assembler::notEqual, legacy_setup); // jump if EVEX is not supported + + if (FLAG_IS_DEFAULT(UseAVX)) { + __ lea(rsi, Address(rbp, in_bytes(VM_Version::std_cpuid1_offset()))); + __ movl(rax, Address(rsi, 0)); + __ cmpl(rax, 0x50654); // If it is Skylake + __ jcc(Assembler::equal, legacy_setup); + } // EVEX setup: run in lowest evex mode VM_Version::set_evex_cpuFeatures(); // Enable temporary to pass asserts UseAVX = 3; @@ -455,27 +458,28 @@ VM_Version::set_cpuinfo_cont_addr(__ pc()); // Returns here after signal. Save xmm0 to check it later. - // check _cpuid_info.sef_cpuid7_ebx.bits.avx512f - __ lea(rsi, Address(rbp, in_bytes(VM_Version::sef_cpuid7_offset()))); - __ movl(rax, 0x10000); - __ andl(rax, Address(rsi, 4)); - __ cmpl(rax, 0x10000); - __ jcc(Assembler::notEqual, legacy_save_restore); - // check _cpuid_info.xem_xcr0_eax.bits.opmask - // check _cpuid_info.xem_xcr0_eax.bits.zmm512 - // check _cpuid_info.xem_xcr0_eax.bits.zmm32 - __ movl(rax, 0xE0); - __ andl(rax, Address(rbp, in_bytes(VM_Version::xem_xcr0_offset()))); // xcr0 bits sse | ymm - __ cmpl(rax, 0xE0); - __ jcc(Assembler::notEqual, legacy_save_restore); - - __ lea(rsi, Address(rbp, in_bytes(VM_Version::std_cpuid1_offset()))); - __ movl(rax, Address(rsi, 0)); - __ cmpl(rax, 0x50654); // If it is Skylake - __ jcc(Assembler::equal, legacy_save_restore); - // If UseAVX is unitialized or is set by the user to include EVEX if (use_evex) { + // check _cpuid_info.sef_cpuid7_ebx.bits.avx512f + __ lea(rsi, Address(rbp, in_bytes(VM_Version::sef_cpuid7_offset()))); + __ movl(rax, 0x10000); + __ andl(rax, Address(rsi, 4)); + __ cmpl(rax, 0x10000); + __ jcc(Assembler::notEqual, legacy_save_restore); + // check _cpuid_info.xem_xcr0_eax.bits.opmask + // check _cpuid_info.xem_xcr0_eax.bits.zmm512 + // check _cpuid_info.xem_xcr0_eax.bits.zmm32 + __ movl(rax, 0xE0); + __ andl(rax, Address(rbp, in_bytes(VM_Version::xem_xcr0_offset()))); // xcr0 bits sse | ymm + __ cmpl(rax, 0xE0); + __ jcc(Assembler::notEqual, legacy_save_restore); + + if (FLAG_IS_DEFAULT(UseAVX)) { + __ lea(rsi, Address(rbp, in_bytes(VM_Version::std_cpuid1_offset()))); + __ movl(rax, Address(rsi, 0)); + __ cmpl(rax, 0x50654); // If it is Skylake + __ jcc(Assembler::equal, legacy_save_restore); + } // EVEX check: run in lowest evex mode VM_Version::set_evex_cpuFeatures(); // Enable temporary to pass asserts UseAVX = 3; diff -r bfc8074ea4ef -r cfe31d2f935c src/hotspot/cpu/x86/x86_32.ad --- a/src/hotspot/cpu/x86/x86_32.ad Tue Nov 26 10:22:13 2019 +0000 +++ b/src/hotspot/cpu/x86/x86_32.ad Fri Nov 29 10:02:07 2019 +0000 @@ -3917,6 +3917,13 @@ interface(REG_INTER); %} +operand eDXRegP(eRegP reg) %{ + constraint(ALLOC_IN_RC(edx_reg)); + match(reg); + format %{ "EDX" %} + interface(REG_INTER); +%} + operand eSIRegP(eRegP reg) %{ constraint(ALLOC_IN_RC(esi_reg)); match(reg); @@ -8977,7 +8984,7 @@ %} ins_pipe(ialu_reg_reg); -%} +%} //----------Long Instructions------------------------------------------------ // Add Long Register with Register diff -r bfc8074ea4ef -r cfe31d2f935c src/hotspot/cpu/x86/x86_64.ad --- a/src/hotspot/cpu/x86/x86_64.ad Tue Nov 26 10:22:13 2019 +0000 +++ b/src/hotspot/cpu/x86/x86_64.ad Fri Nov 29 10:02:07 2019 +0000 @@ -267,6 +267,9 @@ // Singleton class for RSI pointer register reg_class ptr_rsi_reg(RSI, RSI_H); +// Singleton class for RBP pointer register +reg_class ptr_rbp_reg(RBP, RBP_H); + // Singleton class for RDI pointer register reg_class ptr_rdi_reg(RDI, RDI_H); @@ -3530,6 +3533,16 @@ interface(REG_INTER); %} +operand rbp_RegP() +%{ + constraint(ALLOC_IN_RC(ptr_rbp_reg)); + match(RegP); + match(rRegP); + + format %{ %} + interface(REG_INTER); +%} + // Used in rep stosq operand rdi_RegP() %{ diff -r bfc8074ea4ef -r cfe31d2f935c src/hotspot/cpu/zero/cppInterpreter_zero.cpp --- a/src/hotspot/cpu/zero/cppInterpreter_zero.cpp Tue Nov 26 10:22:13 2019 +0000 +++ b/src/hotspot/cpu/zero/cppInterpreter_zero.cpp Fri Nov 29 10:02:07 2019 +0000 @@ -38,13 +38,11 @@ #include "prims/jvmtiExport.hpp" #include "prims/jvmtiThreadState.hpp" #include "runtime/arguments.hpp" -#include "runtime/atomic.hpp" #include "runtime/deoptimization.hpp" #include "runtime/frame.inline.hpp" #include "runtime/handles.inline.hpp" #include "runtime/interfaceSupport.inline.hpp" #include "runtime/jniHandles.inline.hpp" -#include "runtime/orderAccess.hpp" #include "runtime/sharedRuntime.hpp" #include "runtime/stubRoutines.hpp" #include "runtime/synchronizer.hpp" diff -r bfc8074ea4ef -r cfe31d2f935c src/hotspot/os/aix/os_aix.cpp --- a/src/hotspot/os/aix/os_aix.cpp Tue Nov 26 10:22:13 2019 +0000 +++ b/src/hotspot/os/aix/os_aix.cpp Fri Nov 29 10:02:07 2019 +0000 @@ -60,7 +60,6 @@ #include "runtime/javaCalls.hpp" #include "runtime/mutexLocker.hpp" #include "runtime/objectMonitor.hpp" -#include "runtime/orderAccess.hpp" #include "runtime/os.hpp" #include "runtime/osThread.hpp" #include "runtime/perfMemory.hpp" diff -r bfc8074ea4ef -r cfe31d2f935c src/hotspot/os/linux/os_linux.cpp --- a/src/hotspot/os/linux/os_linux.cpp Tue Nov 26 10:22:13 2019 +0000 +++ b/src/hotspot/os/linux/os_linux.cpp Fri Nov 29 10:02:07 2019 +0000 @@ -53,7 +53,6 @@ #include "runtime/javaCalls.hpp" #include "runtime/mutexLocker.hpp" #include "runtime/objectMonitor.hpp" -#include "runtime/orderAccess.hpp" #include "runtime/osThread.hpp" #include "runtime/perfMemory.hpp" #include "runtime/sharedRuntime.hpp" diff -r bfc8074ea4ef -r cfe31d2f935c src/hotspot/os/posix/os_posix.cpp --- a/src/hotspot/os/posix/os_posix.cpp Tue Nov 26 10:22:13 2019 +0000 +++ b/src/hotspot/os/posix/os_posix.cpp Fri Nov 29 10:02:07 2019 +0000 @@ -30,6 +30,8 @@ #include "runtime/frame.inline.hpp" #include "runtime/interfaceSupport.inline.hpp" #include "services/memTracker.hpp" +#include "runtime/atomic.hpp" +#include "runtime/orderAccess.hpp" #include "utilities/align.hpp" #include "utilities/events.hpp" #include "utilities/formatBuffer.hpp" diff -r bfc8074ea4ef -r cfe31d2f935c src/hotspot/os/windows/osThread_windows.cpp --- a/src/hotspot/os/windows/osThread_windows.cpp Tue Nov 26 10:22:13 2019 +0000 +++ b/src/hotspot/os/windows/osThread_windows.cpp Fri Nov 29 10:02:07 2019 +0000 @@ -23,7 +23,6 @@ */ // no precompiled headers -#include "runtime/orderAccess.hpp" #include "runtime/os.hpp" #include "runtime/osThread.hpp" diff -r bfc8074ea4ef -r cfe31d2f935c src/hotspot/os_cpu/solaris_x86/os_solaris_x86.cpp --- a/src/hotspot/os_cpu/solaris_x86/os_solaris_x86.cpp Tue Nov 26 10:22:13 2019 +0000 +++ b/src/hotspot/os_cpu/solaris_x86/os_solaris_x86.cpp Fri Nov 29 10:02:07 2019 +0000 @@ -38,7 +38,6 @@ #include "prims/jniFastGetField.hpp" #include "prims/jvm_misc.hpp" #include "runtime/arguments.hpp" -#include "runtime/atomic.hpp" #include "runtime/extendedPC.hpp" #include "runtime/frame.inline.hpp" #include "runtime/interfaceSupport.inline.hpp" diff -r bfc8074ea4ef -r cfe31d2f935c src/hotspot/share/adlc/adlparse.cpp --- a/src/hotspot/share/adlc/adlparse.cpp Tue Nov 26 10:22:13 2019 +0000 +++ b/src/hotspot/share/adlc/adlparse.cpp Fri Nov 29 10:02:07 2019 +0000 @@ -123,6 +123,7 @@ parse_err(SEMERR, "Did not declare 'register' definitions"); } regBlock->addSpillRegClass(); + regBlock->addDynamicRegClass(); // Done with parsing, check consistency. diff -r bfc8074ea4ef -r cfe31d2f935c src/hotspot/share/adlc/archDesc.cpp --- a/src/hotspot/share/adlc/archDesc.cpp Tue Nov 26 10:22:13 2019 +0000 +++ b/src/hotspot/share/adlc/archDesc.cpp Fri Nov 29 10:02:07 2019 +0000 @@ -245,12 +245,12 @@ // Construct chain rules build_chain_rule(op); - MatchRule &mrule = *op->_matrule; - Predicate *pred = op->_predicate; + MatchRule *mrule = op->_matrule; + Predicate *pred = op->_predicate; // Grab the machine type of the operand const char *rootOp = op->_ident; - mrule._machType = rootOp; + mrule->_machType = rootOp; // Check for special cases if (strcmp(rootOp,"Universe")==0) continue; @@ -271,10 +271,13 @@ // Find result type for match. const char *result = op->reduce_result(); - bool has_root = false; - // Construct a MatchList for this entry - buildMatchList(op->_matrule, result, rootOp, pred, cost); + // Construct a MatchList for this entry. + // Iterate over the list to enumerate all match cases for operands with multiple match rules. + for (; mrule != NULL; mrule = mrule->_next) { + mrule->_machType = rootOp; + buildMatchList(mrule, result, rootOp, pred, cost); + } } } @@ -805,6 +808,8 @@ return "RegMask::Empty"; } else if (strcmp(reg_class_name,"stack_slots")==0) { return "(Compile::current()->FIRST_STACK_mask())"; + } else if (strcmp(reg_class_name, "dynamic")==0) { + return "*_opnds[0]->in_RegMask(0)"; } else { char *rc_name = toUpper(reg_class_name); const char *mask = "_mask"; @@ -867,7 +872,7 @@ } // Instructions producing 'Universe' use RegMask::Empty - if( strcmp(result,"Universe")==0 ) { + if (strcmp(result,"Universe") == 0) { return "RegMask::Empty"; } diff -r bfc8074ea4ef -r cfe31d2f935c src/hotspot/share/adlc/formsopt.cpp --- a/src/hotspot/share/adlc/formsopt.cpp Tue Nov 26 10:22:13 2019 +0000 +++ b/src/hotspot/share/adlc/formsopt.cpp Fri Nov 29 10:02:07 2019 +0000 @@ -80,6 +80,15 @@ _regClass.Insert(rc_name,reg_class); } +// Called after parsing the Register block. Record the register class +// for operands which are overwritten after matching. +void RegisterForm::addDynamicRegClass() { + const char *rc_name = "dynamic"; + RegClass* reg_class = new RegClass(rc_name); + reg_class->set_stack_version(false); + _rclasses.addName(rc_name); + _regClass.Insert(rc_name,reg_class); +} // Provide iteration over all register definitions // in the order used by the register allocator diff -r bfc8074ea4ef -r cfe31d2f935c src/hotspot/share/adlc/formsopt.hpp --- a/src/hotspot/share/adlc/formsopt.hpp Tue Nov 26 10:22:13 2019 +0000 +++ b/src/hotspot/share/adlc/formsopt.hpp Fri Nov 29 10:02:07 2019 +0000 @@ -104,6 +104,7 @@ AllocClass *addAllocClass(char *allocName); void addSpillRegClass(); + void addDynamicRegClass(); // Provide iteration over all register definitions // in the order used by the register allocator diff -r bfc8074ea4ef -r cfe31d2f935c src/hotspot/share/adlc/output_c.cpp --- a/src/hotspot/share/adlc/output_c.cpp Tue Nov 26 10:22:13 2019 +0000 +++ b/src/hotspot/share/adlc/output_c.cpp Fri Nov 29 10:02:07 2019 +0000 @@ -2781,6 +2781,8 @@ // Return the sole RegMask. if (strcmp(first_reg_class, "stack_slots") == 0) { fprintf(fp," return &(Compile::current()->FIRST_STACK_mask());\n"); + } else if (strcmp(first_reg_class, "dynamic") == 0) { + fprintf(fp," return &RegMask::Empty;\n"); } else { const char* first_reg_class_to_upper = toUpper(first_reg_class); fprintf(fp," return &%s_mask();\n", first_reg_class_to_upper); diff -r bfc8074ea4ef -r cfe31d2f935c src/hotspot/share/aot/aotCodeHeap.cpp --- a/src/hotspot/share/aot/aotCodeHeap.cpp Tue Nov 26 10:22:13 2019 +0000 +++ b/src/hotspot/share/aot/aotCodeHeap.cpp Fri Nov 29 10:02:07 2019 +0000 @@ -40,6 +40,7 @@ #include "oops/compressedOops.hpp" #include "oops/klass.inline.hpp" #include "oops/method.inline.hpp" +#include "runtime/atomic.hpp" #include "runtime/deoptimization.hpp" #include "runtime/handles.inline.hpp" #include "runtime/os.hpp" diff -r bfc8074ea4ef -r cfe31d2f935c src/hotspot/share/aot/aotCompiledMethod.cpp --- a/src/hotspot/share/aot/aotCompiledMethod.cpp Tue Nov 26 10:22:13 2019 +0000 +++ b/src/hotspot/share/aot/aotCompiledMethod.cpp Fri Nov 29 10:02:07 2019 +0000 @@ -37,6 +37,7 @@ #include "runtime/frame.inline.hpp" #include "runtime/handles.inline.hpp" #include "runtime/java.hpp" +#include "runtime/orderAccess.hpp" #include "runtime/os.hpp" #include "runtime/safepointVerifiers.hpp" #include "runtime/sharedRuntime.hpp" diff -r bfc8074ea4ef -r cfe31d2f935c src/hotspot/share/asm/assembler.cpp --- a/src/hotspot/share/asm/assembler.cpp Tue Nov 26 10:22:13 2019 +0000 +++ b/src/hotspot/share/asm/assembler.cpp Fri Nov 29 10:02:07 2019 +0000 @@ -29,7 +29,6 @@ #include "gc/shared/collectedHeap.hpp" #include "memory/universe.hpp" #include "oops/compressedOops.hpp" -#include "runtime/atomic.hpp" #include "runtime/icache.hpp" #include "runtime/os.hpp" #include "runtime/thread.hpp" diff -r bfc8074ea4ef -r cfe31d2f935c src/hotspot/share/classfile/classLoader.inline.hpp --- a/src/hotspot/share/classfile/classLoader.inline.hpp Tue Nov 26 10:22:13 2019 +0000 +++ b/src/hotspot/share/classfile/classLoader.inline.hpp Fri Nov 29 10:02:07 2019 +0000 @@ -26,7 +26,7 @@ #define SHARE_CLASSFILE_CLASSLOADER_INLINE_HPP #include "classfile/classLoader.hpp" -#include "runtime/orderAccess.hpp" +#include "runtime/atomic.hpp" // Next entry in class path inline ClassPathEntry* ClassPathEntry::next() const { return Atomic::load_acquire(&_next); } diff -r bfc8074ea4ef -r cfe31d2f935c src/hotspot/share/classfile/classLoaderData.cpp --- a/src/hotspot/share/classfile/classLoaderData.cpp Tue Nov 26 10:22:13 2019 +0000 +++ b/src/hotspot/share/classfile/classLoaderData.cpp Fri Nov 29 10:02:07 2019 +0000 @@ -67,7 +67,6 @@ #include "runtime/atomic.hpp" #include "runtime/handles.inline.hpp" #include "runtime/mutex.hpp" -#include "runtime/orderAccess.hpp" #include "runtime/safepoint.hpp" #include "utilities/growableArray.hpp" #include "utilities/macros.hpp" diff -r bfc8074ea4ef -r cfe31d2f935c src/hotspot/share/classfile/classLoaderDataGraph.cpp --- a/src/hotspot/share/classfile/classLoaderDataGraph.cpp Tue Nov 26 10:22:13 2019 +0000 +++ b/src/hotspot/share/classfile/classLoaderDataGraph.cpp Fri Nov 29 10:02:07 2019 +0000 @@ -38,7 +38,6 @@ #include "runtime/atomic.hpp" #include "runtime/handles.inline.hpp" #include "runtime/mutex.hpp" -#include "runtime/orderAccess.hpp" #include "runtime/safepoint.hpp" #include "runtime/safepointVerifiers.hpp" #include "utilities/growableArray.hpp" diff -r bfc8074ea4ef -r cfe31d2f935c src/hotspot/share/classfile/dictionary.cpp --- a/src/hotspot/share/classfile/dictionary.cpp Tue Nov 26 10:22:13 2019 +0000 +++ b/src/hotspot/share/classfile/dictionary.cpp Fri Nov 29 10:02:07 2019 +0000 @@ -33,8 +33,6 @@ #include "memory/metaspaceClosure.hpp" #include "memory/resourceArea.hpp" #include "oops/oop.inline.hpp" -#include "runtime/atomic.hpp" -#include "runtime/orderAccess.hpp" #include "runtime/mutexLocker.hpp" #include "runtime/safepointVerifiers.hpp" #include "utilities/hashtable.inline.hpp" diff -r bfc8074ea4ef -r cfe31d2f935c src/hotspot/share/classfile/systemDictionary.cpp --- a/src/hotspot/share/classfile/systemDictionary.cpp Tue Nov 26 10:22:13 2019 +0000 +++ b/src/hotspot/share/classfile/systemDictionary.cpp Fri Nov 29 10:02:07 2019 +0000 @@ -79,7 +79,6 @@ #include "runtime/java.hpp" #include "runtime/javaCalls.hpp" #include "runtime/mutexLocker.hpp" -#include "runtime/orderAccess.hpp" #include "runtime/sharedRuntime.hpp" #include "runtime/signature.hpp" #include "services/classLoadingService.hpp" diff -r bfc8074ea4ef -r cfe31d2f935c src/hotspot/share/classfile/verifier.cpp --- a/src/hotspot/share/classfile/verifier.cpp Tue Nov 26 10:22:13 2019 +0000 +++ b/src/hotspot/share/classfile/verifier.cpp Fri Nov 29 10:02:07 2019 +0000 @@ -50,7 +50,6 @@ #include "runtime/interfaceSupport.inline.hpp" #include "runtime/javaCalls.hpp" #include "runtime/jniHandles.inline.hpp" -#include "runtime/orderAccess.hpp" #include "runtime/os.hpp" #include "runtime/safepointVerifiers.hpp" #include "runtime/thread.hpp" diff -r bfc8074ea4ef -r cfe31d2f935c src/hotspot/share/code/codeCache.cpp --- a/src/hotspot/share/code/codeCache.cpp Tue Nov 26 10:22:13 2019 +0000 +++ b/src/hotspot/share/code/codeCache.cpp Fri Nov 29 10:02:07 2019 +0000 @@ -47,6 +47,7 @@ #include "oops/oop.inline.hpp" #include "oops/verifyOopClosure.hpp" #include "runtime/arguments.hpp" +#include "runtime/atomic.hpp" #include "runtime/deoptimization.hpp" #include "runtime/handles.inline.hpp" #include "runtime/icache.hpp" diff -r bfc8074ea4ef -r cfe31d2f935c src/hotspot/share/code/compiledMethod.cpp --- a/src/hotspot/share/code/compiledMethod.cpp Tue Nov 26 10:22:13 2019 +0000 +++ b/src/hotspot/share/code/compiledMethod.cpp Fri Nov 29 10:02:07 2019 +0000 @@ -38,6 +38,7 @@ #include "oops/methodData.hpp" #include "oops/method.inline.hpp" #include "prims/methodHandles.hpp" +#include "runtime/atomic.hpp" #include "runtime/deoptimization.hpp" #include "runtime/handles.inline.hpp" #include "runtime/mutexLocker.hpp" diff -r bfc8074ea4ef -r cfe31d2f935c src/hotspot/share/code/compiledMethod.inline.hpp --- a/src/hotspot/share/code/compiledMethod.inline.hpp Tue Nov 26 10:22:13 2019 +0000 +++ b/src/hotspot/share/code/compiledMethod.inline.hpp Fri Nov 29 10:02:07 2019 +0000 @@ -27,8 +27,8 @@ #include "code/compiledMethod.hpp" #include "code/nativeInst.hpp" +#include "runtime/atomic.hpp" #include "runtime/frame.hpp" -#include "runtime/orderAccess.hpp" inline bool CompiledMethod::is_deopt_pc(address pc) { return is_deopt_entry(pc) || is_deopt_mh_entry(pc); } diff -r bfc8074ea4ef -r cfe31d2f935c src/hotspot/share/code/dependencyContext.cpp --- a/src/hotspot/share/code/dependencyContext.cpp Tue Nov 26 10:22:13 2019 +0000 +++ b/src/hotspot/share/code/dependencyContext.cpp Fri Nov 29 10:02:07 2019 +0000 @@ -28,6 +28,7 @@ #include "code/dependencyContext.hpp" #include "memory/resourceArea.hpp" #include "runtime/atomic.hpp" +#include "runtime/orderAccess.hpp" #include "runtime/perfData.hpp" #include "utilities/exceptions.hpp" diff -r bfc8074ea4ef -r cfe31d2f935c src/hotspot/share/compiler/compileBroker.hpp --- a/src/hotspot/share/compiler/compileBroker.hpp Tue Nov 26 10:22:13 2019 +0000 +++ b/src/hotspot/share/compiler/compileBroker.hpp Fri Nov 29 10:02:07 2019 +0000 @@ -29,6 +29,7 @@ #include "compiler/abstractCompiler.hpp" #include "compiler/compileTask.hpp" #include "compiler/compilerDirectives.hpp" +#include "runtime/atomic.hpp" #include "runtime/perfData.hpp" #include "utilities/stack.hpp" #if INCLUDE_JVMCI diff -r bfc8074ea4ef -r cfe31d2f935c src/hotspot/share/compiler/disassembler.cpp --- a/src/hotspot/share/compiler/disassembler.cpp Tue Nov 26 10:22:13 2019 +0000 +++ b/src/hotspot/share/compiler/disassembler.cpp Fri Nov 29 10:02:07 2019 +0000 @@ -414,9 +414,10 @@ _bytes_per_line = Disassembler::pd_instruction_alignment(); _print_file_name = true; - if (_optionsParsed) return; // parse only once - - // parse the global option string: + // parse the global option string + // We need to fill the options buffer for each newly created + // decode_env instance. The hsdis_* library looks for options + // in that buffer. collect_options(Disassembler::pd_cpu_opts()); collect_options(PrintAssemblyOptions); @@ -424,6 +425,8 @@ _print_raw = (strstr(options(), "xml") ? 2 : 1); } + if (_optionsParsed) return; // parse only once + if (strstr(options(), "help")) { _print_help = true; } diff -r bfc8074ea4ef -r cfe31d2f935c src/hotspot/share/gc/epsilon/epsilonHeap.cpp --- a/src/hotspot/share/gc/epsilon/epsilonHeap.cpp Tue Nov 26 10:22:13 2019 +0000 +++ b/src/hotspot/share/gc/epsilon/epsilonHeap.cpp Fri Nov 29 10:02:07 2019 +0000 @@ -31,6 +31,7 @@ #include "memory/allocation.inline.hpp" #include "memory/resourceArea.hpp" #include "memory/universe.hpp" +#include "runtime/atomic.hpp" #include "runtime/globals.hpp" jint EpsilonHeap::initialize() { diff -r bfc8074ea4ef -r cfe31d2f935c src/hotspot/share/gc/g1/g1Analytics.cpp --- a/src/hotspot/share/gc/g1/g1Analytics.cpp Tue Nov 26 10:22:13 2019 +0000 +++ b/src/hotspot/share/gc/g1/g1Analytics.cpp Fri Nov 29 10:02:07 2019 +0000 @@ -45,11 +45,11 @@ }; // all the same -static double young_cards_per_entry_ratio_defaults[] = { +static double young_card_merge_to_scan_ratio_defaults[] = { 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0 }; -static double young_only_cost_per_remset_card_ms_defaults[] = { +static double young_only_cost_per_card_scan_ms_defaults[] = { 0.015, 0.01, 0.01, 0.008, 0.008, 0.0055, 0.0055, 0.005 }; @@ -62,7 +62,6 @@ 5.0, 5.0, 5.0, 5.0, 5.0, 5.0, 5.0, 5.0 }; - static double young_other_cost_per_region_ms_defaults[] = { 0.3, 0.2, 0.2, 0.15, 0.15, 0.12, 0.12, 0.1 }; @@ -81,13 +80,13 @@ _rs_length_diff_seq(new TruncatedSeq(TruncatedSeqLength)), _concurrent_refine_rate_ms_seq(new TruncatedSeq(TruncatedSeqLength)), _logged_cards_rate_ms_seq(new TruncatedSeq(TruncatedSeqLength)), - _cost_per_logged_card_ms_seq(new TruncatedSeq(TruncatedSeqLength)), - _cost_scan_hcc_seq(new TruncatedSeq(TruncatedSeqLength)), - _young_cards_per_entry_ratio_seq(new TruncatedSeq(TruncatedSeqLength)), - _mixed_cards_per_entry_ratio_seq(new TruncatedSeq(TruncatedSeqLength)), - _young_only_cost_per_remset_card_ms_seq(new TruncatedSeq(TruncatedSeqLength)), - _mixed_cost_per_remset_card_ms_seq(new TruncatedSeq(TruncatedSeqLength)), - _cost_per_byte_ms_seq(new TruncatedSeq(TruncatedSeqLength)), + _young_card_merge_to_scan_ratio_seq(new TruncatedSeq(TruncatedSeqLength)), + _mixed_card_merge_to_scan_ratio_seq(new TruncatedSeq(TruncatedSeqLength)), + _young_cost_per_card_scan_ms_seq(new TruncatedSeq(TruncatedSeqLength)), + _mixed_cost_per_card_scan_ms_seq(new TruncatedSeq(TruncatedSeqLength)), + _young_cost_per_card_merge_ms_seq(new TruncatedSeq(TruncatedSeqLength)), + _mixed_cost_per_card_merge_ms_seq(new TruncatedSeq(TruncatedSeqLength)), + _copy_cost_per_byte_ms_seq(new TruncatedSeq(TruncatedSeqLength)), _constant_other_time_ms_seq(new TruncatedSeq(TruncatedSeqLength)), _young_other_cost_per_region_ms_seq(new TruncatedSeq(TruncatedSeqLength)), _non_young_other_cost_per_region_ms_seq(new TruncatedSeq(TruncatedSeqLength)), @@ -109,11 +108,10 @@ _concurrent_refine_rate_ms_seq->add(1/cost_per_logged_card_ms_defaults[0]); // Some applications have very low rates for logging cards. _logged_cards_rate_ms_seq->add(0.0); - _cost_per_logged_card_ms_seq->add(cost_per_logged_card_ms_defaults[index]); - _cost_scan_hcc_seq->add(0.0); - _young_cards_per_entry_ratio_seq->add(young_cards_per_entry_ratio_defaults[index]); - _young_only_cost_per_remset_card_ms_seq->add(young_only_cost_per_remset_card_ms_defaults[index]); - _cost_per_byte_ms_seq->add(cost_per_byte_ms_defaults[index]); + _young_card_merge_to_scan_ratio_seq->add(young_card_merge_to_scan_ratio_defaults[index]); + _young_cost_per_card_scan_ms_seq->add(young_only_cost_per_card_scan_ms_defaults[index]); + + _copy_cost_per_byte_ms_seq->add(cost_per_byte_ms_defaults[index]); _constant_other_time_ms_seq->add(constant_other_time_ms_defaults[index]); _young_other_cost_per_region_ms_seq->add(young_other_cost_per_region_ms_defaults[index]); _non_young_other_cost_per_region_ms_seq->add(non_young_other_cost_per_region_ms_defaults[index]); @@ -123,12 +121,20 @@ _concurrent_mark_cleanup_times_ms->add(0.20); } -double G1Analytics::get_new_prediction(TruncatedSeq const* seq) const { - return _predictor->get_new_prediction(seq); +bool G1Analytics::enough_samples_available(TruncatedSeq const* seq) const { + return seq->num() >= 3; +} + +double G1Analytics::get_new_unit_prediction(TruncatedSeq const* seq) const { + return _predictor->get_new_unit_prediction(seq); } size_t G1Analytics::get_new_size_prediction(TruncatedSeq const* seq) const { - return (size_t)get_new_prediction(seq); + return (size_t)get_new_lower_zero_bound_prediction(seq); +} + +double G1Analytics::get_new_lower_zero_bound_prediction(TruncatedSeq const* seq) const { + return _predictor->get_new_lower_zero_bound_prediction(seq); } int G1Analytics::num_alloc_rate_ms() const { @@ -166,27 +172,27 @@ _logged_cards_rate_ms_seq->add(cards_per_ms); } -void G1Analytics::report_cost_per_logged_card_ms(double cost_per_logged_card_ms) { - _cost_per_logged_card_ms_seq->add(cost_per_logged_card_ms); -} - -void G1Analytics::report_cost_scan_hcc(double cost_scan_hcc) { - _cost_scan_hcc_seq->add(cost_scan_hcc); -} - -void G1Analytics::report_cost_per_remset_card_ms(double cost_per_remset_card_ms, bool for_young_gc) { +void G1Analytics::report_cost_per_card_scan_ms(double cost_per_card_ms, bool for_young_gc) { if (for_young_gc) { - _young_only_cost_per_remset_card_ms_seq->add(cost_per_remset_card_ms); + _young_cost_per_card_scan_ms_seq->add(cost_per_card_ms); } else { - _mixed_cost_per_remset_card_ms_seq->add(cost_per_remset_card_ms); + _mixed_cost_per_card_scan_ms_seq->add(cost_per_card_ms); } } -void G1Analytics::report_cards_per_entry_ratio(double cards_per_entry_ratio, bool for_young_gc) { +void G1Analytics::report_cost_per_card_merge_ms(double cost_per_card_ms, bool for_young_gc) { if (for_young_gc) { - _young_cards_per_entry_ratio_seq->add(cards_per_entry_ratio); + _young_cost_per_card_merge_ms_seq->add(cost_per_card_ms); } else { - _mixed_cards_per_entry_ratio_seq->add(cards_per_entry_ratio); + _mixed_cost_per_card_merge_ms_seq->add(cost_per_card_ms); + } +} + +void G1Analytics::report_card_merge_to_scan_ratio(double merge_to_scan_ratio, bool for_young_gc) { + if (for_young_gc) { + _young_card_merge_to_scan_ratio_seq->add(merge_to_scan_ratio); + } else { + _mixed_card_merge_to_scan_ratio_seq->add(merge_to_scan_ratio); } } @@ -198,7 +204,7 @@ if (mark_or_rebuild_in_progress) { _cost_per_byte_ms_during_cm_seq->add(cost_per_byte_ms); } else { - _cost_per_byte_ms_seq->add(cost_per_byte_ms); + _copy_cost_per_byte_ms_seq->add(cost_per_byte_ms); } } @@ -223,70 +229,50 @@ } double G1Analytics::predict_alloc_rate_ms() const { - return get_new_prediction(_alloc_rate_ms_seq); + return get_new_lower_zero_bound_prediction(_alloc_rate_ms_seq); } double G1Analytics::predict_concurrent_refine_rate_ms() const { - return get_new_prediction(_concurrent_refine_rate_ms_seq); + return get_new_lower_zero_bound_prediction(_concurrent_refine_rate_ms_seq); } double G1Analytics::predict_logged_cards_rate_ms() const { - return get_new_prediction(_logged_cards_rate_ms_seq); -} - -double G1Analytics::predict_cost_per_logged_card_ms() const { - return get_new_prediction(_cost_per_logged_card_ms_seq); -} - -double G1Analytics::predict_scan_hcc_ms() const { - return get_new_prediction(_cost_scan_hcc_seq); + return get_new_lower_zero_bound_prediction(_logged_cards_rate_ms_seq); } -double G1Analytics::predict_rs_update_time_ms(size_t pending_cards) const { - return pending_cards * predict_cost_per_logged_card_ms() + predict_scan_hcc_ms(); +double G1Analytics::predict_young_card_merge_to_scan_ratio() const { + return get_new_unit_prediction(_young_card_merge_to_scan_ratio_seq); } -double G1Analytics::predict_young_cards_per_entry_ratio() const { - return get_new_prediction(_young_cards_per_entry_ratio_seq); -} - -double G1Analytics::predict_mixed_cards_per_entry_ratio() const { - if (_mixed_cards_per_entry_ratio_seq->num() < 2) { - return predict_young_cards_per_entry_ratio(); +size_t G1Analytics::predict_scan_card_num(size_t rs_length, bool for_young_gc) const { + if (for_young_gc || !enough_samples_available(_mixed_card_merge_to_scan_ratio_seq)) { + return (size_t)(rs_length * predict_young_card_merge_to_scan_ratio()); } else { - return get_new_prediction(_mixed_cards_per_entry_ratio_seq); + return (size_t)(rs_length * get_new_unit_prediction(_mixed_card_merge_to_scan_ratio_seq)); } } -size_t G1Analytics::predict_card_num(size_t rs_length, bool for_young_gc) const { - if (for_young_gc) { - return (size_t) (rs_length * predict_young_cards_per_entry_ratio()); +double G1Analytics::predict_card_merge_time_ms(size_t card_num, bool for_young_gc) const { + if (for_young_gc || !enough_samples_available(_mixed_cost_per_card_merge_ms_seq)) { + return card_num * get_new_lower_zero_bound_prediction(_young_cost_per_card_merge_ms_seq); } else { - return (size_t) (rs_length * predict_mixed_cards_per_entry_ratio()); + return card_num * get_new_lower_zero_bound_prediction(_mixed_cost_per_card_merge_ms_seq); } } -double G1Analytics::predict_rs_scan_time_ms(size_t card_num, bool for_young_gc) const { - if (for_young_gc) { - return card_num * get_new_prediction(_young_only_cost_per_remset_card_ms_seq); +double G1Analytics::predict_card_scan_time_ms(size_t card_num, bool for_young_gc) const { + if (for_young_gc || !enough_samples_available(_mixed_cost_per_card_scan_ms_seq)) { + return card_num * get_new_lower_zero_bound_prediction(_young_cost_per_card_scan_ms_seq); } else { - return predict_mixed_rs_scan_time_ms(card_num); - } -} - -double G1Analytics::predict_mixed_rs_scan_time_ms(size_t card_num) const { - if (_mixed_cost_per_remset_card_ms_seq->num() < 3) { - return card_num * get_new_prediction(_young_only_cost_per_remset_card_ms_seq); - } else { - return card_num * get_new_prediction(_mixed_cost_per_remset_card_ms_seq); + return card_num * get_new_lower_zero_bound_prediction(_mixed_cost_per_card_scan_ms_seq); } } double G1Analytics::predict_object_copy_time_ms_during_cm(size_t bytes_to_copy) const { - if (_cost_per_byte_ms_during_cm_seq->num() < 3) { - return (1.1 * bytes_to_copy) * get_new_prediction(_cost_per_byte_ms_seq); + if (!enough_samples_available(_cost_per_byte_ms_during_cm_seq)) { + return (1.1 * bytes_to_copy) * get_new_lower_zero_bound_prediction(_copy_cost_per_byte_ms_seq); } else { - return bytes_to_copy * get_new_prediction(_cost_per_byte_ms_during_cm_seq); + return bytes_to_copy * get_new_lower_zero_bound_prediction(_cost_per_byte_ms_during_cm_seq); } } @@ -294,36 +280,32 @@ if (during_concurrent_mark) { return predict_object_copy_time_ms_during_cm(bytes_to_copy); } else { - return bytes_to_copy * get_new_prediction(_cost_per_byte_ms_seq); + return bytes_to_copy * get_new_lower_zero_bound_prediction(_copy_cost_per_byte_ms_seq); } } -double G1Analytics::predict_cost_per_byte_ms() const { - return get_new_prediction(_cost_per_byte_ms_seq); -} - double G1Analytics::predict_constant_other_time_ms() const { - return get_new_prediction(_constant_other_time_ms_seq); + return get_new_lower_zero_bound_prediction(_constant_other_time_ms_seq); } double G1Analytics::predict_young_other_time_ms(size_t young_num) const { - return young_num * get_new_prediction(_young_other_cost_per_region_ms_seq); + return young_num * get_new_lower_zero_bound_prediction(_young_other_cost_per_region_ms_seq); } double G1Analytics::predict_non_young_other_time_ms(size_t non_young_num) const { - return non_young_num * get_new_prediction(_non_young_other_cost_per_region_ms_seq); + return non_young_num * get_new_lower_zero_bound_prediction(_non_young_other_cost_per_region_ms_seq); } double G1Analytics::predict_remark_time_ms() const { - return get_new_prediction(_concurrent_mark_remark_times_ms); + return get_new_lower_zero_bound_prediction(_concurrent_mark_remark_times_ms); } double G1Analytics::predict_cleanup_time_ms() const { - return get_new_prediction(_concurrent_mark_cleanup_times_ms); + return get_new_lower_zero_bound_prediction(_concurrent_mark_cleanup_times_ms); } size_t G1Analytics::predict_rs_length() const { - return get_new_size_prediction(_rs_length_seq) + get_new_prediction(_rs_length_diff_seq); + return get_new_size_prediction(_rs_length_seq) + get_new_size_prediction(_rs_length_diff_seq); } size_t G1Analytics::predict_pending_cards() const { diff -r bfc8074ea4ef -r cfe31d2f935c src/hotspot/share/gc/g1/g1Analytics.hpp --- a/src/hotspot/share/gc/g1/g1Analytics.hpp Tue Nov 26 10:22:13 2019 +0000 +++ b/src/hotspot/share/gc/g1/g1Analytics.hpp Fri Nov 29 10:02:07 2019 +0000 @@ -48,13 +48,21 @@ TruncatedSeq* _rs_length_diff_seq; TruncatedSeq* _concurrent_refine_rate_ms_seq; TruncatedSeq* _logged_cards_rate_ms_seq; - TruncatedSeq* _cost_per_logged_card_ms_seq; - TruncatedSeq* _cost_scan_hcc_seq; - TruncatedSeq* _young_cards_per_entry_ratio_seq; - TruncatedSeq* _mixed_cards_per_entry_ratio_seq; - TruncatedSeq* _young_only_cost_per_remset_card_ms_seq; - TruncatedSeq* _mixed_cost_per_remset_card_ms_seq; - TruncatedSeq* _cost_per_byte_ms_seq; + // The ratio between the number of merged cards and actually scanned cards, for + // young-only and mixed gcs. + TruncatedSeq* _young_card_merge_to_scan_ratio_seq; + TruncatedSeq* _mixed_card_merge_to_scan_ratio_seq; + + // The cost to scan a card during young-only and mixed gcs in ms. + TruncatedSeq* _young_cost_per_card_scan_ms_seq; + TruncatedSeq* _mixed_cost_per_card_scan_ms_seq; + + // The cost to merge a card during young-only and mixed gcs in ms. + TruncatedSeq* _young_cost_per_card_merge_ms_seq; + TruncatedSeq* _mixed_cost_per_card_merge_ms_seq; + + // The cost to copy a byte in ms. + TruncatedSeq* _copy_cost_per_byte_ms_seq; TruncatedSeq* _constant_other_time_ms_seq; TruncatedSeq* _young_other_cost_per_region_ms_seq; TruncatedSeq* _non_young_other_cost_per_region_ms_seq; @@ -72,8 +80,13 @@ double _recent_avg_pause_time_ratio; double _last_pause_time_ratio; - double get_new_prediction(TruncatedSeq const* seq) const; + // Returns whether the sequence have enough samples to get a "good" prediction. + // The constant used is random but "small". + bool enough_samples_available(TruncatedSeq const* seq) const; + + double get_new_unit_prediction(TruncatedSeq const* seq) const; size_t get_new_size_prediction(TruncatedSeq const* seq) const; + double get_new_lower_zero_bound_prediction(TruncatedSeq const* seq) const; public: G1Analytics(const G1Predictions* predictor); @@ -103,10 +116,9 @@ void report_alloc_rate_ms(double alloc_rate); void report_concurrent_refine_rate_ms(double cards_per_ms); void report_logged_cards_rate_ms(double cards_per_ms); - void report_cost_per_logged_card_ms(double cost_per_logged_card_ms); - void report_cost_scan_hcc(double cost_scan_hcc); - void report_cost_per_remset_card_ms(double cost_per_remset_card_ms, bool for_young_gc); - void report_cards_per_entry_ratio(double cards_per_entry_ratio, bool for_young_gc); + void report_cost_per_card_scan_ms(double cost_per_remset_card_ms, bool for_young_gc); + void report_cost_per_card_merge_ms(double cost_per_card_ms, bool for_young_gc); + void report_card_merge_to_scan_ratio(double cards_per_entry_ratio, bool for_young_gc); void report_rs_length_diff(double rs_length_diff); void report_cost_per_byte_ms(double cost_per_byte_ms, bool mark_or_rebuild_in_progress); void report_young_other_cost_per_region_ms(double other_cost_per_region_ms); @@ -120,21 +132,14 @@ double predict_concurrent_refine_rate_ms() const; double predict_logged_cards_rate_ms() const; - double predict_cost_per_logged_card_ms() const; - - double predict_scan_hcc_ms() const; + double predict_young_card_merge_to_scan_ratio() const; - double predict_rs_update_time_ms(size_t pending_cards) const; - - double predict_young_cards_per_entry_ratio() const; + double predict_mixed_card_merge_to_scan_ratio() const; - double predict_mixed_cards_per_entry_ratio() const; - - size_t predict_card_num(size_t rs_length, bool for_young_gc) const; + size_t predict_scan_card_num(size_t rs_length, bool for_young_gc) const; - double predict_rs_scan_time_ms(size_t card_num, bool for_young_gc) const; - - double predict_mixed_rs_scan_time_ms(size_t card_num) const; + double predict_card_merge_time_ms(size_t card_num, bool for_young_gc) const; + double predict_card_scan_time_ms(size_t card_num, bool for_young_gc) const; double predict_object_copy_time_ms_during_cm(size_t bytes_to_copy) const; @@ -153,8 +158,6 @@ size_t predict_rs_length() const; size_t predict_pending_cards() const; - double predict_cost_per_byte_ms() const; - // Add a new GC of the given duration and end time to the record. void update_recent_gc_times(double end_time_sec, double elapsed_ms); void compute_pause_time_ratio(double interval_ms, double pause_time_ms); diff -r bfc8074ea4ef -r cfe31d2f935c src/hotspot/share/gc/g1/g1BarrierSet.cpp --- a/src/hotspot/share/gc/g1/g1BarrierSet.cpp Tue Nov 26 10:22:13 2019 +0000 +++ b/src/hotspot/share/gc/g1/g1BarrierSet.cpp Fri Nov 29 10:02:07 2019 +0000 @@ -37,6 +37,7 @@ #include "oops/oop.inline.hpp" #include "runtime/interfaceSupport.inline.hpp" #include "runtime/mutexLocker.hpp" +#include "runtime/orderAccess.hpp" #include "runtime/thread.inline.hpp" #include "utilities/macros.hpp" #ifdef COMPILER1 diff -r bfc8074ea4ef -r cfe31d2f935c src/hotspot/share/gc/g1/g1CardTable.cpp --- a/src/hotspot/share/gc/g1/g1CardTable.cpp Tue Nov 26 10:22:13 2019 +0000 +++ b/src/hotspot/share/gc/g1/g1CardTable.cpp Fri Nov 29 10:02:07 2019 +0000 @@ -27,8 +27,6 @@ #include "gc/g1/g1CollectedHeap.inline.hpp" #include "gc/shared/memset_with_concurrent_readers.hpp" #include "logging/log.hpp" -#include "runtime/atomic.hpp" -#include "runtime/orderAccess.hpp" void G1CardTable::g1_mark_as_young(const MemRegion& mr) { CardValue *const first = byte_for(mr.start()); diff -r bfc8074ea4ef -r cfe31d2f935c src/hotspot/share/gc/g1/g1CardTable.hpp --- a/src/hotspot/share/gc/g1/g1CardTable.hpp Tue Nov 26 10:22:13 2019 +0000 +++ b/src/hotspot/share/gc/g1/g1CardTable.hpp Fri Nov 29 10:02:07 2019 +0000 @@ -92,12 +92,16 @@ return pointer_delta(p, _byte_map, sizeof(CardValue)); } - // Mark the given card as Dirty if it is Clean. - inline void mark_clean_as_dirty(size_t card_index); + // Mark the given card as Dirty if it is Clean. Returns the number of dirtied + // cards that were not yet dirty. This result may be inaccurate as it does not + // perform the dirtying atomically. + inline size_t mark_clean_as_dirty(size_t card_index); // Change Clean cards in a (large) area on the card table as Dirty, preserving // already scanned cards. Assumes that most cards in that area are Clean. - inline void mark_region_dirty(size_t start_card_index, size_t num_cards); + // Returns the number of dirtied cards that were not yet dirty. This result may + // be inaccurate as it does not perform the dirtying atomically. + inline size_t mark_region_dirty(size_t start_card_index, size_t num_cards); // Mark the given range of cards as Scanned. All of these cards must be Dirty. inline void mark_as_scanned(size_t start_card_index, size_t num_cards); diff -r bfc8074ea4ef -r cfe31d2f935c src/hotspot/share/gc/g1/g1CardTable.inline.hpp --- a/src/hotspot/share/gc/g1/g1CardTable.inline.hpp Tue Nov 26 10:22:13 2019 +0000 +++ b/src/hotspot/share/gc/g1/g1CardTable.inline.hpp Fri Nov 29 10:02:07 2019 +0000 @@ -33,17 +33,21 @@ return (uint)(card_idx >> (HeapRegion::LogOfHRGrainBytes - card_shift)); } -inline void G1CardTable::mark_clean_as_dirty(size_t card_index) { +inline size_t G1CardTable::mark_clean_as_dirty(size_t card_index) { CardValue value = _byte_map[card_index]; if (value == clean_card_val()) { _byte_map[card_index] = dirty_card_val(); + return 1; } + return 0; } -inline void G1CardTable::mark_region_dirty(size_t start_card_index, size_t num_cards) { +inline size_t G1CardTable::mark_region_dirty(size_t start_card_index, size_t num_cards) { assert(is_aligned(start_card_index, sizeof(size_t)), "Start card index must be aligned."); assert(is_aligned(num_cards, sizeof(size_t)), "Number of cards to change must be evenly divisible."); + size_t result = 0; + size_t const num_chunks = num_cards / sizeof(size_t); size_t* cur_word = (size_t*)&_byte_map[start_card_index]; @@ -52,6 +56,7 @@ size_t value = *cur_word; if (value == WordAllClean) { *cur_word = WordAllDirty; + result += sizeof(value); } else if (value == WordAllDirty) { // do nothing. } else { @@ -61,12 +66,15 @@ CardValue value = *cur; if (value == clean_card_val()) { *cur = dirty_card_val(); + result++; } cur++; } } cur_word++; } + + return result; } inline void G1CardTable::mark_as_scanned(size_t start_card_index, size_t num_cards) { diff -r bfc8074ea4ef -r cfe31d2f935c src/hotspot/share/gc/g1/g1CodeCacheRemSet.cpp --- a/src/hotspot/share/gc/g1/g1CodeCacheRemSet.cpp Tue Nov 26 10:22:13 2019 +0000 +++ b/src/hotspot/share/gc/g1/g1CodeCacheRemSet.cpp Fri Nov 29 10:02:07 2019 +0000 @@ -32,6 +32,7 @@ #include "memory/iterator.hpp" #include "oops/access.inline.hpp" #include "oops/oop.inline.hpp" +#include "runtime/atomic.hpp" #include "utilities/hashtable.inline.hpp" #include "utilities/stack.inline.hpp" diff -r bfc8074ea4ef -r cfe31d2f935c src/hotspot/share/gc/g1/g1CollectedHeap.cpp --- a/src/hotspot/share/gc/g1/g1CollectedHeap.cpp Tue Nov 26 10:22:13 2019 +0000 +++ b/src/hotspot/share/gc/g1/g1CollectedHeap.cpp Fri Nov 29 10:02:07 2019 +0000 @@ -1,4 +1,4 @@ -/* + /* * Copyright (c) 2001, 2019, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -2777,112 +2777,6 @@ G1EagerReclaimHumongousObjects && rem_set->is_empty(); } -class RegisterRegionsWithRegionAttrTableClosure : public HeapRegionClosure { - private: - size_t _total_humongous; - size_t _candidate_humongous; - - bool humongous_region_is_candidate(G1CollectedHeap* g1h, HeapRegion* region) const { - assert(region->is_starts_humongous(), "Must start a humongous object"); - - oop obj = oop(region->bottom()); - - // Dead objects cannot be eager reclaim candidates. Due to class - // unloading it is unsafe to query their classes so we return early. - if (g1h->is_obj_dead(obj, region)) { - return false; - } - - // If we do not have a complete remembered set for the region, then we can - // not be sure that we have all references to it. - if (!region->rem_set()->is_complete()) { - return false; - } - // 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 obj->is_typeArray() && - g1h->is_potential_eager_reclaim_candidate(region); - } - - public: - RegisterRegionsWithRegionAttrTableClosure() - : _total_humongous(0), - _candidate_humongous(0) { - } - - virtual bool do_heap_region(HeapRegion* r) { - G1CollectedHeap* g1h = G1CollectedHeap::heap(); - - if (!r->is_starts_humongous()) { - g1h->register_region_with_region_attr(r); - return false; - } - - 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_region_attr(rindex); - _candidate_humongous++; - // We will later handle the remembered sets of these regions. - } else { - g1h->register_region_with_region_attr(r); - } - _total_humongous++; - - return false; - } - - size_t total_humongous() const { return _total_humongous; } - size_t candidate_humongous() const { return _candidate_humongous; } -}; - -void G1CollectedHeap::register_regions_with_region_attr() { - Ticks start = Ticks::now(); - - RegisterRegionsWithRegionAttrTableClosure cl; - heap_region_iterate(&cl); - - phase_times()->record_register_regions((Ticks::now() - start).seconds() * 1000.0, - cl.total_humongous(), - cl.candidate_humongous()); - _has_humongous_reclaim_candidates = cl.candidate_humongous() > 0; -} - #ifndef PRODUCT void G1CollectedHeap::verify_region_attr_remset_update() { class VerifyRegionAttrRemSet : public HeapRegionClosure { @@ -3699,6 +3593,145 @@ phase_times()->record_or_add_time_secs(G1GCPhaseTimes::MergePSS, 0 /* worker_id */, (Ticks::now() - start).seconds()); } +class G1PrepareEvacuationTask : public AbstractGangTask { + class G1PrepareRegionsClosure : public HeapRegionClosure { + G1CollectedHeap* _g1h; + G1PrepareEvacuationTask* _parent_task; + size_t _worker_humongous_total; + size_t _worker_humongous_candidates; + + bool humongous_region_is_candidate(HeapRegion* region) const { + assert(region->is_starts_humongous(), "Must start a humongous object"); + + oop obj = oop(region->bottom()); + + // Dead objects cannot be eager reclaim candidates. Due to class + // unloading it is unsafe to query their classes so we return early. + if (_g1h->is_obj_dead(obj, region)) { + return false; + } + + // If we do not have a complete remembered set for the region, then we can + // not be sure that we have all references to it. + if (!region->rem_set()->is_complete()) { + return false; + } + // 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 obj->is_typeArray() && + _g1h->is_potential_eager_reclaim_candidate(region); + } + + public: + G1PrepareRegionsClosure(G1CollectedHeap* g1h, G1PrepareEvacuationTask* parent_task) : + _g1h(g1h), + _parent_task(parent_task), + _worker_humongous_total(0), + _worker_humongous_candidates(0) { } + + ~G1PrepareRegionsClosure() { + _parent_task->add_humongous_candidates(_worker_humongous_candidates); + _parent_task->add_humongous_total(_worker_humongous_total); + } + + virtual bool do_heap_region(HeapRegion* hr) { + // First prepare the region for scanning + _g1h->rem_set()->prepare_region_for_scan(hr); + + // Now check if region is a humongous candidate + if (!hr->is_starts_humongous()) { + _g1h->register_region_with_region_attr(hr); + return false; + } + + uint index = hr->hrm_index(); + if (humongous_region_is_candidate(hr)) { + _g1h->set_humongous_reclaim_candidate(index, true); + _g1h->register_humongous_region_with_region_attr(index); + _worker_humongous_candidates++; + // We will later handle the remembered sets of these regions. + } else { + _g1h->set_humongous_reclaim_candidate(index, false); + _g1h->register_region_with_region_attr(hr); + } + _worker_humongous_total++; + + return false; + } + }; + + G1CollectedHeap* _g1h; + HeapRegionClaimer _claimer; + volatile size_t _humongous_total; + volatile size_t _humongous_candidates; +public: + G1PrepareEvacuationTask(G1CollectedHeap* g1h) : + AbstractGangTask("Prepare Evacuation"), + _g1h(g1h), + _claimer(_g1h->workers()->active_workers()), + _humongous_total(0), + _humongous_candidates(0) { } + + ~G1PrepareEvacuationTask() { + _g1h->set_has_humongous_reclaim_candidate(_humongous_candidates > 0); + } + + void work(uint worker_id) { + G1PrepareRegionsClosure cl(_g1h, this); + _g1h->heap_region_par_iterate_from_worker_offset(&cl, &_claimer, worker_id); + } + + void add_humongous_candidates(size_t candidates) { + Atomic::add(&_humongous_candidates, candidates); + } + + void add_humongous_total(size_t total) { + Atomic::add(&_humongous_total, total); + } + + size_t humongous_candidates() { + return _humongous_candidates; + } + + size_t humongous_total() { + return _humongous_total; + } +}; + void G1CollectedHeap::pre_evacuate_collection_set(G1EvacuationInfo& evacuation_info, G1ParScanThreadStateSet* per_thread_states) { _bytes_used_during_gc = 0; @@ -3718,9 +3751,16 @@ phase_times()->record_prepare_heap_roots_time_ms((Ticks::now() - start).seconds() * 1000.0); } - register_regions_with_region_attr(); + { + G1PrepareEvacuationTask g1_prep_task(this); + Tickspan task_time = run_task(&g1_prep_task); + + phase_times()->record_register_regions(task_time.seconds() * 1000.0, + g1_prep_task.humongous_total(), + g1_prep_task.humongous_candidates()); + } + assert(_verifier->check_region_attr_table(), "Inconsistency in the region attributes table."); - _preserved_marks_set.assert_empty(); #if COMPILER2_OR_JVMCI diff -r bfc8074ea4ef -r cfe31d2f935c src/hotspot/share/gc/g1/g1CollectedHeap.hpp --- a/src/hotspot/share/gc/g1/g1CollectedHeap.hpp Tue Nov 26 10:22:13 2019 +0000 +++ b/src/hotspot/share/gc/g1/g1CollectedHeap.hpp Fri Nov 29 10:02:07 2019 +0000 @@ -593,6 +593,7 @@ // 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); + inline void set_has_humongous_reclaim_candidate(bool value); // Remove from the reclaim candidate set. Also remove from the // collection set so that later encounters avoid the slow path. @@ -600,8 +601,7 @@ // Register the given region to be part of the collection set. inline void register_humongous_region_with_region_attr(uint index); - // Update region attributes table with information about all regions. - void register_regions_with_region_attr(); + // 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_young_region_with_region_attr(HeapRegion* r) { diff -r bfc8074ea4ef -r cfe31d2f935c src/hotspot/share/gc/g1/g1CollectedHeap.inline.hpp --- a/src/hotspot/share/gc/g1/g1CollectedHeap.inline.hpp Tue Nov 26 10:22:13 2019 +0000 +++ b/src/hotspot/share/gc/g1/g1CollectedHeap.inline.hpp Fri Nov 29 10:02:07 2019 +0000 @@ -34,7 +34,6 @@ #include "gc/g1/heapRegionRemSet.hpp" #include "gc/g1/heapRegionSet.inline.hpp" #include "gc/shared/taskqueue.inline.hpp" -#include "runtime/orderAccess.hpp" G1GCPhaseTimes* G1CollectedHeap::phase_times() const { return _policy->phase_times(); @@ -181,7 +180,7 @@ void G1CollectedHeap::register_old_region_with_region_attr(HeapRegion* r) { _region_attr.set_in_old(r->hrm_index(), r->rem_set()->is_tracked()); - _rem_set->prepare_for_scan_heap_roots(r->hrm_index()); + _rem_set->exclude_region_from_scan(r->hrm_index()); } void G1CollectedHeap::register_optional_region_with_region_attr(HeapRegion* r) { @@ -299,6 +298,10 @@ return _humongous_reclaim_candidates.is_candidate(region); } +inline void G1CollectedHeap::set_has_humongous_reclaim_candidate(bool value) { + _has_humongous_reclaim_candidates = value; +} + inline void G1CollectedHeap::set_humongous_is_live(oop obj) { uint region = addr_to_region((HeapWord*)obj); // Clear the flag in the humongous_reclaim_candidates table. Also diff -r bfc8074ea4ef -r cfe31d2f935c src/hotspot/share/gc/g1/g1CollectionSet.cpp --- a/src/hotspot/share/gc/g1/g1CollectionSet.cpp Tue Nov 26 10:22:13 2019 +0000 +++ b/src/hotspot/share/gc/g1/g1CollectionSet.cpp Fri Nov 29 10:02:07 2019 +0000 @@ -27,12 +27,14 @@ #include "gc/g1/g1CollectionSet.hpp" #include "gc/g1/g1CollectionSetCandidates.hpp" #include "gc/g1/g1CollectorState.hpp" +#include "gc/g1/g1HotCardCache.hpp" #include "gc/g1/g1ParScanThreadState.hpp" #include "gc/g1/g1Policy.hpp" #include "gc/g1/heapRegion.inline.hpp" #include "gc/g1/heapRegionRemSet.hpp" #include "gc/g1/heapRegionSet.hpp" #include "logging/logStream.hpp" +#include "runtime/orderAccess.hpp" #include "utilities/debug.hpp" #include "utilities/globalDefinitions.hpp" #include "utilities/quickSort.hpp" @@ -276,19 +278,6 @@ assert(hr->is_young(), "invariant"); assert(_inc_build_state == Active, "Precondition"); - size_t collection_set_length = _collection_set_cur_length; - // We use UINT_MAX as "invalid" marker in verification. - assert(collection_set_length < (UINT_MAX - 1), - "Collection set is too large with " SIZE_FORMAT " entries", collection_set_length); - hr->set_young_index_in_cset((uint)collection_set_length + 1); - - _collection_set_regions[collection_set_length] = hr->hrm_index(); - // Concurrent readers must observe the store of the value in the array before an - // update to the length field. - OrderAccess::storestore(); - _collection_set_cur_length++; - assert(_collection_set_cur_length <= _collection_set_max_length, "Collection set larger than maximum allowed."); - // This routine is used when: // * adding survivor regions to the incremental cset at the end of an // evacuation pause or @@ -323,6 +312,19 @@ assert(!hr->in_collection_set(), "invariant"); _g1h->register_young_region_with_region_attr(hr); + + size_t collection_set_length = _collection_set_cur_length; + // We use UINT_MAX as "invalid" marker in verification. + assert(collection_set_length < (UINT_MAX - 1), + "Collection set is too large with " SIZE_FORMAT " entries", collection_set_length); + hr->set_young_index_in_cset((uint)collection_set_length + 1); + + _collection_set_regions[collection_set_length] = hr->hrm_index(); + // Concurrent readers must observe the store of the value in the array before an + // update to the length field. + OrderAccess::storestore(); + _collection_set_cur_length++; + assert(_collection_set_cur_length <= _collection_set_max_length, "Collection set larger than maximum allowed."); } void G1CollectionSet::add_survivor_regions(HeapRegion* hr) { @@ -409,7 +411,7 @@ guarantee(target_pause_time_ms > 0.0, "target_pause_time_ms = %1.6lf should be positive", target_pause_time_ms); - size_t pending_cards = _policy->pending_cards_at_gc_start(); + size_t pending_cards = _policy->pending_cards_at_gc_start() + _g1h->hot_card_cache()->num_entries(); double base_time_ms = _policy->predict_base_elapsed_time_ms(pending_cards); double time_remaining_ms = MAX2(target_pause_time_ms - base_time_ms, 0.0); diff -r bfc8074ea4ef -r cfe31d2f935c src/hotspot/share/gc/g1/g1ConcurrentMark.cpp --- a/src/hotspot/share/gc/g1/g1ConcurrentMark.cpp Tue Nov 26 10:22:13 2019 +0000 +++ b/src/hotspot/share/gc/g1/g1ConcurrentMark.cpp Fri Nov 29 10:02:07 2019 +0000 @@ -62,6 +62,7 @@ #include "runtime/atomic.hpp" #include "runtime/handles.inline.hpp" #include "runtime/java.hpp" +#include "runtime/orderAccess.hpp" #include "runtime/prefetch.inline.hpp" #include "services/memTracker.hpp" #include "utilities/align.hpp" @@ -2587,7 +2588,8 @@ // and do_marking_step() is not being called serially. bool do_stealing = do_termination && !is_serial; - double diff_prediction_ms = _g1h->policy()->predictor().get_new_prediction(&_marking_step_diff_ms); + G1Predictions const& predictor = _g1h->policy()->predictor(); + double diff_prediction_ms = predictor.get_new_lower_zero_bound_prediction(&_marking_step_diff_ms); _time_target_ms = time_target_ms - diff_prediction_ms; // set up the variables that are used in the work-based scheme to diff -r bfc8074ea4ef -r cfe31d2f935c src/hotspot/share/gc/g1/g1DirtyCardQueue.cpp --- a/src/hotspot/share/gc/g1/g1DirtyCardQueue.cpp Tue Nov 26 10:22:13 2019 +0000 +++ b/src/hotspot/share/gc/g1/g1DirtyCardQueue.cpp Fri Nov 29 10:02:07 2019 +0000 @@ -34,9 +34,9 @@ #include "gc/g1/heapRegionRemSet.hpp" #include "gc/shared/suspendibleThreadSet.hpp" #include "gc/shared/workgroup.hpp" -#include "runtime/atomic.hpp" #include "runtime/flags/flagSetting.hpp" #include "runtime/mutexLocker.hpp" +#include "runtime/orderAccess.hpp" #include "runtime/os.hpp" #include "runtime/safepoint.hpp" #include "runtime/thread.inline.hpp" diff -r bfc8074ea4ef -r cfe31d2f935c src/hotspot/share/gc/g1/g1GCPhaseTimes.cpp --- a/src/hotspot/share/gc/g1/g1GCPhaseTimes.cpp Tue Nov 26 10:22:13 2019 +0000 +++ b/src/hotspot/share/gc/g1/g1GCPhaseTimes.cpp Fri Nov 29 10:02:07 2019 +0000 @@ -72,6 +72,8 @@ _gc_par_phases[MergeRS]->link_thread_work_items(_merge_rs_merged_fine, MergeRSMergedFine); _merge_rs_merged_coarse = new WorkerDataArray(max_gc_threads, "Merged Coarse:"); _gc_par_phases[MergeRS]->link_thread_work_items(_merge_rs_merged_coarse, MergeRSMergedCoarse); + _merge_rs_dirty_cards = new WorkerDataArray(max_gc_threads, "Dirty Cards:"); + _gc_par_phases[MergeRS]->link_thread_work_items(_merge_rs_dirty_cards, MergeRSDirtyCards); _gc_par_phases[OptMergeRS] = new WorkerDataArray(max_gc_threads, "Optional Remembered Sets (ms):"); _opt_merge_rs_merged_sparse = new WorkerDataArray(max_gc_threads, "Merged Sparse:"); @@ -80,6 +82,8 @@ _gc_par_phases[OptMergeRS]->link_thread_work_items(_opt_merge_rs_merged_fine, MergeRSMergedFine); _opt_merge_rs_merged_coarse = new WorkerDataArray(max_gc_threads, "Merged Coarse:"); _gc_par_phases[OptMergeRS]->link_thread_work_items(_opt_merge_rs_merged_coarse, MergeRSMergedCoarse); + _opt_merge_rs_dirty_cards = new WorkerDataArray(max_gc_threads, "Dirty Cards:"); + _gc_par_phases[OptMergeRS]->link_thread_work_items(_opt_merge_rs_dirty_cards, MergeRSDirtyCards); _gc_par_phases[MergeLB] = new WorkerDataArray(max_gc_threads, "Log Buffers (ms):"); if (G1HotCardCache::default_use_cache()) { @@ -304,10 +308,16 @@ // return the average time for a phase in milliseconds double G1GCPhaseTimes::average_time_ms(GCParPhases phase) { + if (_gc_par_phases[phase] == NULL) { + return 0.0; + } return _gc_par_phases[phase]->average() * 1000.0; } size_t G1GCPhaseTimes::sum_thread_work_items(GCParPhases phase, uint index) { + if (_gc_par_phases[phase] == NULL) { + return 0; + } assert(_gc_par_phases[phase]->thread_work_items(index) != NULL, "No sub count"); return _gc_par_phases[phase]->thread_work_items(index)->sum(); } diff -r bfc8074ea4ef -r cfe31d2f935c src/hotspot/share/gc/g1/g1GCPhaseTimes.hpp --- a/src/hotspot/share/gc/g1/g1GCPhaseTimes.hpp Tue Nov 26 10:22:13 2019 +0000 +++ b/src/hotspot/share/gc/g1/g1GCPhaseTimes.hpp Fri Nov 29 10:02:07 2019 +0000 @@ -88,7 +88,8 @@ enum GCMergeRSWorkTimes { MergeRSMergedSparse, MergeRSMergedFine, - MergeRSMergedCoarse + MergeRSMergedCoarse, + MergeRSDirtyCards }; enum GCScanHRWorkItems { @@ -124,6 +125,7 @@ WorkerDataArray* _merge_rs_merged_sparse; WorkerDataArray* _merge_rs_merged_fine; WorkerDataArray* _merge_rs_merged_coarse; + WorkerDataArray* _merge_rs_dirty_cards; WorkerDataArray* _merge_hcc_dirty_cards; WorkerDataArray* _merge_hcc_skipped_cards; @@ -138,6 +140,7 @@ WorkerDataArray* _opt_merge_rs_merged_sparse; WorkerDataArray* _opt_merge_rs_merged_fine; WorkerDataArray* _opt_merge_rs_merged_coarse; + WorkerDataArray* _opt_merge_rs_dirty_cards; WorkerDataArray* _opt_scan_hr_scanned_cards; WorkerDataArray* _opt_scan_hr_scanned_blocks; diff -r bfc8074ea4ef -r cfe31d2f935c src/hotspot/share/gc/g1/g1HotCardCache.cpp --- a/src/hotspot/share/gc/g1/g1HotCardCache.cpp Tue Nov 26 10:22:13 2019 +0000 +++ b/src/hotspot/share/gc/g1/g1HotCardCache.cpp Fri Nov 29 10:02:07 2019 +0000 @@ -32,7 +32,7 @@ G1HotCardCache::G1HotCardCache(G1CollectedHeap *g1h): _g1h(g1h), _use_cache(false), _card_counts(g1h), _hot_cache(NULL), _hot_cache_size(0), _hot_cache_par_chunk_size(0), - _hot_cache_idx(0), _hot_cache_par_claimed_idx(0) + _hot_cache_idx(0), _hot_cache_par_claimed_idx(0), _cache_wrapped_around(false) {} void G1HotCardCache::initialize(G1RegionToSpaceMapper* card_counts_storage) { @@ -48,6 +48,8 @@ _hot_cache_par_chunk_size = ClaimChunkSize; _hot_cache_par_claimed_idx = 0; + _cache_wrapped_around = false; + _card_counts.initialize(card_counts_storage); } } @@ -69,6 +71,11 @@ } // Otherwise, the card is hot. size_t index = Atomic::add(&_hot_cache_idx, 1u) - 1; + if (index == _hot_cache_size) { + // Can use relaxed store because all racing threads are writing the same + // value and there aren't any concurrent readers. + Atomic::store(&_cache_wrapped_around, true); + } size_t masked_index = index & (_hot_cache_size - 1); CardValue* current_ptr = _hot_cache[masked_index]; diff -r bfc8074ea4ef -r cfe31d2f935c src/hotspot/share/gc/g1/g1HotCardCache.hpp --- a/src/hotspot/share/gc/g1/g1HotCardCache.hpp Tue Nov 26 10:22:13 2019 +0000 +++ b/src/hotspot/share/gc/g1/g1HotCardCache.hpp Fri Nov 29 10:02:07 2019 +0000 @@ -81,6 +81,11 @@ char _pad_after[DEFAULT_CACHE_LINE_SIZE]; + // Records whether insertion overflowed the hot card cache at least once. This + // avoids the need for a separate atomic counter of how many valid entries are + // in the HCC. + volatile bool _cache_wrapped_around; + // The number of cached cards a thread claims when flushing the cache static const int ClaimChunkSize = 32; @@ -125,13 +130,17 @@ assert(SafepointSynchronize::is_at_safepoint(), "Should be at a safepoint"); assert(Thread::current()->is_VM_thread(), "Current thread should be the VMthread"); if (default_use_cache()) { - reset_hot_cache_internal(); + reset_hot_cache_internal(); } } // Zeros the values in the card counts table for the given region void reset_card_counts(HeapRegion* hr); + // Number of entries in the HCC. + size_t num_entries() const { + return _cache_wrapped_around ? _hot_cache_size : _hot_cache_idx + 1; + } private: void reset_hot_cache_internal() { assert(_hot_cache != NULL, "Logic"); @@ -139,6 +148,7 @@ for (size_t i = 0; i < _hot_cache_size; i++) { _hot_cache[i] = NULL; } + _cache_wrapped_around = false; } }; diff -r bfc8074ea4ef -r cfe31d2f935c src/hotspot/share/gc/g1/g1IHOPControl.cpp --- a/src/hotspot/share/gc/g1/g1IHOPControl.cpp Tue Nov 26 10:22:13 2019 +0000 +++ b/src/hotspot/share/gc/g1/g1IHOPControl.cpp Fri Nov 29 10:02:07 2019 +0000 @@ -113,6 +113,10 @@ ); } +double G1AdaptiveIHOPControl::get_new_prediction(TruncatedSeq const* seq) const { + return _predictor->get_new_lower_zero_bound_prediction(seq); +} + bool G1AdaptiveIHOPControl::have_enough_data_for_prediction() const { return ((size_t)_marking_times_s.num() >= G1AdaptiveIHOPNumInitialSamples) && ((size_t)_allocation_rate_s.num() >= G1AdaptiveIHOPNumInitialSamples); @@ -120,8 +124,8 @@ size_t G1AdaptiveIHOPControl::get_conc_mark_start_threshold() { if (have_enough_data_for_prediction()) { - double pred_marking_time = _predictor->get_new_prediction(&_marking_times_s); - double pred_promotion_rate = _predictor->get_new_prediction(&_allocation_rate_s); + double pred_marking_time = get_new_prediction(&_marking_times_s); + double pred_promotion_rate = get_new_prediction(&_allocation_rate_s); size_t pred_promotion_size = (size_t)(pred_marking_time * pred_promotion_rate); size_t predicted_needed_bytes_during_marking = @@ -168,8 +172,8 @@ actual_target, G1CollectedHeap::heap()->used(), _last_unrestrained_young_size, - _predictor->get_new_prediction(&_allocation_rate_s), - _predictor->get_new_prediction(&_marking_times_s) * 1000.0, + get_new_prediction(&_allocation_rate_s), + get_new_prediction(&_marking_times_s) * 1000.0, have_enough_data_for_prediction() ? "true" : "false"); } @@ -179,7 +183,7 @@ actual_target_threshold(), G1CollectedHeap::heap()->used(), _last_unrestrained_young_size, - _predictor->get_new_prediction(&_allocation_rate_s), - _predictor->get_new_prediction(&_marking_times_s), + get_new_prediction(&_allocation_rate_s), + get_new_prediction(&_marking_times_s), have_enough_data_for_prediction()); } diff -r bfc8074ea4ef -r cfe31d2f935c src/hotspot/share/gc/g1/g1IHOPControl.hpp --- a/src/hotspot/share/gc/g1/g1IHOPControl.hpp Tue Nov 26 10:22:13 2019 +0000 +++ b/src/hotspot/share/gc/g1/g1IHOPControl.hpp Fri Nov 29 10:02:07 2019 +0000 @@ -123,6 +123,9 @@ // as there is no marking or mixed gc that could impact its size too much. size_t _last_unrestrained_young_size; + // Get a new prediction bounded below by zero from the given sequence. + double get_new_prediction(TruncatedSeq const* seq) const; + bool have_enough_data_for_prediction() const; // The "actual" target threshold the algorithm wants to keep during and at the diff -r bfc8074ea4ef -r cfe31d2f935c src/hotspot/share/gc/g1/g1ParallelCleaning.cpp --- a/src/hotspot/share/gc/g1/g1ParallelCleaning.cpp Tue Nov 26 10:22:13 2019 +0000 +++ b/src/hotspot/share/gc/g1/g1ParallelCleaning.cpp Fri Nov 29 10:02:07 2019 +0000 @@ -25,6 +25,7 @@ #include "precompiled.hpp" #include "gc/g1/g1ParallelCleaning.hpp" +#include "runtime/atomic.hpp" #if INCLUDE_JVMCI #include "jvmci/jvmci.hpp" #endif diff -r bfc8074ea4ef -r cfe31d2f935c src/hotspot/share/gc/g1/g1Policy.cpp --- a/src/hotspot/share/gc/g1/g1Policy.cpp Tue Nov 26 10:22:13 2019 +0000 +++ b/src/hotspot/share/gc/g1/g1Policy.cpp Fri Nov 29 10:02:07 2019 +0000 @@ -329,9 +329,8 @@ const double target_pause_time_ms = _mmu_tracker->max_gc_time() * 1000.0; const double survivor_regions_evac_time = predict_survivor_regions_evac_time(); const size_t pending_cards = _analytics->predict_pending_cards(); - const size_t scanned_cards = _analytics->predict_card_num(rs_length, true /* for_young_gc */); const double base_time_ms = - predict_base_elapsed_time_ms(pending_cards, scanned_cards) + + predict_base_elapsed_time_ms(pending_cards, rs_length) + survivor_regions_evac_time; const uint available_free_regions = _free_regions_at_end_of_collection; const uint base_free_regions = @@ -713,67 +712,58 @@ } _short_lived_surv_rate_group->start_adding_regions(); - // Do that for any other surv rate groups - double scan_hcc_time_ms = G1HotCardCache::default_use_cache() ? average_time_ms(G1GCPhaseTimes::MergeHCC) : 0.0; - + double merge_hcc_time_ms = average_time_ms(G1GCPhaseTimes::MergeHCC); if (update_stats) { - double cost_per_logged_card = 0.0; - size_t const pending_logged_cards = p->sum_thread_work_items(G1GCPhaseTimes::MergeLB, G1GCPhaseTimes::MergeLBDirtyCards); - if (pending_logged_cards > 0) { - cost_per_logged_card = logged_cards_processing_time() / pending_logged_cards; - _analytics->report_cost_per_logged_card_ms(cost_per_logged_card); - } - _analytics->report_cost_scan_hcc(scan_hcc_time_ms); + size_t const total_log_buffer_cards = p->sum_thread_work_items(G1GCPhaseTimes::MergeHCC, G1GCPhaseTimes::MergeHCCDirtyCards) + + p->sum_thread_work_items(G1GCPhaseTimes::MergeLB, G1GCPhaseTimes::MergeLBDirtyCards); + // Update prediction for card merge; MergeRSDirtyCards includes the cards from the Eager Reclaim phase. + size_t const total_cards_merged = p->sum_thread_work_items(G1GCPhaseTimes::MergeRS, G1GCPhaseTimes::MergeRSDirtyCards) + + p->sum_thread_work_items(G1GCPhaseTimes::OptMergeRS, G1GCPhaseTimes::MergeRSDirtyCards) + + total_log_buffer_cards; - size_t const total_cards_scanned = p->sum_thread_work_items(G1GCPhaseTimes::ScanHR, G1GCPhaseTimes::ScanHRScannedCards) + - p->sum_thread_work_items(G1GCPhaseTimes::OptScanHR, G1GCPhaseTimes::ScanHRScannedCards); - size_t remset_cards_scanned = 0; - // There might have been duplicate log buffer entries in the queues which could - // increase this value beyond the cards scanned. In this case attribute all cards - // to the log buffers. - if (pending_logged_cards <= total_cards_scanned) { - remset_cards_scanned = total_cards_scanned - pending_logged_cards; + // The threshold for the number of cards in a given sampling which we consider + // large enough so that the impact from setup and other costs is negligible. + size_t const CardsNumSamplingThreshold = 10; + + if (total_cards_merged > CardsNumSamplingThreshold) { + double avg_time_merge_cards = average_time_ms(G1GCPhaseTimes::MergeER) + + average_time_ms(G1GCPhaseTimes::MergeRS) + + average_time_ms(G1GCPhaseTimes::MergeHCC) + + average_time_ms(G1GCPhaseTimes::MergeLB) + + average_time_ms(G1GCPhaseTimes::OptMergeRS); + _analytics->report_cost_per_card_merge_ms(avg_time_merge_cards / total_cards_merged, this_pause_was_young_only); } - double cost_per_remset_card_ms = 0.0; - if (remset_cards_scanned > 10) { - double avg_time_remset_scan = ((average_time_ms(G1GCPhaseTimes::ScanHR) + average_time_ms(G1GCPhaseTimes::OptScanHR)) * - remset_cards_scanned / total_cards_scanned) + - average_time_ms(G1GCPhaseTimes::MergeER) + - average_time_ms(G1GCPhaseTimes::MergeRS) + - average_time_ms(G1GCPhaseTimes::OptMergeRS); + // Update prediction for card scan + size_t const total_cards_scanned = p->sum_thread_work_items(G1GCPhaseTimes::ScanHR, G1GCPhaseTimes::ScanHRScannedCards) + + p->sum_thread_work_items(G1GCPhaseTimes::OptScanHR, G1GCPhaseTimes::ScanHRScannedCards); - cost_per_remset_card_ms = avg_time_remset_scan / remset_cards_scanned; - _analytics->report_cost_per_remset_card_ms(cost_per_remset_card_ms, this_pause_was_young_only); - } + if (total_cards_scanned > CardsNumSamplingThreshold) { + double avg_time_dirty_card_scan = average_time_ms(G1GCPhaseTimes::ScanHR) + + average_time_ms(G1GCPhaseTimes::OptScanHR); - if (_rs_length > 0) { - double cards_per_entry_ratio = - (double) remset_cards_scanned / (double) _rs_length; - _analytics->report_cards_per_entry_ratio(cards_per_entry_ratio, this_pause_was_young_only); + _analytics->report_cost_per_card_scan_ms(avg_time_dirty_card_scan / total_cards_scanned, this_pause_was_young_only); } - // This is defensive. For a while _rs_length could get - // smaller than _recorded_rs_length which was causing - // rs_length_diff to get very large and mess up the RSet length - // predictions. The reason was unsafe concurrent updates to the - // _inc_cset_recorded_rs_length field which the code below guards - // against (see CR 7118202). This bug has now been fixed (see CR - // 7119027). However, I'm still worried that - // _inc_cset_recorded_rs_length might still end up somewhat - // inaccurate. The concurrent refinement thread calculates an - // RSet's length concurrently with other CR threads updating it - // which might cause it to calculate the length incorrectly (if, - // say, it's in mid-coarsening). So I'll leave in the defensive - // conditional below just in case. - size_t rs_length_diff = 0; - size_t recorded_rs_length = _collection_set->recorded_rs_length(); - if (_rs_length > recorded_rs_length) { - rs_length_diff = _rs_length - recorded_rs_length; + // Update prediction for the ratio between cards from the remembered + // sets and actually scanned cards from the remembered sets. + // Cards from the remembered sets are all cards not duplicated by cards from + // the logs. + // Due to duplicates in the log buffers, the number of actually scanned cards + // can be smaller than the cards in the log buffers. + const size_t from_rs_length_cards = (total_cards_scanned > total_log_buffer_cards) ? total_cards_scanned - total_log_buffer_cards : 0; + double merge_to_scan_ratio = 0.0; + if (total_cards_scanned > 0) { + merge_to_scan_ratio = (double) from_rs_length_cards / total_cards_scanned; } - _analytics->report_rs_length_diff((double) rs_length_diff); + _analytics->report_card_merge_to_scan_ratio(merge_to_scan_ratio, this_pause_was_young_only); + const size_t recorded_rs_length = _collection_set->recorded_rs_length(); + const size_t rs_length_diff = _rs_length > recorded_rs_length ? _rs_length - recorded_rs_length : 0; + _analytics->report_rs_length_diff(rs_length_diff); + + // Update prediction for copy cost per byte size_t copied_bytes = p->sum_thread_work_items(G1GCPhaseTimes::MergePSS, G1GCPhaseTimes::MergePSSCopiedBytes); if (copied_bytes > 0) { @@ -842,21 +832,21 @@ // Note that _mmu_tracker->max_gc_time() returns the time in seconds. double scan_logged_cards_time_goal_ms = _mmu_tracker->max_gc_time() * MILLIUNITS * G1RSetUpdatingPauseTimePercent / 100.0; - if (scan_logged_cards_time_goal_ms < scan_hcc_time_ms) { + if (scan_logged_cards_time_goal_ms < merge_hcc_time_ms) { log_debug(gc, ergo, refine)("Adjust concurrent refinement thresholds (scanning the HCC expected to take longer than Update RS time goal)." "Logged Cards Scan time goal: %1.2fms Scan HCC time: %1.2fms", - scan_logged_cards_time_goal_ms, scan_hcc_time_ms); + scan_logged_cards_time_goal_ms, merge_hcc_time_ms); scan_logged_cards_time_goal_ms = 0; } else { - scan_logged_cards_time_goal_ms -= scan_hcc_time_ms; + scan_logged_cards_time_goal_ms -= merge_hcc_time_ms; } _pending_cards_at_prev_gc_end = _g1h->pending_card_num(); double const logged_cards_time = logged_cards_processing_time(); log_debug(gc, ergo, refine)("Concurrent refinement times: Logged Cards Scan time goal: %1.2fms Logged Cards Scan time: %1.2fms HCC time: %1.2fms", - scan_logged_cards_time_goal_ms, logged_cards_time, scan_hcc_time_ms); + scan_logged_cards_time_goal_ms, logged_cards_time, merge_hcc_time_ms); _g1h->concurrent_refine()->adjust(logged_cards_time, phase_times()->sum_thread_work_items(G1GCPhaseTimes::MergeLB, G1GCPhaseTimes::MergeLBDirtyCards), @@ -924,11 +914,7 @@ double G1Policy::predict_yg_surv_rate(int age, SurvRateGroup* surv_rate_group) const { TruncatedSeq* seq = surv_rate_group->get_seq(age); guarantee(seq->num() > 0, "There should be some young gen survivor samples available. Tried to access with age %d", age); - double pred = _predictor.get_new_prediction(seq); - if (pred > 1.0) { - pred = 1.0; - } - return pred; + return _predictor.get_new_unit_prediction(seq); } double G1Policy::accum_yg_surv_rate_pred(int age) const { @@ -936,17 +922,17 @@ } double G1Policy::predict_base_elapsed_time_ms(size_t pending_cards, - size_t scanned_cards) const { + size_t rs_length) const { + size_t effective_scanned_cards = _analytics->predict_scan_card_num(rs_length, collector_state()->in_young_only_phase()); return - _analytics->predict_rs_update_time_ms(pending_cards) + - _analytics->predict_rs_scan_time_ms(scanned_cards, collector_state()->in_young_only_phase()) + + _analytics->predict_card_merge_time_ms(pending_cards + rs_length, collector_state()->in_young_only_phase()) + + _analytics->predict_card_scan_time_ms(effective_scanned_cards, collector_state()->in_young_only_phase()) + _analytics->predict_constant_other_time_ms(); } double G1Policy::predict_base_elapsed_time_ms(size_t pending_cards) const { size_t rs_length = _analytics->predict_rs_length(); - size_t card_num = _analytics->predict_card_num(rs_length, collector_state()->in_young_only_phase()); - return predict_base_elapsed_time_ms(pending_cards, card_num); + return predict_base_elapsed_time_ms(pending_cards, rs_length); } size_t G1Policy::predict_bytes_to_copy(HeapRegion* hr) const { @@ -965,13 +951,13 @@ double G1Policy::predict_region_elapsed_time_ms(HeapRegion* hr, bool for_young_gc) const { size_t rs_length = hr->rem_set()->occupied(); - // Predicting the number of cards is based on which type of GC - // we're predicting for. - size_t card_num = _analytics->predict_card_num(rs_length, for_young_gc); + size_t scan_card_num = _analytics->predict_scan_card_num(rs_length, for_young_gc); + size_t bytes_to_copy = predict_bytes_to_copy(hr); double region_elapsed_time_ms = - _analytics->predict_rs_scan_time_ms(card_num, collector_state()->in_young_only_phase()) + + _analytics->predict_card_merge_time_ms(rs_length, collector_state()->in_young_only_phase()) + + _analytics->predict_card_scan_time_ms(scan_card_num, collector_state()->in_young_only_phase()) + _analytics->predict_object_copy_time_ms(bytes_to_copy, collector_state()->mark_or_rebuild_in_progress()); // The prediction of the "other" time for this region is based diff -r bfc8074ea4ef -r cfe31d2f935c src/hotspot/share/gc/g1/g1Policy.hpp --- a/src/hotspot/share/gc/g1/g1Policy.hpp Tue Nov 26 10:22:13 2019 +0000 +++ b/src/hotspot/share/gc/g1/g1Policy.hpp Fri Nov 29 10:02:07 2019 +0000 @@ -140,9 +140,9 @@ _rs_length = rs_length; } - double predict_base_elapsed_time_ms(size_t pending_cards) const; - double predict_base_elapsed_time_ms(size_t pending_cards, - size_t scanned_cards) const; + double predict_base_elapsed_time_ms(size_t num_pending_cards) const; + double predict_base_elapsed_time_ms(size_t num_pending_cards, + size_t rs_length) const; size_t predict_bytes_to_copy(HeapRegion* hr) const; double predict_region_elapsed_time_ms(HeapRegion* hr, bool for_young_gc) const; diff -r bfc8074ea4ef -r cfe31d2f935c src/hotspot/share/gc/g1/g1Predictions.hpp --- a/src/hotspot/share/gc/g1/g1Predictions.hpp Tue Nov 26 10:22:13 2019 +0000 +++ b/src/hotspot/share/gc/g1/g1Predictions.hpp Fri Nov 29 10:02:07 2019 +0000 @@ -57,6 +57,14 @@ double get_new_prediction(TruncatedSeq const* seq) const { return seq->davg() + _sigma * stddev_estimate(seq); } + + double get_new_unit_prediction(TruncatedSeq const* seq) const { + return clamp(get_new_prediction(seq), 0.0, 1.0); + } + + double get_new_lower_zero_bound_prediction(TruncatedSeq const* seq) const { + return MAX2(get_new_prediction(seq), 0.0); + } }; #endif // SHARE_GC_G1_G1PREDICTIONS_HPP diff -r bfc8074ea4ef -r cfe31d2f935c src/hotspot/share/gc/g1/g1RemSet.cpp --- a/src/hotspot/share/gc/g1/g1RemSet.cpp Tue Nov 26 10:22:13 2019 +0000 +++ b/src/hotspot/share/gc/g1/g1RemSet.cpp Fri Nov 29 10:02:07 2019 +0000 @@ -49,6 +49,7 @@ #include "memory/resourceArea.hpp" #include "oops/access.inline.hpp" #include "oops/oop.inline.hpp" +#include "runtime/atomic.hpp" #include "runtime/os.hpp" #include "utilities/align.hpp" #include "utilities/globalDefinitions.hpp" @@ -196,30 +197,6 @@ } }; - // Creates a snapshot of the current _top values at the start of collection to - // filter out card marks that we do not want to scan. - class G1ResetScanTopClosure : public HeapRegionClosure { - G1RemSetScanState* _scan_state; - - public: - G1ResetScanTopClosure(G1RemSetScanState* scan_state) : _scan_state(scan_state) { } - - virtual bool do_heap_region(HeapRegion* r) { - uint hrm_index = r->hrm_index(); - if (r->in_collection_set()) { - // Young regions had their card table marked as young at their allocation; - // we need to make sure that these marks are cleared at the end of GC, *but* - // they should not be scanned for cards. - // So directly add them to the "all_dirty_regions". - // Same for regions in the (initial) collection set: they may contain cards from - // the log buffers, make sure they are cleaned. - _scan_state->add_all_dirty_region(hrm_index); - } else if (r->is_old_or_humongous_or_archive()) { - _scan_state->set_scan_top(hrm_index, r->top()); - } - return false; - } - }; // For each region, contains the maximum top() value to be used during this garbage // collection. Subsumes common checks like filtering out everything but old and // humongous regions outside the collection set. @@ -328,16 +305,8 @@ } void prepare() { - for (size_t i = 0; i < _max_regions; i++) { - _collection_set_iter_state[i] = false; - clear_scan_top((uint)i); - } - _all_dirty_regions = new G1DirtyRegions(_max_regions); _next_dirty_regions = new G1DirtyRegions(_max_regions); - - G1ResetScanTopClosure cl(this); - G1CollectedHeap::heap()->heap_region_iterate(&cl); } void prepare_for_merge_heap_roots() { @@ -430,6 +399,10 @@ } while (cur != start_pos); } + void reset_region_claim(uint region_idx) { + _collection_set_iter_state[region_idx] = false; + } + // Attempt to claim the given region in the collection set for iteration. Returns true // if this call caused the transition from Unclaimed to Claimed. inline bool claim_collection_set_region(uint region) { @@ -909,6 +882,26 @@ } } +void G1RemSet::prepare_region_for_scan(HeapRegion* region) { + uint hrm_index = region->hrm_index(); + + _scan_state->reset_region_claim(hrm_index); + if (region->in_collection_set()) { + // Young regions had their card table marked as young at their allocation; + // we need to make sure that these marks are cleared at the end of GC, *but* + // they should not be scanned for cards. + // So directly add them to the "all_dirty_regions". + // Same for regions in the (initial) collection set: they may contain cards from + // the log buffers, make sure they are cleaned. + _scan_state->clear_scan_top(hrm_index); + _scan_state->add_all_dirty_region(hrm_index); + } else if (region->is_old_or_humongous_or_archive()) { + _scan_state->set_scan_top(hrm_index, region->top()); + } else { + assert(region->is_free(), "Should only be free region at this point %s", region->get_type_str()); + } +} + void G1RemSet::prepare_for_scan_heap_roots() { G1DirtyCardQueueSet& dcqs = G1BarrierSet::dirty_card_queue_set(); dcqs.concatenate_logs(); @@ -927,6 +920,8 @@ uint _merged_fine; uint _merged_coarse; + size_t _cards_dirty; + // Returns if the region contains cards we need to scan. If so, remember that // region in the current set of dirty regions. bool remember_if_interesting(uint const region_idx) { @@ -942,7 +937,8 @@ _ct(G1CollectedHeap::heap()->card_table()), _merged_sparse(0), _merged_fine(0), - _merged_coarse(0) { } + _merged_coarse(0), + _cards_dirty(0) { } void next_coarse_prt(uint const region_idx) { if (!remember_if_interesting(region_idx)) { @@ -952,7 +948,7 @@ _merged_coarse++; size_t region_base_idx = (size_t)region_idx << HeapRegion::LogCardsPerRegion; - _ct->mark_region_dirty(region_base_idx, HeapRegion::CardsPerRegion); + _cards_dirty += _ct->mark_region_dirty(region_base_idx, HeapRegion::CardsPerRegion); _scan_state->set_chunk_region_dirty(region_base_idx); } @@ -966,7 +962,7 @@ size_t const region_base_idx = (size_t)region_idx << HeapRegion::LogCardsPerRegion; BitMap::idx_t cur = bm->get_next_one_offset(0); while (cur != bm->size()) { - _ct->mark_clean_as_dirty(region_base_idx + cur); + _cards_dirty += _ct->mark_clean_as_dirty(region_base_idx + cur); _scan_state->set_chunk_dirty(region_base_idx + cur); cur = bm->get_next_one_offset(cur + 1); } @@ -982,7 +978,7 @@ size_t const region_base_idx = (size_t)region_idx << HeapRegion::LogCardsPerRegion; for (uint i = 0; i < num_cards; i++) { size_t card_idx = region_base_idx + cards[i]; - _ct->mark_clean_as_dirty(card_idx); + _cards_dirty += _ct->mark_clean_as_dirty(card_idx); _scan_state->set_chunk_dirty(card_idx); } } @@ -1001,6 +997,8 @@ size_t merged_sparse() const { return _merged_sparse; } size_t merged_fine() const { return _merged_fine; } size_t merged_coarse() const { return _merged_coarse; } + + size_t cards_dirty() const { return _cards_dirty; } }; // Visitor for the remembered sets of humongous candidate regions to merge their @@ -1046,6 +1044,8 @@ size_t merged_sparse() const { return _cl.merged_sparse(); } size_t merged_fine() const { return _cl.merged_fine(); } size_t merged_coarse() const { return _cl.merged_coarse(); } + + size_t cards_dirty() const { return _cl.cards_dirty(); } }; // Visitor for the log buffer entries to merge them into the card table. @@ -1147,6 +1147,7 @@ p->record_or_add_thread_work_item(merge_remset_phase, worker_id, cl.merged_sparse(), G1GCPhaseTimes::MergeRSMergedSparse); p->record_or_add_thread_work_item(merge_remset_phase, worker_id, cl.merged_fine(), G1GCPhaseTimes::MergeRSMergedFine); p->record_or_add_thread_work_item(merge_remset_phase, worker_id, cl.merged_coarse(), G1GCPhaseTimes::MergeRSMergedCoarse); + p->record_or_add_thread_work_item(merge_remset_phase, worker_id, cl.cards_dirty(), G1GCPhaseTimes::MergeRSDirtyCards); } // Merge remembered sets of current candidates. @@ -1158,6 +1159,7 @@ p->record_or_add_thread_work_item(merge_remset_phase, worker_id, cl.merged_sparse(), G1GCPhaseTimes::MergeRSMergedSparse); p->record_or_add_thread_work_item(merge_remset_phase, worker_id, cl.merged_fine(), G1GCPhaseTimes::MergeRSMergedFine); p->record_or_add_thread_work_item(merge_remset_phase, worker_id, cl.merged_coarse(), G1GCPhaseTimes::MergeRSMergedCoarse); + p->record_or_add_thread_work_item(merge_remset_phase, worker_id, cl.cards_dirty(), G1GCPhaseTimes::MergeRSDirtyCards); } // Apply closure to log entries in the HCC. @@ -1236,7 +1238,7 @@ } } -void G1RemSet::prepare_for_scan_heap_roots(uint region_idx) { +void G1RemSet::exclude_region_from_scan(uint region_idx) { _scan_state->clear_scan_top(region_idx); } diff -r bfc8074ea4ef -r cfe31d2f935c src/hotspot/share/gc/g1/g1RemSet.hpp --- a/src/hotspot/share/gc/g1/g1RemSet.hpp Tue Nov 26 10:22:13 2019 +0000 +++ b/src/hotspot/share/gc/g1/g1RemSet.hpp Fri Nov 29 10:02:07 2019 +0000 @@ -102,8 +102,11 @@ void prepare_for_scan_heap_roots(); // Cleans the card table from temporary duplicate detection information. void cleanup_after_scan_heap_roots(); - // Prepares the given region for heap root scanning. - void prepare_for_scan_heap_roots(uint region_idx); + // Excludes the given region from heap root scanning. + void exclude_region_from_scan(uint region_idx); + // Creates a snapshot of the current _top values at the start of collection to + // filter out card marks that we do not want to scan. + void prepare_region_for_scan(HeapRegion* region); // Do work for regions in the current increment of the collection set, scanning // non-card based (heap) roots. diff -r bfc8074ea4ef -r cfe31d2f935c src/hotspot/share/gc/g1/g1StringDedup.cpp --- a/src/hotspot/share/gc/g1/g1StringDedup.cpp Tue Nov 26 10:22:13 2019 +0000 +++ b/src/hotspot/share/gc/g1/g1StringDedup.cpp Fri Nov 29 10:02:07 2019 +0000 @@ -34,7 +34,6 @@ #include "gc/shared/stringdedup/stringDedupTable.hpp" #include "gc/shared/stringdedup/stringDedupThread.inline.hpp" #include "oops/oop.inline.hpp" -#include "runtime/atomic.hpp" void G1StringDedup::initialize() { assert(UseG1GC, "String deduplication available with G1"); @@ -88,4 +87,3 @@ G1StringDedupQueue::push(worker_id, java_string); } } - diff -r bfc8074ea4ef -r cfe31d2f935c src/hotspot/share/gc/g1/heapRegion.cpp --- a/src/hotspot/share/gc/g1/heapRegion.cpp Tue Nov 26 10:22:13 2019 +0000 +++ b/src/hotspot/share/gc/g1/heapRegion.cpp Fri Nov 29 10:02:07 2019 +0000 @@ -43,8 +43,6 @@ #include "oops/access.inline.hpp" #include "oops/compressedOops.inline.hpp" #include "oops/oop.inline.hpp" -#include "runtime/atomic.hpp" -#include "runtime/orderAccess.hpp" int HeapRegion::LogOfHRGrainBytes = 0; int HeapRegion::LogOfHRGrainWords = 0; diff -r bfc8074ea4ef -r cfe31d2f935c src/hotspot/share/gc/g1/heapRegionManager.cpp --- a/src/hotspot/share/gc/g1/heapRegionManager.cpp Tue Nov 26 10:22:13 2019 +0000 +++ b/src/hotspot/share/gc/g1/heapRegionManager.cpp Fri Nov 29 10:02:07 2019 +0000 @@ -33,6 +33,8 @@ #include "gc/g1/heterogeneousHeapRegionManager.hpp" #include "logging/logStream.hpp" #include "memory/allocation.hpp" +#include "runtime/atomic.hpp" +#include "runtime/orderAccess.hpp" #include "utilities/bitMap.inline.hpp" class MasterFreeRegionListChecker : public HeapRegionSetChecker { diff -r bfc8074ea4ef -r cfe31d2f935c src/hotspot/share/gc/g1/heapRegionRemSet.hpp --- a/src/hotspot/share/gc/g1/heapRegionRemSet.hpp Tue Nov 26 10:22:13 2019 +0000 +++ b/src/hotspot/share/gc/g1/heapRegionRemSet.hpp Fri Nov 29 10:02:07 2019 +0000 @@ -28,6 +28,7 @@ #include "gc/g1/g1CodeCacheRemSet.hpp" #include "gc/g1/g1FromCardCache.hpp" #include "gc/g1/sparsePRT.hpp" +#include "runtime/atomic.hpp" #include "utilities/bitMap.hpp" // Remembered set for a heap region. Represent a set of "cards" that diff -r bfc8074ea4ef -r cfe31d2f935c src/hotspot/share/gc/g1/heapRegionRemSet.inline.hpp --- a/src/hotspot/share/gc/g1/heapRegionRemSet.inline.hpp Tue Nov 26 10:22:13 2019 +0000 +++ b/src/hotspot/share/gc/g1/heapRegionRemSet.inline.hpp Fri Nov 29 10:02:07 2019 +0000 @@ -28,6 +28,7 @@ #include "gc/g1/heapRegion.inline.hpp" #include "gc/g1/heapRegionRemSet.hpp" #include "gc/g1/sparsePRT.hpp" +#include "runtime/atomic.hpp" #include "utilities/bitMap.inline.hpp" template diff -r bfc8074ea4ef -r cfe31d2f935c src/hotspot/share/gc/g1/sparsePRT.cpp --- a/src/hotspot/share/gc/g1/sparsePRT.cpp Tue Nov 26 10:22:13 2019 +0000 +++ b/src/hotspot/share/gc/g1/sparsePRT.cpp Fri Nov 29 10:02:07 2019 +0000 @@ -30,7 +30,6 @@ #include "gc/shared/cardTableBarrierSet.hpp" #include "gc/shared/space.inline.hpp" #include "memory/allocation.inline.hpp" -#include "runtime/atomic.hpp" #include "runtime/mutexLocker.hpp" // Check that the size of the SparsePRTEntry is evenly divisible by the maximum diff -r bfc8074ea4ef -r cfe31d2f935c src/hotspot/share/gc/g1/survRateGroup.cpp --- a/src/hotspot/share/gc/g1/survRateGroup.cpp Tue Nov 26 10:22:13 2019 +0000 +++ b/src/hotspot/share/gc/g1/survRateGroup.cpp Fri Nov 29 10:02:07 2019 +0000 @@ -116,8 +116,7 @@ double accum = 0.0; double pred = 0.0; for (size_t i = 0; i < _stats_arrays_length; ++i) { - pred = predictor.get_new_prediction(_surv_rate_pred[i]); - if (pred > 1.0) pred = 1.0; + pred = predictor.get_new_unit_prediction(_surv_rate_pred[i]); accum += pred; _accum_surv_rate_pred[i] = accum; } diff -r bfc8074ea4ef -r cfe31d2f935c src/hotspot/share/gc/parallel/psCompactionManager.cpp --- a/src/hotspot/share/gc/parallel/psCompactionManager.cpp Tue Nov 26 10:22:13 2019 +0000 +++ b/src/hotspot/share/gc/parallel/psCompactionManager.cpp Fri Nov 29 10:02:07 2019 +0000 @@ -39,7 +39,6 @@ #include "oops/instanceMirrorKlass.inline.hpp" #include "oops/objArrayKlass.inline.hpp" #include "oops/oop.inline.hpp" -#include "runtime/atomic.hpp" PSOldGen* ParCompactionManager::_old_gen = NULL; ParCompactionManager** ParCompactionManager::_manager_array = NULL; diff -r bfc8074ea4ef -r cfe31d2f935c src/hotspot/share/gc/parallel/psParallelCompact.hpp --- a/src/hotspot/share/gc/parallel/psParallelCompact.hpp Tue Nov 26 10:22:13 2019 +0000 +++ b/src/hotspot/share/gc/parallel/psParallelCompact.hpp Fri Nov 29 10:02:07 2019 +0000 @@ -32,6 +32,8 @@ #include "gc/shared/collectedHeap.hpp" #include "gc/shared/collectorCounters.hpp" #include "oops/oop.hpp" +#include "runtime/atomic.hpp" +#include "runtime/orderAccess.hpp" class ParallelScavengeHeap; class PSAdaptiveSizePolicy; diff -r bfc8074ea4ef -r cfe31d2f935c src/hotspot/share/gc/serial/defNewGeneration.cpp --- a/src/hotspot/share/gc/serial/defNewGeneration.cpp Tue Nov 26 10:22:13 2019 +0000 +++ b/src/hotspot/share/gc/serial/defNewGeneration.cpp Fri Nov 29 10:02:07 2019 +0000 @@ -51,7 +51,6 @@ #include "memory/resourceArea.hpp" #include "oops/instanceRefKlass.hpp" #include "oops/oop.inline.hpp" -#include "runtime/atomic.hpp" #include "runtime/java.hpp" #include "runtime/prefetch.inline.hpp" #include "runtime/thread.inline.hpp" diff -r bfc8074ea4ef -r cfe31d2f935c src/hotspot/share/gc/shared/barrierSetNMethod.cpp --- a/src/hotspot/share/gc/shared/barrierSetNMethod.cpp Tue Nov 26 10:22:13 2019 +0000 +++ b/src/hotspot/share/gc/shared/barrierSetNMethod.cpp Fri Nov 29 10:02:07 2019 +0000 @@ -32,9 +32,7 @@ #include "utilities/debug.hpp" int BarrierSetNMethod::disarmed_value() const { - char* disarmed_addr = reinterpret_cast(Thread::current()); - disarmed_addr += in_bytes(thread_disarmed_offset()); - return *reinterpret_cast(disarmed_addr); + return *disarmed_value_address(); } bool BarrierSetNMethod::supports_entry_barrier(nmethod* nm) { diff -r bfc8074ea4ef -r cfe31d2f935c src/hotspot/share/gc/shared/barrierSetNMethod.hpp --- a/src/hotspot/share/gc/shared/barrierSetNMethod.hpp Tue Nov 26 10:22:13 2019 +0000 +++ b/src/hotspot/share/gc/shared/barrierSetNMethod.hpp Fri Nov 29 10:02:07 2019 +0000 @@ -34,13 +34,14 @@ class BarrierSetNMethod: public CHeapObj { bool supports_entry_barrier(nmethod* nm); void deoptimize(nmethod* nm, address* return_addr_ptr); + int disarmed_value() const; protected: - virtual int disarmed_value() const; virtual bool nmethod_entry_barrier(nmethod* nm) = 0; public: virtual ByteSize thread_disarmed_offset() const = 0; + virtual int* disarmed_value_address() const = 0; static int nmethod_stub_entry_barrier(address* return_address_ptr); bool nmethod_osr_entry_barrier(nmethod* nm); diff -r bfc8074ea4ef -r cfe31d2f935c src/hotspot/share/gc/shared/concurrentGCThread.cpp --- a/src/hotspot/share/gc/shared/concurrentGCThread.cpp Tue Nov 26 10:22:13 2019 +0000 +++ b/src/hotspot/share/gc/shared/concurrentGCThread.cpp Fri Nov 29 10:02:07 2019 +0000 @@ -24,9 +24,9 @@ #include "precompiled.hpp" #include "gc/shared/concurrentGCThread.hpp" +#include "runtime/atomic.hpp" #include "runtime/init.hpp" #include "runtime/mutexLocker.hpp" -#include "runtime/orderAccess.hpp" #include "runtime/os.hpp" ConcurrentGCThread::ConcurrentGCThread() : diff -r bfc8074ea4ef -r cfe31d2f935c src/hotspot/share/gc/shared/gc_globals.hpp --- a/src/hotspot/share/gc/shared/gc_globals.hpp Tue Nov 26 10:22:13 2019 +0000 +++ b/src/hotspot/share/gc/shared/gc_globals.hpp Fri Nov 29 10:02:07 2019 +0000 @@ -166,10 +166,11 @@ "Use the Garbage-First garbage collector") \ \ product(bool, UseParallelGC, false, \ - "Use the Parallel Scavenge garbage collector") \ + "Use the Parallel garbage collector.") \ \ product(bool, UseParallelOldGC, false, \ - "Use the Parallel Old garbage collector") \ + "Use the Parallel or Serial garbage collector when collecting " \ + "the old generation. Deprecated.") \ \ experimental(bool, UseEpsilonGC, false, \ "Use the Epsilon (no-op) garbage collector") \ diff -r bfc8074ea4ef -r cfe31d2f935c src/hotspot/share/gc/shared/parallelCleaning.cpp --- a/src/hotspot/share/gc/shared/parallelCleaning.cpp Tue Nov 26 10:22:13 2019 +0000 +++ b/src/hotspot/share/gc/shared/parallelCleaning.cpp Fri Nov 29 10:02:07 2019 +0000 @@ -30,6 +30,7 @@ #include "logging/log.hpp" #include "memory/resourceArea.hpp" #include "logging/log.hpp" +#include "runtime/atomic.hpp" StringDedupCleaningTask::StringDedupCleaningTask(BoolObjectClosure* is_alive, OopClosure* keep_alive, diff -r bfc8074ea4ef -r cfe31d2f935c src/hotspot/share/gc/shared/preservedMarks.cpp --- a/src/hotspot/share/gc/shared/preservedMarks.cpp Tue Nov 26 10:22:13 2019 +0000 +++ b/src/hotspot/share/gc/shared/preservedMarks.cpp Fri Nov 29 10:02:07 2019 +0000 @@ -28,6 +28,7 @@ #include "memory/allocation.inline.hpp" #include "memory/resourceArea.hpp" #include "oops/oop.inline.hpp" +#include "runtime/atomic.hpp" #include "utilities/macros.hpp" void PreservedMarks::restore() { diff -r bfc8074ea4ef -r cfe31d2f935c src/hotspot/share/gc/shared/ptrQueue.cpp --- a/src/hotspot/share/gc/shared/ptrQueue.cpp Tue Nov 26 10:22:13 2019 +0000 +++ b/src/hotspot/share/gc/shared/ptrQueue.cpp Fri Nov 29 10:02:07 2019 +0000 @@ -30,7 +30,6 @@ #include "runtime/atomic.hpp" #include "runtime/mutex.hpp" #include "runtime/mutexLocker.hpp" -#include "runtime/orderAccess.hpp" #include "runtime/thread.inline.hpp" #include "utilities/globalCounter.inline.hpp" diff -r bfc8074ea4ef -r cfe31d2f935c src/hotspot/share/gc/shared/referenceProcessorPhaseTimes.cpp --- a/src/hotspot/share/gc/shared/referenceProcessorPhaseTimes.cpp Tue Nov 26 10:22:13 2019 +0000 +++ b/src/hotspot/share/gc/shared/referenceProcessorPhaseTimes.cpp Fri Nov 29 10:02:07 2019 +0000 @@ -30,6 +30,7 @@ #include "logging/log.hpp" #include "logging/logStream.hpp" #include "memory/allocation.inline.hpp" +#include "runtime/atomic.hpp" #define ASSERT_REF_TYPE(ref_type) assert((ref_type) >= REF_SOFT && (ref_type) <= REF_PHANTOM, \ "Invariant (%d)", (int)ref_type) diff -r bfc8074ea4ef -r cfe31d2f935c src/hotspot/share/gc/shared/satbMarkQueue.cpp --- a/src/hotspot/share/gc/shared/satbMarkQueue.cpp Tue Nov 26 10:22:13 2019 +0000 +++ b/src/hotspot/share/gc/shared/satbMarkQueue.cpp Fri Nov 29 10:02:07 2019 +0000 @@ -30,7 +30,6 @@ #include "oops/oop.inline.hpp" #include "runtime/atomic.hpp" #include "runtime/mutexLocker.hpp" -#include "runtime/orderAccess.hpp" #include "runtime/os.hpp" #include "runtime/safepoint.hpp" #include "runtime/thread.hpp" diff -r bfc8074ea4ef -r cfe31d2f935c src/hotspot/share/gc/shared/space.cpp --- a/src/hotspot/share/gc/shared/space.cpp Tue Nov 26 10:22:13 2019 +0000 +++ b/src/hotspot/share/gc/shared/space.cpp Fri Nov 29 10:02:07 2019 +0000 @@ -37,7 +37,6 @@ #include "oops/oop.inline.hpp" #include "runtime/atomic.hpp" #include "runtime/java.hpp" -#include "runtime/orderAccess.hpp" #include "runtime/prefetch.inline.hpp" #include "runtime/safepoint.hpp" #include "utilities/align.hpp" diff -r bfc8074ea4ef -r cfe31d2f935c src/hotspot/share/gc/shared/stringdedup/stringDedupTable.cpp --- a/src/hotspot/share/gc/shared/stringdedup/stringDedupTable.cpp Tue Nov 26 10:22:13 2019 +0000 +++ b/src/hotspot/share/gc/shared/stringdedup/stringDedupTable.cpp Fri Nov 29 10:02:07 2019 +0000 @@ -35,6 +35,7 @@ #include "oops/arrayOop.inline.hpp" #include "oops/oop.inline.hpp" #include "oops/typeArrayOop.hpp" +#include "runtime/atomic.hpp" #include "runtime/mutexLocker.hpp" #include "runtime/safepointVerifiers.hpp" diff -r bfc8074ea4ef -r cfe31d2f935c src/hotspot/share/gc/shared/stringdedup/stringDedupThread.cpp --- a/src/hotspot/share/gc/shared/stringdedup/stringDedupThread.cpp Tue Nov 26 10:22:13 2019 +0000 +++ b/src/hotspot/share/gc/shared/stringdedup/stringDedupThread.cpp Fri Nov 29 10:02:07 2019 +0000 @@ -33,7 +33,6 @@ #include "logging/log.hpp" #include "oops/access.inline.hpp" #include "oops/oop.inline.hpp" -#include "runtime/atomic.hpp" StringDedupThread* StringDedupThread::_thread = NULL; diff -r bfc8074ea4ef -r cfe31d2f935c src/hotspot/share/gc/shenandoah/shenandoahArguments.cpp --- a/src/hotspot/share/gc/shenandoah/shenandoahArguments.cpp Tue Nov 26 10:22:13 2019 +0000 +++ b/src/hotspot/share/gc/shenandoah/shenandoahArguments.cpp Fri Nov 29 10:02:07 2019 +0000 @@ -171,11 +171,7 @@ } // If class unloading is disabled, no unloading for concurrent cycles as well. - // If class unloading is enabled, users should opt-in for unloading during - // concurrent cycles. - if (!ClassUnloading || !FLAG_IS_CMDLINE(ClassUnloadingWithConcurrentMark)) { - log_info(gc)("Consider -XX:+ClassUnloadingWithConcurrentMark if large pause times " - "are observed on class-unloading sensitive workloads"); + if (!ClassUnloading) { FLAG_SET_DEFAULT(ClassUnloadingWithConcurrentMark, false); } diff -r bfc8074ea4ef -r cfe31d2f935c src/hotspot/share/gc/shenandoah/shenandoahBarrierSet.cpp --- a/src/hotspot/share/gc/shenandoah/shenandoahBarrierSet.cpp Tue Nov 26 10:22:13 2019 +0000 +++ b/src/hotspot/share/gc/shenandoah/shenandoahBarrierSet.cpp Fri Nov 29 10:02:07 2019 +0000 @@ -26,6 +26,7 @@ #include "gc/shenandoah/shenandoahBarrierSet.hpp" #include "gc/shenandoah/shenandoahBarrierSetClone.inline.hpp" #include "gc/shenandoah/shenandoahBarrierSetAssembler.hpp" +#include "gc/shenandoah/shenandoahBarrierSetNMethod.hpp" #include "gc/shenandoah/shenandoahCollectorPolicy.hpp" #include "gc/shenandoah/shenandoahConcurrentRoots.hpp" #include "gc/shenandoah/shenandoahHeap.inline.hpp" @@ -43,11 +44,19 @@ class ShenandoahBarrierSetC1; class ShenandoahBarrierSetC2; +static BarrierSetNMethod* make_barrier_set_nmethod(ShenandoahHeap* heap) { + // NMethod barriers are only used when concurrent nmethod unloading is enabled + if (!ShenandoahConcurrentRoots::can_do_concurrent_class_unloading()) { + return NULL; + } + return new ShenandoahBarrierSetNMethod(heap); +} + ShenandoahBarrierSet::ShenandoahBarrierSet(ShenandoahHeap* heap) : BarrierSet(make_barrier_set_assembler(), make_barrier_set_c1(), make_barrier_set_c2(), - NULL /* barrier_set_nmethod */, + make_barrier_set_nmethod(heap), BarrierSet::FakeRtti(BarrierSet::ShenandoahBarrierSet)), _heap(heap), _satb_mark_queue_buffer_allocator("SATB Buffer Allocator", ShenandoahSATBBufferSize), @@ -101,36 +110,6 @@ return (on_weak_ref || unknown) && (keep_alive || is_traversal_mode); } -template -inline void ShenandoahBarrierSet::inline_write_ref_field_pre(T* field, oop new_val) { - shenandoah_assert_not_in_cset_loc_except(field, _heap->cancelled_gc()); - if (_heap->is_concurrent_mark_in_progress()) { - T heap_oop = RawAccess<>::oop_load(field); - if (!CompressedOops::is_null(heap_oop)) { - enqueue(CompressedOops::decode(heap_oop)); - } - } -} - -// These are the more general virtual versions. -void ShenandoahBarrierSet::write_ref_field_pre_work(oop* field, oop new_val) { - inline_write_ref_field_pre(field, new_val); -} - -void ShenandoahBarrierSet::write_ref_field_pre_work(narrowOop* field, oop new_val) { - inline_write_ref_field_pre(field, new_val); -} - -void ShenandoahBarrierSet::write_ref_field_pre_work(void* field, oop new_val) { - guarantee(false, "Not needed"); -} - -void ShenandoahBarrierSet::write_ref_field_work(void* v, oop o, bool release) { - shenandoah_assert_not_in_cset_loc_except(v, _heap->cancelled_gc()); - shenandoah_assert_not_forwarded_except (v, o, o == NULL || _heap->cancelled_gc() || !_heap->is_concurrent_mark_in_progress()); - shenandoah_assert_not_in_cset_except (v, o, o == NULL || _heap->cancelled_gc() || !_heap->is_concurrent_mark_in_progress()); -} - oop ShenandoahBarrierSet::load_reference_barrier_not_null(oop obj) { if (ShenandoahLoadRefBarrier && _heap->has_forwarded_objects()) { return load_reference_barrier_impl(obj); @@ -234,30 +213,6 @@ } } -void ShenandoahBarrierSet::storeval_barrier(oop obj) { - if (ShenandoahStoreValEnqueueBarrier && !CompressedOops::is_null(obj) && _heap->is_concurrent_traversal_in_progress()) { - enqueue(obj); - } -} - -void ShenandoahBarrierSet::keep_alive_barrier(oop obj) { - if (ShenandoahKeepAliveBarrier && _heap->is_concurrent_mark_in_progress()) { - enqueue(obj); - } -} - -void ShenandoahBarrierSet::enqueue(oop obj) { - shenandoah_assert_not_forwarded_if(NULL, obj, _heap->is_concurrent_traversal_in_progress()); - assert(_satb_mark_queue_set.is_active(), "only get here when SATB active"); - - // Filter marked objects before hitting the SATB queues. The same predicate would - // be used by SATBMQ::filter to eliminate already marked objects downstream, but - // filtering here helps to avoid wasteful SATB queueing work to begin with. - if (!_heap->requires_marking(obj)) return; - - ShenandoahThreadLocalData::satb_mark_queue(Thread::current()).enqueue_known_active(obj); -} - void ShenandoahBarrierSet::on_thread_create(Thread* thread) { // Create thread local data ShenandoahThreadLocalData::create(thread); diff -r bfc8074ea4ef -r cfe31d2f935c src/hotspot/share/gc/shenandoah/shenandoahBarrierSet.hpp --- a/src/hotspot/share/gc/shenandoah/shenandoahBarrierSet.hpp Tue Nov 26 10:22:13 2019 +0000 +++ b/src/hotspot/share/gc/shenandoah/shenandoahBarrierSet.hpp Fri Nov 29 10:02:07 2019 +0000 @@ -77,17 +77,6 @@ inline void clone_barrier(oop src); void clone_barrier_runtime(oop src); - // We export this to make it available in cases where the static - // type of the barrier set is known. Note that it is non-virtual. - template inline void inline_write_ref_field_pre(T* field, oop new_val); - - // These are the more general virtual versions. - void write_ref_field_pre_work(oop* field, oop new_val); - void write_ref_field_pre_work(narrowOop* field, oop new_val); - void write_ref_field_pre_work(void* field, oop new_val); - - void write_ref_field_work(void* v, oop o, bool release = false); - virtual void on_thread_create(Thread* thread); virtual void on_thread_destroy(Thread* thread); virtual void on_thread_attach(Thread* thread); @@ -96,8 +85,17 @@ static inline oop resolve_forwarded_not_null(oop p); static inline oop resolve_forwarded(oop p); - void storeval_barrier(oop obj); - void keep_alive_barrier(oop obj); + template + inline void satb_barrier(T* field); + inline void satb_enqueue(oop value); + inline void storeval_barrier(oop obj); + + template + inline void keep_alive_if_weak(oop value); + inline void keep_alive_if_weak(DecoratorSet decorators, oop value); + inline void keep_alive_barrier(oop value); + + inline void enqueue(oop obj); oop load_reference_barrier(oop obj); oop load_reference_barrier_not_null(oop obj); @@ -111,8 +109,6 @@ oop load_reference_barrier_native(oop obj, oop* load_addr); oop load_reference_barrier_native(oop obj, narrowOop* load_addr); - void enqueue(oop obj); - private: template inline void arraycopy_pre_work(T* src, T* dst, size_t count); @@ -126,27 +122,12 @@ template oop load_reference_barrier_native_impl(oop obj, T* load_addr); - static void keep_alive_if_weak(DecoratorSet decorators, oop value) { - assert((decorators & ON_UNKNOWN_OOP_REF) == 0, "Reference strength must be known"); - const bool on_strong_oop_ref = (decorators & ON_STRONG_OOP_REF) != 0; - const bool peek = (decorators & AS_NO_KEEPALIVE) != 0; - if (!peek && !on_strong_oop_ref && value != NULL) { - ShenandoahBarrierSet::barrier_set()->keep_alive_barrier(value); - } - } - public: // Callbacks for runtime accesses. template class AccessBarrier: public BarrierSet::AccessBarrier { typedef BarrierSet::AccessBarrier Raw; - template - static oop oop_atomic_cmpxchg_in_heap_impl(T* addr, oop compare_value, oop new_value); - - template - static oop oop_atomic_xchg_in_heap_impl(T* addr, oop new_value); - public: // Heap oop accesses. These accessors get resolved when // IN_HEAP is set (e.g. when using the HeapAccess API), it is diff -r bfc8074ea4ef -r cfe31d2f935c src/hotspot/share/gc/shenandoah/shenandoahBarrierSet.inline.hpp --- a/src/hotspot/share/gc/shenandoah/shenandoahBarrierSet.inline.hpp Tue Nov 26 10:22:13 2019 +0000 +++ b/src/hotspot/share/gc/shenandoah/shenandoahBarrierSet.inline.hpp Fri Nov 29 10:02:07 2019 +0000 @@ -48,41 +48,124 @@ } } +inline void ShenandoahBarrierSet::enqueue(oop obj) { + shenandoah_assert_not_forwarded_if(NULL, obj, _heap->is_concurrent_traversal_in_progress()); + assert(_satb_mark_queue_set.is_active(), "only get here when SATB active"); + + // Filter marked objects before hitting the SATB queues. The same predicate would + // be used by SATBMQ::filter to eliminate already marked objects downstream, but + // filtering here helps to avoid wasteful SATB queueing work to begin with. + if (!_heap->requires_marking(obj)) return; + + ShenandoahThreadLocalData::satb_mark_queue(Thread::current()).enqueue_known_active(obj); +} + +template +inline void ShenandoahBarrierSet::satb_barrier(T *field) { + if (HasDecorator::value || + HasDecorator::value) { + return; + } + if (ShenandoahSATBBarrier && _heap->is_concurrent_mark_in_progress()) { + T heap_oop = RawAccess<>::oop_load(field); + if (!CompressedOops::is_null(heap_oop)) { + enqueue(CompressedOops::decode(heap_oop)); + } + } +} + +inline void ShenandoahBarrierSet::satb_enqueue(oop value) { + assert(value != NULL, "checked before"); + if (ShenandoahSATBBarrier && _heap->is_concurrent_mark_in_progress()) { + enqueue(value); + } +} + +inline void ShenandoahBarrierSet::storeval_barrier(oop obj) { + if (obj != NULL && ShenandoahStoreValEnqueueBarrier && _heap->is_concurrent_traversal_in_progress()) { + enqueue(obj); + } +} + +inline void ShenandoahBarrierSet::keep_alive_barrier(oop value) { + assert(value != NULL, "checked before"); + if (ShenandoahKeepAliveBarrier && _heap->is_concurrent_mark_in_progress()) { + enqueue(value); + } +} + +inline void ShenandoahBarrierSet::keep_alive_if_weak(DecoratorSet decorators, oop value) { + assert((decorators & ON_UNKNOWN_OOP_REF) == 0, "Reference strength must be known"); + const bool on_strong_oop_ref = (decorators & ON_STRONG_OOP_REF) != 0; + const bool peek = (decorators & AS_NO_KEEPALIVE) != 0; + if (!peek && !on_strong_oop_ref) { + keep_alive_barrier(value); + } +} + +template +inline void ShenandoahBarrierSet::keep_alive_if_weak(oop value) { + assert((decorators & ON_UNKNOWN_OOP_REF) == 0, "Reference strength must be known"); + if (!HasDecorator::value && + !HasDecorator::value) { + keep_alive_barrier(value); + } +} + +template +template +inline oop ShenandoahBarrierSet::AccessBarrier::oop_load_not_in_heap(T* addr) { + oop value = Raw::oop_load_not_in_heap(addr); + if (value != NULL) { + ShenandoahBarrierSet *const bs = ShenandoahBarrierSet::barrier_set(); + value = bs->load_reference_barrier_native(value, addr); + bs->keep_alive_if_weak(value); + } + return value; +} + template template inline oop ShenandoahBarrierSet::AccessBarrier::oop_load_in_heap(T* addr) { oop value = Raw::oop_load_in_heap(addr); - value = ShenandoahBarrierSet::barrier_set()->load_reference_barrier(value); - keep_alive_if_weak(decorators, value); + if (value != NULL) { + ShenandoahBarrierSet *const bs = ShenandoahBarrierSet::barrier_set(); + value = bs->load_reference_barrier_not_null(value); + bs->keep_alive_if_weak(value); + } return value; } template inline oop ShenandoahBarrierSet::AccessBarrier::oop_load_in_heap_at(oop base, ptrdiff_t offset) { oop value = Raw::oop_load_in_heap_at(base, offset); - value = ShenandoahBarrierSet::barrier_set()->load_reference_barrier(value); - keep_alive_if_weak(AccessBarrierSupport::resolve_possibly_unknown_oop_ref_strength(base, offset), value); + if (value != NULL) { + ShenandoahBarrierSet *const bs = ShenandoahBarrierSet::barrier_set(); + value = bs->load_reference_barrier_not_null(value); + bs->keep_alive_if_weak(AccessBarrierSupport::resolve_possibly_unknown_oop_ref_strength(base, offset), + value); + } return value; } template template -inline oop ShenandoahBarrierSet::AccessBarrier::oop_load_not_in_heap(T* addr) { - oop value = Raw::oop_load_not_in_heap(addr); - value = ShenandoahBarrierSet::barrier_set()->load_reference_barrier_native(value, addr); - keep_alive_if_weak(decorators, value); - return value; +inline void ShenandoahBarrierSet::AccessBarrier::oop_store_not_in_heap(T* addr, oop value) { + shenandoah_assert_marked_if(NULL, value, !CompressedOops::is_null(value) && ShenandoahHeap::heap()->is_evacuation_in_progress()); + ShenandoahBarrierSet* const bs = ShenandoahBarrierSet::barrier_set(); + bs->storeval_barrier(value); + bs->satb_barrier(addr); + Raw::oop_store(addr, value); } template template inline void ShenandoahBarrierSet::AccessBarrier::oop_store_in_heap(T* addr, oop value) { - ShenandoahBarrierSet::barrier_set()->storeval_barrier(value); - const bool keep_alive = (decorators & AS_NO_KEEPALIVE) == 0; - if (keep_alive) { - ShenandoahBarrierSet::barrier_set()->write_ref_field_pre_work(addr, value); - } - Raw::oop_store_in_heap(addr, value); + shenandoah_assert_not_in_cset_loc_except(addr, ShenandoahHeap::heap()->cancelled_gc()); + shenandoah_assert_not_forwarded_except (addr, value, value == NULL || ShenandoahHeap::heap()->cancelled_gc() || !ShenandoahHeap::heap()->is_concurrent_mark_in_progress()); + shenandoah_assert_not_in_cset_except (addr, value, value == NULL || ShenandoahHeap::heap()->cancelled_gc() || !ShenandoahHeap::heap()->is_concurrent_mark_in_progress()); + + oop_store_not_in_heap(addr, value); } template @@ -92,14 +175,10 @@ template template -inline void ShenandoahBarrierSet::AccessBarrier::oop_store_not_in_heap(T* addr, oop value) { - shenandoah_assert_marked_if(NULL, value, !CompressedOops::is_null(value) && ShenandoahHeap::heap()->is_evacuation_in_progress()); - Raw::oop_store(addr, value); -} +inline oop ShenandoahBarrierSet::AccessBarrier::oop_atomic_cmpxchg_not_in_heap(T* addr, oop compare_value, oop new_value) { + ShenandoahBarrierSet* bs = ShenandoahBarrierSet::barrier_set(); + bs->storeval_barrier(new_value); -template -template -inline oop ShenandoahBarrierSet::AccessBarrier::oop_atomic_cmpxchg_not_in_heap(T* addr, oop compare_value, oop new_value) { oop res; oop expected = compare_value; do { @@ -107,79 +186,53 @@ res = Raw::oop_atomic_cmpxchg(addr, compare_value, new_value); expected = res; } while ((compare_value != expected) && (resolve_forwarded(compare_value) == resolve_forwarded(expected))); + + // Note: We don't need a keep-alive-barrier here. We already enqueue any loaded reference for SATB anyway, + // because it must be the previous value. if (res != NULL) { - return ShenandoahBarrierSet::barrier_set()->load_reference_barrier_not_null(res); - } else { - return res; + res = ShenandoahBarrierSet::barrier_set()->load_reference_barrier_not_null(res); + bs->satb_enqueue(res); } -} - -template -template -inline oop ShenandoahBarrierSet::AccessBarrier::oop_atomic_cmpxchg_in_heap_impl(T* addr, oop compare_value, oop new_value) { - ShenandoahBarrierSet::barrier_set()->storeval_barrier(new_value); - oop result = oop_atomic_cmpxchg_not_in_heap(addr, compare_value, new_value); - const bool keep_alive = (decorators & AS_NO_KEEPALIVE) == 0; - if (keep_alive && ShenandoahSATBBarrier && !CompressedOops::is_null(result) && - (result == compare_value) && - ShenandoahHeap::heap()->is_concurrent_mark_in_progress()) { - ShenandoahBarrierSet::barrier_set()->enqueue(result); - } - return result; + return res; } template template inline oop ShenandoahBarrierSet::AccessBarrier::oop_atomic_cmpxchg_in_heap(T* addr, oop compare_value, oop new_value) { - oop result = oop_atomic_cmpxchg_in_heap_impl(addr, compare_value, new_value); - keep_alive_if_weak(decorators, result); - return result; + return oop_atomic_cmpxchg_not_in_heap(addr, compare_value, new_value); } template inline oop ShenandoahBarrierSet::AccessBarrier::oop_atomic_cmpxchg_in_heap_at(oop base, ptrdiff_t offset, oop compare_value, oop new_value) { - oop result = oop_atomic_cmpxchg_in_heap_impl(AccessInternal::oop_field_addr(base, offset), compare_value, new_value); - keep_alive_if_weak(AccessBarrierSupport::resolve_possibly_unknown_oop_ref_strength(base, offset), result); - return result; + return oop_atomic_cmpxchg_in_heap(AccessInternal::oop_field_addr(base, offset), compare_value, new_value); } template template inline oop ShenandoahBarrierSet::AccessBarrier::oop_atomic_xchg_not_in_heap(T* addr, oop new_value) { + ShenandoahBarrierSet* bs = ShenandoahBarrierSet::barrier_set(); + bs->storeval_barrier(new_value); + oop previous = Raw::oop_atomic_xchg(addr, new_value); - if (previous != NULL) { - return ShenandoahBarrierSet::barrier_set()->load_reference_barrier_not_null(previous); - } else { - return previous; - } -} -template -template -inline oop ShenandoahBarrierSet::AccessBarrier::oop_atomic_xchg_in_heap_impl(T* addr, oop new_value) { - ShenandoahBarrierSet::barrier_set()->storeval_barrier(new_value); - oop result = oop_atomic_xchg_not_in_heap(addr, new_value); - const bool keep_alive = (decorators & AS_NO_KEEPALIVE) == 0; - if (keep_alive && ShenandoahSATBBarrier && !CompressedOops::is_null(result) && - ShenandoahHeap::heap()->is_concurrent_mark_in_progress()) { - ShenandoahBarrierSet::barrier_set()->enqueue(result); + // Note: We don't need a keep-alive-barrier here. We already enqueue any loaded reference for SATB anyway, + // because it must be the previous value. + if (previous != NULL) { + previous = ShenandoahBarrierSet::barrier_set()->load_reference_barrier_not_null(previous); + bs->satb_enqueue(previous); } - return result; + return previous; } template template inline oop ShenandoahBarrierSet::AccessBarrier::oop_atomic_xchg_in_heap(T* addr, oop new_value) { - oop result = oop_atomic_xchg_in_heap_impl(addr, new_value); - keep_alive_if_weak(addr, result); - return result; + return oop_atomic_xchg_not_in_heap(addr, new_value); } template inline oop ShenandoahBarrierSet::AccessBarrier::oop_atomic_xchg_in_heap_at(oop base, ptrdiff_t offset, oop new_value) { - oop result = oop_atomic_xchg_in_heap_impl(AccessInternal::oop_field_addr(base, offset), new_value); - keep_alive_if_weak(AccessBarrierSupport::resolve_possibly_unknown_oop_ref_strength(base, offset), result); - return result; + return oop_atomic_xchg_in_heap(AccessInternal::oop_field_addr(base, offset), new_value); } // Clone barrier support diff -r bfc8074ea4ef -r cfe31d2f935c src/hotspot/share/gc/shenandoah/shenandoahBarrierSetNMethod.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/hotspot/share/gc/shenandoah/shenandoahBarrierSetNMethod.cpp Fri Nov 29 10:02:07 2019 +0000 @@ -0,0 +1,76 @@ +/* + * Copyright (c) 2019, Red Hat, Inc. All rights reserved. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +#include "precompiled.hpp" + +#include "gc/shenandoah/shenandoahBarrierSetNMethod.hpp" +#include "gc/shenandoah/shenandoahClosures.inline.hpp" +#include "gc/shenandoah/shenandoahCodeRoots.hpp" +#include "gc/shenandoah/shenandoahHeap.inline.hpp" +#include "gc/shenandoah/shenandoahLock.hpp" +#include "gc/shenandoah/shenandoahNMethod.inline.hpp" +#include "gc/shenandoah/shenandoahThreadLocalData.hpp" +#include "memory/iterator.hpp" +#include "memory/resourceArea.hpp" + +bool ShenandoahBarrierSetNMethod::nmethod_entry_barrier(nmethod* nm) { + ShenandoahReentrantLock* lock = ShenandoahNMethod::lock_for_nmethod(nm); + assert(lock != NULL, "Must be"); + ShenandoahReentrantLocker locker(lock); + + if (!is_armed(nm)) { + // Some other thread got here first and healed the oops + // and disarmed the nmethod. + return true; + } + + if (nm->is_unloading()) { + // We don't need to take the lock when unlinking nmethods from + // the Method, because it is only concurrently unlinked by + // the entry barrier, which acquires the per nmethod lock. + nm->unlink_from_method(); + + // We can end up calling nmethods that are unloading + // since we clear compiled ICs lazily. Returning false + // will re-resovle the call and update the compiled IC. + return false; + } + + // Heal oops and disarm + ShenandoahEvacOOMScope scope; + ShenandoahNMethod::heal_nmethod(nm); + ShenandoahNMethod::disarm_nmethod(nm); + return true; +} + +int ShenandoahBarrierSetNMethod::disarmed_value() const { + return ShenandoahCodeRoots::disarmed_value(); +} + +ByteSize ShenandoahBarrierSetNMethod::thread_disarmed_offset() const { + return ShenandoahThreadLocalData::disarmed_value_offset(); +} + +int* ShenandoahBarrierSetNMethod::disarmed_value_address() const { + return ShenandoahCodeRoots::disarmed_value_address(); +} diff -r bfc8074ea4ef -r cfe31d2f935c src/hotspot/share/gc/shenandoah/shenandoahBarrierSetNMethod.hpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/hotspot/share/gc/shenandoah/shenandoahBarrierSetNMethod.hpp Fri Nov 29 10:02:07 2019 +0000 @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2019, Red Hat, Inc. All rights reserved. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +#ifndef SHARE_GC_SHENANDOAH_SHENANDOAHBARRIERSETNMETHOD_HPP +#define SHARE_GC_SHENANDOAH_SHENANDOAHBARRIERSETNMETHOD_HPP + +#include "gc/shared/barrierSetNMethod.hpp" +#include "memory/allocation.hpp" + +class nmethod; +class ShenandoahHeap; + +class ShenandoahBarrierSetNMethod : public BarrierSetNMethod { +private: + ShenandoahHeap* _heap; + +protected: + virtual int disarmed_value() const; + virtual bool nmethod_entry_barrier(nmethod* nm); + +public: + ShenandoahBarrierSetNMethod(ShenandoahHeap* heap) : _heap(heap) { + } + + virtual ByteSize thread_disarmed_offset() const; + virtual int* disarmed_value_address() const; +}; + +#endif // SHARE_GC_SHENANDOAH_SHENANDOAHBARRIERSETNMETHOD_HPP diff -r bfc8074ea4ef -r cfe31d2f935c src/hotspot/share/gc/shenandoah/shenandoahClosures.hpp --- a/src/hotspot/share/gc/shenandoah/shenandoahClosures.hpp Tue Nov 26 10:22:13 2019 +0000 +++ b/src/hotspot/share/gc/shenandoah/shenandoahClosures.hpp Fri Nov 29 10:02:07 2019 +0000 @@ -104,6 +104,15 @@ inline void do_oop(narrowOop* p); }; +class ShenandoahCodeBlobAndDisarmClosure: public CodeBlobToOopClosure { +private: + BarrierSetNMethod* const _bs; + +public: + inline ShenandoahCodeBlobAndDisarmClosure(OopClosure* cl); + inline void do_code_blob(CodeBlob* cb); +}; + #ifdef ASSERT class ShenandoahAssertNotForwardedClosure : public OopClosure { private: diff -r bfc8074ea4ef -r cfe31d2f935c src/hotspot/share/gc/shenandoah/shenandoahClosures.inline.hpp --- a/src/hotspot/share/gc/shenandoah/shenandoahClosures.inline.hpp Tue Nov 26 10:22:13 2019 +0000 +++ b/src/hotspot/share/gc/shenandoah/shenandoahClosures.inline.hpp Fri Nov 29 10:02:07 2019 +0000 @@ -23,11 +23,14 @@ #ifndef SHARE_GC_SHENANDOAH_SHENANDOAHCLOSURES_INLINE_HPP #define SHARE_GC_SHENANDOAH_SHENANDOAHCLOSURES_INLINE_HPP +#include "gc/shared/barrierSetNMethod.hpp" #include "gc/shenandoah/shenandoahAsserts.hpp" #include "gc/shenandoah/shenandoahClosures.hpp" #include "gc/shenandoah/shenandoahHeap.inline.hpp" +#include "gc/shenandoah/shenandoahNMethod.inline.hpp" #include "gc/shenandoah/shenandoahTraversalGC.hpp" #include "oops/compressedOops.inline.hpp" +#include "runtime/atomic.hpp" #include "runtime/thread.hpp" ShenandoahForwardedIsAliveClosure::ShenandoahForwardedIsAliveClosure() : @@ -156,6 +159,20 @@ ShouldNotReachHere(); } +ShenandoahCodeBlobAndDisarmClosure::ShenandoahCodeBlobAndDisarmClosure(OopClosure* cl) : + CodeBlobToOopClosure(cl, true /* fix_relocations */), + _bs(BarrierSet::barrier_set()->barrier_set_nmethod()) { +} + +void ShenandoahCodeBlobAndDisarmClosure::do_code_blob(CodeBlob* cb) { + nmethod* const nm = cb->as_nmethod_or_null(); + if (nm != NULL && nm->oops_do_try_claim()) { + assert(!ShenandoahNMethod::gc_data(nm)->is_unregistered(), "Should not be here"); + CodeBlobToOopClosure::do_code_blob(cb); + _bs->disarm(nm); + } +} + #ifdef ASSERT template void ShenandoahAssertNotForwardedClosure::do_oop_work(T* p) { diff -r bfc8074ea4ef -r cfe31d2f935c src/hotspot/share/gc/shenandoah/shenandoahCodeRoots.cpp --- a/src/hotspot/share/gc/shenandoah/shenandoahCodeRoots.cpp Tue Nov 26 10:22:13 2019 +0000 +++ b/src/hotspot/share/gc/shenandoah/shenandoahCodeRoots.cpp Fri Nov 29 10:02:07 2019 +0000 @@ -23,12 +23,15 @@ #include "precompiled.hpp" #include "code/codeCache.hpp" +#include "code/icBuffer.hpp" #include "code/nmethod.hpp" +#include "gc/shenandoah/shenandoahCodeRoots.hpp" #include "gc/shenandoah/shenandoahHeap.inline.hpp" -#include "gc/shenandoah/shenandoahCodeRoots.hpp" +#include "gc/shenandoah/shenandoahNMethod.inline.hpp" #include "gc/shenandoah/shenandoahUtils.hpp" #include "memory/resourceArea.hpp" #include "memory/universe.hpp" +#include "runtime/atomic.hpp" ShenandoahParallelCodeCacheIterator::ShenandoahParallelCodeCacheIterator(const GrowableArray* heaps) { _length = heaps->length(); @@ -97,69 +100,45 @@ _finished = true; } -class ShenandoahNMethodOopDetector : public OopClosure { -private: - ResourceMark rm; // For growable array allocation below. - GrowableArray _oops; - -public: - ShenandoahNMethodOopDetector() : _oops(10) {}; - - void do_oop(oop* o) { - _oops.append(o); - } - void do_oop(narrowOop* o) { - fatal("NMethods should not have compressed oops embedded."); - } - - GrowableArray* oops() { - return &_oops; - } - - bool has_oops() { - return !_oops.is_empty(); - } -}; - -GrowableArray* ShenandoahCodeRoots::_recorded_nms; -ShenandoahLock ShenandoahCodeRoots::_recorded_nms_lock; +ShenandoahNMethodTable* ShenandoahCodeRoots::_nmethod_table; +int ShenandoahCodeRoots::_disarmed_value = 1; void ShenandoahCodeRoots::initialize() { - _recorded_nms = new (ResourceObj::C_HEAP, mtGC) GrowableArray(100, true, mtGC); + _nmethod_table = new ShenandoahNMethodTable(); } -void ShenandoahCodeRoots::add_nmethod(nmethod* nm) { +void ShenandoahCodeRoots::register_nmethod(nmethod* nm) { switch (ShenandoahCodeRootsStyle) { case 0: case 1: break; case 2: { assert_locked_or_safepoint(CodeCache_lock); - ShenandoahLocker locker(CodeCache_lock->owned_by_self() ? NULL : &_recorded_nms_lock); - - ShenandoahNMethodOopDetector detector; - nm->oops_do(&detector); - - if (detector.has_oops()) { - ShenandoahNMethod* nmr = new ShenandoahNMethod(nm, detector.oops()); - nmr->assert_alive_and_correct(); - int idx = _recorded_nms->find(nm, ShenandoahNMethod::find_with_nmethod); - if (idx != -1) { - ShenandoahNMethod* old = _recorded_nms->at(idx); - _recorded_nms->at_put(idx, nmr); - delete old; - } else { - _recorded_nms->append(nmr); - } - } + _nmethod_table->register_nmethod(nm); break; } default: ShouldNotReachHere(); } -}; +} -void ShenandoahCodeRoots::remove_nmethod(nmethod* nm) { +void ShenandoahCodeRoots::unregister_nmethod(nmethod* nm) { + switch (ShenandoahCodeRootsStyle) { + case 0: + case 1: { + break; + } + case 2: { + assert_locked_or_safepoint(CodeCache_lock); + _nmethod_table->unregister_nmethod(nm); + break; + } + default: + ShouldNotReachHere(); + } +} + +void ShenandoahCodeRoots::flush_nmethod(nmethod* nm) { switch (ShenandoahCodeRootsStyle) { case 0: case 1: { @@ -167,19 +146,7 @@ } case 2: { assert_locked_or_safepoint(CodeCache_lock); - ShenandoahLocker locker(CodeCache_lock->owned_by_self() ? NULL : &_recorded_nms_lock); - - ShenandoahNMethodOopDetector detector; - nm->oops_do(&detector, /* allow_dead = */ true); - - if (detector.has_oops()) { - int idx = _recorded_nms->find(nm, ShenandoahNMethod::find_with_nmethod); - assert(idx != -1, "nmethod " PTR_FORMAT " should be registered", p2i(nm)); - ShenandoahNMethod* old = _recorded_nms->at(idx); - old->assert_same_oops(detector.oops()); - _recorded_nms->delete_at(idx); - delete old; - } + _nmethod_table->flush_nmethod(nm); break; } default: @@ -187,10 +154,186 @@ } } +void ShenandoahCodeRoots::prepare_concurrent_unloading() { + assert(SafepointSynchronize::is_at_safepoint(), "Must be at a safepoint"); + _disarmed_value ++; + // 0 is reserved for new nmethod + if (_disarmed_value == 0) { + _disarmed_value = 1; + } + + JavaThreadIteratorWithHandle jtiwh; + for (JavaThread *thr = jtiwh.next(); thr != NULL; thr = jtiwh.next()) { + ShenandoahThreadLocalData::set_disarmed_value(thr, _disarmed_value); + } +} + +class ShenandoahNMethodUnlinkClosure : public NMethodClosure { +private: + bool _unloading_occurred; + volatile bool _failed; + ShenandoahHeap* _heap; + + void set_failed() { + Atomic::store(&_failed, true); + } + + void unlink(nmethod* nm) { + // Unlinking of the dependencies must happen before the + // handshake separating unlink and purge. + nm->flush_dependencies(false /* delete_immediately */); + + // unlink_from_method will take the CompiledMethod_lock. + // In this case we don't strictly need it when unlinking nmethods from + // the Method, because it is only concurrently unlinked by + // the entry barrier, which acquires the per nmethod lock. + nm->unlink_from_method(); + + if (nm->is_osr_method()) { + // Invalidate the osr nmethod only once + nm->invalidate_osr_method(); + } + } +public: + ShenandoahNMethodUnlinkClosure(bool unloading_occurred) : + _unloading_occurred(unloading_occurred), + _failed(false), + _heap(ShenandoahHeap::heap()) {} + + virtual void do_nmethod(nmethod* nm) { + if (failed()) { + return; + } + + ShenandoahNMethod* nm_data = ShenandoahNMethod::gc_data(nm); + assert(!nm_data->is_unregistered(), "Should not see unregistered entry"); + + if (!nm->is_alive()) { + return; + } + + if (nm->is_unloading()) { + ShenandoahReentrantLocker locker(nm_data->lock()); + unlink(nm); + return; + } + + ShenandoahReentrantLocker locker(nm_data->lock()); + + // Heal oops and disarm + ShenandoahEvacOOMScope scope; + ShenandoahNMethod::heal_nmethod(nm); + ShenandoahNMethod::disarm_nmethod(nm); + + // Clear compiled ICs and exception caches + if (!nm->unload_nmethod_caches(_unloading_occurred)) { + set_failed(); + } + } + + bool failed() const { + return Atomic::load(&_failed); + } +}; + +class ShenandoahUnlinkTask : public AbstractGangTask { +private: + ShenandoahNMethodUnlinkClosure _cl; + ICRefillVerifier* _verifier; + ShenandoahConcurrentNMethodIterator _iterator; + +public: + ShenandoahUnlinkTask(bool unloading_occurred, ICRefillVerifier* verifier) : + AbstractGangTask("ShenandoahNMethodUnlinkTask"), + _cl(unloading_occurred), + _verifier(verifier), + _iterator(ShenandoahCodeRoots::table()) { + MutexLocker mu(CodeCache_lock, Mutex::_no_safepoint_check_flag); + _iterator.nmethods_do_begin(); + } + + ~ShenandoahUnlinkTask() { + MutexLocker mu(CodeCache_lock, Mutex::_no_safepoint_check_flag); + _iterator.nmethods_do_end(); + } + + virtual void work(uint worker_id) { + ICRefillVerifierMark mark(_verifier); + _iterator.nmethods_do(&_cl); + } + + bool success() const { + return !_cl.failed(); + } +}; + +void ShenandoahCodeRoots::unlink(WorkGang* workers, bool unloading_occurred) { + assert(ShenandoahConcurrentRoots::should_do_concurrent_class_unloading(), + "Only when running concurrent class unloading"); + + for (;;) { + ICRefillVerifier verifier; + + { + ShenandoahUnlinkTask task(unloading_occurred, &verifier); + workers->run_task(&task); + if (task.success()) { + return; + } + } + + // Cleaning failed because we ran out of transitional IC stubs, + // so we have to refill and try again. Refilling requires taking + // a safepoint, so we temporarily leave the suspendible thread set. + SuspendibleThreadSetLeaver sts; + InlineCacheBuffer::refill_ic_stubs(); + } +} + +class ShenandoahNMethodPurgeClosure : public NMethodClosure { +public: + virtual void do_nmethod(nmethod* nm) { + if (nm->is_alive() && nm->is_unloading()) { + nm->make_unloaded(); + } + } +}; + +class ShenandoahNMethodPurgeTask : public AbstractGangTask { +private: + ShenandoahNMethodPurgeClosure _cl; + ShenandoahConcurrentNMethodIterator _iterator; + +public: + ShenandoahNMethodPurgeTask() : + AbstractGangTask("ShenandoahNMethodPurgeTask"), + _cl(), + _iterator(ShenandoahCodeRoots::table()) { + MutexLocker mu(CodeCache_lock, Mutex::_no_safepoint_check_flag); + _iterator.nmethods_do_begin(); + } + + ~ShenandoahNMethodPurgeTask() { + MutexLocker mu(CodeCache_lock, Mutex::_no_safepoint_check_flag); + _iterator.nmethods_do_end(); + } + + virtual void work(uint worker_id) { + _iterator.nmethods_do(&_cl); + } +}; + +void ShenandoahCodeRoots::purge(WorkGang* workers) { + assert(ShenandoahConcurrentRoots::should_do_concurrent_class_unloading(), + "Only when running concurrent class unloading"); + + ShenandoahNMethodPurgeTask task; + workers->run_task(&task); +} + ShenandoahCodeRootsIterator::ShenandoahCodeRootsIterator() : - _heap(ShenandoahHeap::heap()), _par_iterator(CodeCache::heaps()), - _claimed(0) { + _table_snapshot(NULL) { assert(SafepointSynchronize::is_at_safepoint(), "Must be at safepoint"); assert(!Thread::current()->is_Worker_thread(), "Should not be acquired by workers"); switch (ShenandoahCodeRootsStyle) { @@ -201,6 +344,7 @@ } case 2: { CodeCache_lock->lock_without_safepoint_check(); + _table_snapshot = ShenandoahCodeRoots::table()->snapshot_for_iteration(); break; } default: @@ -216,6 +360,8 @@ break; } case 2: { + ShenandoahCodeRoots::table()->finish_iteration(_table_snapshot); + _table_snapshot = NULL; CodeCache_lock->unlock(); break; } @@ -257,77 +403,7 @@ template void ShenandoahCodeRootsIterator::fast_parallel_blobs_do(CodeBlobClosure *f) { assert(SafepointSynchronize::is_at_safepoint(), "Must be at safepoint"); - - size_t stride = 256; // educated guess - - GrowableArray* list = ShenandoahCodeRoots::_recorded_nms; - - size_t max = (size_t)list->length(); - while (_claimed < max) { - size_t cur = Atomic::add(&_claimed, stride) - stride; - size_t start = cur; - size_t end = MIN2(cur + stride, max); - if (start >= max) break; - - for (size_t idx = start; idx < end; idx++) { - ShenandoahNMethod* nmr = list->at((int) idx); - nmr->assert_alive_and_correct(); - - if (CSET_FILTER && !nmr->has_cset_oops(_heap)) { - continue; - } - - f->do_code_blob(nmr->nm()); - } - } -} - -ShenandoahNMethod::ShenandoahNMethod(nmethod* nm, GrowableArray* oops) { - _nm = nm; - _oops = NEW_C_HEAP_ARRAY(oop*, oops->length(), mtGC); - _oops_count = oops->length(); - for (int c = 0; c < _oops_count; c++) { - _oops[c] = oops->at(c); - } + assert(_table_snapshot != NULL, "Sanity"); + _table_snapshot->parallel_blobs_do(f); } -ShenandoahNMethod::~ShenandoahNMethod() { - if (_oops != NULL) { - FREE_C_HEAP_ARRAY(oop*, _oops); - } -} - -bool ShenandoahNMethod::has_cset_oops(ShenandoahHeap *heap) { - for (int c = 0; c < _oops_count; c++) { - oop o = RawAccess<>::oop_load(_oops[c]); - if (heap->in_collection_set(o)) { - return true; - } - } - return false; -} - -#ifdef ASSERT -void ShenandoahNMethod::assert_alive_and_correct() { - assert(_nm->is_alive(), "only alive nmethods here"); - assert(_oops_count > 0, "should have filtered nmethods without oops before"); - ShenandoahHeap* heap = ShenandoahHeap::heap(); - for (int c = 0; c < _oops_count; c++) { - oop *loc = _oops[c]; - assert(_nm->code_contains((address) loc) || _nm->oops_contains(loc), "nmethod should contain the oop*"); - oop o = RawAccess<>::oop_load(loc); - shenandoah_assert_correct_except(loc, o, - o == NULL || - heap->is_full_gc_move_in_progress() || - (VMThread::vm_operation() != NULL) && (VMThread::vm_operation()->type() == VM_Operation::VMOp_HeapWalkOperation) - ); - } -} - -void ShenandoahNMethod::assert_same_oops(GrowableArray* oops) { - assert(_oops_count == oops->length(), "should have the same number of oop*"); - for (int c = 0; c < _oops_count; c++) { - assert(_oops[c] == oops->at(c), "should be the same oop*"); - } -} -#endif diff -r bfc8074ea4ef -r cfe31d2f935c src/hotspot/share/gc/shenandoah/shenandoahCodeRoots.hpp --- a/src/hotspot/share/gc/shenandoah/shenandoahCodeRoots.hpp Tue Nov 26 10:22:13 2019 +0000 +++ b/src/hotspot/share/gc/shenandoah/shenandoahCodeRoots.hpp Fri Nov 29 10:02:07 2019 +0000 @@ -27,6 +27,7 @@ #include "code/codeCache.hpp" #include "gc/shenandoah/shenandoahSharedVariables.hpp" #include "gc/shenandoah/shenandoahLock.hpp" +#include "gc/shenandoah/shenandoahNMethod.hpp" #include "memory/allocation.hpp" #include "memory/iterator.hpp" @@ -62,43 +63,13 @@ void parallel_blobs_do(CodeBlobClosure* f); }; -// ShenandoahNMethod tuple records the internal locations of oop slots within the nmethod. -// This allows us to quickly scan the oops without doing the nmethod-internal scans, that -// sometimes involves parsing the machine code. Note it does not record the oops themselves, -// because it would then require handling these tuples as the new class of roots. -class ShenandoahNMethod : public CHeapObj { -private: - nmethod* _nm; - oop** _oops; - int _oops_count; - -public: - ShenandoahNMethod(nmethod *nm, GrowableArray* oops); - ~ShenandoahNMethod(); - - nmethod* nm() { - return _nm; - } - - bool has_cset_oops(ShenandoahHeap* heap); - - void assert_alive_and_correct() NOT_DEBUG_RETURN; - void assert_same_oops(GrowableArray* oops) NOT_DEBUG_RETURN; - - static bool find_with_nmethod(void* nm, ShenandoahNMethod* other) { - return other->_nm == nm; - } -}; - class ShenandoahCodeRootsIterator { friend class ShenandoahCodeRoots; protected: - ShenandoahHeap* _heap; ShenandoahParallelCodeCacheIterator _par_iterator; ShenandoahSharedFlag _seq_claimed; - DEFINE_PAD_MINUS_SIZE(0, DEFAULT_CACHE_LINE_SIZE, sizeof(volatile size_t)); - volatile size_t _claimed; - DEFINE_PAD_MINUS_SIZE(1, DEFAULT_CACHE_LINE_SIZE, 0); + ShenandoahNMethodTableSnapshot* _table_snapshot; + protected: ShenandoahCodeRootsIterator(); ~ShenandoahCodeRootsIterator(); @@ -128,12 +99,24 @@ public: static void initialize(); - static void add_nmethod(nmethod* nm); - static void remove_nmethod(nmethod* nm); + static void register_nmethod(nmethod* nm); + static void unregister_nmethod(nmethod* nm); + static void flush_nmethod(nmethod* nm); + + static ShenandoahNMethodTable* table() { + return _nmethod_table; + } + + // Concurrent nmethod unloading support + static void unlink(WorkGang* workers, bool unloading_occurred); + static void purge(WorkGang* workers); + static void prepare_concurrent_unloading(); + static int disarmed_value() { return _disarmed_value; } + static int* disarmed_value_address() { return &_disarmed_value; } private: - static GrowableArray* _recorded_nms; - static ShenandoahLock _recorded_nms_lock; + static ShenandoahNMethodTable* _nmethod_table; + static int _disarmed_value; }; #endif // SHARE_GC_SHENANDOAH_SHENANDOAHCODEROOTS_HPP diff -r bfc8074ea4ef -r cfe31d2f935c src/hotspot/share/gc/shenandoah/shenandoahConcurrentRoots.cpp --- a/src/hotspot/share/gc/shenandoah/shenandoahConcurrentRoots.cpp Tue Nov 26 10:22:13 2019 +0000 +++ b/src/hotspot/share/gc/shenandoah/shenandoahConcurrentRoots.cpp Fri Nov 29 10:02:07 2019 +0000 @@ -32,9 +32,21 @@ } bool ShenandoahConcurrentRoots::should_do_concurrent_roots() { - ShenandoahHeap* const heap = ShenandoahHeap::heap(); - bool stw_gc_in_progress = heap->is_full_gc_in_progress() || - heap->is_degenerated_gc_in_progress(); return can_do_concurrent_roots() && - !stw_gc_in_progress; + !ShenandoahHeap::heap()->is_stw_gc_in_progress(); } + +bool ShenandoahConcurrentRoots::can_do_concurrent_class_unloading() { +#if defined(X86) && !defined(SOLARIS) + return ShenandoahCodeRootsStyle == 2 && + ClassUnloading && + strcmp(ShenandoahGCMode, "traversal") != 0; +#else + return false; +#endif +} + +bool ShenandoahConcurrentRoots::should_do_concurrent_class_unloading() { + return can_do_concurrent_class_unloading() && + !ShenandoahHeap::heap()->is_stw_gc_in_progress(); +} diff -r bfc8074ea4ef -r cfe31d2f935c src/hotspot/share/gc/shenandoah/shenandoahConcurrentRoots.hpp --- a/src/hotspot/share/gc/shenandoah/shenandoahConcurrentRoots.hpp Tue Nov 26 10:22:13 2019 +0000 +++ b/src/hotspot/share/gc/shenandoah/shenandoahConcurrentRoots.hpp Fri Nov 29 10:02:07 2019 +0000 @@ -32,6 +32,11 @@ static bool can_do_concurrent_roots(); // If current GC cycle can process roots concurrently static bool should_do_concurrent_roots(); + + // If GC settings allow concurrent class unloading + static bool can_do_concurrent_class_unloading(); + // If current GC cycle can unload classes concurrently + static bool should_do_concurrent_class_unloading(); }; diff -r bfc8074ea4ef -r cfe31d2f935c src/hotspot/share/gc/shenandoah/shenandoahControlThread.cpp --- a/src/hotspot/share/gc/shenandoah/shenandoahControlThread.cpp Tue Nov 26 10:22:13 2019 +0000 +++ b/src/hotspot/share/gc/shenandoah/shenandoahControlThread.cpp Fri Nov 29 10:02:07 2019 +0000 @@ -37,6 +37,7 @@ #include "gc/shenandoah/shenandoahWorkerPolicy.hpp" #include "memory/iterator.hpp" #include "memory/universe.hpp" +#include "runtime/atomic.hpp" ShenandoahControlThread::ShenandoahControlThread() : ConcurrentGCThread(), diff -r bfc8074ea4ef -r cfe31d2f935c src/hotspot/share/gc/shenandoah/shenandoahEvacOOMHandler.cpp --- a/src/hotspot/share/gc/shenandoah/shenandoahEvacOOMHandler.cpp Tue Nov 26 10:22:13 2019 +0000 +++ b/src/hotspot/share/gc/shenandoah/shenandoahEvacOOMHandler.cpp Fri Nov 29 10:02:07 2019 +0000 @@ -27,7 +27,7 @@ #include "gc/shenandoah/shenandoahUtils.hpp" #include "gc/shenandoah/shenandoahEvacOOMHandler.hpp" #include "gc/shenandoah/shenandoahThreadLocalData.hpp" -#include "runtime/orderAccess.hpp" +#include "runtime/atomic.hpp" #include "runtime/os.hpp" #include "runtime/thread.hpp" @@ -113,7 +113,7 @@ void ShenandoahEvacOOMHandler::clear() { assert(ShenandoahSafepoint::is_at_shenandoah_safepoint(), "must be at a safepoint"); assert((Atomic::load_acquire(&_threads_in_evac) & ~OOM_MARKER_MASK) == 0, "sanity"); - Atomic::release_store_fence(&_threads_in_evac, 0); + Atomic::release_store_fence(&_threads_in_evac, (jint)0); } ShenandoahEvacOOMScope::ShenandoahEvacOOMScope() { diff -r bfc8074ea4ef -r cfe31d2f935c src/hotspot/share/gc/shenandoah/shenandoahForwarding.inline.hpp --- a/src/hotspot/share/gc/shenandoah/shenandoahForwarding.inline.hpp Tue Nov 26 10:22:13 2019 +0000 +++ b/src/hotspot/share/gc/shenandoah/shenandoahForwarding.inline.hpp Fri Nov 29 10:02:07 2019 +0000 @@ -27,7 +27,6 @@ #include "gc/shenandoah/shenandoahAsserts.hpp" #include "gc/shenandoah/shenandoahForwarding.hpp" #include "oops/markWord.inline.hpp" -#include "runtime/atomic.hpp" inline HeapWord* ShenandoahForwarding::get_forwardee_raw(oop obj) { shenandoah_assert_in_heap(NULL, obj); diff -r bfc8074ea4ef -r cfe31d2f935c src/hotspot/share/gc/shenandoah/shenandoahFreeSet.cpp --- a/src/hotspot/share/gc/shenandoah/shenandoahFreeSet.cpp Tue Nov 26 10:22:13 2019 +0000 +++ b/src/hotspot/share/gc/shenandoah/shenandoahFreeSet.cpp Fri Nov 29 10:02:07 2019 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2018, Red Hat, Inc. All rights reserved. + * Copyright (c) 2016, 2019, Red Hat, Inc. All rights reserved. * * 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 @@ -29,6 +29,7 @@ #include "gc/shenandoah/shenandoahMarkingContext.inline.hpp" #include "gc/shenandoah/shenandoahTraversalGC.hpp" #include "logging/logStream.hpp" +#include "runtime/orderAccess.hpp" ShenandoahFreeSet::ShenandoahFreeSet(ShenandoahHeap* heap, size_t max_regions) : _heap(heap), @@ -148,6 +149,11 @@ HeapWord* ShenandoahFreeSet::try_allocate_in(ShenandoahHeapRegion* r, ShenandoahAllocRequest& req, bool& in_new_region) { assert (!has_no_alloc_capacity(r), "Performance: should avoid full regions on this path: " SIZE_FORMAT, r->region_number()); + if (_heap->is_concurrent_root_in_progress() && + r->is_trash()) { + return NULL; + } + try_recycle_trashed(r); in_new_region = r->is_empty(); diff -r bfc8074ea4ef -r cfe31d2f935c src/hotspot/share/gc/shenandoah/shenandoahHeap.cpp --- a/src/hotspot/share/gc/shenandoah/shenandoahHeap.cpp Tue Nov 26 10:22:13 2019 +0000 +++ b/src/hotspot/share/gc/shenandoah/shenandoahHeap.cpp Fri Nov 29 10:02:07 2019 +0000 @@ -71,8 +71,10 @@ #include "memory/metaspace.hpp" #include "oops/compressedOops.inline.hpp" +#include "runtime/atomic.hpp" #include "runtime/globals.hpp" #include "runtime/interfaceSupport.inline.hpp" +#include "runtime/orderAccess.hpp" #include "runtime/safepointMechanism.hpp" #include "runtime/vmThread.hpp" #include "services/mallocTracker.hpp" @@ -1074,7 +1076,8 @@ // Include concurrent roots if current cycle can not process those roots concurrently ShenandoahRootEvacuator rp(workers()->active_workers(), ShenandoahPhaseTimings::init_evac, - !ShenandoahConcurrentRoots::should_do_concurrent_roots()); + !ShenandoahConcurrentRoots::should_do_concurrent_roots(), + !ShenandoahConcurrentRoots::should_do_concurrent_class_unloading()); ShenandoahEvacuateUpdateRootsTask roots_task(&rp); workers()->run_task(&roots_task); } @@ -1546,6 +1549,8 @@ set_has_forwarded_objects(true); if (!is_degenerated_gc_in_progress()) { + prepare_concurrent_roots(); + prepare_concurrent_unloading(); evacuate_and_update_roots(); } @@ -1554,13 +1559,16 @@ } if (ShenandoahVerify) { + ShenandoahRootVerifier::RootTypes types = ShenandoahRootVerifier::None; if (ShenandoahConcurrentRoots::should_do_concurrent_roots()) { - ShenandoahRootVerifier::RootTypes types = ShenandoahRootVerifier::combine(ShenandoahRootVerifier::JNIHandleRoots, ShenandoahRootVerifier::WeakRoots); + types = ShenandoahRootVerifier::combine(ShenandoahRootVerifier::JNIHandleRoots, ShenandoahRootVerifier::WeakRoots); types = ShenandoahRootVerifier::combine(types, ShenandoahRootVerifier::CLDGRoots); - verifier()->verify_roots_no_forwarded_except(types); - } else { - verifier()->verify_roots_no_forwarded(); } + + if (ShenandoahConcurrentRoots::should_do_concurrent_class_unloading()) { + types = ShenandoahRootVerifier::combine(types, ShenandoahRootVerifier::CodeRoots); + } + verifier()->verify_roots_no_forwarded_except(types); verifier()->verify_during_evacuation(); } } else { @@ -1656,11 +1664,18 @@ }; void ShenandoahHeap::op_roots() { - if (is_evacuation_in_progress() && - ShenandoahConcurrentRoots::should_do_concurrent_roots()) { - ShenandoahConcurrentRootsEvacUpdateTask task; - workers()->run_task(&task); + if (is_evacuation_in_progress()) { + if (ShenandoahConcurrentRoots::should_do_concurrent_class_unloading()) { + _unloader.unload(); + } + + if (ShenandoahConcurrentRoots::should_do_concurrent_roots()) { + ShenandoahConcurrentRootsEvacUpdateTask task; + workers()->run_task(&task); + } } + + set_concurrent_root_in_progress(false); } void ShenandoahHeap::op_reset() { @@ -1918,6 +1933,15 @@ set_gc_state_mask(EVACUATION, in_progress); } +void ShenandoahHeap::set_concurrent_root_in_progress(bool in_progress) { + assert(ShenandoahConcurrentRoots::can_do_concurrent_roots(), "Why set the flag?"); + if (in_progress) { + _concurrent_root_in_progress.set(); + } else { + _concurrent_root_in_progress.unset(); + } +} + void ShenandoahHeap::ref_processing_init() { assert(_max_workers > 0, "Sanity"); @@ -2026,10 +2050,10 @@ MetaspaceUtils::verify_metrics(); } -// Process leftover weak oops: update them, if needed or assert they do not -// need updating otherwise. -// Weak processor API requires us to visit the oops, even if we are not doing -// anything to them. +// Weak roots are either pre-evacuated (final mark) or updated (final updaterefs), +// so they should not have forwarded oops. +// However, we do need to "null" dead oops in the roots, if can not be done +// in concurrent cycles. void ShenandoahHeap::stw_process_weak_roots(bool full_gc) { ShenandoahGCPhase root_phase(full_gc ? ShenandoahPhaseTimings::full_gc_purge : @@ -2071,7 +2095,9 @@ void ShenandoahHeap::parallel_cleaning(bool full_gc) { assert(SafepointSynchronize::is_at_safepoint(), "Must be at a safepoint"); stw_process_weak_roots(full_gc); - stw_unload_classes(full_gc); + if (!ShenandoahConcurrentRoots::should_do_concurrent_class_unloading()) { + stw_unload_classes(full_gc); + } } void ShenandoahHeap::set_has_forwarded_objects(bool cond) { @@ -2139,11 +2165,15 @@ } void ShenandoahHeap::register_nmethod(nmethod* nm) { - ShenandoahCodeRoots::add_nmethod(nm); + ShenandoahCodeRoots::register_nmethod(nm); } void ShenandoahHeap::unregister_nmethod(nmethod* nm) { - ShenandoahCodeRoots::remove_nmethod(nm); + ShenandoahCodeRoots::unregister_nmethod(nm); +} + +void ShenandoahHeap::flush_nmethod(nmethod* nm) { + ShenandoahCodeRoots::flush_nmethod(nm); } oop ShenandoahHeap::pin_object(JavaThread* thr, oop o) { @@ -2190,6 +2220,28 @@ return _gc_timer; } +void ShenandoahHeap::prepare_concurrent_roots() { + assert(SafepointSynchronize::is_at_safepoint(), "Must be at a safepoint"); + if (ShenandoahConcurrentRoots::should_do_concurrent_roots()) { + set_concurrent_root_in_progress(true); + } +} + +void ShenandoahHeap::prepare_concurrent_unloading() { + assert(SafepointSynchronize::is_at_safepoint(), "Must be at a safepoint"); + if (ShenandoahConcurrentRoots::should_do_concurrent_class_unloading()) { + ShenandoahCodeRoots::prepare_concurrent_unloading(); + _unloader.prepare(); + } +} + +void ShenandoahHeap::finish_concurrent_unloading() { + assert(SafepointSynchronize::is_at_safepoint(), "Must be at a safepoint"); + if (ShenandoahConcurrentRoots::should_do_concurrent_class_unloading()) { + _unloader.finish(); + } +} + #ifdef ASSERT void ShenandoahHeap::assert_gc_workers(uint nworkers) { assert(nworkers > 0 && nworkers <= max_workers(), "Sanity"); @@ -2313,6 +2365,8 @@ void ShenandoahHeap::op_final_updaterefs() { assert(ShenandoahSafepoint::is_at_shenandoah_safepoint(), "must be at safepoint"); + finish_concurrent_unloading(); + // Check if there is left-over work, and finish it if (_update_refs_iterator.has_next()) { ShenandoahGCPhase phase(ShenandoahPhaseTimings::final_update_refs_finish_work); @@ -2330,7 +2384,7 @@ assert(!cancelled_gc(), "Should have been done right before"); if (ShenandoahVerify && !is_degenerated_gc_in_progress()) { - verifier()->verify_roots_no_forwarded_except(ShenandoahRootVerifier::ThreadRoots); + verifier()->verify_roots_in_to_space_except(ShenandoahRootVerifier::ThreadRoots); } if (is_degenerated_gc_in_progress()) { diff -r bfc8074ea4ef -r cfe31d2f935c src/hotspot/share/gc/shenandoah/shenandoahHeap.hpp --- a/src/hotspot/share/gc/shenandoah/shenandoahHeap.hpp Tue Nov 26 10:22:13 2019 +0000 +++ b/src/hotspot/share/gc/shenandoah/shenandoahHeap.hpp Fri Nov 29 10:02:07 2019 +0000 @@ -32,6 +32,7 @@ #include "gc/shenandoah/shenandoahLock.hpp" #include "gc/shenandoah/shenandoahEvacOOMHandler.hpp" #include "gc/shenandoah/shenandoahSharedVariables.hpp" +#include "gc/shenandoah/shenandoahUnload.hpp" #include "services/memoryManager.hpp" class ConcurrentGCTimer; @@ -271,6 +272,7 @@ ShenandoahSharedFlag _full_gc_in_progress; ShenandoahSharedFlag _full_gc_move_in_progress; ShenandoahSharedFlag _progress_last_gc; + ShenandoahSharedFlag _concurrent_root_in_progress; void set_gc_state_all_threads(char state); void set_gc_state_mask(uint mask, bool value); @@ -287,6 +289,7 @@ void set_full_gc_move_in_progress(bool in_progress); void set_concurrent_traversal_in_progress(bool in_progress); void set_has_forwarded_objects(bool cond); + void set_concurrent_root_in_progress(bool cond); inline bool is_stable() const; inline bool is_idle() const; @@ -299,6 +302,8 @@ inline bool is_concurrent_traversal_in_progress() const; inline bool has_forwarded_objects() const; inline bool is_gc_in_progress_mask(uint mask) const; + inline bool is_stw_gc_in_progress() const; + inline bool is_concurrent_root_in_progress() const; // ---------- GC cancellation and degeneration machinery // @@ -511,6 +516,7 @@ // private: ShenandoahSharedFlag _unload_classes; + ShenandoahUnload _unloader; public: void set_unload_classes(bool uc); @@ -523,6 +529,12 @@ void stw_unload_classes(bool full_gc); void stw_process_weak_roots(bool full_gc); + // Prepare concurrent root processing + void prepare_concurrent_roots(); + // Prepare and finish concurrent unloading + void prepare_concurrent_unloading(); + void finish_concurrent_unloading(); + // ---------- Generic interface hooks // Minor things that super-interface expects us to implement to play nice with // the rest of runtime. Some of the things here are not required to be implemented, @@ -562,7 +574,7 @@ public: void register_nmethod(nmethod* nm); void unregister_nmethod(nmethod* nm); - void flush_nmethod(nmethod* nm) {} + void flush_nmethod(nmethod* nm); void verify_nmethod(nmethod* nm) {} // ---------- Pinning hooks diff -r bfc8074ea4ef -r cfe31d2f935c src/hotspot/share/gc/shenandoah/shenandoahHeap.inline.hpp --- a/src/hotspot/share/gc/shenandoah/shenandoahHeap.inline.hpp Tue Nov 26 10:22:13 2019 +0000 +++ b/src/hotspot/share/gc/shenandoah/shenandoahHeap.inline.hpp Fri Nov 29 10:02:07 2019 +0000 @@ -372,6 +372,14 @@ return _gc_state.is_set(UPDATEREFS); } +inline bool ShenandoahHeap::is_stw_gc_in_progress() const { + return is_full_gc_in_progress() || is_degenerated_gc_in_progress(); +} + +inline bool ShenandoahHeap::is_concurrent_root_in_progress() const { + return _concurrent_root_in_progress.is_set(); +} + template inline void ShenandoahHeap::marked_object_iterate(ShenandoahHeapRegion* region, T* cl) { marked_object_iterate(region, cl, region->top()); diff -r bfc8074ea4ef -r cfe31d2f935c src/hotspot/share/gc/shenandoah/shenandoahHeapRegion.cpp --- a/src/hotspot/share/gc/shenandoah/shenandoahHeapRegion.cpp Tue Nov 26 10:22:13 2019 +0000 +++ b/src/hotspot/share/gc/shenandoah/shenandoahHeapRegion.cpp Fri Nov 29 10:02:07 2019 +0000 @@ -34,6 +34,7 @@ #include "memory/resourceArea.hpp" #include "memory/universe.hpp" #include "oops/oop.inline.hpp" +#include "runtime/atomic.hpp" #include "runtime/java.hpp" #include "runtime/mutexLocker.hpp" #include "runtime/os.hpp" diff -r bfc8074ea4ef -r cfe31d2f935c src/hotspot/share/gc/shenandoah/shenandoahHeapRegionCounters.cpp --- a/src/hotspot/share/gc/shenandoah/shenandoahHeapRegionCounters.cpp Tue Nov 26 10:22:13 2019 +0000 +++ b/src/hotspot/share/gc/shenandoah/shenandoahHeapRegionCounters.cpp Fri Nov 29 10:02:07 2019 +0000 @@ -27,6 +27,7 @@ #include "gc/shenandoah/shenandoahHeapRegionSet.hpp" #include "gc/shenandoah/shenandoahHeapRegionCounters.hpp" #include "memory/resourceArea.hpp" +#include "runtime/atomic.hpp" #include "runtime/perfData.inline.hpp" ShenandoahHeapRegionCounters::ShenandoahHeapRegionCounters() : diff -r bfc8074ea4ef -r cfe31d2f935c src/hotspot/share/gc/shenandoah/shenandoahLock.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/hotspot/share/gc/shenandoah/shenandoahLock.cpp Fri Nov 29 10:02:07 2019 +0000 @@ -0,0 +1,82 @@ +/* + * Copyright (c) 2019, Red Hat, Inc. All rights reserved. + * + * 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 "runtime/os.hpp" + +#include "gc/shenandoah/shenandoahLock.hpp" +#include "runtime/atomic.hpp" +#include "runtime/os.inline.hpp" +#include "runtime/thread.hpp" + +ShenandoahSimpleLock::ShenandoahSimpleLock() { + assert(os::mutex_init_done(), "Too early!"); +} + +void ShenandoahSimpleLock::lock() { + _lock.lock(); +} + +void ShenandoahSimpleLock::unlock() { + _lock.unlock(); +} + +ShenandoahReentrantLock::ShenandoahReentrantLock() : + ShenandoahSimpleLock(), _owner(NULL), _count(0) { + assert(os::mutex_init_done(), "Too early!"); +} + +ShenandoahReentrantLock::~ShenandoahReentrantLock() { + assert(_count == 0, "Unbalance"); +} + +void ShenandoahReentrantLock::lock() { + Thread* const thread = Thread::current(); + Thread* const owner = Atomic::load(&_owner); + + if (owner != thread) { + ShenandoahSimpleLock::lock(); + Atomic::store(&_owner, thread); + } + + _count++; +} + +void ShenandoahReentrantLock::unlock() { + assert(owned_by_self(), "Invalid owner"); + assert(_count > 0, "Invalid count"); + + _count--; + + if (_count == 0) { + Atomic::store(&_owner, (Thread*)NULL); + ShenandoahSimpleLock::unlock(); + } +} + +bool ShenandoahReentrantLock::owned_by_self() const { + Thread* const thread = Thread::current(); + Thread* const owner = Atomic::load(&_owner); + return owner == thread; +} diff -r bfc8074ea4ef -r cfe31d2f935c src/hotspot/share/gc/shenandoah/shenandoahLock.hpp --- a/src/hotspot/share/gc/shenandoah/shenandoahLock.hpp Tue Nov 26 10:22:13 2019 +0000 +++ b/src/hotspot/share/gc/shenandoah/shenandoahLock.hpp Fri Nov 29 10:02:07 2019 +0000 @@ -25,6 +25,7 @@ #define SHARE_GC_SHENANDOAH_SHENANDOAHLOCK_HPP #include "memory/allocation.hpp" +#include "runtime/safepoint.hpp" #include "runtime/thread.hpp" class ShenandoahLock { @@ -96,4 +97,50 @@ } }; +class ShenandoahSimpleLock { +private: + os::PlatformMonitor _lock; // native lock +public: + ShenandoahSimpleLock(); + + virtual void lock(); + virtual void unlock(); +}; + +class ShenandoahReentrantLock : public ShenandoahSimpleLock { +private: + Thread* volatile _owner; + uint64_t _count; + +public: + ShenandoahReentrantLock(); + ~ShenandoahReentrantLock(); + + virtual void lock(); + virtual void unlock(); + + // If the lock already owned by this thread + bool owned_by_self() const ; +}; + +class ShenandoahReentrantLocker : public StackObj { +private: + ShenandoahReentrantLock* const _lock; + +public: + ShenandoahReentrantLocker(ShenandoahReentrantLock* lock) : + _lock(lock) { + if (_lock != NULL) { + _lock->lock(); + } + } + + ~ShenandoahReentrantLocker() { + if (_lock != NULL) { + assert(_lock->owned_by_self(), "Must be owner"); + _lock->unlock(); + } + } +}; + #endif // SHARE_GC_SHENANDOAH_SHENANDOAHLOCK_HPP diff -r bfc8074ea4ef -r cfe31d2f935c src/hotspot/share/gc/shenandoah/shenandoahMarkCompact.cpp --- a/src/hotspot/share/gc/shenandoah/shenandoahMarkCompact.cpp Tue Nov 26 10:22:13 2019 +0000 +++ b/src/hotspot/share/gc/shenandoah/shenandoahMarkCompact.cpp Fri Nov 29 10:02:07 2019 +0000 @@ -48,6 +48,7 @@ #include "oops/compressedOops.inline.hpp" #include "oops/oop.inline.hpp" #include "runtime/biasedLocking.hpp" +#include "runtime/orderAccess.hpp" #include "runtime/thread.hpp" #include "utilities/copy.hpp" #include "utilities/growableArray.hpp" diff -r bfc8074ea4ef -r cfe31d2f935c src/hotspot/share/gc/shenandoah/shenandoahNMethod.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/hotspot/share/gc/shenandoah/shenandoahNMethod.cpp Fri Nov 29 10:02:07 2019 +0000 @@ -0,0 +1,516 @@ +/* + * Copyright (c) 2019, Red Hat, Inc. All rights reserved. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +#include "precompiled.hpp" + +#include "gc/shenandoah/shenandoahClosures.inline.hpp" +#include "gc/shenandoah/shenandoahConcurrentRoots.hpp" +#include "gc/shenandoah/shenandoahHeap.inline.hpp" +#include "gc/shenandoah/shenandoahNMethod.inline.hpp" +#include "memory/resourceArea.hpp" + +ShenandoahNMethod::ShenandoahNMethod(nmethod* nm, GrowableArray& oops, bool non_immediate_oops) : + _nm(nm), _oops(NULL), _oops_count(0), _unregistered(false) { + + if (!oops.is_empty()) { + _oops_count = oops.length(); + _oops = NEW_C_HEAP_ARRAY(oop*, _oops_count, mtGC); + for (int c = 0; c < _oops_count; c++) { + _oops[c] = oops.at(c); + } + } + _has_non_immed_oops = non_immediate_oops; + + assert_same_oops(); +} + +ShenandoahNMethod::~ShenandoahNMethod() { + if (_oops != NULL) { + FREE_C_HEAP_ARRAY(oop*, _oops); + } +} + +class ShenandoahHasCSetOopClosure : public OopClosure { +private: + ShenandoahHeap* const _heap; + bool _has_cset_oops; + +public: + ShenandoahHasCSetOopClosure() : + _heap(ShenandoahHeap::heap()), + _has_cset_oops(false) { + } + + bool has_cset_oops() const { + return _has_cset_oops; + } + + void do_oop(oop* p) { + oop value = RawAccess<>::oop_load(p); + if (!_has_cset_oops && _heap->in_collection_set(value)) { + _has_cset_oops = true; + } + } + + void do_oop(narrowOop* p) { + ShouldNotReachHere(); + } +}; + +bool ShenandoahNMethod::has_cset_oops(ShenandoahHeap *heap) { + ShenandoahHasCSetOopClosure cl; + oops_do(&cl); + return cl.has_cset_oops(); +} + +void ShenandoahNMethod::update() { + ResourceMark rm; + bool non_immediate_oops = false; + GrowableArray oops; + + detect_reloc_oops(nm(), oops, non_immediate_oops); + if (oops.length() != _oops_count) { + if (_oops != NULL) { + FREE_C_HEAP_ARRAY(oop*, _oops); + _oops = NULL; + } + + _oops_count = oops.length(); + if (_oops_count > 0) { + _oops = NEW_C_HEAP_ARRAY(oop*, _oops_count, mtGC); + } + } + + for (int index = 0; index < _oops_count; index ++) { + _oops[index] = oops.at(index); + } + _has_non_immed_oops = non_immediate_oops; + + assert_same_oops(); +} + +void ShenandoahNMethod::oops_do(OopClosure* oops, bool fix_relocations) { + for (int c = 0; c < _oops_count; c ++) { + oops->do_oop(_oops[c]); + } + + oop* const begin = _nm->oops_begin(); + oop* const end = _nm->oops_end(); + for (oop* p = begin; p < end; p++) { + if (*p != Universe::non_oop_word()) { + oops->do_oop(p); + } + } + + if (fix_relocations && _has_non_immed_oops) { + _nm->fix_oop_relocations(); + } +} + +void ShenandoahNMethod::detect_reloc_oops(nmethod* nm, GrowableArray& oops, bool& has_non_immed_oops) { + has_non_immed_oops = false; + // Find all oops relocations + RelocIterator iter(nm); + while (iter.next()) { + if (iter.type() != relocInfo::oop_type) { + // Not an oop + continue; + } + + oop_Relocation* r = iter.oop_reloc(); + if (!r->oop_is_immediate()) { + // Non-immediate oop found + has_non_immed_oops = true; + continue; + } + + if (r->oop_value() != NULL) { + // Non-NULL immediate oop found. NULL oops can safely be + // ignored since the method will be re-registered if they + // are later patched to be non-NULL. + oops.push(r->oop_addr()); + } + } +} + +ShenandoahNMethod* ShenandoahNMethod::for_nmethod(nmethod* nm) { + ResourceMark rm; + bool non_immediate_oops = false; + GrowableArray oops; + + detect_reloc_oops(nm, oops, non_immediate_oops); + + // No embedded oops + if(!ShenandoahConcurrentRoots::can_do_concurrent_class_unloading() && + oops.is_empty() && nm->oops_begin() >= nm->oops_end()) { + return NULL; + } + + return new ShenandoahNMethod(nm, oops, non_immediate_oops); +} + +void ShenandoahNMethod::heal_nmethod(nmethod* nm) { + ShenandoahNMethod* data = gc_data(nm); + assert(data != NULL, "Sanity"); + assert(data->lock()->owned_by_self(), "Must hold the lock"); + + ShenandoahEvacuateUpdateRootsClosure cl; + data->oops_do(&cl, true /*fix relocation*/); +} + +#ifdef ASSERT +void ShenandoahNMethod::assert_alive_and_correct() { + assert(_nm->is_alive(), "only alive nmethods here"); + ShenandoahHeap* heap = ShenandoahHeap::heap(); + for (int c = 0; c < _oops_count; c++) { + oop *loc = _oops[c]; + assert(_nm->code_contains((address) loc) || _nm->oops_contains(loc), "nmethod should contain the oop*"); + oop o = RawAccess<>::oop_load(loc); + shenandoah_assert_correct_except(loc, o, o == NULL || heap->is_full_gc_move_in_progress()); + } + + oop* const begin = _nm->oops_begin(); + oop* const end = _nm->oops_end(); + for (oop* p = begin; p < end; p++) { + if (*p != Universe::non_oop_word()) { + oop o = RawAccess<>::oop_load(p); + shenandoah_assert_correct_except(p, o, o == NULL || heap->is_full_gc_move_in_progress()); + } + } +} + +class ShenandoahNMethodOopDetector : public OopClosure { +private: + ResourceMark rm; // For growable array allocation below. + GrowableArray _oops; + +public: + ShenandoahNMethodOopDetector() : _oops(10) {}; + + void do_oop(oop* o) { + _oops.append(o); + } + void do_oop(narrowOop* o) { + fatal("NMethods should not have compressed oops embedded."); + } + + GrowableArray* oops() { + return &_oops; + } + + bool has_oops() { + return !_oops.is_empty(); + } +}; + +void ShenandoahNMethod::assert_same_oops(bool allow_dead) { + ShenandoahNMethodOopDetector detector; + nm()->oops_do(&detector, allow_dead); + + GrowableArray* oops = detector.oops(); + + assert(oops->length() == oop_count(), "Must match"); + + for (int index = 0; index < _oops_count; index ++) { + assert(oops->contains(_oops[index]), "Must contain this oop"); + } + + for (oop* p = nm()->oops_begin(); p < nm()->oops_end(); p ++) { + assert(oops->contains(p), "Must contain this oop"); + } +} + +void ShenandoahNMethod::assert_no_oops(nmethod* nm, bool allow_dead) { + ShenandoahNMethodOopDetector detector; + nm->oops_do(&detector, allow_dead); + assert(detector.oops()->length() == 0, "Should not have oops"); +} +#endif + +ShenandoahNMethodTable::ShenandoahNMethodTable() : + _heap(ShenandoahHeap::heap()), + _size(minSize), + _index(0), + _iteration_in_progress(false) { + _array = NEW_C_HEAP_ARRAY(ShenandoahNMethod*, _size, mtGC); +} + +ShenandoahNMethodTable::~ShenandoahNMethodTable() { + assert(_array != NULL, "Sanity"); + FREE_C_HEAP_ARRAY(ShenandoahNMethod*, _array); +} + +void ShenandoahNMethodTable::register_nmethod(nmethod* nm) { + assert(CodeCache_lock->owned_by_self(), "Must have CodeCache_lock held"); + assert(_index >= 0 && _index <= _size, "Sanity"); + + ShenandoahNMethod* data = ShenandoahNMethod::gc_data(nm); + ShenandoahReentrantLocker data_locker(data != NULL ? data->lock() : NULL); + + if (data != NULL) { + assert(contain(nm), "Must have been registered"); + data->update(); + } else { + data = ShenandoahNMethod::for_nmethod(nm); + if (data == NULL) { + assert(!ShenandoahConcurrentRoots::can_do_concurrent_class_unloading(), + "Only possible when concurrent class unloading is off"); + return; + } + ShenandoahNMethod::attach_gc_data(nm, data); + ShenandoahLocker locker(&_lock); + log_register_nmethod(nm); + append(data); + } + // Disarm new nmethod + ShenandoahNMethod::disarm_nmethod(nm); +} + +void ShenandoahNMethodTable::unregister_nmethod(nmethod* nm) { + assert_locked_or_safepoint(CodeCache_lock); + + ShenandoahNMethod* data = ShenandoahNMethod::gc_data(nm); + if (data == NULL) { + assert(!ShenandoahConcurrentRoots::can_do_concurrent_class_unloading(), + "Only possible when concurrent class unloading is off"); + ShenandoahNMethod::assert_no_oops(nm, true /*allow_dead*/); + return; + } + + if (Thread::current()->is_Code_cache_sweeper_thread()) { + wait_until_concurrent_iteration_done(); + } + log_unregister_nmethod(nm); + ShenandoahLocker locker(&_lock); + assert(contain(nm), "Must have been registered"); + + ShenandoahReentrantLocker data_locker(data->lock()); + data->mark_unregistered(); +} + +void ShenandoahNMethodTable::flush_nmethod(nmethod* nm) { + assert(CodeCache_lock->owned_by_self(), "Must have CodeCache_lock held"); + assert(Thread::current()->is_Code_cache_sweeper_thread(), "Must from Sweep thread"); + ShenandoahNMethod* data = ShenandoahNMethod::gc_data(nm); + assert(data != NULL || !ShenandoahConcurrentRoots::can_do_concurrent_class_unloading(), + "Only possible when concurrent class unloading is off"); + if (data == NULL) { + ShenandoahNMethod::assert_no_oops(nm, true /*allow_dead*/); + return; + } + + // Can not alter the array when iteration is in progress + wait_until_concurrent_iteration_done(); + log_flush_nmethod(nm); + + ShenandoahLocker locker(&_lock); + int idx = index_of(nm); + assert(idx >= 0 && idx < _index, "Invalid index"); + ShenandoahNMethod::attach_gc_data(nm, NULL); + remove(idx); +} + +bool ShenandoahNMethodTable::contain(nmethod* nm) const { + return index_of(nm) != -1; +} + +ShenandoahNMethod* ShenandoahNMethodTable::at(int index) const { + assert(index >= 0 && index < _index, "Out of bound"); + return _array[index]; +} + +int ShenandoahNMethodTable::index_of(nmethod* nm) const { + for (int index = 0; index < length(); index ++) { + if (_array[index]->nm() == nm) { + return index; + } + } + return -1; +} + +void ShenandoahNMethodTable::remove(int idx) { + shenandoah_assert_locked_or_safepoint(CodeCache_lock); + assert(!_iteration_in_progress, "Can not happen"); + assert(_index >= 0 && _index <= _size, "Sanity"); + + assert(idx >= 0 && idx < _index, "Out of bound"); + ShenandoahNMethod* snm = _array[idx]; + + _index --; + _array[idx] = _array[_index]; + + delete snm; +} + +void ShenandoahNMethodTable::wait_until_concurrent_iteration_done() { + assert(CodeCache_lock->owned_by_self(), "Lock must be held"); + while (iteration_in_progress()) { + CodeCache_lock->wait_without_safepoint_check(); + } +} + +void ShenandoahNMethodTable::append(ShenandoahNMethod* snm) { + if (is_full()) { + int new_size = 2 * _size; + ShenandoahNMethod** old_table = _array; + + // Rebuild table and replace current one + rebuild(new_size); + + // An iteration is in progress over early snapshot, + // can not release the array until iteration is completed + if (!iteration_in_progress()) { + FREE_C_HEAP_ARRAY(ShenandoahNMethod*, old_table); + } + } + + _array[_index ++] = snm; + assert(_index >= 0 && _index <= _size, "Sanity"); +} + +void ShenandoahNMethodTable::rebuild(int size) { + ShenandoahNMethod** arr = NEW_C_HEAP_ARRAY(ShenandoahNMethod*, size, mtGC); + for (int index = 0; index < _index; index ++) { + arr[index] = _array[index]; + } + _array = arr; + _size = size; +} + +ShenandoahNMethodTableSnapshot* ShenandoahNMethodTable::snapshot_for_iteration() { + assert(!iteration_in_progress(), "Already in progress"); + _iteration_in_progress = true; + + return new ShenandoahNMethodTableSnapshot(this); +} + +void ShenandoahNMethodTable::finish_iteration(ShenandoahNMethodTableSnapshot* snapshot) { + assert(iteration_in_progress(), "Why we here?"); + assert(snapshot != NULL, "No snapshot"); + _iteration_in_progress = false; + + // Table has been rebuilt during iteration, free old table + if (snapshot->_array != _array) { + FREE_C_HEAP_ARRAY(ShenandoahNMethod*, snapshot->_array); + } + delete snapshot; +} + +void ShenandoahNMethodTable::log_register_nmethod(nmethod* nm) { + LogTarget(Debug, gc, nmethod) log; + if (!log.is_enabled()) { + return; + } + + ResourceMark rm; + log.print("Register NMethod: %s.%s [" PTR_FORMAT "] (%s)", + nm->method()->method_holder()->external_name(), + nm->method()->name()->as_C_string(), + p2i(nm), + nm->compiler_name()); +} + +void ShenandoahNMethodTable::log_unregister_nmethod(nmethod* nm) { + LogTarget(Debug, gc, nmethod) log; + if (!log.is_enabled()) { + return; + } + + ResourceMark rm; + log.print("Unregister NMethod: %s.%s [" PTR_FORMAT "]", + nm->method()->method_holder()->external_name(), + nm->method()->name()->as_C_string(), + p2i(nm)); +} + +void ShenandoahNMethodTable::log_flush_nmethod(nmethod* nm) { + LogTarget(Debug, gc, nmethod) log; + if (!log.is_enabled()) { + return; + } + + ResourceMark rm; + log.print("Flush NMethod: (" PTR_FORMAT ")", p2i(nm)); +} + +#ifdef ASSERT +void ShenandoahNMethodTable::assert_nmethods_alive_and_correct() { + assert_locked_or_safepoint(CodeCache_lock); + + for (int index = 0; index < length(); index ++) { + ShenandoahNMethod* m = _array[index]; + // Concurrent unloading may have dead nmethods to be cleaned by sweeper + if (m->is_unregistered()) continue; + m->assert_alive_and_correct(); + } +} +#endif + +ShenandoahNMethodTableSnapshot::ShenandoahNMethodTableSnapshot(ShenandoahNMethodTable* table) : + _heap(ShenandoahHeap::heap()), _table(table), _array(table->_array), _length(table->_index), _claimed(0) { +} + +void ShenandoahNMethodTableSnapshot::concurrent_nmethods_do(NMethodClosure* cl) { + size_t stride = 256; // educated guess + + ShenandoahNMethod** list = _array; + size_t max = (size_t)_length; + while (_claimed < max) { + size_t cur = Atomic::add(&_claimed, stride) - stride; + size_t start = cur; + size_t end = MIN2(cur + stride, max); + if (start >= max) break; + + for (size_t idx = start; idx < end; idx++) { + ShenandoahNMethod* data = list[idx]; + assert(data != NULL, "Should not be NULL"); + if (!data->is_unregistered()) { + cl->do_nmethod(data->nm()); + } + } + } +} + +ShenandoahConcurrentNMethodIterator::ShenandoahConcurrentNMethodIterator(ShenandoahNMethodTable* table) : + _table(table), _table_snapshot(NULL) { +} + +void ShenandoahConcurrentNMethodIterator::nmethods_do_begin() { + assert(CodeCache_lock->owned_by_self(), "Lock must be held"); + assert(ShenandoahConcurrentRoots::can_do_concurrent_class_unloading(), + "Only for concurrent class unloading"); + _table_snapshot = _table->snapshot_for_iteration(); +} + +void ShenandoahConcurrentNMethodIterator::nmethods_do(NMethodClosure* cl) { + assert(_table_snapshot != NULL, "Must first call nmethod_do_begin()"); + _table_snapshot->concurrent_nmethods_do(cl); +} + +void ShenandoahConcurrentNMethodIterator::nmethods_do_end() { + assert(CodeCache_lock->owned_by_self(), "Lock must be held"); + assert(ShenandoahConcurrentRoots::can_do_concurrent_class_unloading(), + "Only for concurrent class unloading"); + _table->finish_iteration(_table_snapshot); + CodeCache_lock->notify_all(); +} diff -r bfc8074ea4ef -r cfe31d2f935c src/hotspot/share/gc/shenandoah/shenandoahNMethod.hpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/hotspot/share/gc/shenandoah/shenandoahNMethod.hpp Fri Nov 29 10:02:07 2019 +0000 @@ -0,0 +1,172 @@ +/* + * Copyright (c) 2019, Red Hat, Inc. All rights reserved. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +#ifndef SHARE_GC_SHENANDOAH_SHENANDOAHNMETHOD_HPP +#define SHARE_GC_SHENANDOAH_SHENANDOAHNMETHOD_HPP + +#include "code/nmethod.hpp" +#include "gc/shenandoah/shenandoahHeap.hpp" +#include "gc/shenandoah/shenandoahLock.hpp" +#include "memory/allocation.hpp" +#include "utilities/growableArray.hpp" + +// ShenandoahNMethod tuple records the internal locations of oop slots within reclocation stream in +// the nmethod. This allows us to quickly scan the oops without doing the nmethod-internal scans, +// that sometimes involves parsing the machine code. Note it does not record the oops themselves, +// because it would then require handling these tuples as the new class of roots. +class ShenandoahNMethod : public CHeapObj { +private: + nmethod* const _nm; + oop** _oops; + int _oops_count; + bool _has_non_immed_oops; + bool _unregistered; + ShenandoahReentrantLock _lock; + +public: + ShenandoahNMethod(nmethod *nm, GrowableArray& oops, bool has_non_immed_oops); + ~ShenandoahNMethod(); + + inline nmethod* nm() const; + inline ShenandoahReentrantLock* lock(); + void oops_do(OopClosure* oops, bool fix_relocations = false); + // Update oops when the nmethod is re-registered + void update(); + + bool has_cset_oops(ShenandoahHeap* heap); + + inline int oop_count() const; + inline bool has_oops() const; + + inline void mark_unregistered(); + inline bool is_unregistered() const; + + static ShenandoahNMethod* for_nmethod(nmethod* nm); + static inline ShenandoahReentrantLock* lock_for_nmethod(nmethod* nm); + + static void heal_nmethod(nmethod* nm); + static inline void disarm_nmethod(nmethod* nm); + + static inline ShenandoahNMethod* gc_data(nmethod* nm); + static inline void attach_gc_data(nmethod* nm, ShenandoahNMethod* gc_data); + + void assert_alive_and_correct() NOT_DEBUG_RETURN; + void assert_same_oops(bool allow_dead = false) NOT_DEBUG_RETURN; + static void assert_no_oops(nmethod* nm, bool allow_dea = false) NOT_DEBUG_RETURN; + +private: + bool has_non_immed_oops() const { return _has_non_immed_oops; } + static void detect_reloc_oops(nmethod* nm, GrowableArray& oops, bool& _has_non_immed_oops); +}; + +class ShenandoahNMethodTable; + +// An opaque snapshot of current nmethod table for iteration +class ShenandoahNMethodTableSnapshot : public CHeapObj { + friend class ShenandoahNMethodTable; +private: + ShenandoahHeap* const _heap; + ShenandoahNMethodTable* _table; + ShenandoahNMethod** const _array; + const int _length; + + DEFINE_PAD_MINUS_SIZE(0, DEFAULT_CACHE_LINE_SIZE, sizeof(volatile size_t)); + volatile size_t _claimed; + DEFINE_PAD_MINUS_SIZE(1, DEFAULT_CACHE_LINE_SIZE, 0); + +public: + ShenandoahNMethodTableSnapshot(ShenandoahNMethodTable* table); + + template + void parallel_blobs_do(CodeBlobClosure *f); + + void concurrent_nmethods_do(NMethodClosure* cl); +}; + +class ShenandoahNMethodTable : public CHeapObj { + friend class ShenandoahNMethodTableSnapshot; +private: + enum { + minSize = 1024 + }; + + ShenandoahHeap* const _heap; + ShenandoahNMethod** _array; + int _size; + int _index; + ShenandoahLock _lock; + bool _iteration_in_progress; + +public: + ShenandoahNMethodTable(); + ~ShenandoahNMethodTable(); + + void register_nmethod(nmethod* nm); + void unregister_nmethod(nmethod* nm); + void flush_nmethod(nmethod* nm); + + bool contain(nmethod* nm) const; + int length() const { return _index; } + + // Table iteration support + ShenandoahNMethodTableSnapshot* snapshot_for_iteration(); + void finish_iteration(ShenandoahNMethodTableSnapshot* snapshot); + + void assert_nmethods_alive_and_correct() NOT_DEBUG_RETURN; +private: + // Rebuild table and replace current one + void rebuild(int size); + + bool is_full() const { + assert(_index <= _size, "Sanity"); + return _index == _size; + } + + ShenandoahNMethod* at(int index) const; + int index_of(nmethod* nm) const; + void remove(int index); + void append(ShenandoahNMethod* snm); + + inline bool iteration_in_progress() const; + void wait_until_concurrent_iteration_done(); + + // Logging support + void log_register_nmethod(nmethod* nm); + void log_unregister_nmethod(nmethod* nm); + void log_flush_nmethod(nmethod* nm); +}; + +class ShenandoahConcurrentNMethodIterator { +private: + ShenandoahNMethodTable* const _table; + ShenandoahNMethodTableSnapshot* _table_snapshot; + +public: + ShenandoahConcurrentNMethodIterator(ShenandoahNMethodTable* table); + + void nmethods_do_begin(); + void nmethods_do(NMethodClosure* cl); + void nmethods_do_end(); +}; + +#endif // SHARE_GC_SHENANDOAH_SHENANDOAHNMETHOD_HPP diff -r bfc8074ea4ef -r cfe31d2f935c src/hotspot/share/gc/shenandoah/shenandoahNMethod.inline.hpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/hotspot/share/gc/shenandoah/shenandoahNMethod.inline.hpp Fri Nov 29 10:02:07 2019 +0000 @@ -0,0 +1,113 @@ +/* + * Copyright (c) 2019, Red Hat, Inc. All rights reserved. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +#ifndef SHARE_GC_SHENANDOAH_SHENANDOAHNMETHOD_INLINE_HPP +#define SHARE_GC_SHENANDOAH_SHENANDOAHNMETHOD_INLINE_HPP + +#include "gc/shared/barrierSet.hpp" +#include "gc/shared/barrierSetNMethod.hpp" +#include "gc/shenandoah/shenandoahConcurrentRoots.hpp" +#include "gc/shenandoah/shenandoahNMethod.hpp" + +nmethod* ShenandoahNMethod::nm() const { + return _nm; +} + +ShenandoahReentrantLock* ShenandoahNMethod::lock() { + return &_lock; +} + +int ShenandoahNMethod::oop_count() const { + return _oops_count + static_cast(nm()->oops_end() - nm()->oops_begin()); +} + +bool ShenandoahNMethod::has_oops() const { + return oop_count() > 0; +} + +void ShenandoahNMethod::mark_unregistered() { + _unregistered = true; +} + +bool ShenandoahNMethod::is_unregistered() const { + return _unregistered; +} + +void ShenandoahNMethod::disarm_nmethod(nmethod* nm) { + if (!ShenandoahConcurrentRoots::can_do_concurrent_class_unloading()) { + return; + } + + BarrierSetNMethod* const bs = BarrierSet::barrier_set()->barrier_set_nmethod(); + assert(bs != NULL, "Sanity"); + bs->disarm(nm); +} + +ShenandoahNMethod* ShenandoahNMethod::gc_data(nmethod* nm) { + return nm->gc_data(); +} + +void ShenandoahNMethod::attach_gc_data(nmethod* nm, ShenandoahNMethod* gc_data) { + nm->set_gc_data(gc_data); +} + +ShenandoahReentrantLock* ShenandoahNMethod::lock_for_nmethod(nmethod* nm) { + return gc_data(nm)->lock(); +} + +bool ShenandoahNMethodTable::iteration_in_progress() const { + return _iteration_in_progress; +} + +template +void ShenandoahNMethodTableSnapshot::parallel_blobs_do(CodeBlobClosure *f) { + size_t stride = 256; // educated guess + + ShenandoahNMethod** const list = _array; + + size_t max = (size_t)_length; + while (_claimed < max) { + size_t cur = Atomic::add(&_claimed, stride) - stride; + size_t start = cur; + size_t end = MIN2(cur + stride, max); + if (start >= max) break; + + for (size_t idx = start; idx < end; idx++) { + ShenandoahNMethod* nmr = list[idx]; + assert(nmr != NULL, "Sanity"); + if (nmr->is_unregistered()) { + continue; + } + + nmr->assert_alive_and_correct(); + + if (CSET_FILTER && !nmr->has_cset_oops(_heap)) { + continue; + } + + f->do_code_blob(nmr->nm()); + } + } +} + +#endif // SHARE_GC_SHENANDOAH_SHENANDOAHNMETHOD_INLINE_HPP diff -r bfc8074ea4ef -r cfe31d2f935c src/hotspot/share/gc/shenandoah/shenandoahNormalMode.cpp --- a/src/hotspot/share/gc/shenandoah/shenandoahNormalMode.cpp Tue Nov 26 10:22:13 2019 +0000 +++ b/src/hotspot/share/gc/shenandoah/shenandoahNormalMode.cpp Fri Nov 29 10:02:07 2019 +0000 @@ -21,6 +21,7 @@ */ #include "precompiled.hpp" +#include "gc/shenandoah/shenandoahConcurrentRoots.hpp" #include "gc/shenandoah/shenandoahNormalMode.hpp" #include "gc/shenandoah/heuristics/shenandoahAdaptiveHeuristics.hpp" #include "gc/shenandoah/heuristics/shenandoahAggressiveHeuristics.hpp" @@ -32,6 +33,9 @@ void ShenandoahNormalMode::initialize_flags() const { SHENANDOAH_ERGO_ENABLE_FLAG(ExplicitGCInvokesConcurrent); SHENANDOAH_ERGO_ENABLE_FLAG(ShenandoahImplicitGCInvokesConcurrent); + if (ShenandoahConcurrentRoots::can_do_concurrent_class_unloading()) { + SHENANDOAH_ERGO_ENABLE_FLAG(ShenandoahSuspendibleWorkers); + } // Final configuration checks SHENANDOAH_CHECK_FLAG_SET(ShenandoahLoadRefBarrier); diff -r bfc8074ea4ef -r cfe31d2f935c src/hotspot/share/gc/shenandoah/shenandoahPacer.cpp --- a/src/hotspot/share/gc/shenandoah/shenandoahPacer.cpp Tue Nov 26 10:22:13 2019 +0000 +++ b/src/hotspot/share/gc/shenandoah/shenandoahPacer.cpp Fri Nov 29 10:02:07 2019 +0000 @@ -26,6 +26,7 @@ #include "gc/shenandoah/shenandoahFreeSet.hpp" #include "gc/shenandoah/shenandoahHeap.inline.hpp" #include "gc/shenandoah/shenandoahPacer.hpp" +#include "runtime/atomic.hpp" /* * In normal concurrent cycle, we have to pace the application to let GC finish. diff -r bfc8074ea4ef -r cfe31d2f935c src/hotspot/share/gc/shenandoah/shenandoahRootProcessor.cpp --- a/src/hotspot/share/gc/shenandoah/shenandoahRootProcessor.cpp Tue Nov 26 10:22:13 2019 +0000 +++ b/src/hotspot/share/gc/shenandoah/shenandoahRootProcessor.cpp Fri Nov 29 10:02:07 2019 +0000 @@ -27,8 +27,10 @@ #include "classfile/stringTable.hpp" #include "classfile/systemDictionary.hpp" #include "code/codeCache.hpp" +#include "gc/shenandoah/shenandoahClosures.inline.hpp" +#include "gc/shenandoah/shenandoahConcurrentRoots.hpp" #include "gc/shenandoah/shenandoahRootProcessor.inline.hpp" -#include "gc/shenandoah/shenandoahHeap.inline.hpp" +#include "gc/shenandoah/shenandoahHeap.hpp" #include "gc/shenandoah/shenandoahPhaseTimings.hpp" #include "gc/shenandoah/shenandoahStringDedup.hpp" #include "gc/shenandoah/shenandoahTimingTracker.hpp" @@ -159,14 +161,22 @@ _heap->phase_timings()->record_workers_end(_phase); } -ShenandoahRootEvacuator::ShenandoahRootEvacuator(uint n_workers, ShenandoahPhaseTimings::Phase phase, bool include_concurrent_roots) : +ShenandoahRootEvacuator::ShenandoahRootEvacuator(uint n_workers, + ShenandoahPhaseTimings::Phase phase, + bool include_concurrent_roots, + bool include_concurrent_code_roots) : ShenandoahRootProcessor(phase), _thread_roots(n_workers > 1), - _include_concurrent_roots(include_concurrent_roots) { + _include_concurrent_roots(include_concurrent_roots), + _include_concurrent_code_roots(include_concurrent_code_roots) { } void ShenandoahRootEvacuator::roots_do(uint worker_id, OopClosure* oops) { MarkingCodeBlobClosure blobsCl(oops, CodeBlobToOopClosure::FixRelocations); + ShenandoahCodeBlobAndDisarmClosure blobs_and_disarm_Cl(oops); + CodeBlobToOopClosure* codes_cl = ShenandoahConcurrentRoots::can_do_concurrent_class_unloading() ? + static_cast(&blobs_and_disarm_Cl) : + static_cast(&blobsCl); AlwaysTrueClosure always_true; _serial_roots.oops_do(oops, worker_id); @@ -178,8 +188,12 @@ _weak_roots.oops_do(oops, worker_id); } - _thread_roots.oops_do(oops, NULL, worker_id); - _code_roots.code_blobs_do(&blobsCl, worker_id); + if (_include_concurrent_code_roots) { + _code_roots.code_blobs_do(codes_cl, worker_id); + _thread_roots.oops_do(oops, NULL, worker_id); + } else { + _thread_roots.oops_do(oops, codes_cl, worker_id); + } _dedup_roots.oops_do(&always_true, oops, worker_id); } @@ -208,7 +222,11 @@ } void ShenandoahRootAdjuster::roots_do(uint worker_id, OopClosure* oops) { - CodeBlobToOopClosure adjust_code_closure(oops, CodeBlobToOopClosure::FixRelocations); + CodeBlobToOopClosure code_blob_cl(oops, CodeBlobToOopClosure::FixRelocations); + ShenandoahCodeBlobAndDisarmClosure blobs_and_disarm_Cl(oops); + CodeBlobToOopClosure* adjust_code_closure = ShenandoahConcurrentRoots::can_do_concurrent_class_unloading() ? + static_cast(&blobs_and_disarm_Cl) : + static_cast(&code_blob_cl); CLDToOopClosure adjust_cld_closure(oops, ClassLoaderData::_claim_strong); AlwaysTrueClosure always_true; @@ -217,7 +235,7 @@ _thread_roots.oops_do(oops, NULL, worker_id); _cld_roots.cld_do(&adjust_cld_closure, worker_id); - _code_roots.code_blobs_do(&adjust_code_closure, worker_id); + _code_roots.code_blobs_do(adjust_code_closure, worker_id); _serial_weak_roots.weak_oops_do(oops, worker_id); _weak_roots.oops_do(oops, worker_id); diff -r bfc8074ea4ef -r cfe31d2f935c src/hotspot/share/gc/shenandoah/shenandoahRootProcessor.hpp --- a/src/hotspot/share/gc/shenandoah/shenandoahRootProcessor.hpp Tue Nov 26 10:22:13 2019 +0000 +++ b/src/hotspot/share/gc/shenandoah/shenandoahRootProcessor.hpp Fri Nov 29 10:02:07 2019 +0000 @@ -277,11 +277,12 @@ ShenandoahSerialWeakRoots _serial_weak_roots; ShenandoahWeakRoots _weak_roots; ShenandoahStringDedupRoots _dedup_roots; - ShenandoahCodeCacheRoots _code_roots; + ShenandoahCodeCacheRoots _code_roots; bool _include_concurrent_roots; - + bool _include_concurrent_code_roots; public: - ShenandoahRootEvacuator(uint n_workers, ShenandoahPhaseTimings::Phase phase, bool include_concurrent_roots); + ShenandoahRootEvacuator(uint n_workers, ShenandoahPhaseTimings::Phase phase, + bool include_concurrent_roots, bool _include_concurrent_code_roots); void roots_do(uint worker_id, OopClosure* oops); }; @@ -297,7 +298,7 @@ ShenandoahSerialWeakRoots _serial_weak_roots; ShenandoahWeakRoots _weak_roots; ShenandoahStringDedupRoots _dedup_roots; - ShenandoahCodeCacheRoots _code_roots; + ShenandoahCodeCacheRoots _code_roots; public: ShenandoahRootUpdater(uint n_workers, ShenandoahPhaseTimings::Phase phase); diff -r bfc8074ea4ef -r cfe31d2f935c src/hotspot/share/gc/shenandoah/shenandoahRootProcessor.inline.hpp --- a/src/hotspot/share/gc/shenandoah/shenandoahRootProcessor.inline.hpp Tue Nov 26 10:22:13 2019 +0000 +++ b/src/hotspot/share/gc/shenandoah/shenandoahRootProcessor.inline.hpp Fri Nov 29 10:02:07 2019 +0000 @@ -28,6 +28,8 @@ #include "classfile/stringTable.hpp" #include "classfile/systemDictionary.hpp" #include "gc/shared/oopStorageParState.inline.hpp" +#include "gc/shenandoah/shenandoahClosures.inline.hpp" +#include "gc/shenandoah/shenandoahConcurrentRoots.hpp" #include "gc/shenandoah/shenandoahHeuristics.hpp" #include "gc/shenandoah/shenandoahRootProcessor.hpp" #include "gc/shenandoah/shenandoahTimingTracker.hpp" @@ -265,14 +267,19 @@ template void ShenandoahRootUpdater::roots_do(uint worker_id, IsAlive* is_alive, KeepAlive* keep_alive) { CodeBlobToOopClosure update_blobs(keep_alive, CodeBlobToOopClosure::FixRelocations); + ShenandoahCodeBlobAndDisarmClosure blobs_and_disarm_Cl(keep_alive); + CodeBlobToOopClosure* codes_cl = ShenandoahConcurrentRoots::can_do_concurrent_class_unloading() ? + static_cast(&blobs_and_disarm_Cl) : + static_cast(&update_blobs); + CLDToOopClosure clds(keep_alive, ClassLoaderData::_claim_strong); _serial_roots.oops_do(keep_alive, worker_id); _vm_roots.oops_do(keep_alive, worker_id); - _thread_roots.oops_do(keep_alive, NULL, worker_id); _cld_roots.cld_do(&clds, worker_id); _code_roots.code_blobs_do(&update_blobs, worker_id); + _thread_roots.oops_do(keep_alive, NULL, worker_id); _serial_weak_roots.weak_oops_do(is_alive, keep_alive, worker_id); _weak_roots.weak_oops_do(is_alive, keep_alive, worker_id); diff -r bfc8074ea4ef -r cfe31d2f935c src/hotspot/share/gc/shenandoah/shenandoahRootVerifier.cpp --- a/src/hotspot/share/gc/shenandoah/shenandoahRootVerifier.cpp Tue Nov 26 10:22:13 2019 +0000 +++ b/src/hotspot/share/gc/shenandoah/shenandoahRootVerifier.cpp Fri Nov 29 10:02:07 2019 +0000 @@ -43,7 +43,7 @@ // Check for overflow of number of root types. STATIC_ASSERT((static_cast(ShenandoahRootVerifier::AllRoots) + 1) > static_cast(ShenandoahRootVerifier::AllRoots)); -ShenandoahRootVerifier::ShenandoahRootVerifier() : _types(AllRoots) { +ShenandoahRootVerifier::ShenandoahRootVerifier(RootTypes types) : _types(types) { } void ShenandoahRootVerifier::excludes(RootTypes types) { diff -r bfc8074ea4ef -r cfe31d2f935c src/hotspot/share/gc/shenandoah/shenandoahRootVerifier.hpp --- a/src/hotspot/share/gc/shenandoah/shenandoahRootVerifier.hpp Tue Nov 26 10:22:13 2019 +0000 +++ b/src/hotspot/share/gc/shenandoah/shenandoahRootVerifier.hpp Fri Nov 29 10:02:07 2019 +0000 @@ -30,6 +30,7 @@ class ShenandoahRootVerifier : public StackObj { public: enum RootTypes { + None = 0, SerialRoots = 1 << 0, ThreadRoots = 1 << 1, CodeRoots = 1 << 2, @@ -44,7 +45,7 @@ RootTypes _types; public: - ShenandoahRootVerifier(); + ShenandoahRootVerifier(RootTypes types = AllRoots); void excludes(RootTypes types); void oops_do(OopClosure* cl); diff -r bfc8074ea4ef -r cfe31d2f935c src/hotspot/share/gc/shenandoah/shenandoahSharedVariables.hpp --- a/src/hotspot/share/gc/shenandoah/shenandoahSharedVariables.hpp Tue Nov 26 10:22:13 2019 +0000 +++ b/src/hotspot/share/gc/shenandoah/shenandoahSharedVariables.hpp Fri Nov 29 10:02:07 2019 +0000 @@ -25,7 +25,7 @@ #define SHARE_GC_SHENANDOAH_SHENANDOAHSHAREDVARIABLES_HPP #include "memory/allocation.hpp" -#include "runtime/orderAccess.hpp" +#include "runtime/atomic.hpp" typedef jbyte ShenandoahSharedValue; diff -r bfc8074ea4ef -r cfe31d2f935c src/hotspot/share/gc/shenandoah/shenandoahTaskqueue.hpp --- a/src/hotspot/share/gc/shenandoah/shenandoahTaskqueue.hpp Tue Nov 26 10:22:13 2019 +0000 +++ b/src/hotspot/share/gc/shenandoah/shenandoahTaskqueue.hpp Fri Nov 29 10:02:07 2019 +0000 @@ -26,6 +26,7 @@ #include "gc/shared/owstTaskTerminator.hpp" #include "gc/shared/taskqueue.hpp" #include "memory/allocation.hpp" +#include "runtime/atomic.hpp" #include "runtime/mutex.hpp" #include "runtime/thread.hpp" diff -r bfc8074ea4ef -r cfe31d2f935c src/hotspot/share/gc/shenandoah/shenandoahThreadLocalData.hpp --- a/src/hotspot/share/gc/shenandoah/shenandoahThreadLocalData.hpp Tue Nov 26 10:22:13 2019 +0000 +++ b/src/hotspot/share/gc/shenandoah/shenandoahThreadLocalData.hpp Fri Nov 29 10:02:07 2019 +0000 @@ -26,6 +26,7 @@ #include "gc/shared/plab.hpp" #include "gc/shenandoah/shenandoahBarrierSet.hpp" +#include "gc/shenandoah/shenandoahCodeRoots.hpp" #include "gc/shenandoah/shenandoahSATBMarkQueueSet.hpp" #include "runtime/thread.hpp" #include "utilities/debug.hpp" @@ -43,6 +44,7 @@ size_t _gclab_size; uint _worker_id; bool _force_satb_flush; + int _disarmed_value; ShenandoahThreadLocalData() : _gc_state(0), @@ -125,6 +127,7 @@ assert(data(thread)->_gclab == NULL, "Only initialize once"); data(thread)->_gclab = new PLAB(PLAB::min_size()); data(thread)->_gclab_size = 0; + data(thread)->_disarmed_value = ShenandoahCodeRoots::disarmed_value(); } static PLAB* gclab(Thread* thread) { @@ -139,6 +142,10 @@ data(thread)->_gclab_size = v; } + static void set_disarmed_value(Thread* thread, int value) { + data(thread)->_disarmed_value = value; + } + #ifdef ASSERT static void set_evac_allowed(Thread* thread, bool evac_allowed) { if (evac_allowed) { @@ -170,6 +177,9 @@ return Thread::gc_data_offset() + byte_offset_of(ShenandoahThreadLocalData, _gc_state); } + static ByteSize disarmed_value_offset() { + return Thread::gc_data_offset() + byte_offset_of(ShenandoahThreadLocalData, _disarmed_value); + } }; #endif // SHARE_GC_SHENANDOAH_SHENANDOAHTHREADLOCALDATA_HPP diff -r bfc8074ea4ef -r cfe31d2f935c src/hotspot/share/gc/shenandoah/shenandoahUnload.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/hotspot/share/gc/shenandoah/shenandoahUnload.cpp Fri Nov 29 10:02:07 2019 +0000 @@ -0,0 +1,186 @@ +/* + * Copyright (c) 2019, Red Hat, Inc. All rights reserved. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +#include "precompiled.hpp" + +#include "classfile/classLoaderDataGraph.hpp" +#include "classfile/systemDictionary.hpp" +#include "code/codeBehaviours.hpp" +#include "code/codeCache.hpp" +#include "code/dependencyContext.hpp" +#include "gc/shared/gcBehaviours.hpp" +#include "gc/shared/suspendibleThreadSet.hpp" +#include "gc/shenandoah/shenandoahClosures.inline.hpp" +#include "gc/shenandoah/shenandoahCodeRoots.hpp" +#include "gc/shenandoah/shenandoahConcurrentRoots.hpp" +#include "gc/shenandoah/shenandoahNMethod.inline.hpp" +#include "gc/shenandoah/shenandoahLock.hpp" +#include "gc/shenandoah/shenandoahRootProcessor.hpp" +#include "gc/shenandoah/shenandoahUnload.hpp" +#include "gc/shenandoah/shenandoahVerifier.hpp" +#include "memory/iterator.hpp" +#include "memory/resourceArea.hpp" +#include "oops/access.inline.hpp" + +class ShenandoahIsUnloadingOopClosure : public OopClosure { +private: + ShenandoahMarkingContext* _marking_context; + bool _is_unloading; + +public: + ShenandoahIsUnloadingOopClosure() : + _marking_context(ShenandoahHeap::heap()->marking_context()), + _is_unloading(false) { + } + + virtual void do_oop(oop* p) { + if (_is_unloading) { + return; + } + + const oop o = RawAccess<>::oop_load(p); + if (!CompressedOops::is_null(o) && + _marking_context->is_complete() && + !_marking_context->is_marked(o)) { + _is_unloading = true; + } + } + + virtual void do_oop(narrowOop* p) { + ShouldNotReachHere(); + } + + bool is_unloading() const { + return _is_unloading; + } +}; + +class ShenandoahIsUnloadingBehaviour : public IsUnloadingBehaviour { +public: + virtual bool is_unloading(CompiledMethod* method) const { + nmethod* const nm = method->as_nmethod(); + guarantee(ShenandoahHeap::heap()->is_evacuation_in_progress(), "Only this phase"); + ShenandoahNMethod* data = ShenandoahNMethod::gc_data(nm); + ShenandoahReentrantLocker locker(data->lock()); + ShenandoahIsUnloadingOopClosure cl; + data->oops_do(&cl); + return cl.is_unloading(); + } +}; + +class ShenandoahCompiledICProtectionBehaviour : public CompiledICProtectionBehaviour { +public: + virtual bool lock(CompiledMethod* method) { + nmethod* const nm = method->as_nmethod(); + ShenandoahReentrantLock* const lock = ShenandoahNMethod::lock_for_nmethod(nm); + assert(lock != NULL, "Not yet registered?"); + lock->lock(); + return true; + } + + virtual void unlock(CompiledMethod* method) { + nmethod* const nm = method->as_nmethod(); + ShenandoahReentrantLock* const lock = ShenandoahNMethod::lock_for_nmethod(nm); + assert(lock != NULL, "Not yet registered?"); + lock->unlock(); + } + + virtual bool is_safe(CompiledMethod* method) { + if (SafepointSynchronize::is_at_safepoint()) { + return true; + } + + nmethod* const nm = method->as_nmethod(); + ShenandoahReentrantLock* const lock = ShenandoahNMethod::lock_for_nmethod(nm); + assert(lock != NULL, "Not yet registered?"); + return lock->owned_by_self(); + } +}; + +ShenandoahUnload::ShenandoahUnload() { + if (ShenandoahConcurrentRoots::can_do_concurrent_class_unloading()) { + static ShenandoahIsUnloadingBehaviour is_unloading_behaviour; + IsUnloadingBehaviour::set_current(&is_unloading_behaviour); + + static ShenandoahCompiledICProtectionBehaviour ic_protection_behaviour; + CompiledICProtectionBehaviour::set_current(&ic_protection_behaviour); + } +} + +void ShenandoahUnload::prepare() { + assert(SafepointSynchronize::is_at_safepoint(), "Should be at safepoint"); + assert(ShenandoahConcurrentRoots::can_do_concurrent_class_unloading(), "Sanity"); + CodeCache::increment_unloading_cycle(); + DependencyContext::cleaning_start(); +} + +void ShenandoahUnload::unlink() { + SuspendibleThreadSetJoiner sts; + bool unloading_occurred; + ShenandoahHeap* const heap = ShenandoahHeap::heap(); + { + MutexLocker cldg_ml(ClassLoaderDataGraph_lock); + unloading_occurred = SystemDictionary::do_unloading(heap->gc_timer()); + } + + Klass::clean_weak_klass_links(unloading_occurred); + ShenandoahCodeRoots::unlink(ShenandoahHeap::heap()->workers(), unloading_occurred); + DependencyContext::cleaning_end(); +} + +void ShenandoahUnload::purge() { + { + SuspendibleThreadSetJoiner sts; + ShenandoahCodeRoots::purge(ShenandoahHeap::heap()->workers()); + } + + ClassLoaderDataGraph::purge(); + CodeCache::purge_exception_caches(); +} + +class ShenandoahUnloadRendezvousClosure : public ThreadClosure { +public: + void do_thread(Thread* thread) {} +}; + +void ShenandoahUnload::unload() { + assert(ShenandoahConcurrentRoots::can_do_concurrent_class_unloading(), "Why we here?"); + if (!ShenandoahHeap::heap()->is_evacuation_in_progress()) { + return; + } + + // Unlink stale metadata and nmethods + unlink(); + + // Make sure stale metadata and nmethods are no longer observable + ShenandoahUnloadRendezvousClosure cl; + Handshake::execute(&cl); + + // Purge stale metadata and nmethods that were unlinked + purge(); +} + +void ShenandoahUnload::finish() { + MetaspaceGC::compute_new_size(); + MetaspaceUtils::verify_metrics(); +} diff -r bfc8074ea4ef -r cfe31d2f935c src/hotspot/share/gc/shenandoah/shenandoahUnload.hpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/hotspot/share/gc/shenandoah/shenandoahUnload.hpp Fri Nov 29 10:02:07 2019 +0000 @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2019, Red Hat, Inc. All rights reserved. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +#ifndef SHARE_GC_SHENANDOAH_SHENANDOAHCLASSUNLOAD_HPP +#define SHARE_GC_SHENANDOAH_SHENANDOAHCLASSUNLOAD_HPP + +#include "memory/allocation.hpp" + +class ShenandoahHeap; + +class ShenandoahUnload { +public: + ShenandoahUnload(); + void prepare(); + void unload(); + void finish(); +private: + void unlink(); + void purge(); +}; + +#endif // SHARE_GC_SHENANDOAH_SHENANDOAHCLASSUNLOAD_HPP diff -r bfc8074ea4ef -r cfe31d2f935c src/hotspot/share/gc/shenandoah/shenandoahVerifier.cpp --- a/src/hotspot/share/gc/shenandoah/shenandoahVerifier.cpp Tue Nov 26 10:22:13 2019 +0000 +++ b/src/hotspot/share/gc/shenandoah/shenandoahVerifier.cpp Fri Nov 29 10:02:07 2019 +0000 @@ -35,6 +35,8 @@ #include "memory/iterator.inline.hpp" #include "memory/resourceArea.hpp" #include "oops/compressedOops.inline.hpp" +#include "runtime/atomic.hpp" +#include "runtime/orderAccess.hpp" #include "utilities/align.hpp" // Avoid name collision on verify_oop (defined in macroAssembler_arm.hpp) @@ -1007,6 +1009,13 @@ verifier.oops_do(&cl); } +void ShenandoahVerifier::verify_roots_in_to_space_except(ShenandoahRootVerifier::RootTypes types) { + ShenandoahRootVerifier verifier; + verifier.excludes(types); + ShenandoahVerifyInToSpaceClosure cl; + verifier.oops_do(&cl); +} + void ShenandoahVerifier::verify_roots_no_forwarded() { ShenandoahRootVerifier verifier; ShenandoahVerifyNoForwared cl; diff -r bfc8074ea4ef -r cfe31d2f935c src/hotspot/share/gc/shenandoah/shenandoahVerifier.hpp --- a/src/hotspot/share/gc/shenandoah/shenandoahVerifier.hpp Tue Nov 26 10:22:13 2019 +0000 +++ b/src/hotspot/share/gc/shenandoah/shenandoahVerifier.hpp Fri Nov 29 10:02:07 2019 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2018, Red Hat, Inc. All rights reserved. + * Copyright (c) 2017, 2019, Red Hat, Inc. All rights reserved. * * 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 @@ -190,6 +190,8 @@ // Roots should only contain to-space oops void verify_roots_in_to_space(); + void verify_roots_in_to_space_except(ShenandoahRootVerifier::RootTypes types); + void verify_roots_no_forwarded(); void verify_roots_no_forwarded_except(ShenandoahRootVerifier::RootTypes types); }; diff -r bfc8074ea4ef -r cfe31d2f935c src/hotspot/share/gc/shenandoah/shenandoah_globals.hpp --- a/src/hotspot/share/gc/shenandoah/shenandoah_globals.hpp Tue Nov 26 10:22:13 2019 +0000 +++ b/src/hotspot/share/gc/shenandoah/shenandoah_globals.hpp Fri Nov 29 10:02:07 2019 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2018, Red Hat, Inc. All rights reserved. + * Copyright (c) 2016, 2019, Red Hat, Inc. All rights reserved. * * 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 @@ -86,7 +86,7 @@ "References get processed at every Nth GC cycle. Set to zero " \ "to disable reference processing.") \ \ - experimental(uintx, ShenandoahUnloadClassesFrequency, 5, \ + experimental(uintx, ShenandoahUnloadClassesFrequency, 1, \ "How often should classes get unloaded. " \ "Class unloading is performed at every Nth GC cycle. " \ "Set to zero to disable class unloading during concurrent GC.") \ diff -r bfc8074ea4ef -r cfe31d2f935c src/hotspot/share/gc/z/zBarrierSetNMethod.cpp --- a/src/hotspot/share/gc/z/zBarrierSetNMethod.cpp Tue Nov 26 10:22:13 2019 +0000 +++ b/src/hotspot/share/gc/z/zBarrierSetNMethod.cpp Fri Nov 29 10:02:07 2019 +0000 @@ -61,12 +61,10 @@ return true; } -int ZBarrierSetNMethod::disarmed_value() const { - // We override the default BarrierSetNMethod::disarmed_value() since - // this can be called by GC threads, which doesn't keep an up to date - // address_bad_mask. - const uintptr_t disarmed_addr = ((uintptr_t)&ZAddressBadMask) + ZNMethodDisarmedOffset; - return *((int*)disarmed_addr); +int* ZBarrierSetNMethod::disarmed_value_address() const { + const uintptr_t mask_addr = reinterpret_cast(&ZAddressBadMask); + const uintptr_t disarmed_addr = mask_addr + ZNMethodDisarmedOffset; + return reinterpret_cast(disarmed_addr); } ByteSize ZBarrierSetNMethod::thread_disarmed_offset() const { diff -r bfc8074ea4ef -r cfe31d2f935c src/hotspot/share/gc/z/zBarrierSetNMethod.hpp --- a/src/hotspot/share/gc/z/zBarrierSetNMethod.hpp Tue Nov 26 10:22:13 2019 +0000 +++ b/src/hotspot/share/gc/z/zBarrierSetNMethod.hpp Fri Nov 29 10:02:07 2019 +0000 @@ -31,11 +31,11 @@ class ZBarrierSetNMethod : public BarrierSetNMethod { protected: - virtual int disarmed_value() const; virtual bool nmethod_entry_barrier(nmethod* nm); public: virtual ByteSize thread_disarmed_offset() const; + virtual int* disarmed_value_address() const; }; #endif // SHARE_GC_Z_ZBARRIERSETNMETHOD_HPP diff -r bfc8074ea4ef -r cfe31d2f935c src/hotspot/share/gc/z/zLiveMap.cpp --- a/src/hotspot/share/gc/z/zLiveMap.cpp Tue Nov 26 10:22:13 2019 +0000 +++ b/src/hotspot/share/gc/z/zLiveMap.cpp Fri Nov 29 10:02:07 2019 +0000 @@ -28,7 +28,6 @@ #include "gc/z/zThread.inline.hpp" #include "logging/log.hpp" #include "runtime/atomic.hpp" -#include "runtime/orderAccess.hpp" #include "utilities/debug.hpp" static const ZStatCounter ZCounterMarkSeqNumResetContention("Contention", "Mark SeqNum Reset Contention", ZStatUnitOpsPerSecond); diff -r bfc8074ea4ef -r cfe31d2f935c src/hotspot/share/gc/z/zLiveMap.inline.hpp --- a/src/hotspot/share/gc/z/zLiveMap.inline.hpp Tue Nov 26 10:22:13 2019 +0000 +++ b/src/hotspot/share/gc/z/zLiveMap.inline.hpp Fri Nov 29 10:02:07 2019 +0000 @@ -30,7 +30,6 @@ #include "gc/z/zOop.inline.hpp" #include "gc/z/zUtils.inline.hpp" #include "runtime/atomic.hpp" -#include "runtime/orderAccess.hpp" #include "utilities/bitMap.inline.hpp" #include "utilities/debug.hpp" diff -r bfc8074ea4ef -r cfe31d2f935c src/hotspot/share/gc/z/zMark.cpp --- a/src/hotspot/share/gc/z/zMark.cpp Tue Nov 26 10:22:13 2019 +0000 +++ b/src/hotspot/share/gc/z/zMark.cpp Fri Nov 29 10:02:07 2019 +0000 @@ -44,7 +44,6 @@ #include "oops/oop.inline.hpp" #include "runtime/atomic.hpp" #include "runtime/handshake.hpp" -#include "runtime/orderAccess.hpp" #include "runtime/prefetch.inline.hpp" #include "runtime/thread.hpp" #include "utilities/align.hpp" diff -r bfc8074ea4ef -r cfe31d2f935c src/hotspot/share/gc/z/zMarkTerminate.inline.hpp --- a/src/hotspot/share/gc/z/zMarkTerminate.inline.hpp Tue Nov 26 10:22:13 2019 +0000 +++ b/src/hotspot/share/gc/z/zMarkTerminate.inline.hpp Fri Nov 29 10:02:07 2019 +0000 @@ -25,7 +25,6 @@ #define SHARE_GC_Z_ZMARKTERMINATE_INLINE_HPP #include "runtime/atomic.hpp" -#include "runtime/orderAccess.hpp" inline ZMarkTerminate::ZMarkTerminate() : _nworkers(0), diff -r bfc8074ea4ef -r cfe31d2f935c src/hotspot/share/gc/z/zNMethod.cpp --- a/src/hotspot/share/gc/z/zNMethod.cpp Tue Nov 26 10:22:13 2019 +0000 +++ b/src/hotspot/share/gc/z/zNMethod.cpp Fri Nov 29 10:02:07 2019 +0000 @@ -41,7 +41,6 @@ #include "memory/resourceArea.hpp" #include "memory/universe.hpp" #include "runtime/atomic.hpp" -#include "runtime/orderAccess.hpp" #include "utilities/debug.hpp" static ZNMethodData* gc_data(const nmethod* nm) { diff -r bfc8074ea4ef -r cfe31d2f935c src/hotspot/share/gc/z/zNMethodData.cpp --- a/src/hotspot/share/gc/z/zNMethodData.cpp Tue Nov 26 10:22:13 2019 +0000 +++ b/src/hotspot/share/gc/z/zNMethodData.cpp Fri Nov 29 10:02:07 2019 +0000 @@ -27,7 +27,6 @@ #include "gc/z/zNMethodData.hpp" #include "memory/allocation.hpp" #include "runtime/atomic.hpp" -#include "runtime/orderAccess.hpp" #include "utilities/align.hpp" #include "utilities/debug.hpp" #include "utilities/growableArray.hpp" diff -r bfc8074ea4ef -r cfe31d2f935c src/hotspot/share/gc/z/zNMethodTable.cpp --- a/src/hotspot/share/gc/z/zNMethodTable.cpp Tue Nov 26 10:22:13 2019 +0000 +++ b/src/hotspot/share/gc/z/zNMethodTable.cpp Fri Nov 29 10:02:07 2019 +0000 @@ -42,8 +42,6 @@ #include "memory/allocation.hpp" #include "memory/iterator.hpp" #include "memory/resourceArea.hpp" -#include "runtime/atomic.hpp" -#include "runtime/orderAccess.hpp" #include "utilities/debug.hpp" ZNMethodTableEntry* ZNMethodTable::_table = NULL; diff -r bfc8074ea4ef -r cfe31d2f935c src/hotspot/share/gc/z/zReferenceProcessor.cpp --- a/src/hotspot/share/gc/z/zReferenceProcessor.cpp Tue Nov 26 10:22:13 2019 +0000 +++ b/src/hotspot/share/gc/z/zReferenceProcessor.cpp Fri Nov 29 10:02:07 2019 +0000 @@ -34,6 +34,7 @@ #include "gc/z/zUtils.inline.hpp" #include "gc/z/zValue.inline.hpp" #include "memory/universe.hpp" +#include "runtime/atomic.hpp" #include "runtime/mutexLocker.hpp" #include "runtime/os.hpp" diff -r bfc8074ea4ef -r cfe31d2f935c src/hotspot/share/interpreter/oopMapCache.cpp --- a/src/hotspot/share/interpreter/oopMapCache.cpp Tue Nov 26 10:22:13 2019 +0000 +++ b/src/hotspot/share/interpreter/oopMapCache.cpp Fri Nov 29 10:02:07 2019 +0000 @@ -29,6 +29,7 @@ #include "memory/allocation.inline.hpp" #include "memory/resourceArea.hpp" #include "oops/oop.inline.hpp" +#include "runtime/atomic.hpp" #include "runtime/handles.inline.hpp" #include "runtime/signature.hpp" diff -r bfc8074ea4ef -r cfe31d2f935c src/hotspot/share/jfr/recorder/service/jfrRecorderService.cpp --- a/src/hotspot/share/jfr/recorder/service/jfrRecorderService.cpp Tue Nov 26 10:22:13 2019 +0000 +++ b/src/hotspot/share/jfr/recorder/service/jfrRecorderService.cpp Fri Nov 29 10:02:07 2019 +0000 @@ -46,7 +46,6 @@ #include "jfr/utilities/jfrTypes.hpp" #include "logging/log.hpp" #include "memory/resourceArea.hpp" -#include "runtime/atomic.hpp" #include "runtime/handles.inline.hpp" #include "runtime/mutexLocker.hpp" #include "runtime/orderAccess.hpp" diff -r bfc8074ea4ef -r cfe31d2f935c src/hotspot/share/jfr/recorder/storage/jfrStorage.cpp --- a/src/hotspot/share/jfr/recorder/storage/jfrStorage.cpp Tue Nov 26 10:22:13 2019 +0000 +++ b/src/hotspot/share/jfr/recorder/storage/jfrStorage.cpp Fri Nov 29 10:02:07 2019 +0000 @@ -39,7 +39,6 @@ #include "jfr/writers/jfrNativeEventWriter.hpp" #include "logging/log.hpp" #include "runtime/mutexLocker.hpp" -#include "runtime/orderAccess.hpp" #include "runtime/os.inline.hpp" #include "runtime/safepoint.hpp" #include "runtime/thread.hpp" diff -r bfc8074ea4ef -r cfe31d2f935c src/hotspot/share/jfr/recorder/stringpool/jfrStringPool.cpp --- a/src/hotspot/share/jfr/recorder/stringpool/jfrStringPool.cpp Tue Nov 26 10:22:13 2019 +0000 +++ b/src/hotspot/share/jfr/recorder/stringpool/jfrStringPool.cpp Fri Nov 29 10:02:07 2019 +0000 @@ -33,8 +33,8 @@ #include "jfr/recorder/stringpool/jfrStringPoolWriter.hpp" #include "jfr/utilities/jfrTypes.hpp" #include "logging/log.hpp" +#include "runtime/atomic.hpp" #include "runtime/mutexLocker.hpp" -#include "runtime/orderAccess.hpp" #include "runtime/safepoint.hpp" #include "runtime/thread.inline.hpp" diff -r bfc8074ea4ef -r cfe31d2f935c src/hotspot/share/jfr/utilities/jfrHashtable.hpp --- a/src/hotspot/share/jfr/utilities/jfrHashtable.hpp Tue Nov 26 10:22:13 2019 +0000 +++ b/src/hotspot/share/jfr/utilities/jfrHashtable.hpp Fri Nov 29 10:02:07 2019 +0000 @@ -26,7 +26,7 @@ #define SHARE_JFR_UTILITIES_JFRHASHTABLE_HPP #include "jfr/utilities/jfrAllocation.hpp" -#include "runtime/orderAccess.hpp" +#include "runtime/atomic.hpp" #include "utilities/debug.hpp" #include "utilities/macros.hpp" diff -r bfc8074ea4ef -r cfe31d2f935c src/hotspot/share/jvmci/jvmciCompiler.hpp --- a/src/hotspot/share/jvmci/jvmciCompiler.hpp Tue Nov 26 10:22:13 2019 +0000 +++ b/src/hotspot/share/jvmci/jvmciCompiler.hpp Fri Nov 29 10:02:07 2019 +0000 @@ -25,6 +25,7 @@ #define SHARE_JVMCI_JVMCICOMPILER_HPP #include "compiler/abstractCompiler.hpp" +#include "runtime/atomic.hpp" class JVMCICompiler : public AbstractCompiler { private: diff -r bfc8074ea4ef -r cfe31d2f935c src/hotspot/share/jvmci/jvmciCompilerToVM.cpp --- a/src/hotspot/share/jvmci/jvmciCompilerToVM.cpp Tue Nov 26 10:22:13 2019 +0000 +++ b/src/hotspot/share/jvmci/jvmciCompilerToVM.cpp Fri Nov 29 10:02:07 2019 +0000 @@ -42,6 +42,7 @@ #include "oops/method.inline.hpp" #include "oops/typeArrayOop.inline.hpp" #include "prims/nativeLookup.hpp" +#include "runtime/atomic.hpp" #include "runtime/deoptimization.hpp" #include "runtime/fieldDescriptor.inline.hpp" #include "runtime/frame.inline.hpp" diff -r bfc8074ea4ef -r cfe31d2f935c src/hotspot/share/jvmci/jvmciRuntime.cpp --- a/src/hotspot/share/jvmci/jvmciRuntime.cpp Tue Nov 26 10:22:13 2019 +0000 +++ b/src/hotspot/share/jvmci/jvmciRuntime.cpp Fri Nov 29 10:02:07 2019 +0000 @@ -34,6 +34,7 @@ #include "oops/method.inline.hpp" #include "oops/objArrayKlass.hpp" #include "oops/oop.inline.hpp" +#include "runtime/atomic.hpp" #include "runtime/biasedLocking.hpp" #include "runtime/deoptimization.hpp" #include "runtime/fieldDescriptor.inline.hpp" diff -r bfc8074ea4ef -r cfe31d2f935c src/hotspot/share/jvmci/metadataHandleBlock.cpp --- a/src/hotspot/share/jvmci/metadataHandleBlock.cpp Tue Nov 26 10:22:13 2019 +0000 +++ b/src/hotspot/share/jvmci/metadataHandleBlock.cpp Fri Nov 29 10:02:07 2019 +0000 @@ -23,6 +23,7 @@ #include "precompiled.hpp" #include "jvmci/metadataHandleBlock.hpp" +#include "runtime/atomic.hpp" MetadataHandleBlock* MetadataHandleBlock::_last = NULL; intptr_t MetadataHandleBlock::_free_list = 0; diff -r bfc8074ea4ef -r cfe31d2f935c src/hotspot/share/logging/logDecorations.cpp --- a/src/hotspot/share/logging/logDecorations.cpp Tue Nov 26 10:22:13 2019 +0000 +++ b/src/hotspot/share/logging/logDecorations.cpp Fri Nov 29 10:02:07 2019 +0000 @@ -26,7 +26,6 @@ #include "logging/logConfiguration.hpp" #include "logging/logDecorations.hpp" #include "runtime/atomic.hpp" -#include "runtime/orderAccess.hpp" #include "runtime/os.inline.hpp" #include "runtime/thread.inline.hpp" #include "services/management.hpp" diff -r bfc8074ea4ef -r cfe31d2f935c src/hotspot/share/memory/allocation.cpp --- a/src/hotspot/share/memory/allocation.cpp Tue Nov 26 10:22:13 2019 +0000 +++ b/src/hotspot/share/memory/allocation.cpp Fri Nov 29 10:02:07 2019 +0000 @@ -28,7 +28,6 @@ #include "memory/arena.hpp" #include "memory/metaspaceShared.hpp" #include "memory/resourceArea.hpp" -#include "runtime/atomic.hpp" #include "runtime/os.hpp" #include "runtime/task.hpp" #include "runtime/threadCritical.hpp" diff -r bfc8074ea4ef -r cfe31d2f935c src/hotspot/share/memory/arena.cpp --- a/src/hotspot/share/memory/arena.cpp Tue Nov 26 10:22:13 2019 +0000 +++ b/src/hotspot/share/memory/arena.cpp Fri Nov 29 10:02:07 2019 +0000 @@ -27,7 +27,6 @@ #include "memory/allocation.inline.hpp" #include "memory/metaspaceShared.hpp" #include "memory/resourceArea.hpp" -#include "runtime/atomic.hpp" #include "runtime/os.hpp" #include "runtime/task.hpp" #include "runtime/threadCritical.hpp" @@ -325,7 +324,7 @@ // change the size void Arena::set_size_in_bytes(size_t size) { if (_size_in_bytes != size) { - long delta = (long)(size - size_in_bytes()); + ssize_t delta = size - size_in_bytes(); _size_in_bytes = size; MemTracker::record_arena_size_change(delta, _flags); } diff -r bfc8074ea4ef -r cfe31d2f935c src/hotspot/share/memory/filemap.cpp --- a/src/hotspot/share/memory/filemap.cpp Tue Nov 26 10:22:13 2019 +0000 +++ b/src/hotspot/share/memory/filemap.cpp Fri Nov 29 10:02:07 2019 +0000 @@ -1385,14 +1385,6 @@ } - DEBUG_ONLY(if (addr_delta == 0 && ArchiveRelocationMode == 1) { - // This is for simulating mmap failures at the requested address. We do it here (instead - // of MetaspaceShared::map_archives) so we can thoroughly test the code for failure handling - // (releasing all allocated resource, etc). - log_info(cds)("ArchiveRelocationMode == 1: always map archive(s) at an alternative address"); - return MAP_ARCHIVE_MMAP_FAILURE; - }); - header()->set_mapped_base_address(header()->requested_base_address() + addr_delta); if (addr_delta != 0 && !relocate_pointers(addr_delta)) { return MAP_ARCHIVE_OTHER_FAILURE; @@ -1446,12 +1438,14 @@ MemTracker::record_virtual_memory_type((address)requested_addr, mtClassShared); } - if (MetaspaceShared::use_windows_memory_mapping() && addr_delta != 0) { + if (MetaspaceShared::use_windows_memory_mapping() && rs.is_reserved()) { // This is the second time we try to map the archive(s). We have already created a ReservedSpace // that covers all the FileMapRegions to ensure all regions can be mapped. However, Windows // can't mmap into a ReservedSpace, so we just os::read() the data. We're going to patch all the // regions anyway, so there's no benefit for mmap anyway. if (!read_region(i, requested_addr, size)) { + log_info(cds)("Failed to read %s shared space into reserved space at " INTPTR_FORMAT, + shared_region_name[i], p2i(requested_addr)); return MAP_ARCHIVE_OTHER_FAILURE; // oom or I/O error. } } else { @@ -1459,7 +1453,8 @@ requested_addr, size, si->read_only(), si->allow_exec()); if (base != requested_addr) { - log_info(cds)("Unable to map %s shared space at required address.", shared_region_name[i]); + log_info(cds)("Unable to map %s shared space at " INTPTR_FORMAT, + shared_region_name[i], p2i(requested_addr)); _memory_mapping_failed = true; return MAP_ARCHIVE_MMAP_FAILURE; } @@ -1468,7 +1463,7 @@ si->set_mapped_base(requested_addr); if (!rs.is_reserved()) { - // When mapping on Windows with (addr_delta == 0), we don't reserve the address space for the regions + // When mapping on Windows for the first attempt, we don't reserve the address space for the regions // (Windows can't mmap into a ReservedSpace). In this case, NMT requires we call it after // os::map_memory has succeeded. assert(MetaspaceShared::use_windows_memory_mapping(), "Windows memory mapping only"); diff -r bfc8074ea4ef -r cfe31d2f935c src/hotspot/share/memory/metaspace.cpp --- a/src/hotspot/share/memory/metaspace.cpp Tue Nov 26 10:22:13 2019 +0000 +++ b/src/hotspot/share/memory/metaspace.cpp Fri Nov 29 10:02:07 2019 +0000 @@ -40,8 +40,8 @@ #include "memory/metaspaceTracer.hpp" #include "memory/universe.hpp" #include "oops/compressedOops.hpp" +#include "runtime/atomic.hpp" #include "runtime/init.hpp" -#include "runtime/orderAccess.hpp" #include "services/memTracker.hpp" #include "utilities/copy.hpp" #include "utilities/debug.hpp" diff -r bfc8074ea4ef -r cfe31d2f935c src/hotspot/share/memory/metaspace/virtualSpaceList.cpp --- a/src/hotspot/share/memory/metaspace/virtualSpaceList.cpp Tue Nov 26 10:22:13 2019 +0000 +++ b/src/hotspot/share/memory/metaspace/virtualSpaceList.cpp Fri Nov 29 10:02:07 2019 +0000 @@ -32,6 +32,7 @@ #include "memory/metaspace/metaspaceCommon.hpp" #include "memory/metaspace/virtualSpaceList.hpp" #include "memory/metaspace/virtualSpaceNode.hpp" +#include "runtime/atomic.hpp" #include "runtime/orderAccess.hpp" #include "runtime/mutexLocker.hpp" #include "runtime/safepoint.hpp" @@ -444,4 +445,3 @@ #endif // ASSERT } // namespace metaspace - diff -r bfc8074ea4ef -r cfe31d2f935c src/hotspot/share/memory/metaspace/virtualSpaceNode.cpp --- a/src/hotspot/share/memory/metaspace/virtualSpaceNode.cpp Tue Nov 26 10:22:13 2019 +0000 +++ b/src/hotspot/share/memory/metaspace/virtualSpaceNode.cpp Fri Nov 29 10:02:07 2019 +0000 @@ -34,6 +34,7 @@ #include "memory/metaspace/occupancyMap.hpp" #include "memory/metaspace/virtualSpaceNode.hpp" #include "memory/virtualspace.hpp" +#include "runtime/atomic.hpp" #include "runtime/os.hpp" #include "services/memTracker.hpp" #include "utilities/copy.hpp" @@ -585,4 +586,3 @@ } } // namespace metaspace - diff -r bfc8074ea4ef -r cfe31d2f935c src/hotspot/share/memory/metaspaceShared.cpp --- a/src/hotspot/share/memory/metaspaceShared.cpp Tue Nov 26 10:22:13 2019 +0000 +++ b/src/hotspot/share/memory/metaspaceShared.cpp Fri Nov 29 10:02:07 2019 +0000 @@ -2147,6 +2147,19 @@ MapArchiveResult dynamic_result = (static_result == MAP_ARCHIVE_SUCCESS) ? map_archive(dynamic_mapinfo, mapped_base_address, archive_space_rs) : MAP_ARCHIVE_OTHER_FAILURE; + DEBUG_ONLY(if (ArchiveRelocationMode == 1 && use_requested_addr) { + // This is for simulating mmap failures at the requested address. In debug builds, we do it + // here (after all archives have possibly been mapped), so we can thoroughly test the code for + // failure handling (releasing all allocated resource, etc). + log_info(cds)("ArchiveRelocationMode == 1: always map archive(s) at an alternative address"); + if (static_result == MAP_ARCHIVE_SUCCESS) { + static_result = MAP_ARCHIVE_MMAP_FAILURE; + } + if (dynamic_result == MAP_ARCHIVE_SUCCESS) { + dynamic_result = MAP_ARCHIVE_MMAP_FAILURE; + } + }); + if (static_result == MAP_ARCHIVE_SUCCESS) { if (dynamic_result == MAP_ARCHIVE_SUCCESS) { result = MAP_ARCHIVE_SUCCESS; @@ -2298,7 +2311,7 @@ MapArchiveResult MetaspaceShared::map_archive(FileMapInfo* mapinfo, char* mapped_base_address, ReservedSpace rs) { assert(UseSharedSpaces, "must be runtime"); if (mapinfo == NULL) { - return MAP_ARCHIVE_SUCCESS; // no error has happeed -- trivially succeeded. + return MAP_ARCHIVE_SUCCESS; // The dynamic archive has not been specified. No error has happened -- trivially succeeded. } mapinfo->set_is_mapped(false); diff -r bfc8074ea4ef -r cfe31d2f935c src/hotspot/share/memory/resourceArea.cpp --- a/src/hotspot/share/memory/resourceArea.cpp Tue Nov 26 10:22:13 2019 +0000 +++ b/src/hotspot/share/memory/resourceArea.cpp Fri Nov 29 10:02:07 2019 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2019, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -31,8 +31,11 @@ void ResourceArea::bias_to(MEMFLAGS new_flags) { if (new_flags != _flags) { + size_t size = size_in_bytes(); + MemTracker::record_arena_size_change(-ssize_t(size), _flags); MemTracker::record_arena_free(_flags); MemTracker::record_new_arena(new_flags); + MemTracker::record_arena_size_change(ssize_t(size), new_flags); _flags = new_flags; } } diff -r bfc8074ea4ef -r cfe31d2f935c src/hotspot/share/oops/accessBackend.inline.hpp --- a/src/hotspot/share/oops/accessBackend.inline.hpp Tue Nov 26 10:22:13 2019 +0000 +++ b/src/hotspot/share/oops/accessBackend.inline.hpp Fri Nov 29 10:02:07 2019 +0000 @@ -29,6 +29,8 @@ #include "oops/accessBackend.hpp" #include "oops/compressedOops.inline.hpp" #include "oops/oopsHierarchy.hpp" +#include "runtime/atomic.hpp" +#include "runtime/orderAccess.hpp" template template diff -r bfc8074ea4ef -r cfe31d2f935c src/hotspot/share/oops/arrayKlass.inline.hpp --- a/src/hotspot/share/oops/arrayKlass.inline.hpp Tue Nov 26 10:22:13 2019 +0000 +++ b/src/hotspot/share/oops/arrayKlass.inline.hpp Fri Nov 29 10:02:07 2019 +0000 @@ -25,7 +25,7 @@ #ifndef SHARE_OOPS_ARRAYKLASS_INLINE_HPP #define SHARE_OOPS_ARRAYKLASS_INLINE_HPP -#include "runtime/orderAccess.hpp" +#include "runtime/atomic.hpp" #include "oops/arrayKlass.hpp" inline Klass* ArrayKlass::higher_dimension_acquire() const { diff -r bfc8074ea4ef -r cfe31d2f935c src/hotspot/share/oops/constantPool.cpp --- a/src/hotspot/share/oops/constantPool.cpp Tue Nov 26 10:22:13 2019 +0000 +++ b/src/hotspot/share/oops/constantPool.cpp Fri Nov 29 10:02:07 2019 +0000 @@ -49,6 +49,7 @@ #include "oops/objArrayOop.inline.hpp" #include "oops/oop.inline.hpp" #include "oops/typeArrayOop.inline.hpp" +#include "runtime/atomic.hpp" #include "runtime/fieldType.hpp" #include "runtime/handles.inline.hpp" #include "runtime/init.hpp" diff -r bfc8074ea4ef -r cfe31d2f935c src/hotspot/share/oops/constantPool.inline.hpp --- a/src/hotspot/share/oops/constantPool.inline.hpp Tue Nov 26 10:22:13 2019 +0000 +++ b/src/hotspot/share/oops/constantPool.inline.hpp Fri Nov 29 10:02:07 2019 +0000 @@ -27,7 +27,7 @@ #include "oops/constantPool.hpp" #include "oops/cpCache.inline.hpp" -#include "runtime/orderAccess.hpp" +#include "runtime/atomic.hpp" inline CPSlot ConstantPool::slot_at(int which) const { assert(is_within_bounds(which), "index out of bounds"); diff -r bfc8074ea4ef -r cfe31d2f935c src/hotspot/share/oops/cpCache.cpp --- a/src/hotspot/share/oops/cpCache.cpp Tue Nov 26 10:22:13 2019 +0000 +++ b/src/hotspot/share/oops/cpCache.cpp Fri Nov 29 10:02:07 2019 +0000 @@ -44,7 +44,6 @@ #include "prims/methodHandles.hpp" #include "runtime/atomic.hpp" #include "runtime/handles.inline.hpp" -#include "runtime/orderAccess.hpp" #include "utilities/macros.hpp" // Implementation of ConstantPoolCacheEntry diff -r bfc8074ea4ef -r cfe31d2f935c src/hotspot/share/oops/cpCache.inline.hpp --- a/src/hotspot/share/oops/cpCache.inline.hpp Tue Nov 26 10:22:13 2019 +0000 +++ b/src/hotspot/share/oops/cpCache.inline.hpp Fri Nov 29 10:02:07 2019 +0000 @@ -27,7 +27,7 @@ #include "oops/cpCache.hpp" #include "oops/oopHandle.inline.hpp" -#include "runtime/orderAccess.hpp" +#include "runtime/atomic.hpp" inline int ConstantPoolCacheEntry::indices_ord() const { return Atomic::load_acquire(&_indices); } diff -r bfc8074ea4ef -r cfe31d2f935c src/hotspot/share/oops/instanceKlass.inline.hpp --- a/src/hotspot/share/oops/instanceKlass.inline.hpp Tue Nov 26 10:22:13 2019 +0000 +++ b/src/hotspot/share/oops/instanceKlass.inline.hpp Fri Nov 29 10:02:07 2019 +0000 @@ -29,7 +29,7 @@ #include "oops/instanceKlass.hpp" #include "oops/klass.hpp" #include "oops/oop.inline.hpp" -#include "runtime/orderAccess.hpp" +#include "runtime/atomic.hpp" #include "utilities/debug.hpp" #include "utilities/globalDefinitions.hpp" #include "utilities/macros.hpp" diff -r bfc8074ea4ef -r cfe31d2f935c src/hotspot/share/oops/klass.cpp --- a/src/hotspot/share/oops/klass.cpp Tue Nov 26 10:22:13 2019 +0000 +++ b/src/hotspot/share/oops/klass.cpp Fri Nov 29 10:02:07 2019 +0000 @@ -47,7 +47,6 @@ #include "oops/oopHandle.inline.hpp" #include "runtime/atomic.hpp" #include "runtime/handles.inline.hpp" -#include "runtime/orderAccess.hpp" #include "utilities/macros.hpp" #include "utilities/stack.inline.hpp" diff -r bfc8074ea4ef -r cfe31d2f935c src/hotspot/share/oops/method.cpp --- a/src/hotspot/share/oops/method.cpp Tue Nov 26 10:22:13 2019 +0000 +++ b/src/hotspot/share/oops/method.cpp Fri Nov 29 10:02:07 2019 +0000 @@ -58,6 +58,7 @@ #include "prims/methodHandles.hpp" #include "prims/nativeLookup.hpp" #include "runtime/arguments.hpp" +#include "runtime/atomic.hpp" #include "runtime/frame.inline.hpp" #include "runtime/handles.inline.hpp" #include "runtime/init.hpp" diff -r bfc8074ea4ef -r cfe31d2f935c src/hotspot/share/oops/method.inline.hpp --- a/src/hotspot/share/oops/method.inline.hpp Tue Nov 26 10:22:13 2019 +0000 +++ b/src/hotspot/share/oops/method.inline.hpp Fri Nov 29 10:02:07 2019 +0000 @@ -26,7 +26,7 @@ #define SHARE_OOPS_METHOD_INLINE_HPP #include "oops/method.hpp" -#include "runtime/orderAccess.hpp" +#include "runtime/atomic.hpp" inline address Method::from_compiled_entry() const { return Atomic::load_acquire(&_from_compiled_entry); diff -r bfc8074ea4ef -r cfe31d2f935c src/hotspot/share/oops/methodData.cpp --- a/src/hotspot/share/oops/methodData.cpp Tue Nov 26 10:22:13 2019 +0000 +++ b/src/hotspot/share/oops/methodData.cpp Fri Nov 29 10:02:07 2019 +0000 @@ -35,6 +35,7 @@ #include "oops/methodData.inline.hpp" #include "prims/jvmtiRedefineClasses.hpp" #include "runtime/arguments.hpp" +#include "runtime/atomic.hpp" #include "runtime/deoptimization.hpp" #include "runtime/handles.inline.hpp" #include "runtime/orderAccess.hpp" diff -r bfc8074ea4ef -r cfe31d2f935c src/hotspot/share/oops/methodData.inline.hpp --- a/src/hotspot/share/oops/methodData.inline.hpp Tue Nov 26 10:22:13 2019 +0000 +++ b/src/hotspot/share/oops/methodData.inline.hpp Fri Nov 29 10:02:07 2019 +0000 @@ -26,7 +26,7 @@ #define SHARE_OOPS_METHODDATA_INLINE_HPP #include "oops/methodData.hpp" -#include "runtime/orderAccess.hpp" +#include "runtime/atomic.hpp" inline void DataLayout::release_set_cell_at(int index, intptr_t value) { Atomic::release_store(&_cells[index], value); diff -r bfc8074ea4ef -r cfe31d2f935c src/hotspot/share/oops/oop.inline.hpp --- a/src/hotspot/share/oops/oop.inline.hpp Tue Nov 26 10:22:13 2019 +0000 +++ b/src/hotspot/share/oops/oop.inline.hpp Fri Nov 29 10:02:07 2019 +0000 @@ -35,7 +35,6 @@ #include "oops/markWord.inline.hpp" #include "oops/oop.hpp" #include "runtime/atomic.hpp" -#include "runtime/orderAccess.hpp" #include "runtime/os.hpp" #include "utilities/align.hpp" #include "utilities/macros.hpp" diff -r bfc8074ea4ef -r cfe31d2f935c src/hotspot/share/opto/cfgnode.hpp --- a/src/hotspot/share/opto/cfgnode.hpp Tue Nov 26 10:22:13 2019 +0000 +++ b/src/hotspot/share/opto/cfgnode.hpp Fri Nov 29 10:02:07 2019 +0000 @@ -308,6 +308,8 @@ Node* Ideal_common(PhaseGVN *phase, bool can_reshape); Node* search_identical(int dist); + Node* simple_subsuming(PhaseIterGVN* igvn); + public: // Degrees of branch prediction probability by order of magnitude: diff -r bfc8074ea4ef -r cfe31d2f935c src/hotspot/share/opto/ifnode.cpp --- a/src/hotspot/share/opto/ifnode.cpp Tue Nov 26 10:22:13 2019 +0000 +++ b/src/hotspot/share/opto/ifnode.cpp Fri Nov 29 10:02:07 2019 +0000 @@ -599,7 +599,7 @@ //------------------------------filtered_int_type-------------------------------- // Return a possibly more restrictive type for val based on condition control flow for an if -const TypeInt* IfNode::filtered_int_type(PhaseGVN* gvn, Node *val, Node* if_proj) { +const TypeInt* IfNode::filtered_int_type(PhaseGVN* gvn, Node* val, Node* if_proj) { assert(if_proj && (if_proj->Opcode() == Op_IfTrue || if_proj->Opcode() == Op_IfFalse), "expecting an if projection"); if (if_proj->in(0) && if_proj->in(0)->is_If()) { @@ -1239,8 +1239,7 @@ if (cmpi_folds(igvn)) { Node* ctrl = in(0); - if (is_ctrl_folds(ctrl, igvn) && - ctrl->outcnt() == 1) { + if (is_ctrl_folds(ctrl, igvn) && ctrl->outcnt() == 1) { // A integer comparison immediately dominated by another integer // comparison ProjNode* success = NULL; @@ -1392,41 +1391,36 @@ // Check for people making a useless boolean: things like // if( (x < y ? true : false) ) { ... } // Replace with if( x < y ) { ... } - Node *bol2 = remove_useless_bool(this, phase); - if( bol2 ) return bol2; + Node* bol2 = remove_useless_bool(this, phase); + if (bol2) return bol2; if (in(0) == NULL) return NULL; // Dead loop? - PhaseIterGVN *igvn = phase->is_IterGVN(); + PhaseIterGVN* igvn = phase->is_IterGVN(); Node* result = fold_compares(igvn); if (result != NULL) { return result; } // Scan for an equivalent test - Node *cmp; - int dist = 0; // Cutoff limit for search - int op = Opcode(); - if( op == Op_If && - (cmp=in(1)->in(1))->Opcode() == Op_CmpP ) { - if( cmp->in(2) != NULL && // make sure cmp is not already dead - cmp->in(2)->bottom_type() == TypePtr::NULL_PTR ) { + int dist = 4; // Cutoff limit for search + if (is_If() && in(1)->is_Bool()) { + Node* cmp = in(1)->in(1); + if (cmp->Opcode() == Op_CmpP && + cmp->in(2) != NULL && // make sure cmp is not already dead + cmp->in(2)->bottom_type() == TypePtr::NULL_PTR) { dist = 64; // Limit for null-pointer scans - } else { - dist = 4; // Do not bother for random pointer tests } - } else { - dist = 4; // Limit for random junky scans } Node* prev_dom = search_identical(dist); - if (prev_dom == NULL) { - return NULL; + if (prev_dom != NULL) { + // Replace dominated IfNode + return dominated_by(prev_dom, igvn); } - // Replace dominated IfNode - return dominated_by(prev_dom, igvn); + return simple_subsuming(igvn); } //------------------------------dominated_by----------------------------------- @@ -1523,6 +1517,114 @@ return prev_dom; } + +static int subsuming_bool_test_encode(Node*); + +// Check if dominating test is subsuming 'this' one. +// +// cmp +// / \ +// (r1) bool \ +// / bool (r2) +// (dom) if \ +// \ ) +// (pre) if[TF] / +// \ / +// if (this) +// \r1 +// r2\ eqT eqF neT neF ltT ltF leT leF gtT gtF geT geF +// eq t f f t f - - f f - - f +// ne f t t f t - - t t - - t +// lt f - - f t f - f f - f t +// le t - - t t - t f f t - t +// gt f - - f f - f t t f - f +// ge t - - t f t - t t - t f +// +Node* IfNode::simple_subsuming(PhaseIterGVN* igvn) { + // Table encoding: N/A (na), True-branch (tb), False-branch (fb). + static enum { na, tb, fb } s_short_circuit_map[6][12] = { + /*rel: eq+T eq+F ne+T ne+F lt+T lt+F le+T le+F gt+T gt+F ge+T ge+F*/ + /*eq*/{ tb, fb, fb, tb, fb, na, na, fb, fb, na, na, fb }, + /*ne*/{ fb, tb, tb, fb, tb, na, na, tb, tb, na, na, tb }, + /*lt*/{ fb, na, na, fb, tb, fb, na, fb, fb, na, fb, tb }, + /*le*/{ tb, na, na, tb, tb, na, tb, fb, fb, tb, na, tb }, + /*gt*/{ fb, na, na, fb, fb, na, fb, tb, tb, fb, na, fb }, + /*ge*/{ tb, na, na, tb, fb, tb, na, tb, tb, na, tb, fb }}; + + Node* pre = in(0); + if (!pre->is_IfTrue() && !pre->is_IfFalse()) { + return NULL; + } + Node* dom = pre->in(0); + if (!dom->is_If()) { + return NULL; + } + Node* bol = in(1); + if (!bol->is_Bool()) { + return NULL; + } + Node* cmp = in(1)->in(1); + if (!cmp->is_Cmp()) { + return NULL; + } + + if (!dom->in(1)->is_Bool()) { + return NULL; + } + if (dom->in(1)->in(1) != cmp) { // Not same cond? + return NULL; + } + + int drel = subsuming_bool_test_encode(dom->in(1)); + int trel = subsuming_bool_test_encode(bol); + int bout = pre->is_IfFalse() ? 1 : 0; + + if (drel < 0 || trel < 0) { + return NULL; + } + int br = s_short_circuit_map[trel][2*drel+bout]; + if (br == na) { + return NULL; + } +#ifndef PRODUCT + if (TraceIterativeGVN) { + tty->print(" Subsumed IfNode: "); dump(); + } +#endif + // Replace condition with constant True(1)/False(0). + set_req(1, igvn->intcon(br == tb ? 1 : 0)); + + if (bol->outcnt() == 0) { + igvn->remove_dead_node(bol); // Kill the BoolNode. + } + return this; +} + +// Map BoolTest to local table ecoding. The BoolTest (e)numerals +// { eq = 0, ne = 4, le = 5, ge = 7, lt = 3, gt = 1 } +// are mapped to table indices, while the remaining (e)numerals in BoolTest +// { overflow = 2, no_overflow = 6, never = 8, illegal = 9 } +// are ignored (these are not modelled in the table). +// +static int subsuming_bool_test_encode(Node* node) { + precond(node->is_Bool()); + BoolTest::mask x = node->as_Bool()->_test._test; + switch (x) { + case BoolTest::eq: return 0; + case BoolTest::ne: return 1; + case BoolTest::lt: return 2; + case BoolTest::le: return 3; + case BoolTest::gt: return 4; + case BoolTest::ge: return 5; + case BoolTest::overflow: + case BoolTest::no_overflow: + case BoolTest::never: + case BoolTest::illegal: + default: + return -1; + } +} + //------------------------------Identity--------------------------------------- // If the test is constant & we match, then we are the input Control Node* IfProjNode::Identity(PhaseGVN* phase) { @@ -1668,7 +1770,7 @@ // checks. // The top 3 range checks seen - const int NRC =3; + const int NRC = 3; RangeCheck prev_checks[NRC]; int nb_checks = 0; diff -r bfc8074ea4ef -r cfe31d2f935c src/hotspot/share/opto/parse3.cpp --- a/src/hotspot/share/opto/parse3.cpp Tue Nov 26 10:22:13 2019 +0000 +++ b/src/hotspot/share/opto/parse3.cpp Fri Nov 29 10:02:07 2019 +0000 @@ -55,8 +55,9 @@ return; } - // Deoptimize on putfield writes to call site target field. - if (!is_get && field->is_call_site_target()) { + // Deoptimize on putfield writes to call site target field outside of CallSite ctor. + if (!is_get && field->is_call_site_target() && + !(method()->holder() == field_holder && method()->is_object_initializer())) { uncommon_trap(Deoptimization::Reason_unhandled, Deoptimization::Action_reinterpret, NULL, "put to call site target field"); diff -r bfc8074ea4ef -r cfe31d2f935c src/hotspot/share/prims/jni.cpp --- a/src/hotspot/share/prims/jni.cpp Tue Nov 26 10:22:13 2019 +0000 +++ b/src/hotspot/share/prims/jni.cpp Fri Nov 29 10:02:07 2019 +0000 @@ -72,7 +72,6 @@ #include "runtime/javaCalls.hpp" #include "runtime/jfieldIDWorkaround.hpp" #include "runtime/jniHandles.inline.hpp" -#include "runtime/orderAccess.hpp" #include "runtime/reflection.hpp" #include "runtime/safepointVerifiers.hpp" #include "runtime/sharedRuntime.hpp" diff -r bfc8074ea4ef -r cfe31d2f935c src/hotspot/share/prims/jvm.cpp --- a/src/hotspot/share/prims/jvm.cpp Tue Nov 26 10:22:13 2019 +0000 +++ b/src/hotspot/share/prims/jvm.cpp Fri Nov 29 10:02:07 2019 +0000 @@ -70,7 +70,6 @@ #include "runtime/javaCalls.hpp" #include "runtime/jfieldIDWorkaround.hpp" #include "runtime/jniHandles.inline.hpp" -#include "runtime/orderAccess.hpp" #include "runtime/os.inline.hpp" #include "runtime/perfData.hpp" #include "runtime/reflection.hpp" diff -r bfc8074ea4ef -r cfe31d2f935c src/hotspot/share/prims/jvmtiEnvBase.hpp --- a/src/hotspot/share/prims/jvmtiEnvBase.hpp Tue Nov 26 10:22:13 2019 +0000 +++ b/src/hotspot/share/prims/jvmtiEnvBase.hpp Fri Nov 29 10:02:07 2019 +0000 @@ -30,9 +30,9 @@ #include "prims/jvmtiEventController.hpp" #include "prims/jvmtiThreadState.hpp" #include "oops/oopHandle.hpp" +#include "runtime/atomic.hpp" #include "runtime/fieldDescriptor.hpp" #include "runtime/frame.hpp" -#include "runtime/orderAccess.hpp" #include "runtime/thread.hpp" #include "runtime/vmOperations.hpp" #include "utilities/growableArray.hpp" diff -r bfc8074ea4ef -r cfe31d2f935c src/hotspot/share/prims/jvmtiImpl.cpp --- a/src/hotspot/share/prims/jvmtiImpl.cpp Tue Nov 26 10:22:13 2019 +0000 +++ b/src/hotspot/share/prims/jvmtiImpl.cpp Fri Nov 29 10:02:07 2019 +0000 @@ -38,7 +38,6 @@ #include "prims/jvmtiEventController.inline.hpp" #include "prims/jvmtiImpl.hpp" #include "prims/jvmtiRedefineClasses.hpp" -#include "runtime/atomic.hpp" #include "runtime/deoptimization.hpp" #include "runtime/frame.inline.hpp" #include "runtime/handles.inline.hpp" diff -r bfc8074ea4ef -r cfe31d2f935c src/hotspot/share/prims/resolvedMethodTable.cpp --- a/src/hotspot/share/prims/resolvedMethodTable.cpp Tue Nov 26 10:22:13 2019 +0000 +++ b/src/hotspot/share/prims/resolvedMethodTable.cpp Fri Nov 29 10:02:07 2019 +0000 @@ -35,6 +35,7 @@ #include "oops/oop.inline.hpp" #include "oops/weakHandle.inline.hpp" #include "prims/resolvedMethodTable.hpp" +#include "runtime/atomic.hpp" #include "runtime/handles.inline.hpp" #include "runtime/interfaceSupport.inline.hpp" #include "runtime/mutexLocker.hpp" diff -r bfc8074ea4ef -r cfe31d2f935c src/hotspot/share/prims/unsafe.cpp --- a/src/hotspot/share/prims/unsafe.cpp Tue Nov 26 10:22:13 2019 +0000 +++ b/src/hotspot/share/prims/unsafe.cpp Fri Nov 29 10:02:07 2019 +0000 @@ -37,7 +37,6 @@ #include "oops/oop.inline.hpp" #include "oops/typeArrayOop.inline.hpp" #include "prims/unsafe.hpp" -#include "runtime/atomic.hpp" #include "runtime/globals.hpp" #include "runtime/handles.inline.hpp" #include "runtime/interfaceSupport.inline.hpp" diff -r bfc8074ea4ef -r cfe31d2f935c src/hotspot/share/prims/whitebox.cpp --- a/src/hotspot/share/prims/whitebox.cpp Tue Nov 26 10:22:13 2019 +0000 +++ b/src/hotspot/share/prims/whitebox.cpp Fri Nov 29 10:02:07 2019 +0000 @@ -59,6 +59,7 @@ #include "prims/wbtestmethods/parserTests.hpp" #include "prims/whitebox.inline.hpp" #include "runtime/arguments.hpp" +#include "runtime/atomic.hpp" #include "runtime/deoptimization.hpp" #include "runtime/fieldDescriptor.inline.hpp" #include "runtime/flags/jvmFlag.hpp" @@ -797,6 +798,21 @@ assert(hash_size > 0, "NMT hash_size should be > 0"); return (jint)hash_size; WB_END + +WB_ENTRY(jlong, WB_NMTNewArena(JNIEnv* env, jobject o, jlong init_size)) + Arena* arena = new (mtTest) Arena(mtTest, size_t(init_size)); + return (jlong)arena; +WB_END + +WB_ENTRY(void, WB_NMTFreeArena(JNIEnv* env, jobject o, jlong arena)) + Arena* a = (Arena*)arena; + delete a; +WB_END + +WB_ENTRY(void, WB_NMTArenaMalloc(JNIEnv* env, jobject o, jlong arena, jlong size)) + Arena* a = (Arena*)arena; + a->Amalloc(size_t(size)); +WB_END #endif // INCLUDE_NMT static jmethodID reflected_method_to_jmid(JavaThread* thread, JNIEnv* env, jobject method) { @@ -2244,6 +2260,9 @@ {CC"NMTReleaseMemory", CC"(JJ)V", (void*)&WB_NMTReleaseMemory }, {CC"NMTChangeTrackingLevel", CC"()Z", (void*)&WB_NMTChangeTrackingLevel}, {CC"NMTGetHashSize", CC"()I", (void*)&WB_NMTGetHashSize }, + {CC"NMTNewArena", CC"(J)J", (void*)&WB_NMTNewArena }, + {CC"NMTFreeArena", CC"(J)V", (void*)&WB_NMTFreeArena }, + {CC"NMTArenaMalloc", CC"(JJ)V", (void*)&WB_NMTArenaMalloc }, #endif // INCLUDE_NMT {CC"deoptimizeFrames", CC"(Z)I", (void*)&WB_DeoptimizeFrames }, {CC"deoptimizeAll", CC"()V", (void*)&WB_DeoptimizeAll }, diff -r bfc8074ea4ef -r cfe31d2f935c src/hotspot/share/runtime/arguments.cpp --- a/src/hotspot/share/runtime/arguments.cpp Tue Nov 26 10:22:13 2019 +0000 +++ b/src/hotspot/share/runtime/arguments.cpp Fri Nov 29 10:02:07 2019 +0000 @@ -528,6 +528,7 @@ { "CompactFields", JDK_Version::jdk(14), JDK_Version::jdk(15), JDK_Version::jdk(16) }, { "MonitorBound", JDK_Version::jdk(14), JDK_Version::jdk(15), JDK_Version::jdk(16) }, { "G1RSetScanBlockSize", JDK_Version::jdk(14), JDK_Version::jdk(15), JDK_Version::jdk(16) }, + { "UseParallelOldGC", JDK_Version::jdk(14), JDK_Version::jdk(15), JDK_Version::jdk(16) }, // --- Deprecated alias flags (see also aliased_jvm_flags) - sorted by obsolete_in then expired_in: { "DefaultMaxRAMFraction", JDK_Version::jdk(8), JDK_Version::undefined(), JDK_Version::undefined() }, diff -r bfc8074ea4ef -r cfe31d2f935c src/hotspot/share/runtime/deoptimization.cpp --- a/src/hotspot/share/runtime/deoptimization.cpp Tue Nov 26 10:22:13 2019 +0000 +++ b/src/hotspot/share/runtime/deoptimization.cpp Fri Nov 29 10:02:07 2019 +0000 @@ -1,3 +1,5 @@ + + /* * Copyright (c) 1997, 2019, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. @@ -48,6 +50,7 @@ #include "oops/typeArrayOop.inline.hpp" #include "oops/verifyOopClosure.hpp" #include "prims/jvmtiThreadState.hpp" +#include "runtime/atomic.hpp" #include "runtime/biasedLocking.hpp" #include "runtime/deoptimization.hpp" #include "runtime/fieldDescriptor.hpp" diff -r bfc8074ea4ef -r cfe31d2f935c src/hotspot/share/runtime/handshake.cpp --- a/src/hotspot/share/runtime/handshake.cpp Tue Nov 26 10:22:13 2019 +0000 +++ b/src/hotspot/share/runtime/handshake.cpp Fri Nov 29 10:02:07 2019 +0000 @@ -26,9 +26,9 @@ #include "logging/log.hpp" #include "logging/logStream.hpp" #include "memory/resourceArea.hpp" +#include "runtime/atomic.hpp" #include "runtime/handshake.hpp" #include "runtime/interfaceSupport.inline.hpp" -#include "runtime/orderAccess.hpp" #include "runtime/osThread.hpp" #include "runtime/semaphore.inline.hpp" #include "runtime/task.hpp" @@ -289,20 +289,24 @@ void HandshakeState::process_self_inner(JavaThread* thread) { assert(Thread::current() == thread, "should call from thread"); assert(!thread->is_terminated(), "should not be a terminated thread"); + assert(thread->thread_state() != _thread_blocked, "should not be in a blocked state"); + assert(thread->thread_state() != _thread_in_native, "should not be in native"); - ThreadInVMForHandshake tivm(thread); - if (!_semaphore.trywait()) { - _semaphore.wait_with_safepoint_check(thread); - } - HandshakeOperation* op = Atomic::load_acquire(&_operation); - if (op != NULL) { - HandleMark hm(thread); - CautiouslyPreserveExceptionMark pem(thread); - // Disarm before execute the operation - clear_handshake(thread); - op->do_handshake(thread); - } - _semaphore.signal(); + do { + ThreadInVMForHandshake tivm(thread); + if (!_semaphore.trywait()) { + _semaphore.wait_with_safepoint_check(thread); + } + HandshakeOperation* op = Atomic::load_acquire(&_operation); + if (op != NULL) { + HandleMark hm(thread); + CautiouslyPreserveExceptionMark pem(thread); + // Disarm before execute the operation + clear_handshake(thread); + op->do_handshake(thread); + } + _semaphore.signal(); + } while (has_operation()); } bool HandshakeState::vmthread_can_process_handshake(JavaThread* target) { diff -r bfc8074ea4ef -r cfe31d2f935c src/hotspot/share/runtime/init.cpp --- a/src/hotspot/share/runtime/init.cpp Tue Nov 26 10:22:13 2019 +0000 +++ b/src/hotspot/share/runtime/init.cpp Fri Nov 29 10:02:07 2019 +0000 @@ -35,11 +35,11 @@ #include "logging/logTag.hpp" #include "memory/universe.hpp" #include "prims/methodHandles.hpp" +#include "runtime/atomic.hpp" #include "runtime/flags/jvmFlag.hpp" #include "runtime/handles.inline.hpp" #include "runtime/icache.hpp" #include "runtime/init.hpp" -#include "runtime/orderAccess.hpp" #include "runtime/safepoint.hpp" #include "runtime/sharedRuntime.hpp" #include "services/memTracker.hpp" diff -r bfc8074ea4ef -r cfe31d2f935c src/hotspot/share/runtime/interfaceSupport.cpp --- a/src/hotspot/share/runtime/interfaceSupport.cpp Tue Nov 26 10:22:13 2019 +0000 +++ b/src/hotspot/share/runtime/interfaceSupport.cpp Fri Nov 29 10:02:07 2019 +0000 @@ -33,7 +33,6 @@ #include "runtime/handles.inline.hpp" #include "runtime/init.hpp" #include "runtime/interfaceSupport.inline.hpp" -#include "runtime/orderAccess.hpp" #include "runtime/os.inline.hpp" #include "runtime/thread.inline.hpp" #include "runtime/safepointVerifiers.hpp" diff -r bfc8074ea4ef -r cfe31d2f935c src/hotspot/share/runtime/perfMemory.cpp --- a/src/hotspot/share/runtime/perfMemory.cpp Tue Nov 26 10:22:13 2019 +0000 +++ b/src/hotspot/share/runtime/perfMemory.cpp Fri Nov 29 10:02:07 2019 +0000 @@ -27,10 +27,10 @@ #include "logging/log.hpp" #include "memory/allocation.inline.hpp" #include "runtime/arguments.hpp" +#include "runtime/atomic.hpp" #include "runtime/java.hpp" #include "runtime/mutex.hpp" #include "runtime/mutexLocker.hpp" -#include "runtime/orderAccess.hpp" #include "runtime/os.hpp" #include "runtime/perfData.hpp" #include "runtime/perfMemory.hpp" diff -r bfc8074ea4ef -r cfe31d2f935c src/hotspot/share/runtime/safepointMechanism.cpp --- a/src/hotspot/share/runtime/safepointMechanism.cpp Tue Nov 26 10:22:13 2019 +0000 +++ b/src/hotspot/share/runtime/safepointMechanism.cpp Fri Nov 29 10:02:07 2019 +0000 @@ -25,6 +25,7 @@ #include "precompiled.hpp" #include "logging/log.hpp" #include "runtime/globals.hpp" +#include "runtime/orderAccess.hpp" #include "runtime/os.hpp" #include "runtime/safepointMechanism.inline.hpp" #include "services/memTracker.hpp" diff -r bfc8074ea4ef -r cfe31d2f935c src/hotspot/share/runtime/sweeper.cpp --- a/src/hotspot/share/runtime/sweeper.cpp Tue Nov 26 10:22:13 2019 +0000 +++ b/src/hotspot/share/runtime/sweeper.cpp Fri Nov 29 10:02:07 2019 +0000 @@ -37,7 +37,6 @@ #include "memory/resourceArea.hpp" #include "memory/universe.hpp" #include "oops/method.hpp" -#include "runtime/atomic.hpp" #include "runtime/interfaceSupport.inline.hpp" #include "runtime/handshake.hpp" #include "runtime/mutexLocker.hpp" diff -r bfc8074ea4ef -r cfe31d2f935c src/hotspot/share/runtime/threadHeapSampler.cpp --- a/src/hotspot/share/runtime/threadHeapSampler.cpp Tue Nov 26 10:22:13 2019 +0000 +++ b/src/hotspot/share/runtime/threadHeapSampler.cpp Fri Nov 29 10:02:07 2019 +0000 @@ -24,8 +24,8 @@ */ #include "precompiled.hpp" +#include "runtime/atomic.hpp" #include "runtime/handles.inline.hpp" -#include "runtime/orderAccess.hpp" #include "runtime/sharedRuntime.hpp" #include "runtime/threadHeapSampler.hpp" diff -r bfc8074ea4ef -r cfe31d2f935c src/hotspot/share/runtime/threadSMR.cpp --- a/src/hotspot/share/runtime/threadSMR.cpp Tue Nov 26 10:22:13 2019 +0000 +++ b/src/hotspot/share/runtime/threadSMR.cpp Fri Nov 29 10:02:07 2019 +0000 @@ -25,7 +25,9 @@ #include "precompiled.hpp" #include "logging/logStream.hpp" #include "memory/allocation.inline.hpp" +#include "runtime/atomic.hpp" #include "runtime/jniHandles.inline.hpp" +#include "runtime/orderAccess.hpp" #include "runtime/sharedRuntime.hpp" #include "runtime/thread.inline.hpp" #include "runtime/threadSMR.inline.hpp" diff -r bfc8074ea4ef -r cfe31d2f935c src/hotspot/share/runtime/vmThread.cpp --- a/src/hotspot/share/runtime/vmThread.cpp Tue Nov 26 10:22:13 2019 +0000 +++ b/src/hotspot/share/runtime/vmThread.cpp Fri Nov 29 10:02:07 2019 +0000 @@ -35,6 +35,7 @@ #include "oops/method.hpp" #include "oops/oop.inline.hpp" #include "oops/verifyOopClosure.hpp" +#include "runtime/atomic.hpp" #include "runtime/handles.inline.hpp" #include "runtime/interfaceSupport.inline.hpp" #include "runtime/mutexLocker.hpp" diff -r bfc8074ea4ef -r cfe31d2f935c src/hotspot/share/services/lowMemoryDetector.hpp --- a/src/hotspot/share/services/lowMemoryDetector.hpp Tue Nov 26 10:22:13 2019 +0000 +++ b/src/hotspot/share/services/lowMemoryDetector.hpp Fri Nov 29 10:02:07 2019 +0000 @@ -26,6 +26,7 @@ #define SHARE_SERVICES_LOWMEMORYDETECTOR_HPP #include "memory/allocation.hpp" +#include "runtime/atomic.hpp" #include "services/memoryPool.hpp" #include "services/memoryService.hpp" #include "services/memoryUsage.hpp" diff -r bfc8074ea4ef -r cfe31d2f935c src/hotspot/share/services/mallocSiteTable.hpp --- a/src/hotspot/share/services/mallocSiteTable.hpp Tue Nov 26 10:22:13 2019 +0000 +++ b/src/hotspot/share/services/mallocSiteTable.hpp Fri Nov 29 10:02:07 2019 +0000 @@ -25,6 +25,8 @@ #ifndef SHARE_SERVICES_MALLOCSITETABLE_HPP #define SHARE_SERVICES_MALLOCSITETABLE_HPP +#include "utilities/macros.hpp" + #if INCLUDE_NMT #include "memory/allocation.hpp" diff -r bfc8074ea4ef -r cfe31d2f935c src/hotspot/share/services/mallocTracker.cpp --- a/src/hotspot/share/services/mallocTracker.cpp Tue Nov 26 10:22:13 2019 +0000 +++ b/src/hotspot/share/services/mallocTracker.cpp Fri Nov 29 10:02:07 2019 +0000 @@ -23,7 +23,6 @@ */ #include "precompiled.hpp" -#include "runtime/atomic.hpp" #include "services/mallocSiteTable.hpp" #include "services/mallocTracker.hpp" #include "services/mallocTracker.inline.hpp" @@ -153,5 +152,3 @@ header->release(); return (void*)header; } - - diff -r bfc8074ea4ef -r cfe31d2f935c src/hotspot/share/services/mallocTracker.hpp --- a/src/hotspot/share/services/mallocTracker.hpp Tue Nov 26 10:22:13 2019 +0000 +++ b/src/hotspot/share/services/mallocTracker.hpp Fri Nov 29 10:02:07 2019 +0000 @@ -70,8 +70,9 @@ } } - inline void resize(long sz) { + inline void resize(ssize_t sz) { if (sz != 0) { + assert(sz >= 0 || _size >= size_t(-sz), "Must be"); Atomic::add(&_size, size_t(sz)); DEBUG_ONLY(_peak_size = MAX2(_size, _peak_size);) } @@ -113,7 +114,7 @@ _arena.deallocate(0); } - inline void record_arena_size_change(long sz) { + inline void record_arena_size_change(ssize_t sz) { _arena.resize(sz); } @@ -207,7 +208,7 @@ as_snapshot()->by_type(flag)->record_arena_free(); } - static inline void record_arena_size_change(long size, MEMFLAGS flag) { + static inline void record_arena_size_change(ssize_t size, MEMFLAGS flag) { as_snapshot()->by_type(flag)->record_arena_size_change(size); } @@ -361,7 +362,7 @@ MallocMemorySummary::record_arena_free(flags); } - static inline void record_arena_size_change(int size, MEMFLAGS flags) { + static inline void record_arena_size_change(ssize_t size, MEMFLAGS flags) { MallocMemorySummary::record_arena_size_change(size, flags); } private: diff -r bfc8074ea4ef -r cfe31d2f935c src/hotspot/share/services/memTracker.cpp --- a/src/hotspot/share/services/memTracker.cpp Tue Nov 26 10:22:13 2019 +0000 +++ b/src/hotspot/share/services/memTracker.cpp Fri Nov 29 10:02:07 2019 +0000 @@ -24,6 +24,7 @@ #include "precompiled.hpp" #include "jvm.h" +#include "runtime/atomic.hpp" #include "runtime/orderAccess.hpp" #include "runtime/vmThread.hpp" #include "runtime/vmOperations.hpp" diff -r bfc8074ea4ef -r cfe31d2f935c src/hotspot/share/services/memTracker.hpp --- a/src/hotspot/share/services/memTracker.hpp Tue Nov 26 10:22:13 2019 +0000 +++ b/src/hotspot/share/services/memTracker.hpp Fri Nov 29 10:02:07 2019 +0000 @@ -63,7 +63,7 @@ static inline void record_new_arena(MEMFLAGS flag) { } static inline void record_arena_free(MEMFLAGS flag) { } - static inline void record_arena_size_change(int diff, MEMFLAGS flag) { } + static inline void record_arena_size_change(ssize_t diff, MEMFLAGS flag) { } static inline void record_virtual_memory_reserve(void* addr, size_t size, const NativeCallStack& stack, MEMFLAGS flag = mtNone) { } static inline void record_virtual_memory_reserve_and_commit(void* addr, size_t size, @@ -203,7 +203,7 @@ // Record arena size change. Arena size is the size of all arena // chuncks that backing up the arena. - static inline void record_arena_size_change(int diff, MEMFLAGS flag) { + static inline void record_arena_size_change(ssize_t diff, MEMFLAGS flag) { if (tracking_level() < NMT_summary) return; MallocTracker::record_arena_size_change(diff, flag); } diff -r bfc8074ea4ef -r cfe31d2f935c src/hotspot/share/services/memoryManager.cpp --- a/src/hotspot/share/services/memoryManager.cpp Tue Nov 26 10:22:13 2019 +0000 +++ b/src/hotspot/share/services/memoryManager.cpp Fri Nov 29 10:02:07 2019 +0000 @@ -27,9 +27,9 @@ #include "classfile/vmSymbols.hpp" #include "memory/allocation.inline.hpp" #include "oops/oop.inline.hpp" +#include "runtime/atomic.hpp" #include "runtime/handles.inline.hpp" #include "runtime/javaCalls.hpp" -#include "runtime/orderAccess.hpp" #include "services/lowMemoryDetector.hpp" #include "services/management.hpp" #include "services/memoryManager.hpp" diff -r bfc8074ea4ef -r cfe31d2f935c src/hotspot/share/services/memoryPool.cpp --- a/src/hotspot/share/services/memoryPool.cpp Tue Nov 26 10:22:13 2019 +0000 +++ b/src/hotspot/share/services/memoryPool.cpp Fri Nov 29 10:02:07 2019 +0000 @@ -27,9 +27,9 @@ #include "classfile/vmSymbols.hpp" #include "memory/metaspace.hpp" #include "oops/oop.inline.hpp" +#include "runtime/atomic.hpp" #include "runtime/handles.inline.hpp" #include "runtime/javaCalls.hpp" -#include "runtime/orderAccess.hpp" #include "services/lowMemoryDetector.hpp" #include "services/management.hpp" #include "services/memoryManager.hpp" diff -r bfc8074ea4ef -r cfe31d2f935c src/hotspot/share/services/threadIdTable.cpp --- a/src/hotspot/share/services/threadIdTable.cpp Tue Nov 26 10:22:13 2019 +0000 +++ b/src/hotspot/share/services/threadIdTable.cpp Fri Nov 29 10:02:07 2019 +0000 @@ -24,6 +24,7 @@ */ #include "precompiled.hpp" +#include "runtime/atomic.hpp" #include "runtime/interfaceSupport.inline.hpp" #include "runtime/thread.hpp" #include "runtime/threadSMR.hpp" @@ -32,7 +33,6 @@ #include "utilities/concurrentHashTable.inline.hpp" #include "utilities/concurrentHashTableTasks.inline.hpp" - typedef ConcurrentHashTable ThreadIdTableHash; // 2^24 is max size diff -r bfc8074ea4ef -r cfe31d2f935c src/hotspot/share/services/threadStackTracker.cpp --- a/src/hotspot/share/services/threadStackTracker.cpp Tue Nov 26 10:22:13 2019 +0000 +++ b/src/hotspot/share/services/threadStackTracker.cpp Fri Nov 29 10:02:07 2019 +0000 @@ -23,7 +23,6 @@ #include "precompiled.hpp" -#include "runtime/atomic.hpp" #include "runtime/threadCritical.hpp" #include "services/mallocTracker.hpp" #include "services/memTracker.hpp" diff -r bfc8074ea4ef -r cfe31d2f935c src/hotspot/share/services/virtualMemoryTracker.cpp --- a/src/hotspot/share/services/virtualMemoryTracker.cpp Tue Nov 26 10:22:13 2019 +0000 +++ b/src/hotspot/share/services/virtualMemoryTracker.cpp Fri Nov 29 10:02:07 2019 +0000 @@ -25,7 +25,6 @@ #include "logging/log.hpp" #include "memory/metaspace.hpp" -#include "runtime/atomic.hpp" #include "runtime/os.hpp" #include "runtime/threadCritical.hpp" #include "services/memTracker.hpp" diff -r bfc8074ea4ef -r cfe31d2f935c src/hotspot/share/utilities/bitMap.inline.hpp --- a/src/hotspot/share/utilities/bitMap.inline.hpp Tue Nov 26 10:22:13 2019 +0000 +++ b/src/hotspot/share/utilities/bitMap.inline.hpp Fri Nov 29 10:02:07 2019 +0000 @@ -26,7 +26,6 @@ #define SHARE_UTILITIES_BITMAP_INLINE_HPP #include "runtime/atomic.hpp" -#include "runtime/orderAccess.hpp" #include "utilities/bitMap.hpp" #include "utilities/count_trailing_zeros.hpp" diff -r bfc8074ea4ef -r cfe31d2f935c src/hotspot/share/utilities/concurrentHashTableTasks.inline.hpp --- a/src/hotspot/share/utilities/concurrentHashTableTasks.inline.hpp Tue Nov 26 10:22:13 2019 +0000 +++ b/src/hotspot/share/utilities/concurrentHashTableTasks.inline.hpp Fri Nov 29 10:02:07 2019 +0000 @@ -25,6 +25,7 @@ #ifndef SHARE_UTILITIES_CONCURRENTHASHTABLETASKS_INLINE_HPP #define SHARE_UTILITIES_CONCURRENTHASHTABLETASKS_INLINE_HPP +#include "runtime/atomic.hpp" #include "utilities/globalDefinitions.hpp" #include "utilities/concurrentHashTable.inline.hpp" diff -r bfc8074ea4ef -r cfe31d2f935c src/hotspot/share/utilities/globalCounter.cpp --- a/src/hotspot/share/utilities/globalCounter.cpp Tue Nov 26 10:22:13 2019 +0000 +++ b/src/hotspot/share/utilities/globalCounter.cpp Fri Nov 29 10:02:07 2019 +0000 @@ -24,7 +24,7 @@ #include "precompiled.hpp" #include "utilities/globalCounter.hpp" -#include "runtime/orderAccess.hpp" +#include "runtime/atomic.hpp" #include "runtime/thread.hpp" #include "runtime/threadSMR.inline.hpp" #include "runtime/vmThread.hpp" diff -r bfc8074ea4ef -r cfe31d2f935c src/hotspot/share/utilities/globalCounter.inline.hpp --- a/src/hotspot/share/utilities/globalCounter.inline.hpp Tue Nov 26 10:22:13 2019 +0000 +++ b/src/hotspot/share/utilities/globalCounter.inline.hpp Fri Nov 29 10:02:07 2019 +0000 @@ -26,7 +26,6 @@ #define SHARE_UTILITIES_GLOBALCOUNTER_INLINE_HPP #include "runtime/atomic.hpp" -#include "runtime/orderAccess.hpp" #include "runtime/thread.inline.hpp" #include "utilities/globalCounter.hpp" diff -r bfc8074ea4ef -r cfe31d2f935c src/hotspot/share/utilities/hashtable.inline.hpp --- a/src/hotspot/share/utilities/hashtable.inline.hpp Tue Nov 26 10:22:13 2019 +0000 +++ b/src/hotspot/share/utilities/hashtable.inline.hpp Fri Nov 29 10:02:07 2019 +0000 @@ -26,7 +26,7 @@ #define SHARE_UTILITIES_HASHTABLE_INLINE_HPP #include "memory/allocation.inline.hpp" -#include "runtime/orderAccess.hpp" +#include "runtime/atomic.hpp" #include "utilities/hashtable.hpp" #include "utilities/dtrace.hpp" diff -r bfc8074ea4ef -r cfe31d2f935c src/java.base/share/classes/java/io/InvalidClassException.java --- a/src/java.base/share/classes/java/io/InvalidClassException.java Tue Nov 26 10:22:13 2019 +0000 +++ b/src/java.base/share/classes/java/io/InvalidClassException.java Fri Nov 29 10:02:07 2019 +0000 @@ -33,6 +33,10 @@ * descriptor read from the stream *
  • The class contains unknown datatypes *
  • The class does not have an accessible no-arg constructor + *
  • The ObjectStreamClass of an enum constant does not represent + * an enum type + *
  • Other conditions given in the Java Object Serialization + * Specification * * * @author unascribed diff -r bfc8074ea4ef -r cfe31d2f935c src/java.base/share/classes/java/lang/Class.java --- a/src/java.base/share/classes/java/lang/Class.java Tue Nov 26 10:22:13 2019 +0000 +++ b/src/java.base/share/classes/java/lang/Class.java Fri Nov 29 10:02:07 2019 +0000 @@ -3503,7 +3503,9 @@ * Returns true if and only if this class was declared as an enum in the * source code. * - * Note that if an enum constant is declared with a class body, + * Note that {@link java.lang.Enum} is not itself an enum type. + * + * Also note that if an enum constant is declared with a class body, * the class of that enum constant object is an anonymous class * and not the class of the declaring enum type. The * {@link Enum#getDeclaringClass} method of an enum constant can diff -r bfc8074ea4ef -r cfe31d2f935c src/java.base/share/classes/java/lang/invoke/CallSite.java --- a/src/java.base/share/classes/java/lang/invoke/CallSite.java Tue Nov 26 10:22:13 2019 +0000 +++ b/src/java.base/share/classes/java/lang/invoke/CallSite.java Fri Nov 29 10:02:07 2019 +0000 @@ -87,9 +87,10 @@ abstract public class CallSite { - // The actual payload of this call site: + // The actual payload of this call site. + // Can be modified using {@link MethodHandleNatives#setCallSiteTargetNormal} or {@link MethodHandleNatives#setCallSiteTargetVolatile}. /*package-private*/ - MethodHandle target; // Note: This field is known to the JVM. Do not change. + final MethodHandle target; // Note: This field is known to the JVM. /** * Make a blank call site object with the given method type. @@ -129,11 +130,11 @@ */ /*package-private*/ CallSite(MethodType targetType, MethodHandle createTargetHook) throws Throwable { - this(targetType); + this(targetType); // need to initialize target to make CallSite.type() work in createTargetHook ConstantCallSite selfCCS = (ConstantCallSite) this; MethodHandle boundTarget = (MethodHandle) createTargetHook.invokeWithArguments(selfCCS); - checkTargetChange(this.target, boundTarget); - this.target = boundTarget; + setTargetNormal(boundTarget); // ConstantCallSite doesn't publish CallSite.target + UNSAFE.storeStoreFence(); // barrier between target and isFrozen updates } /** @@ -190,11 +191,12 @@ */ public abstract void setTarget(MethodHandle newTarget); - void checkTargetChange(MethodHandle oldTarget, MethodHandle newTarget) { - MethodType oldType = oldTarget.type(); + private void checkTargetChange(MethodHandle newTarget) { + MethodType oldType = target.type(); // target is always present MethodType newType = newTarget.type(); // null check! - if (!newType.equals(oldType)) + if (newType != oldType) { throw wrongTargetType(newTarget, oldType); + } } private static WrongMethodTypeException wrongTargetType(MethodHandle target, MethodType type) { @@ -217,7 +219,7 @@ */ public abstract MethodHandle dynamicInvoker(); - /*non-public*/ + /*package-private*/ MethodHandle makeDynamicInvoker() { MethodHandle getTarget = getTargetHandle().bindArgumentL(0, this); MethodHandle invoker = MethodHandles.exactInvoker(this.type()); @@ -283,19 +285,24 @@ } /*package-private*/ - void setTargetNormal(MethodHandle newTarget) { + final void setTargetNormal(MethodHandle newTarget) { + checkTargetChange(newTarget); MethodHandleNatives.setCallSiteTargetNormal(this, newTarget); } + /*package-private*/ - MethodHandle getTargetVolatile() { + final MethodHandle getTargetVolatile() { return (MethodHandle) UNSAFE.getReferenceVolatile(this, getTargetOffset()); } + /*package-private*/ - void setTargetVolatile(MethodHandle newTarget) { + final void setTargetVolatile(MethodHandle newTarget) { + checkTargetChange(newTarget); MethodHandleNatives.setCallSiteTargetVolatile(this, newTarget); } // this implements the upcall from the JVM, MethodHandleNatives.linkCallSite: + /*package-private*/ static CallSite makeSite(MethodHandle bootstrapMethod, // Callee information: String name, MethodType type, diff -r bfc8074ea4ef -r cfe31d2f935c src/java.base/share/classes/java/lang/invoke/ConstantCallSite.java --- a/src/java.base/share/classes/java/lang/invoke/ConstantCallSite.java Tue Nov 26 10:22:13 2019 +0000 +++ b/src/java.base/share/classes/java/lang/invoke/ConstantCallSite.java Fri Nov 29 10:02:07 2019 +0000 @@ -25,6 +25,9 @@ package java.lang.invoke; +import jdk.internal.misc.Unsafe; +import jdk.internal.vm.annotation.Stable; + /** * A {@code ConstantCallSite} is a {@link CallSite} whose target is permanent, and can never be changed. * An {@code invokedynamic} instruction linked to a {@code ConstantCallSite} is permanently @@ -33,7 +36,10 @@ * @since 1.7 */ public class ConstantCallSite extends CallSite { - private final boolean isFrozen; + private static final Unsafe UNSAFE = Unsafe.getUnsafe(); + + @Stable // should NOT be constant folded during instance initialization (isFrozen == false) + /*final*/ private boolean isFrozen; /** * Creates a call site with a permanent target. @@ -43,6 +49,7 @@ public ConstantCallSite(MethodHandle target) { super(target); isFrozen = true; + UNSAFE.storeStoreFence(); // properly publish isFrozen update } /** @@ -79,8 +86,9 @@ * @throws Throwable anything else thrown by the hook function */ protected ConstantCallSite(MethodType targetType, MethodHandle createTargetHook) throws Throwable { - super(targetType, createTargetHook); + super(targetType, createTargetHook); // "this" instance leaks into createTargetHook isFrozen = true; + UNSAFE.storeStoreFence(); // properly publish isFrozen } /** diff -r bfc8074ea4ef -r cfe31d2f935c src/java.base/share/classes/java/lang/invoke/MutableCallSite.java --- a/src/java.base/share/classes/java/lang/invoke/MutableCallSite.java Tue Nov 26 10:22:13 2019 +0000 +++ b/src/java.base/share/classes/java/lang/invoke/MutableCallSite.java Fri Nov 29 10:02:07 2019 +0000 @@ -152,7 +152,6 @@ * @see #getTarget */ @Override public void setTarget(MethodHandle newTarget) { - checkTargetChange(this.target, newTarget); setTargetNormal(newTarget); } diff -r bfc8074ea4ef -r cfe31d2f935c src/java.base/share/classes/java/lang/invoke/VolatileCallSite.java --- a/src/java.base/share/classes/java/lang/invoke/VolatileCallSite.java Tue Nov 26 10:22:13 2019 +0000 +++ b/src/java.base/share/classes/java/lang/invoke/VolatileCallSite.java Fri Nov 29 10:02:07 2019 +0000 @@ -96,7 +96,6 @@ * @see #getTarget */ @Override public void setTarget(MethodHandle newTarget) { - checkTargetChange(getTargetVolatile(), newTarget); setTargetVolatile(newTarget); } diff -r bfc8074ea4ef -r cfe31d2f935c src/java.base/share/classes/java/net/MulticastSocket.java --- a/src/java.base/share/classes/java/net/MulticastSocket.java Tue Nov 26 10:22:13 2019 +0000 +++ b/src/java.base/share/classes/java/net/MulticastSocket.java Fri Nov 29 10:02:07 2019 +0000 @@ -576,7 +576,7 @@ public NetworkInterface getNetworkInterface() throws SocketException { NetworkInterface ni = (NetworkInterface)getImpl().getOption(SocketOptions.IP_MULTICAST_IF2); - if ((ni.getIndex() == 0) || (ni.getIndex() == -1)) { + if (ni == null) { InetAddress[] addrs = new InetAddress[1]; addrs[0] = InetAddress.anyLocalAddress(); return new NetworkInterface(addrs[0].getHostName(), 0, addrs); diff -r bfc8074ea4ef -r cfe31d2f935c src/java.base/share/classes/java/util/Arrays.java --- a/src/java.base/share/classes/java/util/Arrays.java Tue Nov 26 10:22:13 2019 +0000 +++ b/src/java.base/share/classes/java/util/Arrays.java Fri Nov 29 10:02:07 2019 +0000 @@ -7117,10 +7117,10 @@ * and proper prefix.) * *

    A {@code null} array reference is considered lexicographically less - * than a non-{@code null} array reference. Two {@code null} array + * than a non-{@code null} array reference. Two {@code null} array * references are considered equal. - * A {@code null} array element is considered lexicographically than a - * non-{@code null} array element. Two {@code null} array elements are + * A {@code null} array element is considered lexicographically less than a + * non-{@code null} array element. Two {@code null} array elements are * considered equal. * *

    The comparison is consistent with {@link #equals(Object[], Object[]) equals}, diff -r bfc8074ea4ef -r cfe31d2f935c src/java.base/share/classes/jdk/internal/PreviewFeature.java --- a/src/java.base/share/classes/jdk/internal/PreviewFeature.java Tue Nov 26 10:22:13 2019 +0000 +++ b/src/java.base/share/classes/jdk/internal/PreviewFeature.java Fri Nov 29 10:02:07 2019 +0000 @@ -54,6 +54,8 @@ public boolean essentialAPI() default false; public enum Feature { - TEXT_BLOCKS; + PATTERN_MATCHING_IN_INSTANCEOF, + TEXT_BLOCKS, + ; } } diff -r bfc8074ea4ef -r cfe31d2f935c src/java.base/unix/native/libnet/PlainDatagramSocketImpl.c --- a/src/java.base/unix/native/libnet/PlainDatagramSocketImpl.c Tue Nov 26 10:22:13 2019 +0000 +++ b/src/java.base/unix/native/libnet/PlainDatagramSocketImpl.c Fri Nov 29 10:02:07 2019 +0000 @@ -1494,25 +1494,7 @@ if (ni) { return ni; } - - /* - * The address doesn't appear to be bound at any known - * NetworkInterface. Therefore we construct a NetworkInterface - * with this address. - */ - ni = (*env)->NewObject(env, ni_class, ni_ctrID, 0); - CHECK_NULL_RETURN(ni, NULL); - - (*env)->SetIntField(env, ni, ni_indexID, -1); - addrArray = (*env)->NewObjectArray(env, 1, inet4_class, NULL); - CHECK_NULL_RETURN(addrArray, NULL); - (*env)->SetObjectArrayElement(env, addrArray, 0, addr); - (*env)->SetObjectField(env, ni, ni_addrsID, addrArray); - ni_name = (*env)->NewStringUTF(env, ""); - if (ni_name != NULL) { - (*env)->SetObjectField(env, ni, ni_nameID, ni_name); - } - return ni; + return NULL; } @@ -1619,19 +1601,6 @@ if (opt == java_net_SocketOptions_IP_MULTICAST_IF) { return addr; } - - ni = (*env)->NewObject(env, ni_class, ni_ctrID, 0); - CHECK_NULL_RETURN(ni, NULL); - (*env)->SetIntField(env, ni, ni_indexID, -1); - addrArray = (*env)->NewObjectArray(env, 1, ia_class, NULL); - CHECK_NULL_RETURN(addrArray, NULL); - (*env)->SetObjectArrayElement(env, addrArray, 0, addr); - (*env)->SetObjectField(env, ni, ni_addrsID, addrArray); - ni_name = (*env)->NewStringUTF(env, ""); - if (ni_name != NULL) { - (*env)->SetObjectField(env, ni, ni_nameID, ni_name); - } - return ni; } return NULL; } diff -r bfc8074ea4ef -r cfe31d2f935c src/java.base/windows/native/libnet/TwoStacksPlainDatagramSocketImpl.c --- a/src/java.base/windows/native/libnet/TwoStacksPlainDatagramSocketImpl.c Tue Nov 26 10:22:13 2019 +0000 +++ b/src/java.base/windows/native/libnet/TwoStacksPlainDatagramSocketImpl.c Fri Nov 29 10:02:07 2019 +0000 @@ -1691,7 +1691,6 @@ static jfieldID ni_indexID; static jfieldID ni_addrsID; - jobjectArray addrArray; jobject addr; jobject ni; @@ -1749,19 +1748,7 @@ if (ni) { return ni; } - if (ipv4Mode) { - ni = (*env)->NewObject(env, ni_class, ni_ctrID, 0); - CHECK_NULL_RETURN(ni, NULL); - - (*env)->SetIntField(env, ni, ni_indexID, -1); - addrArray = (*env)->NewObjectArray(env, 1, inet4_class, NULL); - CHECK_NULL_RETURN(addrArray, NULL); - (*env)->SetObjectArrayElement(env, addrArray, 0, addr); - (*env)->SetObjectField(env, ni, ni_addrsID, addrArray); - } else { - ni = NULL; - } - return ni; + return NULL; } /* @@ -1898,26 +1885,6 @@ return netObject; } } - - /* - * Multicast to any address - return anyLocalAddress - * or a NetworkInterface with addrs[0] set to anyLocalAddress - */ - - addr = (*env)->CallStaticObjectMethod(env, ia_class, ia_anyLocalAddressID, - NULL); - if (opt == java_net_SocketOptions_IP_MULTICAST_IF) { - return addr; - } - - ni = (*env)->NewObject(env, ni_class, ni_ctrID, 0); - CHECK_NULL_RETURN(ni, NULL); - (*env)->SetIntField(env, ni, ni_indexID, -1); - addrArray = (*env)->NewObjectArray(env, 1, ia_class, NULL); - CHECK_NULL_RETURN(addrArray, NULL); - (*env)->SetObjectArrayElement(env, addrArray, 0, addr); - (*env)->SetObjectField(env, ni, ni_addrsID, addrArray); - return ni; } return NULL; } diff -r bfc8074ea4ef -r cfe31d2f935c src/java.rmi/share/classes/sun/rmi/transport/tcp/TCPConnection.java --- a/src/java.rmi/share/classes/sun/rmi/transport/tcp/TCPConnection.java Tue Nov 26 10:22:13 2019 +0000 +++ b/src/java.rmi/share/classes/sun/rmi/transport/tcp/TCPConnection.java Fri Nov 29 10:02:07 2019 +0000 @@ -209,7 +209,10 @@ * Close the connection. */ public void close() throws IOException { - TCPTransport.tcpLog.log(Log.BRIEF, "close connection"); + if (TCPTransport.tcpLog.isLoggable(Log.BRIEF)) { + TCPTransport.tcpLog.log(Log.BRIEF, + "close connection, socket: " + socket); + } if (socket != null) socket.close(); diff -r bfc8074ea4ef -r cfe31d2f935c src/java.rmi/share/classes/sun/rmi/transport/tcp/TCPTransport.java --- a/src/java.rmi/share/classes/sun/rmi/transport/tcp/TCPTransport.java Tue Nov 26 10:22:13 2019 +0000 +++ b/src/java.rmi/share/classes/sun/rmi/transport/tcp/TCPTransport.java Fri Nov 29 10:02:07 2019 +0000 @@ -273,12 +273,23 @@ private void decrementExportCount() { assert Thread.holdsLock(this); exportCount--; + if (tcpLog.isLoggable(Log.VERBOSE)) { + tcpLog.log(Log.VERBOSE, + "server socket: " + server + ", exportCount: " + exportCount); + } if (exportCount == 0 && getEndpoint().getListenPort() != 0) { ServerSocket ss = server; server = null; try { + if (tcpLog.isLoggable(Log.BRIEF)) { + tcpLog.log(Log.BRIEF, "server socket close: " + ss); + } ss.close(); } catch (IOException e) { + if (tcpLog.isLoggable(Log.BRIEF)) { + tcpLog.log(Log.BRIEF, + "server socket close throws: " + e); + } } } } @@ -366,6 +377,10 @@ executeAcceptLoop(); } finally { try { + if (tcpLog.isLoggable(Log.BRIEF)) { + tcpLog.log(Log.BRIEF, + "server socket close: " + serverSocket); + } /* * Only one accept loop is started per server * socket, so after no more connections will be @@ -374,6 +389,10 @@ */ serverSocket.close(); } catch (IOException e) { + if (tcpLog.isLoggable(Log.BRIEF)) { + tcpLog.log(Log.BRIEF, + "server socket close throws: " + e); + } } } } @@ -524,9 +543,15 @@ /** close socket and eat exception */ private static void closeSocket(Socket sock) { try { + if (tcpLog.isLoggable(Log.BRIEF)) { + tcpLog.log(Log.BRIEF, "socket close: " + sock); + } sock.close(); } catch (IOException ex) { // eat exception + if (tcpLog.isLoggable(Log.BRIEF)) { + tcpLog.log(Log.BRIEF, "socket close throws: " + ex); + } } } @@ -591,6 +616,9 @@ conn.close(); } catch (IOException ex) { // eat exception + if (tcpLog.isLoggable(Log.BRIEF)) { + tcpLog.log(Log.BRIEF, "Connection close throws " + ex); + } } } } @@ -723,6 +751,10 @@ // just close socket: this would recurse if we marshal an // exception to the client and the protocol at other end // doesn't match. + if (tcpLog.isLoggable(Log.BRIEF)) { + tcpLog.log(Log.BRIEF, "magic or version not match: " + + magic + ", " + version); + } closeSocket(socket); return; } diff -r bfc8074ea4ef -r cfe31d2f935c src/jdk.compiler/share/classes/com/sun/source/tree/BindingPatternTree.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/jdk.compiler/share/classes/com/sun/source/tree/BindingPatternTree.java Fri Nov 29 10:02:07 2019 +0000 @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2017, 2019, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package com.sun.source.tree; + +import javax.lang.model.element.Name; + +/** + * {@preview Associated with pattern matching for instanceof, a preview feature of + * the Java language. + * + * This interface is associated with pattern matching for instanceof, a preview + * feature of the Java language. Preview features + * may be removed in a future release, or upgraded to permanent + * features of the Java language.} + * + * A binding pattern tree + * + * @since 14 + */ +public interface BindingPatternTree extends PatternTree { + + /** + * Returns the type of the bind variable. + * @return the type + */ + Tree getType(); + + /** + * A binding variable name. + * @return the name of the binding variable + */ + Name getBinding(); + +} + diff -r bfc8074ea4ef -r cfe31d2f935c src/jdk.compiler/share/classes/com/sun/source/tree/InstanceOfTree.java --- a/src/jdk.compiler/share/classes/com/sun/source/tree/InstanceOfTree.java Tue Nov 26 10:22:13 2019 +0000 +++ b/src/jdk.compiler/share/classes/com/sun/source/tree/InstanceOfTree.java Fri Nov 29 10:02:07 2019 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2019, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -51,4 +51,33 @@ * @return the type */ Tree getType(); + + /** + * {@preview Associated with pattern matching for instanceof, a preview feature of + * the Java language. + * + * This method is associated with pattern matching for instanceof, a preview + * feature of the Java language. Preview features + * may be removed in a future release, or upgraded to permanent + * features of the Java language.} + * + * Returns the tested pattern, or null if this instanceof does not use + * a pattern. + * + *

    For instanceof with a pattern, i.e. in the following form: + *

    +     *   expression instanceof type variable name
    +     * 
    + * returns the pattern. + * + *

    For instanceof without a pattern, i.e. in the following form: + *

    +     *   expression instanceof type
    +     * 
    + * returns null. + * + * @return the tested pattern, or null if this instanceof does not use a pattern. + * @since 14 + */ + PatternTree getPattern(); } diff -r bfc8074ea4ef -r cfe31d2f935c src/jdk.compiler/share/classes/com/sun/source/tree/PatternTree.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/jdk.compiler/share/classes/com/sun/source/tree/PatternTree.java Fri Nov 29 10:02:07 2019 +0000 @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2017, 2019, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package com.sun.source.tree; + +/** + * {@preview Associated with pattern matching for instanceof, a preview feature of + * the Java language. + * + * This interface is associated with pattern matching for instanceof, a preview + * feature of the Java language. Preview features + * may be removed in a future release, or upgraded to permanent + * features of the Java language.} + * + * A tree node used as the base class for the different kinds of + * statements. + * + * @since 14 + */ +public interface PatternTree extends Tree {} diff -r bfc8074ea4ef -r cfe31d2f935c src/jdk.compiler/share/classes/com/sun/source/tree/Tree.java --- a/src/jdk.compiler/share/classes/com/sun/source/tree/Tree.java Tue Nov 26 10:22:13 2019 +0000 +++ b/src/jdk.compiler/share/classes/com/sun/source/tree/Tree.java Fri Nov 29 10:02:07 2019 +0000 @@ -220,6 +220,21 @@ PARENTHESIZED(ParenthesizedTree.class), /** + * {@preview Associated with pattern matching for instanceof, a preview feature of + * the Java language. + * + * This enum constant is associated with pattern matching for instanceof, a preview + * feature of the Java language. Preview features + * may be removed in a future release, or upgraded to permanent + * features of the Java language.} + * + * Used for instances of {@link BindingPatternTree}. + * + * @since 14 + */ + BINDING_PATTERN(BindingPatternTree.class), + + /** * Used for instances of {@link PrimitiveTypeTree}. */ PRIMITIVE_TYPE(PrimitiveTypeTree.class), diff -r bfc8074ea4ef -r cfe31d2f935c src/jdk.compiler/share/classes/com/sun/source/tree/TreeVisitor.java --- a/src/jdk.compiler/share/classes/com/sun/source/tree/TreeVisitor.java Tue Nov 26 10:22:13 2019 +0000 +++ b/src/jdk.compiler/share/classes/com/sun/source/tree/TreeVisitor.java Fri Nov 29 10:02:07 2019 +0000 @@ -258,6 +258,23 @@ R visitLiteral(LiteralTree node, P p); /** + * {@preview Associated with pattern matching for instanceof, a preview feature of + * the Java language. + * + * This method is associated with pattern matching for instanceof, a preview + * feature of the Java language. Preview features + * may be removed in a future release, or upgraded to permanent + * features of the Java language.} + * + * Visits an BindingPattern node. + * @param node the node being visited + * @param p a parameter value + * @return a result value + * @since 14 + */ + R visitBindingPattern(BindingPatternTree node, P p); + + /** * Visits a MethodTree node. * @param node the node being visited * @param p a parameter value diff -r bfc8074ea4ef -r cfe31d2f935c src/jdk.compiler/share/classes/com/sun/source/util/SimpleTreeVisitor.java --- a/src/jdk.compiler/share/classes/com/sun/source/util/SimpleTreeVisitor.java Tue Nov 26 10:22:13 2019 +0000 +++ b/src/jdk.compiler/share/classes/com/sun/source/util/SimpleTreeVisitor.java Fri Nov 29 10:02:07 2019 +0000 @@ -557,6 +557,19 @@ * @param node {@inheritDoc} * @param p {@inheritDoc} * @return the result of {@code defaultAction} + * @since 14 + */ + @Override + public R visitBindingPattern(BindingPatternTree node, P p) { + return defaultAction(node, p); + } + + /** + * {@inheritDoc} This implementation calls {@code defaultAction}. + * + * @param node {@inheritDoc} + * @param p {@inheritDoc} + * @return the result of {@code defaultAction} */ @Override public R visitArrayAccess(ArrayAccessTree node, P p) { diff -r bfc8074ea4ef -r cfe31d2f935c src/jdk.compiler/share/classes/com/sun/source/util/TreeScanner.java --- a/src/jdk.compiler/share/classes/com/sun/source/util/TreeScanner.java Tue Nov 26 10:22:13 2019 +0000 +++ b/src/jdk.compiler/share/classes/com/sun/source/util/TreeScanner.java Fri Nov 29 10:02:07 2019 +0000 @@ -667,7 +667,11 @@ @Override public R visitInstanceOf(InstanceOfTree node, P p) { R r = scan(node.getExpression(), p); - r = scanAndReduce(node.getType(), p, r); + if (node.getPattern() != null) { + r = scanAndReduce(node.getPattern(), p, r); + } else { + r = scanAndReduce(node.getType(), p, r); + } return r; } @@ -677,6 +681,19 @@ * @param node {@inheritDoc} * @param p {@inheritDoc} * @return the result of scanning + * @since 14 + */ + @Override + public R visitBindingPattern(BindingPatternTree node, P p) { + return scan(node.getType(), p); + } + + /** + * {@inheritDoc} This implementation scans the children in left to right order. + * + * @param node {@inheritDoc} + * @param p {@inheritDoc} + * @return the result of scanning */ @Override public R visitArrayAccess(ArrayAccessTree node, P p) { diff -r bfc8074ea4ef -r cfe31d2f935c src/jdk.compiler/share/classes/com/sun/tools/javac/code/Flags.java --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Flags.java Tue Nov 26 10:22:13 2019 +0000 +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Flags.java Fri Nov 29 10:02:07 2019 +0000 @@ -334,6 +334,16 @@ */ public static final long PREVIEW_ESSENTIAL_API = 1L<<58; //any Symbol kind + /** + * Flag to indicate the given variable is a match binding variable. + */ + public static final long MATCH_BINDING = 1L<<59; + + /** + * A flag to indicate a match binding variable whose scope extends after the current statement. + */ + public static final long MATCH_BINDING_TO_OUTER = 1L<<60; + /** Modifier masks. */ public static final int @@ -453,7 +463,9 @@ ANONCONSTR_BASED(Flags.ANONCONSTR_BASED), NAME_FILLED(Flags.NAME_FILLED), PREVIEW_API(Flags.PREVIEW_API), - PREVIEW_ESSENTIAL_API(Flags.PREVIEW_ESSENTIAL_API); + PREVIEW_ESSENTIAL_API(Flags.PREVIEW_ESSENTIAL_API), + MATCH_BINDING(Flags.MATCH_BINDING), + MATCH_BINDING_TO_OUTER(Flags.MATCH_BINDING_TO_OUTER); Flag(long flag) { this.value = flag; diff -r bfc8074ea4ef -r cfe31d2f935c src/jdk.compiler/share/classes/com/sun/tools/javac/code/Preview.java --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Preview.java Tue Nov 26 10:22:13 2019 +0000 +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Preview.java Fri Nov 29 10:02:07 2019 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2019, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -165,7 +165,9 @@ * @return true, if given feature is a preview feature. */ public boolean isPreview(Feature feature) { - if (feature == Feature.TEXT_BLOCKS) + if (feature == Feature.PATTERN_MATCHING_IN_INSTANCEOF || + feature == Feature.REIFIABLE_TYPES_INSTANCEOF || + feature == Feature.TEXT_BLOCKS) return true; //Note: this is a backdoor which allows to optionally treat all features as 'preview' (for testing). //When real preview features will be added, this method can be implemented to return 'true' diff -r bfc8074ea4ef -r cfe31d2f935c src/jdk.compiler/share/classes/com/sun/tools/javac/code/Source.java --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Source.java Tue Nov 26 10:22:13 2019 +0000 +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Source.java Fri Nov 29 10:02:07 2019 +0000 @@ -198,7 +198,10 @@ SWITCH_MULTIPLE_CASE_LABELS(JDK14, Fragments.FeatureMultipleCaseLabels, DiagKind.PLURAL), SWITCH_RULE(JDK14, Fragments.FeatureSwitchRules, DiagKind.PLURAL), SWITCH_EXPRESSION(JDK14, Fragments.FeatureSwitchExpressions, DiagKind.PLURAL), - TEXT_BLOCKS(JDK14, Fragments.FeatureTextBlocks, DiagKind.PLURAL); + TEXT_BLOCKS(JDK14, Fragments.FeatureTextBlocks, DiagKind.PLURAL), + PATTERN_MATCHING_IN_INSTANCEOF(JDK14, Fragments.FeaturePatternMatchingInstanceof, DiagKind.NORMAL), + REIFIABLE_TYPES_INSTANCEOF(JDK14, Fragments.FeatureReifiableTypesInstanceof, DiagKind.PLURAL), + ; enum DiagKind { NORMAL, diff -r bfc8074ea4ef -r cfe31d2f935c src/jdk.compiler/share/classes/com/sun/tools/javac/code/TypeAnnotations.java --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/code/TypeAnnotations.java Tue Nov 26 10:22:13 2019 +0000 +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/code/TypeAnnotations.java Fri Nov 29 10:02:07 2019 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2009, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2009, 2019, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -390,22 +390,26 @@ sym.getKind() == ElementKind.LOCAL_VARIABLE || sym.getKind() == ElementKind.RESOURCE_VARIABLE || sym.getKind() == ElementKind.EXCEPTION_PARAMETER) { - // Make sure all type annotations from the symbol are also - // on the owner. If the owner is an initializer block, propagate - // to the type. - final long ownerFlags = sym.owner.flags(); - if ((ownerFlags & Flags.BLOCK) != 0) { - // Store init and clinit type annotations with the ClassSymbol - // to allow output in Gen.normalizeDefs. - ClassSymbol cs = (ClassSymbol) sym.owner.owner; - if ((ownerFlags & Flags.STATIC) != 0) { - cs.appendClassInitTypeAttributes(typeAnnotations); - } else { - cs.appendInitTypeAttributes(typeAnnotations); - } + appendTypeAnnotationsToOwner(sym, typeAnnotations); + } + } + + private void appendTypeAnnotationsToOwner(Symbol sym, List typeAnnotations) { + // Make sure all type annotations from the symbol are also + // on the owner. If the owner is an initializer block, propagate + // to the type. + final long ownerFlags = sym.owner.flags(); + if ((ownerFlags & Flags.BLOCK) != 0) { + // Store init and clinit type annotations with the ClassSymbol + // to allow output in Gen.normalizeDefs. + ClassSymbol cs = (ClassSymbol) sym.owner.owner; + if ((ownerFlags & Flags.STATIC) != 0) { + cs.appendClassInitTypeAttributes(typeAnnotations); } else { - sym.owner.appendUniqueTypeAttributes(sym.getRawTypeAttributes()); + cs.appendInitTypeAttributes(typeAnnotations); } + } else { + sym.owner.appendUniqueTypeAttributes(typeAnnotations); } } @@ -943,10 +947,11 @@ " within frame " + frame); } + case BINDING_PATTERN: case VARIABLE: - VarSymbol v = ((JCVariableDecl)frame).sym; + VarSymbol v = frame.hasTag(Tag.BINDINGPATTERN) ? ((JCBindingPattern) frame).symbol : ((JCVariableDecl) frame).sym; if (v.getKind() != ElementKind.FIELD) { - v.owner.appendUniqueTypeAttributes(v.getRawTypeAttributes()); + appendTypeAnnotationsToOwner(v, v.getRawTypeAttributes()); } switch (v.getKind()) { case LOCAL_VARIABLE: diff -r bfc8074ea4ef -r cfe31d2f935c src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Annotate.java --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Annotate.java Tue Nov 26 10:22:13 2019 +0000 +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Annotate.java Fri Nov 29 10:02:07 2019 +0000 @@ -1122,6 +1122,13 @@ } @Override + public void visitBindingPattern(JCTree.JCBindingPattern tree) { + //type binding pattern's type will be annotated separatelly, avoid + //adding its annotations into the owning method here (would clash + //with repeatable annotations). + } + + @Override public void visitClassDef(JCClassDecl tree) { // We can only hit a classdef if it is declared within // a method. Ignore it - the class will be visited diff -r bfc8074ea4ef -r cfe31d2f935c src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Attr.java --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Attr.java Tue Nov 26 10:22:13 2019 +0000 +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Attr.java Fri Nov 29 10:02:07 2019 +0000 @@ -49,6 +49,7 @@ import com.sun.tools.javac.comp.ArgumentAttr.LocalCacheContext; import com.sun.tools.javac.comp.Check.CheckContext; import com.sun.tools.javac.comp.DeferredAttr.AttrMode; +import com.sun.tools.javac.comp.MatchBindingsComputer.BindingSymbol; import com.sun.tools.javac.jvm.*; import static com.sun.tools.javac.resources.CompilerProperties.Fragments.Diamond; import static com.sun.tools.javac.resources.CompilerProperties.Fragments.DiamondInvalidArg; @@ -110,6 +111,7 @@ final Enter enter; final Target target; final Types types; + final Preview preview; final JCDiagnostic.Factory diags; final TypeAnnotations typeAnnotations; final DeferredLintHandler deferredLintHandler; @@ -117,6 +119,7 @@ final Dependencies dependencies; final Annotate annotate; final ArgumentAttr argumentAttr; + final MatchBindingsComputer matchBindingsComputer; public static Attr instance(Context context) { Attr instance = context.get(attrKey); @@ -145,6 +148,7 @@ cfolder = ConstFold.instance(context); target = Target.instance(context); types = Types.instance(context); + preview = Preview.instance(context); diags = JCDiagnostic.Factory.instance(context); annotate = Annotate.instance(context); typeAnnotations = TypeAnnotations.instance(context); @@ -152,6 +156,7 @@ typeEnvs = TypeEnvs.instance(context); dependencies = Dependencies.instance(context); argumentAttr = ArgumentAttr.instance(context); + matchBindingsComputer = MatchBindingsComputer.instance(context); Options options = Options.instance(context); @@ -161,6 +166,9 @@ allowLambda = Feature.LAMBDA.allowedInSource(source); allowDefaultMethods = Feature.DEFAULT_METHODS.allowedInSource(source); allowStaticInterfaceMethods = Feature.STATIC_INTERFACE_METHODS.allowedInSource(source); + allowReifiableTypesInInstanceof = + Feature.REIFIABLE_TYPES_INSTANCEOF.allowedInSource(source) && + (!preview.isPreview(Feature.REIFIABLE_TYPES_INSTANCEOF) || preview.isEnabled()); sourceName = source.name; useBeforeDeclarationWarning = options.isSet("useBeforeDeclarationWarning"); @@ -193,6 +201,10 @@ */ boolean allowStaticInterfaceMethods; + /** Switch: reifiable types in instanceof enabled? + */ + boolean allowReifiableTypesInInstanceof; + /** * Switch: warn about use of variable before declaration? * RFE: 6425594 @@ -292,6 +304,8 @@ isAssignableAsBlankFinal(v, env)))) { if (v.isResourceVariable()) { //TWR resource log.error(pos, Errors.TryResourceMayNotBeAssigned(v)); + } else if ((v.flags() & MATCH_BINDING) != 0) { + log.error(pos, Errors.PatternBindingMayNotBeAssigned(v)); } else { log.error(pos, Errors.CantAssignValToFinalVar(v)); } @@ -1298,29 +1312,73 @@ public void visitDoLoop(JCDoWhileLoop tree) { attribStat(tree.body, env.dup(tree)); attribExpr(tree.cond, env, syms.booleanType); + if (!breaksOutOf(tree, tree.body)) { + //include condition's body when false after the while, if cannot get out of the loop + List bindings = matchBindingsComputer.getMatchBindings(tree.cond, false); + + bindings.forEach(env.info.scope::enter); + bindings.forEach(BindingSymbol::preserveBinding); + } result = null; } public void visitWhileLoop(JCWhileLoop tree) { attribExpr(tree.cond, env, syms.booleanType); - attribStat(tree.body, env.dup(tree)); + // include condition's bindings when true in the body: + Env whileEnv = bindingEnv(env, matchBindingsComputer.getMatchBindings(tree.cond, true)); + try { + attribStat(tree.body, whileEnv.dup(tree)); + } finally { + whileEnv.info.scope.leave(); + } + if (!breaksOutOf(tree, tree.body)) { + //include condition's bindings when false after the while, if cannot get out of the loop + List bindings = + matchBindingsComputer.getMatchBindings(tree.cond, false); + + bindings.forEach(env.info.scope::enter); + bindings.forEach(BindingSymbol::preserveBinding); + } result = null; } + private boolean breaksOutOf(JCTree loop, JCTree body) { + preFlow(body); + return flow.breaksOutOf(env, loop, body, make); + } + public void visitForLoop(JCForLoop tree) { Env loopEnv = env.dup(env.tree, env.info.dup(env.info.scope.dup())); try { attribStats(tree.init, loopEnv); - if (tree.cond != null) attribExpr(tree.cond, loopEnv, syms.booleanType); - loopEnv.tree = tree; // before, we were not in loop! - attribStats(tree.step, loopEnv); - attribStat(tree.body, loopEnv); + List matchBindings = List.nil(); + if (tree.cond != null) { + attribExpr(tree.cond, loopEnv, syms.booleanType); + // include condition's bindings when true in the body and step: + matchBindings = matchBindingsComputer.getMatchBindings(tree.cond, true); + } + Env bodyEnv = bindingEnv(loopEnv, matchBindings); + try { + bodyEnv.tree = tree; // before, we were not in loop! + attribStats(tree.step, bodyEnv); + attribStat(tree.body, bodyEnv); + } finally { + bodyEnv.info.scope.leave(); + } result = null; } finally { loopEnv.info.scope.leave(); } + if (!breaksOutOf(tree, tree.body)) { + //include condition's body when false after the while, if cannot get out of the loop + List bindings = + matchBindingsComputer.getMatchBindings(tree.cond, false); + + bindings.forEach(env.info.scope::enter); + bindings.forEach(BindingSymbol::preserveBinding); + } } public void visitForeachLoop(JCEnhancedForLoop tree) { @@ -1673,8 +1731,26 @@ unknownExprInfo : resultInfo.dup(conditionalContext(resultInfo.checkContext)); - Type truetype = attribTree(tree.truepart, env, condInfo); - Type falsetype = attribTree(tree.falsepart, env, condInfo); + + // x ? y : z + // include x's bindings when true in y + // include x's bindings when false in z + + Type truetype; + Env trueEnv = bindingEnv(env, matchBindingsComputer.getMatchBindings(tree.cond, true)); + try { + truetype = attribTree(tree.truepart, trueEnv, condInfo); + } finally { + trueEnv.info.scope.leave(); + } + + Type falsetype; + Env falseEnv = bindingEnv(env, matchBindingsComputer.getMatchBindings(tree.cond, false)); + try { + falsetype = attribTree(tree.falsepart, falseEnv, condInfo); + } finally { + falseEnv.info.scope.leave(); + } Type owntype = (tree.polyKind == PolyKind.STANDALONE) ? condType(List.of(tree.truepart.pos(), tree.falsepart.pos()), @@ -1829,15 +1905,77 @@ BOOLEAN, }; + Env bindingEnv(Env env, List bindings) { + Env env1 = env.dup(env.tree, env.info.dup(env.info.scope.dup())); + bindings.forEach(env1.info.scope::enter); + return env1; + } + public void visitIf(JCIf tree) { attribExpr(tree.cond, env, syms.booleanType); - attribStat(tree.thenpart, env); - if (tree.elsepart != null) - attribStat(tree.elsepart, env); + + // if (x) { y } [ else z ] + // include x's bindings when true in y + // include x's bindings when false in z + + List thenBindings = matchBindingsComputer.getMatchBindings(tree.cond, true); + Env thenEnv = bindingEnv(env, thenBindings); + + try { + attribStat(tree.thenpart, thenEnv); + } finally { + thenEnv.info.scope.leave(); + } + + preFlow(tree.thenpart); + boolean aliveAfterThen = flow.aliveAfter(env, tree.thenpart, make); + boolean aliveAfterElse; + List elseBindings = matchBindingsComputer.getMatchBindings(tree.cond, false); + + if (tree.elsepart != null) { + Env elseEnv = bindingEnv(env, elseBindings); + try { + attribStat(tree.elsepart, elseEnv); + } finally { + elseEnv.info.scope.leave(); + } + preFlow(tree.elsepart); + aliveAfterElse = flow.aliveAfter(env, tree.elsepart, make); + } else { + aliveAfterElse = true; + } + chk.checkEmptyIf(tree); + + List afterIfBindings = List.nil(); + + if (aliveAfterThen && !aliveAfterElse) { + afterIfBindings = thenBindings; + } else if (aliveAfterElse && !aliveAfterThen) { + afterIfBindings = elseBindings; + } + + afterIfBindings.forEach(env.info.scope::enter); + afterIfBindings.forEach(BindingSymbol::preserveBinding); + result = null; } + void preFlow(JCTree tree) { + new PostAttrAnalyzer() { + @Override + public void scan(JCTree tree) { + if (tree == null || + (tree.type != null && + tree.type == Type.stuckType)) { + //don't touch stuck expressions! + return; + } + super.scan(tree); + } + }.scan(tree); + } + public void visitExec(JCExpressionStatement tree) { //a fresh environment is required for 292 inference to work properly --- //see Infer.instantiatePolymorphicSignatureInstance() @@ -3521,7 +3659,32 @@ public void visitBinary(JCBinary tree) { // Attribute arguments. Type left = chk.checkNonVoid(tree.lhs.pos(), attribExpr(tree.lhs, env)); - Type right = chk.checkNonVoid(tree.rhs.pos(), attribExpr(tree.rhs, env)); + // x && y + // include x's bindings when true in y + + // x || y + // include x's bindings when false in y + + List matchBindings; + switch (tree.getTag()) { + case AND: + matchBindings = matchBindingsComputer.getMatchBindings(tree.lhs, true); + break; + case OR: + matchBindings = matchBindingsComputer.getMatchBindings(tree.lhs, false); + break; + default: + matchBindings = List.nil(); + break; + } + Env rhsEnv = bindingEnv(env, matchBindings); + Type right; + try { + right = chk.checkNonVoid(tree.rhs.pos(), attribExpr(tree.rhs, rhsEnv)); + } finally { + rhsEnv.info.scope.leave(); + } + // Find operator. Symbol operator = tree.operator = operators.resolveBinary(tree, tree.getTag(), left, right); Type owntype = types.createErrorType(tree.type); @@ -3587,19 +3750,63 @@ public void visitTypeTest(JCInstanceOf tree) { Type exprtype = chk.checkNullOrRefType( tree.expr.pos(), attribExpr(tree.expr, env)); - Type clazztype = attribType(tree.clazz, env); + Type clazztype; + JCTree typeTree; + if (tree.pattern.getTag() == BINDINGPATTERN) { + attribTree(tree.pattern, env, unknownExprInfo); + clazztype = tree.pattern.type; + JCBindingPattern pattern = (JCBindingPattern) tree.pattern; + typeTree = pattern.vartype; + if (!clazztype.hasTag(TYPEVAR)) { + clazztype = chk.checkClassOrArrayType(pattern.vartype.pos(), clazztype); + } + } else { + clazztype = attribType(tree.pattern, env); + typeTree = tree.pattern; + } if (!clazztype.hasTag(TYPEVAR)) { - clazztype = chk.checkClassOrArrayType(tree.clazz.pos(), clazztype); + clazztype = chk.checkClassOrArrayType(typeTree.pos(), clazztype); } if (!clazztype.isErroneous() && !types.isReifiable(clazztype)) { - log.error(tree.clazz.pos(), Errors.IllegalGenericTypeForInstof); - clazztype = types.createErrorType(clazztype); - } - chk.validate(tree.clazz, env, false); + boolean valid = false; + if (allowReifiableTypesInInstanceof) { + if (preview.isPreview(Feature.REIFIABLE_TYPES_INSTANCEOF)) { + preview.warnPreview(tree.expr.pos(), Feature.REIFIABLE_TYPES_INSTANCEOF); + } + Warner warner = new Warner(); + if (!types.isCastable(exprtype, clazztype, warner)) { + chk.basicHandler.report(tree.expr.pos(), + diags.fragment(Fragments.InconvertibleTypes(exprtype, clazztype))); + } else if (warner.hasLint(LintCategory.UNCHECKED)) { + log.error(tree.expr.pos(), + Errors.InstanceofReifiableNotSafe(exprtype, clazztype)); + } else { + valid = true; + } + } else { + log.error(typeTree.pos(), Errors.IllegalGenericTypeForInstof); + } + if (!valid) { + clazztype = types.createErrorType(clazztype); + } + } + chk.validate(typeTree, env, false); chk.checkCastable(tree.expr.pos(), exprtype, clazztype); result = check(tree, syms.booleanType, KindSelector.VAL, resultInfo); } + public void visitBindingPattern(JCBindingPattern tree) { + ResultInfo varInfo = new ResultInfo(KindSelector.TYP, resultInfo.pt, resultInfo.checkContext); + tree.type = attribTree(tree.vartype, env, varInfo); + VarSymbol v = tree.symbol = new BindingSymbol(tree.name, tree.vartype.type, env.info.scope.owner); + if (chk.checkUnique(tree.pos(), v, env.info.scope)) { + chk.checkTransparentVar(tree.pos(), v, env.info.scope); + } + annotate.queueScanTreeAndTypeAnnotate(tree.vartype, env, v, tree.pos()); + annotate.flush(); + result = tree.type; + } + public void visitIndexed(JCArrayAccess tree) { Type owntype = types.createErrorType(tree.type); Type atype = attribExpr(tree.indexed, env); @@ -4991,8 +5198,8 @@ super.visitTypeCast(tree); } public void visitTypeTest(JCInstanceOf tree) { - if (tree.clazz != null && tree.clazz.type != null) - validateAnnotatedType(tree.clazz, tree.clazz.type); + if (tree.pattern != null && !(tree.pattern instanceof JCPattern) && tree.pattern.type != null) + validateAnnotatedType(tree.pattern, tree.pattern.type); super.visitTypeTest(tree); } public void visitNewClass(JCNewClass tree) { @@ -5253,6 +5460,15 @@ } @Override + public void visitBindingPattern(JCBindingPattern that) { + if (that.symbol == null) { + that.symbol = new BindingSymbol(that.name, that.type, syms.noSymbol); + that.symbol.adr = 0; + } + super.visitBindingPattern(that); + } + + @Override public void visitNewClass(JCNewClass that) { if (that.constructor == null) { that.constructor = new MethodSymbol(0, names.init, diff -r bfc8074ea4ef -r cfe31d2f935c src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Check.java --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Check.java Tue Nov 26 10:22:13 2019 +0000 +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Check.java Fri Nov 29 10:02:07 2019 +0000 @@ -3486,6 +3486,11 @@ duplicateErasureError(pos, sym, byName); sym.flags_field |= CLASH; return true; + } else if ((sym.flags() & MATCH_BINDING) != 0 && + (byName.flags() & MATCH_BINDING) != 0 && + (byName.flags() & MATCH_BINDING_TO_OUTER) == 0) { + //this error will be reported separatelly in MatchBindingsComputer + return false; } else { duplicateError(pos, byName); return false; diff -r bfc8074ea4ef -r cfe31d2f935c src/jdk.compiler/share/classes/com/sun/tools/javac/comp/CompileStates.java --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/CompileStates.java Tue Nov 26 10:22:13 2019 +0000 +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/CompileStates.java Fri Nov 29 10:02:07 2019 +0000 @@ -59,9 +59,10 @@ ATTR(4), FLOW(5), TRANSTYPES(6), - UNLAMBDA(7), - LOWER(8), - GENERATE(9); + TRANSPATTERNS(7), + UNLAMBDA(8), + LOWER(9), + GENERATE(10); CompileState(int value) { this.value = value; diff -r bfc8074ea4ef -r cfe31d2f935c src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Flow.java --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Flow.java Tue Nov 26 10:22:13 2019 +0000 +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Flow.java Fri Nov 29 10:02:07 2019 +0000 @@ -255,6 +255,41 @@ } } + public boolean aliveAfter(Env env, JCTree that, TreeMaker make) { + //we need to disable diagnostics temporarily; the problem is that if + //"that" contains e.g. an unreachable statement, an error + //message will be reported and will cause compilation to skip the flow analyis + //step - if we suppress diagnostics, we won't stop at Attr for flow-analysis + //related errors, which will allow for more errors to be detected + Log.DiagnosticHandler diagHandler = new Log.DiscardDiagnosticHandler(log); + try { + SnippetAliveAnalyzer analyzer = new SnippetAliveAnalyzer(); + + analyzer.analyzeTree(env, that, make); + return analyzer.isAlive(); + } finally { + log.popDiagnosticHandler(diagHandler); + } + } + + public boolean breaksOutOf(Env env, JCTree loop, JCTree body, TreeMaker make) { + //we need to disable diagnostics temporarily; the problem is that if + //"that" contains e.g. an unreachable statement, an error + //message will be reported and will cause compilation to skip the flow analyis + //step - if we suppress diagnostics, we won't stop at Attr for flow-analysis + //related errors, which will allow for more errors to be detected + Log.DiagnosticHandler diagHandler = new Log.DiscardDiagnosticHandler(log); + try { + boolean[] breaksOut = new boolean[1]; + SnippetBreakAnalyzer analyzer = new SnippetBreakAnalyzer(loop); + + analyzer.analyzeTree(env, body, make); + return analyzer.breaksOut(); + } finally { + log.popDiagnosticHandler(diagHandler); + } + } + /** * Definite assignment scan mode */ @@ -1467,6 +1502,38 @@ } /** + * Determine if alive after the given tree. + */ + class SnippetAliveAnalyzer extends AliveAnalyzer { + @Override + public void visitClassDef(JCClassDecl tree) { + //skip + } + public boolean isAlive() { + return super.alive != Liveness.DEAD; + } + } + + class SnippetBreakAnalyzer extends AliveAnalyzer { + private final JCTree loop; + private boolean breaksOut; + + public SnippetBreakAnalyzer(JCTree loop) { + this.loop = loop; + } + + @Override + public void visitBreak(JCBreak tree) { + breaksOut |= (super.alive == Liveness.ALIVE && tree.target == loop); + super.visitBreak(tree); + } + + public boolean breaksOut() { + return breaksOut; + } + } + + /** * Specialized pass that performs DA/DU on a lambda */ class LambdaAssignAnalyzer extends AssignAnalyzer { diff -r bfc8074ea4ef -r cfe31d2f935c src/jdk.compiler/share/classes/com/sun/tools/javac/comp/MatchBindingsComputer.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/MatchBindingsComputer.java Fri Nov 29 10:02:07 2019 +0000 @@ -0,0 +1,216 @@ +/* + * Copyright (c) 2017, 2019, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package com.sun.tools.javac.comp; + +import com.sun.tools.javac.code.Flags; +import com.sun.tools.javac.code.Symbol; +import com.sun.tools.javac.code.Symbol.VarSymbol; +import com.sun.tools.javac.code.Type; +import com.sun.tools.javac.code.Types; +import com.sun.tools.javac.resources.CompilerProperties.Errors; +import com.sun.tools.javac.tree.JCTree; +import com.sun.tools.javac.tree.JCTree.JCBinary; +import com.sun.tools.javac.tree.JCTree.JCConditional; +import com.sun.tools.javac.tree.JCTree.JCUnary; +import com.sun.tools.javac.tree.JCTree.JCBindingPattern; +import com.sun.tools.javac.tree.TreeScanner; +import com.sun.tools.javac.util.Context; +import com.sun.tools.javac.util.List; +import com.sun.tools.javac.util.Log; +import com.sun.tools.javac.util.Name; + + +public class MatchBindingsComputer extends TreeScanner { + protected static final Context.Key matchBindingsComputerKey = new Context.Key<>(); + + private final Log log; + private final Types types; + boolean whenTrue; + List bindings; + + public static MatchBindingsComputer instance(Context context) { + MatchBindingsComputer instance = context.get(matchBindingsComputerKey); + if (instance == null) + instance = new MatchBindingsComputer(context); + return instance; + } + + protected MatchBindingsComputer(Context context) { + this.log = Log.instance(context); + this.types = Types.instance(context); + } + + public List getMatchBindings(JCTree expression, boolean whenTrue) { + this.whenTrue = whenTrue; + this.bindings = List.nil(); + scan(expression); + return bindings; + } + + @Override + public void visitBindingPattern(JCBindingPattern tree) { + bindings = whenTrue ? List.of(tree.symbol) : List.nil(); + } + + @Override + public void visitBinary(JCBinary tree) { + switch (tree.getTag()) { + case AND: + // e.T = union(x.T, y.T) + // e.F = intersection(x.F, y.F) + scan(tree.lhs); + List lhsBindings = bindings; + scan(tree.rhs); + List rhsBindings = bindings; + bindings = whenTrue ? union(tree, lhsBindings, rhsBindings) : intersection(tree, lhsBindings, rhsBindings); + break; + case OR: + // e.T = intersection(x.T, y.T) + // e.F = union(x.F, y.F) + scan(tree.lhs); + lhsBindings = bindings; + scan(tree.rhs); + rhsBindings = bindings; + bindings = whenTrue ? intersection(tree, lhsBindings, rhsBindings) : union(tree, lhsBindings, rhsBindings); + break; + default: + super.visitBinary(tree); + break; + } + } + + @Override + public void visitUnary(JCUnary tree) { + switch (tree.getTag()) { + case NOT: + // e.T = x.F // flip 'em + // e.F = x.T + whenTrue = !whenTrue; + scan(tree.arg); + whenTrue = !whenTrue; + break; + default: + super.visitUnary(tree); + break; + } + } + + @Override + public void visitConditional(JCConditional tree) { + /* if e = "x ? y : z", then: + e.T = union(intersect(y.T, z.T), intersect(x.T, z.T), intersect(x.F, y.T)) + e.F = union(intersect(y.F, z.F), intersect(x.T, z.F), intersect(x.F, y.F)) + */ + if (whenTrue) { + List xT, yT, zT, xF; + scan(tree.cond); + xT = bindings; + scan(tree.truepart); + yT = bindings; + scan(tree.falsepart); + zT = bindings; + whenTrue = false; + scan(tree.cond); + xF = bindings; + whenTrue = true; + bindings = union(tree, intersection(tree, yT, zT), intersection(tree, xT, zT), intersection(tree, xF, yT)); + } else { + List xF, yF, zF, xT; + scan(tree.cond); + xF = bindings; + scan(tree.truepart); + yF = bindings; + scan(tree.falsepart); + zF = bindings; + whenTrue = true; + scan(tree.cond); + xT = bindings; + whenTrue = false; + bindings = union(tree, intersection(tree, yF, zF), intersection(tree, xT, zF), intersection(tree, xF, yF)); + } + } + + private List intersection(JCTree tree, List lhsBindings, List rhsBindings) { + // It is an error if, for intersection(a,b), if a and b contain the same variable name (may be eventually relaxed to merge variables of same type) + List list = List.nil(); + for (BindingSymbol v1 : lhsBindings) { + for (BindingSymbol v2 : rhsBindings) { + if (v1.name == v2.name) { + log.error(tree.pos(), Errors.MatchBindingExists); + list = list.append(v2); + } + } + } + return list; + } + + @SafeVarargs + private final List union(JCTree tree, List lhsBindings, List ... rhsBindings_s) { + // It is an error if for union(a,b), a and b contain the same name (disjoint union). + List list = lhsBindings; + for (List rhsBindings : rhsBindings_s) { + for (BindingSymbol v : rhsBindings) { + for (BindingSymbol ov : list) { + if (ov.name == v.name) { + log.error(tree.pos(), Errors.MatchBindingExists); + } + } + list = list.append(v); + } + } + return list; + } + + @Override + public void scan(JCTree tree) { + bindings = List.nil(); + super.scan(tree); + } + + public static class BindingSymbol extends VarSymbol { + + public BindingSymbol(Name name, Type type, Symbol owner) { + super(Flags.FINAL | Flags.HASINIT | Flags.MATCH_BINDING, name, type, owner); + } + + public boolean isAliasFor(BindingSymbol b) { + return aliases().containsAll(b.aliases()); + } + + List aliases() { + return List.of(this); + } + + public void preserveBinding() { + flags_field |= Flags.MATCH_BINDING_TO_OUTER; + } + + public boolean isPreserved() { + return (flags_field & Flags.MATCH_BINDING_TO_OUTER) != 0; + } + } + +} diff -r bfc8074ea4ef -r cfe31d2f935c src/jdk.compiler/share/classes/com/sun/tools/javac/comp/TransPatterns.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/TransPatterns.java Fri Nov 29 10:02:07 2019 +0000 @@ -0,0 +1,457 @@ +/* + * Copyright (c) 2017, 2019, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package com.sun.tools.javac.comp; + +import com.sun.tools.javac.code.Flags; +import com.sun.tools.javac.code.Symbol.VarSymbol; +import com.sun.tools.javac.code.Symtab; +import com.sun.tools.javac.code.Type; +import com.sun.tools.javac.code.Types; +import com.sun.tools.javac.comp.MatchBindingsComputer.BindingSymbol; +import com.sun.tools.javac.tree.JCTree; +import com.sun.tools.javac.tree.JCTree.JCAssign; +import com.sun.tools.javac.tree.JCTree.JCBinary; +import com.sun.tools.javac.tree.JCTree.JCConditional; +import com.sun.tools.javac.tree.JCTree.JCExpression; +import com.sun.tools.javac.tree.JCTree.JCForLoop; +import com.sun.tools.javac.tree.JCTree.JCIdent; +import com.sun.tools.javac.tree.JCTree.JCIf; +import com.sun.tools.javac.tree.JCTree.JCInstanceOf; +import com.sun.tools.javac.tree.JCTree.JCLabeledStatement; +import com.sun.tools.javac.tree.JCTree.JCMethodDecl; +import com.sun.tools.javac.tree.JCTree.JCStatement; +import com.sun.tools.javac.tree.JCTree.JCVariableDecl; +import com.sun.tools.javac.tree.JCTree.JCBindingPattern; +import com.sun.tools.javac.tree.JCTree.JCWhileLoop; +import com.sun.tools.javac.tree.JCTree.Tag; +import com.sun.tools.javac.tree.TreeMaker; +import com.sun.tools.javac.tree.TreeTranslator; +import com.sun.tools.javac.util.Assert; +import com.sun.tools.javac.util.Context; +import com.sun.tools.javac.util.List; +import com.sun.tools.javac.util.ListBuffer; +import com.sun.tools.javac.util.Log; +import com.sun.tools.javac.util.Names; +import com.sun.tools.javac.util.Options; + +import java.util.Map; +import java.util.Map.Entry; +import java.util.stream.Collectors; + +import com.sun.tools.javac.code.Symbol.MethodSymbol; +import static com.sun.tools.javac.code.TypeTag.BOOLEAN; +import static com.sun.tools.javac.code.TypeTag.BOT; +import com.sun.tools.javac.comp.MatchBindingsComputer.BindingSymbol; +import com.sun.tools.javac.jvm.Target; +import com.sun.tools.javac.tree.JCTree.JCBlock; +import com.sun.tools.javac.tree.JCTree.JCDoWhileLoop; +import com.sun.tools.javac.tree.JCTree.JCStatement; +import com.sun.tools.javac.tree.JCTree.LetExpr; +import com.sun.tools.javac.util.List; + +/** + * This pass translates pattern-matching constructs, such as instanceof . + */ +public class TransPatterns extends TreeTranslator { + + protected static final Context.Key transPatternsKey = new Context.Key<>(); + + public static TransPatterns instance(Context context) { + TransPatterns instance = context.get(transPatternsKey); + if (instance == null) + instance = new TransPatterns(context); + return instance; + } + + private final Symtab syms; + private final Types types; + private final Operators operators; + private final Log log; + private final ConstFold constFold; + private final Names names; + private final Target target; + private final MatchBindingsComputer matchBindingsComputer; + private TreeMaker make; + + BindingContext bindingContext = new BindingContext() { + @Override + VarSymbol getBindingFor(BindingSymbol varSymbol) { + return null; + } + + @Override + JCStatement decorateStatement(JCStatement stat) { + return stat; + } + + @Override + JCExpression decorateExpression(JCExpression expr) { + return expr; + } + + @Override + BindingContext pop() { + //do nothing + return this; + } + + @Override + boolean tryPrepend(BindingSymbol binding, JCVariableDecl var) { + return false; + } + }; + + JCLabeledStatement pendingMatchLabel = null; + + boolean debugTransPatterns; + + private MethodSymbol currentMethodSym = null; + + protected TransPatterns(Context context) { + context.put(transPatternsKey, this); + syms = Symtab.instance(context); + make = TreeMaker.instance(context); + types = Types.instance(context); + operators = Operators.instance(context); + log = Log.instance(context); + constFold = ConstFold.instance(context); + names = Names.instance(context); + target = Target.instance(context); + matchBindingsComputer = MatchBindingsComputer.instance(context); + debugTransPatterns = Options.instance(context).isSet("debug.patterns"); + } + + @Override + public void visitTypeTest(JCInstanceOf tree) { + if (tree.pattern.hasTag(Tag.BINDINGPATTERN)) { + //E instanceof T N + //=> + //(let T' N$temp = E; N$temp instanceof T && (N = (T) N$temp == (T) N$temp)) + JCBindingPattern patt = (JCBindingPattern)tree.pattern; + VarSymbol pattSym = patt.symbol; + Type tempType = tree.expr.type.hasTag(BOT) ? + syms.objectType + : tree.expr.type; + VarSymbol temp = new VarSymbol(pattSym.flags() | Flags.SYNTHETIC, + names.fromString(pattSym.name.toString() + target.syntheticNameChar() + "temp"), + tempType, + patt.symbol.owner); + JCExpression translatedExpr = translate(tree.expr); + Type castTargetType = types.boxedTypeOrType(pattSym.erasure(types)); + + result = makeTypeTest(make.Ident(temp), make.Type(castTargetType)); + + VarSymbol bindingVar = bindingContext.getBindingFor(patt.symbol); + if (bindingVar != null) { + JCAssign fakeInit = (JCAssign)make.at(tree.pos).Assign( + make.Ident(bindingVar), convert(make.Ident(temp), castTargetType)).setType(bindingVar.erasure(types)); + result = makeBinary(Tag.AND, (JCExpression)result, + makeBinary(Tag.EQ, fakeInit, convert(make.Ident(temp), castTargetType))); + } + result = make.at(tree.pos).LetExpr(make.VarDef(temp, translatedExpr), (JCExpression)result).setType(syms.booleanType); + ((LetExpr) result).needsCond = true; + } else { + super.visitTypeTest(tree); + } + } + + @Override + public void visitBinary(JCBinary tree) { + List matchBindings; + switch (tree.getTag()) { + case AND: + matchBindings = matchBindingsComputer.getMatchBindings(tree.lhs, true); + break; + case OR: + matchBindings = matchBindingsComputer.getMatchBindings(tree.lhs, false); + break; + default: + matchBindings = List.nil(); + break; + } + + bindingContext = new BasicBindingContext(matchBindings); + try { + super.visitBinary(tree); + result = bindingContext.decorateExpression(tree); + } finally { + bindingContext.pop(); + } + } + + @Override + public void visitConditional(JCConditional tree) { + bindingContext = new BasicBindingContext( + matchBindingsComputer.getMatchBindings(tree.cond, true) + .appendList(matchBindingsComputer.getMatchBindings(tree.cond, false))); + try { + super.visitConditional(tree); + result = bindingContext.decorateExpression(tree); + } finally { + bindingContext.pop(); + } + } + + @Override + public void visitIf(JCIf tree) { + bindingContext = new BasicBindingContext(getMatchBindings(tree.cond)); + try { + super.visitIf(tree); + result = bindingContext.decorateStatement(tree); + } finally { + bindingContext.pop(); + } + } + + @Override + public void visitForLoop(JCForLoop tree) { + bindingContext = new BasicBindingContext(getMatchBindings(tree.cond)); + try { + super.visitForLoop(tree); + result = bindingContext.decorateStatement(tree); + } finally { + bindingContext.pop(); + } + } + + @Override + public void visitWhileLoop(JCWhileLoop tree) { + bindingContext = new BasicBindingContext(getMatchBindings(tree.cond)); + try { + super.visitWhileLoop(tree); + result = bindingContext.decorateStatement(tree); + } finally { + bindingContext.pop(); + } + } + + @Override + public void visitDoLoop(JCDoWhileLoop tree) { + bindingContext = new BasicBindingContext(getMatchBindings(tree.cond)); + try { + super.visitDoLoop(tree); + result = bindingContext.decorateStatement(tree); + } finally { + bindingContext.pop(); + } + } + + @Override + public void visitMethodDef(JCMethodDecl tree) { + MethodSymbol prevMethodSym = currentMethodSym; + try { + currentMethodSym = tree.sym; + super.visitMethodDef(tree); + } finally { + currentMethodSym = prevMethodSym; + } + } + + @Override + public void visitIdent(JCIdent tree) { + VarSymbol bindingVar = null; + if ((tree.sym.flags() & Flags.MATCH_BINDING) != 0) { + bindingVar = bindingContext.getBindingFor((BindingSymbol)tree.sym); + } + if (bindingVar == null) { + super.visitIdent(tree); + } else { + result = make.at(tree.pos).Ident(bindingVar); + } + } + + @Override + public void visitBlock(JCBlock tree) { + ListBuffer statements = new ListBuffer<>(); + bindingContext = new BasicBindingContext(List.nil()) { + boolean tryPrepend(BindingSymbol binding, JCVariableDecl var) { + //{ + // if (E instanceof T N) { + // return ; + // } + // //use of N: + //} + //=> + //{ + // T N; + // if ((let T' N$temp = E; N$temp instanceof T && (N = (T) N$temp == (T) N$temp))) { + // return ; + // } + // //use of N: + //} + hoistedVarMap.put(binding, var.sym); + statements.append(var); + return true; + } + }; + try { + for (List l = tree.stats; l.nonEmpty(); l = l.tail) { + statements.append(translate(l.head)); + } + + tree.stats = statements.toList(); + result = tree; + } finally { + bindingContext.pop(); + } + } + + public JCTree translateTopLevelClass(Env env, JCTree cdef, TreeMaker make) { + try { + this.make = make; + translate(cdef); + } finally { + // note that recursive invocations of this method fail hard + this.make = null; + } + + return cdef; + } + + /** Make an instanceof expression. + * @param lhs The expression. + * @param type The type to be tested. + */ + + JCInstanceOf makeTypeTest(JCExpression lhs, JCExpression type) { + JCInstanceOf tree = make.TypeTest(lhs, type); + tree.type = syms.booleanType; + return tree; + } + + /** Make an attributed binary expression (copied from Lower). + * @param optag The operators tree tag. + * @param lhs The operator's left argument. + * @param rhs The operator's right argument. + */ + JCBinary makeBinary(JCTree.Tag optag, JCExpression lhs, JCExpression rhs) { + JCBinary tree = make.Binary(optag, lhs, rhs); + tree.operator = operators.resolveBinary(tree, optag, lhs.type, rhs.type); + tree.type = tree.operator.type.getReturnType(); + return tree; + } + + JCExpression convert(JCExpression expr, Type target) { + JCExpression result = make.at(expr.pos()).TypeCast(make.Type(target), expr); + result.type = target; + return result; + } + + private List getMatchBindings(JCExpression cond) { + return matchBindingsComputer.getMatchBindings(cond, true) + .appendList(matchBindingsComputer.getMatchBindings(cond, false)); + } + abstract class BindingContext { + abstract VarSymbol getBindingFor(BindingSymbol varSymbol); + abstract JCStatement decorateStatement(JCStatement stat); + abstract JCExpression decorateExpression(JCExpression expr); + abstract BindingContext pop(); + abstract boolean tryPrepend(BindingSymbol binding, JCVariableDecl var); + } + + class BasicBindingContext extends BindingContext { + List matchBindings; + Map hoistedVarMap; + BindingContext parent; + + public BasicBindingContext(List matchBindings) { + this.matchBindings = matchBindings; + this.parent = bindingContext; + this.hoistedVarMap = matchBindings.stream() + .filter(v -> parent.getBindingFor(v) == null) + .collect(Collectors.toMap(v -> v, v -> { + VarSymbol res = new VarSymbol(v.flags(), v.name, v.type, v.owner); + res.setTypeAttributes(v.getRawTypeAttributes()); + return res; + })); + } + + @Override + VarSymbol getBindingFor(BindingSymbol varSymbol) { + VarSymbol res = parent.getBindingFor(varSymbol); + if (res != null) { + return res; + } + return hoistedVarMap.entrySet().stream() + .filter(e -> e.getKey().isAliasFor(varSymbol)) + .findFirst() + .map(e -> e.getValue()).orElse(null); + } + + @Override + JCStatement decorateStatement(JCStatement stat) { + if (hoistedVarMap.isEmpty()) return stat; + //if (E instanceof T N) { + // //use N + //} + //=> + //{ + // T N; + // if ((let T' N$temp = E; N$temp instanceof T && (N = (T) N$temp == (T) N$temp))) { + // //use N + // } + //} + ListBuffer stats = new ListBuffer<>(); + for (Entry e : hoistedVarMap.entrySet()) { + JCVariableDecl decl = makeHoistedVarDecl(stat.pos, e.getValue()); + if (!e.getKey().isPreserved() || + !parent.tryPrepend(e.getKey(), decl)) { + stats.add(decl); + } + } + if (stats.nonEmpty()) { + stats.add(stat); + stat = make.at(stat.pos).Block(0, stats.toList()); + } + return stat; + } + + @Override + JCExpression decorateExpression(JCExpression expr) { + //E instanceof T N && /*use of N*/ + //=> + //(let T N; (let T' N$temp = E; N$temp instanceof T && (N = (T) N$temp == (T) N$temp)) && /*use of N*/) + for (VarSymbol vsym : hoistedVarMap.values()) { + expr = make.at(expr.pos).LetExpr(makeHoistedVarDecl(expr.pos, vsym), expr).setType(expr.type); + } + return expr; + } + + @Override + BindingContext pop() { + return bindingContext = parent; + } + + @Override + boolean tryPrepend(BindingSymbol binding, JCVariableDecl var) { + return false; + } + + private JCVariableDecl makeHoistedVarDecl(int pos, VarSymbol varSymbol) { + return make.at(pos).VarDef(varSymbol, null); + } + } +} diff -r bfc8074ea4ef -r cfe31d2f935c src/jdk.compiler/share/classes/com/sun/tools/javac/comp/TransTypes.java --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/TransTypes.java Tue Nov 26 10:22:13 2019 +0000 +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/TransTypes.java Fri Nov 29 10:02:07 2019 +0000 @@ -567,6 +567,13 @@ result = tree; } + public void visitBindingPattern(JCBindingPattern tree) { + if (tree.vartype != null) { + tree.vartype = translate(tree.vartype, null); + } + result = tree; + } + public void visitSwitchExpression(JCSwitchExpression tree) { Type selsuper = types.supertype(tree.selector.type); boolean enumSwitch = selsuper != null && @@ -780,7 +787,7 @@ public void visitTypeTest(JCInstanceOf tree) { tree.expr = translate(tree.expr, null); - tree.clazz = translate(tree.clazz, null); + tree.pattern = translate(tree.pattern, null); result = tree; } diff -r bfc8074ea4ef -r cfe31d2f935c src/jdk.compiler/share/classes/com/sun/tools/javac/comp/TreeDiffer.java --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/TreeDiffer.java Tue Nov 26 10:22:13 2019 +0000 +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/TreeDiffer.java Fri Nov 29 10:02:07 2019 +0000 @@ -35,6 +35,7 @@ import com.sun.tools.javac.tree.JCTree.JCAssign; import com.sun.tools.javac.tree.JCTree.JCAssignOp; import com.sun.tools.javac.tree.JCTree.JCBinary; +import com.sun.tools.javac.tree.JCTree.JCBindingPattern; import com.sun.tools.javac.tree.JCTree.JCBlock; import com.sun.tools.javac.tree.JCTree.JCBreak; import com.sun.tools.javac.tree.JCTree.JCCase; @@ -253,6 +254,18 @@ } @Override + public void visitBindingPattern(JCBindingPattern tree) { + JCBindingPattern that = (JCBindingPattern) parameter; + result = + scan(tree.vartype, that.vartype) + && tree.name == that.name; + if (!result) { + return; + } + equiv.put(tree.symbol, that.symbol); + } + + @Override public void visitBlock(JCBlock tree) { JCBlock that = (JCBlock) parameter; result = tree.flags == that.flags && scan(tree.stats, that.stats); @@ -591,7 +604,7 @@ @Override public void visitTypeTest(JCInstanceOf tree) { JCInstanceOf that = (JCInstanceOf) parameter; - result = scan(tree.expr, that.expr) && scan(tree.clazz, that.clazz); + result = scan(tree.expr, that.expr) && scan(tree.pattern, that.pattern); } @Override diff -r bfc8074ea4ef -r cfe31d2f935c src/jdk.compiler/share/classes/com/sun/tools/javac/comp/TreeHasher.java --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/TreeHasher.java Tue Nov 26 10:22:13 2019 +0000 +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/TreeHasher.java Fri Nov 29 10:02:07 2019 +0000 @@ -106,6 +106,12 @@ } @Override + public void visitBindingPattern(JCTree.JCBindingPattern tree) { + symbolHashes.computeIfAbsent(tree.symbol, k -> symbolHashes.size()); + super.visitBindingPattern(tree); + } + + @Override public void visitVarDef(JCVariableDecl tree) { symbolHashes.computeIfAbsent(tree.sym, k -> symbolHashes.size()); super.visitVarDef(tree); diff -r bfc8074ea4ef -r cfe31d2f935c src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/CRTable.java --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/CRTable.java Tue Nov 26 10:22:13 2019 +0000 +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/CRTable.java Fri Nov 29 10:02:07 2019 +0000 @@ -473,7 +473,7 @@ public void visitTypeTest(JCInstanceOf tree) { SourceRange sr = new SourceRange(startPos(tree), endPos(tree)); sr.mergeWith(csp(tree.expr)); - sr.mergeWith(csp(tree.clazz)); + sr.mergeWith(csp(tree.pattern)); result = sr; } diff -r bfc8074ea4ef -r cfe31d2f935c src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/Code.java --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/Code.java Tue Nov 26 10:22:13 2019 +0000 +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/Code.java Fri Nov 29 10:02:07 2019 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2019, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -50,6 +50,7 @@ import static com.sun.tools.javac.jvm.ClassFile.CONSTANT_String; import static com.sun.tools.javac.jvm.UninitializedType.*; import static com.sun.tools.javac.jvm.ClassWriter.StackMapTableFrame; +import java.util.Arrays; /** An internal structure that corresponds to the code attribute of * methods in a classfile. The class also provides some utility operations to @@ -2075,6 +2076,7 @@ lvar[adr] = v.dup(); v.closeRange(length); putVar(v); + fillLocalVarPosition(v); } else { v.removeLastRange(); } @@ -2106,20 +2108,31 @@ private void fillLocalVarPosition(LocalVar lv) { if (lv == null || lv.sym == null || lv.sym.isExceptionParameter()|| !lv.sym.hasTypeAnnotations()) return; - LocalVar.Range widestRange = lv.getWidestRange(); + LocalVar.Range[] validRanges = lv.aliveRanges.stream().filter(r -> r.closed() && r.length > 0).toArray(s -> new LocalVar.Range[s]); + if (validRanges.length == 0) + return ; + int[] lvarOffset = Arrays.stream(validRanges).mapToInt(r -> r.start_pc).toArray(); + int[] lvarLength = Arrays.stream(validRanges).mapToInt(r -> r.length).toArray(); + int[] lvarIndex = Arrays.stream(validRanges).mapToInt(r -> lv.reg).toArray(); for (Attribute.TypeCompound ta : lv.sym.getRawTypeAttributes()) { TypeAnnotationPosition p = ta.position; - if (widestRange.closed() && widestRange.length > 0) { - p.lvarOffset = new int[] { (int)widestRange.start_pc }; - p.lvarLength = new int[] { (int)widestRange.length }; - p.lvarIndex = new int[] { (int)lv.reg }; - p.isValidOffset = true; - } else { - p.isValidOffset = false; - } + p.lvarOffset = appendArray(p.lvarOffset, lvarOffset); + p.lvarLength = appendArray(p.lvarLength, lvarLength); + p.lvarIndex = appendArray(p.lvarIndex, lvarIndex); + p.isValidOffset = true; } } + private int[] appendArray(int[] source, int[] append) { + if (source == null || source.length == 0) return append; + + int[] result = new int[source.length + append.length]; + + System.arraycopy(source, 0, result, 0, source.length); + System.arraycopy(append, 0, result, source.length, append.length); + return result; + } + // Method to be called after compressCatchTable to // fill in the exception table index for type // annotations on exception parameters. diff -r bfc8074ea4ef -r cfe31d2f935c src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/Gen.java --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/Gen.java Tue Nov 26 10:22:13 2019 +0000 +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/Gen.java Fri Nov 29 10:02:07 2019 +0000 @@ -2216,7 +2216,7 @@ public void visitTypeTest(JCInstanceOf tree) { genExpr(tree.expr, tree.expr.type).load(); setTypeAnnotationPositions(tree.pos); - code.emitop2(instanceof_, makeRef(tree.pos(), tree.clazz.type)); + code.emitop2(instanceof_, makeRef(tree.pos(), tree.pattern.type)); result = items.makeStackItem(syms.booleanType); } diff -r bfc8074ea4ef -r cfe31d2f935c src/jdk.compiler/share/classes/com/sun/tools/javac/main/JavaCompiler.java --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/main/JavaCompiler.java Tue Nov 26 10:22:13 2019 +0000 +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/main/JavaCompiler.java Fri Nov 29 10:02:07 2019 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2019, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -1558,6 +1558,12 @@ env.tree = transTypes.translateTopLevelClass(env.tree, localMake); compileStates.put(env, CompileState.TRANSTYPES); + if (shouldStop(CompileState.TRANSPATTERNS)) + return; + + env.tree = TransPatterns.instance(context).translateTopLevelClass(env, env.tree, localMake); + compileStates.put(env, CompileState.TRANSPATTERNS); + if (Feature.LAMBDA.allowedInSource(source) && scanner.hasLambdas) { if (shouldStop(CompileState.UNLAMBDA)) return; diff -r bfc8074ea4ef -r cfe31d2f935c src/jdk.compiler/share/classes/com/sun/tools/javac/parser/JavacParser.java --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/parser/JavacParser.java Tue Nov 26 10:22:13 2019 +0000 +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/parser/JavacParser.java Fri Nov 29 10:02:07 2019 +0000 @@ -893,6 +893,7 @@ /* Expression2Rest = {infixop Expression3} * | Expression3 instanceof Type + * | Expression3 instanceof Pattern * infixop = "||" * | "&&" * | "|" @@ -915,13 +916,24 @@ Token topOp = Tokens.DUMMY; while (prec(token.kind) >= minprec) { opStack[top] = topOp; - top++; - topOp = token; - nextToken(); - odStack[top] = (topOp.kind == INSTANCEOF) ? parseType() : term3(); + + if (token.kind == INSTANCEOF) { + int pos = token.pos; + nextToken(); + JCTree pattern = parseType(); + if (token.kind == IDENTIFIER) { + checkSourceLevel(token.pos, Feature.PATTERN_MATCHING_IN_INSTANCEOF); + pattern = toP(F.at(token.pos).BindingPattern(ident(), pattern)); + } + odStack[top] = F.at(pos).TypeTest(odStack[top], pattern); + } else { + topOp = token; + nextToken(); + top++; + odStack[top] = term3(); + } while (top > 0 && prec(topOp.kind) >= prec(token.kind)) { - odStack[top-1] = makeOp(topOp.pos, topOp.kind, odStack[top-1], - odStack[top]); + odStack[top - 1] = F.at(topOp.pos).Binary(optag(topOp.kind), odStack[top - 1], odStack[top]); top--; topOp = opStack[top]; } @@ -938,19 +950,6 @@ return t; } //where - /** Construct a binary or type test node. - */ - private JCExpression makeOp(int pos, - TokenKind topOp, - JCExpression od1, - JCExpression od2) - { - if (topOp == INSTANCEOF) { - return F.at(pos).TypeTest(od1, od2); - } else { - return F.at(pos).Binary(optag(topOp), od1, od2); - } - } /** If tree is a concatenation of string literals, replace it * by a single literal representing the concatenated string. */ diff -r bfc8074ea4ef -r cfe31d2f935c src/jdk.compiler/share/classes/com/sun/tools/javac/resources/compiler.properties --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/resources/compiler.properties Tue Nov 26 10:22:13 2019 +0000 +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/resources/compiler.properties Fri Nov 29 10:02:07 2019 +0000 @@ -546,6 +546,10 @@ auto-closeable resource {0} may not be assigned # 0: symbol +compiler.err.pattern.binding.may.not.be.assigned=\ + pattern binding {0} may not be assigned + +# 0: symbol compiler.err.multicatch.parameter.may.not.be.assigned=\ multi-catch parameter {0} may not be assigned @@ -1416,6 +1420,10 @@ compiler.misc.varargs.trustme.on.reifiable.varargs=\ Varargs element type {0} is reifiable. +# 0: type, 1: type +compiler.err.instanceof.reifiable.not.safe=\ + {0} cannot be safely cast to {1} + # 0: symbol compiler.misc.varargs.trustme.on.non.varargs.meth=\ Method {0} is not a varargs method. @@ -2909,6 +2917,12 @@ compiler.misc.feature.var.syntax.in.implicit.lambda=\ var syntax in implicit lambdas +compiler.misc.feature.pattern.matching.instanceof=\ + pattern matching in instanceof + +compiler.misc.feature.reifiable.types.instanceof=\ + reifiable types in instanceof + compiler.warn.underscore.as.identifier=\ as of release 9, ''_'' is a keyword, and may not be used as an identifier @@ -3399,6 +3413,9 @@ compiler.err.illegal.argument.for.option=\ illegal argument for {0}: {1} +compiler.err.match.binding.exists=\ + illegal attempt to redefine an existing match binding + compiler.err.switch.null.not.allowed=\ null label in case is not allowed diff -r bfc8074ea4ef -r cfe31d2f935c src/jdk.compiler/share/classes/com/sun/tools/javac/tree/JCTree.java --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/JCTree.java Tue Nov 26 10:22:13 2019 +0000 +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/JCTree.java Fri Nov 29 10:02:07 2019 +0000 @@ -38,6 +38,7 @@ import com.sun.tools.javac.code.Directive.RequiresDirective; import com.sun.tools.javac.code.Scope.*; import com.sun.tools.javac.code.Symbol.*; +import com.sun.tools.javac.comp.MatchBindingsComputer.BindingSymbol; import com.sun.tools.javac.util.*; import com.sun.tools.javac.util.DefinedBy.Api; import com.sun.tools.javac.util.JCDiagnostic.DiagnosticPosition; @@ -238,6 +239,10 @@ */ TYPETEST, + /** Patterns. + */ + BINDINGPATTERN, + /** Indexed array expressions, of type Indexed. */ INDEXED, @@ -2135,10 +2140,10 @@ */ public static class JCInstanceOf extends JCExpression implements InstanceOfTree { public JCExpression expr; - public JCTree clazz; - protected JCInstanceOf(JCExpression expr, JCTree clazz) { + public JCTree pattern; + protected JCInstanceOf(JCExpression expr, JCTree pattern) { this.expr = expr; - this.clazz = clazz; + this.pattern = pattern; } @Override public void accept(Visitor v) { v.visitTypeTest(this); } @@ -2146,7 +2151,13 @@ @DefinedBy(Api.COMPILER_TREE) public Kind getKind() { return Kind.INSTANCE_OF; } @DefinedBy(Api.COMPILER_TREE) - public JCTree getType() { return clazz; } + public JCTree getType() { return pattern instanceof JCPattern ? pattern.hasTag(BINDINGPATTERN) ? ((JCBindingPattern) pattern).vartype : null : pattern; } + + @Override @DefinedBy(Api.COMPILER_TREE) + public JCPattern getPattern() { + return pattern instanceof JCPattern ? (JCPattern) pattern : null; + } + @DefinedBy(Api.COMPILER_TREE) public JCExpression getExpression() { return expr; } @Override @DefinedBy(Api.COMPILER_TREE) @@ -2160,6 +2171,60 @@ } /** + * Pattern matching forms. + */ + public static abstract class JCPattern extends JCTree + implements PatternTree { + public JCExpression constExpression() { + return null; + } + } + + public static class JCBindingPattern extends JCPattern + implements BindingPatternTree { + public Name name; + public BindingSymbol symbol; + public JCTree vartype; + + protected JCBindingPattern(Name name, BindingSymbol symbol, JCTree vartype) { + this.name = name; + this.symbol = symbol; + this.vartype = vartype; + } + + @DefinedBy(Api.COMPILER_TREE) + public Name getBinding() { + return name; + } + + @Override @DefinedBy(Api.COMPILER_TREE) + public Tree getType() { + return vartype; + } + + @Override + public void accept(Visitor v) { + v.visitBindingPattern(this); + } + + @DefinedBy(Api.COMPILER_TREE) + public Kind getKind() { + return Kind.BINDING_PATTERN; + } + + @Override + @DefinedBy(Api.COMPILER_TREE) + public R accept(TreeVisitor v, D d) { + return v.visitBindingPattern(this, d); + } + + @Override + public Tag getTag() { + return BINDINGPATTERN; + } + } + + /** * An array selection */ public static class JCArrayAccess extends JCExpression implements ArrayAccessTree { @@ -3133,6 +3198,7 @@ JCBinary Binary(Tag opcode, JCExpression lhs, JCExpression rhs); JCTypeCast TypeCast(JCTree expr, JCExpression type); JCInstanceOf TypeTest(JCExpression expr, JCTree clazz); + JCBindingPattern BindingPattern(Name name, JCTree vartype); JCArrayAccess Indexed(JCExpression indexed, JCExpression index); JCFieldAccess Select(JCExpression selected, Name selector); JCIdent Ident(Name idname); @@ -3197,6 +3263,7 @@ public void visitBinary(JCBinary that) { visitTree(that); } public void visitTypeCast(JCTypeCast that) { visitTree(that); } public void visitTypeTest(JCInstanceOf that) { visitTree(that); } + public void visitBindingPattern(JCBindingPattern that) { visitTree(that); } public void visitIndexed(JCArrayAccess that) { visitTree(that); } public void visitSelect(JCFieldAccess that) { visitTree(that); } public void visitReference(JCMemberReference that) { visitTree(that); } diff -r bfc8074ea4ef -r cfe31d2f935c src/jdk.compiler/share/classes/com/sun/tools/javac/tree/Pretty.java --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/Pretty.java Tue Nov 26 10:22:13 2019 +0000 +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/Pretty.java Fri Nov 29 10:02:07 2019 +0000 @@ -234,6 +234,14 @@ printExprs(trees, ", "); } + + /** Derived visitor method: print pattern. + */ + + public void printPattern(JCTree tree) throws IOException { + printExpr(tree); + } + /** Derived visitor method: print list of statements, each on a separate line. */ public void printStats(List trees) throws IOException { @@ -877,6 +885,16 @@ } } + public void visitBindingPattern(JCBindingPattern patt) { + try { + printExpr(patt.vartype); + print(" "); + print(patt.name); + } catch (IOException e) { + throw new UncheckedIOException(e); + } + } + public void visitSynchronized(JCSynchronized tree) { try { print("synchronized "); @@ -1283,7 +1301,11 @@ open(prec, TreeInfo.ordPrec); printExpr(tree.expr, TreeInfo.ordPrec); print(" instanceof "); - printExpr(tree.clazz, TreeInfo.ordPrec + 1); + if (tree.pattern instanceof JCPattern) { + printPattern(tree.pattern); + } else { + printExpr(tree.getType(), TreeInfo.ordPrec + 1); + } close(prec, TreeInfo.ordPrec); } catch (IOException e) { throw new UncheckedIOException(e); diff -r bfc8074ea4ef -r cfe31d2f935c src/jdk.compiler/share/classes/com/sun/tools/javac/tree/TreeCopier.java --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/TreeCopier.java Tue Nov 26 10:22:13 2019 +0000 +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/TreeCopier.java Fri Nov 29 10:02:07 2019 +0000 @@ -26,7 +26,6 @@ package com.sun.tools.javac.tree; import com.sun.source.tree.*; -import com.sun.source.tree.Tree.Kind; import com.sun.tools.javac.tree.JCTree.*; import com.sun.tools.javac.util.DefinedBy; import com.sun.tools.javac.util.DefinedBy.Api; @@ -481,8 +480,15 @@ public JCTree visitInstanceOf(InstanceOfTree node, P p) { JCInstanceOf t = (JCInstanceOf) node; JCExpression expr = copy(t.expr, p); - JCTree clazz = copy(t.clazz, p); - return M.at(t.pos).TypeTest(expr, clazz); + JCTree pattern = copy(t.pattern, p); + return M.at(t.pos).TypeTest(expr, pattern); + } + + @DefinedBy(Api.COMPILER_TREE) + public JCTree visitBindingPattern(BindingPatternTree node, P p) { + JCBindingPattern t = (JCBindingPattern) node; + JCTree vartype = copy(t.vartype, p); + return M.at(t.pos).BindingPattern(t.name, vartype); } @DefinedBy(Api.COMPILER_TREE) diff -r bfc8074ea4ef -r cfe31d2f935c src/jdk.compiler/share/classes/com/sun/tools/javac/tree/TreeInfo.java --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/TreeInfo.java Tue Nov 26 10:22:13 2019 +0000 +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/TreeInfo.java Fri Nov 29 10:02:07 2019 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2019, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -490,6 +490,10 @@ return getStartPos(node.vartype); } } + case BINDINGPATTERN: { + JCBindingPattern node = (JCBindingPattern)tree; + return getStartPos(node.vartype); + } case ERRONEOUS: { JCErroneous node = (JCErroneous)tree; if (node.errs != null && node.errs.nonEmpty()) @@ -574,7 +578,7 @@ case TYPECAST: return getEndPos(((JCTypeCast) tree).expr, endPosTable); case TYPETEST: - return getEndPos(((JCInstanceOf) tree).clazz, endPosTable); + return getEndPos(((JCInstanceOf) tree).pattern, endPosTable); case WHILELOOP: return getEndPos(((JCWhileLoop) tree).body, endPosTable); case ANNOTATED_TYPE: @@ -847,6 +851,8 @@ if (node.type != null) return node.type.tsym; return null; + case BINDINGPATTERN: + return ((JCBindingPattern) node).symbol; default: return null; } @@ -1225,4 +1231,5 @@ public static boolean isPackageInfo(JCCompilationUnit tree) { return tree.sourcefile.isNameCompatible("package-info", JavaFileObject.Kind.SOURCE); } + } diff -r bfc8074ea4ef -r cfe31d2f935c src/jdk.compiler/share/classes/com/sun/tools/javac/tree/TreeMaker.java --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/TreeMaker.java Tue Nov 26 10:22:13 2019 +0000 +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/TreeMaker.java Fri Nov 29 10:02:07 2019 +0000 @@ -29,7 +29,6 @@ import com.sun.source.tree.CaseTree; import com.sun.source.tree.ModuleTree.ModuleKind; -import com.sun.source.tree.Tree.Kind; import com.sun.tools.javac.code.*; import com.sun.tools.javac.code.Attribute.UnresolvedClass; import com.sun.tools.javac.code.Symbol.*; @@ -465,6 +464,12 @@ return tree; } + public JCBindingPattern BindingPattern(Name name, JCTree vartype) { + JCBindingPattern tree = new JCBindingPattern(name, null, vartype); + tree.pos = pos; + return tree; + } + public JCArrayAccess Indexed(JCExpression indexed, JCExpression index) { JCArrayAccess tree = new JCArrayAccess(indexed, index); tree.pos = pos; diff -r bfc8074ea4ef -r cfe31d2f935c src/jdk.compiler/share/classes/com/sun/tools/javac/tree/TreeScanner.java --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/TreeScanner.java Tue Nov 26 10:22:13 2019 +0000 +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/TreeScanner.java Fri Nov 29 10:02:07 2019 +0000 @@ -299,7 +299,12 @@ public void visitTypeTest(JCInstanceOf tree) { scan(tree.expr); - scan(tree.clazz); + scan(tree.pattern); + } + + public void visitBindingPattern(JCBindingPattern tree) { + if (tree.vartype != null) + scan(tree.vartype); } public void visitIndexed(JCArrayAccess tree) { diff -r bfc8074ea4ef -r cfe31d2f935c src/jdk.compiler/share/classes/com/sun/tools/javac/tree/TreeTranslator.java --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/TreeTranslator.java Tue Nov 26 10:22:13 2019 +0000 +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/TreeTranslator.java Fri Nov 29 10:02:07 2019 +0000 @@ -354,7 +354,12 @@ public void visitTypeTest(JCInstanceOf tree) { tree.expr = translate(tree.expr); - tree.clazz = translate(tree.clazz); + tree.pattern = translate(tree.pattern); + result = tree; + } + + public void visitBindingPattern(JCBindingPattern tree) { + tree.vartype = translate(tree.vartype); result = tree; } diff -r bfc8074ea4ef -r cfe31d2f935c src/jdk.httpserver/share/classes/sun/net/httpserver/ServerImpl.java --- a/src/jdk.httpserver/share/classes/sun/net/httpserver/ServerImpl.java Tue Nov 26 10:22:13 2019 +0000 +++ b/src/jdk.httpserver/share/classes/sun/net/httpserver/ServerImpl.java Fri Nov 29 10:02:07 2019 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2019, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -210,7 +210,7 @@ if (timer1Enabled) { timer1.cancel(); } - if (dispatcherThread != null) { + if (dispatcherThread != null && dispatcherThread != Thread.currentThread()) { try { dispatcherThread.join(); } catch (InterruptedException e) { diff -r bfc8074ea4ef -r cfe31d2f935c src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/AbstractIndexWriter.java --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/AbstractIndexWriter.java Tue Nov 26 10:22:13 2019 +0000 +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/AbstractIndexWriter.java Fri Nov 29 10:02:07 2019 +0000 @@ -92,7 +92,7 @@ IndexBuilder indexbuilder) { super(configuration, path); this.indexbuilder = indexbuilder; - this.navBar = new Navigation(null, configuration, fixedNavDiv, PageMode.INDEX, path); + this.navBar = new Navigation(null, configuration, PageMode.INDEX, path); } /** @@ -419,7 +419,7 @@ * @return a content tree for the marker anchor */ public Content getMarkerAnchorForIndex(String anchorNameForIndex) { - return links.createAnchor(getNameForIndex(anchorNameForIndex), null); + return links.createAnchor(getNameForIndex(anchorNameForIndex)); } /** diff -r bfc8074ea4ef -r cfe31d2f935c src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/AbstractOverviewIndexWriter.java --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/AbstractOverviewIndexWriter.java Tue Nov 26 10:22:13 2019 +0000 +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/AbstractOverviewIndexWriter.java Fri Nov 29 10:02:07 2019 +0000 @@ -25,6 +25,8 @@ package jdk.javadoc.internal.doclets.formats.html; +import jdk.javadoc.internal.doclets.formats.html.markup.BodyContents; +import jdk.javadoc.internal.doclets.formats.html.markup.ContentBuilder; import jdk.javadoc.internal.doclets.formats.html.markup.HtmlStyle; import jdk.javadoc.internal.doclets.formats.html.markup.HtmlTag; import jdk.javadoc.internal.doclets.formats.html.markup.HtmlTree; @@ -57,12 +59,12 @@ public AbstractOverviewIndexWriter(HtmlConfiguration configuration, DocPath filename) { super(configuration, filename); - this.navBar = new Navigation(null, configuration, fixedNavDiv, PageMode.OVERVIEW, path); + this.navBar = new Navigation(null, configuration, PageMode.OVERVIEW, path); } /** * Adds the top text (from the -top option), the upper - * navigation bar, and then the title (from the"-title" + * navigation bar, and then the title (from the"-header" * option), at the top of page. * * @param header the documentation tree to which the navigation bar header will be added @@ -126,16 +128,18 @@ throws DocFileIOException { String windowOverview = resources.getText(title); Content body = getBody(getWindowTitle(windowOverview)); - Content header = HtmlTree.HEADER(); + Content header = new ContentBuilder(); addNavigationBarHeader(header); - Content main = HtmlTree.MAIN(); + Content main = new ContentBuilder(); addOverviewHeader(main); addIndex(main); Content footer = HtmlTree.FOOTER(); addNavigationBarFooter(footer); - body.add(header); - body.add(main); - body.add(footer); + body.add(new BodyContents() + .setHeader(header) + .addMainContent(main) + .setFooter(footer) + .toContent()); printHtmlDocument( configuration.metakeywords.getOverviewMetaKeywords(title, configuration.doctitle), description, body); diff -r bfc8074ea4ef -r cfe31d2f935c src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/AllClassesIndexWriter.java --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/AllClassesIndexWriter.java Tue Nov 26 10:22:13 2019 +0000 +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/AllClassesIndexWriter.java Fri Nov 29 10:02:07 2019 +0000 @@ -31,6 +31,7 @@ import javax.lang.model.element.TypeElement; import com.sun.source.doctree.DocTree; +import jdk.javadoc.internal.doclets.formats.html.markup.BodyContents; import jdk.javadoc.internal.doclets.formats.html.markup.ContentBuilder; import jdk.javadoc.internal.doclets.formats.html.markup.HtmlStyle; import jdk.javadoc.internal.doclets.formats.html.markup.HtmlTag; @@ -56,13 +57,6 @@ protected IndexBuilder indexbuilder; /** - * The HTML tree for main tag. - */ - protected HtmlTree mainTree = HtmlTree.MAIN(); - - private final Navigation navBar; - - /** * Construct AllClassesIndexWriter object. Also initializes the indexbuilder variable in this * class. * @@ -74,7 +68,6 @@ DocPath filename, IndexBuilder indexbuilder) { super(configuration, filename); this.indexbuilder = indexbuilder; - this.navBar = new Navigation(null, configuration, fixedNavDiv, PageMode.ALLCLASSES, path); } /** @@ -101,21 +94,25 @@ */ protected void buildAllClassesFile() throws DocFileIOException { String label = resources.getText("doclet.All_Classes"); - HtmlTree bodyTree = getBody(getWindowTitle(label)); - HtmlTree header = HtmlTree.HEADER(); + Content header = new ContentBuilder(); addTop(header); + Navigation navBar = new Navigation(null, configuration, PageMode.ALLCLASSES, path); navBar.setUserHeader(getUserHeaderFooter(true)); header.add(navBar.getContent(true)); - bodyTree.add(header); Content allClassesContent = new ContentBuilder(); addContents(allClassesContent); - mainTree.add(allClassesContent); - bodyTree.add(mainTree); + Content mainContent = new ContentBuilder(); + mainContent.add(allClassesContent); Content footer = HtmlTree.FOOTER(); navBar.setUserFooter(getUserHeaderFooter(false)); footer.add(navBar.getContent(false)); addBottom(footer); - bodyTree.add(footer); + HtmlTree bodyTree = getBody(getWindowTitle(label)); + bodyTree.add(new BodyContents() + .setHeader(header) + .addMainContent(mainContent) + .setFooter(footer) + .toContent()); printHtmlDocument(null, "class index", bodyTree); } diff -r bfc8074ea4ef -r cfe31d2f935c src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/AllPackagesIndexWriter.java --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/AllPackagesIndexWriter.java Tue Nov 26 10:22:13 2019 +0000 +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/AllPackagesIndexWriter.java Fri Nov 29 10:02:07 2019 +0000 @@ -26,6 +26,7 @@ import javax.lang.model.element.PackageElement; +import jdk.javadoc.internal.doclets.formats.html.markup.BodyContents; import jdk.javadoc.internal.doclets.formats.html.markup.ContentBuilder; import jdk.javadoc.internal.doclets.formats.html.markup.HtmlStyle; import jdk.javadoc.internal.doclets.formats.html.markup.HtmlTag; @@ -46,13 +47,6 @@ public class AllPackagesIndexWriter extends HtmlDocletWriter { /** - * The HTML tree for main tag. - */ - protected HtmlTree mainTree = HtmlTree.MAIN(); - - private final Navigation navBar; - - /** * Construct AllPackagesIndexWriter object. * * @param configuration The current configuration @@ -60,7 +54,6 @@ */ public AllPackagesIndexWriter(HtmlConfiguration configuration, DocPath filename) { super(configuration, filename); - this.navBar = new Navigation(null, configuration, fixedNavDiv, PageMode.ALLPACKAGES, path); } /** @@ -83,12 +76,11 @@ */ protected void buildAllPackagesFile() throws DocFileIOException { String label = resources.getText("doclet.All_Packages"); - HtmlTree bodyTree = getBody(getWindowTitle(label)); - HtmlTree header = HtmlTree.HEADER(); - addTop(header); + Content headerContent = new ContentBuilder(); + Navigation navBar = new Navigation(null, configuration, PageMode.ALLPACKAGES, path); + addTop(headerContent); navBar.setUserHeader(getUserHeaderFooter(true)); - header.add(navBar.getContent(true)); - bodyTree.add(header); + headerContent.add(navBar.getContent(true)); HtmlTree div = new HtmlTree(HtmlTag.DIV); div.setStyle(HtmlStyle.allPackagesContainer); addPackages(div); @@ -96,14 +88,17 @@ Content pHeading = HtmlTree.HEADING(Headings.PAGE_TITLE_HEADING, true, HtmlStyle.title, titleContent); Content headerDiv = HtmlTree.DIV(HtmlStyle.header, pHeading); - mainTree.add(headerDiv); - mainTree.add(div); - bodyTree.add(mainTree); Content footer = HtmlTree.FOOTER(); navBar.setUserFooter(getUserHeaderFooter(false)); footer.add(navBar.getContent(false)); addBottom(footer); - bodyTree.add(footer); + HtmlTree bodyTree = getBody(getWindowTitle(label)); + bodyTree.add(new BodyContents() + .setHeader(headerContent) + .addMainContent(headerDiv) + .addMainContent(div) + .setFooter(footer) + .toContent()); printHtmlDocument(null, "package index", bodyTree); } diff -r bfc8074ea4ef -r cfe31d2f935c src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/AnnotationTypeWriterImpl.java --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/AnnotationTypeWriterImpl.java Tue Nov 26 10:22:13 2019 +0000 +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/AnnotationTypeWriterImpl.java Fri Nov 29 10:02:07 2019 +0000 @@ -32,6 +32,7 @@ import javax.lang.model.element.TypeElement; import com.sun.source.doctree.DocTree; +import jdk.javadoc.internal.doclets.formats.html.markup.ContentBuilder; import jdk.javadoc.internal.doclets.formats.html.markup.Entity; import jdk.javadoc.internal.doclets.formats.html.markup.HtmlStyle; import jdk.javadoc.internal.doclets.formats.html.markup.HtmlTag; @@ -78,7 +79,7 @@ super(configuration, configuration.docPaths.forClass(annotationType)); this.annotationType = annotationType; configuration.currentTypeElement = annotationType; - this.navBar = new Navigation(annotationType, configuration, fixedNavDiv, PageMode.CLASS, path); + this.navBar = new Navigation(annotationType, configuration, PageMode.CLASS, path); } /** @@ -86,17 +87,15 @@ */ @Override public Content getHeader(String header) { - HtmlTree bodyTree = getBody(getWindowTitle(utils.getSimpleName(annotationType))); - HtmlTree htmlTree = HtmlTree.HEADER(); - addTop(htmlTree); + Content headerContent = new ContentBuilder(); + addTop(headerContent); Content linkContent = getModuleLink(utils.elementUtils.getModuleOf(annotationType), contents.moduleLabel); navBar.setNavLinkModule(linkContent); navBar.setMemberSummaryBuilder(configuration.getBuilderFactory().getMemberSummaryBuilder(this)); navBar.setUserHeader(getUserHeaderFooter(true)); - htmlTree.add(navBar.getContent(true)); - bodyTree.add(htmlTree); - bodyTree.add(MarkerComments.START_OF_CLASS_DATA); + headerContent.add(navBar.getContent(true)); + HtmlTree div = new HtmlTree(HtmlTag.DIV); div.setStyle(HtmlStyle.header); if (configuration.showModules) { @@ -118,13 +117,14 @@ } LinkInfoImpl linkInfo = new LinkInfoImpl(configuration, LinkInfoImpl.Kind.CLASS_HEADER, annotationType); - Content headerContent = new StringContent(header); Content heading = HtmlTree.HEADING(Headings.PAGE_TITLE_HEADING, true, - HtmlStyle.title, headerContent); + HtmlStyle.title, new StringContent(header)); heading.add(getTypeParameterLinks(linkInfo)); div.add(heading); - mainTree.add(div); - return bodyTree; + bodyContents.setHeader(headerContent) + .addMainContent(MarkerComments.START_OF_CLASS_DATA) + .addMainContent(div); + return getBody(getWindowTitle(utils.getSimpleName(annotationType))); } /** @@ -139,13 +139,13 @@ * {@inheritDoc} */ @Override - public void addFooter(Content contentTree) { - contentTree.add(MarkerComments.END_OF_CLASS_DATA); + public void addFooter() { Content htmlTree = HtmlTree.FOOTER(); navBar.setUserFooter(getUserHeaderFooter(false)); htmlTree.add(navBar.getContent(false)); addBottom(htmlTree); - contentTree.add(htmlTree); + bodyContents.addMainContent(MarkerComments.END_OF_CLASS_DATA) + .setFooter(htmlTree); } /** @@ -156,6 +156,7 @@ String description = getDescription("declaration", annotationType); PackageElement pkg = utils.containingPackage(this.annotationType); List localStylesheets = getLocalStylesheets(pkg); + contentTree.add(bodyContents.toContent()); printHtmlDocument(configuration.metakeywords.getMetaKeywords(annotationType), description, localStylesheets, contentTree); } diff -r bfc8074ea4ef -r cfe31d2f935c src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/ClassUseWriter.java --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/ClassUseWriter.java Tue Nov 26 10:22:13 2019 +0000 +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/ClassUseWriter.java Fri Nov 29 10:02:07 2019 +0000 @@ -100,11 +100,6 @@ private final Navigation navBar; /** - * The HTML tree for main tag. - */ - protected HtmlTree mainTree = HtmlTree.MAIN(); - - /** * Constructor. * * @param filename the file to be generated. @@ -154,7 +149,7 @@ constrSubWriter = new ConstructorWriterImpl(this); fieldSubWriter = new FieldWriterImpl(this); classSubWriter = new NestedClassWriterImpl(this); - this.navBar = new Navigation(typeElement, configuration, fixedNavDiv, PageMode.USE, path); + this.navBar = new Navigation(typeElement, configuration, PageMode.USE, path); } /** @@ -232,13 +227,13 @@ div.add(contents.getContent("doclet.ClassUse_No.usage.of.0", utils.getFullyQualifiedName(typeElement))); } - mainTree.add(div); - body.add(mainTree); + bodyContents.addMainContent(div); HtmlTree footer = HtmlTree.FOOTER(); navBar.setUserFooter(getUserHeaderFooter(false)); footer.add(navBar.getContent(false)); addBottom(footer); - body.add(footer); + bodyContents.setFooter(footer); + body.add(bodyContents.toContent()); String description = getDescription("use", typeElement); printHtmlDocument(null, description, body); } @@ -432,8 +427,8 @@ String title = resources.getText("doclet.Window_ClassUse_Header", cltype, clname); HtmlTree bodyTree = getBody(getWindowTitle(title)); - HtmlTree htmlTree = HtmlTree.HEADER(); - addTop(htmlTree); + Content headerContent = new ContentBuilder(); + addTop(headerContent); Content mdleLinkContent = getModuleLink(utils.elementUtils.getModuleOf(typeElement), contents.moduleLabel); navBar.setNavLinkModule(mdleLinkContent); @@ -442,16 +437,15 @@ .label(resources.getText("doclet.Class"))); navBar.setNavLinkClass(classLinkContent); navBar.setUserHeader(getUserHeaderFooter(true)); - htmlTree.add(navBar.getContent(true)); - bodyTree.add(htmlTree); - ContentBuilder headContent = new ContentBuilder(); - headContent.add(contents.getContent("doclet.ClassUse_Title", cltype)); - headContent.add(new HtmlTree(HtmlTag.BR)); - headContent.add(clname); + headerContent.add(navBar.getContent(true)); + ContentBuilder headingContent = new ContentBuilder(); + headingContent.add(contents.getContent("doclet.ClassUse_Title", cltype)); + headingContent.add(new HtmlTree(HtmlTag.BR)); + headingContent.add(clname); Content heading = HtmlTree.HEADING(Headings.PAGE_TITLE_HEADING, - true, HtmlStyle.title, headContent); + true, HtmlStyle.title, headingContent); Content div = HtmlTree.DIV(HtmlStyle.header, heading); - mainTree.add(div); + bodyContents.setHeader(headerContent).addMainContent(div); return bodyTree; } } diff -r bfc8074ea4ef -r cfe31d2f935c src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/ClassWriterImpl.java --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/ClassWriterImpl.java Tue Nov 26 10:22:13 2019 +0000 +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/ClassWriterImpl.java Fri Nov 29 10:02:07 2019 +0000 @@ -105,7 +105,7 @@ this.typeElement = typeElement; configuration.currentTypeElement = typeElement; this.classtree = classTree; - this.navBar = new Navigation(typeElement, configuration, fixedNavDiv, PageMode.CLASS, path); + this.navBar = new Navigation(typeElement, configuration, PageMode.CLASS, path); } /** @@ -114,16 +114,14 @@ @Override public Content getHeader(String header) { HtmlTree bodyTree = getBody(getWindowTitle(utils.getSimpleName(typeElement))); - HtmlTree htmlTree = HtmlTree.HEADER(); - addTop(htmlTree); + Content headerContent = new ContentBuilder(); + addTop(headerContent); Content linkContent = getModuleLink(utils.elementUtils.getModuleOf(typeElement), contents.moduleLabel); navBar.setNavLinkModule(linkContent); navBar.setMemberSummaryBuilder(configuration.getBuilderFactory().getMemberSummaryBuilder(this)); navBar.setUserHeader(getUserHeaderFooter(true)); - htmlTree.add(navBar.getContent(true)); - bodyTree.add(htmlTree); - bodyTree.add(MarkerComments.START_OF_CLASS_DATA); + headerContent.add(navBar.getContent(true)); HtmlTree div = new HtmlTree(HtmlTag.DIV); div.setStyle(HtmlStyle.header); if (configuration.showModules) { @@ -149,12 +147,13 @@ LinkInfoImpl.Kind.CLASS_HEADER, typeElement); //Let's not link to ourselves in the header. linkInfo.linkToSelf = false; - Content headerContent = new StringContent(header); Content heading = HtmlTree.HEADING(Headings.PAGE_TITLE_HEADING, true, - HtmlStyle.title, headerContent); + HtmlStyle.title, new StringContent(header)); heading.add(getTypeParameterLinks(linkInfo)); div.add(heading); - mainTree.add(div); + bodyContents.setHeader(headerContent) + .addMainContent(MarkerComments.START_OF_CLASS_DATA) + .addMainContent(div); return bodyTree; } @@ -170,13 +169,13 @@ * {@inheritDoc} */ @Override - public void addFooter(Content contentTree) { - contentTree.add(MarkerComments.END_OF_CLASS_DATA); + public void addFooter() { + bodyContents.addMainContent(MarkerComments.END_OF_CLASS_DATA); Content htmlTree = HtmlTree.FOOTER(); navBar.setUserFooter(getUserHeaderFooter(false)); htmlTree.add(navBar.getContent(false)); addBottom(htmlTree); - contentTree.add(htmlTree); + bodyContents.setFooter(htmlTree); } /** @@ -187,6 +186,7 @@ String description = getDescription("declaration", typeElement); PackageElement pkg = utils.containingPackage(typeElement); List localStylesheets = getLocalStylesheets(pkg); + contentTree.add(bodyContents.toContent()); printHtmlDocument(configuration.metakeywords.getMetaKeywords(typeElement), description, localStylesheets, contentTree); } diff -r bfc8074ea4ef -r cfe31d2f935c src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/ConstantsSummaryWriterImpl.java --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/ConstantsSummaryWriterImpl.java Tue Nov 26 10:22:13 2019 +0000 +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/ConstantsSummaryWriterImpl.java Fri Nov 29 10:02:07 2019 +0000 @@ -33,6 +33,7 @@ import javax.lang.model.element.TypeElement; import javax.lang.model.element.VariableElement; +import jdk.javadoc.internal.doclets.formats.html.markup.BodyContents; import jdk.javadoc.internal.doclets.formats.html.markup.ContentBuilder; import jdk.javadoc.internal.doclets.formats.html.markup.Entity; import jdk.javadoc.internal.doclets.formats.html.markup.HtmlStyle; @@ -76,17 +77,14 @@ private final TableHeader constantsTableHeader; /** - * The HTML tree for main tag. - */ - private final HtmlTree mainTree = HtmlTree.MAIN(); - - /** * The HTML tree for constant values summary. */ private HtmlTree summaryTree; private final Navigation navBar; + private final BodyContents bodyContents = new BodyContents(); + /** * Construct a ConstantsSummaryWriter. * @param configuration the configuration used in this run @@ -97,7 +95,7 @@ this.configuration = configuration; constantsTableHeader = new TableHeader( contents.modifierAndTypeLabel, contents.constantFieldLabel, contents.valueLabel); - this.navBar = new Navigation(null, configuration, fixedNavDiv, PageMode.CONSTANTVALUES, path); + this.navBar = new Navigation(null, configuration, PageMode.CONSTANTVALUES, path); } /** @@ -107,11 +105,11 @@ public Content getHeader() { String label = resources.getText("doclet.Constants_Summary"); HtmlTree bodyTree = getBody(getWindowTitle(label)); - HtmlTree htmlTree = HtmlTree.HEADER(); - addTop(htmlTree); + Content headerContent = new ContentBuilder(); + addTop(headerContent); navBar.setUserHeader(getUserHeaderFooter(true)); - htmlTree.add(navBar.getContent(true)); - bodyTree.add(htmlTree); + headerContent.add(navBar.getContent(true)); + bodyContents.setHeader(headerContent); return bodyTree; } @@ -150,7 +148,7 @@ * {@inheritDoc} */ @Override - public void addContentsList(Content contentTree, Content contentListTree) { + public void addContentsList(Content contentListTree) { Content titleContent = contents.constantsSummaryTitle; Content pHeading = HtmlTree.HEADING(Headings.PAGE_TITLE_HEADING, true, HtmlStyle.title, titleContent); @@ -161,7 +159,7 @@ HtmlTree section = HtmlTree.SECTION(HtmlStyle.packages, heading); section.add(contentListTree); div.add(section); - mainTree.add(div); + bodyContents.addMainContent(div); } /** @@ -303,24 +301,23 @@ * {@inheritDoc} */ @Override - public void addConstantSummaries(Content contentTree, Content summariesTree) { + public void addConstantSummaries(Content summariesTree) { if (summaryTree != null) { summariesTree.add(summaryTree); } - mainTree.add(summariesTree); - contentTree.add(mainTree); + bodyContents.addMainContent(summariesTree); } /** * {@inheritDoc} */ @Override - public void addFooter(Content contentTree) { + public void addFooter() { Content htmlTree = HtmlTree.FOOTER(); navBar.setUserFooter(getUserHeaderFooter(false)); htmlTree.add(navBar.getContent(false)); addBottom(htmlTree); - contentTree.add(htmlTree); + bodyContents.setFooter(htmlTree); } /** @@ -328,6 +325,7 @@ */ @Override public void printDocument(Content contentTree) throws DocFileIOException { + contentTree.add(bodyContents.toContent()); printHtmlDocument(null, "summary of constants", contentTree); } } diff -r bfc8074ea4ef -r cfe31d2f935c src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/DeprecatedListWriter.java --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/DeprecatedListWriter.java Tue Nov 26 10:22:13 2019 +0000 +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/DeprecatedListWriter.java Fri Nov 29 10:02:07 2019 +0000 @@ -222,7 +222,7 @@ public DeprecatedListWriter(HtmlConfiguration configuration, DocPath filename) { super(configuration, filename); this.configuration = configuration; - this.navBar = new Navigation(null, configuration, fixedNavDiv, PageMode.DEPRECATED, path); + this.navBar = new Navigation(null, configuration, PageMode.DEPRECATED, path); NestedClassWriterImpl classW = new NestedClassWriterImpl(this); writerMap = new EnumMap<>(DeprElementKind.class); for (DeprElementKind kind : DeprElementKind.values()) { @@ -283,8 +283,7 @@ protected void generateDeprecatedListFile(DeprecatedAPIListBuilder deprapi) throws DocFileIOException { HtmlTree body = getHeader(); - HtmlTree htmlTree = HtmlTree.MAIN(); - htmlTree.add(getContentsList(deprapi)); + bodyContents.addMainContent(getContentsList(deprapi)); String memberTableSummary; HtmlTree div = new HtmlTree(HtmlTag.DIV); div.setStyle(HtmlStyle.contentContainer); @@ -300,14 +299,14 @@ getHeadingKey(kind), memberTableSummary, memberTableHeader, div); } } - htmlTree.add(div); - body.add(htmlTree); - htmlTree = HtmlTree.FOOTER(); + bodyContents.addMainContent(div); + HtmlTree htmlTree = HtmlTree.FOOTER(); navBar.setUserFooter(getUserHeaderFooter(false)); htmlTree.add(navBar.getContent(false)); addBottom(htmlTree); - body.add(htmlTree); + bodyContents.setFooter(htmlTree); String description = "deprecated elements"; + body.add(bodyContents.toContent()); printHtmlDocument(null, description, body); } @@ -315,7 +314,7 @@ * Add the index link. * * @param builder the deprecated list builder - * @param type the type of list being documented + * @param kind the kind of list being documented * @param contentTree the content tree to which the index link will be added */ private void addIndexLink(DeprecatedAPIListBuilder builder, @@ -353,7 +352,7 @@ * Add the anchor. * * @param builder the deprecated list builder - * @param type the type of list being documented + * @param kind the kind of list being documented * @param htmlTree the content tree to which the anchor will be added */ private void addAnchor(DeprecatedAPIListBuilder builder, DeprElementKind kind, Content htmlTree) { @@ -370,11 +369,11 @@ public HtmlTree getHeader() { String title = resources.getText("doclet.Window_Deprecated_List"); HtmlTree bodyTree = getBody(getWindowTitle(title)); - HtmlTree htmlTree = HtmlTree.HEADER(); - addTop(htmlTree); + Content headerContent = new ContentBuilder(); + addTop(headerContent); navBar.setUserHeader(getUserHeaderFooter(true)); - htmlTree.add(navBar.getContent(true)); - bodyTree.add(htmlTree); + headerContent.add(navBar.getContent(true)); + bodyContents.setHeader(headerContent); return bodyTree; } diff -r bfc8074ea4ef -r cfe31d2f935c src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/DocFilesHandlerImpl.java --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/DocFilesHandlerImpl.java Tue Nov 26 10:22:13 2019 +0000 +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/DocFilesHandlerImpl.java Fri Nov 29 10:02:07 2019 +0000 @@ -31,6 +31,9 @@ import com.sun.source.doctree.TextTree; import com.sun.source.util.DocTreeFactory; import com.sun.tools.doclint.HtmlTag; +import jdk.javadoc.internal.doclets.formats.html.markup.BodyContents; +import jdk.javadoc.internal.doclets.formats.html.markup.ContentBuilder; +import jdk.javadoc.internal.doclets.formats.html.markup.HtmlStyle; import jdk.javadoc.internal.doclets.formats.html.markup.HtmlTree; import jdk.javadoc.internal.doclets.formats.html.markup.Navigation; import jdk.javadoc.internal.doclets.toolkit.Content; @@ -180,32 +183,31 @@ String title = getWindowTitle(docletWriter, dfElement).trim(); HtmlTree htmlContent = docletWriter.getBody(title); - docletWriter.addTop(htmlContent); PackageElement pkg = dfElement.getPackageElement(); - this.navBar = new Navigation(element, configuration, docletWriter.fixedNavDiv, - PageMode.DOCFILE, docletWriter.path); + this.navBar = new Navigation(element, configuration, PageMode.DOCFILE, docletWriter.path); + Content headerContent = new ContentBuilder(); + docletWriter.addTop(headerContent); Content mdleLinkContent = docletWriter.getModuleLink(utils.elementUtils.getModuleOf(pkg), docletWriter.contents.moduleLabel); navBar.setNavLinkModule(mdleLinkContent); Content pkgLinkContent = docletWriter.getPackageLink(pkg, docletWriter.contents.packageLabel); navBar.setNavLinkPackage(pkgLinkContent); navBar.setUserHeader(docletWriter.getUserHeaderFooter(true)); - Content header = HtmlTree.HEADER(); - header.add(navBar.getContent(true)); - htmlContent.add(header); + headerContent.add(navBar.getContent(true)); List fullBody = utils.getFullBody(dfElement); - Content bodyContent = docletWriter.commentTagsToContent(null, dfElement, fullBody, false); - docletWriter.addTagsInfo(dfElement, bodyContent); - Content main = HtmlTree.MAIN(); - main.add(bodyContent); - htmlContent.add(main); + Content pageContent = docletWriter.commentTagsToContent(null, dfElement, fullBody, false); + docletWriter.addTagsInfo(dfElement, pageContent); navBar.setUserFooter(docletWriter.getUserHeaderFooter(false)); Content footer = HtmlTree.FOOTER(); footer.add(navBar.getContent(false)); docletWriter.addBottom(footer); - htmlContent.add(footer); + htmlContent.add(new BodyContents() + .setHeader(headerContent) + .addMainContent(HtmlTree.DIV(HtmlStyle.contentContainer, pageContent)) + .setFooter(footer) + .toContent()); docletWriter.printHtmlDocument(Collections.emptyList(), null, localTagsContent, Collections.emptyList(), htmlContent); } diff -r bfc8074ea4ef -r cfe31d2f935c src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/HelpWriter.java --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/HelpWriter.java Tue Nov 26 10:22:13 2019 +0000 +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/HelpWriter.java Fri Nov 29 10:02:07 2019 +0000 @@ -25,6 +25,8 @@ package jdk.javadoc.internal.doclets.formats.html; +import jdk.javadoc.internal.doclets.formats.html.markup.BodyContents; +import jdk.javadoc.internal.doclets.formats.html.markup.ContentBuilder; import jdk.javadoc.internal.doclets.formats.html.markup.HtmlStyle; import jdk.javadoc.internal.doclets.formats.html.markup.HtmlTag; import jdk.javadoc.internal.doclets.formats.html.markup.HtmlTree; @@ -50,8 +52,6 @@ */ public class HelpWriter extends HtmlDocletWriter { - HtmlTree mainTree = HtmlTree.MAIN(); - private final Navigation navBar; /** @@ -62,7 +62,7 @@ public HelpWriter(HtmlConfiguration configuration, DocPath filename) { super(configuration, filename); - this.navBar = new Navigation(null, configuration, fixedNavDiv, PageMode.HELP, path); + this.navBar = new Navigation(null, configuration, PageMode.HELP, path); } /** @@ -88,17 +88,21 @@ protected void generateHelpFile() throws DocFileIOException { String title = resources.getText("doclet.Window_Help_title"); HtmlTree body = getBody(getWindowTitle(title)); - HtmlTree htmlTree = HtmlTree.HEADER(); - addTop(htmlTree); + Content headerContent = new ContentBuilder(); + addTop(headerContent); navBar.setUserHeader(getUserHeaderFooter(true)); - htmlTree.add(navBar.getContent(true)); - body.add(htmlTree); - addHelpFileContents(body); - htmlTree = HtmlTree.FOOTER(); + headerContent.add(navBar.getContent(true)); + ContentBuilder helpFileContent = new ContentBuilder(); + addHelpFileContents(helpFileContent); + HtmlTree footer = HtmlTree.FOOTER(); navBar.setUserFooter(getUserHeaderFooter(false)); - htmlTree.add(navBar.getContent(false)); - addBottom(htmlTree); - body.add(htmlTree); + footer.add(navBar.getContent(false)); + addBottom(footer); + body.add(new BodyContents() + .setHeader(headerContent) + .addMainContent(helpFileContent) + .setFooter(footer) + .toContent()); printHtmlDocument(null, "help", body); } @@ -118,7 +122,7 @@ Content intro = HtmlTree.DIV(HtmlStyle.subTitle, contents.getContent("doclet.help.intro")); div.add(intro); - mainTree.add(div); + contentTree.add(div); HtmlTree htmlTree; HtmlTree ul = new HtmlTree(HtmlTag.UL); ul.setStyle(HtmlStyle.blockList); @@ -332,7 +336,6 @@ Content footnote = HtmlTree.SPAN(HtmlStyle.emphasizedPhrase, contents.getContent("doclet.help.footnote")); divContent.add(footnote); - mainTree.add(divContent); - contentTree.add(mainTree); + contentTree.add(divContent); } } diff -r bfc8074ea4ef -r cfe31d2f935c src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/HtmlDocletWriter.java --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/HtmlDocletWriter.java Tue Nov 26 10:22:13 2019 +0000 +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/HtmlDocletWriter.java Fri Nov 29 10:02:07 2019 +0000 @@ -188,8 +188,6 @@ */ private boolean isContainerDocumented = false; - HtmlTree fixedNavDiv = new HtmlTree(HtmlTag.DIV); - /** * The window title of this file. */ @@ -509,7 +507,7 @@ */ public void addTop(Content htmlTree) { Content top = new RawHtml(replaceDocRootDir(configuration.top)); - fixedNavDiv.add(top); + htmlTree.add(top); } /** @@ -2112,29 +2110,6 @@ } /** - * Returns an HtmlTree for the SCRIPT tag. - * - * @return an HtmlTree for the SCRIPT tag - */ - protected Script getWinTitleScript() { - Script script = new Script(); - if (winTitle != null && winTitle.length() > 0) { - script.append("\n"); - } - return script; - } - - /** * Returns an HtmlTree for the BODY tag. * * @param title title for the window diff -r bfc8074ea4ef -r cfe31d2f935c src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/ModuleWriterImpl.java --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/ModuleWriterImpl.java Tue Nov 26 10:22:13 2019 +0000 +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/ModuleWriterImpl.java Fri Nov 29 10:02:07 2019 +0000 @@ -42,6 +42,7 @@ import com.sun.source.doctree.DocTree; import jdk.javadoc.doclet.DocletEnvironment.ModuleMode; +import jdk.javadoc.internal.doclets.formats.html.markup.BodyContents; import jdk.javadoc.internal.doclets.formats.html.markup.ContentBuilder; import jdk.javadoc.internal.doclets.formats.html.markup.Entity; import jdk.javadoc.internal.doclets.formats.html.markup.HtmlStyle; @@ -161,12 +162,9 @@ private final Map providesTrees = new TreeMap<>(utils.makeAllClassesComparator()); - /** - * The HTML tree for main tag. - */ - protected HtmlTree mainTree = HtmlTree.MAIN(); + private final Navigation navBar; - private final Navigation navBar; + private final BodyContents bodyContents = new BodyContents(); /** * Constructor to construct ModuleWriter object and to generate "moduleName-summary.html" file. @@ -178,7 +176,7 @@ super(configuration, configuration.docPaths.moduleSummary(mdle)); this.mdle = mdle; this.moduleMode = configuration.docEnv.getModuleMode(); - this.navBar = new Navigation(mdle, configuration, fixedNavDiv, PageMode.MODULE, path); + this.navBar = new Navigation(mdle, configuration, PageMode.MODULE, path); computeModulesData(); } @@ -190,16 +188,15 @@ @Override public Content getModuleHeader(String heading) { HtmlTree bodyTree = getBody(getWindowTitle(mdle.getQualifiedName().toString())); - HtmlTree htmlTree = HtmlTree.HEADER(); - addTop(htmlTree); + Content headerContent = new ContentBuilder(); + addTop(headerContent); navBar.setDisplaySummaryModuleDescLink(!utils.getFullBody(mdle).isEmpty() && !configuration.nocomment); navBar.setDisplaySummaryModulesLink(display(requires) || display(indirectModules)); navBar.setDisplaySummaryPackagesLink(display(packages) || display(indirectPackages) || display(indirectOpenPackages)); navBar.setDisplaySummaryServicesLink(displayServices(uses, usesTrees) || displayServices(provides.keySet(), providesTrees)); navBar.setUserHeader(getUserHeaderFooter(true)); - htmlTree.add(navBar.getContent(true)); - bodyTree.add(htmlTree); + headerContent.add(navBar.getContent(true)); HtmlTree div = new HtmlTree(HtmlTag.DIV); div.setStyle(HtmlStyle.header); Content annotationContent = new HtmlTree(HtmlTag.P); @@ -213,7 +210,8 @@ Content moduleHead = new RawHtml(heading); tHeading.add(moduleHead); div.add(tHeading); - mainTree.add(div); + bodyContents.setHeader(headerContent) + .addMainContent(div); return bodyTree; } @@ -877,21 +875,20 @@ * {@inheritDoc} */ @Override - public void addModuleContent(Content contentTree, Content moduleContentTree) { - mainTree.add(moduleContentTree); - contentTree.add(mainTree); + public void addModuleContent(Content moduleContentTree) { + bodyContents.addMainContent(moduleContentTree); } /** * {@inheritDoc} */ @Override - public void addModuleFooter(Content contentTree) { + public void addModuleFooter() { Content htmlTree = HtmlTree.FOOTER(); navBar.setUserFooter(getUserHeaderFooter(false)); htmlTree.add(navBar.getContent(false)); addBottom(htmlTree); - contentTree.add(htmlTree); + bodyContents.setFooter(htmlTree); } /** @@ -901,6 +898,7 @@ */ @Override public void printDocument(Content contentTree) throws DocFileIOException { + contentTree.add(bodyContents.toContent()); printHtmlDocument(configuration.metakeywords.getMetaKeywordsForModule(mdle), getDescription("declaration", mdle), getLocalStylesheets(mdle), contentTree); } diff -r bfc8074ea4ef -r cfe31d2f935c src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/PackageTreeWriter.java --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/PackageTreeWriter.java Tue Nov 26 10:22:13 2019 +0000 +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/PackageTreeWriter.java Fri Nov 29 10:02:07 2019 +0000 @@ -27,6 +27,8 @@ import javax.lang.model.element.PackageElement; +import jdk.javadoc.internal.doclets.formats.html.markup.BodyContents; +import jdk.javadoc.internal.doclets.formats.html.markup.ContentBuilder; import jdk.javadoc.internal.doclets.formats.html.markup.HtmlStyle; import jdk.javadoc.internal.doclets.formats.html.markup.HtmlTag; import jdk.javadoc.internal.doclets.formats.html.markup.HtmlTree; @@ -60,6 +62,8 @@ private final Navigation navBar; + private final BodyContents bodyContents = new BodyContents(); + /** * Constructor. * @param configuration the configuration @@ -70,7 +74,7 @@ super(configuration, path, new ClassTree(configuration.typeElementCatalog.allClasses(packageElement), configuration)); this.packageElement = packageElement; - this.navBar = new Navigation(packageElement, configuration, fixedNavDiv, PageMode.TREE, path); + this.navBar = new Navigation(packageElement, configuration, PageMode.TREE, path); } /** @@ -97,7 +101,7 @@ */ protected void generatePackageTreeFile() throws DocFileIOException { HtmlTree body = getPackageTreeHeader(); - HtmlTree mainTree = HtmlTree.MAIN(); + Content mainContent = new ContentBuilder(); Content headContent = contents.getContent("doclet.Hierarchy_For_Package", utils.getPackageName(packageElement)); Content heading = HtmlTree.HEADING(Headings.PAGE_TITLE_HEADING, false, @@ -106,20 +110,21 @@ if (configuration.packages.size() > 1) { addLinkToMainTree(div); } - mainTree.add(div); + mainContent.add(div); HtmlTree divTree = new HtmlTree(HtmlTag.DIV); divTree.setStyle(HtmlStyle.contentContainer); addTree(classtree.baseClasses(), "doclet.Class_Hierarchy", divTree); addTree(classtree.baseInterfaces(), "doclet.Interface_Hierarchy", divTree); addTree(classtree.baseAnnotationTypes(), "doclet.Annotation_Type_Hierarchy", divTree); addTree(classtree.baseEnums(), "doclet.Enum_Hierarchy", divTree, true); - mainTree.add(divTree); - body.add(mainTree); + mainContent.add(divTree); + bodyContents.addMainContent(mainContent); HtmlTree footer = HtmlTree.FOOTER(); navBar.setUserFooter(getUserHeaderFooter(false)); footer.add(navBar.getContent(false)); addBottom(footer); - body.add(footer); + bodyContents.setFooter(footer); + body.add(bodyContents.toContent()); printHtmlDocument(null, getDescription("tree", packageElement), body); } @@ -132,14 +137,14 @@ String packageName = packageElement.isUnnamed() ? "" : utils.getPackageName(packageElement); String title = packageName + " " + resources.getText("doclet.Window_Class_Hierarchy"); HtmlTree bodyTree = getBody(getWindowTitle(title)); - HtmlTree htmlTree = HtmlTree.HEADER(); - addTop(htmlTree); + Content headerContent = new ContentBuilder(); + addTop(headerContent); Content linkContent = getModuleLink(utils.elementUtils.getModuleOf(packageElement), contents.moduleLabel); navBar.setNavLinkModule(linkContent); navBar.setUserHeader(getUserHeaderFooter(true)); - htmlTree.add(navBar.getContent(true)); - bodyTree.add(htmlTree); + headerContent.add(navBar.getContent(true)); + bodyContents.setHeader(headerContent); return bodyTree; } diff -r bfc8074ea4ef -r cfe31d2f935c src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/PackageUseWriter.java --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/PackageUseWriter.java Tue Nov 26 10:22:13 2019 +0000 +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/PackageUseWriter.java Fri Nov 29 10:02:07 2019 +0000 @@ -64,7 +64,6 @@ final PackageElement packageElement; final SortedMap> usingPackageToUsedClasses = new TreeMap<>(); - protected HtmlTree mainTree = HtmlTree.MAIN(); final String packageUseTableSummary; private final Navigation navBar; @@ -104,7 +103,7 @@ packageUseTableSummary = resources.getText("doclet.Use_Table_Summary", resources.getText("doclet.packages")); - this.navBar = new Navigation(packageElement, configuration, fixedNavDiv, PageMode.USE, path); + this.navBar = new Navigation(packageElement, configuration, PageMode.USE, path); } /** @@ -136,13 +135,13 @@ } else { addPackageUse(div); } - mainTree.add(div); - body.add(mainTree); + bodyContents.addMainContent(div); HtmlTree footer = HtmlTree.FOOTER(); navBar.setUserFooter(getUserHeaderFooter(false)); footer.add(navBar.getContent(false)); addBottom(footer); - body.add(footer); + bodyContents.setFooter(footer); + body.add(bodyContents.toContent()); printHtmlDocument(null, getDescription("use", packageElement), body); @@ -242,22 +241,22 @@ String name = packageElement.isUnnamed() ? "" : utils.getPackageName(packageElement); String title = resources.getText("doclet.Window_ClassUse_Header", packageText, name); HtmlTree bodyTree = getBody(getWindowTitle(title)); - HtmlTree htmlTree = HtmlTree.HEADER(); - addTop(htmlTree); + Content headerContent = new ContentBuilder(); + addTop(headerContent); Content linkContent = getModuleLink(utils.elementUtils.getModuleOf(packageElement), contents.moduleLabel); navBar.setNavLinkModule(linkContent); navBar.setUserHeader(getUserHeaderFooter(true)); - htmlTree.add(navBar.getContent(true)); - bodyTree.add(htmlTree); - ContentBuilder headContent = new ContentBuilder(); - headContent.add(contents.getContent("doclet.ClassUse_Title", packageText)); - headContent.add(new HtmlTree(HtmlTag.BR)); - headContent.add(name); + headerContent.add(navBar.getContent(true)); + ContentBuilder headingContent = new ContentBuilder(); + headingContent.add(contents.getContent("doclet.ClassUse_Title", packageText)); + headingContent.add(new HtmlTree(HtmlTag.BR)); + headingContent.add(name); Content heading = HtmlTree.HEADING(Headings.PAGE_TITLE_HEADING, true, - HtmlStyle.title, headContent); + HtmlStyle.title, headingContent); Content div = HtmlTree.DIV(HtmlStyle.header, heading); - mainTree.add(div); + bodyContents.setHeader(headerContent) + .addMainContent(div); return bodyTree; } } diff -r bfc8074ea4ef -r cfe31d2f935c src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/PackageWriterImpl.java --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/PackageWriterImpl.java Tue Nov 26 10:22:13 2019 +0000 +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/PackageWriterImpl.java Fri Nov 29 10:02:07 2019 +0000 @@ -33,6 +33,7 @@ import javax.lang.model.element.TypeElement; import com.sun.source.doctree.DocTree; +import jdk.javadoc.internal.doclets.formats.html.markup.BodyContents; import jdk.javadoc.internal.doclets.formats.html.markup.ContentBuilder; import jdk.javadoc.internal.doclets.formats.html.markup.Entity; import jdk.javadoc.internal.doclets.formats.html.markup.HtmlStyle; @@ -72,17 +73,14 @@ protected PackageElement packageElement; /** - * The HTML tree for main tag. - */ - protected HtmlTree mainTree = HtmlTree.MAIN(); - - /** * The HTML tree for section tag. */ protected HtmlTree sectionTree = HtmlTree.SECTION(HtmlStyle.packageDescription, new ContentBuilder()); private final Navigation navBar; + private final BodyContents bodyContents = new BodyContents(); + /** * Constructor to construct PackageWriter object and to generate * "package-summary.html" file in the respective package directory. @@ -99,7 +97,7 @@ configuration.docPaths.forPackage(packageElement) .resolve(DocPaths.PACKAGE_SUMMARY)); this.packageElement = packageElement; - this.navBar = new Navigation(packageElement, configuration, fixedNavDiv, PageMode.PACKAGE, path); + this.navBar = new Navigation(packageElement, configuration, PageMode.PACKAGE, path); } /** @@ -108,14 +106,13 @@ @Override public Content getPackageHeader(String heading) { HtmlTree bodyTree = getBody(getWindowTitle(utils.getPackageName(packageElement))); - HtmlTree htmlTree = HtmlTree.HEADER(); - addTop(htmlTree); + Content headerContent = new ContentBuilder(); + addTop(headerContent); Content linkContent = getModuleLink(utils.elementUtils.getModuleOf(packageElement), contents.moduleLabel); navBar.setNavLinkModule(linkContent); navBar.setUserHeader(getUserHeaderFooter(true)); - htmlTree.add(navBar.getContent(true)); - bodyTree.add(htmlTree); + headerContent.add(navBar.getContent(true)); HtmlTree div = new HtmlTree(HtmlTag.DIV); div.setStyle(HtmlStyle.header); if (configuration.showModules) { @@ -136,7 +133,8 @@ Content packageHead = new StringContent(heading); tHeading.add(packageHead); div.add(tHeading); - mainTree.add(div); + bodyContents.setHeader(headerContent) + .addMainContent(div); return bodyTree; } @@ -295,21 +293,20 @@ * {@inheritDoc} */ @Override - public void addPackageContent(Content contentTree, Content packageContentTree) { - mainTree.add(packageContentTree); - contentTree.add(mainTree); + public void addPackageContent(Content packageContentTree) { + bodyContents.addMainContent(packageContentTree); } /** * {@inheritDoc} */ @Override - public void addPackageFooter(Content contentTree) { + public void addPackageFooter() { Content htmlTree = HtmlTree.FOOTER(); navBar.setUserFooter(getUserHeaderFooter(false)); htmlTree.add(navBar.getContent(false)); addBottom(htmlTree); - contentTree.add(htmlTree); + bodyContents.setFooter(htmlTree); } /** @@ -319,6 +316,7 @@ public void printDocument(Content contentTree) throws DocFileIOException { String description = getDescription("declaration", packageElement); List localStylesheets = getLocalStylesheets(packageElement); + contentTree.add(bodyContents.toContent()); printHtmlDocument(configuration.metakeywords.getMetaKeywords(packageElement), description, localStylesheets, contentTree); } diff -r bfc8074ea4ef -r cfe31d2f935c src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/SerializedFormWriterImpl.java --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/SerializedFormWriterImpl.java Tue Nov 26 10:22:13 2019 +0000 +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/SerializedFormWriterImpl.java Fri Nov 29 10:02:07 2019 +0000 @@ -29,6 +29,7 @@ import javax.lang.model.element.TypeElement; +import jdk.javadoc.internal.doclets.formats.html.markup.ContentBuilder; import jdk.javadoc.internal.doclets.formats.html.markup.Entity; import jdk.javadoc.internal.doclets.formats.html.markup.HtmlStyle; import jdk.javadoc.internal.doclets.formats.html.markup.HtmlTag; @@ -56,11 +57,6 @@ Set visibleClasses; - /** - * HTML tree for main tag. - */ - private HtmlTree mainTree = HtmlTree.MAIN(); - private final Navigation navBar; /** @@ -69,7 +65,7 @@ public SerializedFormWriterImpl(HtmlConfiguration configuration) { super(configuration, DocPaths.SERIALIZED_FORM); visibleClasses = configuration.getIncludedTypeElements(); - this.navBar = new Navigation(null, configuration, fixedNavDiv, PageMode.SERIALIZEDFORM, path); + this.navBar = new Navigation(null, configuration, PageMode.SERIALIZEDFORM, path); } /** @@ -80,16 +76,16 @@ */ public Content getHeader(String header) { HtmlTree bodyTree = getBody(getWindowTitle(header)); - HtmlTree htmlTree = HtmlTree.HEADER(); - addTop(htmlTree); + Content headerContent = new ContentBuilder(); + addTop(headerContent); navBar.setUserHeader(getUserHeaderFooter(true)); - htmlTree.add(navBar.getContent(true)); - bodyTree.add(htmlTree); + headerContent.add(navBar.getContent(true)); Content h1Content = new StringContent(header); Content heading = HtmlTree.HEADING(Headings.PAGE_TITLE_HEADING, true, HtmlStyle.title, h1Content); Content div = HtmlTree.DIV(HtmlStyle.header, heading); - mainTree.add(div); + bodyContents.setHeader(headerContent) + .addMainContent(div); return bodyTree; } @@ -216,16 +212,14 @@ } /** - * Get the serialized content tree section. + * Add the serialized content tree section. * * @param serializedTreeContent the serialized content tree to be added - * @return a div content tree */ - public Content getSerializedContent(Content serializedTreeContent) { + public void addSerializedContent(Content serializedTreeContent) { HtmlTree divContent = HtmlTree.DIV(HtmlStyle.serializedFormContainer, serializedTreeContent); - mainTree.add(divContent); - return mainTree; + bodyContents.addMainContent(divContent); } /** @@ -238,15 +232,13 @@ /** * Add the footer. - * - * @param serializedTree the serialized tree to be added */ - public void addFooter(Content serializedTree) { + public void addFooter() { Content htmlTree = HtmlTree.FOOTER(); navBar.setUserFooter(getUserHeaderFooter(false)); htmlTree.add(navBar.getContent(false)); addBottom(htmlTree); - serializedTree.add(htmlTree); + bodyContents.setFooter(htmlTree); } /** @@ -254,6 +246,7 @@ */ @Override public void printDocument(Content serializedTree) throws DocFileIOException { + serializedTree.add(bodyContents.toContent()); printHtmlDocument(null, "serialized forms", serializedTree); } diff -r bfc8074ea4ef -r cfe31d2f935c src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/SingleIndexWriter.java --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/SingleIndexWriter.java Tue Nov 26 10:22:13 2019 +0000 +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/SingleIndexWriter.java Fri Nov 29 10:02:07 2019 +0000 @@ -28,6 +28,8 @@ import java.util.Set; import java.util.TreeSet; +import jdk.javadoc.internal.doclets.formats.html.markup.BodyContents; +import jdk.javadoc.internal.doclets.formats.html.markup.ContentBuilder; import jdk.javadoc.internal.doclets.formats.html.markup.Entity; import jdk.javadoc.internal.doclets.formats.html.markup.HtmlStyle; import jdk.javadoc.internal.doclets.formats.html.markup.HtmlTag; @@ -95,15 +97,10 @@ protected void generateIndexFile() throws DocFileIOException { String title = resources.getText("doclet.Window_Single_Index"); HtmlTree body = getBody(getWindowTitle(title)); - HtmlTree header = HtmlTree.HEADER(); - addTop(header); + Content headerContent = new ContentBuilder(); + addTop(headerContent); navBar.setUserHeader(getUserHeaderFooter(true)); - header.add(navBar.getContent(true)); - body.add(header); - HtmlTree main = HtmlTree.MAIN(); - main.add(HtmlTree.DIV(HtmlStyle.header, - HtmlTree.HEADING(Headings.PAGE_TITLE_HEADING, - contents.getContent("doclet.Index")))); + headerContent.add(navBar.getContent(true)); HtmlTree divTree = new HtmlTree(HtmlTag.DIV); divTree.setStyle(HtmlStyle.contentContainer); elements = new TreeSet<>(indexbuilder.getIndexMap().keySet()); @@ -120,13 +117,18 @@ } } addLinksForIndexes(divTree); - main.add(divTree); - body.add(main); HtmlTree footer = HtmlTree.FOOTER(); navBar.setUserFooter(getUserHeaderFooter(false)); footer.add(navBar.getContent(false)); addBottom(footer); - body.add(footer); + body.add(new BodyContents() + .setHeader(headerContent) + .addMainContent(HtmlTree.DIV(HtmlStyle.header, + HtmlTree.HEADING(Headings.PAGE_TITLE_HEADING, + contents.getContent("doclet.Index")))) + .addMainContent(divTree) + .setFooter(footer) + .toContent()); createSearchIndexFiles(); printHtmlDocument(null, "index", body); } diff -r bfc8074ea4ef -r cfe31d2f935c src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/SplitIndexWriter.java --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/SplitIndexWriter.java Tue Nov 26 10:22:13 2019 +0000 +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/SplitIndexWriter.java Fri Nov 29 10:02:07 2019 +0000 @@ -32,6 +32,8 @@ import java.util.Set; import java.util.TreeSet; +import jdk.javadoc.internal.doclets.formats.html.markup.BodyContents; +import jdk.javadoc.internal.doclets.formats.html.markup.ContentBuilder; import jdk.javadoc.internal.doclets.formats.html.markup.Entity; import jdk.javadoc.internal.doclets.formats.html.markup.HtmlStyle; import jdk.javadoc.internal.doclets.formats.html.markup.HtmlTag; @@ -122,12 +124,11 @@ String title = resources.getText("doclet.Window_Split_Index", unicode.toString()); HtmlTree body = getBody(getWindowTitle(title)); - HtmlTree header = HtmlTree.HEADER(); - addTop(header); + Content headerContent = new ContentBuilder(); + addTop(headerContent); navBar.setUserHeader(getUserHeaderFooter(true)); - header.add(navBar.getContent(true)); - body.add(header); - HtmlTree main = HtmlTree.MAIN(); + headerContent.add(navBar.getContent(true)); + Content main = new ContentBuilder(); main.add(HtmlTree.DIV(HtmlStyle.header, HtmlTree.HEADING(Headings.PAGE_TITLE_HEADING, contents.getContent("doclet.Index")))); @@ -144,12 +145,15 @@ } addLinksForIndexes(divTree); main.add(divTree); - body.add(main); HtmlTree footer = HtmlTree.FOOTER(); navBar.setUserFooter(getUserHeaderFooter(false)); footer.add(navBar.getContent(false)); addBottom(footer); - body.add(footer); + body.add(new BodyContents() + .setHeader(headerContent) + .addMainContent(main) + .setFooter(footer) + .toContent()); String description = "index: " + unicode; printHtmlDocument(null, description, body); } diff -r bfc8074ea4ef -r cfe31d2f935c src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/SubWriterHolderWriter.java --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/SubWriterHolderWriter.java Tue Nov 26 10:22:13 2019 +0000 +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/SubWriterHolderWriter.java Fri Nov 29 10:02:07 2019 +0000 @@ -31,6 +31,7 @@ import javax.lang.model.element.TypeElement; import com.sun.source.doctree.DocTree; +import jdk.javadoc.internal.doclets.formats.html.markup.BodyContents; import jdk.javadoc.internal.doclets.formats.html.markup.HtmlStyle; import jdk.javadoc.internal.doclets.formats.html.markup.HtmlTag; import jdk.javadoc.internal.doclets.formats.html.markup.HtmlTree; @@ -60,9 +61,9 @@ public abstract class SubWriterHolderWriter extends HtmlDocletWriter { /** - * The HTML tree for main tag. + * The HTML builder for the body contents. */ - protected HtmlTree mainTree = HtmlTree.MAIN(); + protected BodyContents bodyContents = new BodyContents(); public SubWriterHolderWriter(HtmlConfiguration configuration, DocPath filename) { super(configuration, filename); @@ -191,22 +192,19 @@ /** * Add the class content tree. * - * @param contentTree content tree to which the class content will be added * @param classContentTree class content tree which will be added to the content tree */ - public void addClassContentTree(Content contentTree, Content classContentTree) { - mainTree.add(classContentTree); - contentTree.add(mainTree); + public void addClassContentTree(Content classContentTree) { + bodyContents.addMainContent(classContentTree); } /** * Add the annotation content tree. * - * @param contentTree content tree to which the annotation content will be added * @param annotationContentTree annotation content tree which will be added to the content tree */ - public void addAnnotationContentTree(Content contentTree, Content annotationContentTree) { - addClassContentTree(contentTree, annotationContentTree); + public void addAnnotationContentTree(Content annotationContentTree) { + addClassContentTree(annotationContentTree); } /** diff -r bfc8074ea4ef -r cfe31d2f935c src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/TreeWriter.java --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/TreeWriter.java Tue Nov 26 10:22:13 2019 +0000 +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/TreeWriter.java Fri Nov 29 10:02:07 2019 +0000 @@ -29,6 +29,8 @@ import javax.lang.model.element.PackageElement; +import jdk.javadoc.internal.doclets.formats.html.markup.BodyContents; +import jdk.javadoc.internal.doclets.formats.html.markup.ContentBuilder; import jdk.javadoc.internal.doclets.formats.html.markup.HtmlStyle; import jdk.javadoc.internal.doclets.formats.html.markup.HtmlTag; import jdk.javadoc.internal.doclets.formats.html.markup.HtmlTree; @@ -70,6 +72,8 @@ private final Navigation navBar; + protected BodyContents bodyContents; + /** * Constructor to construct TreeWriter object. * @@ -81,7 +85,8 @@ super(configuration, filename, classtree); packages = configuration.packages; classesOnly = packages.isEmpty(); - this.navBar = new Navigation(null, configuration, fixedNavDiv, PageMode.TREE, path); + this.navBar = new Navigation(null, configuration, PageMode.TREE, path); + this.bodyContents = new BodyContents(); } /** @@ -111,21 +116,23 @@ HtmlStyle.title, headContent); Content div = HtmlTree.DIV(HtmlStyle.header, heading); addPackageTreeLinks(div); - HtmlTree htmlTree = HtmlTree.MAIN(); - htmlTree.add(div); + Content mainContent = new ContentBuilder(); + mainContent.add(div); HtmlTree divTree = new HtmlTree(HtmlTag.DIV); divTree.setStyle(HtmlStyle.contentContainer); addTree(classtree.baseClasses(), "doclet.Class_Hierarchy", divTree); addTree(classtree.baseInterfaces(), "doclet.Interface_Hierarchy", divTree); addTree(classtree.baseAnnotationTypes(), "doclet.Annotation_Type_Hierarchy", divTree); addTree(classtree.baseEnums(), "doclet.Enum_Hierarchy", divTree, true); - htmlTree.add(divTree); - body.add(htmlTree); - htmlTree = HtmlTree.FOOTER(); + mainContent.add(divTree); + HtmlTree footerTree = HtmlTree.FOOTER(); navBar.setUserFooter(getUserHeaderFooter(false)); - htmlTree.add(navBar.getContent(false)); - addBottom(htmlTree); - body.add(htmlTree); + footerTree.add(navBar.getContent(false)); + addBottom(footerTree); + body.add(bodyContents + .addMainContent(mainContent) + .setFooter(footerTree) + .toContent()); printHtmlDocument(null, "class tree", body); } @@ -176,11 +183,11 @@ protected HtmlTree getTreeHeader() { String title = resources.getText("doclet.Window_Class_Hierarchy"); HtmlTree bodyTree = getBody(getWindowTitle(title)); - HtmlTree htmlTree = HtmlTree.HEADER(); - addTop(htmlTree); + Content headerContent = new ContentBuilder(); + addTop(headerContent); navBar.setUserHeader(getUserHeaderFooter(true)); - htmlTree.add(navBar.getContent(true)); - bodyTree.add(htmlTree); + headerContent.add(navBar.getContent(true)); + bodyContents.setHeader(headerContent); return bodyTree; } diff -r bfc8074ea4ef -r cfe31d2f935c src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/markup/BodyContents.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/markup/BodyContents.java Fri Nov 29 10:02:07 2019 +0000 @@ -0,0 +1,78 @@ +/* + * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.javadoc.internal.doclets.formats.html.markup; + +import jdk.javadoc.internal.doclets.toolkit.Content; + +import java.util.ArrayList; +import java.util.List; + +/** + * A builder for the contents of the BODY element. + * + *

    This is NOT part of any supported API. + * If you write code that depends on this, you do so at your own risk. + * This code and its internal interfaces are subject to change or + * deletion without notice. + */ +public class BodyContents { + + private List mainContents = new ArrayList<>(); + private Content header = HtmlTree.EMPTY; + private Content footer = HtmlTree.EMPTY; + + public BodyContents addMainContent(Content content) { + mainContents.add(content); + return this; + } + + public BodyContents setHeader(Content header) { + this.header = header; + return this; + } + + public BodyContents setFooter(Content footer) { + this.footer = footer; + return this; + } + + /** + * Returns the HTML for the contents of the BODY element. + * + * @return the HTML + */ + public Content toContent() { + HtmlTree mainTree = HtmlTree.MAIN(); + mainContents.forEach(mainTree::add); + HtmlTree flexHeader = HtmlTree.HEADER().setStyle(HtmlStyle.flexHeader); + flexHeader.add(header); + HtmlTree flexBox = HtmlTree.DIV(HtmlStyle.flexBox, flexHeader); + HtmlTree flexContent = HtmlTree.DIV(HtmlStyle.flexContent, mainTree); + flexContent.add(footer); + flexBox.add(flexContent); + return flexBox; + } +} diff -r bfc8074ea4ef -r cfe31d2f935c src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/markup/HtmlStyle.java --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/markup/HtmlStyle.java Tue Nov 26 10:22:13 2019 +0000 +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/markup/HtmlStyle.java Fri Nov 29 10:02:07 2019 +0000 @@ -73,7 +73,9 @@ externalLink, fieldDetails, fieldSummary, - fixedNav, + flexBox, + flexHeader, + flexContent, header, helpSection, hierarchy, diff -r bfc8074ea4ef -r cfe31d2f935c src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/markup/HtmlTree.java --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/markup/HtmlTree.java Tue Nov 26 10:22:13 2019 +0000 +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/markup/HtmlTree.java Fri Nov 29 10:02:07 2019 +0000 @@ -584,21 +584,6 @@ } /** - * Generates a MAIN tag with role attribute, style attribute and some content. - * - * @param styleClass style of the MAIN tag - * @param body content of the MAIN tag - * @return an HtmlTree object for the MAIN tag - */ - public static HtmlTree MAIN(HtmlStyle styleClass, Content body) { - HtmlTree htmltree = HtmlTree.MAIN(body); - if (styleClass != null) { - htmltree.setStyle(styleClass); - } - return htmltree; - } - - /** * Generates a META tag with the http-equiv, content and charset attributes. * * @param httpEquiv http equiv attribute for the META tag diff -r bfc8074ea4ef -r cfe31d2f935c src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/markup/Navigation.java --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/markup/Navigation.java Tue Nov 26 10:22:13 2019 +0000 +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/markup/Navigation.java Fri Nov 29 10:02:07 2019 +0000 @@ -70,7 +70,6 @@ private final DocPath path; private final DocPath pathToRoot; private final Links links; - private final HtmlTree fixedNavDiv; private final PageMode documentedPage; private Content navLinkModule; private Content navLinkPackage; @@ -85,9 +84,6 @@ private Content userFooter; private final String rowListTitle; private final Content searchLabel; - private static final Script FIXED_NAV_SCRIPT = new Script("\n"); public enum PageMode { ALLCLASSES, @@ -133,15 +129,12 @@ * * @param element element being documented. null if its not an element documentation page * @param configuration the configuration object - * @param fixedNavDiv the fixed navigation for the header navigation * @param page the kind of page being documented * @param path the DocPath object */ - public Navigation(Element element, HtmlConfiguration configuration, HtmlTree fixedNavDiv, - PageMode page, DocPath path) { + public Navigation(Element element, HtmlConfiguration configuration, PageMode page, DocPath path) { this.configuration = configuration; this.element = element; - this.fixedNavDiv = fixedNavDiv; this.contents = configuration.contents; this.documentedPage = page; this.path = path; @@ -941,10 +934,6 @@ tree.add(searchDiv); } - private void addFixedNavScript(Content tree) { - tree.add(FIXED_NAV_SCRIPT.asContent()); - } - /** * Get the navigation content. * @@ -952,69 +941,58 @@ * @return the navigation contents */ public Content getContent(boolean top) { - Content contentTree = new ContentBuilder(); - if (!configuration.nonavbar) { - Deque queue; - Content tree = HtmlTree.NAV(); - HtmlTree navDiv = new HtmlTree(HtmlTag.DIV); - if (top) { - queue = topBottomNavContents.get(Position.TOP); - fixedNavDiv.add(Position.TOP.startOfNav()); - navDiv.setStyle(HtmlStyle.topNav); - } else { - queue = topBottomNavContents.get(Position.BOTTOM); - tree.add(Position.BOTTOM.startOfNav()); - navDiv.setStyle(HtmlStyle.bottomNav); - } - navDiv.add(queue.poll()); - HtmlTree skipLinkDiv = HtmlTree.DIV(HtmlStyle.skipNav, queue.poll()); - navDiv.add(skipLinkDiv); - navDiv.add(queue.poll()); - HtmlTree navList = new HtmlTree(HtmlTag.UL); - navList.setStyle(HtmlStyle.navList); - navList.put(HtmlAttr.TITLE, rowListTitle); - fixedNavDiv.setStyle(HtmlStyle.fixedNav); - addMainNavLinks(navList); - navDiv.add(navList); - Content aboutDiv = HtmlTree.DIV(HtmlStyle.aboutLanguage, top ? userHeader : userFooter); - navDiv.add(aboutDiv); - if (top) { - fixedNavDiv.add(navDiv); - } else { - tree.add(navDiv); - } - HtmlTree subDiv = new HtmlTree(HtmlTag.DIV); - subDiv.setStyle(HtmlStyle.subNav); - HtmlTree div = new HtmlTree(HtmlTag.DIV); - // Add the summary links if present. - HtmlTree ulNavSummary = new HtmlTree(HtmlTag.UL); - ulNavSummary.setStyle(HtmlStyle.subNavList); - addSummaryLinks(ulNavSummary); - div.add(ulNavSummary); - // Add the detail links if present. - HtmlTree ulNavDetail = new HtmlTree(HtmlTag.UL); - ulNavDetail.setStyle(HtmlStyle.subNavList); - addDetailLinks(ulNavDetail); - div.add(ulNavDetail); - subDiv.add(div); - if (top && configuration.createindex) { - addSearch(subDiv); - } - if (top) { - fixedNavDiv.add(subDiv); - fixedNavDiv.add(queue.poll()); - fixedNavDiv.add(Position.TOP.endOfNav()); - tree.add(fixedNavDiv); - HtmlTree paddingDiv = HtmlTree.DIV(HtmlStyle.navPadding, Entity.NO_BREAK_SPACE); - tree.add(paddingDiv); - addFixedNavScript(tree); - } else { - tree.add(subDiv); - tree.add(queue.poll()); - tree.add(Position.BOTTOM.endOfNav()); - } - return tree; + if (configuration.nonavbar) { + return new ContentBuilder(); + } + Deque queue; + Content tree = HtmlTree.NAV(); + HtmlTree navDiv = new HtmlTree(HtmlTag.DIV); + if (top) { + queue = topBottomNavContents.get(Position.TOP); + tree.add(Position.TOP.startOfNav()); + navDiv.setStyle(HtmlStyle.topNav); + } else { + queue = topBottomNavContents.get(Position.BOTTOM); + tree.add(Position.BOTTOM.startOfNav()); + navDiv.setStyle(HtmlStyle.bottomNav); } - return contentTree; + navDiv.add(queue.poll()); + HtmlTree skipLinkDiv = HtmlTree.DIV(HtmlStyle.skipNav, queue.poll()); + navDiv.add(skipLinkDiv); + navDiv.add(queue.poll()); + HtmlTree navList = new HtmlTree(HtmlTag.UL); + navList.setStyle(HtmlStyle.navList); + navList.put(HtmlAttr.TITLE, rowListTitle); + addMainNavLinks(navList); + navDiv.add(navList); + Content aboutDiv = HtmlTree.DIV(HtmlStyle.aboutLanguage, top ? userHeader : userFooter); + navDiv.add(aboutDiv); + tree.add(navDiv); + HtmlTree subDiv = new HtmlTree(HtmlTag.DIV); + subDiv.setStyle(HtmlStyle.subNav); + HtmlTree div = new HtmlTree(HtmlTag.DIV); + // Add the summary links if present. + HtmlTree ulNavSummary = new HtmlTree(HtmlTag.UL); + ulNavSummary.setStyle(HtmlStyle.subNavList); + addSummaryLinks(ulNavSummary); + div.add(ulNavSummary); + // Add the detail links if present. + HtmlTree ulNavDetail = new HtmlTree(HtmlTag.UL); + ulNavDetail.setStyle(HtmlStyle.subNavList); + addDetailLinks(ulNavDetail); + div.add(ulNavDetail); + subDiv.add(div); + if (top && configuration.createindex) { + addSearch(subDiv); + } + tree.add(subDiv); + if (top) { + tree.add(Position.TOP.endOfNav()); + tree.add(HtmlTree.DIV(HtmlStyle.skipNav, queue.poll())); + } else { + tree.add(queue.poll()); + tree.add(Position.BOTTOM.endOfNav()); + } + return tree; } } diff -r bfc8074ea4ef -r cfe31d2f935c src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/AnnotationTypeWriter.java --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/AnnotationTypeWriter.java Tue Nov 26 10:22:13 2019 +0000 +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/AnnotationTypeWriter.java Fri Nov 29 10:02:07 2019 +0000 @@ -112,10 +112,9 @@ /** * Add the annotation content tree to the documentation content tree. * - * @param contentTree content tree to which the annotation content will be added * @param annotationContentTree annotation content tree which will be added to the content tree */ - public void addAnnotationContentTree(Content contentTree, Content annotationContentTree); + public void addAnnotationContentTree(Content annotationContentTree); /** * Get the member tree. @@ -143,10 +142,8 @@ /** * Add the footer of the page. - * - * @param contentTree content tree to which the footer will be added */ - public void addFooter(Content contentTree); + public void addFooter(); /** * Print the document. diff -r bfc8074ea4ef -r cfe31d2f935c src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/ClassWriter.java --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/ClassWriter.java Tue Nov 26 10:22:13 2019 +0000 +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/ClassWriter.java Fri Nov 29 10:02:07 2019 +0000 @@ -177,17 +177,14 @@ /** * Add the class content tree. * - * @param contentTree content tree to which the class content will be added * @param classContentTree class content tree which will be added to the content tree */ - public void addClassContentTree(Content contentTree, Content classContentTree); + public void addClassContentTree(Content classContentTree); /** * Add the footer of the page. - * - * @param contentTree content tree to which the footer will be added */ - public void addFooter(Content contentTree); + public void addFooter(); /** * Print the document. diff -r bfc8074ea4ef -r cfe31d2f935c src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/ConstantsSummaryWriter.java --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/ConstantsSummaryWriter.java Tue Nov 26 10:22:13 2019 +0000 +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/ConstantsSummaryWriter.java Fri Nov 29 10:02:07 2019 +0000 @@ -75,10 +75,9 @@ /** * Add the content list to the documentation tree. * - * @param contentTree the tree to which the contents list will be added * @param contentListTree the content that will be added to the list */ - public abstract void addContentsList(Content contentTree, Content contentListTree); + public abstract void addContentsList(Content contentListTree); /** * Get the constant summaries for the document. @@ -129,17 +128,14 @@ /** * Add the summaries list to the content tree. * - * @param contentTree the tree to which the summaries list will be added * @param summariesTree the summaries content tree that will be added to the list */ - public abstract void addConstantSummaries(Content contentTree, Content summariesTree); + public abstract void addConstantSummaries(Content summariesTree); /** * Adds the footer for the summary documentation. - * - * @param contentTree content tree to which the footer will be added */ - public abstract void addFooter(Content contentTree); + public abstract void addFooter(); /** * Print the constants summary document. diff -r bfc8074ea4ef -r cfe31d2f935c src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/ModuleSummaryWriter.java --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/ModuleSummaryWriter.java Tue Nov 26 10:22:13 2019 +0000 +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/ModuleSummaryWriter.java Fri Nov 29 10:02:07 2019 +0000 @@ -111,17 +111,14 @@ /** * Adds the module content tree to the documentation tree. * - * @param contentTree the tree to which the module content tree will be added * @param moduleContentTree the content tree that will be added */ - public abstract void addModuleContent(Content contentTree, Content moduleContentTree); + public abstract void addModuleContent(Content moduleContentTree); /** * Adds the footer to the documentation tree. - * - * @param contentTree the tree to which the footer will be added */ - public abstract void addModuleFooter(Content contentTree); + public abstract void addModuleFooter(); /** * Print the module summary document. diff -r bfc8074ea4ef -r cfe31d2f935c src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/PackageSummaryWriter.java --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/PackageSummaryWriter.java Tue Nov 26 10:22:13 2019 +0000 +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/PackageSummaryWriter.java Fri Nov 29 10:02:07 2019 +0000 @@ -143,17 +143,14 @@ * Adds the tag information from the "packages.html" or "package-info.java" file to the * documentation tree. * - * @param contentTree the content tree to which the package content tree will be added * @param packageContentTree the package content tree to be added */ - public abstract void addPackageContent(Content contentTree, Content packageContentTree); + public abstract void addPackageContent(Content packageContentTree); /** * Adds the footer to the documentation tree. - * - * @param contentTree the tree to which the footer will be added */ - public abstract void addPackageFooter(Content contentTree); + public abstract void addPackageFooter(); /** * Print the package summary document. diff -r bfc8074ea4ef -r cfe31d2f935c src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/SerializedFormWriter.java --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/SerializedFormWriter.java Tue Nov 26 10:22:13 2019 +0000 +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/SerializedFormWriter.java Fri Nov 29 10:02:07 2019 +0000 @@ -140,19 +140,16 @@ public SerialMethodWriter getSerialMethodWriter(TypeElement typeElement); /** - * Get the serialized content. + * Add the serialized content to the body content. * * @param serializedTreeContent content for serialized data - * @return a content tree for serialized information */ - public Content getSerializedContent(Content serializedTreeContent); + public void addSerializedContent(Content serializedTreeContent); /** * Add the footer. - * - * @param serializedTree the serialized tree to be added */ - public void addFooter(Content serializedTree); + public void addFooter(); /** * Print the serialized form document. diff -r bfc8074ea4ef -r cfe31d2f935c src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/builders/AnnotationTypeBuilder.java --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/builders/AnnotationTypeBuilder.java Tue Nov 26 10:22:13 2019 +0000 +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/builders/AnnotationTypeBuilder.java Fri Nov 29 10:02:07 2019 +0000 @@ -59,11 +59,6 @@ private final AnnotationTypeWriter writer; /** - * The content tree for the annotation documentation. - */ - private Content contentTree; - - /** * Construct a new ClassBuilder. * * @param context the build context. @@ -97,17 +92,16 @@ */ @Override public void build() throws DocletException { - buildAnnotationTypeDoc(contentTree); + buildAnnotationTypeDoc(); } /** * Build the annotation type documentation. * - * @param contentTree the content tree to which the documentation will be added * @throws DocletException if there is a problem building the documentation */ - protected void buildAnnotationTypeDoc(Content contentTree) throws DocletException { - contentTree = writer.getHeader(resources.getText("doclet.AnnotationType") + + protected void buildAnnotationTypeDoc() throws DocletException { + Content contentTree = writer.getHeader(resources.getText("doclet.AnnotationType") + " " + utils.getSimpleName(annotationType)); Content annotationContentTree = writer.getAnnotationContentHeader(); @@ -115,8 +109,8 @@ buildMemberSummary(annotationContentTree); buildAnnotationTypeMemberDetails(annotationContentTree); - writer.addAnnotationContentTree(contentTree, annotationContentTree); - writer.addFooter(contentTree); + writer.addAnnotationContentTree(annotationContentTree); + writer.addFooter(); writer.printDocument(contentTree); copyDocFiles(); } diff -r bfc8074ea4ef -r cfe31d2f935c src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/builders/ClassBuilder.java --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/builders/ClassBuilder.java Tue Nov 26 10:22:13 2019 +0000 +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/builders/ClassBuilder.java Fri Nov 29 10:02:07 2019 +0000 @@ -69,11 +69,6 @@ */ private final boolean isEnum; - /** - * The content tree for the class documentation. - */ - private Content contentTree; - private final Utils utils; /** @@ -118,16 +113,15 @@ */ @Override public void build() throws DocletException { - buildClassDoc(contentTree); + buildClassDoc(); } /** * Handles the {@literal } tag. * - * @param contentTree the content tree to which the documentation will be added * @throws DocletException if there is a problem while building the documentation */ - protected void buildClassDoc(Content contentTree) throws DocletException { + protected void buildClassDoc() throws DocletException { String key; if (isInterface) { key = "doclet.Interface"; @@ -136,7 +130,7 @@ } else { key = "doclet.Class"; } - contentTree = writer.getHeader(resources.getText(key) + " " + Content contentTree = writer.getHeader(resources.getText(key) + " " + utils.getSimpleName(typeElement)); Content classContentTree = writer.getClassContentHeader(); @@ -145,8 +139,8 @@ buildMemberSummary(classContentTree); buildMemberDetails(classContentTree); - writer.addClassContentTree(contentTree, classContentTree); - writer.addFooter(contentTree); + writer.addClassContentTree(classContentTree); + writer.addFooter(); writer.printDocument(contentTree); copyDocFiles(); } diff -r bfc8074ea4ef -r cfe31d2f935c src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/builders/ConstantsSummaryBuilder.java --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/builders/ConstantsSummaryBuilder.java Tue Nov 26 10:22:13 2019 +0000 +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/builders/ConstantsSummaryBuilder.java Fri Nov 29 10:02:07 2019 +0000 @@ -84,11 +84,6 @@ private TypeElement currentClass; /** - * The content tree for the constant summary documentation. - */ - private Content contentTree; - - /** * True if first package is listed. */ private boolean first = true; @@ -129,31 +124,28 @@ //Doclet does not support this output. return; } - buildConstantSummary(contentTree); + buildConstantSummary(); } /** * Build the constant summary. * - * @param contentTree the content tree to which the documentation will be added * @throws DocletException if there is a problem while building the documentation */ - protected void buildConstantSummary(Content contentTree) throws DocletException { - contentTree = writer.getHeader(); + protected void buildConstantSummary() throws DocletException { + Content contentTree = writer.getHeader(); - buildContents(contentTree); - buildConstantSummaries(contentTree); + buildContents(); + buildConstantSummaries(); - writer.addFooter(contentTree); + writer.addFooter(); writer.printDocument(contentTree); } /** * Build the list of packages. - * - * @param contentTree the content tree to which the content list will be added */ - protected void buildContents(Content contentTree) { + protected void buildContents() { Content contentListTree = writer.getContentsHeader(); printedPackageHeaders.clear(); for (PackageElement pkg : configuration.packages) { @@ -161,16 +153,15 @@ writer.addLinkToPackageContent(pkg, printedPackageHeaders, contentListTree); } } - writer.addContentsList(contentTree, contentListTree); + writer.addContentsList(contentListTree); } /** * Build the summary for each documented package. * - * @param contentTree the tree to which the summaries will be added * @throws DocletException if there is a problem while building the documentation */ - protected void buildConstantSummaries(Content contentTree) throws DocletException { + protected void buildConstantSummaries() throws DocletException { printedPackageHeaders.clear(); Content summariesTree = writer.getConstantSummaries(); for (PackageElement aPackage : configuration.packages) { @@ -184,7 +175,7 @@ first = false; } } - writer.addConstantSummaries(contentTree, summariesTree); + writer.addConstantSummaries(summariesTree); } /** diff -r bfc8074ea4ef -r cfe31d2f935c src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/builders/ModuleSummaryBuilder.java --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/builders/ModuleSummaryBuilder.java Tue Nov 26 10:22:13 2019 +0000 +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/builders/ModuleSummaryBuilder.java Fri Nov 29 10:02:07 2019 +0000 @@ -56,11 +56,6 @@ private final ModuleSummaryWriter moduleWriter; /** - * The content that will be added to the module summary documentation tree. - */ - private Content contentTree; - - /** * Construct a new ModuleSummaryBuilder. * * @param context the build context. @@ -101,21 +96,20 @@ //Doclet does not support this output. return; } - buildModuleDoc(contentTree); + buildModuleDoc(); } /** * Build the module documentation. * - * @param contentTree the content tree to which the documentation will be added * @throws DocletException if there is a problem while building the documentation */ - protected void buildModuleDoc(Content contentTree) throws DocletException { - contentTree = moduleWriter.getModuleHeader(mdle.getQualifiedName().toString()); + protected void buildModuleDoc() throws DocletException { + Content contentTree = moduleWriter.getModuleHeader(mdle.getQualifiedName().toString()); - buildContent(contentTree); + buildContent(); - moduleWriter.addModuleFooter(contentTree); + moduleWriter.addModuleFooter(); moduleWriter.printDocument(contentTree); DocFilesHandler docFilesHandler = configuration.getWriterFactory().getDocFilesHandler(mdle); docFilesHandler.copyDocFiles(); @@ -124,18 +118,16 @@ /** * Build the content for the module doc. * - * @param contentTree the content tree to which the module contents - * will be added * @throws DocletException if there is a problem while building the documentation */ - protected void buildContent(Content contentTree) throws DocletException { + protected void buildContent() throws DocletException { Content moduleContentTree = moduleWriter.getContentHeader(); buildModuleDescription(moduleContentTree); buildModuleTags(moduleContentTree); buildSummary(moduleContentTree); - moduleWriter.addModuleContent(contentTree, moduleContentTree); + moduleWriter.addModuleContent(moduleContentTree); } /** diff -r bfc8074ea4ef -r cfe31d2f935c src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/builders/PackageSummaryBuilder.java --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/builders/PackageSummaryBuilder.java Tue Nov 26 10:22:13 2019 +0000 +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/builders/PackageSummaryBuilder.java Fri Nov 29 10:02:07 2019 +0000 @@ -61,11 +61,6 @@ private final PackageSummaryWriter packageWriter; /** - * The content that will be added to the package summary documentation tree. - */ - private Content contentTree; - - /** * Construct a new PackageSummaryBuilder. * * @param context the build context. @@ -107,21 +102,20 @@ //Doclet does not support this output. return; } - buildPackageDoc(contentTree); + buildPackageDoc(); } /** * Build the package documentation. * - * @param contentTree the content tree to which the documentation will be added * @throws DocletException if there is a problem while building the documentation */ - protected void buildPackageDoc(Content contentTree) throws DocletException { - contentTree = packageWriter.getPackageHeader(utils.getPackageName(packageElement)); + protected void buildPackageDoc() throws DocletException { + Content contentTree = packageWriter.getPackageHeader(utils.getPackageName(packageElement)); - buildContent(contentTree); + buildContent(); - packageWriter.addPackageFooter(contentTree); + packageWriter.addPackageFooter(); packageWriter.printDocument(contentTree); DocFilesHandler docFilesHandler = configuration .getWriterFactory() @@ -132,18 +126,16 @@ /** * Build the content for the package. * - * @param contentTree the content tree to which the package contents - * will be added * @throws DocletException if there is a problem while building the documentation */ - protected void buildContent(Content contentTree) throws DocletException { + protected void buildContent() throws DocletException { Content packageContentTree = packageWriter.getContentHeader(); buildPackageDescription(packageContentTree); buildPackageTags(packageContentTree); buildSummary(packageContentTree); - packageWriter.addPackageContent(contentTree, packageContentTree); + packageWriter.addPackageContent(packageContentTree); } /** diff -r bfc8074ea4ef -r cfe31d2f935c src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/builders/SerializedFormBuilder.java --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/builders/SerializedFormBuilder.java Tue Nov 26 10:22:13 2019 +0000 +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/builders/SerializedFormBuilder.java Fri Nov 29 10:02:07 2019 +0000 @@ -96,12 +96,6 @@ protected Element currentMember; /** - * The content that will be added to the serialized form documentation tree. - */ - private Content contentTree; - - - /** * Construct a new SerializedFormBuilder. * @param context the build context. */ @@ -137,32 +131,30 @@ //Doclet does not support this output. return; } - buildSerializedForm(contentTree); + buildSerializedForm(); } /** * Build the serialized form. * - * @param serializedTree content tree to which the documentation will be added * @throws DocletException if there is a problem while building the documentation */ - protected void buildSerializedForm(Content serializedTree) throws DocletException { - serializedTree = writer.getHeader(resources.getText( + protected void buildSerializedForm() throws DocletException { + Content contentTree = writer.getHeader(resources.getText( "doclet.Serialized_Form")); - buildSerializedFormSummaries(serializedTree); + buildSerializedFormSummaries(); - writer.addFooter(serializedTree); - writer.printDocument(serializedTree); + writer.addFooter(); + writer.printDocument(contentTree); } /** * Build the serialized form summaries. * - * @param serializedTree content tree to which the documentation will be added * @throws DocletException if there is a problem while building the documentation */ - protected void buildSerializedFormSummaries(Content serializedTree) + protected void buildSerializedFormSummaries() throws DocletException { Content serializedSummariesTree = writer.getSerializedSummariesHeader(); for (PackageElement pkg : configuration.packages) { @@ -170,8 +162,7 @@ buildPackageSerializedForm(serializedSummariesTree); } - serializedTree.add(writer.getSerializedContent( - serializedSummariesTree)); + writer.addSerializedContent(serializedSummariesTree); } /** diff -r bfc8074ea4ef -r cfe31d2f935c src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/resources/script.js --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/resources/script.js Tue Nov 26 10:22:13 2019 +0000 +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/resources/script.js Fri Nov 29 10:02:07 2019 +0000 @@ -102,9 +102,6 @@ if (!tagSearchIndex) { createElem(doc, tag, 'tag-search-index.js'); } - $(window).resize(function() { - $('.navPadding').css('padding-top', $('.fixedNav').css("height")); - }); } function createElem(doc, tag, path) { diff -r bfc8074ea4ef -r cfe31d2f935c src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/resources/stylesheet.css --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/resources/stylesheet.css Tue Nov 26 10:22:13 2019 +0000 +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/resources/stylesheet.css Fri Nov 29 10:02:07 2019 +0000 @@ -40,13 +40,6 @@ a[name] { color:#353833; } -a[name]:before, a[name]:target, a[id]:before, a[id]:target { - content:""; - display:inline-block; - position:relative; - padding-top:129px; - margin-top:-129px; -} pre { font-family:'DejaVu Sans Mono', monospace; font-size:14px; @@ -131,14 +124,19 @@ /* * Styles for navigation bar. */ -.navPadding { - padding-top: 107px; +.flexBox { + position:fixed; + display:flex; + flex-direction:column; + height: 100%; + width: 100%; } -.fixedNav { - position:fixed; - width:100%; - z-index:999; - background-color:#ffffff; +.flexHeader { + flex: 0 0 auto; +} +.flexContent { + flex: 1 1 auto; + overflow-y: auto; } .topNav { background-color:#4D7A97; @@ -632,7 +630,7 @@ background-size:12px; border:0 none; width:16px; - height:17px; + height:16px; position:relative; left:-4px; top:-4px; @@ -649,8 +647,8 @@ font-style:italic; font-size:12px; } -.searchTagResult:before, .searchTagResult:target { - color:red; +.searchTagResult:target { + background-color:yellow; } .moduleGraph span { display:none; diff -r bfc8074ea4ef -r cfe31d2f935c src/jdk.jfr/share/classes/jdk/jfr/internal/Utils.java --- a/src/jdk.jfr/share/classes/jdk/jfr/internal/Utils.java Tue Nov 26 10:22:13 2019 +0000 +++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/Utils.java Fri Nov 29 10:02:07 2019 +0000 @@ -45,6 +45,7 @@ import java.time.Duration; import java.time.Instant; import java.time.LocalDateTime; +import java.time.temporal.ChronoUnit; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; @@ -78,6 +79,17 @@ private static Boolean SAVE_GENERATED; + private static final Duration MICRO_SECOND = Duration.ofNanos(1_000); + private static final Duration SECOND = Duration.ofSeconds(1); + private static final Duration MINUTE = Duration.ofMinutes(1); + private static final Duration HOUR = Duration.ofHours(1); + private static final Duration DAY = Duration.ofDays(1); + private static final int NANO_SIGNIFICANT_FIGURES = 9; + private static final int MILL_SIGNIFICANT_FIGURES = 3; + private static final int DISPLAY_NANO_DIGIT = 3; + private static final int BASE = 10; + + public static void checkAccessFlightRecorder() throws SecurityException { SecurityManager sm = System.getSecurityManager(); if (sm != null) { @@ -597,6 +609,90 @@ return "hotspot-" + "pid-" + pid + idText + "-" + date + ".jfr"; } + public static String formatDuration(Duration d) { + Duration roundedDuration = roundDuration(d); + if (roundedDuration.equals(Duration.ZERO)) { + return "0 s"; + } else if(roundedDuration.isNegative()){ + return "-" + formatPositiveDuration(roundedDuration.abs()); + } else { + return formatPositiveDuration(roundedDuration); + } + } + + private static String formatPositiveDuration(Duration d){ + if (d.compareTo(MICRO_SECOND) < 0) { + // 0.000001 ms - 0.000999 ms + double outputMs = (double) d.toNanosPart() / 1_000_000; + return String.format("%.6f ms", outputMs); + } else if (d.compareTo(SECOND) < 0) { + // 0.001 ms - 999 ms + int valueLength = countLength(d.toNanosPart()); + int outputDigit = NANO_SIGNIFICANT_FIGURES - valueLength; + double outputMs = (double) d.toNanosPart() / 1_000_000; + return String.format("%." + outputDigit + "f ms", outputMs); + } else if (d.compareTo(MINUTE) < 0) { + // 1.00 s - 59.9 s + int valueLength = countLength(d.toSecondsPart()); + int outputDigit = MILL_SIGNIFICANT_FIGURES - valueLength; + double outputSecond = d.toSecondsPart() + (double) d.toMillisPart() / 1_000; + return String.format("%." + outputDigit + "f s", outputSecond); + } else if (d.compareTo(HOUR) < 0) { + // 1 m 0 s - 59 m 59 s + return String.format("%d m %d s", d.toMinutesPart(), d.toSecondsPart()); + } else if (d.compareTo(DAY) < 0) { + // 1 h 0 m - 23 h 59 m + return String.format("%d h %d m", d.toHoursPart(), d.toMinutesPart()); + } else { + // 1 d 0 h - + return String.format("%d d %d h", d.toDaysPart(), d.toHoursPart()); + } + } + + private static int countLength(long value){ + return (int) Math.log10(value) + 1; + } + + private static Duration roundDuration(Duration d) { + if (d.equals(Duration.ZERO)) { + return d; + } else if(d.isNegative()){ + Duration roundedPositiveDuration = roundPositiveDuration(d.abs()); + return roundedPositiveDuration.negated(); + } else { + return roundPositiveDuration(d); + } + } + + private static Duration roundPositiveDuration(Duration d){ + if (d.compareTo(MICRO_SECOND) < 0) { + // No round + return d; + } else if (d.compareTo(SECOND) < 0) { + // Round significant figures to three digits + int valueLength = countLength(d.toNanosPart()); + int roundValue = (int) Math.pow(BASE, valueLength - DISPLAY_NANO_DIGIT); + long roundedNanos = Math.round((double) d.toNanosPart() / roundValue) * roundValue; + return d.truncatedTo(ChronoUnit.SECONDS).plusNanos(roundedNanos); + } else if (d.compareTo(MINUTE) < 0) { + // Round significant figures to three digits + int valueLength = countLength(d.toSecondsPart()); + int roundValue = (int) Math.pow(BASE, valueLength); + long roundedMills = Math.round((double) d.toMillisPart() / roundValue) * roundValue; + return d.truncatedTo(ChronoUnit.SECONDS).plusMillis(roundedMills); + } else if (d.compareTo(HOUR) < 0) { + // Round for more than 500 ms or less + return d.plusMillis(SECOND.dividedBy(2).toMillisPart()).truncatedTo(ChronoUnit.SECONDS); + } else if (d.compareTo(DAY) < 0) { + // Round for more than 30 seconds or less + return d.plusSeconds(MINUTE.dividedBy(2).toSecondsPart()).truncatedTo(ChronoUnit.MINUTES); + } else { + // Round for more than 30 minutes or less + return d.plusMinutes(HOUR.dividedBy(2).toMinutesPart()).truncatedTo(ChronoUnit.HOURS); + } + } + + public static void takeNap(long millis) { try { Thread.sleep(millis); diff -r bfc8074ea4ef -r cfe31d2f935c src/jdk.jfr/share/classes/jdk/jfr/internal/consumer/AbstractEventStream.java --- a/src/jdk.jfr/share/classes/jdk/jfr/internal/consumer/AbstractEventStream.java Tue Nov 26 10:22:13 2019 +0000 +++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/consumer/AbstractEventStream.java Fri Nov 29 10:02:07 2019 +0000 @@ -48,7 +48,7 @@ * an event stream. */ abstract class AbstractEventStream implements EventStream { - private final static AtomicLong counter = new AtomicLong(1); + private final static AtomicLong counter = new AtomicLong(0); private final Object terminated = new Object(); private final Runnable flushOperation = () -> dispatcher().runFlushActions(); diff -r bfc8074ea4ef -r cfe31d2f935c src/jdk.jfr/share/classes/jdk/jfr/internal/consumer/ChunkHeader.java --- a/src/jdk.jfr/share/classes/jdk/jfr/internal/consumer/ChunkHeader.java Tue Nov 26 10:22:13 2019 +0000 +++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/consumer/ChunkHeader.java Fri Nov 29 10:02:07 2019 +0000 @@ -292,4 +292,8 @@ static long headerSize() { return HEADER_SIZE; } + + public long getLastNanos() { + return getStartNanos() + getDurationNanos(); + } } diff -r bfc8074ea4ef -r cfe31d2f935c src/jdk.jfr/share/classes/jdk/jfr/internal/consumer/ChunkParser.java --- a/src/jdk.jfr/share/classes/jdk/jfr/internal/consumer/ChunkParser.java Tue Nov 26 10:22:13 2019 +0000 +++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/consumer/ChunkParser.java Fri Nov 29 10:02:07 2019 +0000 @@ -106,6 +106,7 @@ private Runnable flushOperation; private ParserConfiguration configuration; + private volatile boolean closed; public ChunkParser(RecordingInput input) throws IOException { this(input, new ParserConfiguration()); @@ -202,7 +203,7 @@ long lastValid = absoluteChunkEnd; long metadataPoistion = chunkHeader.getMetataPosition(); long contantPosition = chunkHeader.getConstantPoolPosition(); - chunkFinished = awaitUpdatedHeader(absoluteChunkEnd); + chunkFinished = awaitUpdatedHeader(absoluteChunkEnd, configuration.filterEnd); if (chunkFinished) { Logger.log(LogTag.JFR_SYSTEM_PARSER, LogLevel.INFO, "At chunk end"); return null; @@ -279,11 +280,17 @@ } } - private boolean awaitUpdatedHeader(long absoluteChunkEnd) throws IOException { + private boolean awaitUpdatedHeader(long absoluteChunkEnd, long filterEnd) throws IOException { if (Logger.shouldLog(LogTag.JFR_SYSTEM_PARSER, LogLevel.INFO)) { Logger.log(LogTag.JFR_SYSTEM_PARSER, LogLevel.INFO, "Waiting for more data (streaming). Read so far: " + chunkHeader.getChunkSize() + " bytes"); } while (true) { + if (closed) { + return true; + } + if (chunkHeader.getLastNanos() > filterEnd) { + return true; + } chunkHeader.refresh(); if (absoluteChunkEnd != chunkHeader.getEnd()) { return false; @@ -452,4 +459,9 @@ return chunkHeader.isFinalChunk(); } + public void close() { + this.closed = true; + Utils.notifyFlush(); + } + } diff -r bfc8074ea4ef -r cfe31d2f935c src/jdk.jfr/share/classes/jdk/jfr/internal/consumer/EventDirectoryStream.java --- a/src/jdk.jfr/share/classes/jdk/jfr/internal/consumer/EventDirectoryStream.java Tue Nov 26 10:22:13 2019 +0000 +++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/consumer/EventDirectoryStream.java Fri Nov 29 10:02:07 2019 +0000 @@ -69,6 +69,9 @@ setClosed(true); dispatcher().runCloseActions(); repositoryFiles.close(); + if (currentParser != null) { + currentParser.close(); + } } @Override diff -r bfc8074ea4ef -r cfe31d2f935c src/jdk.jfr/share/classes/jdk/jfr/internal/tool/PrettyWriter.java --- a/src/jdk.jfr/share/classes/jdk/jfr/internal/tool/PrettyWriter.java Tue Nov 26 10:22:13 2019 +0000 +++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/tool/PrettyWriter.java Fri Nov 29 10:02:07 2019 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2019, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -57,9 +57,6 @@ * This class is also used by {@link RecordedObject#toString()} */ public final class PrettyWriter extends EventPrintWriter { - private static final Duration MILLSECOND = Duration.ofMillis(1); - private static final Duration SECOND = Duration.ofSeconds(1); - private static final Duration MINUTE = Duration.ofMinutes(1); private static final String TYPE_OLD_OBJECT = Type.TYPES_PREFIX + "OldObject"; private final static DateTimeFormatter TIME_FORMAT = DateTimeFormatter.ofPattern("HH:mm:ss.SSS"); private final static Long ZERO = 0L; @@ -553,15 +550,7 @@ println("N/A"); return true; } - if(d.compareTo(MILLSECOND) < 0){ - println(String.format("%.3f us", (double)d.toNanos() / 1_000)); - } else if(d.compareTo(SECOND) < 0){ - println(String.format("%.3f ms", (double)d.toNanos() / 1_000_000)); - } else if(d.compareTo(MINUTE) < 0){ - println(String.format("%.3f s", (double)d.toMillis() / 1_000)); - } else { - println(String.format("%d s", d.toSeconds())); - } + println(Utils.formatDuration(d)); return true; } if (value instanceof OffsetDateTime) { diff -r bfc8074ea4ef -r cfe31d2f935c test/hotspot/gtest/gc/g1/test_g1Predictions.cpp --- a/test/hotspot/gtest/gc/g1/test_g1Predictions.cpp Tue Nov 26 10:22:13 2019 +0000 +++ b/test/hotspot/gtest/gc/g1/test_g1Predictions.cpp Fri Nov 29 10:02:07 2019 +0000 @@ -26,6 +26,8 @@ #include "gc/g1/g1Predictions.hpp" #include "unittest.hpp" +#include "utilities/ostream.hpp" + static const double epsilon = 1e-6; // Some basic formula tests with confidence = 0.0 @@ -96,3 +98,51 @@ double p4 = predictor.get_new_prediction(&s); ASSERT_GT(p4, p3) << "Fourth prediction must be greater than third"; } + +// Some tests to verify bounding between [0 .. 1] +TEST_VM(G1Predictions, unit_predictions) { + G1Predictions predictor(0.5); + TruncatedSeq s; + + double p0 = predictor.get_new_unit_prediction(&s); + ASSERT_LT(p0, epsilon) << "Initial prediction of empty sequence must be 0.0"; + + s.add(100.0); + double p1 = predictor.get_new_unit_prediction(&s); + ASSERT_NEAR(p1, 1.0, epsilon); + + // Feed the sequence additional positive values to test the high bound. + for (int i = 0; i < 3; i++) { + s.add(2.0); + } + ASSERT_NEAR(predictor.get_new_unit_prediction(&s), 1.0, epsilon); + + // Feed the sequence additional large negative value to test the low bound. + for (int i = 0; i < 4; i++) { + s.add(-200.0); + } + ASSERT_NEAR(predictor.get_new_unit_prediction(&s), 0.0, epsilon); +} + +// Some tests to verify bounding between [0 .. +inf] +TEST_VM(G1Predictions, lower_bound_zero_predictions) { + G1Predictions predictor(0.5); + TruncatedSeq s; + + double p0 = predictor.get_new_lower_zero_bound_prediction(&s); + ASSERT_LT(p0, epsilon) << "Initial prediction of empty sequence must be 0.0"; + + s.add(100.0); + // Feed the sequence additional positive values to see that the high bound is not + // bounded by e.g. 1.0 + for (int i = 0; i < 3; i++) { + s.add(2.0); + } + ASSERT_GT(predictor.get_new_lower_zero_bound_prediction(&s), 1.0); + + // Feed the sequence additional large negative value to test the low bound. + for (int i = 0; i < 4; i++) { + s.add(-200.0); + } + ASSERT_NEAR(predictor.get_new_lower_zero_bound_prediction(&s), 0.0, epsilon); +} diff -r bfc8074ea4ef -r cfe31d2f935c test/hotspot/jtreg/compiler/escapeAnalysis/TestEliminateLocksOffCrash.java --- a/test/hotspot/jtreg/compiler/escapeAnalysis/TestEliminateLocksOffCrash.java Tue Nov 26 10:22:13 2019 +0000 +++ b/test/hotspot/jtreg/compiler/escapeAnalysis/TestEliminateLocksOffCrash.java Fri Nov 29 10:02:07 2019 +0000 @@ -25,6 +25,7 @@ * @test * @bug 8227384 * @summary C2 compilation fails with "graph should be schedulable" when running with -XX:-EliminateLocks + * @requires vm.compiler2.enabled & !vm.graal.enabled * * @run main/othervm -XX:-EliminateLocks TestEliminateLocksOffCrash */ diff -r bfc8074ea4ef -r cfe31d2f935c test/hotspot/jtreg/compiler/loopopts/LoopRotateBadNodeBudget.java --- a/test/hotspot/jtreg/compiler/loopopts/LoopRotateBadNodeBudget.java Tue Nov 26 10:22:13 2019 +0000 +++ b/test/hotspot/jtreg/compiler/loopopts/LoopRotateBadNodeBudget.java Fri Nov 29 10:02:07 2019 +0000 @@ -27,7 +27,7 @@ * @summary Node estimate for loop rotate is not correct/sufficient: * assert(delta <= 2 * required) failed: Bad node estimate ... * - * @requires !vm.graal.enabled + * @requires vm.compiler2.enabled & !vm.graal.enabled * * @run main/othervm -XX:PartialPeelNewPhiDelta=5 LoopRotateBadNodeBudget * @run main/othervm -Xbatch -XX:PartialPeelNewPhiDelta=5 LoopRotateBadNodeBudget diff -r bfc8074ea4ef -r cfe31d2f935c test/hotspot/jtreg/gc/shenandoah/options/TestClassUnloadingArguments.java --- a/test/hotspot/jtreg/gc/shenandoah/options/TestClassUnloadingArguments.java Tue Nov 26 10:22:13 2019 +0000 +++ b/test/hotspot/jtreg/gc/shenandoah/options/TestClassUnloadingArguments.java Fri Nov 29 10:02:07 2019 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, Red Hat, Inc. All rights reserved. + * Copyright (c) 2018, 2019, Red Hat, Inc. All rights reserved. * * 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 @@ -81,7 +81,7 @@ public static void testShenandoah() throws Exception { testWith("Shenandoah GC should have class unloading enabled", - true, false, + true, true, "-XX:+UnlockExperimentalVMOptions", "-XX:+UseShenandoahGC"); diff -r bfc8074ea4ef -r cfe31d2f935c test/hotspot/jtreg/gc/startup_warnings/TestParallelScavengeSerialOld.java --- a/test/hotspot/jtreg/gc/startup_warnings/TestParallelScavengeSerialOld.java Tue Nov 26 10:22:13 2019 +0000 +++ b/test/hotspot/jtreg/gc/startup_warnings/TestParallelScavengeSerialOld.java Fri Nov 29 10:02:07 2019 +0000 @@ -28,7 +28,7 @@ * @key gc * @bug 8006398 * @requires vm.gc.Parallel -* @summary Test that the ParallelScavenge+SerialOld combination does not print a warning message +* @summary Test that the ParallelScavenge+SerialOld combination prints a deprecation message * @library /test/lib * @modules java.base/jdk.internal.misc * java.management @@ -44,7 +44,7 @@ public static void main(String args[]) throws Exception { ProcessBuilder pb = ProcessTools.createJavaProcessBuilder("-XX:+UseParallelGC", "-XX:-UseParallelOldGC", "-version"); OutputAnalyzer output = new OutputAnalyzer(pb.start()); - output.shouldNotContain("deprecated"); + output.shouldContain("deprecated"); output.shouldNotContain("error"); output.shouldHaveExitValue(0); } diff -r bfc8074ea4ef -r cfe31d2f935c test/hotspot/jtreg/gc/z/TestSmallHeap.java --- a/test/hotspot/jtreg/gc/z/TestSmallHeap.java Tue Nov 26 10:22:13 2019 +0000 +++ b/test/hotspot/jtreg/gc/z/TestSmallHeap.java Fri Nov 29 10:02:07 2019 +0000 @@ -25,7 +25,7 @@ /* * @test TestSmallHeap - * @requires vm.gc.Z & !vm.graal.enabled + * @requires vm.gc.Z & !vm.graal.enabled & vm.compMode != "Xcomp" * @summary Test ZGC with small heaps * @run main/othervm -XX:+UnlockExperimentalVMOptions -XX:+UseZGC -Xlog:gc,gc+init,gc+heap -Xmx8M gc.z.TestSmallHeap * @run main/othervm -XX:+UnlockExperimentalVMOptions -XX:+UseZGC -Xlog:gc,gc+init,gc+heap -Xmx16M gc.z.TestSmallHeap diff -r bfc8074ea4ef -r cfe31d2f935c test/hotspot/jtreg/runtime/CommandLine/VMDeprecatedOptions.java --- a/test/hotspot/jtreg/runtime/CommandLine/VMDeprecatedOptions.java Tue Nov 26 10:22:13 2019 +0000 +++ b/test/hotspot/jtreg/runtime/CommandLine/VMDeprecatedOptions.java Fri Nov 29 10:02:07 2019 +0000 @@ -48,6 +48,7 @@ {"AllowRedefinitionToAddDeleteMethods", "true"}, {"CompactFields", "true"}, {"FieldsAllocationStyle", "1"}, + {"UseParallelOldGC", "false"}, // deprecated alias flags (see also aliased_jvm_flags): {"DefaultMaxRAMFraction", "4"}, diff -r bfc8074ea4ef -r cfe31d2f935c test/hotspot/jtreg/runtime/NMT/HugeArenaTracking.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/hotspot/jtreg/runtime/NMT/HugeArenaTracking.java Fri Nov 29 10:02:07 2019 +0000 @@ -0,0 +1,87 @@ +/* + * Copyright (c) 2019, Red Hat, Inc. All rights reserved. + * + * 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 + * @key nmt jcmd + * @library /test/lib + * @modules java.base/jdk.internal.misc + * java.management + * @build sun.hotspot.WhiteBox + * @run driver ClassFileInstaller sun.hotspot.WhiteBox + * sun.hotspot.WhiteBox$WhiteBoxPermission + * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -XX:NativeMemoryTracking=detail HugeArenaTracking + */ + +import java.util.Random; +import jdk.test.lib.process.ProcessTools; +import jdk.test.lib.process.OutputAnalyzer; +import jdk.test.lib.JDKToolFinder; +import sun.hotspot.WhiteBox; + +public class HugeArenaTracking { + private static final long GB = 1024 * 1024 * 1024; + + public static void main(String args[]) throws Exception { + OutputAnalyzer output; + final WhiteBox wb = WhiteBox.getWhiteBox(); + + // Grab my own PID + String pid = Long.toString(ProcessTools.getProcessId()); + ProcessBuilder pb = new ProcessBuilder(); + + long arena1 = wb.NMTNewArena(1024); + long arena2 = wb.NMTNewArena(1024); + + // Run 'jcmd VM.native_memory summary' + pb.command(new String[] { JDKToolFinder.getJDKTool("jcmd"), pid, "VM.native_memory", "summary"}); + output = new OutputAnalyzer(pb.start()); + output.shouldContain("Test (reserved=2KB, committed=2KB)"); + + Random rand = new Random(); + + // Allocate 2GB+ from arena + long total = 0; + while (total < 2 * GB) { + // Cap to 10M + long inc = rand.nextInt(10 * 1024 * 1024); + wb.NMTArenaMalloc(arena1, inc); + total += inc; + } + + ProcessBuilder pb2 = new ProcessBuilder(); + // Run 'jcmd VM.native_memory summary' + pb2.command(new String[] { JDKToolFinder.getJDKTool("jcmd"), pid, "VM.native_memory", "summary", "scale=GB"}); + output = new OutputAnalyzer(pb2.start()); + output.shouldContain("Test (reserved=2GB, committed=2GB)"); + + wb.NMTFreeArena(arena1); + + output = new OutputAnalyzer(pb.start()); + output.shouldContain("Test (reserved=1KB, committed=1KB)"); + wb.NMTFreeArena(arena2); + + output = new OutputAnalyzer(pb.start()); + output.shouldNotContain("Test (reserved"); + } +} diff -r bfc8074ea4ef -r cfe31d2f935c test/hotspot/jtreg/serviceability/sa/ClhsdbCDSCore.java --- a/test/hotspot/jtreg/serviceability/sa/ClhsdbCDSCore.java Tue Nov 26 10:22:13 2019 +0000 +++ b/test/hotspot/jtreg/serviceability/sa/ClhsdbCDSCore.java Fri Nov 29 10:02:07 2019 +0000 @@ -111,8 +111,20 @@ if (coreFileLocation == null) { if (Platform.isOSX()) { File coresDir = new File("/cores"); - if (!coresDir.isDirectory() || !coresDir.canWrite()) { - throw new Error("cores is not a directory or does not have write permissions"); + if (!coresDir.isDirectory()) { + throw new Error("cores is not a directory"); + } + // the /cores directory is usually not writable on macOS 10.15 + final String osVersion = System.getProperty("os.version"); + if (osVersion == null) { + throw new Error("Cannot query the 'os.version' property!"); + } + if (!coresDir.canWrite()) { + if (osVersion.startsWith("10.15")) { + throw new SkippedException("/cores is not writable"); + } else { + throw new Error("cores does not have write permissions"); + } } } else if (Platform.isLinux()) { // Check if a crash report tool is installed. diff -r bfc8074ea4ef -r cfe31d2f935c test/jdk/com/sun/net/httpserver/HttpServerTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/jdk/com/sun/net/httpserver/HttpServerTest.java Fri Nov 29 10:02:07 2019 +0000 @@ -0,0 +1,101 @@ +/* + * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/** + * @test + * @bug 8233185 + * @summary HttpServer.stop() blocks indefinitely when called on dispatch thread + * @modules java.base/sun.net.www + * @library /test/lib + * @run main/othervm HttpServerTest + */ + +import java.io.IOException; +import java.io.InputStream; +import java.net.HttpURLConnection; +import java.net.InetAddress; +import java.net.InetSocketAddress; +import java.net.Proxy; +import java.net.URL; +import java.util.concurrent.CountDownLatch; + +import com.sun.net.httpserver.HttpExchange; +import com.sun.net.httpserver.HttpHandler; +import com.sun.net.httpserver.HttpServer; +import jdk.test.lib.net.URIBuilder; + +public class HttpServerTest implements HttpHandler { + private static final int HTTP_STATUS_CODE_OK = 200; + private static CountDownLatch serverStopped = new CountDownLatch(1); + private final HttpServer server; + + + public HttpServerTest(HttpServer server) { + this.server = server; + } + + @Override + public void handle(HttpExchange ex) throws IOException { + + sendHttpStatusCode(HTTP_STATUS_CODE_OK, ex); + + System.out.println("Stopping server ..."); + server.stop(1); + serverStopped.countDown(); + } + + private void sendHttpStatusCode(int httpCode, HttpExchange ex) { + try { + ex.sendResponseHeaders(httpCode, 0); + ex.close(); + } catch (IOException e) { + throw new RuntimeException("Server couldn't send response: " + e, e); + } + } + + public static void main(String[] args) throws IOException, InterruptedException { + HttpServer server = HttpServer.create( + new InetSocketAddress(InetAddress.getLoopbackAddress(), 0), 0); + + try { + server.createContext("/context", new HttpServerTest(server)); + server.start(); + + URL url = URIBuilder.newBuilder() + .scheme("http") + .loopback() + .port(server.getAddress().getPort()) + .path("/context") + .toURLUnchecked(); + + HttpURLConnection urlc = (HttpURLConnection) url.openConnection(Proxy.NO_PROXY); + System.out.println("Client: Response code received: " + urlc.getResponseCode()); + InputStream is = urlc.getInputStream(); + is.readAllBytes(); + is.close(); + } finally { + serverStopped.await(); + System.out.println("Server stopped as expected"); + } + } +} diff -r bfc8074ea4ef -r cfe31d2f935c test/jdk/java/lang/invoke/CallSiteTest.java --- a/test/jdk/java/lang/invoke/CallSiteTest.java Tue Nov 26 10:22:13 2019 +0000 +++ b/test/jdk/java/lang/invoke/CallSiteTest.java Fri Nov 29 10:02:07 2019 +0000 @@ -24,10 +24,11 @@ /** * @test * @summary smoke tests for CallSite + * @library /test/lib * * @build indify.Indify * @compile CallSiteTest.java - * @run main/othervm/timeout=3600 -XX:+IgnoreUnrecognizedVMOptions -XX:-VerifyDependencies + * @run main/othervm/timeout=3600 -XX:+IgnoreUnrecognizedVMOptions -XX:-VerifyDependencies -Xbatch * indify.Indify * --expand-properties --classpath ${test.classes} * --java test.java.lang.invoke.CallSiteTest @@ -40,6 +41,7 @@ import java.lang.invoke.*; import static java.lang.invoke.MethodHandles.*; import static java.lang.invoke.MethodType.*; +import static jdk.test.lib.Asserts.*; public class CallSiteTest { private static final Class CLASS = CallSiteTest.class; @@ -51,16 +53,19 @@ static { try { + mh_foo = lookup().findStatic(CLASS, "foo", methodType(int.class, int.class, int.class)); mh_bar = lookup().findStatic(CLASS, "bar", methodType(int.class, int.class, int.class)); mcs = new MutableCallSite(mh_foo); vcs = new VolatileCallSite(mh_foo); } catch (Exception e) { e.printStackTrace(); + throw new Error(e); } } public static void main(String... av) throws Throwable { + testConstantCallSite(); testMutableCallSite(); testVolatileCallSite(); } @@ -69,9 +74,61 @@ private static final int RESULT1 = 762786192; private static final int RESULT2 = -21474836; - private static void assertEquals(int expected, int actual) { - if (expected != actual) - throw new AssertionError("expected: " + expected + ", actual: " + actual); + static final CallSite MCS = new MutableCallSite(methodType(void.class)); + static final MethodHandle MCS_INVOKER = MCS.dynamicInvoker(); + + static void test(boolean shouldThrow) { + try { + MCS_INVOKER.invokeExact(); + if (shouldThrow) { + throw new AssertionError("should throw"); + } + } catch (IllegalStateException ise) { + if (!shouldThrow) { + throw new AssertionError("should not throw", ise); + } + } catch (Throwable e) { + throw new Error(e); + } + } + + static class MyCCS extends ConstantCallSite { + public MyCCS(MethodType targetType, MethodHandle createTargetHook) throws Throwable { + super(targetType, createTargetHook); + } + } + + private static MethodHandle testConstantCallSiteHandler(CallSite cs, CallSite[] holder) throws Throwable { + holder[0] = cs; // capture call site instance for subsequent checks + + MethodType csType = cs.type(); // should not throw on partially constructed instance + + // Truly dynamic invoker for constant call site + MethodHandle getTarget = lookup().findVirtual(CallSite.class, "getTarget", MethodType.methodType(MethodHandle.class)) + .bindTo(cs); + MethodHandle invoker = MethodHandles.exactInvoker(csType); + MethodHandle target = MethodHandles.foldArguments(invoker, getTarget); + + MCS.setTarget(target); + // warmup + for (int i = 0; i < 20_000; i++) { + test(true); // should throw IllegalStateException + } + + return MethodHandles.empty(csType); // initialize cs with an empty method handle + } + + private static void testConstantCallSite() throws Throwable { + CallSite[] holder = new CallSite[1]; + MethodHandle handler = lookup().findStatic(CLASS, "testConstantCallSiteHandler", MethodType.methodType(MethodHandle.class, CallSite.class, CallSite[].class)); + handler = MethodHandles.insertArguments(handler, 1, new Object[] { holder } ); + + CallSite ccs = new MyCCS(MCS.type(), handler); // trigger call to handler + + if (ccs != holder[0]) { + throw new AssertionError("different call site instances"); + } + test(false); // should not throw } private static void testMutableCallSite() throws Throwable { @@ -83,11 +140,11 @@ for (int n = 0; n < 2; n++) { mcs.setTarget(mh_foo); for (int i = 0; i < 5; i++) { - assertEquals(RESULT1, runMutableCallSite()); + assertEQ(RESULT1, runMutableCallSite()); } mcs.setTarget(mh_bar); for (int i = 0; i < 5; i++) { - assertEquals(RESULT2, runMutableCallSite()); + assertEQ(RESULT2, runMutableCallSite()); } } } @@ -100,11 +157,11 @@ for (int n = 0; n < 2; n++) { vcs.setTarget(mh_foo); for (int i = 0; i < 5; i++) { - assertEquals(RESULT1, runVolatileCallSite()); + assertEQ(RESULT1, runVolatileCallSite()); } vcs.setTarget(mh_bar); for (int i = 0; i < 5; i++) { - assertEquals(RESULT2, runVolatileCallSite()); + assertEQ(RESULT2, runVolatileCallSite()); } } } diff -r bfc8074ea4ef -r cfe31d2f935c test/jdk/java/net/DatagramSocket/InterruptibleDatagramSocket.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/jdk/java/net/DatagramSocket/InterruptibleDatagramSocket.java Fri Nov 29 10:02:07 2019 +0000 @@ -0,0 +1,106 @@ +/* + * Copyright (c) 2019 Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.net.DatagramPacket; +import java.net.DatagramSocket; +import java.net.MulticastSocket; +import java.net.SocketException; +import java.net.SocketTimeoutException; +import java.nio.channels.ClosedByInterruptException; +import java.nio.channels.DatagramChannel; +import java.util.concurrent.CountDownLatch; + +import static java.lang.Thread.sleep; + +/* + * @test + * @summary Check interrupt mechanism for DatagramSocket, + * MulticastSocket, and DatagramSocketAdaptor + */ + +public class InterruptibleDatagramSocket { + private static void test0(DatagramSocket s) throws Exception { + CountDownLatch latch = new CountDownLatch(1); + Thread testThread = Thread.currentThread(); + + Thread coordinator = new Thread(() -> { + try { + latch.await(); + sleep(500); + testThread.interrupt(); + } catch (InterruptedException e) { + } + }); + byte[] data = {0, 1, 2}; + DatagramPacket p = new DatagramPacket(data, data.length, + s.getLocalAddress(), s.getLocalPort()); + s.setSoTimeout(2000); + coordinator.start(); + latch.countDown(); + try { + s.receive(p); + } finally { + try { + coordinator.join(); + } catch (InterruptedException e) { + } + } + } + + static void test(DatagramSocket s, boolean interruptible) throws Exception { + try { + test0(s); + throw new RuntimeException("Receive shouldn't have succeeded"); + } catch (SocketTimeoutException e) { + if (interruptible) + throw e; + System.out.println("Got expected SocketTimeoutException: " + e); + } catch (SocketException e) { + if ((e.getCause() instanceof ClosedByInterruptException) && interruptible) { + System.out.println("Got expected ClosedByInterruptException: " + e); + } else { + throw e; + } + } catch (ClosedByInterruptException e) { + if (!interruptible) + throw e; + System.out.println("Got expected ClosedByInterruptException: " + e); + } + if (s.isClosed() && !interruptible) + throw new RuntimeException("DatagramSocket should not be closed"); + else if (!s.isClosed() && interruptible) + throw new RuntimeException("DatagramSocket should be closed"); + } + + public static void main(String[] args) throws Exception { + try (DatagramSocket s = new DatagramSocket()) { + test(s, false); + } + try (DatagramSocket s = new MulticastSocket()) { + test(s, false); + } + try (DatagramSocket s = DatagramChannel.open().socket()) { + test(s, true); + } + } +} diff -r bfc8074ea4ef -r cfe31d2f935c test/jdk/java/net/NetworkInterface/NoSetNetworkInterface.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/jdk/java/net/NetworkInterface/NoSetNetworkInterface.java Fri Nov 29 10:02:07 2019 +0000 @@ -0,0 +1,147 @@ +/* + * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 8233307 + * @library /test/lib + * @run main/othervm NoSetNetworkInterface + * @run main/othervm -Djava.net.preferIPv4Stack=true NoSetNetworkInterface + * @run main/othervm -Djava.net.preferIPv6Addresses=true NoSetNetworkInterface + * @summary Check that methods that are used to set and get the NetworkInterface + * for a MulticastSocket work as expected. This test also checks that getOption + * returns null correctly when a NetworkInterface has not been set + */ + +import jdk.test.lib.NetworkConfiguration; + +import java.io.IOException; +import java.io.UncheckedIOException; +import java.net.InetAddress; +import java.net.MulticastSocket; +import java.net.NetworkInterface; +import java.net.StandardSocketOptions; +import java.util.Optional; +import java.util.function.Predicate; + +public class NoSetNetworkInterface { + public static void main(String[] args) throws Exception { + + NetworkConfiguration nc = NetworkConfiguration.probe(); + + // check set and get methods work as expected + nc.multicastInterfaces(true).forEach(ni -> { + checkSetInterface(ni); + checkSetNetworkInterface(ni); + checkSetOption(ni); + }); + + // Check that dummy NetworkInterface is returned when not set + checkDummyNetworkInterface(); + } + + public static void checkSetInterface(NetworkInterface ni) { + try (MulticastSocket ms = new MulticastSocket()) { + Optional iAddr = ni.inetAddresses() + .filter(Predicate.not(InetAddress::isAnyLocalAddress)) + .findFirst(); + if (iAddr.isPresent()) { + ms.setInterface(iAddr.get()); + checkForCorrectNetworkInterface("setInterface", ms, ni); + } + } catch (IOException e) { + throw new UncheckedIOException(e); + } + } + + public static void checkSetNetworkInterface(NetworkInterface ni) { + try (MulticastSocket ms = new MulticastSocket()) { + ms.setNetworkInterface(ni); + checkForCorrectNetworkInterface("setNetworkInterface", ms, ni); + } catch (IOException e) { + throw new UncheckedIOException(e); + } + } + + public static void checkSetOption(NetworkInterface ni) { + try (MulticastSocket ms = new MulticastSocket()) { + ms.setOption(StandardSocketOptions.IP_MULTICAST_IF, ni); + checkForCorrectNetworkInterface("setOption", ms, ni); + } catch (IOException e) { + throw new UncheckedIOException(e); + } + } + + public static void checkForCorrectNetworkInterface(String setterMethod, + MulticastSocket ms, + NetworkInterface ni) throws IOException { + + // getInterface + InetAddress testAddr = ms.getInterface(); + if (!ni.inetAddresses().anyMatch(i -> i.equals(testAddr))) { + throw new RuntimeException(setterMethod + " != getInterface"); + } + + // getNetworkInterface + if (!ni.equals(ms.getNetworkInterface())) { + throw new RuntimeException(setterMethod + " != getNetworkInterface"); + } + + // getOption + if (!ni.equals(ms.getOption(StandardSocketOptions.IP_MULTICAST_IF))) { + throw new RuntimeException(setterMethod + " != getOption"); + } + } + + public static void checkDummyNetworkInterface() throws IOException { + + try(MulticastSocket ms = new MulticastSocket()) { + + // getOption with no Network Interface set + NetworkInterface n0 = ms.getOption(StandardSocketOptions.IP_MULTICAST_IF); + if (n0 != null) { + throw new RuntimeException("NetworkInterface should be null"); + } + + // getNetworkInterface with no Network Interface set + NetworkInterface n1 = ms.getNetworkInterface(); + if (n1 == null) { + throw new RuntimeException("getNetworkInterface() should not return null"); + } else if (!((n1.getName().equals("0.0.0.0") || n1.getName().equals("::")) + && (n1.getIndex() == 0) + && (n1.inetAddresses().count() == 1))) { + + throw new RuntimeException("Dummy NetworkInterface not returned as expected"); + } + + // getInterface with no Network Interface set + InetAddress iaddr = ms.getInterface(); + if (iaddr == null) { + throw new RuntimeException("getInterface() should not return null"); + } else if (!iaddr.isAnyLocalAddress()) { + throw new RuntimeException("getInterface() should return anyLocalAddress"); + } + } + } +} + diff -r bfc8074ea4ef -r cfe31d2f935c test/jdk/java/nio/channels/spi/SelectorProvider/inheritedChannel/Launcher.java --- a/test/jdk/java/nio/channels/spi/SelectorProvider/inheritedChannel/Launcher.java Tue Nov 26 10:22:13 2019 +0000 +++ b/test/jdk/java/nio/channels/spi/SelectorProvider/inheritedChannel/Launcher.java Fri Nov 29 10:02:07 2019 +0000 @@ -1,3 +1,4 @@ + /* * Copyright (c) 2003, 2019, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. @@ -91,7 +92,7 @@ */ public static SocketChannel launchWithSocketChannel(String className, String options[], String args[]) throws IOException { ServerSocketChannel ssc = ServerSocketChannel.open(); - ssc.socket().bind(new InetSocketAddress(0)); + ssc.socket().bind(new InetSocketAddress(InetAddress.getLocalHost(), 0)); InetSocketAddress isa = new InetSocketAddress(InetAddress.getLocalHost(), ssc.socket().getLocalPort()); SocketChannel sc1 = SocketChannel.open(isa); @@ -120,7 +121,7 @@ throws IOException { ServerSocketChannel ssc = ServerSocketChannel.open(); - ssc.socket().bind(new InetSocketAddress(0)); + ssc.socket().bind(new InetSocketAddress(InetAddress.getLocalHost(), 0)); int port = ssc.socket().getLocalPort(); launch(className, options, args, Util.getFD(ssc)); ssc.close(); @@ -147,18 +148,18 @@ public static DatagramChannel launchWithDatagramChannel(String className, String options[], String args[]) throws IOException { + InetAddress address = InetAddress.getLocalHost(); + if (address.isLoopbackAddress()) { + address = InetAddress.getLoopbackAddress(); + } DatagramChannel dc = DatagramChannel.open(); - dc.socket().bind(new InetSocketAddress(0)); + dc.socket().bind(new InetSocketAddress(address, 0)); int port = dc.socket().getLocalPort(); launch(className, options, args, Util.getFD(dc)); dc.close(); dc = DatagramChannel.open(); - InetAddress address = InetAddress.getLocalHost(); - if (address.isLoopbackAddress()) { - address = InetAddress.getLoopbackAddress(); - } InetSocketAddress isa = new InetSocketAddress(address, port); dc.connect(isa); diff -r bfc8074ea4ef -r cfe31d2f935c test/jdk/java/nio/channels/spi/SelectorProvider/inheritedChannel/StateTest.java --- a/test/jdk/java/nio/channels/spi/SelectorProvider/inheritedChannel/StateTest.java Tue Nov 26 10:22:13 2019 +0000 +++ b/test/jdk/java/nio/channels/spi/SelectorProvider/inheritedChannel/StateTest.java Fri Nov 29 10:02:07 2019 +0000 @@ -35,6 +35,7 @@ */ import java.io.IOException; import java.net.InetSocketAddress; +import java.net.InetAddress; import java.nio.ByteBuffer; import java.nio.channels.DatagramChannel; import java.nio.channels.SelectionKey; @@ -66,6 +67,7 @@ /* * Wait for service to connect */ + System.err.println("Waiting for the service to connect"); ssc.configureBlocking(false); sk = ssc.register(sel, SelectionKey.OP_ACCEPT); long to = Utils.adjustTimeout(15*1000); @@ -89,6 +91,7 @@ /* * Wait for service to report test result */ + System.err.println("Waiting for the service to report test result"); sc.configureBlocking(false); sk = sc.register(sel, SelectionKey.OP_READ); to = Utils.adjustTimeout(5000); @@ -111,6 +114,7 @@ throw new IOException("Timed out waiting for service to report test result"); } } + System.err.println("Cleaning up"); sk.cancel(); sc.close(); sel.close(); @@ -118,6 +122,7 @@ /* * Examine the test result */ + System.err.println("Examine test result"); bb.flip(); byte b = bb.get(); @@ -152,7 +157,8 @@ * from the service. */ ServerSocketChannel ssc = ServerSocketChannel.open(); - ssc.socket().bind(new InetSocketAddress(0)); + ssc.socket().bind(new InetSocketAddress(InetAddress.getLocalHost(), 0)); + System.err.println("Listener bound to: " + ssc.socket().getLocalSocketAddress()); /* * The port is passed to the service as an argument. @@ -164,7 +170,9 @@ /* * Launch service with a SocketChannel (tcp nowait) */ + System.err.println("launchWithSocketChannel"); SocketChannel sc = Launcher.launchWithSocketChannel(TEST_SERVICE, options, arg); + System.err.println("Waiting for test results"); waitForTestResult(ssc, expectFail); sc.close(); @@ -173,6 +181,7 @@ * launchWithServerSocketChannel establishes a connection to the service * and the returned SocketChannel is connected to the service. */ + System.err.println("launchWithServerSocketChannel"); sc = Launcher.launchWithServerSocketChannel(TEST_SERVICE, options, arg); waitForTestResult(ssc, expectFail); sc.close(); @@ -180,10 +189,12 @@ /* * Launch service with a DatagramChannel (udp wait) */ + System.err.println("launchWithDatagramChannel"); DatagramChannel dc = Launcher.launchWithDatagramChannel(TEST_SERVICE, options, arg); waitForTestResult(ssc, expectFail); dc.close(); + System.err.println("done"); if (failures > 0) { throw new RuntimeException("Test failed - see log for details"); } else { diff -r bfc8074ea4ef -r cfe31d2f935c test/jdk/javax/net/ssl/TLS/TLSClientPropertyTest.java --- a/test/jdk/javax/net/ssl/TLS/TLSClientPropertyTest.java Tue Nov 26 10:22:13 2019 +0000 +++ b/test/jdk/javax/net/ssl/TLS/TLSClientPropertyTest.java Fri Nov 29 10:02:07 2019 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2019, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -23,7 +23,7 @@ /* * @test - * @bug 8049432 8069038 + * @bug 8049432 8069038 8234723 * @summary New tests for TLS property jdk.tls.client.protocols * @summary javax/net/ssl/TLS/TLSClientPropertyTest.java needs to be * updated for JDK-8061210 @@ -40,6 +40,8 @@ * @run main/othervm TLSClientPropertyTest TLSv1 * @run main/othervm TLSClientPropertyTest TLSv11 * @run main/othervm TLSClientPropertyTest TLSv12 + * @run main/othervm TLSClientPropertyTest TLSv13 + * @run main/othervm TLSClientPropertyTest TLS * @run main/othervm TLSClientPropertyTest WrongProperty */ @@ -57,7 +59,7 @@ */ public class TLSClientPropertyTest { private final String[] expectedSupportedProtos = new String[] { - "SSLv2Hello", "SSLv3", "TLSv1", "TLSv1.1", "TLSv1.2" + "SSLv2Hello", "SSLv3", "TLSv1", "TLSv1.1", "TLSv1.2", "TLSv1.3" }; public static void main(String[] args) throws Exception { @@ -77,7 +79,7 @@ } contextProtocol = null; expectedDefaultProtos = new String[] { - "TLSv1", "TLSv1.1", "TLSv1.2" + "TLSv1", "TLSv1.1", "TLSv1.2", "TLSv1.3" }; break; case "SSLv3": @@ -103,6 +105,13 @@ "TLSv1", "TLSv1.1", "TLSv1.2" }; break; + case "TLSv13": + case "TLS": + contextProtocol = "TLSv1.3"; + expectedDefaultProtos = new String[] { + "TLSv1", "TLSv1.1", "TLSv1.2", "TLSv1.3" + }; + break; case "WrongProperty": expectedDefaultProtos = new String[] {}; contextProtocol = "TLSV"; diff -r bfc8074ea4ef -r cfe31d2f935c test/jdk/javax/net/ssl/TLS/TestJSSEClientDefaultProtocol.java --- a/test/jdk/javax/net/ssl/TLS/TestJSSEClientDefaultProtocol.java Tue Nov 26 10:22:13 2019 +0000 +++ b/test/jdk/javax/net/ssl/TLS/TestJSSEClientDefaultProtocol.java Fri Nov 29 10:02:07 2019 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2019, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -23,7 +23,7 @@ /* * @test - * @bug 8049429 + * @bug 8049429 8234723 * @modules java.management * jdk.crypto.ec/sun.security.ec * @summary Test that all cipher suites work in all versions and all client @@ -33,23 +33,35 @@ * @run main/othervm * -DSERVER_PROTOCOL=SSLv2Hello,SSLv3,TLSv1 * -DCLIENT_PROTOCOL=DEFAULT - * -DCIPHER=SSL_RSA_WITH_RC4_128_MD5 + * -DCIPHER=TLS_RSA_WITH_AES_128_CBC_SHA * TestJSSE * @run main/othervm * -DSERVER_PROTOCOL=SSLv2Hello,SSLv3,TLSv1,TLSv1.1,TLSv1.2 * -DCLIENT_PROTOCOL=DEFAULT - * -DCIPHER=SSL_RSA_WITH_RC4_128_MD5 + * -DCIPHER=TLS_RSA_WITH_AES_128_GCM_SHA256 * TestJSSE * @run main/othervm * -DSERVER_PROTOCOL=SSLv2Hello,SSLv3,TLSv1,TLSv1.1,TLSv1.2 * -DCLIENT_PROTOCOL=DEFAULT * -Djdk.tls.client.protocols=TLSv1 - * -DCIPHER=SSL_RSA_WITH_RC4_128_MD5 + * -DCIPHER=TLS_RSA_WITH_AES_128_CBC_SHA * TestJSSE * @run main/othervm * -DSERVER_PROTOCOL=SSLv2Hello,SSLv3,TLSv1 * -DCLIENT_PROTOCOL=DEFAULT * -Djdk.tls.client.protocols=TLSv1.2 - * -DCIPHER=SSL_RSA_WITH_RC4_128_MD5 + * -DCIPHER=TLS_RSA_WITH_AES_128_GCM_SHA256 + * TestJSSE javax.net.ssl.SSLHandshakeException + * @run main/othervm + * -DSERVER_PROTOCOL=SSLv2Hello,SSLv3,TLSv1,TLSv1.1,TLSv1.2,TLSv1.3 + * -DCLIENT_PROTOCOL=DEFAULT + * -Djdk.tls.client.protocols=TLSv1.3 + * -DCIPHER=TLS_AES_256_GCM_SHA384 + * TestJSSE + * @run main/othervm + * -DSERVER_PROTOCOL=SSLv2Hello,SSLv3,TLSv1 + * -DCLIENT_PROTOCOL=DEFAULT + * -Djdk.tls.client.protocols=TLSv1.3 + * -DCIPHER=TLS_AES_256_GCM_SHA384 * TestJSSE javax.net.ssl.SSLHandshakeException */ diff -r bfc8074ea4ef -r cfe31d2f935c test/jdk/javax/net/ssl/TLS/TestJSSEClientProtocol.java --- a/test/jdk/javax/net/ssl/TLS/TestJSSEClientProtocol.java Tue Nov 26 10:22:13 2019 +0000 +++ b/test/jdk/javax/net/ssl/TLS/TestJSSEClientProtocol.java Fri Nov 29 10:02:07 2019 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2019, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -23,7 +23,7 @@ /* * @test - * @bug 8049429 8172273 + * @bug 8049429 8172273 8234723 * @modules java.management * jdk.crypto.ec/sun.security.ec * @summary Test that all cipher suites work in all versions and all client @@ -31,21 +31,26 @@ * and all checking is done on the client side. * @compile CipherTestUtils.java JSSEClient.java JSSEServer.java * @run main/othervm - * -DSERVER_PROTOCOL=SSLv2Hello,SSLv3,TLSv1,TLSv1.1,TLSv1.2 - * -DCLIENT_PROTOCOL=SSLv2Hello,SSLv3,TLSv1,TLSv1.1,TLSv1.2 + * -DSERVER_PROTOCOL=SSLv2Hello,SSLv3,TLSv1,TLSv1.1,TLSv1.2,TLSv1.3 + * -DCLIENT_PROTOCOL=SSLv2Hello,SSLv3,TLSv1,TLSv1.1,TLSv1.2,TLSv1.3 * -DCIPHER=SSL_RSA_WITH_RC4_128_MD5 * TestJSSE * @run main/othervm - * -DSERVER_PROTOCOL=SSLv2Hello,SSLv3,TLSv1,TLSv1.1,TLSv1.2 - * -DCLIENT_PROTOCOL=SSLv2Hello,SSLv3,TLSv1,TLSv1.1,TLSv1.2 + * -DSERVER_PROTOCOL=SSLv2Hello,SSLv3,TLSv1,TLSv1.1,TLSv1.2,TLSv1.3 + * -DCLIENT_PROTOCOL=SSLv2Hello,SSLv3,TLSv1,TLSv1.1,TLSv1.2,TLSv1.3 * -DCIPHER=TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256 * TestJSSE * @run main/othervm - * -DSERVER_PROTOCOL=SSLv2Hello,SSLv3,TLSv1,TLSv1.1,TLSv1.2 - * -DCLIENT_PROTOCOL=SSLv2Hello,SSLv3,TLSv1,TLSv1.1,TLSv1.2 + * -DSERVER_PROTOCOL=SSLv2Hello,SSLv3,TLSv1,TLSv1.1,TLSv1.2,TLSv1.3 + * -DCLIENT_PROTOCOL=SSLv2Hello,SSLv3,TLSv1,TLSv1.1,TLSv1.2,TLSv1.3 * -DCIPHER=TLS_DHE_RSA_WITH_AES_128_CBC_SHA * TestJSSE * @run main/othervm + * -DSERVER_PROTOCOL=SSLv2Hello,SSLv3,TLSv1,TLSv1.1,TLSv1.2,TLSv1.3 + * -DCLIENT_PROTOCOL=SSLv2Hello,SSLv3,TLSv1,TLSv1.1,TLSv1.2,TLSv1.3 + * -DCIPHER=TLS_AES_256_GCM_SHA384 + * TestJSSE + * @run main/othervm * -DSERVER_PROTOCOL=SSLv3 * -DCLIENT_PROTOCOL=SSLv3 * -DCIPHER=SSL_RSA_WITH_RC4_128_MD5 @@ -53,16 +58,21 @@ * @run main/othervm * -DSERVER_PROTOCOL=SSLv3,TLSv1 * -DCLIENT_PROTOCOL=TLSv1 - * -DCIPHER=SSL_RSA_WITH_RC4_128_MD5 + * -DCIPHER=TLS_RSA_WITH_AES_128_CBC_SHA * TestJSSE * @run main/othervm * -DSERVER_PROTOCOL=SSLv3,TLSv1,TLSv1.1 * -DCLIENT_PROTOCOL=TLSv1.1 - * -DCIPHER=SSL_RSA_WITH_RC4_128_MD5 + * -DCIPHER=TLS_RSA_WITH_AES_256_CBC_SHA * TestJSSE * @run main/othervm - * -DSERVER_PROTOCOL=SSLv3,TLSv1,TLSv1.1,TLSv1.2 + * -DSERVER_PROTOCOL=SSLv3,TLSv1,TLSv1.1,TLSv1.2,TLSv1.3 * -DCLIENT_PROTOCOL=TLSv1.2 - * -DCIPHER=SSL_RSA_WITH_RC4_128_MD5 + * -DCIPHER=TLS_RSA_WITH_AES_128_GCM_SHA256 + * TestJSSE + * @run main/othervm + * -DSERVER_PROTOCOL=SSLv3,TLSv1,TLSv1.1,TLSv1.2,TLSv1.3 + * -DCLIENT_PROTOCOL=TLSv1.3 + * -DCIPHER=TLS_AES_256_GCM_SHA384 * TestJSSE */ diff -r bfc8074ea4ef -r cfe31d2f935c test/jdk/javax/net/ssl/TLS/TestJSSEServerProtocol.java --- a/test/jdk/javax/net/ssl/TLS/TestJSSEServerProtocol.java Tue Nov 26 10:22:13 2019 +0000 +++ b/test/jdk/javax/net/ssl/TLS/TestJSSEServerProtocol.java Fri Nov 29 10:02:07 2019 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2019, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -23,7 +23,7 @@ /* * @test - * @bug 8049429 + * @bug 8049429 8234723 * @modules java.management * jdk.crypto.ec/sun.security.ec * @summary Test that all cipher suites work in all versions and all client @@ -38,16 +38,26 @@ * @run main/othervm * -DSERVER_PROTOCOL=TLSv1 * -DCLIENT_PROTOCOL=SSLv3,TLSv1,TLSv1.1,TLSv1.2 - * -DCIPHER=SSL_RSA_WITH_RC4_128_MD5 + * -DCIPHER=TLS_RSA_WITH_AES_128_CBC_SHA * TestJSSE * @run main/othervm * -DSERVER_PROTOCOL=TLSv1.1 * -DCLIENT_PROTOCOL=SSLv3,TLSv1,TLSv1.1,TLSv1.2 - * -DCIPHER=SSL_RSA_WITH_RC4_128_MD5 + * -DCIPHER=TLS_RSA_WITH_AES_256_CBC_SHA * TestJSSE * @run main/othervm * -DSERVER_PROTOCOL=TLSv1.2 * -DCLIENT_PROTOCOL=SSLv3,TLSv1,TLSv1.1,TLSv1.2 - * -DCIPHER=SSL_RSA_WITH_RC4_128_MD5 + * -DCIPHER=TLS_RSA_WITH_AES_128_GCM_SHA256 + * TestJSSE + * @run main/othervm + * -DSERVER_PROTOCOL=TLSv1.3 + * -DCLIENT_PROTOCOL=SSLv3,TLSv1,TLSv1.1,TLSv1.2,TLSv1.3 + * -DCIPHER=TLS_AES_256_GCM_SHA384 * TestJSSE + * @run main/othervm + * -DSERVER_PROTOCOL=TLSv1.2 + * -DCLIENT_PROTOCOL=TLSv1.3 + * -DCIPHER=TLS_AES_256_GCM_SHA384 + * TestJSSE javax.net.ssl.SSLHandshakeException */ diff -r bfc8074ea4ef -r cfe31d2f935c test/jdk/javax/net/ssl/templates/SSLSocketSSLEngineTemplate.java --- a/test/jdk/javax/net/ssl/templates/SSLSocketSSLEngineTemplate.java Tue Nov 26 10:22:13 2019 +0000 +++ b/test/jdk/javax/net/ssl/templates/SSLSocketSSLEngineTemplate.java Fri Nov 29 10:02:07 2019 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 2019, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -124,7 +124,6 @@ private static final String pathToStores = "../etc"; private static final String keyStoreFile = "keystore"; private static final String trustStoreFile = "truststore"; - private static final String passwd = "passphrase"; private static final String keyFilename = System.getProperty("test.src", ".") + "/" + pathToStores + "/" + keyStoreFile; @@ -146,7 +145,7 @@ } String [] protocols = new String [] { - "SSLv3", "TLSv1", "TLSv1.1", "TLSv1.2" }; + "SSLv3", "TLSv1", "TLSv1.1", "TLSv1.2", "TLSv1.3" }; for (String protocol : protocols) { log("Testing " + protocol); diff -r bfc8074ea4ef -r cfe31d2f935c test/jdk/jdk/jfr/api/consumer/recordingstream/TestClose.java --- a/test/jdk/jdk/jfr/api/consumer/recordingstream/TestClose.java Tue Nov 26 10:22:13 2019 +0000 +++ b/test/jdk/jdk/jfr/api/consumer/recordingstream/TestClose.java Fri Nov 29 10:02:07 2019 +0000 @@ -25,11 +25,15 @@ package jdk.jfr.api.consumer.recordingstream; +import java.time.Instant; import java.util.concurrent.CompletableFuture; import java.util.concurrent.CountDownLatch; import java.util.concurrent.atomic.AtomicLong; +import java.util.concurrent.atomic.AtomicReference; import jdk.jfr.Event; +import jdk.jfr.Recording; +import jdk.jfr.consumer.EventStream; import jdk.jfr.consumer.RecordingStream; /** @@ -51,6 +55,7 @@ testCloseTwice(); testCloseStreaming(); testCloseMySelf(); + testCloseNoEvents(); } private static void testCloseMySelf() throws Exception { @@ -122,6 +127,26 @@ log("Leaving testCloseTwice()"); } + private static void testCloseNoEvents() throws Exception { + try (Recording r = new Recording()) { + r.start(); + CountDownLatch finished = new CountDownLatch(2); + AtomicReference streamingThread = new AtomicReference<>(); + try (EventStream es = EventStream.openRepository()) { + es.setStartTime(Instant.EPOCH); + es.onFlush( () -> { + streamingThread.set(Thread.currentThread()); + finished.countDown();; + }); + es.startAsync(); + finished.await(); + } // <- EventStream::close should terminate thread + while (streamingThread.get().isAlive()) { + Thread.sleep(10); + } + } + } + private static void log(String msg) { System.out.println(msg); } diff -r bfc8074ea4ef -r cfe31d2f935c test/jdk/jdk/jfr/api/consumer/recordingstream/TestSetEndTime.java --- a/test/jdk/jdk/jfr/api/consumer/recordingstream/TestSetEndTime.java Tue Nov 26 10:22:13 2019 +0000 +++ b/test/jdk/jdk/jfr/api/consumer/recordingstream/TestSetEndTime.java Fri Nov 29 10:02:07 2019 +0000 @@ -63,6 +63,14 @@ public static void main(String... args) throws Exception { testEventStream(); testRecordingStream(); + testEmptyStream(); + } + + private static void testEmptyStream() { + try (RecordingStream rs = new RecordingStream()) { + rs.setEndTime(Instant.now().plusMillis(1100)); + rs.start(); + } } private static void testRecordingStream() throws Exception { @@ -89,10 +97,10 @@ } closed.await(); System.out.println("Found events: " + count.get()); - if (count.get() < 50) { + if (count.get() > 0 && count.get() < 50) { return; } - System.out.println("Found 50 events. Retrying"); + System.out.println("Retrying"); System.out.println(); } } diff -r bfc8074ea4ef -r cfe31d2f935c test/jdk/jdk/jfr/jvm/TestFormatDuration.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/jdk/jdk/jfr/jvm/TestFormatDuration.java Fri Nov 29 10:02:07 2019 +0000 @@ -0,0 +1,173 @@ +/* + * Copyright (c) 2019, 2019, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.jfr.jvm; + +import jdk.jfr.internal.Utils; +import jdk.test.lib.Asserts; + +import java.time.Duration; +import java.util.Locale; + +/** + * @test + * @key jfr + * @requires vm.hasJFR + * @library /test/lib + * @modules jdk.jfr/jdk.jfr.internal + * @run main/othervm jdk.jfr.jvm.TestFormatDuration + */ +public class TestFormatDuration { + public static void main(String[] args) throws Exception{ + Locale.setDefault(Locale.US); + + // Nanoseconds + assertDuration("0 ns ", "0 s"); + assertDuration("1 ns ", "0.000001 ms"); + assertDuration("10 ns ", "0.000010 ms"); + assertDuration("100 ns ", "0.000100 ms"); + assertDuration("999 ns ", "0.000999 ms"); + assertDuration("1000 ns", "0.00100 ms"); + assertDuration("1004 ns", "0.00100 ms"); + assertDuration("1005 ns", "0.00101 ms"); + + // 10 us + assertDuration("9 us 994 ns", "0.00999 ms"); + assertDuration("9 us 995 ns", "0.0100 ms"); + assertDuration("10 us ", "0.0100 ms"); + assertDuration("10 us 49 ns", "0.0100 ms"); + assertDuration("10 us 50 ns", "0.0101 ms"); + + // 100 us + assertDuration("99 us 949 ns ", "0.0999 ms"); + assertDuration("99 us 950 ns ", "0.100 ms"); + assertDuration("100 us ", "0.100 ms"); + assertDuration("100 us 499 ns", "0.100 ms"); + assertDuration("100 us 500 ns", "0.101 ms"); + + // 1 ms + assertDuration("999 us 499 ns ", "0.999 ms"); + assertDuration("999 us 500 ns ", "1.00 ms"); + assertDuration("1 ms ", "1.00 ms"); + assertDuration("1 ms 4 us 999 ns ", "1.00 ms"); + assertDuration("1 ms 5 us", "1.01 ms"); + + // 10 ms + assertDuration("9 ms 994 us 999 ns", "9.99 ms"); + assertDuration("9 ms 995 us ", "10.0 ms"); + assertDuration("10 ms ", "10.0 ms"); + assertDuration("10 ms 49 us 999 ns", "10.0 ms"); + assertDuration("10 ms 50 us 999 ns", "10.1 ms"); + + // 100 ms + assertDuration("99 ms 949 us 999 ns ", "99.9 ms"); + assertDuration("99 ms 950 us 000 ns ", "100 ms"); + assertDuration("100 ms ", "100 ms"); + assertDuration("100 ms 499 us 999 ns", "100 ms"); + assertDuration("100 ms 500 us ", "101 ms"); + + // 1 second + assertDuration("999 ms 499 us 999 ns ", "999 ms"); + assertDuration("999 ms 500 us ", "1.00 s"); + assertDuration("1 s ", "1.00 s"); + assertDuration("1 s 4 ms 999 us 999 ns", "1.00 s"); + assertDuration("1 s 5 ms ", "1.01 s"); + + // 10 seconds + assertDuration("9 s 994 ms 999 us 999 ns ", "9.99 s"); + assertDuration("9 s 995 ms ", "10.0 s"); + assertDuration("10 s ", "10.0 s"); + assertDuration("10 s 049 ms 999 us 999 ns", "10.0 s"); + assertDuration("10 s 050 ms ", "10.1 s"); + + // 1 minute + assertDuration("59 s 949 ms 999 us 999 ns", "59.9 s"); + assertDuration("59 s 950 ms ", "1 m 0 s"); + assertDuration("1 m 0 s ", "1 m 0 s"); + assertDuration("60 s 499 ms 999 us 999 ns", "1 m 0 s"); + assertDuration("60 s 500 ms ", "1 m 1 s"); + + // 10 minutes + assertDuration("10 m 0 s", "10 m 0 s"); + + // 1 hour + assertDuration("59 m 59 s 499 ms 999 us 999 ns", "59 m 59 s"); + assertDuration("59 m 59 s 500 ms ", "1 h 0 m"); + assertDuration("1 h 0 m ", "1 h 0 m"); + assertDuration("1 h 29 s 999 ms 999 us 999 ns ", "1 h 0 m"); + assertDuration("1 h 30 s ", "1 h 1 m"); + + // 1 day + assertDuration("23 h 59 m 29 s 999 ms 999 us 999 ns", "23 h 59 m"); + assertDuration("23 h 59 m 30 s ", "1 d 0 h"); + assertDuration("1 d 0 h ", "1 d 0 h"); + assertDuration("1 d 29 m 59 s 999 ms 999 us 999 ns ", "1 d 0 h"); + assertDuration("1 d 30 m ", "1 d 1 h"); + + // 100 days + assertDuration("100 d 13 h", "100 d 13 h"); + + // 1000 days + assertDuration("1000 d 13 h", "1000 d 13 h"); + } + + private static void assertDuration(String value, String expected) throws Exception { + long nanos = parse(value); + System.out.println(value + " == " + expected + " ? (" + nanos + " ns) "); + Asserts.assertEquals(Utils.formatDuration(Duration.ofNanos(nanos)), expected); + if (nanos != 0) { + Asserts.assertEquals(Utils.formatDuration(Duration.ofNanos(-nanos)), "-" + expected); + } + } + + + private static long parse(String duration) throws Exception { + String[] t = duration.trim().split(" "); + long nanos = 0; + for (int i = 0; i < t.length - 1; i += 2) { + nanos += Long.parseLong(t[i]) * parseUnit(t[i + 1]); + } + return nanos; + } + + private static long parseUnit(String unit) throws Exception { + switch (unit) { + case "ns": + return 1L; + case "us": + return 1_000L; + case "ms": + return 1_000_000L; + case "s": + return 1_000_000_000L; + case "m": + return 60 * 1_000_000_000L; + case "h": + return 3600 * 1_000_000_000L; + case "d": + return 24 * 3600 * 1_000_000_000L; + } + throw new Exception("Test error. Unknown unit " + unit); + } +} diff -r bfc8074ea4ef -r cfe31d2f935c test/jdk/security/infra/java/security/cert/CertPathValidator/certification/AmazonCA.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/jdk/security/infra/java/security/cert/CertPathValidator/certification/AmazonCA.java Fri Nov 29 10:02:07 2019 +0000 @@ -0,0 +1,552 @@ +/* + * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 8233223 + * @summary Interoperability tests with Amazon's CA1, CA2, CA3, and CA4 + * @build ValidatePathWithParams + * @run main/othervm -Djava.security.debug=certpath AmazonCA OCSP + * @run main/othervm -Djava.security.debug=certpath AmazonCA CRL + */ + +/* + * Obtain TLS test artifacts for Amazon CAs from: + * + * Amazon Root CA 1 + * Valid - https://good.sca1a.amazontrust.com/ + * Revoked - https://revoked.sca1a.amazontrust.com/ + * Amazon Root CA 2 + * Valid - https://good.sca2a.amazontrust.com/ + * Revoked - https://revoked.sca2a.amazontrust.com/ + * Amazon Root CA 3 + * Valid - https://good.sca3a.amazontrust.com/ + * Revoked - https://revoked.sca3a.amazontrust.com/ + * Amazon Root CA 4 + * Valid - https://good.sca4a.amazontrust.com/ + * Revoked - https://revoked.sca4a.amazontrust.com/ + */ +public class AmazonCA { + + public static void main(String[] args) throws Exception { + + ValidatePathWithParams pathValidator = new ValidatePathWithParams(null); + boolean ocspEnabled = false; + + if (args.length >= 1 && "CRL".equalsIgnoreCase(args[0])) { + pathValidator.enableCRLCheck(); + } else { + // OCSP check by default + pathValidator.enableOCSPCheck(); + ocspEnabled = true; + } + + new AmazonCA_1().runTest(pathValidator, ocspEnabled); + new AmazonCA_2().runTest(pathValidator, ocspEnabled); + new AmazonCA_3().runTest(pathValidator, ocspEnabled); + new AmazonCA_4().runTest(pathValidator, ocspEnabled); + } +} + +class AmazonCA_1 { + + // Owner: CN=Amazon, OU=Server CA 1A, O=Amazon, C=US + // Issuer: CN=Amazon Root CA 1, O=Amazon, C=US + // Serial number: 67f9457508c648c09ca652e71791830e72592 + // Valid from: Wed Oct 21 17:00:00 PDT 2015 until: Sat Oct 18 17:00:00 PDT 2025 + private static final String INT = "-----BEGIN CERTIFICATE-----\n" + + "MIIERzCCAy+gAwIBAgITBn+UV1CMZIwJymUucXkYMOclkjANBgkqhkiG9w0BAQsF\n" + + "ADA5MQswCQYDVQQGEwJVUzEPMA0GA1UEChMGQW1hem9uMRkwFwYDVQQDExBBbWF6\n" + + "b24gUm9vdCBDQSAxMB4XDTE1MTAyMjAwMDAwMFoXDTI1MTAxOTAwMDAwMFowRjEL\n" + + "MAkGA1UEBhMCVVMxDzANBgNVBAoTBkFtYXpvbjEVMBMGA1UECxMMU2VydmVyIENB\n" + + "IDFBMQ8wDQYDVQQDEwZBbWF6b24wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEK\n" + + "AoIBAQCeQM3XCsIZunv8bSJxOqkc/ed87uL76FDB7teBNThDRB+1J7aITuadbNfH\n" + + "5ZfZykrdZ1qQLKxP6DwHOmJr9u2b4IxjUX9qUMuq4B02ghD2g6yU3YivEosZ7fpo\n" + + "srD2TBN29JpgPGrOrpOE+ArZuIpBjdKFinemu6fTDD0NCeQlfyHXd1NOYyfYRLTa\n" + + "xlpDqr/2M41BgSkWQfSPHHyRWNQgWBiGsIQaS8TK0g8OWi1ov78+2K9DWT+AHgXW\n" + + "AanjZK91GfygPXJYSlAGxSiBAwH/KhAMifhaoFYAbH0Yuohmd85B45G2xVsop4TM\n" + + "Dsl007U7qnS7sdJ4jYGzEvva/a95AgMBAAGjggE5MIIBNTASBgNVHRMBAf8ECDAG\n" + + "AQH/AgEAMA4GA1UdDwEB/wQEAwIBhjAdBgNVHQ4EFgQUYtRCXoZwdWqQvMa40k1g\n" + + "wjS6UTowHwYDVR0jBBgwFoAUhBjMhTTsvAyUlC4IWZzHshBOCggwewYIKwYBBQUH\n" + + "AQEEbzBtMC8GCCsGAQUFBzABhiNodHRwOi8vb2NzcC5yb290Y2ExLmFtYXpvbnRy\n" + + "dXN0LmNvbTA6BggrBgEFBQcwAoYuaHR0cDovL2NydC5yb290Y2ExLmFtYXpvbnRy\n" + + "dXN0LmNvbS9yb290Y2ExLmNlcjA/BgNVHR8EODA2MDSgMqAwhi5odHRwOi8vY3Js\n" + + "LnJvb3RjYTEuYW1hem9udHJ1c3QuY29tL3Jvb3RjYTEuY3JsMBEGA1UdIAQKMAgw\n" + + "BgYEVR0gADANBgkqhkiG9w0BAQsFAAOCAQEAMHbSWHRFMzGNIE0qhN6gnRahTrTU\n" + + "CDPwe7l9/q0IA+QBlrpUHnlAreetYeH1jB8uF3qXXzy22gpBU7NqulTkqSPByT1J\n" + + "xOhpT2FpO5R3VAdMPdWfSEgtrED0jkmyUQrR1T+/A+nBLdJZeQcl+OqLgeY790JM\n" + + "JJTsJnnI6FBWeTGhcDI4Y+n3KS3QCVePeWI7jx1dhrHcXH+QDX8Ywe31hV7YENdr\n" + + "HDpUXrjK6eHN8gazy8G6pndXHFwHp4auiZbJbYAk/q1peOTRagD2JojcLkm+i3cD\n" + + "843t4By6YT/PVlePU2PCWejkrJQnKQAPOov7IA8kuO2RDWuzE/zF6Hotdg==\n" + + "-----END CERTIFICATE-----"; + + // Owner: CN=good.sca1a.amazontrust.com, O=Amazon Trust Services, L=Seattle, ST=Washington, C=US, \ + // SERIALNUMBER=5846743, OID.2.5.4.15=Private Organization, OID.1.3.6.1.4.1.311.60.2.1.2=Delaware, \ + // OID.1.3.6.1.4.1.311.60.2.1.3=US + // Issuer: CN=Amazon, OU=Server CA 1A, O=Amazon, C=US + // Serial number: 703e4e4bbd78e2b6db5634f36c4ee944cb1a4 + // Valid from: Mon Jul 29 16:53:36 PDT 2019 until: Sat Aug 29 16:53:36 PDT 2020 + private static final String VALID = "-----BEGIN CERTIFICATE-----\n" + + "MIIFEzCCA/ugAwIBAgITBwPk5LvXjitttWNPNsTulEyxpDANBgkqhkiG9w0BAQsF\n" + + "ADBGMQswCQYDVQQGEwJVUzEPMA0GA1UEChMGQW1hem9uMRUwEwYDVQQLEwxTZXJ2\n" + + "ZXIgQ0EgMUExDzANBgNVBAMTBkFtYXpvbjAeFw0xOTA3MjkyMzUzMzZaFw0yMDA4\n" + + "MjkyMzUzMzZaMIHaMRMwEQYLKwYBBAGCNzwCAQMTAlVTMRkwFwYLKwYBBAGCNzwC\n" + + "AQITCERlbGF3YXJlMR0wGwYDVQQPExRQcml2YXRlIE9yZ2FuaXphdGlvbjEQMA4G\n" + + "A1UEBRMHNTg0Njc0MzELMAkGA1UEBhMCVVMxEzARBgNVBAgTCldhc2hpbmd0b24x\n" + + "EDAOBgNVBAcTB1NlYXR0bGUxHjAcBgNVBAoTFUFtYXpvbiBUcnVzdCBTZXJ2aWNl\n" + + "czEjMCEGA1UEAxMaZ29vZC5zY2ExYS5hbWF6b250cnVzdC5jb20wggEiMA0GCSqG\n" + + "SIb3DQEBAQUAA4IBDwAwggEKAoIBAQDQyuJ83c2Zf9k29f6iLqd8nJSuHSk1v+SS\n" + + "0sYyG8tjscfCC1HcOdNj37vtiNN65sXh/e/kBKH9wvzhCLOJbBqVKRHOZuHdJEpH\n" + + "35R6C/PbcV/tp49g6mNmBe+lcmm/cwwCtYvkL0rgL/OKB0liFhhRIqy2TPg08op/\n" + + "RlY2DdbgBA2B3g7wdMo0hK3SO56/QUccUtLRm43km9Yd4E3U+CEUyDd0Bmc/YbPa\n" + + "htuXVsXJwiwlwooomujIIENhFw3htdcsu2apRj8EYUrKL8Mvvn+h16gDyobj0f01\n" + + "jWXlUgmH2lzUzca5eGuphfvmWN/ME/yqC2mMvWGnWySycqtT8VdJAgMBAAGjggFj\n" + + "MIIBXzAOBgNVHQ8BAf8EBAMCBaAwHQYDVR0OBBYEFFENOZBwFkjVdQX0iK32c77z\n" + + "SUl6MB8GA1UdIwQYMBaAFGLUQl6GcHVqkLzGuNJNYMI0ulE6MB0GA1UdJQQWMBQG\n" + + "CCsGAQUFBwMBBggrBgEFBQcDAjB1BggrBgEFBQcBAQRpMGcwLQYIKwYBBQUHMAGG\n" + + "IWh0dHA6Ly9vY3NwLnNjYTFhLmFtYXpvbnRydXN0LmNvbTA2BggrBgEFBQcwAoYq\n" + + "aHR0cDovL2NydC5zY2ExYS5hbWF6b250cnVzdC5jb20vc2NhMWEuY2VyMCUGA1Ud\n" + + "EQQeMByCGmdvb2Quc2NhMWEuYW1hem9udHJ1c3QuY29tMFAGA1UdIARJMEcwDQYL\n" + + "YIZIAYb9bgEHGAMwNgYFZ4EMAQEwLTArBggrBgEFBQcCARYfaHR0cHM6Ly93d3cu\n" + + "YW1hem9udHJ1c3QuY29tL2NwczANBgkqhkiG9w0BAQsFAAOCAQEAmn7z6Ub1sL77\n" + + "wyUEaCq/Odqm+2RtYYMJ1MeW6nTXTfAgZ/iLx/6hStafd9AK9gHiTCggBpj6KgnF\n" + + "UsGMDeX879jP675fH6SEk710QPDhIrfAzwE0pF/eUNsd7pLwne32zHX0ouCoAt4d\n" + + "KwBCZkKNUkdj4U+bpOJzvtcTP9JlzziLp9IFRjjQh3xKgfblx57CmRJbqH3fT5JJ\n" + + "IAIDVTz3ZUcqhPTFAnNsO1oNBEyrO5X9rwCiSy7aRijY/11R75mIIvyA9zyd9ss1\n" + + "kvrrER0GWMTDvC84FZD2vhkXgPTFrB1Dn9f3QgO5APT9GCFY5hdpqqPEXOSdRzQo\n" + + "h9j4OQAqtA==\n" + + "-----END CERTIFICATE-----"; + + // Owner: CN=revoked.sca1a.amazontrust.com, O=Amazon Trust Services, L=Seattle, ST=Washington, C=US, \ + // SERIALNUMBER=5846743, OID.2.5.4.15=PrivateOrganization, OID.1.3.6.1.4.1.311.60.2.1.2=Delaware, \ + // OID.1.3.6.1.4.1.311.60.2.1.3=US + // Issuer: CN=Amazon, OU=Server CA 1A, O=Amazon, C=US + // Serial number: 6f1d774ad5e7b6d251d217661782bbdb6f37d + // Valid from: Mon Jan 28 15:34:38 PST 2019 until: Thu Apr 28 16:34:38 PDT 2022 + private static final String REVOKED = "-----BEGIN CERTIFICATE-----\n" + + "MIIE2zCCA8OgAwIBAgITBvHXdK1ee20lHSF2YXgrvbbzfTANBgkqhkiG9w0BAQsF\n" + + "ADBGMQswCQYDVQQGEwJVUzEPMA0GA1UEChMGQW1hem9uMRUwEwYDVQQLEwxTZXJ2\n" + + "ZXIgQ0EgMUExDzANBgNVBAMTBkFtYXpvbjAeFw0xOTAxMjgyMzM0MzhaFw0yMjA0\n" + + "MjgyMzM0MzhaMIHcMRMwEQYLKwYBBAGCNzwCAQMTAlVTMRkwFwYLKwYBBAGCNzwC\n" + + "AQITCERlbGF3YXJlMRwwGgYDVQQPExNQcml2YXRlT3JnYW5pemF0aW9uMRAwDgYD\n" + + "VQQFEwc1ODQ2NzQzMQswCQYDVQQGEwJVUzETMBEGA1UECBMKV2FzaGluZ3RvbjEQ\n" + + "MA4GA1UEBxMHU2VhdHRsZTEeMBwGA1UEChMVQW1hem9uIFRydXN0IFNlcnZpY2Vz\n" + + "MSYwJAYDVQQDEx1yZXZva2VkLnNjYTFhLmFtYXpvbnRydXN0LmNvbTCCASIwDQYJ\n" + + "KoZIhvcNAQEBBQADggEPADCCAQoCggEBANUoHop9sW+QlgVsdtacioraTAWHcSTd\n" + + "MNkOkOEMgJIFPyfdcDvW/H2NvpdYeIQqzaCgT2kcsONWTZTPJMirCPnzl1ohHOZU\n" + + "uTnOVkamGxvNmQCURLBXmlCMRTCI5RY3CuYntFFbSPAnbumsF+K/gKqcE6ME53Bw\n" + + "PAwn4qwavB0i5Ib7Jk8XYzxSYXC9l8QLxt6fshPJRlecpXzfmVFvMAm3IbaLcpuv\n" + + "AtD+8I2KwjNtBPRPNYeFsWxwsgUGAyHEGa61oTGUqqAXu5YmPfyK+YTOJdoofsh4\n" + + "Tf3K7AKxnPWuvY3RNTs1pzEVwJYZqSsNwbgyKJJ4+0Xe4iP7qB8SYf8CAwEAAaOC\n" + + "ASkwggElMA4GA1UdDwEB/wQEAwIFoDAdBgNVHQ4EFgQUGHreoz+LP/Wr+RKzuexO\n" + + "V8ICtmEwHwYDVR0jBBgwFoAUYtRCXoZwdWqQvMa40k1gwjS6UTowHQYDVR0lBBYw\n" + + "FAYIKwYBBQUHAwEGCCsGAQUFBwMCMHUGCCsGAQUFBwEBBGkwZzAtBggrBgEFBQcw\n" + + "AYYhaHR0cDovL29jc3Auc2NhMWEuYW1hem9udHJ1c3QuY29tMDYGCCsGAQUFBzAC\n" + + "hipodHRwOi8vY3J0LnNjYTFhLmFtYXpvbnRydXN0LmNvbS9zY2ExYS5jZXIwKAYD\n" + + "VR0RBCEwH4IdcmV2b2tlZC5zY2ExYS5hbWF6b250cnVzdC5jb20wEwYDVR0gBAww\n" + + "CjAIBgZngQwBAgEwDQYJKoZIhvcNAQELBQADggEBABSbe1UCLL7Qay6XK5wD8B5a\n" + + "wvR1XG3UrggpVIz/w5cutEm/yE71hzE0gag/3YPbNYEnaLbJH+9jz4YW9wd/cEPj\n" + + "xSK5PErAQjCd+aA4LKN1xqkSysgYknl0y47hJBXGnWf+hxvBBHeSoUzM0KIC21pC\n" + + "ZyXrmfaPCQAz13ruYIYdQaETqXGVORmKbf/a+Zn18/tfQt0LeeCYVoSopbXWQvcJ\n" + + "gUMtdIqYQmb8aVj0pdZXwKl4yZ2DtlS3Z9MpWNgQNlhRPmiYlu28y2yTtZ9SwD6m\n" + + "2f+cwc19aJrDT4Y280px+jRU7dIE6oZVJU+yBRVIZYpUFAB7extCMVxnTkCf8Dk=\n" + + "-----END CERTIFICATE-----"; + + public void runTest(ValidatePathWithParams pathValidator, boolean ocspEnabled) throws Exception { + // EE certificates don't have CRLDP extension + if (!ocspEnabled){ + pathValidator.validate(new String[]{INT}, + ValidatePathWithParams.Status.GOOD, null, System.out); + + return; + } + + // Validate valid + pathValidator.validate(new String[]{VALID, INT}, + ValidatePathWithParams.Status.GOOD, null, System.out); + + // Validate Revoked + pathValidator.validate(new String[]{REVOKED, INT}, + ValidatePathWithParams.Status.REVOKED, + "Mon Jan 28 15:35:56 PST 2019", System.out); + } +} + +class AmazonCA_2 { + + // Owner: CN=Amazon, OU=Server CA 2A, O=Amazon, C=US + // Issuer: CN=Amazon Root CA 2, O=Amazon, C=US + // Serial number: 67f945755f187a91f8163f3e624620177ff38 + // Valid from: Wed Oct 21 17:00:00 PDT 2015 until: Sat Oct 18 17:00:00 PDT 2025 + private static final String INT = "-----BEGIN CERTIFICATE-----\n" + + "MIIGRzCCBC+gAwIBAgITBn+UV1Xxh6kfgWPz5iRiAXf/ODANBgkqhkiG9w0BAQwF\n" + + "ADA5MQswCQYDVQQGEwJVUzEPMA0GA1UEChMGQW1hem9uMRkwFwYDVQQDExBBbWF6\n" + + "b24gUm9vdCBDQSAyMB4XDTE1MTAyMjAwMDAwMFoXDTI1MTAxOTAwMDAwMFowRjEL\n" + + "MAkGA1UEBhMCVVMxDzANBgNVBAoTBkFtYXpvbjEVMBMGA1UECxMMU2VydmVyIENB\n" + + "IDJBMQ8wDQYDVQQDEwZBbWF6b24wggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIK\n" + + "AoICAQC0P8hSLewmrZ41CCPBQytZs5NBFMq5ztbnMf+kZUp9S25LPfjNW3zgC/6E\n" + + "qCTWNVMMHhq7ez9IQJk48qbfBTLlZkuKnUWbA9vowrDfcxUN0mRE4B/TJbveXyTf\n" + + "vE91iDlqDrERecE9D8sdjzURrtHTp27lZdRkXFvfEVCq4hl3sHkzjodisaQthLp1\n" + + "gLsiA7vKt+8zcL4Aeq52UyYb8r4/jdZ3KaQp8O/T4VwDCRKm8ey3kttpJWaflci7\n" + + "eRzNjY7gE3NMANVXCeQwOBfH2GjINFCObmPsqiBuoAnsv2k5aQLNoU1OZk08ClXm\n" + + "mEZ2rI5qZUTX1HuefBJnpMkPugFCw8afaHnB13SkLE7wxX8SZRdDIe5WiwyDL1tR\n" + + "2+8lpz4JsMoFopHmD3GaHyjbN+hkOqHgLltwewOsiyM0u3CZphypN2KeD+1FLjnY\n" + + "TgdIAd1FRgK2ZXDDrEdjnsSEfShKf0l4mFPSBs9E3U6sLmubDRXKLLLpa/dF4eKu\n" + + "LEKS1bXYT28iM6D5gSCnzho5G4d18jQD/slmc5XmRo5Pig0RyBwDaLuxeIZuiJ0A\n" + + "J6YFhffbrLYF5dEQl0cU+t3VBK5u/o1WkWXsZawU038lWn/AXerodT/pAcrtWA4E\n" + + "NQEN09WEKMhZVPhqdwhF/Gusr04mQtKt7T2v6UMQvtVglv5E7wIDAQABo4IBOTCC\n" + + "ATUwEgYDVR0TAQH/BAgwBgEB/wIBADAOBgNVHQ8BAf8EBAMCAYYwHQYDVR0OBBYE\n" + + "FNpDStD8AcBLv1gnjHbNCoHzlC70MB8GA1UdIwQYMBaAFLAM8Eww9AVYAkj9M+VS\n" + + "r0uE42ZSMHsGCCsGAQUFBwEBBG8wbTAvBggrBgEFBQcwAYYjaHR0cDovL29jc3Au\n" + + "cm9vdGNhMi5hbWF6b250cnVzdC5jb20wOgYIKwYBBQUHMAKGLmh0dHA6Ly9jcnQu\n" + + "cm9vdGNhMi5hbWF6b250cnVzdC5jb20vcm9vdGNhMi5jZXIwPwYDVR0fBDgwNjA0\n" + + "oDKgMIYuaHR0cDovL2NybC5yb290Y2EyLmFtYXpvbnRydXN0LmNvbS9yb290Y2Ey\n" + + "LmNybDARBgNVHSAECjAIMAYGBFUdIAAwDQYJKoZIhvcNAQEMBQADggIBAEO5W+iF\n" + + "yChjDyyrmiwFupVWQ0Xy2ReFNQiZq7XKVHvsLQe01moSLnxcBxioOPBKt1KkZO7w\n" + + "Gcbmke0+7AxLaG/F5NPnzRtK1/pRhXQ0XdU8pVh/1/h4GoqRlZ/eN0JDarUhZPkV\n" + + "kSr96LUYDTxcsAidF7zkzWfmtcJg/Aw8mi14xKVEa6aVyKu54c8kKkdlt0WaigOv\n" + + "Z/xYhxp24AfoFKaIraDNdsD8q2N7eDYeN4WGLzNSlil+iFjzflI9mq1hTuI/ZNjV\n" + + "rbvob6FUQ8Cc524gMjbpZCNuZ1gfXzwwhGp0AnQF6CJsWF9uwPpZEVFnnnfiWH3M\n" + + "oup41EvBhqaAqOlny0sm5pI82nRUCAE3DLkJ1+eAtdQaYblZQkQrRyTuPmJEm+5y\n" + + "QwdDVw6uHc5OsSj/tyhh8zJ2Xq3zgh3dMONGjJEysxGaCoIb+61PWwMy2dIarVwI\n" + + "r+c+AY+3PrhgBspNdWZ87JzNHii7ksdjUSVGTTy1vGXgPYrv0lp0IMnKaZP58xiw\n" + + "rDx7uTlQuPVWNOZvCaT3ZcoxTsNKNscIUe+WJjWx5hdzpv/oksDPY5ltZ0j3hlDS\n" + + "D+Itk95/cNJVRM/0HpxI1SX9MTZtOSJoEDdUtOpVaOuBAvEK4gvTzdt0r5L+fuI6\n" + + "o5LAuRo/LO1xVRH49KFRoaznzU3Ch9+kbPb3\n" + + "-----END CERTIFICATE-----"; + + // Owner: CN=good.sca2a.amazontrust.com, O=Amazon Trust Services, L=Seattle, ST=Washington, C=US, \ + // SERIALNUMBER=5846743, OID.2.5.4.15=Private Organization, OID.1.3.6.1.4.1.311.60.2.1.2=Delaware, \ + // OID.1.3.6.1.4.1.311.60.2.1.3=US + // Issuer: CN=Amazon, OU=Server CA 2A, O=Amazon, C=US + // Serial number: 703e4e70616c90d611fd04a5ecc635665184e + // Valid from: Mon Jul 29 16:54:06 PDT 2019 until: Sat Aug 29 16:54:06 PDT 2020 + private static final String VALID = "-----BEGIN CERTIFICATE-----\n" + + "MIIHEzCCBPugAwIBAgITBwPk5wYWyQ1hH9BKXsxjVmUYTjANBgkqhkiG9w0BAQwF\n" + + "ADBGMQswCQYDVQQGEwJVUzEPMA0GA1UEChMGQW1hem9uMRUwEwYDVQQLEwxTZXJ2\n" + + "ZXIgQ0EgMkExDzANBgNVBAMTBkFtYXpvbjAeFw0xOTA3MjkyMzU0MDZaFw0yMDA4\n" + + "MjkyMzU0MDZaMIHaMRMwEQYLKwYBBAGCNzwCAQMTAlVTMRkwFwYLKwYBBAGCNzwC\n" + + "AQITCERlbGF3YXJlMR0wGwYDVQQPExRQcml2YXRlIE9yZ2FuaXphdGlvbjEQMA4G\n" + + "A1UEBRMHNTg0Njc0MzELMAkGA1UEBhMCVVMxEzARBgNVBAgTCldhc2hpbmd0b24x\n" + + "EDAOBgNVBAcTB1NlYXR0bGUxHjAcBgNVBAoTFUFtYXpvbiBUcnVzdCBTZXJ2aWNl\n" + + "czEjMCEGA1UEAxMaZ29vZC5zY2EyYS5hbWF6b250cnVzdC5jb20wggIiMA0GCSqG\n" + + "SIb3DQEBAQUAA4ICDwAwggIKAoICAQC+XjOB3ZCFX+b9y9reP+e6EAQz4ytiMSqU\n" + + "O4s5MyYLkY6n4BIZHmgWeQ2IgW1VrH8ho+Iu3UsTiuhd3/L/q/w+T0OJfcrWngTs\n" + + "uVcIuvUr32ObPeeWbg/m/lkN7hqH1jY62iybYVrFXiLo1+0G92PUazcyNvyA20+G\n" + + "HsvGG5jlArWNgRLdc8KUXxvnDUxx5vu4jeHEZnqSwuulV1h9ve0UutkmoK0Sk7Rz\n" + + "HMxYK0LmUT5OvcNQSkUi5nLi+M1FxnYYgsELwSiKSSEDfEdgxooMAiVTgw51Q/DB\n" + + "lTOjAIDL3K3J0yGfIG3bwLvE1qz2Z5yWn8f3JibIah7LrC4PiZDDLHFM6V9l+YqU\n" + + "RqimJ5BltSyAx7bxQNZ1AW3Lxvvm894i4k6/Vdf1CDovRuTMPCDAQmKA/A/AQ7TN\n" + + "q3bBimX6UyuJu0I8RyvAYKzFhOOqe4vXrbndTbje/jnzTNQPeIIcuRa9cgXTOrbw\n" + + "86FTUKj6AZXihRWjKWsQpDwdgE0tQETZ3ynCXfbBKfFmn0MSjeX0CEEAZdYHR8EV\n" + + "F271Yt7UJjS/FP702aHTOWk7zFbIRfFQODvBhn0I8p/Stk2sDq4/YsbXVZOe3+ad\n" + + "YavoiODGSAH6ZcZzULumgK9eii0koAOPB/xqXnkcTS63gEHOKjLQl3hqdVZRCugv\n" + + "1CwUXLvoSwIDAQABo4IBYzCCAV8wDgYDVR0PAQH/BAQDAgWgMB0GA1UdDgQWBBTa\n" + + "j6dHgPdOxTGLcwaNDeaMnlSxNjAfBgNVHSMEGDAWgBTaQ0rQ/AHAS79YJ4x2zQqB\n" + + "85Qu9DAdBgNVHSUEFjAUBggrBgEFBQcDAQYIKwYBBQUHAwIwdQYIKwYBBQUHAQEE\n" + + "aTBnMC0GCCsGAQUFBzABhiFodHRwOi8vb2NzcC5zY2EyYS5hbWF6b250cnVzdC5j\n" + + "b20wNgYIKwYBBQUHMAKGKmh0dHA6Ly9jcnQuc2NhMmEuYW1hem9udHJ1c3QuY29t\n" + + "L3NjYTJhLmNlcjAlBgNVHREEHjAcghpnb29kLnNjYTJhLmFtYXpvbnRydXN0LmNv\n" + + "bTBQBgNVHSAESTBHMA0GC2CGSAGG/W4BBxgDMDYGBWeBDAEBMC0wKwYIKwYBBQUH\n" + + "AgEWH2h0dHBzOi8vd3d3LmFtYXpvbnRydXN0LmNvbS9jcHMwDQYJKoZIhvcNAQEM\n" + + "BQADggIBAE6RwZAZvN0i9ygwzqoX9DhSPtvZ3xIO0G0Bhgjkb986+p8XJstU3gEM\n" + + "8P2i1J/YthXCnRGedm+Odxx+31G6xIYfP5S5g7HyRGkj/aXNXy4s3KjH8HJgOY9N\n" + + "ra3XfC05OKq5FpyZQDZ+hxCdLrH3Gs+UxREbu+LuIKUpI7nMVEjn9XynKyOdKN21\n" + + "Kq5VsuI0fDWCYvUN1M+lI/LgE5HbNJVQJs+dB7g1/kaOeaLia7Wk1ys+uRzB58rp\n" + + "FKAoLk++HWTfNDkbN8vKRfHhJ/xhI9ju3TWcci6EyFVAym1C62UkJNI0KHgQ+zc7\n" + + "nl1tv/ytj8N/eJoysyp23lJ5qrVetlQORfgXryGkWBMYBvYF8zbBb/f+UXHDKVWt\n" + + "9l1lL6HQGY/tTo253pj6/FgDD35bZdjLQeUVmbnz679S5oUmoH5ZtSdnpUTghU3p\n" + + "bae9adBFY9S1pm50Q3ckRVBAwNqNmI0KKUh14Ms8KSAUHg19NvGsBonqwOT2rdbv\n" + + "xZ47N6c2eCl/cjMvzre0v0NoUO+3og2GHeAoOwVos6480YDbMqp739tOFPxBcsII\n" + + "6SjpDVh+14dkSW6kEKeaCFLR+eChqutri1VQbQ49nmADQWw9Al8vBytSnPv0YN6W\n" + + "XfIE1Qj7YmHu/UuoeKVsqDqoP/no29+96dtfd4afJqlIoyZUqXpt\n" + + "-----END CERTIFICATE-----"; + + // Owner: CN=revoked.sca2a.amazontrust.com, O=Amazon Trust Services, L=Seattle, ST=Washington, C=US, \ + // SERIALNUMBER=5846743, OID.2.5.4.15=PrivateOrganization, OID.1.3.6.1.4.1.311.60.2.1.2=Delaware, \ + // OID.1.3.6.1.4.1.311.60.2.1.3=US + //Issuer: CN=Amazon, OU=Server CA 2A, O=Amazon, C=US + //Serial number: 6f1d782c0aa2f4866b7b522c279b939b92369 + //Valid from: Mon Jan 28 15:37:45 PST 2019 until: Thu Apr 28 16:37:45 PDT 2022 + private static final String REVOKED = "-----BEGIN CERTIFICATE-----\n" + + "MIIG2zCCBMOgAwIBAgITBvHXgsCqL0hmt7Uiwnm5ObkjaTANBgkqhkiG9w0BAQwF\n" + + "ADBGMQswCQYDVQQGEwJVUzEPMA0GA1UEChMGQW1hem9uMRUwEwYDVQQLEwxTZXJ2\n" + + "ZXIgQ0EgMkExDzANBgNVBAMTBkFtYXpvbjAeFw0xOTAxMjgyMzM3NDVaFw0yMjA0\n" + + "MjgyMzM3NDVaMIHcMRMwEQYLKwYBBAGCNzwCAQMTAlVTMRkwFwYLKwYBBAGCNzwC\n" + + "AQITCERlbGF3YXJlMRwwGgYDVQQPExNQcml2YXRlT3JnYW5pemF0aW9uMRAwDgYD\n" + + "VQQFEwc1ODQ2NzQzMQswCQYDVQQGEwJVUzETMBEGA1UECBMKV2FzaGluZ3RvbjEQ\n" + + "MA4GA1UEBxMHU2VhdHRsZTEeMBwGA1UEChMVQW1hem9uIFRydXN0IFNlcnZpY2Vz\n" + + "MSYwJAYDVQQDEx1yZXZva2VkLnNjYTJhLmFtYXpvbnRydXN0LmNvbTCCAiIwDQYJ\n" + + "KoZIhvcNAQEBBQADggIPADCCAgoCggIBAKFm418X8hN1YTgD2XpMb4sp78mw8k3j\n" + + "Dq/vnpX48evVUzNpHpy4qRz/ZHBR4HUJO4lhfnX+CO0uRqqqx4F0JZRQB3KevaU8\n" + + "QGWHdJGhEddnurDhrgOUa+ZroqUnMCsTJfbyGtC6aiEXeu/eMhEUFkuBxJH1JtwD\n" + + "dQXMXuMjG07SVjOkhTkbMDzA/YbUqkDeOIybifDuvA5LEsl+kReY0b6RYFo2Tt/M\n" + + "dPhJD8q3Wsu+XCiCnbpcwlEVGxiD2RVRXJJ9o3ALGOxqU69V+lYS0kkwNHT7oV9J\n" + + "rhgt7iOCq0aoTAxu2j4FCp0JHNhGoW9pXoMXnmS6kK80hzLNYDxvKEaVaKkiYHw5\n" + + "CV0Vwii05ICa14nrStH/jcRNLyU+gp+6OeerPV3jpKWshGKWewF+2UiWU2WHTSrd\n" + + "Wis0/qEfFK/kSraAxpd+KavEEavKeudoMAHIxMACOk9E/fF5zhd2y4G1q1BdoRlR\n" + + "KP4GIV2v6qH6Ru2mNSuge9il6kDXxFNucrYKLDbAqkqalohkvDavcPoG9gZT3etv\n" + + "4IcgJriIWRxbJwKPpwJM+6wa6RpwoeJMuEp3ZBP7KDaQ8YX4rlf4zXLAsOKCNA9K\n" + + "OS/qYQ/I4g0E1WhfgEKClaLPS2u7jeVR6s1t4txGo4vq5Dkt17KTCew/WsX3rckf\n" + + "a2p5zvFcfpCNAgMBAAGjggEpMIIBJTAOBgNVHQ8BAf8EBAMCBaAwHQYDVR0OBBYE\n" + + "FAF8N1wV8EoYFkMXH6tEnmR/7vI+MB8GA1UdIwQYMBaAFNpDStD8AcBLv1gnjHbN\n" + + "CoHzlC70MB0GA1UdJQQWMBQGCCsGAQUFBwMBBggrBgEFBQcDAjB1BggrBgEFBQcB\n" + + "AQRpMGcwLQYIKwYBBQUHMAGGIWh0dHA6Ly9vY3NwLnNjYTJhLmFtYXpvbnRydXN0\n" + + "LmNvbTA2BggrBgEFBQcwAoYqaHR0cDovL2NydC5zY2EyYS5hbWF6b250cnVzdC5j\n" + + "b20vc2NhMmEuY2VyMCgGA1UdEQQhMB+CHXJldm9rZWQuc2NhMmEuYW1hem9udHJ1\n" + + "c3QuY29tMBMGA1UdIAQMMAowCAYGZ4EMAQIBMA0GCSqGSIb3DQEBDAUAA4ICAQBC\n" + + "VwR1NFk1IYIF4cjU7ML1aj8OIn+8mtakGQnuSJLK6ypSysINJBS48ZDdP6XZXvyD\n" + + "iTS0xEAPjAZHTqrABdNYmvJeL2RnN99DIwVzBpZp4NLTXbiSW7jb0Y5cEPDGJMOo\n" + + "SUAAM6fsiPRfz5vX4XVPznbcF2AwE/NVV+L3n9LVRt7qv2VqIEvLioR56Dq+5ofR\n" + + "4bw0BVlEYWF4Gsy7WDDTL1iLNBUwZTqBHwTv0fgDRiPqb/odmLQuRANwcJy8B8Zr\n" + + "s/yX4SeESaRdA82lAlQilksQitXS2qvQN06GEDOgUxYE6EabFdgklV5JypKqdOly\n" + + "vzpaDpF3z5W8Bj3D4fns1Kjrh1pPh5JRvg+616diKnQRt4X5q+EtmnXhDvIGMISI\n" + + "FuGwj57CNQ2x2MY2HHKWPrOccpQfEEvoSNR+ntYWrtSSttZq948O+zZBk1TXWuXV\n" + + "TVXllqTg8lp6d5cfKgvtHKgt98WkpPOcLVrNuVnMAIfDw6ar54dVKqrvkeEcF6mJ\n" + + "7oMKjJX/Vu9lYoGViBIfdeqcCPWSI8BpnCKaG7dTQO3Q1ObGmLdGBRlsRh+d+S5l\n" + + "Fq326ckbjx537e5/ai31lOR7OwVh9TDweKLqIACjs987C0EJSEfoOue25WRww2va\n" + + "iX9SrTPm4GxQ2OJgYwx0+HbezJXFN+dhaOFUavTSFw==\n" + + "-----END CERTIFICATE-----"; + + public void runTest(ValidatePathWithParams pathValidator, boolean ocspEnabled) throws Exception { + // EE certificates don't have CRLDP extension + if (!ocspEnabled){ + pathValidator.validate(new String[]{INT}, + ValidatePathWithParams.Status.GOOD, null, System.out); + + return; + } + + // Validate valid + pathValidator.validate(new String[]{VALID, INT}, + ValidatePathWithParams.Status.GOOD, null, System.out); + + // Validate Revoked + pathValidator.validate(new String[]{REVOKED, INT}, + ValidatePathWithParams.Status.REVOKED, + "Mon Jan 28 15:38:57 PST 2019", System.out); + } +} + +class AmazonCA_3 { + + // Owner: CN=Amazon, OU=Server CA 3A, O=Amazon, C=US + // Issuer: CN=Amazon Root CA 3, O=Amazon, C=US + // Serial number: 67f945758fe55b9ee3f75831d47f07d226c8a + // Valid from: Wed Oct 21 17:00:00 PDT 2015 until: Sat Oct 18 17:00:00 PDT 2025 + private static final String INT = "-----BEGIN CERTIFICATE-----\n" + + "MIICuzCCAmGgAwIBAgITBn+UV1j+VbnuP3WDHUfwfSJsijAKBggqhkjOPQQDAjA5\n" + + "MQswCQYDVQQGEwJVUzEPMA0GA1UEChMGQW1hem9uMRkwFwYDVQQDExBBbWF6b24g\n" + + "Um9vdCBDQSAzMB4XDTE1MTAyMjAwMDAwMFoXDTI1MTAxOTAwMDAwMFowRjELMAkG\n" + + "A1UEBhMCVVMxDzANBgNVBAoTBkFtYXpvbjEVMBMGA1UECxMMU2VydmVyIENBIDNB\n" + + "MQ8wDQYDVQQDEwZBbWF6b24wWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAATYcYsK\n" + + "mYdR0Gj8Xz45E/lfcTTnXhg2EtAIYBIHyXv/ZQyyyCas1aptX/I5T1coT6XK181g\n" + + "nB8hADuKfWlNoIYRo4IBOTCCATUwEgYDVR0TAQH/BAgwBgEB/wIBADAOBgNVHQ8B\n" + + "Af8EBAMCAYYwHQYDVR0OBBYEFATc4JXl6LlrlKHvjFsxHhN+VZfaMB8GA1UdIwQY\n" + + "MBaAFKu229cGnjesMIYHkXDHnMQZsXjAMHsGCCsGAQUFBwEBBG8wbTAvBggrBgEF\n" + + "BQcwAYYjaHR0cDovL29jc3Aucm9vdGNhMy5hbWF6b250cnVzdC5jb20wOgYIKwYB\n" + + "BQUHMAKGLmh0dHA6Ly9jcnQucm9vdGNhMy5hbWF6b250cnVzdC5jb20vcm9vdGNh\n" + + "My5jZXIwPwYDVR0fBDgwNjA0oDKgMIYuaHR0cDovL2NybC5yb290Y2EzLmFtYXpv\n" + + "bnRydXN0LmNvbS9yb290Y2EzLmNybDARBgNVHSAECjAIMAYGBFUdIAAwCgYIKoZI\n" + + "zj0EAwIDSAAwRQIgOl/vux0qfxNm05W3eofa9lKwz6oKvdu6g6Sc0UlwgRcCIQCS\n" + + "WSQ6F6JHLoeOWLyFFF658eNKEKbkEGMHz34gLX/N3g==\n" + + "-----END CERTIFICATE-----"; + + // Owner: CN=good.sca3a.amazontrust.com, O=Amazon Trust Services, L=Seattle, ST=Washington, C=US, \ + // SERIALNUMBER=5846743, OID.2.5.4.15=Private Organization, OID.1.3.6.1.4.1.311.60.2.1.2=Delaware, \ + // OID.1.3.6.1.4.1.311.60.2.1.3=US + // Issuer: CN=Amazon, OU=Server CA 3A, O=Amazon, C=US + // Serial number: 703e4e9bbc2605f37967a0e95f31f4789a677 + // Valid from: Mon Jul 29 16:54:43 PDT 2019 until: Sat Aug 29 16:54:43 PDT 2020 + private static final String VALID = "-----BEGIN CERTIFICATE-----\n" + + "MIIDhzCCAy2gAwIBAgITBwPk6bvCYF83lnoOlfMfR4mmdzAKBggqhkjOPQQDAjBG\n" + + "MQswCQYDVQQGEwJVUzEPMA0GA1UEChMGQW1hem9uMRUwEwYDVQQLEwxTZXJ2ZXIg\n" + + "Q0EgM0ExDzANBgNVBAMTBkFtYXpvbjAeFw0xOTA3MjkyMzU0NDNaFw0yMDA4Mjky\n" + + "MzU0NDNaMIHaMRMwEQYLKwYBBAGCNzwCAQMTAlVTMRkwFwYLKwYBBAGCNzwCAQIT\n" + + "CERlbGF3YXJlMR0wGwYDVQQPExRQcml2YXRlIE9yZ2FuaXphdGlvbjEQMA4GA1UE\n" + + "BRMHNTg0Njc0MzELMAkGA1UEBhMCVVMxEzARBgNVBAgTCldhc2hpbmd0b24xEDAO\n" + + "BgNVBAcTB1NlYXR0bGUxHjAcBgNVBAoTFUFtYXpvbiBUcnVzdCBTZXJ2aWNlczEj\n" + + "MCEGA1UEAxMaZ29vZC5zY2EzYS5hbWF6b250cnVzdC5jb20wWTATBgcqhkjOPQIB\n" + + "BggqhkjOPQMBBwNCAARl4yxf8XcvWR0LZ+YuBC0CpkwtU2NiMdlIM7eX0lxhQp53\n" + + "NpLlCrPRNzOWrjCJDdn21D0u7PrtN94UHLHOg9X0o4IBYzCCAV8wDgYDVR0PAQH/\n" + + "BAQDAgeAMB0GA1UdDgQWBBT2cHmOJFLWfg1Op7xAdAnqYcwaPzAfBgNVHSMEGDAW\n" + + "gBQE3OCV5ei5a5Sh74xbMR4TflWX2jAdBgNVHSUEFjAUBggrBgEFBQcDAQYIKwYB\n" + + "BQUHAwIwdQYIKwYBBQUHAQEEaTBnMC0GCCsGAQUFBzABhiFodHRwOi8vb2NzcC5z\n" + + "Y2EzYS5hbWF6b250cnVzdC5jb20wNgYIKwYBBQUHMAKGKmh0dHA6Ly9jcnQuc2Nh\n" + + "M2EuYW1hem9udHJ1c3QuY29tL3NjYTNhLmNlcjAlBgNVHREEHjAcghpnb29kLnNj\n" + + "YTNhLmFtYXpvbnRydXN0LmNvbTBQBgNVHSAESTBHMA0GC2CGSAGG/W4BBxgDMDYG\n" + + "BWeBDAEBMC0wKwYIKwYBBQUHAgEWH2h0dHBzOi8vd3d3LmFtYXpvbnRydXN0LmNv\n" + + "bS9jcHMwCgYIKoZIzj0EAwIDSAAwRQIgURdcqJVr4PWNIkmWcSKmzgZ1i94hQpGe\n" + + "mWbE9osk4m0CIQDhxIguihwvDa5RsBwdM0aRDgGKLNHigGqJoKqgH0d2qg==\n" + + "-----END CERTIFICATE-----"; + + // Owner: CN=revoked.sca3a.amazontrust.com, O=Amazon Trust Services, L=Seattle, ST=Washington, C=US, \ + // SERIALNUMBER=5846743, OID.2.5.4.15=PrivateOrganization, OID.1.3.6.1.4.1.311.60.2.1.2=Delaware, \ + // OID.1.3.6.1.4.1.311.60.2.1.3=US + // Issuer: CN=Amazon, OU=Server CA 3A, O=Amazon, C=US + // Serial number: 6f1d78cf0ca64ce7f551a6f2a0715cc0e8b50 + // Valid from: Mon Jan 28 15:40:01 PST 2019 until: Thu Apr 28 16:40:01 PDT 2022 + private static final String REVOKED = "-----BEGIN CERTIFICATE-----\n" + + "MIIDTzCCAvWgAwIBAgITBvHXjPDKZM5/VRpvKgcVzA6LUDAKBggqhkjOPQQDAjBG\n" + + "MQswCQYDVQQGEwJVUzEPMA0GA1UEChMGQW1hem9uMRUwEwYDVQQLEwxTZXJ2ZXIg\n" + + "Q0EgM0ExDzANBgNVBAMTBkFtYXpvbjAeFw0xOTAxMjgyMzQwMDFaFw0yMjA0Mjgy\n" + + "MzQwMDFaMIHcMRMwEQYLKwYBBAGCNzwCAQMTAlVTMRkwFwYLKwYBBAGCNzwCAQIT\n" + + "CERlbGF3YXJlMRwwGgYDVQQPExNQcml2YXRlT3JnYW5pemF0aW9uMRAwDgYDVQQF\n" + + "Ewc1ODQ2NzQzMQswCQYDVQQGEwJVUzETMBEGA1UECBMKV2FzaGluZ3RvbjEQMA4G\n" + + "A1UEBxMHU2VhdHRsZTEeMBwGA1UEChMVQW1hem9uIFRydXN0IFNlcnZpY2VzMSYw\n" + + "JAYDVQQDEx1yZXZva2VkLnNjYTNhLmFtYXpvbnRydXN0LmNvbTBZMBMGByqGSM49\n" + + "AgEGCCqGSM49AwEHA0IABJNl90Jq0wddpFj+JbLtmvGR/1geL5t1tvV406jGpYn2\n" + + "C5lAFjwASFy7pAnazZbfSkIDUU2i2XU0+7Cs+j1S/EOjggEpMIIBJTAOBgNVHQ8B\n" + + "Af8EBAMCB4AwHQYDVR0OBBYEFPhX3dYays5Sps0xTgouLkZzYLg4MB8GA1UdIwQY\n" + + "MBaAFATc4JXl6LlrlKHvjFsxHhN+VZfaMB0GA1UdJQQWMBQGCCsGAQUFBwMBBggr\n" + + "BgEFBQcDAjB1BggrBgEFBQcBAQRpMGcwLQYIKwYBBQUHMAGGIWh0dHA6Ly9vY3Nw\n" + + "LnNjYTNhLmFtYXpvbnRydXN0LmNvbTA2BggrBgEFBQcwAoYqaHR0cDovL2NydC5z\n" + + "Y2EzYS5hbWF6b250cnVzdC5jb20vc2NhM2EuY2VyMCgGA1UdEQQhMB+CHXJldm9r\n" + + "ZWQuc2NhM2EuYW1hem9udHJ1c3QuY29tMBMGA1UdIAQMMAowCAYGZ4EMAQIBMAoG\n" + + "CCqGSM49BAMCA0gAMEUCICLb16/50S4fOAFafi5lagdx7q6EDPPm596g19eQDMXk\n" + + "AiEAksCMLypRB4t30FABlsEjhVCBIxay0iIer2OcCIrhfEI=\n" + + "-----END CERTIFICATE-----"; + + public void runTest(ValidatePathWithParams pathValidator, boolean ocspEnabled) throws Exception { + // EE certificates don't have CRLDP extension + if (!ocspEnabled){ + pathValidator.validate(new String[]{INT}, + ValidatePathWithParams.Status.GOOD, null, System.out); + + return; + } + + // Validate valid + pathValidator.validate(new String[]{VALID, INT}, + ValidatePathWithParams.Status.GOOD, null, System.out); + + // Validate Revoked + pathValidator.validate(new String[]{REVOKED, INT}, + ValidatePathWithParams.Status.REVOKED, + "Mon Jan 28 15:40:35 PST 2019", System.out); + } +} + +class AmazonCA_4 { + + // Owner: CN=Amazon, OU=Server CA 4A, O=Amazon, C=US + // Issuer: CN=Amazon Root CA 4, O=Amazon, C=US + // Serial number: 67f94575a8862a9072e3239c37ceba1274e18 + // Valid from: Wed Oct 21 17:00:00 PDT 2015 until: Sat Oct 18 17:00:00 PDT 2025 + private static final String INT = "-----BEGIN CERTIFICATE-----\n" + + "MIIC+TCCAn6gAwIBAgITBn+UV1qIYqkHLjI5w3zroSdOGDAKBggqhkjOPQQDAzA5\n" + + "MQswCQYDVQQGEwJVUzEPMA0GA1UEChMGQW1hem9uMRkwFwYDVQQDExBBbWF6b24g\n" + + "Um9vdCBDQSA0MB4XDTE1MTAyMjAwMDAwMFoXDTI1MTAxOTAwMDAwMFowRjELMAkG\n" + + "A1UEBhMCVVMxDzANBgNVBAoTBkFtYXpvbjEVMBMGA1UECxMMU2VydmVyIENBIDRB\n" + + "MQ8wDQYDVQQDEwZBbWF6b24wdjAQBgcqhkjOPQIBBgUrgQQAIgNiAASRP0kIW0Ha\n" + + "7+ORvEVhIS5gIgkH66X5W9vBRTX14oG/1elIyI6LbFZ+E5KAufL0XoWJGI1WbPRm\n" + + "HW246FKSzF0wOEZZyxEROz6tuaVsnXRHRE76roS/Wr064uJpKH+Lv+SjggE5MIIB\n" + + "NTASBgNVHRMBAf8ECDAGAQH/AgEAMA4GA1UdDwEB/wQEAwIBhjAdBgNVHQ4EFgQU\n" + + "pSHN2+tTIZmqytlnQpQlsnv0wuMwHwYDVR0jBBgwFoAU0+zHOmVuzOHadppW+5zz\n" + + "hm1X5YEwewYIKwYBBQUHAQEEbzBtMC8GCCsGAQUFBzABhiNodHRwOi8vb2NzcC5y\n" + + "b290Y2E0LmFtYXpvbnRydXN0LmNvbTA6BggrBgEFBQcwAoYuaHR0cDovL2NydC5y\n" + + "b290Y2E0LmFtYXpvbnRydXN0LmNvbS9yb290Y2E0LmNlcjA/BgNVHR8EODA2MDSg\n" + + "MqAwhi5odHRwOi8vY3JsLnJvb3RjYTQuYW1hem9udHJ1c3QuY29tL3Jvb3RjYTQu\n" + + "Y3JsMBEGA1UdIAQKMAgwBgYEVR0gADAKBggqhkjOPQQDAwNpADBmAjEA59RAOBaj\n" + + "uh0rT/OOTWPEv6TBnb9XEadburBaXb8SSrR8il+NdkfS9WXRAzbwrG7LAjEA3ukD\n" + + "1HrQq+WXHBM5sIuViJI/Zh7MOjsc159Q+dn36PBqLRq03AXqE/lRjnv8C5nj\n" + + "-----END CERTIFICATE-----"; + + // Owner: CN=good.sca4a.amazontrust.com, O=Amazon Trust Services, L=Seattle, ST=Washington, C=US, \ + // SERIALNUMBER=5846743, OID.2.5.4.15=Private Organization, OID.1.3.6.1.4.1.311.60.2.1.2=Delaware, \ + // OID.1.3.6.1.4.1.311.60.2.1.3=US + // Issuer: CN=Amazon, OU=Server CA 4A, O=Amazon, C=US + // Serial number: 703e4ec57c72d5669efbc98875c3f6bc3f934 + // Valid from: Mon Jul 29 16:55:17 PDT 2019 until: Sat Aug 29 16:55:17 PDT 2020 + private static final String VALID = "-----BEGIN CERTIFICATE-----\n" + + "MIIDxTCCA0qgAwIBAgITBwPk7FfHLVZp77yYh1w/a8P5NDAKBggqhkjOPQQDAzBG\n" + + "MQswCQYDVQQGEwJVUzEPMA0GA1UEChMGQW1hem9uMRUwEwYDVQQLEwxTZXJ2ZXIg\n" + + "Q0EgNEExDzANBgNVBAMTBkFtYXpvbjAeFw0xOTA3MjkyMzU1MTdaFw0yMDA4Mjky\n" + + "MzU1MTdaMIHaMRMwEQYLKwYBBAGCNzwCAQMTAlVTMRkwFwYLKwYBBAGCNzwCAQIT\n" + + "CERlbGF3YXJlMR0wGwYDVQQPExRQcml2YXRlIE9yZ2FuaXphdGlvbjEQMA4GA1UE\n" + + "BRMHNTg0Njc0MzELMAkGA1UEBhMCVVMxEzARBgNVBAgTCldhc2hpbmd0b24xEDAO\n" + + "BgNVBAcTB1NlYXR0bGUxHjAcBgNVBAoTFUFtYXpvbiBUcnVzdCBTZXJ2aWNlczEj\n" + + "MCEGA1UEAxMaZ29vZC5zY2E0YS5hbWF6b250cnVzdC5jb20wdjAQBgcqhkjOPQIB\n" + + "BgUrgQQAIgNiAAS9fqMYfOBsdXMSsPjqOlTgIGOlOQWA7Wg6XwVvHTr0+UN+XTeC\n" + + "yZN+XjLbEDQ0CF5eryRZ535sDpwh3qNe0lYFO1n1+2iDtDI1jhhLNYNxBpVnR2BU\n" + + "2l9EuRmgRbQpDCajggFjMIIBXzAOBgNVHQ8BAf8EBAMCB4AwHQYDVR0OBBYEFMd0\n" + + "itH5IcE6DpM1uTSBV/6DLmK7MB8GA1UdIwQYMBaAFKUhzdvrUyGZqsrZZ0KUJbJ7\n" + + "9MLjMB0GA1UdJQQWMBQGCCsGAQUFBwMBBggrBgEFBQcDAjB1BggrBgEFBQcBAQRp\n" + + "MGcwLQYIKwYBBQUHMAGGIWh0dHA6Ly9vY3NwLnNjYTRhLmFtYXpvbnRydXN0LmNv\n" + + "bTA2BggrBgEFBQcwAoYqaHR0cDovL2NydC5zY2E0YS5hbWF6b250cnVzdC5jb20v\n" + + "c2NhNGEuY2VyMCUGA1UdEQQeMByCGmdvb2Quc2NhNGEuYW1hem9udHJ1c3QuY29t\n" + + "MFAGA1UdIARJMEcwDQYLYIZIAYb9bgEHGAMwNgYFZ4EMAQEwLTArBggrBgEFBQcC\n" + + "ARYfaHR0cHM6Ly93d3cuYW1hem9udHJ1c3QuY29tL2NwczAKBggqhkjOPQQDAwNp\n" + + "ADBmAjEA2RBD1F+rnm394VkqA3ncysM3deoyfWqaoAO5923MNisswPnHfVqnfeXf\n" + + "ZwTAvVTBAjEAiiaPx9GRjEk8IBKvCSbTp9rPogVTN7zDDQGrwA83O0pRP7A0dxtT\n" + + "pn/0K5Sj8otp\n" + + "-----END CERTIFICATE-----"; + + // Owner: CN=revoked.sca4a.amazontrust.com, O=Amazon Trust Services, L=Seattle, ST=Washington, C=US, \ + // SERIALNUMBER=5846743, OID.2.5.4.15=PrivateOrganization, OID.1.3.6.1.4.1.311.60.2.1.2=Delaware, \ + // OID.1.3.6.1.4.1.311.60.2.1.3=US + // Issuer: CN=Amazon, OU=Server CA 4A, O=Amazon, C=US + // Serial number: 6f1d79295c384a699d51c2d756bd46213b5b3 + // Valid from: Mon Jan 28 15:41:16 PST 2019 until: Thu Apr 28 16:41:16 PDT 2022 + private static final String REVOKED = "-----BEGIN CERTIFICATE-----\n" + + "MIIDjTCCAxKgAwIBAgITBvHXkpXDhKaZ1RwtdWvUYhO1szAKBggqhkjOPQQDAzBG\n" + + "MQswCQYDVQQGEwJVUzEPMA0GA1UEChMGQW1hem9uMRUwEwYDVQQLEwxTZXJ2ZXIg\n" + + "Q0EgNEExDzANBgNVBAMTBkFtYXpvbjAeFw0xOTAxMjgyMzQxMTZaFw0yMjA0Mjgy\n" + + "MzQxMTZaMIHcMRMwEQYLKwYBBAGCNzwCAQMTAlVTMRkwFwYLKwYBBAGCNzwCAQIT\n" + + "CERlbGF3YXJlMRwwGgYDVQQPExNQcml2YXRlT3JnYW5pemF0aW9uMRAwDgYDVQQF\n" + + "Ewc1ODQ2NzQzMQswCQYDVQQGEwJVUzETMBEGA1UECBMKV2FzaGluZ3RvbjEQMA4G\n" + + "A1UEBxMHU2VhdHRsZTEeMBwGA1UEChMVQW1hem9uIFRydXN0IFNlcnZpY2VzMSYw\n" + + "JAYDVQQDEx1yZXZva2VkLnNjYTRhLmFtYXpvbnRydXN0LmNvbTB2MBAGByqGSM49\n" + + "AgEGBSuBBAAiA2IABLuNpZTcNU3FElNP3Y/OeXIZcIMXkFTBi/n92fNwHfqUbEhH\n" + + "H+PovJ26eAGvb5a8bGc275MBFcVnWL0rCVgM+j9KAtBDCRJX3f7mo0D2VKcmtZKu\n" + + "jPxwGPy2kuqM505dGqOCASkwggElMA4GA1UdDwEB/wQEAwIHgDAdBgNVHQ4EFgQU\n" + + "zUFIhn+hphzCKA2qgAdLztSBzJgwHwYDVR0jBBgwFoAUpSHN2+tTIZmqytlnQpQl\n" + + "snv0wuMwHQYDVR0lBBYwFAYIKwYBBQUHAwEGCCsGAQUFBwMCMHUGCCsGAQUFBwEB\n" + + "BGkwZzAtBggrBgEFBQcwAYYhaHR0cDovL29jc3Auc2NhNGEuYW1hem9udHJ1c3Qu\n" + + "Y29tMDYGCCsGAQUFBzAChipodHRwOi8vY3J0LnNjYTRhLmFtYXpvbnRydXN0LmNv\n" + + "bS9zY2E0YS5jZXIwKAYDVR0RBCEwH4IdcmV2b2tlZC5zY2E0YS5hbWF6b250cnVz\n" + + "dC5jb20wEwYDVR0gBAwwCjAIBgZngQwBAgEwCgYIKoZIzj0EAwMDaQAwZgIxALDA\n" + + "klY3iKwyzwpwVtLfLxzQEl45xvE2VjBJvfJJ60KhJt7Ud0gt0zxkogh29+mpEQIx\n" + + "ANTG1mk8OJB41DU7ru1Pwc6ju8STw1FdwDp/Eliqhvnm2i0k4/F1bBHLta2mlC2V\n" + + "hg==\n" + + "-----END CERTIFICATE-----"; + + public void runTest(ValidatePathWithParams pathValidator, boolean ocspEnabled) throws Exception { + // EE certificates don't have CRLDP extension + if (!ocspEnabled){ + pathValidator.validate(new String[]{INT}, + ValidatePathWithParams.Status.GOOD, null, System.out); + + return; + } + + // Validate valid + pathValidator.validate(new String[]{VALID, INT}, + ValidatePathWithParams.Status.GOOD, null, System.out); + + // Validate Revoked + pathValidator.validate(new String[]{REVOKED, INT}, + ValidatePathWithParams.Status.REVOKED, + "Mon Jan 28 15:41:53 PST 2019", System.out); + } +} diff -r bfc8074ea4ef -r cfe31d2f935c test/jdk/sun/security/lib/cacerts/VerifyCACerts.java --- a/test/jdk/sun/security/lib/cacerts/VerifyCACerts.java Tue Nov 26 10:22:13 2019 +0000 +++ b/test/jdk/sun/security/lib/cacerts/VerifyCACerts.java Fri Nov 29 10:02:07 2019 +0000 @@ -26,7 +26,7 @@ * @test * @bug 8189131 8198240 8191844 8189949 8191031 8196141 8204923 8195774 8199779 * 8209452 8209506 8210432 8195793 8216577 8222089 8222133 8222137 8222136 - * 8223499 8225392 8232019 8234245 + * 8223499 8225392 8232019 8234245 8233223 * @summary Check root CA entries in cacerts file */ import java.io.ByteArrayInputStream; @@ -52,12 +52,12 @@ + File.separator + "security" + File.separator + "cacerts"; // The numbers of certs now. - private static final int COUNT = 89; + private static final int COUNT = 93; // SHA-256 of cacerts, can be generated with // shasum -a 256 cacerts | sed -e 's/../&:/g' | tr '[:lower:]' '[:upper:]' | cut -c1-95 private static final String CHECKSUM - = "DE:71:94:6D:6C:5B:2A:AE:5C:AC:D1:3E:07:23:B6:43:CB:F7:32:69:32:04:36:9C:B4:11:78:6A:49:9D:C5:AB"; + = "22:AA:EB:89:4E:A4:EA:25:CA:3E:DA:0F:F1:2B:FA:05:4B:68:C5:E1:3A:F9:03:40:BF:EF:F5:13:7C:CE:BC:60"; // map of cert alias to SHA-256 fingerprint @SuppressWarnings("serial") @@ -241,6 +241,14 @@ "2C:AB:EA:FE:37:D0:6C:A2:2A:BA:73:91:C0:03:3D:25:98:29:52:C4:53:64:73:49:76:3A:3A:B5:AD:6C:CF:69"); put("luxtrustglobalroot2ca [jdk]", "54:45:5F:71:29:C2:0B:14:47:C4:18:F9:97:16:8F:24:C5:8F:C5:02:3B:F5:DA:5B:E2:EB:6E:1D:D8:90:2E:D5"); + put("amazonrootca1 [jdk]", + "8E:CD:E6:88:4F:3D:87:B1:12:5B:A3:1A:C3:FC:B1:3D:70:16:DE:7F:57:CC:90:4F:E1:CB:97:C6:AE:98:19:6E"); + put("amazonrootca2 [jdk]", + "1B:A5:B2:AA:8C:65:40:1A:82:96:01:18:F8:0B:EC:4F:62:30:4D:83:CE:C4:71:3A:19:C3:9C:01:1E:A4:6D:B4"); + put("amazonrootca3 [jdk]", + "18:CE:6C:FE:7B:F1:4E:60:B2:E3:47:B8:DF:E8:68:CB:31:D0:2E:BB:3A:DA:27:15:69:F5:03:43:B4:6D:B3:A4"); + put("amazonrootca4 [jdk]", + "E3:5D:28:41:9E:D0:20:25:CF:A6:90:38:CD:62:39:62:45:8D:A5:C6:95:FB:DE:A3:C2:2B:0B:FB:25:89:70:92"); } }; diff -r bfc8074ea4ef -r cfe31d2f935c test/jdk/sun/security/ssl/SSLContextImpl/IllegalProtocolProperty.java --- a/test/jdk/sun/security/ssl/SSLContextImpl/IllegalProtocolProperty.java Tue Nov 26 10:22:13 2019 +0000 +++ b/test/jdk/sun/security/ssl/SSLContextImpl/IllegalProtocolProperty.java Fri Nov 29 10:02:07 2019 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2019, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -26,7 +26,7 @@ /* * @test - * @bug 7093640 + * @bug 7093640 8234725 * @summary Enable TLS 1.1 and TLS 1.2 by default in client side of SunJSSE * @run main/othervm -Djdk.tls.client.protocols="XSLv3,TLSv1" * IllegalProtocolProperty @@ -43,7 +43,8 @@ TLS_CV_04("TLSv1", "TLSv1", "TLSv1.2", false), TLS_CV_05("TLSv1.1", "TLSv1.1", "TLSv1.2", false), TLS_CV_06("TLSv1.2", "TLSv1.2", "TLSv1.2", false), - TLS_CV_07("Default", "TLSv1", "TLSv1.2", true); + TLS_CV_07("Default", "TLSv1", "TLSv1.2", true), + TLS_CV_08("TLSv1.3", "TLSv1.3", "TLSv1.3", false); final String contextVersion; final String defaultProtocolVersion; diff -r bfc8074ea4ef -r cfe31d2f935c test/jdk/sun/security/ssl/SSLContextImpl/SSLContextVersion.java --- a/test/jdk/sun/security/ssl/SSLContextImpl/SSLContextVersion.java Tue Nov 26 10:22:13 2019 +0000 +++ b/test/jdk/sun/security/ssl/SSLContextImpl/SSLContextVersion.java Fri Nov 29 10:02:07 2019 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 2019, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -26,7 +26,7 @@ /* * @test - * @bug 6976117 + * @bug 6976117 8234725 * @summary SSLContext.getInstance("TLSv1.1") returns SSLEngines/SSLSockets * without TLSv1.1 enabled * @run main/othervm SSLContextVersion @@ -42,7 +42,10 @@ TLS_CV_04("TLSv1", "TLSv1", "TLSv1.2"), TLS_CV_05("TLSv1.1", "TLSv1.1", "TLSv1.2"), TLS_CV_06("TLSv1.2", "TLSv1.2", "TLSv1.2"), - TLS_CV_07("Default", "TLSv1.2", "TLSv1.2"); + TLS_CV_07("Default", "TLSv1.2", "TLSv1.2"), + TLS_CV_08("Default", "TLSv1.3", "TLSv1.3"), + TLS_CV_09("TLS", "TLSv1.3", "TLSv1.3"), + TLS_CV_10("TLSv1.3", "TLSv1.3", "TLSv1.3"); final String contextVersion; final String defaultProtocolVersion; diff -r bfc8074ea4ef -r cfe31d2f935c test/langtools/jdk/javadoc/doclet/testHtmlLandmarkRegions/TestHtmlLandmarkRegions.java --- a/test/langtools/jdk/javadoc/doclet/testHtmlLandmarkRegions/TestHtmlLandmarkRegions.java Tue Nov 26 10:22:13 2019 +0000 +++ b/test/langtools/jdk/javadoc/doclet/testHtmlLandmarkRegions/TestHtmlLandmarkRegions.java Fri Nov 29 10:02:07 2019 +0000 @@ -23,7 +23,7 @@ /* * @test - * @bug 8210047 8199892 8215599 + * @bug 8210047 8199892 8215599 8223378 * @summary some pages contains content outside of landmark region * @library /tools/lib ../../lib * @modules @@ -74,7 +74,7 @@ checkExit(Exit.OK); checkOrder("index.html", - "

    \n" + "
    \n" + "