--- 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
--- 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"
--- 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
--- /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-----
--- /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-----
--- /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-----
--- /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-----
--- 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
--- 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"
--- 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;
--- 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);
--- 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);
--- 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();
--- 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"
--- 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) {
--- 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();
--- 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;
--- 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();
}
}
--- 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();
--- 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"
--- 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,
--- 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<int (*)(address*)>(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();
+ }
}
--- 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;
--- 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;
+
--- 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;
--- 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
--- 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()
%{
--- 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"
--- 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"
--- 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"
--- 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"
--- 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"
--- 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"
--- 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.
--- 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";
}
--- 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
--- 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
--- 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);
--- 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"
--- 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"
--- 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"
--- 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); }
--- 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"
--- 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"
--- 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"
--- 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"
--- 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"
--- 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"
--- 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"
--- 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); }
--- 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"
--- 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
--- 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;
}
--- 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() {
--- 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 {
--- 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);
--- 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
--- 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());
--- 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);
--- 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) {
--- 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"
--- 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
--- 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) {
--- 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
--- 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);
--- 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
--- 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"
--- 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<size_t>(max_gc_threads, "Merged Coarse:");
_gc_par_phases[MergeRS]->link_thread_work_items(_merge_rs_merged_coarse, MergeRSMergedCoarse);
+ _merge_rs_dirty_cards = new WorkerDataArray<size_t>(max_gc_threads, "Dirty Cards:");
+ _gc_par_phases[MergeRS]->link_thread_work_items(_merge_rs_dirty_cards, MergeRSDirtyCards);
_gc_par_phases[OptMergeRS] = new WorkerDataArray<double>(max_gc_threads, "Optional Remembered Sets (ms):");
_opt_merge_rs_merged_sparse = new WorkerDataArray<size_t>(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<size_t>(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<size_t>(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<double>(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();
}
--- 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<size_t>* _merge_rs_merged_sparse;
WorkerDataArray<size_t>* _merge_rs_merged_fine;
WorkerDataArray<size_t>* _merge_rs_merged_coarse;
+ WorkerDataArray<size_t>* _merge_rs_dirty_cards;
WorkerDataArray<size_t>* _merge_hcc_dirty_cards;
WorkerDataArray<size_t>* _merge_hcc_skipped_cards;
@@ -138,6 +140,7 @@
WorkerDataArray<size_t>* _opt_merge_rs_merged_sparse;
WorkerDataArray<size_t>* _opt_merge_rs_merged_fine;
WorkerDataArray<size_t>* _opt_merge_rs_merged_coarse;
+ WorkerDataArray<size_t>* _opt_merge_rs_dirty_cards;
WorkerDataArray<size_t>* _opt_scan_hr_scanned_cards;
WorkerDataArray<size_t>* _opt_scan_hr_scanned_blocks;
--- 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];
--- 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;
}
};
--- 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());
}
--- 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
--- 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
--- 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
--- 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;
--- 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
--- 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);
}
--- 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.
--- 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);
}
}
-
--- 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;
--- 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 {
--- 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
--- 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 <class Closure>
--- 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
--- 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;
}
--- 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;
--- 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;
--- 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"
--- 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<char*>(Thread::current());
- disarmed_addr += in_bytes(thread_disarmed_offset());
- return *reinterpret_cast<int*>(disarmed_addr);
+ return *disarmed_value_address();
}
bool BarrierSetNMethod::supports_entry_barrier(nmethod* nm) {
--- 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<mtGC> {
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);
--- 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() :
--- 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") \
--- 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,
--- 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() {
--- 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"
--- 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)
--- 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"
--- 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"
--- 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"
--- 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;
--- 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);
}
--- 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<ShenandoahBarrierSetAssembler>(),
make_barrier_set_c1<ShenandoahBarrierSetC1>(),
make_barrier_set_c2<ShenandoahBarrierSetC2>(),
- 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 <class T>
-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<false>(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);
--- 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 <class T> 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 <DecoratorSet decorators, typename T>
+ inline void satb_barrier(T* field);
+ inline void satb_enqueue(oop value);
+ inline void storeval_barrier(oop obj);
+
+ template <DecoratorSet decorators>
+ 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 <class T>
inline void arraycopy_pre_work(T* src, T* dst, size_t count);
@@ -126,27 +122,12 @@
template <class T>
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 <DecoratorSet decorators, typename BarrierSetT = ShenandoahBarrierSet>
class AccessBarrier: public BarrierSet::AccessBarrier<decorators, BarrierSetT> {
typedef BarrierSet::AccessBarrier<decorators, BarrierSetT> Raw;
- template <typename T>
- static oop oop_atomic_cmpxchg_in_heap_impl(T* addr, oop compare_value, oop new_value);
-
- template <typename T>
- 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
--- 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<false>(obj)) return;
+
+ ShenandoahThreadLocalData::satb_mark_queue(Thread::current()).enqueue_known_active(obj);
+}
+
+template <DecoratorSet decorators, typename T>
+inline void ShenandoahBarrierSet::satb_barrier(T *field) {
+ if (HasDecorator<decorators, IS_DEST_UNINITIALIZED>::value ||
+ HasDecorator<decorators, AS_NO_KEEPALIVE>::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 <DecoratorSet decorators>
+inline void ShenandoahBarrierSet::keep_alive_if_weak(oop value) {
+ assert((decorators & ON_UNKNOWN_OOP_REF) == 0, "Reference strength must be known");
+ if (!HasDecorator<decorators, ON_STRONG_OOP_REF>::value &&
+ !HasDecorator<decorators, AS_NO_KEEPALIVE>::value) {
+ keep_alive_barrier(value);
+ }
+}
+
+template <DecoratorSet decorators, typename BarrierSetT>
+template <typename T>
+inline oop ShenandoahBarrierSet::AccessBarrier<decorators, BarrierSetT>::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<decorators>(value);
+ }
+ return value;
+}
+
template <DecoratorSet decorators, typename BarrierSetT>
template <typename T>
inline oop ShenandoahBarrierSet::AccessBarrier<decorators, BarrierSetT>::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<decorators>(value);
+ }
return value;
}
template <DecoratorSet decorators, typename BarrierSetT>
inline oop ShenandoahBarrierSet::AccessBarrier<decorators, BarrierSetT>::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<decorators>(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<decorators>(base, offset),
+ value);
+ }
return value;
}
template <DecoratorSet decorators, typename BarrierSetT>
template <typename T>
-inline oop ShenandoahBarrierSet::AccessBarrier<decorators, BarrierSetT>::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<decorators, BarrierSetT>::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<decorators>(addr);
+ Raw::oop_store(addr, value);
}
template <DecoratorSet decorators, typename BarrierSetT>
template <typename T>
inline void ShenandoahBarrierSet::AccessBarrier<decorators, BarrierSetT>::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 <DecoratorSet decorators, typename BarrierSetT>
@@ -92,14 +175,10 @@
template <DecoratorSet decorators, typename BarrierSetT>
template <typename T>
-inline void ShenandoahBarrierSet::AccessBarrier<decorators, BarrierSetT>::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<decorators, BarrierSetT>::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 <DecoratorSet decorators, typename BarrierSetT>
-template <typename T>
-inline oop ShenandoahBarrierSet::AccessBarrier<decorators, BarrierSetT>::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 <DecoratorSet decorators, typename BarrierSetT>
-template <typename T>
-inline oop ShenandoahBarrierSet::AccessBarrier<decorators, BarrierSetT>::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 <DecoratorSet decorators, typename BarrierSetT>
template <typename T>
inline oop ShenandoahBarrierSet::AccessBarrier<decorators, BarrierSetT>::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 <DecoratorSet decorators, typename BarrierSetT>
inline oop ShenandoahBarrierSet::AccessBarrier<decorators, BarrierSetT>::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<decorators>(base, offset), compare_value, new_value);
- keep_alive_if_weak(AccessBarrierSupport::resolve_possibly_unknown_oop_ref_strength<decorators>(base, offset), result);
- return result;
+ return oop_atomic_cmpxchg_in_heap(AccessInternal::oop_field_addr<decorators>(base, offset), compare_value, new_value);
}
template <DecoratorSet decorators, typename BarrierSetT>
template <typename T>
inline oop ShenandoahBarrierSet::AccessBarrier<decorators, BarrierSetT>::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 <DecoratorSet decorators, typename BarrierSetT>
-template <typename T>
-inline oop ShenandoahBarrierSet::AccessBarrier<decorators, BarrierSetT>::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 <DecoratorSet decorators, typename BarrierSetT>
template <typename T>
inline oop ShenandoahBarrierSet::AccessBarrier<decorators, BarrierSetT>::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 <DecoratorSet decorators, typename BarrierSetT>
inline oop ShenandoahBarrierSet::AccessBarrier<decorators, BarrierSetT>::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<decorators>(base, offset), new_value);
- keep_alive_if_weak(AccessBarrierSupport::resolve_possibly_unknown_oop_ref_strength<decorators>(base, offset), result);
- return result;
+ return oop_atomic_xchg_in_heap(AccessInternal::oop_field_addr<decorators>(base, offset), new_value);
}
// Clone barrier support
--- /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();
+}
--- /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
--- 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:
--- 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 <class T>
void ShenandoahAssertNotForwardedClosure::do_oop_work(T* p) {
--- 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<CodeHeap*>* heaps) {
_length = heaps->length();
@@ -97,69 +100,45 @@
_finished = true;
}
-class ShenandoahNMethodOopDetector : public OopClosure {
-private:
- ResourceMark rm; // For growable array allocation below.
- GrowableArray<oop*> _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<oop*>* oops() {
- return &_oops;
- }
-
- bool has_oops() {
- return !_oops.is_empty();
- }
-};
-
-GrowableArray<ShenandoahNMethod*>* 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<ShenandoahNMethod*>(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 <bool CSET_FILTER>
void ShenandoahCodeRootsIterator::fast_parallel_blobs_do(CodeBlobClosure *f) {
assert(SafepointSynchronize::is_at_safepoint(), "Must be at safepoint");
-
- size_t stride = 256; // educated guess
-
- GrowableArray<ShenandoahNMethod*>* 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<oop*>* 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<CSET_FILTER>(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<oop*>* 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
--- 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<mtGC> {
-private:
- nmethod* _nm;
- oop** _oops;
- int _oops_count;
-
-public:
- ShenandoahNMethod(nmethod *nm, GrowableArray<oop*>* 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<oop*>* 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<ShenandoahNMethod*>* _recorded_nms;
- static ShenandoahLock _recorded_nms_lock;
+ static ShenandoahNMethodTable* _nmethod_table;
+ static int _disarmed_value;
};
#endif // SHARE_GC_SHENANDOAH_SHENANDOAHCODEROOTS_HPP
--- 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();
+}
--- 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();
};
--- 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(),
--- 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<jint>(&_threads_in_evac, 0);
+ Atomic::release_store_fence(&_threads_in_evac, (jint)0);
}
ShenandoahEvacOOMScope::ShenandoahEvacOOMScope() {
--- 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);
--- 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();
--- 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()) {
--- 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
--- 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<class T>
inline void ShenandoahHeap::marked_object_iterate(ShenandoahHeapRegion* region, T* cl) {
marked_object_iterate(region, cl, region->top());
--- 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"
--- 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() :
--- /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;
+}
--- 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
--- 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"
--- /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<oop*>& 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<oop*> 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<oop*>& 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<oop*> 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<oop*> _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<oop*>* 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<oop*>* 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();
+}
--- /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<mtGC> {
+private:
+ nmethod* const _nm;
+ oop** _oops;
+ int _oops_count;
+ bool _has_non_immed_oops;
+ bool _unregistered;
+ ShenandoahReentrantLock _lock;
+
+public:
+ ShenandoahNMethod(nmethod *nm, GrowableArray<oop*>& 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<oop*>& oops, bool& _has_non_immed_oops);
+};
+
+class ShenandoahNMethodTable;
+
+// An opaque snapshot of current nmethod table for iteration
+class ShenandoahNMethodTableSnapshot : public CHeapObj<mtGC> {
+ 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<bool CSET_FILTER>
+ void parallel_blobs_do(CodeBlobClosure *f);
+
+ void concurrent_nmethods_do(NMethodClosure* cl);
+};
+
+class ShenandoahNMethodTable : public CHeapObj<mtGC> {
+ 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
--- /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<int>(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<ShenandoahNMethod>();
+}
+
+void ShenandoahNMethod::attach_gc_data(nmethod* nm, ShenandoahNMethod* gc_data) {
+ nm->set_gc_data<ShenandoahNMethod>(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<bool CSET_FILTER>
+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
--- 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);
--- 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.
--- 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<CodeBlobToOopClosure*>(&blobs_and_disarm_Cl) :
+ static_cast<CodeBlobToOopClosure*>(&blobsCl);
AlwaysTrueClosure always_true;
_serial_roots.oops_do(oops, worker_id);
@@ -178,8 +188,12 @@
_weak_roots.oops_do<OopClosure>(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<CodeBlobToOopClosure*>(&blobs_and_disarm_Cl) :
+ static_cast<CodeBlobToOopClosure*>(&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<OopClosure>(oops, worker_id);
--- 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<false /*concurrent*/> _weak_roots;
ShenandoahStringDedupRoots _dedup_roots;
- ShenandoahCodeCacheRoots<ShenandoahCsetCodeRootsIterator> _code_roots;
+ ShenandoahCodeCacheRoots<ShenandoahAllCodeRootsIterator> _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<false /*concurrent*/> _weak_roots;
ShenandoahStringDedupRoots _dedup_roots;
- ShenandoahCodeCacheRoots<ShenandoahCsetCodeRootsIterator> _code_roots;
+ ShenandoahCodeCacheRoots<ShenandoahAllCodeRootsIterator> _code_roots;
public:
ShenandoahRootUpdater(uint n_workers, ShenandoahPhaseTimings::Phase phase);
--- 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 <typename IsAlive, typename KeepAlive>
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<CodeBlobToOopClosure*>(&blobs_and_disarm_Cl) :
+ static_cast<CodeBlobToOopClosure*>(&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);
--- 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<uint>(ShenandoahRootVerifier::AllRoots) + 1) > static_cast<uint>(ShenandoahRootVerifier::AllRoots));
-ShenandoahRootVerifier::ShenandoahRootVerifier() : _types(AllRoots) {
+ShenandoahRootVerifier::ShenandoahRootVerifier(RootTypes types) : _types(types) {
}
void ShenandoahRootVerifier::excludes(RootTypes types) {
--- 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);
--- 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;
--- 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"
--- 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
--- /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();
+}
--- /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
--- 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;
--- 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);
};
--- 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.") \
--- 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<uintptr_t>(&ZAddressBadMask);
+ const uintptr_t disarmed_addr = mask_addr + ZNMethodDisarmedOffset;
+ return reinterpret_cast<int*>(disarmed_addr);
}
ByteSize ZBarrierSetNMethod::thread_disarmed_offset() const {
--- 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
--- 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);
--- 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"
--- 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"
--- 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),
--- 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) {
--- 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"
--- 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;
--- 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"
--- 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"
--- 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"
--- 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"
--- 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"
--- 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"
--- 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:
--- 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"
--- 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"
--- 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;
--- 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"
--- 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"
--- 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);
}
--- 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");
--- 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"
--- 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
-
--- 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
-
--- 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);
--- 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;
}
}
--- 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 <DecoratorSet decorators>
template <DecoratorSet idecorators, typename T>
--- 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 {
--- 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"
--- 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");
--- 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
--- 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); }
--- 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"
--- 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"
--- 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"
--- 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);
--- 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"
--- 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);
--- 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"
--- 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:
--- 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;
--- 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");
--- 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"
--- 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"
--- 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"
--- 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"
--- 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"
--- 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"
--- 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 },
--- 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() },
--- 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"
--- 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) {
--- 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"
--- 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"
--- 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"
--- 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"
--- 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"
--- 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"
--- 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"
--- 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"
--- 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"
--- 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"
--- 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;
}
-
-
--- 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:
--- 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"
--- 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);
}
--- 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"
--- 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"
--- 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<ThreadIdTableConfig, mtInternal> ThreadIdTableHash;
// 2^24 is max size
--- 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"
--- 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"
--- 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"
--- 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"
--- 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"
--- 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"
--- 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"
--- 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
* <LI> The class contains unknown datatypes
* <LI> The class does not have an accessible no-arg constructor
+ * <LI> The ObjectStreamClass of an enum constant does not represent
+ * an enum type
+ * <LI> Other conditions given in the <cite>Java Object Serialization
+ * Specification</cite>
* </UL>
*
* @author unascribed
--- 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 <em>not</em> the class of the declaring enum type. The
* {@link Enum#getDeclaringClass} method of an enum constant can
--- 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,
--- 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
}
/**
--- 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);
}
--- 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);
}
--- 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);
--- 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.)
*
* <p>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.
*
* <p>The comparison is consistent with {@link #equals(Object[], Object[]) equals},
--- 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,
+ ;
}
}
--- 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;
}
--- 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;
}
--- 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();
--- 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;
}
--- /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 <i>pattern matching for instanceof</i>, 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();
+
+}
+
--- 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 <i>pattern matching for instanceof</i>, 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.
+ *
+ * <p>For instanceof with a pattern, i.e. in the following form:
+ * <pre>
+ * <em>expression</em> instanceof <em>type</em> <em>variable name</em>
+ * </pre>
+ * returns the pattern.
+ *
+ * <p>For instanceof without a pattern, i.e. in the following form:
+ * <pre>
+ * <em>expression</em> instanceof <em>type</em>
+ * </pre>
+ * returns null.
+ *
+ * @return the tested pattern, or null if this instanceof does not use a pattern.
+ * @since 14
+ */
+ PatternTree getPattern();
}
--- /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 <i>pattern matching for instanceof</i>, 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 {}
--- 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 <i>pattern matching for instanceof</i>, 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),
--- 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 <i>pattern matching for instanceof</i>, 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
--- 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) {
--- 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) {
--- 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;
--- 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'
--- 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,
--- 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<Attribute.TypeCompound> 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:
--- 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
--- 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<BindingSymbol> 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<AttrContext> 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<BindingSymbol> 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<AttrContext> 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<BindingSymbol> 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<AttrContext> 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<BindingSymbol> 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<AttrContext> trueEnv = bindingEnv(env, matchBindingsComputer.getMatchBindings(tree.cond, true));
+ try {
+ truetype = attribTree(tree.truepart, trueEnv, condInfo);
+ } finally {
+ trueEnv.info.scope.leave();
+ }
+
+ Type falsetype;
+ Env<AttrContext> 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<AttrContext> bindingEnv(Env<AttrContext> env, List<BindingSymbol> bindings) {
+ Env<AttrContext> 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<BindingSymbol> thenBindings = matchBindingsComputer.getMatchBindings(tree.cond, true);
+ Env<AttrContext> 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<BindingSymbol> elseBindings = matchBindingsComputer.getMatchBindings(tree.cond, false);
+
+ if (tree.elsepart != null) {
+ Env<AttrContext> 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<BindingSymbol> 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<BindingSymbol> 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<AttrContext> 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,
--- 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;
--- 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;
--- 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<AttrContext> 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<AttrContext> 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 {
--- /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<MatchBindingsComputer> matchBindingsComputerKey = new Context.Key<>();
+
+ private final Log log;
+ private final Types types;
+ boolean whenTrue;
+ List<BindingSymbol> 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<BindingSymbol> 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<BindingSymbol> lhsBindings = bindings;
+ scan(tree.rhs);
+ List<BindingSymbol> 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<BindingSymbol> 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<BindingSymbol> 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<BindingSymbol> intersection(JCTree tree, List<BindingSymbol> lhsBindings, List<BindingSymbol> 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<BindingSymbol> 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<BindingSymbol> union(JCTree tree, List<BindingSymbol> lhsBindings, List<BindingSymbol> ... rhsBindings_s) {
+ // It is an error if for union(a,b), a and b contain the same name (disjoint union).
+ List<BindingSymbol> list = lhsBindings;
+ for (List<BindingSymbol> 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<BindingSymbol> 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;
+ }
+ }
+
+}
--- /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 <pattern>.
+ */
+public class TransPatterns extends TreeTranslator {
+
+ protected static final Context.Key<TransPatterns> 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<BindingSymbol> 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<JCStatement> 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<JCStatement> 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<AttrContext> 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<BindingSymbol> 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<BindingSymbol> matchBindings;
+ Map<BindingSymbol, VarSymbol> hoistedVarMap;
+ BindingContext parent;
+
+ public BasicBindingContext(List<BindingSymbol> 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<JCStatement> stats = new ListBuffer<>();
+ for (Entry<BindingSymbol, VarSymbol> 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);
+ }
+ }
+}
--- 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;
}
--- 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
--- 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);
--- 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;
}
--- 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.
--- 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);
}
--- 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;
--- 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.
*/
--- 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
--- 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, D> R accept(TreeVisitor<R, D> 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); }
--- 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<? extends JCTree> 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);
--- 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)
--- 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);
}
+
}
--- 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;
--- 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) {
--- 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;
}
--- 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) {
--- 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));
}
/**
--- 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);
--- 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);
}
--- 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);
}
--- 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<DocPath> localStylesheets = getLocalStylesheets(pkg);
+ contentTree.add(bodyContents.toContent());
printHtmlDocument(configuration.metakeywords.getMetaKeywords(annotationType),
description, localStylesheets, contentTree);
}
--- 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;
}
}
--- 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<DocPath> localStylesheets = getLocalStylesheets(pkg);
+ contentTree.add(bodyContents.toContent());
printHtmlDocument(configuration.metakeywords.getMetaKeywords(typeElement),
description, localStylesheets, contentTree);
}
--- 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);
}
}
--- 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;
}
--- 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<? extends DocTree> 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);
}
--- 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);
}
}
--- 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" +
- " try {\n" +
- " if (location.href.indexOf('is-external=true') == -1) {\n" +
- " parent.document.title=")
- .appendStringLiteral(winTitle)
- .append(";\n" +
- " }\n" +
- " }\n" +
- " catch(err) {\n" +
- " }\n" +
- "//-->\n");
- }
- return script;
- }
-
- /**
* Returns an HtmlTree for the BODY tag.
*
* @param title title for the window
--- 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<TypeElement, Content> 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);
}
--- 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;
}
--- 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<String, Set<TypeElement>> 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;
}
}
--- 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<DocPath> localStylesheets = getLocalStylesheets(packageElement);
+ contentTree.add(bodyContents.toContent());
printHtmlDocument(configuration.metakeywords.getMetaKeywords(packageElement),
description, localStylesheets, contentTree);
}
--- 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<TypeElement> 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);
}
--- 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);
}
--- 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);
}
--- 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);
}
/**
--- 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;
}
--- /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.
+ *
+ * <p><b>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.</b>
+ */
+public class BodyContents {
+
+ private List<Content> 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;
+ }
+}
--- 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,
--- 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
--- 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"
- + "$('.navPadding').css('padding-top', $('.fixedNav').css(\"height\"));\n"
- + "//-->\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<Content> 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<Content> 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;
}
}
--- 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.
--- 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.
--- 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.
--- 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.
--- 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.
--- 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.
--- 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();
}
--- 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 <TypeElement>} 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();
}
--- 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);
}
/**
--- 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);
}
/**
--- 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);
}
/**
--- 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);
}
/**
--- 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) {
--- 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;
--- 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);
--- 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();
--- 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();
+ }
}
--- 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();
+ }
+
}
--- 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
--- 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) {
--- 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);
+}
--- 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
*/
--- 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
--- 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");
--- 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);
}
--- 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
--- 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"},
--- /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 <pid> 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 <pid> 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");
+ }
+}
--- 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.
--- /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");
+ }
+ }
+}
--- 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());
}
}
}
--- /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);
+ }
+ }
+}
--- /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<InetAddress> 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");
+ }
+ }
+ }
+}
+
--- 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);
--- 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 {
--- 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";
--- 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
*/
--- 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
*/
--- 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
*/
--- 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);
--- 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<Thread> 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);
}
--- 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();
}
}
--- /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);
+ }
+}
--- /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);
+ }
+}
--- 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");
}
};
--- 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;
--- 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;
--- 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",
- "<header role=\"banner\">\n"
+ "<header role=\"banner\" class=\"flexHeader\">\n"
+ "<nav role=\"navigation\">",
"<main role=\"main\">\n"
+ "<div class=\"header\">\n"
@@ -98,7 +98,7 @@
checkExit(Exit.OK);
checkOrder("index.html",
- "<header role=\"banner\">\n"
+ "<header role=\"banner\" class=\"flexHeader\">\n"
+ "<nav role=\"navigation\">",
"<main role=\"main\">\n"
+ "<div class=\"header\">\n"
@@ -130,9 +130,10 @@
checkExit(Exit.OK);
checkOrder("pkg1/doc-files/s.html",
- "<header role=\"banner\">\n"
+ "<header role=\"banner\" class=\"flexHeader\">\n"
+ "<nav role=\"navigation\">\n",
- "<main role=\"main\">A sample doc file",
+ "<main role=\"main\">\n"
+ + "<div class=\"contentContainer\">A sample doc file",
"<footer role=\"contentinfo\">\n"
+ "<nav role=\"navigation\">"
);
--- a/test/langtools/jdk/javadoc/doclet/testHtmlVersion/TestHtmlVersion.java Tue Nov 26 10:22:13 2019 +0000
+++ b/test/langtools/jdk/javadoc/doclet/testHtmlVersion/TestHtmlVersion.java Fri Nov 29 10:02:07 2019 +0000
@@ -24,7 +24,7 @@
/*
* @test
* @bug 8072945 8081854 8141492 8148985 8150188 4649116 8173707 8151743 8169819 8183037 8182765 8196202
- * 8202624 8210047 8184205 8221871 8223733
+ * 8202624 8210047 8184205 8221871 8223733 8223378
* @summary Test the version of HTML generated by the javadoc tool.
* @author bpatel
* @library ../../lib
@@ -78,9 +78,8 @@
"<div class=\"overviewSummary\">\n"
+ "<table>\n"
+ "<caption>",
- "<header role=\"banner\">\n"
+ "<header role=\"banner\" class=\"flexHeader\">\n"
+ "<nav role=\"navigation\">\n"
- + "<div class=\"fixedNav\">\n"
+ "<!-- ========= START OF TOP NAVBAR ======= -->",
"<footer role=\"contentinfo\">\n"
+ "<nav role=\"navigation\">\n"
@@ -94,9 +93,8 @@
+ "<!-- -->\n"
+ "</a>",
"<div class=\"typeSummary\">\n<table>",
- "<header role=\"banner\">\n"
+ "<header role=\"banner\" class=\"flexHeader\">\n"
+ "<nav role=\"navigation\">\n"
- + "<div class=\"fixedNav\">\n"
+ "<!-- ========= START OF TOP NAVBAR ======= -->",
"<main role=\"main\">\n"
+ "<div class=\"header\">",
@@ -124,9 +122,8 @@
+ "<!-- -->\n"
+ "</a>",
"<li class=\"circle\">",
- "<header role=\"banner\">\n"
+ "<header role=\"banner\" class=\"flexHeader\">\n"
+ "<nav role=\"navigation\">\n"
- + "<div class=\"fixedNav\">\n"
+ "<!-- ========= START OF TOP NAVBAR ======= -->",
"<main role=\"main\">\n"
+ "<div class=\"header\">",
@@ -150,9 +147,8 @@
+ "<!-- -->\n"
+ "</a>",
"<div class=\"useSummary\">\n<table>",
- "<header role=\"banner\">\n"
+ "<header role=\"banner\" class=\"flexHeader\">\n"
+ "<nav role=\"navigation\">\n"
- + "<div class=\"fixedNav\">\n"
+ "<!-- ========= START OF TOP NAVBAR ======= -->",
"<main role=\"main\">\n"
+ "<div class=\"header\">",
@@ -168,9 +164,8 @@
+ "<!-- -->\n"
+ "</a>",
"<div class=\"constantsSummary\">\n<table>",
- "<header role=\"banner\">\n"
+ "<header role=\"banner\" class=\"flexHeader\">\n"
+ "<nav role=\"navigation\">\n"
- + "<div class=\"fixedNav\">\n"
+ "<!-- ========= START OF TOP NAVBAR ======= -->",
"<main role=\"main\">\n"
+ "<div class=\"header\">",
@@ -190,9 +185,8 @@
+ "<!-- -->\n"
+ "</a>",
"<div class=\"deprecatedSummary\">\n<table>",
- "<header role=\"banner\">\n"
+ "<header role=\"banner\" class=\"flexHeader\">\n"
+ "<nav role=\"navigation\">\n"
- + "<div class=\"fixedNav\">\n"
+ "<!-- ========= START OF TOP NAVBAR ======= -->",
"<main role=\"main\">\n"
+ "<div class=\"header\">",
@@ -207,9 +201,8 @@
"<a id=\"navbar.top.firstrow\">\n"
+ "<!-- -->\n"
+ "</a>",
- "<header role=\"banner\">\n"
+ "<header role=\"banner\" class=\"flexHeader\">\n"
+ "<nav role=\"navigation\">\n"
- + "<div class=\"fixedNav\">\n"
+ "<!-- ========= START OF TOP NAVBAR ======= -->",
"<main role=\"main\">\n"
+ "<div class=\"header\">",
@@ -227,9 +220,8 @@
+ "<!-- -->\n"
+ "</a>",
"<li class=\"circle\">",
- "<header role=\"banner\">\n"
+ "<header role=\"banner\" class=\"flexHeader\">\n"
+ "<nav role=\"navigation\">\n"
- + "<div class=\"fixedNav\">\n"
+ "<!-- ========= START OF TOP NAVBAR ======= -->",
"<main role=\"main\">\n"
+ "<div class=\"header\">",
@@ -252,11 +244,11 @@
"<a id=\"navbar.top.firstrow\">\n"
+ "<!-- -->\n"
+ "</a>",
- "<header role=\"banner\">\n"
+ "<header role=\"banner\" class=\"flexHeader\">\n"
+ "<nav role=\"navigation\">\n"
- + "<div class=\"fixedNav\">\n"
+ "<!-- ========= START OF TOP NAVBAR ======= -->",
"</header>\n"
+ + "<div class=\"flexContent\">\n"
+ "<main role=\"main\">",
"<footer role=\"contentinfo\">\n"
+ "<nav role=\"navigation\">\n"
@@ -275,9 +267,8 @@
"<a id=\"navbar.top.firstrow\">\n"
+ "<!-- -->\n"
+ "</a>",
- "<header role=\"banner\">\n"
+ "<header role=\"banner\" class=\"flexHeader\">\n"
+ "<nav role=\"navigation\">\n"
- + "<div class=\"fixedNav\">\n"
+ "<!-- ========= START OF TOP NAVBAR ======= -->",
"<main role=\"main\">\n"
+ "<div class=\"header\">",
@@ -298,11 +289,11 @@
"<a id=\"navbar.top.firstrow\">\n"
+ "<!-- -->\n"
+ "</a>",
- "<header role=\"banner\">\n"
+ "<header role=\"banner\" class=\"flexHeader\">\n"
+ "<nav role=\"navigation\">\n"
- + "<div class=\"fixedNav\">\n"
+ "<!-- ========= START OF TOP NAVBAR ======= -->",
"<main role=\"main\">\n"
+ + "<!-- ======== START OF CLASS DATA ======== -->\n"
+ "<div class=\"header\">",
"<section class=\"nestedClassSummary\"><a id=\"nested.class.summary\">\n"
+ "<!-- -->\n"
@@ -349,11 +340,11 @@
"<a id=\"navbar.top.firstrow\">\n"
+ "<!-- -->\n"
+ "</a>",
- "<header role=\"banner\">\n"
+ "<header role=\"banner\" class=\"flexHeader\">\n"
+ "<nav role=\"navigation\">\n"
- + "<div class=\"fixedNav\">\n"
+ "<!-- ========= START OF TOP NAVBAR ======= -->",
"<main role=\"main\">\n"
+ + "<!-- ======== START OF CLASS DATA ======== -->\n"
+ "<div class=\"header\">",
"<section class=\"constantsSummary\"><a id=\"enum.constant.summary\">\n"
+ "<!-- -->\n"
@@ -388,11 +379,11 @@
"<a id=\"navbar.top.firstrow\">\n"
+ "<!-- -->\n"
+ "</a>",
- "<header role=\"banner\">\n"
+ "<header role=\"banner\" class=\"flexHeader\">\n"
+ "<nav role=\"navigation\">\n"
- + "<div class=\"fixedNav\">\n"
+ "<!-- ========= START OF TOP NAVBAR ======= -->",
"<main role=\"main\">\n"
+ + "<!-- ======== START OF CLASS DATA ======== -->\n"
+ "<div class=\"header\">",
"<section class=\"methodSummary\"><a id=\"method.summary\">\n"
+ "<!-- -->\n"
@@ -416,11 +407,11 @@
"<a id=\"navbar.top.firstrow\">\n"
+ "<!-- -->\n"
+ "</a>",
- "<header role=\"banner\">\n"
+ "<header role=\"banner\" class=\"flexHeader\">\n"
+ "<nav role=\"navigation\">\n"
- + "<div class=\"fixedNav\">\n"
+ "<!-- ========= START OF TOP NAVBAR ======= -->",
"<main role=\"main\">\n"
+ + "<!-- ======== START OF CLASS DATA ======== -->\n"
+ "<div class=\"header\">",
"<section class=\"constructorSummary\"><a id=\"constructor.summary\">\n"
+ "<!-- -->\n"
@@ -442,11 +433,11 @@
"<a id=\"navbar.top.firstrow\">\n"
+ "<!-- -->\n"
+ "</a>",
- "<header role=\"banner\">\n"
+ "<header role=\"banner\" class=\"flexHeader\">\n"
+ "<nav role=\"navigation\">\n"
- + "<div class=\"fixedNav\">\n"
+ "<!-- ========= START OF TOP NAVBAR ======= -->",
"<main role=\"main\">\n"
+ + "<!-- ======== START OF CLASS DATA ======== -->\n"
+ "<div class=\"header\">",
"<section class=\"constructorSummary\"><a id=\"constructor.summary\">\n"
+ "<!-- -->\n"
@@ -468,11 +459,11 @@
"<a id=\"navbar.top.firstrow\">\n"
+ "<!-- -->\n"
+ "</a>",
- "<header role=\"banner\">\n"
+ "<header role=\"banner\" class=\"flexHeader\">\n"
+ "<nav role=\"navigation\">\n"
- + "<div class=\"fixedNav\">\n"
+ "<!-- ========= START OF TOP NAVBAR ======= -->",
"<main role=\"main\">\n"
+ + "<!-- ======== START OF CLASS DATA ======== -->\n"
+ "<div class=\"header\">",
"<section class=\"memberSummary\"><a id=\"annotation.type.required.element.summary\">\n"
+ "<!-- -->\n"
@@ -500,9 +491,8 @@
"<a id=\"navbar.top.firstrow\">\n"
+ "<!-- -->\n"
+ "</a>",
- "<header role=\"banner\">\n"
+ "<header role=\"banner\" class=\"flexHeader\">\n"
+ "<nav role=\"navigation\">\n"
- + "<div class=\"fixedNav\">\n"
+ "<!-- ========= START OF TOP NAVBAR ======= -->",
"<main role=\"main\">\n"
+ "<div class=\"header\">",
@@ -528,7 +518,6 @@
"<table summary=\"Package Summary table, listing packages, and an explanation\">\n"
+ "<caption>",
"</noscript>\n"
- + "<div class=\"fixedNav\">\n"
+ "<!-- ========= START OF TOP NAVBAR ======= -->");
// Negated test for package-summary page
@@ -574,11 +563,6 @@
+ "</a>",
"<!-- ========= END OF TOP NAVBAR ========= -->\n"
+ "</div>\n"
- + "<div class=\"navPadding\"> </div>\n"
- + "<script type=\"text/javascript\"><!--\n"
- + "$('.navPadding').css('padding-top', $('.fixedNav').css(\"height\"));\n"
- + "//-->\n"
- + "</script>\n"
+ "<div class=\"header\">",
"<div class=\"constantsSummary\">\n"
+ "<table summary=\"Constant Field Values table, listing constant fields, and values\">");
@@ -592,11 +576,6 @@
+ "</a>",
"<!-- ========= END OF TOP NAVBAR ========= -->\n"
+ "</div>\n"
- + "<div class=\"navPadding\"> </div>\n"
- + "<script type=\"text/javascript\"><!--\n"
- + "$('.navPadding').css('padding-top', $('.fixedNav').css(\"height\"));\n"
- + "//-->\n"
- + "</script>\n"
+ "<div class=\"header\">\n"
+ "<h1 title=\"Deprecated API\" class=\"title\">Deprecated API</h1>\n"
+ "<h2 title=\"Contents\">Contents</h2>",
@@ -620,11 +599,6 @@
+ "</a>",
"<!-- ========= END OF TOP NAVBAR ========= -->\n"
+ "</div>\n"
- + "<div class=\"navPadding\"> </div>\n"
- + "<script type=\"text/javascript\"><!--\n"
- + "$('.navPadding').css('padding-top', $('.fixedNav').css(\"height\"));\n"
- + "//-->\n"
- + "</script>\n"
+ "<div class=\"header\">",
"<li class=\"blockList\">\n"
+ "<h2 title=\"Package\">Package pkg</h2>");
@@ -638,11 +612,6 @@
+ "</a>",
"<!-- ========= END OF TOP NAVBAR ========= -->\n"
+ "</div>\n"
- + "<div class=\"navPadding\"> </div>\n"
- + "<script type=\"text/javascript\"><!--\n"
- + "$('.navPadding').css('padding-top', $('.fixedNav').css(\"height\"));\n"
- + "//-->\n"
- + "</script>\n"
+ "<div class=\"header\">",
"<div class=\"contentContainer\">\n"
+ "<h2 title=\"Class Hierarchy\">Class Hierarchy</h2>",
@@ -660,11 +629,6 @@
+ "</a>",
"<!-- ========= END OF TOP NAVBAR ========= -->\n"
+ "</div>\n"
- + "<div class=\"navPadding\"> </div>\n"
- + "<script type=\"text/javascript\"><!--\n"
- + "$('.navPadding').css('padding-top', $('.fixedNav').css(\"height\"));\n"
- + "//-->\n"
- + "</script>\n"
+ "<div class=\"contentContainer\">");
// Negated test for src-html page
@@ -682,11 +646,6 @@
+ "</a>",
"<!-- ========= END OF TOP NAVBAR ========= -->\n"
+ "</div>\n"
- + "<div class=\"navPadding\"> </div>\n"
- + "<script type=\"text/javascript\"><!--\n"
- + "$('.navPadding').css('padding-top', $('.fixedNav').css(\"height\"));\n"
- + "//-->\n"
- + "</script>\n"
+ "<div class=\"header\">",
"<ul class=\"blockList\">\n"
+ "<li class=\"blockList\">\n"
@@ -703,8 +662,6 @@
"<a name=\"navbar.top.firstrow\">\n"
+ "<!-- -->\n"
+ "</a>",
- "<!-- ======== START OF CLASS DATA ======== -->\n"
- + "<div class=\"header\">",
"<!-- ======== NESTED CLASS SUMMARY ======== -->\n"
+ "<ul class=\"blockList\">\n"
+ "<li class=\"blockList\"><a name=\"nested.class.summary\">\n"
@@ -763,8 +720,6 @@
"<a name=\"navbar.top.firstrow\">\n"
+ "<!-- -->\n"
+ "</a>",
- "<!-- ======== START OF CLASS DATA ======== -->\n"
- + "<div class=\"header\">",
"<!-- =========== ENUM CONSTANT SUMMARY =========== -->\n"
+ "<ul class=\"blockList\">\n"
+ "<li class=\"blockList\"><a name=\"enum.constant.summary\">\n"
@@ -801,8 +756,6 @@
"<a name=\"navbar.top.firstrow\">\n"
+ "<!-- -->\n"
+ "</a>",
- "<!-- ======== START OF CLASS DATA ======== -->\n"
- + "<div class=\"header\">",
"<!-- ========== METHOD SUMMARY =========== -->\n"
+ "<ul class=\"blockList\">\n"
+ "<li class=\"blockList\"><a name=\"method.summary\">\n"
@@ -825,8 +778,6 @@
"<a name=\"navbar.top.firstrow\">\n"
+ "<!-- -->\n"
+ "</a>",
- "<!-- ======== START OF CLASS DATA ======== -->\n"
- + "<div class=\"header\">",
"<!-- ======== CONSTRUCTOR SUMMARY ======== -->\n"
+ "<ul class=\"blockList\">\n"
+ "<li class=\"blockList\"><a name=\"constructor.summary\">\n"
@@ -847,8 +798,6 @@
"<a name=\"navbar.top.firstrow\">\n"
+ "<!-- -->\n"
+ "</a>",
- "<!-- ======== START OF CLASS DATA ======== -->\n"
- + "<div class=\"header\">",
"<!-- ======== CONSTRUCTOR SUMMARY ======== -->\n"
+ "<ul class=\"blockList\">\n"
+ "<li class=\"blockList\"><a name=\"constructor.summary\">\n"
@@ -869,8 +818,6 @@
"<a name=\"navbar.top.firstrow\">\n"
+ "<!-- -->\n"
+ "</a>",
- "<!-- ======== START OF CLASS DATA ======== -->\n"
- + "<div class=\"header\">",
"<!-- =========== ANNOTATION TYPE REQUIRED MEMBER SUMMARY =========== -->\n"
+ "<ul class=\"blockList\">\n"
+ "<li class=\"blockList\"><a name=\"annotation.type.required.element.summary\">\n"
@@ -903,11 +850,6 @@
+ "</a>",
"<!-- ========= END OF TOP NAVBAR ========= -->\n"
+ "</div>\n"
- + "<div class=\"navPadding\"> </div>\n"
- + "<script type=\"text/javascript\"><!--\n"
- + "$('.navPadding').css('padding-top', $('.fixedNav').css(\"height\"));\n"
- + "//-->\n"
- + "</script>\n"
+ "<div class=\"header\">",
"<div class=\"useSummary\">\n"
+ "<table summary=\"Use table, listing packages, and an explanation\">",
--- a/test/langtools/jdk/javadoc/doclet/testJavascript/TestJavascript.java Tue Nov 26 10:22:13 2019 +0000
+++ b/test/langtools/jdk/javadoc/doclet/testJavascript/TestJavascript.java Fri Nov 29 10:02:07 2019 +0000
@@ -23,7 +23,7 @@
/*
* @test
- * @bug 4665566 4855876 7025314 8012375 8015997 8016328 8024756 8148985 8151921 8151743 8196202
+ * @bug 4665566 4855876 7025314 8012375 8015997 8016328 8024756 8148985 8151921 8151743 8196202 8223378
* @summary Verify that the output has the right javascript.
* @author jamieh
* @library ../../lib
@@ -48,18 +48,18 @@
"pkg", testSrc("TestJavascript.java"));
checkExit(Exit.OK);
- checkOutput("pkg/C.html", true,
+ checkOutput("pkg/C.html", false,
"<script type=\"text/javascript\"><!--\n"
+ "$('.navPadding').css('padding-top', $('.fixedNav').css(\"height\"));\n"
+ "//-->\n"
+ "</script>");
- checkOutput("index.html", true,
+ checkOutput("index.html", false,
"<script type=\"text/javascript\"><!--\n"
+ "$('.navPadding').css('padding-top', $('.fixedNav').css(\"height\"));\n"
+ "//-->\n");
- checkOutput("script.js", true,
+ checkOutput("script.js", false,
"$(window).resize(function() {\n"
+ " $('.navPadding').css('padding-top', $('.fixedNav').css(\"height\"));\n"
+ " });");
--- a/test/langtools/jdk/javadoc/doclet/testModules/TestModules.java Tue Nov 26 10:22:13 2019 +0000
+++ b/test/langtools/jdk/javadoc/doclet/testModules/TestModules.java Fri Nov 29 10:02:07 2019 +0000
@@ -27,7 +27,7 @@
* 8168766 8168688 8162674 8160196 8175799 8174974 8176778 8177562 8175218
* 8175823 8166306 8178043 8181622 8183511 8169819 8074407 8183037 8191464
8164407 8192007 8182765 8196200 8196201 8196202 8196202 8205593 8202462
- 8184205 8219060
+ 8184205 8219060 8223378
* @summary Test modules support in javadoc.
* @author bpatel
* @library ../../lib
@@ -533,6 +533,7 @@
checkOutput("index.html", found,
"</nav>\n"
+ "</header>\n"
+ + "<div class=\"flexContent\">\n"
+ "<main role=\"main\">\n"
+ "<div class=\"contentContainer\">\n"
+ "<div class=\"block\">The overview summary page header.</div>\n"
@@ -744,9 +745,9 @@
+ "<th class=\"colLast\" scope=\"col\">Description</th>\n"
+ "</tr>\n"
+ "</thead>",
- "</script>\n"
- + "</nav>\n"
+ "</nav>\n"
+ "</header>\n"
+ + "<div class=\"flexContent\">\n"
+ "<main role=\"main\">\n"
+ "<div class=\"contentContainer\">\n"
+ "<div class=\"block\">The overview summary page header.</div>\n"
--- a/test/langtools/jdk/javadoc/doclet/testNavigation/TestNavigation.java Tue Nov 26 10:22:13 2019 +0000
+++ b/test/langtools/jdk/javadoc/doclet/testNavigation/TestNavigation.java Fri Nov 29 10:02:07 2019 +0000
@@ -24,7 +24,7 @@
/*
* @test
* @bug 4131628 4664607 7025314 8023700 7198273 8025633 8026567 8081854 8150188 8151743 8196027 8182765
- * 8196200 8196202
+ * 8196200 8196202 8223378
* @summary Make sure the Next/Prev Class links iterate through all types.
* Make sure the navagation is 2 columns, not 3.
* @author jamieh
@@ -85,26 +85,23 @@
// Remaining tests check for additional padding to offset the fixed navigation bar.
checkOutput("pkg/A.html", true,
"<!-- ========= END OF TOP NAVBAR ========= -->\n"
- + "</div>\n"
- + "<div class=\"navPadding\"> </div>\n"
- + "<script type=\"text/javascript\"><!--\n"
- + "$('.navPadding').css('padding-top', $('.fixedNav').css(\"height\"));\n"
- + "//-->\n"
- + "</script>\n"
+ + "<div class=\"skipNav\"><a id=\"skip.navbar.top\">\n"
+ + "<!-- -->\n"
+ + "</a></div>\n"
+ "</nav>\n"
+ "</header>\n"
+ + "<div class=\"flexContent\">\n"
+ + "<main role=\"main\">\n"
+ "<!-- ======== START OF CLASS DATA ======== -->");
checkOutput("pkg/package-summary.html", true,
"<!-- ========= END OF TOP NAVBAR ========= -->\n"
- + "</div>\n"
- + "<div class=\"navPadding\"> </div>\n"
- + "<script type=\"text/javascript\"><!--\n"
- + "$('.navPadding').css('padding-top', $('.fixedNav').css(\"height\"));\n"
- + "//-->\n"
- + "</script>\n"
+ + "<div class=\"skipNav\"><a id=\"skip.navbar.top\">\n"
+ + "<!-- -->\n"
+ + "</a></div>\n"
+ "</nav>\n"
+ "</header>\n"
+ + "<div class=\"flexContent\">\n"
+ "<main role=\"main\">\n"
+ "<div class=\"header\">");
}
@@ -121,24 +118,20 @@
checkOutput("pkg/A.html", true,
"<!-- ========= END OF TOP NAVBAR ========= -->\n"
- + "</div>\n"
- + "<div class=\"navPadding\"> </div>\n"
- + "<script type=\"text/javascript\"><!--\n"
- + "$('.navPadding').css('padding-top', $('.fixedNav').css(\"height\"));\n"
- + "//-->\n"
- + "</script>\n"
+ + "<div class=\"skipNav\"><a id=\"skip.navbar.top\">\n"
+ + "<!-- -->\n"
+ + "</a></div>\n"
+ "</nav>\n"
+ "</header>\n"
+ + "<div class=\"flexContent\">\n"
+ + "<main role=\"main\">\n"
+ "<!-- ======== START OF CLASS DATA ======== -->");
checkOutput("pkg/package-summary.html", true,
"<!-- ========= END OF TOP NAVBAR ========= -->\n"
- + "</div>\n"
- + "<div class=\"navPadding\"> </div>\n"
- + "<script type=\"text/javascript\"><!--\n"
- + "$('.navPadding').css('padding-top', $('.fixedNav').css(\"height\"));\n"
- + "//-->\n"
- + "</script>\n"
+ + "<div class=\"skipNav\"><a id=\"skip.navbar.top\">\n"
+ + "<!-- -->\n"
+ + "</a></div>\n"
+ "</nav>");
}
@@ -155,11 +148,9 @@
checkOutput("pkg/A.html", false,
"<!-- ========= END OF TOP NAVBAR ========= -->\n"
+ "</div>\n"
- + "<div class=\"navPadding\"> </div>\n"
- + "<script type=\"text/javascript\"><!--\n"
- + "$('.navPadding').css('padding-top', $('.fixedNav').css(\"height\"));\n"
- + "//-->\n"
- + "</script>\n"
+ + "<div class=\"skipNav\"><a id=\"skip.navbar.top\">\n"
+ + "<!-- -->\n"
+ + "</a></div>\n"
+ "</nav>\n"
+ "</header>\n"
+ "<!-- ======== START OF CLASS DATA ======== -->");
@@ -167,11 +158,9 @@
checkOutput("pkg/package-summary.html", false,
"<!-- ========= END OF TOP NAVBAR ========= -->\n"
+ "</div>\n"
- + "<div class=\"navPadding\"> </div>\n"
- + "<script type=\"text/javascript\"><!--\n"
- + "$('.navPadding').css('padding-top', $('.fixedNav').css(\"height\"));\n"
- + "//-->\n"
- + "</script>\n"
+ + "<div class=\"skipNav\"><a id=\"skip.navbar.top\">\n"
+ + "<!-- -->\n"
+ + "</a></div>\n"
+ "</nav>");
}
--- a/test/langtools/jdk/javadoc/doclet/testSearch/TestSearch.java Tue Nov 26 10:22:13 2019 +0000
+++ b/test/langtools/jdk/javadoc/doclet/testSearch/TestSearch.java Fri Nov 29 10:02:07 2019 +0000
@@ -25,7 +25,7 @@
* @test
* @bug 8141492 8071982 8141636 8147890 8166175 8168965 8176794 8175218 8147881
* 8181622 8182263 8074407 8187521 8198522 8182765 8199278 8196201 8196202
- * 8184205 8214468 8222548
+ * 8184205 8214468 8222548 8223378
* @summary Test the search feature of javadoc.
* @author bpatel
* @library ../../lib
@@ -385,7 +385,7 @@
+ "<input type=\"text\" id=\"search\" value=\"search\" disabled=\"disabled\">\n"
+ "<input type=\"reset\" id=\"reset\" value=\"reset\" disabled=\"disabled\">\n");
checkOutput(fileName, true,
- "<div class=\"fixedNav\">");
+ "<div class=\"flexBox\">");
}
void checkSingleIndex(boolean expectedOutput, boolean html5) {
--- a/test/langtools/jdk/javadoc/doclet/testSearchScript/javadoc-search.js Tue Nov 26 10:22:13 2019 +0000
+++ b/test/langtools/jdk/javadoc/doclet/testSearchScript/javadoc-search.js Fri Nov 29 10:02:07 2019 +0000
@@ -52,29 +52,29 @@
f();
} else {
return {
- val: function() {
- return this;
+ val: function() {
+ return this;
},
- prop: function() {
- return this;
+ prop: function() {
+ return this;
},
- addClass: function() {
- return this;
- },
- removeClass: function() {
- return this;
+ addClass: function() {
+ return this;
+ },
+ removeClass: function() {
+ return this;
},
- on: function() {
- return this;
+ on: function() {
+ return this;
},
- focus: function() {
- return this;
+ focus: function() {
+ return this;
},
- blur: function() {
- return this;
+ blur: function() {
+ return this;
},
- click: function() {
- return this;
+ click: function() {
+ return this;
},
catcomplete: function(o) {
o.close = function() {};
@@ -90,11 +90,11 @@
return resultList;
};
for (var i = 0; i < clargs.length; i++) {
- search(clargs[i]);
+ search(clargs[i]);
}
},
"0": {
- setSelectionRange: function() {
+ setSelectionRange: function() {
return this;
}
}
--- a/test/langtools/jdk/javadoc/doclet/testStylesheet/TestStylesheet.java Tue Nov 26 10:22:13 2019 +0000
+++ b/test/langtools/jdk/javadoc/doclet/testStylesheet/TestStylesheet.java Fri Nov 29 10:02:07 2019 +0000
@@ -24,7 +24,7 @@
/*
* @test
* @bug 4494033 7028815 7052425 8007338 8023608 8008164 8016549 8072461 8154261 8162363 8160196 8151743 8177417
- * 8175218 8176452 8181215 8182263 8183511 8169819 8183037 8185369 8182765 8196201 8184205
+ * 8175218 8176452 8181215 8182263 8183511 8169819 8183037 8185369 8182765 8196201 8184205 8223378
* @summary Run tests on doclet stylesheet.
* @author jamieh
* @library ../../lib
@@ -143,18 +143,8 @@
+ " padding:0px 0px 12px 10px;\n"
+ "}",
"@import url('resources/fonts/dejavu.css');",
- ".navPadding {\n"
- + " padding-top: 107px;\n"
- + "}",
- "a[name]:before, a[name]:target, a[id]:before, a[id]:target {\n"
- + " content:\"\";\n"
- + " display:inline-block;\n"
- + " position:relative;\n"
- + " padding-top:129px;\n"
- + " margin-top:-129px;\n"
- + "}",
- ".searchTagResult:before, .searchTagResult:target {\n"
- + " color:red;\n"
+ ".searchTagResult:target {\n"
+ + " background-color:yellow;\n"
+ "}",
"a[href]:hover, a[href]:focus {\n"
+ " text-decoration:none;\n"
@@ -190,7 +180,7 @@
+ " background-size:12px;\n"
+ " border:0 none;\n"
+ " width:16px;\n"
- + " height:17px;\n"
+ + " height:16px;\n"
+ " position:relative;\n"
+ " left:-4px;\n"
+ " top:-4px;\n"
--- a/test/langtools/jdk/javadoc/doclet/testTopOption/TestTopOption.java Tue Nov 26 10:22:13 2019 +0000
+++ b/test/langtools/jdk/javadoc/doclet/testTopOption/TestTopOption.java Fri Nov 29 10:02:07 2019 +0000
@@ -23,7 +23,7 @@
/*
* @test
- * @bug 6227616 8043186 8196202
+ * @bug 6227616 8043186 8196202 8223378
* @summary Test the new -top option.
* @author jamieh
* @library ../../lib
@@ -87,6 +87,30 @@
"help-doc.html");
}
+ @Test
+ public void testNoNavbar() {
+ javadoc("-overview", testSrc("overview.html"),
+ "-use",
+ "-top", "TOP TEXT",
+ "-nonavbar",
+ "-d", "out-3",
+ "-sourcepath", testSrc,
+ "pkg");
+ checkExit(Exit.OK);
+
+ checkTopText(
+ "pkg/AnnotationType.html",
+ "pkg/class-use/AnnotationType.html",
+ "pkg/Cl.html",
+ "pkg/class-use/Cl.html",
+ "pkg/package-summary.html",
+ "pkg/package-use.html",
+ "index.html",
+ "overview-tree.html",
+ "constant-values.html",
+ "help-doc.html");
+ }
+
void checkTopText(String... files) {
for (String file : files) {
checkOutput(file, true, "TOP TEXT");
--- a/test/langtools/tools/javac/annotations/typeAnnotations/classfile/ClassfileTestHelper.java Tue Nov 26 10:22:13 2019 +0000
+++ b/test/langtools/tools/javac/annotations/typeAnnotations/classfile/ClassfileTestHelper.java Fri Nov 29 10:02:07 2019 +0000
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2012, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 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
@@ -27,12 +27,14 @@
import java.util.List;
import com.sun.tools.classfile.*;
+import java.util.ArrayList;
public class ClassfileTestHelper {
int expected_tinvisibles = 0;
int expected_tvisibles = 0;
int expected_invisibles = 0;
int expected_visibles = 0;
+ List<String> extraOptions = List.of();
//Makes debugging much easier. Set to 'false' for less output.
public Boolean verbose = true;
@@ -48,8 +50,9 @@
}
File compile(File f) {
- int rc = com.sun.tools.javac.Main.compile(new String[] {
- "-g", f.getPath() });
+ List<String> options = new ArrayList<>(List.of("-g", f.getPath()));
+ options.addAll(extraOptions);
+ int rc = com.sun.tools.javac.Main.compile(options.toArray(new String[0]));
if (rc != 0)
throw new Error("compilation failed. rc=" + rc);
String path = f.getPath();
--- a/test/langtools/tools/javac/annotations/typeAnnotations/classfile/CombinationsTargetTest2.java Tue Nov 26 10:22:13 2019 +0000
+++ b/test/langtools/tools/javac/annotations/typeAnnotations/classfile/CombinationsTargetTest2.java Fri Nov 29 10:02:07 2019 +0000
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2013, 2015, 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
@@ -30,9 +30,13 @@
import com.sun.tools.classfile.*;
import java.io.File;
+import java.util.List;
public class CombinationsTargetTest2 extends ClassfileTestHelper {
+ private static final String JDK_VERSION =
+ Integer.toString(Runtime.getRuntime().version().feature());
+
// Test count helps identify test case in event of failure.
int testcount = 0;
@@ -45,7 +49,9 @@
src5("(repeating) type annotations on field in anonymous class", false),
src6("(repeating) type annotations on void method declaration", false),
src7("(repeating) type annotations in use of instanceof", true),
- src8("(repeating) type annotations in use of instanceof in method", true);
+ src7p("(repeating) type annotations in use of instanceof with type test pattern", true),
+ src8("(repeating) type annotations in use of instanceof in method", true),
+ src8p("(repeating) type annotations in use of instanceof with type test pattern in method", true);
String description;
Boolean local;
@@ -92,8 +98,12 @@
test( 0, 0, 0, 2, As, BDs, ABMix, "RUNTIME", et, ++testrun, srce.src6);
test( 2, 0, 0, 0, As, BDs, ABMix, "CLASS", et, ++testrun, srce.src7);
test( 0, 2, 0, 0, As, BDs, ABMix, "RUNTIME", et, ++testrun, srce.src7);
+ test( 2, 0, 0, 0, As, BDs, ABMix, "CLASS", et, ++testrun, srce.src7p);
+ test( 0, 2, 0, 0, As, BDs, ABMix, "RUNTIME", et, ++testrun, srce.src7p);
test( 4, 0, 0, 0, As, BDs, ABMix, "CLASS", et, ++testrun, srce.src8);
test( 0, 4, 0, 0, As, BDs, ABMix, "RUNTIME", et, ++testrun, srce.src8);
+ test( 4, 0, 0, 0, As, BDs, ABMix, "CLASS", et, ++testrun, srce.src8p);
+ test( 0, 4, 0, 0, As, BDs, ABMix, "RUNTIME", et, ++testrun, srce.src8p);
break;
case "FIELD":
test( 8, 0, 0, 0, As, BDs, ABMix, "CLASS", et, ++testrun, srce.src1);
@@ -122,6 +132,7 @@
expected_tinvisibles = tinv;
expected_visibles = vis;
expected_invisibles = inv;
+ extraOptions = List.of();
File testFile = null;
String tname="Test" + N.toString();
hasInnerClass=false;
@@ -385,6 +396,24 @@
"\n\n";
hasInnerClass=false;
break;
+ case src7p: // (repeating) type annotations in use of instanceof with type test pattern
+ /*
+ * class Test10{
+ * String data = "test";
+ * boolean dataIsString = ( data instanceof @A @B @A @B String str);
+ * }
+ */
+ source = new String( source +
+ "// " + src.description + "\n" +
+ "class "+ testname + "{\n" +
+ " String data = \"test\";\n" +
+ " boolean dataIsString = ( data instanceof _As_ _Bs_ String str && str.isEmpty());\n" +
+ "}\n").concat(sourceBase).replace("_OTHER_", annot2).replace("_As_",As).replace("_Bs_",Bs) +
+ "\n\n";
+ extraOptions = List.of("--enable-preview",
+ "-source", JDK_VERSION);
+ hasInnerClass=false;
+ break;
case src8: // (repeating) type annotations in use of instanceof
/*
* class Test20{
@@ -411,6 +440,34 @@
"\n\n";
hasInnerClass=false;
break;
+ case src8p: // (repeating) type annotations in use of instanceof with type test pattern
+ /*
+ * class Test20{
+ * String data = "test";
+ * Boolean isString() {
+ * if( data instanceof @A @B @A @B String )
+ * return true;
+ * else
+ * return( data instanceof @A @B @A @B String );
+ * }
+ * }
+ */
+ source = new String( source +
+ "// " + src.description + "\n" +
+ "class "+ testname + "{\n" +
+ " String data = \"test\";\n" +
+ " Boolean isString() { \n" +
+ " if( data instanceof _As_ _Bs_ String str)\n" +
+ " return true;\n" +
+ " else\n" +
+ " return( data instanceof _As_ _Bs_ String str && str.isEmpty());\n" +
+ " }\n" +
+ "}\n").concat(sourceBase).replace("_OTHER_", annot2).replace("_As_",As).replace("_Bs_",Bs) +
+ "\n\n";
+ extraOptions = List.of("--enable-preview",
+ "-source", JDK_VERSION);
+ hasInnerClass=false;
+ break;
}
return imports + source;
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/annotations/typeAnnotations/classfile/Patterns.java Fri Nov 29 10:02:07 2019 +0000
@@ -0,0 +1,222 @@
+/*
+ * 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
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @summary Verify type annotation on binding patterns
+ * @library /tools/lib
+ * @modules java.compiler
+ * jdk.jdeps/com.sun.tools.javap
+ * @build toolbox.JavapTask
+ * @compile --enable-preview -source ${jdk.version} Patterns.java
+ * @run main/othervm --enable-preview Patterns
+ */
+
+import java.lang.annotation.*;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+import java.util.stream.Collectors;
+
+import toolbox.JavapTask;
+import toolbox.Task;
+import toolbox.ToolBox;
+
+public class Patterns {
+
+ private ToolBox tb = new ToolBox();
+
+ public static void main(String[] args) throws Exception {
+ new Patterns().run();
+ }
+
+ public void run() throws Exception {
+ String out = new JavapTask(tb)
+ .options("-private",
+ "-verbose")
+ .classpath(System.getProperty("test.classes"))
+ .classes("Patterns$SimpleBindingPattern")
+ .run()
+ .getOutputLines(Task.OutputKind.DIRECT)
+ .stream()
+ .collect(Collectors.joining("\n"));
+
+ String constantPool = out.substring(0, out.indexOf('{'));
+
+ out = out.replaceAll("(?ms) *Code:.*?\n( *RuntimeInvisibleTypeAnnotations:)", "$1");
+ out = out.substring(out.indexOf('{'));
+ out = out.substring(0, out.lastIndexOf('}') + 1);
+
+ String A = snipCPNumber(constantPool, "LPatterns$SimpleBindingPattern$A;");
+ String CA = snipCPNumber(constantPool, "LPatterns$SimpleBindingPattern$CA;");
+ String value = snipCPNumber(constantPool, "value");
+
+ String expected = """
+ {
+ private static final java.lang.Object o;
+ descriptor: Ljava/lang/Object;
+ flags: (0x001a) ACC_PRIVATE, ACC_STATIC, ACC_FINAL
+
+ private static final boolean B1s;
+ descriptor: Z
+ flags: (0x001a) ACC_PRIVATE, ACC_STATIC, ACC_FINAL
+
+ private static final boolean B1m;
+ descriptor: Z
+ flags: (0x001a) ACC_PRIVATE, ACC_STATIC, ACC_FINAL
+
+ private final boolean B2s;
+ descriptor: Z
+ flags: (0x0012) ACC_PRIVATE, ACC_FINAL
+
+ private final boolean B2m;
+ descriptor: Z
+ flags: (0x0012) ACC_PRIVATE, ACC_FINAL
+
+ public Patterns$SimpleBindingPattern();
+ descriptor: ()V
+ flags: (0x0001) ACC_PUBLIC
+ RuntimeInvisibleTypeAnnotations:
+ 0: #_A_(): LOCAL_VARIABLE, {start_pc=257, length=18, index=2}
+ Patterns$SimpleBindingPattern$A
+ 1: #_CA_(#_value_=[@#_A_(),@#_A_()]): LOCAL_VARIABLE, {start_pc=297, length=19, index=3}
+ Patterns$SimpleBindingPattern$CA(
+ value=[@Patterns$SimpleBindingPattern$A,@Patterns$SimpleBindingPattern$A]
+ )
+ 2: #_A_(): LOCAL_VARIABLE, {start_pc=22, length=18, index=1}
+ Patterns$SimpleBindingPattern$A
+ 3: #_CA_(#_value_=[@#_A_(),@#_A_()]): LOCAL_VARIABLE, {start_pc=62, length=18, index=1}
+ Patterns$SimpleBindingPattern$CA(
+ value=[@Patterns$SimpleBindingPattern$A,@Patterns$SimpleBindingPattern$A]
+ )
+ 4: #_A_(): LOCAL_VARIABLE, {start_pc=101, length=18, index=2}
+ Patterns$SimpleBindingPattern$A
+ 5: #_CA_(#_value_=[@#_A_(),@#_A_()]): LOCAL_VARIABLE, {start_pc=141, length=19, index=3}
+ Patterns$SimpleBindingPattern$CA(
+ value=[@Patterns$SimpleBindingPattern$A,@Patterns$SimpleBindingPattern$A]
+ )
+ 6: #_A_(): LOCAL_VARIABLE, {start_pc=179, length=18, index=2}
+ Patterns$SimpleBindingPattern$A
+ 7: #_CA_(#_value_=[@#_A_(),@#_A_()]): LOCAL_VARIABLE, {start_pc=219, length=19, index=3}
+ Patterns$SimpleBindingPattern$CA(
+ value=[@Patterns$SimpleBindingPattern$A,@Patterns$SimpleBindingPattern$A]
+ )
+
+ void testPatterns();
+ descriptor: ()V
+ flags: (0x0000)
+ RuntimeInvisibleTypeAnnotations:
+ 0: #_A_(): LOCAL_VARIABLE, {start_pc=17, length=18, index=2}
+ Patterns$SimpleBindingPattern$A
+ 1: #_CA_(#_value_=[@#_A_(),@#_A_()]): LOCAL_VARIABLE, {start_pc=57, length=19, index=3}
+ Patterns$SimpleBindingPattern$CA(
+ value=[@Patterns$SimpleBindingPattern$A,@Patterns$SimpleBindingPattern$A]
+ )
+
+ void testPatternsDesugared();
+ descriptor: ()V
+ flags: (0x0000)
+ RuntimeInvisibleTypeAnnotations:
+ 0: #_A_(): LOCAL_VARIABLE, {start_pc=17, length=15, index=1; start_pc=51, length=15, index=1}
+ Patterns$SimpleBindingPattern$A
+
+ static {};
+ descriptor: ()V
+ flags: (0x0008) ACC_STATIC
+ RuntimeInvisibleTypeAnnotations:
+ 0: #_A_(): LOCAL_VARIABLE, {start_pc=22, length=18, index=0}
+ Patterns$SimpleBindingPattern$A
+ 1: #_CA_(#_value_=[@#_A_(),@#_A_()]): LOCAL_VARIABLE, {start_pc=61, length=18, index=0}
+ Patterns$SimpleBindingPattern$CA(
+ value=[@Patterns$SimpleBindingPattern$A,@Patterns$SimpleBindingPattern$A]
+ )
+ 2: #_A_(): LOCAL_VARIABLE, {start_pc=100, length=18, index=1}
+ Patterns$SimpleBindingPattern$A
+ 3: #_CA_(#_value_=[@#_A_(),@#_A_()]): LOCAL_VARIABLE, {start_pc=137, length=18, index=2}
+ Patterns$SimpleBindingPattern$CA(
+ value=[@Patterns$SimpleBindingPattern$A,@Patterns$SimpleBindingPattern$A]
+ )
+ }""".replace("_A_", A).replace("_CA_", CA).replace("_value_", value);
+
+ if (!expected.equals(out)) {
+ throw new AssertionError("Unexpected output:\n" + out + "\nexpected:\n" + expected);
+ }
+ }
+
+ private String snipCPNumber(String constantPool, String expectedConstant) {
+ Matcher m = Pattern.compile("#([0-9]+).*" + Pattern.quote(expectedConstant))
+ .matcher(constantPool);
+ if (!m.find()) {
+ throw new AssertionError("Cannot find constant pool item");
+ }
+
+ return m.group(1);
+ }
+
+ /*********************** Test class *************************/
+ static class SimpleBindingPattern {
+ @Target(ElementType.TYPE_USE)
+ @Repeatable(CA.class)
+ @interface A {}
+ @Target(ElementType.TYPE_USE)
+ @interface CA {
+ public A[] value();
+ }
+
+ private static final Object o = "";
+ private static final boolean B1s = o instanceof @A String s && s.isEmpty();
+ private static final boolean B1m = o instanceof @A @A String s && s.isEmpty();
+ private final boolean B2s = o instanceof @A String s && s.isEmpty();
+ private final boolean B2m = o instanceof @A @A String s && s.isEmpty();
+
+ static {
+ boolean B3s = o instanceof @A String s && s.isEmpty();
+ boolean B3m = o instanceof @A @A String s && s.isEmpty();
+ }
+
+ {
+ boolean B4s = o instanceof @A String s && s.isEmpty();
+ boolean B4m = o instanceof @A @A String s && s.isEmpty();
+ }
+
+ {
+ boolean B5s = o instanceof @A String s && s.isEmpty();
+ boolean B5m = o instanceof @A @A String s && s.isEmpty();
+ }
+
+ public SimpleBindingPattern() {
+ boolean B6s = o instanceof @A String s && s.isEmpty();
+ boolean B6m = o instanceof @A @A String s && s.isEmpty();
+ }
+
+ void testPatterns() {
+ boolean B7s = o instanceof @A String s && s.isEmpty();
+ boolean B7m = o instanceof @A @A String s && s.isEmpty();
+ }
+
+ void testPatternsDesugared() {
+ @A String s;
+ boolean B8s = o instanceof String && (s = (String) o) == s && s.isEmpty();
+ boolean B8sx = o instanceof String && (s = (String) o) == s && s.isEmpty();
+ }
+ }
+}
--- a/test/langtools/tools/javac/api/TestGetElementReference.java Tue Nov 26 10:22:13 2019 +0000
+++ b/test/langtools/tools/javac/api/TestGetElementReference.java Fri Nov 29 10:02:07 2019 +0000
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2013, 2015, 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
@@ -51,6 +51,9 @@
public class TestGetElementReference {
+ private static final String JDK_VERSION =
+ Integer.toString(Runtime.getRuntime().version().feature());
+
public static void main(String... args) throws IOException {
analyze("TestGetElementReferenceData.java");
analyze("mod/module-info.java", "mod/api/pkg/Api.java");
@@ -66,7 +69,10 @@
}
}
DiagnosticCollector<JavaFileObject> diagnostics = new DiagnosticCollector<>();
- JavacTask ct = (JavacTask) ToolProvider.getSystemJavaCompiler().getTask(null, null, diagnostics, Arrays.asList("-Xjcov"), null, files);
+ List<String> options = List.of("-Xjcov",
+ "--enable-preview",
+ "-source", JDK_VERSION);
+ JavacTask ct = (JavacTask) ToolProvider.getSystemJavaCompiler().getTask(null, null, diagnostics, options, null, files);
Trees trees = Trees.instance(ct);
CompilationUnitTree cut = ct.parse().iterator().next();
--- a/test/langtools/tools/javac/api/TestGetElementReferenceData.java Tue Nov 26 10:22:13 2019 +0000
+++ b/test/langtools/tools/javac/api/TestGetElementReferenceData.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
@@ -35,6 +35,8 @@
java.util.List< /*getElement:INTERFACE:java.util.List*/ String> l;
utility/*getElement:METHOD:test.TestGetElementReferenceData.Base.utility()*/();
target(TestGetElementReferenceData :: test/*getElement:METHOD:test.TestGetElementReferenceData.test()*/);
+ Object/*getElement:CLASS:java.lang.Object*/ o = null;
+ if (o/*getElement:LOCAL_VARIABLE:o*/ instanceof String/*getElement:CLASS:java.lang.String*/ str/*getElement:LOCAL_VARIABLE:str*/) ;
}
private static void target(Runnable r) { r.run(); }
public static class Base {
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/diags/examples/InstanceofReifiableNotSafe.java Fri Nov 29 10:02:07 2019 +0000
@@ -0,0 +1,35 @@
+/*
+ * 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.
+ */
+
+// key: compiler.err.instanceof.reifiable.not.safe
+// key: compiler.note.preview.filename
+// key: compiler.note.preview.recompile
+// options: --enable-preview -source ${jdk.version}
+
+import java.util.List;
+
+class InstanceofReifiableNotSafe {
+ boolean test(Object o) {
+ return o instanceof List<String> l;
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/diags/examples/MatchBindingExists.java Fri Nov 29 10:02:07 2019 +0000
@@ -0,0 +1,33 @@
+/*
+ * 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.
+ *
+ * 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.
+ */
+
+// key: compiler.err.match.binding.exists
+// key: compiler.note.preview.filename
+// key: compiler.note.preview.recompile
+// options: --enable-preview -source ${jdk.version}
+
+class MatchBindingExists {
+ public void test(Object o1, Object o2) {
+ if (o1 instanceof String k && o2 instanceof Integer k) {}
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/diags/examples/PatternBindingMayNotBeAssigned.java Fri Nov 29 10:02:07 2019 +0000
@@ -0,0 +1,35 @@
+/*
+ * 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.
+ *
+ * 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.
+ */
+
+// key: compiler.err.pattern.binding.may.not.be.assigned
+// key: compiler.note.preview.filename
+// key: compiler.note.preview.recompile
+// options: --enable-preview -source ${jdk.version}
+
+class ResourceMayNotBeAssigned {
+ void m(Object o) {
+ if (o instanceof String s) {
+ s = "";
+ }
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/diags/examples/PatternMatchingInstanceof.java Fri Nov 29 10:02:07 2019 +0000
@@ -0,0 +1,32 @@
+/*
+ * 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.
+ */
+
+// key: compiler.misc.feature.pattern.matching.instanceof
+// key: compiler.warn.preview.feature.use
+// options: --enable-preview -source ${jdk.version} -Xlint:preview
+
+class PatternMatchingInstanceof {
+ boolean m(Object o) {
+ return o instanceof String s && s.isEmpty();
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/diags/examples/ReifiableTypesInstanceof.java Fri Nov 29 10:02:07 2019 +0000
@@ -0,0 +1,34 @@
+/*
+ * 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.
+ */
+
+// key: compiler.misc.feature.reifiable.types.instanceof
+// key: compiler.warn.preview.feature.use.plural
+// options: --enable-preview -source ${jdk.version} -Xlint:preview
+
+class PatternMatchingInstanceof {
+ boolean m(I<String> i) {
+ return i instanceof C<String>;
+ }
+ interface I<T> {}
+ class C<T> implements I<T> {}
+}
--- a/test/langtools/tools/javac/lambda/deduplication/Deduplication.java Tue Nov 26 10:22:13 2019 +0000
+++ b/test/langtools/tools/javac/lambda/deduplication/Deduplication.java Fri Nov 29 10:02:07 2019 +0000
@@ -163,6 +163,9 @@
group((Function<Integer, Integer>) x -> switch (x) { default: yield x; },
(Function<Integer, Integer>) x -> switch (x) { default: yield x; });
+
+ group((Function<Object, Integer>) x -> x instanceof Integer i ? i : -1,
+ (Function<Object, Integer>) x -> x instanceof Integer i ? i : -1);
}
void f() {}
--- a/test/langtools/tools/javac/lib/DPrinter.java Tue Nov 26 10:22:13 2019 +0000
+++ b/test/langtools/tools/javac/lib/DPrinter.java Fri Nov 29 10:02:07 2019 +0000
@@ -880,7 +880,7 @@
@Override
public void visitTypeTest(JCInstanceOf tree) {
printTree("expr", tree.expr);
- printTree("clazz", tree.clazz);
+ printTree("pattern", tree.pattern);
}
@Override
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/patterns/BindingsExistTest.java Fri Nov 29 10:02:07 2019 +0000
@@ -0,0 +1,30 @@
+/*
+ * @test /nodynamiccopyright/
+ * @bug 8231827
+ * @summary Clashing bindings are reported correctly
+ * @compile/fail/ref=BindingsExistTest.out -XDrawDiagnostics --enable-preview -source ${jdk.version} BindingsExistTest.java
+ */
+public class BindingsExistTest {
+ public void t(Object o1, Object o2) {
+ if (o1 instanceof String k && o2 instanceof Integer k) {}
+
+ if (o1 instanceof String k || o2 instanceof Integer k) {}
+
+ if (!(o1 instanceof String k)) {
+ return ;
+ }
+ if (o1 instanceof Integer k) {}
+
+ String s2 = "";
+ if (o1 instanceof String s2) {}
+
+ if (o1 instanceof String s3) {
+ String s3 = "";
+ }
+
+ if (!(o1 instanceof String s4)) {
+ return ;
+ }
+ String s4 = "";
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/patterns/BindingsExistTest.out Fri Nov 29 10:02:07 2019 +0000
@@ -0,0 +1,9 @@
+BindingsExistTest.java:9:36: compiler.err.match.binding.exists
+BindingsExistTest.java:11:36: compiler.err.match.binding.exists
+BindingsExistTest.java:16:35: compiler.err.already.defined: kindname.variable, k, kindname.method, t(java.lang.Object,java.lang.Object)
+BindingsExistTest.java:19:34: compiler.err.already.defined: kindname.variable, s2, kindname.method, t(java.lang.Object,java.lang.Object)
+BindingsExistTest.java:22:20: compiler.err.already.defined: kindname.variable, s3, kindname.method, t(java.lang.Object,java.lang.Object)
+BindingsExistTest.java:28:16: compiler.err.already.defined: kindname.variable, s4, kindname.method, t(java.lang.Object,java.lang.Object)
+- compiler.note.preview.filename: BindingsExistTest.java
+- compiler.note.preview.recompile
+6 errors
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/patterns/BindingsTest1.java Fri Nov 29 10:02:07 2019 +0000
@@ -0,0 +1,166 @@
+/*
+ * 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.
+ *
+ * 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 8231827
+ * @summary Basic tests for bindings from instanceof
+ * @compile --enable-preview -source ${jdk.version} BindingsTest1.java
+ * @run main/othervm --enable-preview BindingsTest1
+ */
+
+public class BindingsTest1 {
+ public static boolean Ktrue() { return true; }
+ public static void main(String[] args) {
+ Object o1 = "hello";
+ Integer i = 42;
+ Object o2 = i;
+ Object o3 = "there";
+
+
+ // Test for (e matches P).T = { binding variables in P }
+ if (o1 instanceof String s) {
+ s.length();
+ }
+
+ // Test for e1 && e2.T = union(e1.T, e2.T)
+ if (o1 instanceof String s && o2 instanceof Integer in) {
+ s.length();
+ in.intValue();
+ }
+
+ // test for e1&&e2 - include e1.T in e2
+ if (o1 instanceof String s && s.length()>0) {
+ System.out.print("done");
+ }
+
+ // Test for (e1 || e2).F = union(e1.F, e2.F)
+ if (!(o1 instanceof String s) || !(o3 instanceof Integer in)){
+ } else {
+ s.length();
+ i.intValue();
+ }
+
+ // Test for e1||e2 - include e1.F in e2
+
+ if (!(o1 instanceof String s) || s.length()>0) {
+ System.out.println("done");
+ }
+
+ // Test for e1 ? e2: e3 - include e1.T in e2
+ if (o1 instanceof String s ? s.length()>0 : false) {
+ System.out.println("done");
+ }
+
+ // Test for e1 ? e2 : e3 - include e1.F in e3
+ if (!(o1 instanceof String s) ? false : s.length()>0){
+ System.out.println("done");
+ }
+
+ // Test for (!e).T = e.F
+
+ if (!(!(o1 instanceof String s) || !(o3 instanceof Integer in))){
+ s.length();
+ i.intValue();
+ }
+
+ // Test for (!e).F = e.T
+ if (!(o1 instanceof String s)) {
+
+ } else {
+ s.length();
+ }
+
+ L1: {
+ if (o1 instanceof String s) {
+ s.length();
+ } else {
+ break L1;
+ }
+ s.length();
+ }
+
+ L2: {
+ if (!(o1 instanceof String s)) {
+ break L2;
+ } else {
+ s.length();
+ }
+ s.length();
+ }
+
+ L4: {
+ if (!(o1 instanceof String s)) {
+ break L4;
+ }
+ s.length();
+ }
+
+ {
+ while (!(o1 instanceof String s)) {
+ }
+
+ s.length();
+ }
+
+ L5: {
+ while (!(o1 instanceof String s)) {
+ }
+
+ s.length();
+ }
+
+ {
+ L6: for ( ;!(o1 instanceof String s); ) {
+
+ }
+
+ s.length();
+ }
+
+ {
+ L7: do {
+
+ } while (!(o1 instanceof String s));
+
+ s.length();
+ }
+
+ if (o1 instanceof String s) {
+ Runnable r1 = new Runnable() {
+ @Override
+ public void run() {
+ s.length();
+ }
+ };
+ r1.run();
+ Runnable r2 = () -> {
+ s.length();
+ };
+ r2.run();
+ String s2 = s;
+ }
+
+ System.out.println("BindingsTest1 complete");
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/patterns/BindingsTest1Merging.java Fri Nov 29 10:02:07 2019 +0000
@@ -0,0 +1,72 @@
+/*
+ * @test /nodynamiccopyright/
+ * @bug 8231827
+ * @summary Basic tests for bindings from instanceof - tests for merging pattern variables
+ * @compile/fail/ref=BindingsTest1Merging.out -XDrawDiagnostics --enable-preview -source ${jdk.version} BindingsTest1Merging.java
+ */
+
+public class BindingsTest1Merging {
+ public static boolean Ktrue() { return true; }
+ public static void main(String[] args) {
+ Object o1 = "hello";
+ Integer i = 42;
+ Object o2 = i;
+ Object o3 = "there";
+
+ // Test for e1 && e2.F = intersect(e1.F, e2.F)
+ if (!(o1 instanceof String s) && !(o1 instanceof String s)) {
+
+ } else {
+ s.length();
+ }
+
+ // Test for (e1 || e2).T = intersect(e1.T, e2.T)
+ if (o1 instanceof String s || o3 instanceof String s){
+ System.out.println(s); // ?
+ }
+
+ // Test for (e1 ? e2 : e3).T contains intersect(e2.T, e3.T)
+ if (Ktrue() ? o2 instanceof Integer x : o2 instanceof Integer x) {
+ x.intValue();
+ }
+
+ // Test for (e1 ? e2 : e3).T contains intersect(e1.T, e3.T)
+ if (o1 instanceof String s ? true : o1 instanceof String s) {
+ s.length();
+ }
+
+ // Test for (e1 ? e2 : e3).T contains intersect(e1.F, e2.T)
+ if (!(o1 instanceof String s) ? (o1 instanceof String s) : true) {
+ s.length();
+ }
+
+ // Test for (e1 ? e2 : e3).F contains intersect(e2.F, e3.F)
+ if (Ktrue() ? !(o2 instanceof Integer x) : !(o2 instanceof Integer x)){
+ } else {
+ x.intValue();
+ }
+
+ // Test for (e1 ? e2 : e3).F contains intersect(e1.T, e3.F)
+ if (o1 instanceof String s ? true : !(o1 instanceof String s)){
+ } else {
+ s.length();
+ }
+
+ // Test for (e1 ? e2 : e3).F contains intersect(e1.F, e2.F)
+ if (!(o1 instanceof String s) ? !(o1 instanceof String s) : true){
+ } else {
+ s.length();
+ }
+
+ L3: {
+ if ((o1 instanceof String s) || (o3 instanceof String s)) {
+ s.length();
+ } else {
+ break L3;
+ }
+ s.length();
+ }
+
+ System.out.println("BindingsTest1Merging complete");
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/patterns/BindingsTest1Merging.out Fri Nov 29 10:02:07 2019 +0000
@@ -0,0 +1,12 @@
+BindingsTest1Merging.java:17:39: compiler.err.match.binding.exists
+BindingsTest1Merging.java:24:36: compiler.err.match.binding.exists
+BindingsTest1Merging.java:29:21: compiler.err.match.binding.exists
+BindingsTest1Merging.java:34:36: compiler.err.match.binding.exists
+BindingsTest1Merging.java:39:39: compiler.err.match.binding.exists
+BindingsTest1Merging.java:44:21: compiler.err.match.binding.exists
+BindingsTest1Merging.java:50:36: compiler.err.match.binding.exists
+BindingsTest1Merging.java:56:39: compiler.err.match.binding.exists
+BindingsTest1Merging.java:62:42: compiler.err.match.binding.exists
+- compiler.note.preview.filename: BindingsTest1Merging.java
+- compiler.note.preview.recompile
+9 errors
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/patterns/BindingsTest2.java Fri Nov 29 10:02:07 2019 +0000
@@ -0,0 +1,191 @@
+/*
+ * @test /nodynamiccopyright/
+ * @bug 8231827
+ * @summary Ensure that scopes arising from conditionalExpressions are handled corrected.
+ * @compile/fail/ref=BindingsTest2.out -XDrawDiagnostics -XDshould-stop.at=FLOW --enable-preview -source ${jdk.version} BindingsTest2.java
+ */
+public class BindingsTest2 {
+ public static boolean Ktrue() { return true; }
+ public static void main(String[] args) {
+ Object o1 = "hello";
+ Integer in = 42;
+ Object o2 = in;
+ Object o3 = "there";
+
+
+ if (Ktrue() ? o2 instanceof Integer x : o2 instanceof String x) {
+ x.intValue();
+ }
+ if (Ktrue() ? o2 instanceof Integer x : true) {
+ x.intValue();
+ }
+
+ if (o1 instanceof String s ? true : true) {
+ s.length();
+ }
+ if (o1 instanceof String s ? true : o2 instanceof Integer s) {
+ s.length();
+ }
+ if (o1 instanceof String s ? true : o2 instanceof Integer i) {
+ s.length();
+ }
+
+ // Test for (e1 ? e2 : e3).T contains intersect(e1.F, e2.T)
+ if (!(o1 instanceof String s) ? true : true) {
+ s.length();
+ }
+ if (!(o1 instanceof String s) ? (o2 instanceof Integer s) : true) {
+ s.length();
+ }
+ if (!(o1 instanceof String s) ? (o2 instanceof Integer i) : true) {
+ s.length();
+ i.intValue();
+ }
+ if (!(o1 instanceof String s) ? (o1 instanceof String s2) : true) {
+ s.length();
+ s2.length();
+ }
+
+
+ // Test for (e1 ? e2 : e3).F contains intersect(e2.F, e3.F)
+ if (Ktrue() ? !(o2 instanceof Integer x) : !(o1 instanceof String x)){
+ } else {
+ x.intValue();
+ }
+ if (Ktrue() ? !(o2 instanceof Integer x) : !(o1 instanceof String s)){
+ } else {
+ x.intValue();
+ }
+ if (Ktrue() ? !(o2 instanceof Integer x) : !(o2 instanceof Integer x1)){
+ } else {
+ x.intValue();
+ x1.intValue();
+ }
+ if (Ktrue() ? !(o2 instanceof Integer x) : false){
+ } else {
+ x.intValue();
+ }
+
+ // Test for (e1 ? e2 : e3).F contains intersect(e1.T, e3.F)
+ if (o1 instanceof String s ? true : !(o2 instanceof Integer s)){
+ } else {
+ s.length();
+ }
+ if (o1 instanceof String s ? true : !(o2 instanceof Integer i)){
+ } else {
+ s.length();
+ i.intValue();
+ }
+ if (o1 instanceof String s ? true : !(o2 instanceof String s1)){
+ } else {
+ s.length();
+ s1.length();
+ }
+ // Test for (e1 ? e2 : e3).F contains intersect(e1.F, e2.F)
+ if (!(o1 instanceof String s) ? !(o1 instanceof String s1) : true){
+ } else {
+ s.length();
+ s1.length();
+ }
+ if (!(o1 instanceof String s) ? !(o2 instanceof Integer s) : true){
+ } else {
+ s.length();
+ }
+ if (!(o1 instanceof String s) ? !(o2 instanceof Integer i) : true){
+ } else {
+ s.length();
+ i.intValue();
+ }
+
+ // Test for e1 ? e2: e3 - include e1.T in e2
+ if (o1 instanceof String s ? false : s.length()>0) {
+ System.out.println("done");
+ }
+ if (o1 instanceof String s ? false : s.intValue!=0) {
+ System.out.println("done");
+ }
+
+ // Test for e1 ? e2 : e3 - include e1.F in e3
+ if (!(o1 instanceof String s) ? s.length()>0 : false){
+ System.out.println("done");
+ }
+ if (!(o1 instanceof String s) ? s.intValue>0 : false){
+ System.out.println("done");
+ }
+
+ {
+ while (!(o1 instanceof String s)) {
+ break;
+ }
+
+ s.length();
+ }
+
+ {
+ while (!(o1 instanceof String s)) {
+ if (false) break;
+ }
+
+ s.length();
+ }
+
+ {
+ while (!(o1 instanceof String s)) {
+ while (true);
+ break;
+ }
+
+ s.length();
+ }
+
+ {
+ for (; !(o1 instanceof String s); ) {
+ break;
+ }
+
+ s.length();
+ }
+
+ {
+ for (; !(o1 instanceof String s); ) {
+ if (false) break;
+ }
+
+ s.length();
+ }
+
+ {
+ for (; !(o1 instanceof String s); ) {
+ while (true);
+ break;
+ }
+
+ s.length();
+ }
+
+ {
+ do {
+ break;
+ } while (!(o1 instanceof String s));
+
+ s.length();
+ }
+
+ {
+ do {
+ if (false) break;
+ } while (!(o1 instanceof String s));
+
+ s.length();
+ }
+
+ {
+ do {
+ while (true);
+ break;
+ } while (!(o1 instanceof String s));
+
+ s.length();
+ }
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/patterns/BindingsTest2.out Fri Nov 29 10:02:07 2019 +0000
@@ -0,0 +1,48 @@
+BindingsTest2.java:16:21: compiler.err.match.binding.exists
+BindingsTest2.java:17:14: compiler.err.cant.resolve.location.args: kindname.method, intValue, , , (compiler.misc.location.1: kindname.variable, x, java.lang.String)
+BindingsTest2.java:20:13: compiler.err.cant.resolve.location: kindname.variable, x, , , (compiler.misc.location: kindname.class, BindingsTest2, null)
+BindingsTest2.java:24:13: compiler.err.cant.resolve.location: kindname.variable, s, , , (compiler.misc.location: kindname.class, BindingsTest2, null)
+BindingsTest2.java:26:36: compiler.err.match.binding.exists
+BindingsTest2.java:27:14: compiler.err.cant.resolve.location.args: kindname.method, length, , , (compiler.misc.location.1: kindname.variable, s, java.lang.Integer)
+BindingsTest2.java:30:13: compiler.err.cant.resolve.location: kindname.variable, s, , , (compiler.misc.location: kindname.class, BindingsTest2, null)
+BindingsTest2.java:35:13: compiler.err.cant.resolve.location: kindname.variable, s, , , (compiler.misc.location: kindname.class, BindingsTest2, null)
+BindingsTest2.java:37:39: compiler.err.match.binding.exists
+BindingsTest2.java:38:14: compiler.err.cant.resolve.location.args: kindname.method, length, , , (compiler.misc.location.1: kindname.variable, s, java.lang.Integer)
+BindingsTest2.java:41:13: compiler.err.cant.resolve.location: kindname.variable, s, , , (compiler.misc.location: kindname.class, BindingsTest2, null)
+BindingsTest2.java:42:13: compiler.err.cant.resolve.location: kindname.variable, i, , , (compiler.misc.location: kindname.class, BindingsTest2, null)
+BindingsTest2.java:45:13: compiler.err.cant.resolve.location: kindname.variable, s, , , (compiler.misc.location: kindname.class, BindingsTest2, null)
+BindingsTest2.java:46:13: compiler.err.cant.resolve.location: kindname.variable, s2, , , (compiler.misc.location: kindname.class, BindingsTest2, null)
+BindingsTest2.java:51:21: compiler.err.match.binding.exists
+BindingsTest2.java:53:14: compiler.err.cant.resolve.location.args: kindname.method, intValue, , , (compiler.misc.location.1: kindname.variable, x, java.lang.String)
+BindingsTest2.java:57:13: compiler.err.cant.resolve.location: kindname.variable, x, , , (compiler.misc.location: kindname.class, BindingsTest2, null)
+BindingsTest2.java:61:13: compiler.err.cant.resolve.location: kindname.variable, x, , , (compiler.misc.location: kindname.class, BindingsTest2, null)
+BindingsTest2.java:62:13: compiler.err.cant.resolve.location: kindname.variable, x1, , , (compiler.misc.location: kindname.class, BindingsTest2, null)
+BindingsTest2.java:66:13: compiler.err.cant.resolve.location: kindname.variable, x, , , (compiler.misc.location: kindname.class, BindingsTest2, null)
+BindingsTest2.java:70:36: compiler.err.match.binding.exists
+BindingsTest2.java:72:14: compiler.err.cant.resolve.location.args: kindname.method, length, , , (compiler.misc.location.1: kindname.variable, s, java.lang.Integer)
+BindingsTest2.java:76:13: compiler.err.cant.resolve.location: kindname.variable, s, , , (compiler.misc.location: kindname.class, BindingsTest2, null)
+BindingsTest2.java:77:13: compiler.err.cant.resolve.location: kindname.variable, i, , , (compiler.misc.location: kindname.class, BindingsTest2, null)
+BindingsTest2.java:81:13: compiler.err.cant.resolve.location: kindname.variable, s, , , (compiler.misc.location: kindname.class, BindingsTest2, null)
+BindingsTest2.java:82:13: compiler.err.cant.resolve.location: kindname.variable, s1, , , (compiler.misc.location: kindname.class, BindingsTest2, null)
+BindingsTest2.java:87:13: compiler.err.cant.resolve.location: kindname.variable, s, , , (compiler.misc.location: kindname.class, BindingsTest2, null)
+BindingsTest2.java:88:13: compiler.err.cant.resolve.location: kindname.variable, s1, , , (compiler.misc.location: kindname.class, BindingsTest2, null)
+BindingsTest2.java:90:39: compiler.err.match.binding.exists
+BindingsTest2.java:92:14: compiler.err.cant.resolve.location.args: kindname.method, length, , , (compiler.misc.location.1: kindname.variable, s, java.lang.Integer)
+BindingsTest2.java:96:13: compiler.err.cant.resolve.location: kindname.variable, s, , , (compiler.misc.location: kindname.class, BindingsTest2, null)
+BindingsTest2.java:97:13: compiler.err.cant.resolve.location: kindname.variable, i, , , (compiler.misc.location: kindname.class, BindingsTest2, null)
+BindingsTest2.java:101:46: compiler.err.cant.resolve.location: kindname.variable, s, , , (compiler.misc.location: kindname.class, BindingsTest2, null)
+BindingsTest2.java:104:46: compiler.err.cant.resolve.location: kindname.variable, s, , , (compiler.misc.location: kindname.class, BindingsTest2, null)
+BindingsTest2.java:109:41: compiler.err.cant.resolve.location: kindname.variable, s, , , (compiler.misc.location: kindname.class, BindingsTest2, null)
+BindingsTest2.java:112:41: compiler.err.cant.resolve.location: kindname.variable, s, , , (compiler.misc.location: kindname.class, BindingsTest2, null)
+BindingsTest2.java:121:13: compiler.err.cant.resolve.location: kindname.variable, s, , , (compiler.misc.location: kindname.class, BindingsTest2, null)
+BindingsTest2.java:129:13: compiler.err.cant.resolve.location: kindname.variable, s, , , (compiler.misc.location: kindname.class, BindingsTest2, null)
+BindingsTest2.java:146:13: compiler.err.cant.resolve.location: kindname.variable, s, , , (compiler.misc.location: kindname.class, BindingsTest2, null)
+BindingsTest2.java:154:13: compiler.err.cant.resolve.location: kindname.variable, s, , , (compiler.misc.location: kindname.class, BindingsTest2, null)
+BindingsTest2.java:171:13: compiler.err.cant.resolve.location: kindname.variable, s, , , (compiler.misc.location: kindname.class, BindingsTest2, null)
+BindingsTest2.java:179:13: compiler.err.cant.resolve.location: kindname.variable, s, , , (compiler.misc.location: kindname.class, BindingsTest2, null)
+BindingsTest2.java:135:17: compiler.err.unreachable.stmt
+BindingsTest2.java:160:17: compiler.err.unreachable.stmt
+BindingsTest2.java:185:17: compiler.err.unreachable.stmt
+- compiler.note.preview.filename: BindingsTest2.java
+- compiler.note.preview.recompile
+45 errors
\ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/patterns/CastConversionMatch.java Fri Nov 29 10:02:07 2019 +0000
@@ -0,0 +1,18 @@
+/*
+ * @test /nodynamicopyright/
+ * @bug 8231827
+ * @summary Match which involves a cast conversion
+ * @compile/fail/ref=CastConversionMatch.out -XDrawDiagnostics --enable-preview -source ${jdk.version} CastConversionMatch.java
+ */
+
+public class CastConversionMatch {
+ public static void main(String [] args) {
+ Object o = 42;
+ if (o instanceof int s) {
+ System.out.println("Okay");
+ } else {
+ throw new AssertionError("broken");
+ }
+ System.out.println(">Test complete");
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/patterns/CastConversionMatch.out Fri Nov 29 10:02:07 2019 +0000
@@ -0,0 +1,4 @@
+CastConversionMatch.java:11:26: compiler.err.type.found.req: int, (compiler.misc.type.req.class.array)
+- compiler.note.preview.filename: CastConversionMatch.java
+- compiler.note.preview.recompile
+1 error
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/patterns/DuplicateBindingTest.java Fri Nov 29 10:02:07 2019 +0000
@@ -0,0 +1,22 @@
+/*
+ * @test /nodynamiccopyright/
+ * @bug 8231827
+ * @summary Basic pattern bindings scope test
+ * @compile/fail/ref=DuplicateBindingTest.out -XDrawDiagnostics --enable-preview -source ${jdk.version} DuplicateBindingTest.java
+ */
+
+public class DuplicateBindingTest {
+
+ int f;
+
+ public static void main(String[] args) {
+
+ if (args != null) {
+ int s;
+ if (args[0] instanceof String s) { // NOT OK. Redef same scope.
+ }
+ if (args[0] instanceof String f) { // OK to redef field.
+ }
+ }
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/patterns/DuplicateBindingTest.out Fri Nov 29 10:02:07 2019 +0000
@@ -0,0 +1,4 @@
+DuplicateBindingTest.java:16:43: compiler.err.already.defined: kindname.variable, s, kindname.method, main(java.lang.String[])
+- compiler.note.preview.filename: DuplicateBindingTest.java
+- compiler.note.preview.recompile
+1 error
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/patterns/EnsureTypesOrderTest.java Fri Nov 29 10:02:07 2019 +0000
@@ -0,0 +1,13 @@
+/*
+ * @test /nodynamiccopyright/
+ * @bug 8187420 8231827
+ * @summary Error message mentions relevant types transposed
+ * @compile/fail/ref=EnsureTypesOrderTest.out -XDrawDiagnostics --enable-preview -source ${jdk.version} EnsureTypesOrderTest.java
+ */
+public class EnsureTypesOrderTest {
+ public static void main(String [] args) {
+ if (args instanceof String s) {
+ System.out.println("Broken");
+ }
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/patterns/EnsureTypesOrderTest.out Fri Nov 29 10:02:07 2019 +0000
@@ -0,0 +1,4 @@
+EnsureTypesOrderTest.java:9:13: compiler.err.prob.found.req: (compiler.misc.inconvertible.types: java.lang.String[], java.lang.String)
+- compiler.note.preview.filename: EnsureTypesOrderTest.java
+- compiler.note.preview.recompile
+1 error
\ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/patterns/ExamplesFromProposal.java Fri Nov 29 10:02:07 2019 +0000
@@ -0,0 +1,215 @@
+/*
+ * 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.
+ *
+ * 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 8231827
+ * @summary All example code from "Pattern Matching for Java" document, released April 2017, adjusted to current state (no switches, etc)
+ * @compile --enable-preview -source ${jdk.version} ExamplesFromProposal.java
+ * @run main/othervm --enable-preview ExamplesFromProposal
+ */
+
+interface Node {
+}
+
+class IntNode implements Node {
+ int value;
+
+ IntNode(int value) {
+ this.value = value;
+ }
+}
+
+class NegNode implements Node {
+ Node node;
+
+ NegNode(Node node) {
+ this.node = node;
+ }
+}
+
+class MulNode implements Node {
+ Node left, right;
+
+ MulNode(Node left, Node right) {
+ this.left = left;
+ this.right = right;
+ }
+}
+
+class AddNode implements Node {
+ Node left, right;
+
+ AddNode(Node left, Node right) {
+ this.left = left;
+ this.right = right;
+ }
+}
+
+public class ExamplesFromProposal {
+
+ public static Object getSomething() {
+ return new Long(42);
+ }
+
+ public static int eval(Node n) {
+ if (n instanceof IntNode in) return in.value;
+ else if (n instanceof NegNode nn) return -eval(nn.node);
+ else if (n instanceof AddNode an) return eval(an.left) + eval(an.right);
+ else if (n instanceof MulNode mn) return eval(mn.left) * eval(mn.right);
+ else {
+ // should never happen
+ throw new AssertionError("broken");
+ }
+ }
+
+ public static String toString(Node n) {
+ if (n instanceof IntNode in) return String.valueOf(in.value);
+ else if (n instanceof NegNode nn) return "-"+eval(nn.node);
+ else if (n instanceof AddNode an) return eval(an.left) + " + " + eval(an.right);
+ else if (n instanceof MulNode mn) return eval(mn.left) + " * " + eval(mn.right);
+ else {
+ // should never happen
+ throw new AssertionError("broken");
+ }
+ }
+
+ public static Node simplify(Node n) {
+ if (n instanceof IntNode in) {
+ return n;
+ } else if (n instanceof NegNode nn) {
+ return new NegNode(simplify(nn.node));
+ } else if (n instanceof AddNode ad) {
+ n = simplify(ad.left);
+ if (n instanceof IntNode intn) {
+ if (intn.value == 0)
+ return simplify(ad.right);
+ else
+ return new AddNode(intn, simplify(ad.right));
+ } else {
+ return new AddNode(simplify(ad.left), simplify(ad.right));
+ }
+ } else if (n instanceof MulNode mn) {
+ return new MulNode(simplify(mn.left), simplify(mn.right));
+ } else {
+ //should never happen
+ throw new AssertionError("broken");
+ }
+ }
+
+ public static void testNode(Node n, int expected) {
+ if (eval(n) != expected)
+ throw new AssertionError("broken");
+ }
+
+ public static void main(String[] args) {
+ Object x = new Integer(42);
+
+ if (x instanceof Integer i) {
+ // can use i here
+ System.out.println(i.intValue());
+ }
+
+ Object obj = getSomething();
+
+ String formatted = "unknown";
+ if (obj instanceof Integer i) {
+ formatted = String.format("int %d", i);
+ }
+ else if (obj instanceof Byte b) {
+ formatted = String.format("byte %d", b);
+ }
+ else if (obj instanceof Long l) {
+ formatted = String.format("long %d", l);
+ }
+ else if (obj instanceof Double d) {
+ formatted = String.format("double %f", d);
+ }
+ else if (obj instanceof String s) {
+ formatted = String.format("String %s", s);
+ }
+ System.out.println(formatted);
+
+ if (obj instanceof Integer i) formatted = String.format("int %d", i);
+ else if (obj instanceof Byte b) formatted = String.format("byte %d", b);
+ else if (obj instanceof Long l) formatted = String.format("long %d", l);
+ else if (obj instanceof Double d) formatted = String.format("double %f", d);
+ else if (obj instanceof String s) formatted = String.format("String %s", s);
+ else formatted = String.format("Something else "+ obj.toString());
+ System.out.println(formatted);
+
+ Node zero = new IntNode(0);
+ Node one = new IntNode(1);
+ Node ft = new IntNode(42);
+
+ Node temp = new AddNode(zero,ft);
+
+ testNode(temp,42);
+
+
+
+ if (toString(simplify(temp)).equals(toString(ft)))
+ System.out.println("Simplify worked!");
+ else
+ throw new AssertionError("broken");
+
+
+ if (toString(simplify(new AddNode(zero,temp))).equals(toString(ft)))
+ System.out.println("Simplify worked!");
+ else
+ throw new AssertionError("broken");
+
+
+ temp = new AddNode(zero,ft);
+ temp = new AddNode(one,temp);
+ temp = new AddNode(zero,temp);
+
+ Node fortythree = new AddNode(one,ft);
+
+ if (toString(simplify(temp)).equals(toString(fortythree)))
+ System.out.println("Simplify worked!");
+ else
+ throw new AssertionError("broken");
+
+
+ x = "Hello";
+
+ if (x instanceof String s1) {
+ System.out.println(s1);
+ }
+ if (x instanceof String s1 && s1.length() > 0) {
+ System.out.println(s1);
+ }
+ if (x instanceof String s1) {
+ System.out.println(s1 + " is a string");
+ } else {
+ System.out.println("not a string");
+ }
+
+ if (!(x instanceof String s1)) {
+ System.out.println("not a string");
+ } else {
+ System.out.println(s1 + " is a string");
+ }
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/patterns/ImpossibleTypeTest.java Fri Nov 29 10:02:07 2019 +0000
@@ -0,0 +1,21 @@
+/*
+ * @test /nodynamiccopyright/
+ * @bug 8231827
+ * @summary Ensure that in type test patterns, the predicate is not trivially provable false.
+ * @compile/fail/ref=ImpossibleTypeTest.out -XDrawDiagnostics --enable-preview -source ${jdk.version} ImpossibleTypeTest.java
+ */
+public class ImpossibleTypeTest {
+
+ public static void main(String[] args) {
+
+ int in = 42;
+ Integer i = 42;
+
+ if (i instanceof String s ) {
+ System.out.println("Broken");
+ }
+ if (i instanceof Undefined u ) {
+ System.out.println("Broken");
+ }
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/patterns/ImpossibleTypeTest.out Fri Nov 29 10:02:07 2019 +0000
@@ -0,0 +1,5 @@
+ImpossibleTypeTest.java:14:13: compiler.err.prob.found.req: (compiler.misc.inconvertible.types: java.lang.Integer, java.lang.String)
+ImpossibleTypeTest.java:17:26: compiler.err.cant.resolve.location: kindname.class, Undefined, , , (compiler.misc.location: kindname.class, ImpossibleTypeTest, null)
+- compiler.note.preview.filename: ImpossibleTypeTest.java
+- compiler.note.preview.recompile
+2 errors
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/patterns/LocalVariableTable.java Fri Nov 29 10:02:07 2019 +0000
@@ -0,0 +1,165 @@
+/*
+ * 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
+ * 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 8231827
+ * @summary Ensure the LV table entries are generated for bindings
+ * @modules jdk.jdeps/com.sun.tools.classfile
+ * @compile -g --enable-preview -source ${jdk.version} LocalVariableTable.java
+ * @run main/othervm --enable-preview LocalVariableTable
+ */
+
+import java.io.*;
+import java.lang.annotation.*;
+import java.util.*;
+import com.sun.tools.classfile.*;
+
+/*
+ * The test checks that a LocalVariableTable attribute is generated for the
+ * method bodies containing patterns, and checks that the expected
+ * set of entries is found in the attribute.
+ *
+ * The test looks for test cases represented by nested classes whose
+ * name begins with "Pattern". Each such class contains a method
+ * with patterns, and because the test is compiled
+ * with -g, these methods should have a LocalVariableTable. The set of
+ * expected names in the LVT is provided in an annotation on the class for
+ * the test case.
+ */
+//Copied from: test/langtools/tools/javac/lambda/LocalVariableTable.java
+public class LocalVariableTable {
+ public static void main(String... args) throws Exception {
+ new LocalVariableTable().run();
+ }
+
+ void run() throws Exception {
+ // the declared classes are returned in an unspecified order,
+ // so for neatness, sort them by name before processing them
+ Class<?>[] classes = getClass().getDeclaredClasses();
+ Arrays.sort(classes, (c1, c2) -> c1.getName().compareTo(c2.getName()));
+
+ for (Class<?> c : classes) {
+ if (c.getSimpleName().startsWith("Pattern"))
+ check(c);
+ }
+ if (errors > 0)
+ throw new Exception(errors + " errors found");
+ }
+
+ /** Check an individual test case. */
+ void check(Class<?> c) throws Exception {
+ System.err.println("Checking " + c.getSimpleName());
+
+ Expect expect = c.getAnnotation(Expect.class);
+ if (expect == null) {
+ error("@Expect not found for class " + c.getSimpleName());
+ return;
+ }
+
+ ClassFile cf = ClassFile.read(getClass().getResource(c.getName() + ".class").openStream());
+ Method m = getMethodByName(cf, c.getSimpleName().contains("Lambda") ? "lambda$" : "test");
+ if (m == null) {
+ error("test method not found");
+ return;
+ }
+
+ Code_attribute code = (Code_attribute) m.attributes.get(Attribute.Code);
+ if (code == null) {
+ error("Code attribute not found");
+ return;
+ }
+
+ LocalVariableTable_attribute lvt =
+ (LocalVariableTable_attribute) code.attributes.get(Attribute.LocalVariableTable);
+ if (lvt == null) {
+ error("LocalVariableTable attribute not found");
+ return;
+ }
+
+ Set<String> foundNames = new LinkedHashSet<>();
+ for (LocalVariableTable_attribute.Entry e: lvt.local_variable_table) {
+ foundNames.add(cf.constant_pool.getUTF8Value(e.name_index));
+ }
+
+ Set<String> expectNames = new LinkedHashSet<>(Arrays.asList(expect.value()));
+ if (!foundNames.equals(expectNames)) {
+ Set<String> foundOnly = new LinkedHashSet<>(foundNames);
+ foundOnly.removeAll(expectNames);
+ for (String s: foundOnly)
+ error("Unexpected name found: " + s);
+ Set<String> expectOnly = new LinkedHashSet<>(expectNames);
+ expectOnly.removeAll(foundNames);
+ for (String s: expectOnly)
+ error("Expected name not found: " + s);
+ }
+ }
+
+ Method getMethodByName(ClassFile cf, String name) throws ConstantPoolException {
+ for (Method m: cf.methods) {
+ if (m.getName(cf.constant_pool).startsWith(name))
+ return m;
+ }
+ return null;
+ }
+
+ /** Report an error. */
+ void error(String msg) {
+ System.err.println("Error: " + msg);
+ errors++;
+ }
+
+ int errors;
+
+ /**
+ * Annotation used to provide the set of names expected in the LVT attribute.
+ */
+ @Retention(RetentionPolicy.RUNTIME)
+ @interface Expect {
+ String[] value();
+ }
+
+ /*
+ * ---------- Test cases ---------------------------------------------------
+ */
+
+ @Expect({ "o", "s" })
+ static class Pattern_Simple {
+ public static void test(Object o) {
+ if (o instanceof String s) {}
+ }
+ }
+
+ @Expect({ "s" })
+ static class Pattern_Lambda {
+ public static void test(Object o) {
+ if (o instanceof String s) {
+ Runnable r = () -> {
+ s.length();
+ };
+ }
+ }
+ }
+
+}
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/patterns/MatchBindingScopeTest.java Fri Nov 29 10:02:07 2019 +0000
@@ -0,0 +1,68 @@
+/*
+ * @test /nodynamiccopyright/
+ * @bug 8231827
+ * @summary Basic pattern bindings scope test
+ * @compile/fail/ref=MatchBindingScopeTest.out -XDrawDiagnostics --enable-preview -source ${jdk.version} MatchBindingScopeTest.java
+ */
+public class MatchBindingScopeTest {
+
+ static Integer i = 42;
+ static String s = "Hello";
+ static Object o1 = s;
+ static Object o2 = i;
+
+ public static void main(String[] args) {
+
+ if (o1 instanceof String j && j.length() == 5) { // OK
+ System.out.println(j); // OK
+ } else {
+ System.out.println(j); // NOT OK
+ }
+
+ // NOT OK, name reused.
+ if (o1 instanceof String j && o2 instanceof Integer j) {
+ }
+
+ if (o1 instanceof String j && j.length() == 5 && o2 instanceof Integer k && k == 42) { // OK
+ System.out.println(j); // OK
+ System.out.println(k); // OK
+ } else {
+ System.out.println(j); // NOT OK
+ System.out.println(k); // NOT OK
+ }
+
+ if (o1 instanceof String j || j.length() == 5) { // NOT OK
+ System.out.println(j); // NOT OK
+ }
+
+ if (o1 instanceof String j || o2 instanceof Integer j) { // NOT OK, types differ
+ System.out.println(j);
+ } else {
+ System.out.println(j); // NOT OK.
+ }
+
+ while (o1 instanceof String j && j.length() == 5) { // OK
+ System.out.println(j); // OK
+ }
+
+ while (o1 instanceof String j || true) {
+ System.out.println(j); // Not OK
+ }
+
+ for (; o1 instanceof String j; j.length()) { // OK
+ System.out.println(j); // OK
+ }
+
+ for (; o1 instanceof String j || true; j.length()) { // NOT OK
+ System.out.println(j); // Not OK
+ }
+
+ int x = o1 instanceof String j ?
+ j.length() : // OK.
+ j.length(); // NOT OK.
+
+ x = !(o1 instanceof String j) ?
+ j.length() : // NOT OK.
+ j.length(); // OK.
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/patterns/MatchBindingScopeTest.out Fri Nov 29 10:02:07 2019 +0000
@@ -0,0 +1,16 @@
+MatchBindingScopeTest.java:19:32: compiler.err.cant.resolve.location: kindname.variable, j, , , (compiler.misc.location: kindname.class, MatchBindingScopeTest, null)
+MatchBindingScopeTest.java:23:36: compiler.err.match.binding.exists
+MatchBindingScopeTest.java:30:32: compiler.err.cant.resolve.location: kindname.variable, j, , , (compiler.misc.location: kindname.class, MatchBindingScopeTest, null)
+MatchBindingScopeTest.java:31:32: compiler.err.cant.resolve.location: kindname.variable, k, , , (compiler.misc.location: kindname.class, MatchBindingScopeTest, null)
+MatchBindingScopeTest.java:34:39: compiler.err.cant.resolve.location: kindname.variable, j, , , (compiler.misc.location: kindname.class, MatchBindingScopeTest, null)
+MatchBindingScopeTest.java:35:32: compiler.err.cant.resolve.location: kindname.variable, j, , , (compiler.misc.location: kindname.class, MatchBindingScopeTest, null)
+MatchBindingScopeTest.java:38:36: compiler.err.match.binding.exists
+MatchBindingScopeTest.java:41:32: compiler.err.cant.resolve.location: kindname.variable, j, , , (compiler.misc.location: kindname.class, MatchBindingScopeTest, null)
+MatchBindingScopeTest.java:49:32: compiler.err.cant.resolve.location: kindname.variable, j, , , (compiler.misc.location: kindname.class, MatchBindingScopeTest, null)
+MatchBindingScopeTest.java:56:48: compiler.err.cant.resolve.location: kindname.variable, j, , , (compiler.misc.location: kindname.class, MatchBindingScopeTest, null)
+MatchBindingScopeTest.java:57:32: compiler.err.cant.resolve.location: kindname.variable, j, , , (compiler.misc.location: kindname.class, MatchBindingScopeTest, null)
+MatchBindingScopeTest.java:62:23: compiler.err.cant.resolve.location: kindname.variable, j, , , (compiler.misc.location: kindname.class, MatchBindingScopeTest, null)
+MatchBindingScopeTest.java:65:23: compiler.err.cant.resolve.location: kindname.variable, j, , , (compiler.misc.location: kindname.class, MatchBindingScopeTest, null)
+- compiler.note.preview.filename: MatchBindingScopeTest.java
+- compiler.note.preview.recompile
+13 errors
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/patterns/NullsInPatterns.java Fri Nov 29 10:02:07 2019 +0000
@@ -0,0 +1,53 @@
+/*
+ * 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.
+ *
+ * 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 8231827
+ * @summary Testing pattern matching against the null constant
+ * @compile --enable-preview -source ${jdk.version} NullsInPatterns.java
+ * @run main/othervm --enable-preview NullsInPatterns
+ */
+import java.util.List;
+
+public class NullsInPatterns {
+
+ public static void main(String[] args) {
+ if (null instanceof List t) {
+ throw new AssertionError("broken");
+ } else {
+ System.out.println("null does not match List type pattern");
+ }
+ //reifiable types not allowed in type test patterns in instanceof:
+// if (null instanceof List<Integer> l) {
+// throw new AssertionError("broken");
+// } else {
+// System.out.println("null does not match List<Integer> type pattern");
+// }
+ if (null instanceof List<?> l) {
+ throw new AssertionError("broken");
+ } else {
+ System.out.println("null does not match List<?> type pattern");
+ }
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/patterns/PatternMatchPosTest.java Fri Nov 29 10:02:07 2019 +0000
@@ -0,0 +1,105 @@
+/*
+ * 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.
+ *
+ * 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 8231827
+ * @summary Check proper positions.
+ * @build PatternMatchPosTest
+ * @compile/ref=PatternMatchPosTest.out -processor PatternMatchPosTest -Xlint:unchecked -XDrawDiagnostics --enable-preview -source ${jdk.version} PatternMatchPosTestData.java
+ */
+
+import java.io.IOException;
+import java.util.Set;
+
+import javax.annotation.processing.AbstractProcessor;
+import javax.annotation.processing.RoundEnvironment;
+import javax.annotation.processing.SupportedAnnotationTypes;
+import javax.lang.model.SourceVersion;
+import javax.lang.model.element.TypeElement;
+
+import com.sun.source.tree.IfTree;
+import com.sun.source.tree.Tree;
+import com.sun.source.util.SourcePositions;
+import com.sun.source.util.TreePath;
+import com.sun.source.util.TreeScanner;
+import com.sun.source.util.Trees;
+import javax.tools.Diagnostic;
+
+@SupportedAnnotationTypes("*")
+public class PatternMatchPosTest extends AbstractProcessor {
+
+ int round;
+
+ @Override
+ public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
+ if (round++ != 0)
+ return false;
+
+ try {
+ TypeElement data = processingEnv.getElementUtils().getTypeElement("PatternMatchPosTestData");
+ Trees trees = Trees.instance(processingEnv);
+ SourcePositions sp = trees.getSourcePositions();
+ TreePath dataPath = trees.getPath(data);
+ String text = dataPath.getCompilationUnit().getSourceFile().getCharContent(true).toString();
+
+ new TreeScanner<Void, Void>() {
+ boolean print;
+ @Override
+ public Void visitIf(IfTree node, Void p) {
+ boolean prevPrint = print;
+ try {
+ print = true;
+ scan(node.getCondition(), p);
+ } finally {
+ print = prevPrint;
+ }
+ scan(node.getThenStatement(), p);
+ scan(node.getElseStatement(), p);
+ return null;
+ }
+ @Override
+ public Void scan(Tree tree, Void p) {
+ if (tree == null)
+ return null;
+ if (print) {
+ int start = (int) sp.getStartPosition(dataPath.getCompilationUnit(), tree);
+ int end = (int) sp.getEndPosition(dataPath.getCompilationUnit(), tree);
+ processingEnv.getMessager().printMessage(Diagnostic.Kind.NOTE,
+ text.substring(start, end));
+ }
+ return super.scan(tree, p);
+ }
+ }.scan(dataPath.getLeaf(), null);
+ return false;
+ } catch (IOException ex) {
+ throw new IllegalStateException(ex);
+ }
+ }
+
+ @Override
+ public SourceVersion getSupportedSourceVersion() {
+ return SourceVersion.latestSupported();
+ }
+
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/patterns/PatternMatchPosTest.out Fri Nov 29 10:02:07 2019 +0000
@@ -0,0 +1,14 @@
+- compiler.note.proc.messager: (o instanceof String s)
+- compiler.note.proc.messager: o instanceof String s
+- compiler.note.proc.messager: o
+- compiler.note.proc.messager: String s
+- compiler.note.proc.messager: String
+- compiler.note.proc.messager: (o instanceof java.lang.String s)
+- compiler.note.proc.messager: o instanceof java.lang.String s
+- compiler.note.proc.messager: o
+- compiler.note.proc.messager: java.lang.String s
+- compiler.note.proc.messager: java.lang.String
+- compiler.note.proc.messager: java.lang
+- compiler.note.proc.messager: java
+- compiler.note.preview.filename: PatternMatchPosTestData.java
+- compiler.note.preview.recompile
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/patterns/PatternMatchPosTestData.java Fri Nov 29 10:02:07 2019 +0000
@@ -0,0 +1,29 @@
+/*
+ * 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.
+ *
+ * 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.
+ */
+
+class PatternMatchPosTestData {
+ void data(Object o) {
+ if (o instanceof String s) { }
+ if (o instanceof java.lang.String s) { }
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/patterns/PatternTypeTest2.java Fri Nov 29 10:02:07 2019 +0000
@@ -0,0 +1,45 @@
+/*
+ * 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.
+ *
+ * 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 8231827
+ * @summary Basic pattern test
+ * @compile --enable-preview -source ${jdk.version} PatternTypeTest2.java
+ * @run main/othervm --enable-preview PatternTypeTest2
+ */
+public class PatternTypeTest2 {
+
+ public static void main(String[] args) {
+
+ Integer i = 42;
+ String s = "Hello";
+ Object o = i;
+
+ if (o instanceof Integer j) {
+ System.out.println("It's an Integer");
+ } else {
+ throw new AssertionError("Broken");
+ }
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/patterns/PatternVariablesAreFinal.java Fri Nov 29 10:02:07 2019 +0000
@@ -0,0 +1,16 @@
+/*
+ * @test /nodynamiccopyright/
+ * @bug 8231827
+ * @summary Ensure that in type test patterns, the predicate is not trivially provable false.
+ * @compile/fail/ref=PatternVariablesAreFinal.out -XDrawDiagnostics --enable-preview -source ${jdk.version} PatternVariablesAreFinal.java
+ */
+public class PatternVariablesAreFinal {
+ public static void main(String[] args) {
+ Object o = 32;
+ if (o instanceof String s) {
+ s = "hello again";
+ System.out.println(s);
+ }
+ System.out.println("test complete");
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/patterns/PatternVariablesAreFinal.out Fri Nov 29 10:02:07 2019 +0000
@@ -0,0 +1,4 @@
+PatternVariablesAreFinal.java:11:13: compiler.err.pattern.binding.may.not.be.assigned: s
+- compiler.note.preview.filename: PatternVariablesAreFinal.java
+- compiler.note.preview.recompile
+1 error
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/patterns/PatternVariablesAreFinal2.java Fri Nov 29 10:02:07 2019 +0000
@@ -0,0 +1,40 @@
+/*
+ * 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.
+ *
+ * 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 8231827
+ * @summary Pattern variables are final so should be allowed to be referenced in an inner class
+ * @compile --enable-preview -source ${jdk.version} PatternVariablesAreFinal2.java
+ * @run main/othervm --enable-preview PatternVariablesAreFinal2
+ */
+public class PatternVariablesAreFinal2 {
+ public static void main(String[] args) {
+ Object o = "42";
+ if (o instanceof String s) {
+ new Object() {
+ void run() { System.err.println(s); }
+ }.run();
+ }
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/patterns/PatternsSimpleVisitorTest.java Fri Nov 29 10:02:07 2019 +0000
@@ -0,0 +1,126 @@
+/*
+ * 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
+ * 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 8231827
+ * @summary Ensure SimpleTreeVisitor.visitBindingPattern and visitInstanceOf behaves as it should
+ * @modules jdk.compiler
+ */
+
+import java.io.IOException;
+import java.io.StringWriter;
+import java.net.URI;
+import java.util.Arrays;
+import java.util.List;
+
+import javax.tools.*;
+
+import com.sun.source.tree.BindingPatternTree;
+import com.sun.source.tree.CompilationUnitTree;
+import com.sun.source.tree.InstanceOfTree;
+import com.sun.source.tree.Tree;
+import com.sun.source.util.JavacTask;
+import com.sun.source.util.SimpleTreeVisitor;
+import com.sun.source.util.TreePathScanner;
+
+public class PatternsSimpleVisitorTest {
+
+ public static void main(String[] args) throws Exception {
+ new PatternsSimpleVisitorTest().run();
+ }
+
+ void run() throws Exception {
+ String code = "class Test {\n" +
+ " boolean t(Object o) {\n" +
+ " return o instanceof String s ? s.isEmpty() : false;\n" +
+ " }\n" +
+ "}\n";
+ int[] callCount = new int[1];
+ int[] instanceOfNodeCount = new int[1];
+ int[] bindingPatternNodeCount = new int[1];
+ new TreePathScanner<Void, Void>() {
+ @Override
+ public Void visitInstanceOf(InstanceOfTree node, Void p) {
+ node.accept(new SimpleTreeVisitor<Void, Void>() {
+ @Override
+ protected Void defaultAction(Tree defaultActionNode, Void p) {
+ callCount[0]++;
+ if (node == defaultActionNode) {
+ instanceOfNodeCount[0]++;
+ }
+ return null;
+ }
+ }, null);
+ return super.visitInstanceOf(node, p);
+ }
+ @Override
+ public Void visitBindingPattern(BindingPatternTree node, Void p) {
+ node.accept(new SimpleTreeVisitor<Void, Void>() {
+ @Override
+ protected Void defaultAction(Tree defaultActionNode, Void p) {
+ callCount[0]++;
+ if (node == defaultActionNode) {
+ bindingPatternNodeCount[0]++;
+ }
+ return null;
+ }
+ }, null);
+ return super.visitBindingPattern(node, p);
+ }
+ }.scan(parse(code), null);
+
+ if (callCount[0] != 2 || instanceOfNodeCount[0] != 1 ||
+ bindingPatternNodeCount[0] != 1) {
+ throw new AssertionError("Unexpected counts; callCount=" + callCount[0] +
+ ", switchExprNodeCount=" + instanceOfNodeCount[0] +
+ ", yieldNodeCount=" + bindingPatternNodeCount[0]);
+ }
+ }
+
+ private CompilationUnitTree parse(String code) throws IOException {
+ final JavaCompiler tool = ToolProvider.getSystemJavaCompiler();
+ assert tool != null;
+ DiagnosticListener<JavaFileObject> noErrors = d -> {};
+
+ StringWriter out = new StringWriter();
+ JavacTask ct = (JavacTask) tool.getTask(out, null, noErrors,
+ List.of("--enable-preview", "-source", Integer.toString(Runtime.version().feature())), null,
+ Arrays.asList(new MyFileObject(code)));
+ return ct.parse().iterator().next();
+ }
+
+ static class MyFileObject extends SimpleJavaFileObject {
+ private String text;
+
+ public MyFileObject(String text) {
+ super(URI.create("myfo:/Test.java"), JavaFileObject.Kind.SOURCE);
+ this.text = text;
+ }
+
+ @Override
+ public CharSequence getCharContent(boolean ignoreEncodingErrors) {
+ return text;
+ }
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/patterns/Reifiable.java Fri Nov 29 10:02:07 2019 +0000
@@ -0,0 +1,22 @@
+/*
+ * @test /nodynamiccopyright/
+ * @bug 8231827
+ * @summary Verify behavior w.r.t. non-reifiable types and type test patterns in instanceof
+ * @compile/fail/ref=Reifiable.out --enable-preview -source ${jdk.version} -XDrawDiagnostics Reifiable.java
+ */
+
+public class Reifiable implements ReifiableI {
+ private static boolean test(Object o, List<Reifiable> l1, List<String> l2) {
+ return o instanceof ListImpl<Reifiable> li1 &&
+ l1 instanceof ListImpl<Reifiable> li2 &&
+ l2 instanceof ListImpl<Reifiable> li3 &&
+ l2 instanceof ListImpl<String> li4 &&
+ l1 instanceof Unrelated<Reifiable> li5;
+ }
+
+ public class List<T> {}
+ public class ListImpl<T extends ReifiableI> extends List<T> {}
+ public class Unrelated<T> {}
+}
+
+interface ReifiableI {}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/patterns/Reifiable.out Fri Nov 29 10:02:07 2019 +0000
@@ -0,0 +1,7 @@
+Reifiable.java:10:16: compiler.err.instanceof.reifiable.not.safe: java.lang.Object, Reifiable.ListImpl<Reifiable>
+Reifiable.java:12:16: compiler.err.prob.found.req: (compiler.misc.inconvertible.types: Reifiable.List<java.lang.String>, Reifiable.ListImpl<Reifiable>)
+Reifiable.java:13:39: compiler.err.not.within.bounds: java.lang.String, T
+Reifiable.java:14:16: compiler.err.prob.found.req: (compiler.misc.inconvertible.types: Reifiable.List<Reifiable>, Reifiable.Unrelated<Reifiable>)
+- compiler.note.preview.filename: Reifiable.java
+- compiler.note.preview.recompile
+4 errors
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/patterns/ReifiableOld-old.out Fri Nov 29 10:02:07 2019 +0000
@@ -0,0 +1,7 @@
+ReifiableOld.java:12:37: compiler.err.illegal.generic.type.for.instof
+ReifiableOld.java:13:38: compiler.err.illegal.generic.type.for.instof
+ReifiableOld.java:14:38: compiler.err.illegal.generic.type.for.instof
+ReifiableOld.java:15:38: compiler.err.illegal.generic.type.for.instof
+ReifiableOld.java:15:39: compiler.err.not.within.bounds: java.lang.String, T
+ReifiableOld.java:16:39: compiler.err.illegal.generic.type.for.instof
+6 errors
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/patterns/ReifiableOld.java Fri Nov 29 10:02:07 2019 +0000
@@ -0,0 +1,24 @@
+/*
+ * @test /nodynamiccopyright/
+ * @bug 8231827
+ * @summary Verify behavior w.r.t. non-reifiable types in instanceof
+ * @compile/fail/ref=ReifiableOld-old.out -source 13 -Xlint:-options -XDrawDiagnostics ReifiableOld.java
+ * @compile/fail/ref=ReifiableOld-old.out -source ${jdk.version} -XDrawDiagnostics ReifiableOld.java
+ * @compile/fail/ref=ReifiableOld.out --enable-preview -source ${jdk.version} -XDrawDiagnostics ReifiableOld.java
+ */
+
+public class ReifiableOld implements ReifiableOldI {
+ private static boolean test(Object o, List<ReifiableOld> l1, List<String> l2) {
+ return o instanceof ListImpl<ReifiableOld> &&
+ l1 instanceof ListImpl<ReifiableOld> &&
+ l2 instanceof ListImpl<ReifiableOld> &&
+ l2 instanceof ListImpl<String> &&
+ l1 instanceof Unrelated<ReifiableOld>;
+ }
+
+ public class List<T> {}
+ public class ListImpl<T extends ReifiableOldI> extends List<T> {}
+ public class Unrelated<T> {}
+}
+
+interface ReifiableOldI {}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/patterns/ReifiableOld.out Fri Nov 29 10:02:07 2019 +0000
@@ -0,0 +1,7 @@
+ReifiableOld.java:12:16: compiler.err.instanceof.reifiable.not.safe: java.lang.Object, ReifiableOld.ListImpl<ReifiableOld>
+ReifiableOld.java:14:16: compiler.err.prob.found.req: (compiler.misc.inconvertible.types: ReifiableOld.List<java.lang.String>, ReifiableOld.ListImpl<ReifiableOld>)
+ReifiableOld.java:15:39: compiler.err.not.within.bounds: java.lang.String, T
+ReifiableOld.java:16:16: compiler.err.prob.found.req: (compiler.misc.inconvertible.types: ReifiableOld.List<ReifiableOld>, ReifiableOld.Unrelated<ReifiableOld>)
+- compiler.note.preview.filename: ReifiableOld.java
+- compiler.note.preview.recompile
+4 errors
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/patterns/UncheckedWarningOnMatchesTest.java Fri Nov 29 10:02:07 2019 +0000
@@ -0,0 +1,18 @@
+/*
+ * @test /nodynamiccopyright/
+ * @bug 8187429 8231827
+ * @summary Missing unchecked conversion warning
+ * @compile/fail/ref=UncheckedWarningOnMatchesTest.out -Xlint:unchecked -Werror -XDrawDiagnostics --enable-preview -source ${jdk.version} UncheckedWarningOnMatchesTest.java
+ */
+import java.util.ArrayList;
+
+public class UncheckedWarningOnMatchesTest {
+
+ public static void main(String [] args) {
+
+ Object o = new ArrayList<UncheckedWarningOnMatchesTest>();
+ if (o instanceof ArrayList<Integer> ai) { // unchecked conversion
+ System.out.println("Blah");
+ }
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/patterns/UncheckedWarningOnMatchesTest.out Fri Nov 29 10:02:07 2019 +0000
@@ -0,0 +1,4 @@
+UncheckedWarningOnMatchesTest.java:14:13: compiler.err.instanceof.reifiable.not.safe: java.lang.Object, java.util.ArrayList<java.lang.Integer>
+- compiler.note.preview.filename: UncheckedWarningOnMatchesTest.java
+- compiler.note.preview.recompile
+1 error
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/patterns/scope/ScopeTest.java Fri Nov 29 10:02:07 2019 +0000
@@ -0,0 +1,152 @@
+/*
+ * 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
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+import java.io.IOException;
+import java.util.Arrays;
+import java.util.List;
+import java.util.stream.Collectors;
+
+import org.testng.ITestResult;
+import org.testng.annotations.AfterMethod;
+import org.testng.annotations.Test;
+import tools.javac.combo.JavacTemplateTestBase;
+
+import static java.util.stream.Collectors.toList;
+
+@Test
+public class ScopeTest extends JavacTemplateTestBase {
+
+ private static String st_block(String... statements) {
+ return Arrays.stream(statements).collect(Collectors.joining("", "{", "}"));
+ }
+
+ private static String st_if(String condition, String then, String els) {
+ return "if (" + condition + ") " + then + " else " + els;
+ }
+
+ private static String st_while(String condition, String body) {
+ return "while (" + condition + ") " + body;
+ }
+
+ private static String st_do_while(String body, String condition) {
+ return "do " + body + " while (" + condition + ");";
+ }
+
+ private static String st_for(String init, String condition, String update, String body) {
+ return "for (" + init + "; " + condition + "; " + update + ") " + body;
+ }
+
+ private static String st_s_use() {
+ return "s.length();";
+ }
+
+ private static String st_break() {
+ return "break;";
+ }
+
+ private static String st_return() {
+ return "return;";
+ }
+
+ private static String st_noop() {
+ return ";";
+ }
+
+ private static String expr_empty() {
+ return "";
+ }
+
+ private static String expr_o_match_str() {
+ return "o instanceof String s";
+ }
+
+ private static String expr_not(String expr) {
+ return "!(" + expr + ")";
+ }
+
+ @AfterMethod
+ public void dumpTemplateIfError(ITestResult result) {
+ // Make sure offending template ends up in log file on failure
+ if (!result.isSuccess()) {
+ System.err.printf("Diagnostics: %s%nTemplate: %s%n", diags.errorKeys(), sourceFiles.stream().map(p -> p.snd).collect(toList()));
+ }
+ }
+
+ private void program(String block) {
+ String s = "class C { void m(Object o) " + block + "}";
+ addSourceFile("C.java", new StringTemplate(s));
+ }
+
+ private void assertOK(String block) {
+ String sourceVersion = Integer.toString(Runtime.version().feature());
+
+ reset();
+ addCompileOptions("--enable-preview", "-source", sourceVersion);
+ program(block);
+ try {
+ compile();
+ }
+ catch (IOException e) {
+ throw new RuntimeException(e);
+ }
+ assertCompileSucceeded();
+ }
+
+ private void assertFail(String expectedDiag, String block) {
+ String sourceVersion = Integer.toString(Runtime.version().feature());
+
+ reset();
+ addCompileOptions("--enable-preview", "-source", sourceVersion);
+ program(block);
+ try {
+ compile();
+ }
+ catch (IOException e) {
+ throw new RuntimeException(e);
+ }
+ assertCompileFailed(expectedDiag);
+ }
+
+ public void testIf() {
+ assertOK(st_block(st_if(expr_o_match_str(), st_s_use(), st_return()), st_s_use()));
+ assertOK(st_block(st_if(expr_not(expr_o_match_str()), st_return(), st_s_use()), st_s_use()));
+ assertFail("compiler.err.cant.resolve.location", st_block(st_if(expr_o_match_str(), st_s_use(), st_noop()), st_s_use()));
+ assertFail("compiler.err.cant.resolve.location", st_block(st_if(expr_not(expr_o_match_str()), st_noop(), st_s_use()), st_s_use()));
+ }
+
+ public void testWhile() {
+ assertOK(st_block(st_while(expr_not(expr_o_match_str()), st_noop()), st_s_use()));
+ assertFail("compiler.err.cant.resolve.location", st_block(st_while(expr_not(expr_o_match_str()), st_break()), st_s_use()));
+ }
+
+ public void testDoWhile() {
+ assertOK(st_block(st_do_while(st_noop(), expr_not(expr_o_match_str())), st_s_use()));
+ assertFail("compiler.err.cant.resolve.location", st_block(st_do_while(st_break(), expr_not(expr_o_match_str())), st_s_use()));
+ }
+
+ public void testFor() {
+ assertOK(st_block(st_for(expr_empty(), expr_not(expr_o_match_str()), expr_empty(), st_noop()), st_s_use()));
+ assertFail("compiler.err.cant.resolve.location", st_block(st_for(expr_empty(), expr_not(expr_o_match_str()), expr_empty(), st_break()), st_s_use()));
+ }
+
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/patterns/scope/TEST.properties Fri Nov 29 10:02:07 2019 +0000
@@ -0,0 +1,6 @@
+TestNG.dirs = .
+
+lib.dirs = /lib/combo
+
+modules = \
+ jdk.compiler/com.sun.tools.javac.util
--- a/test/lib/sun/hotspot/WhiteBox.java Tue Nov 26 10:22:13 2019 +0000
+++ b/test/lib/sun/hotspot/WhiteBox.java Fri Nov 29 10:02:07 2019 +0000
@@ -222,6 +222,9 @@
public native long NMTMallocWithPseudoStackAndType(long size, int index, int type);
public native boolean NMTChangeTrackingLevel();
public native int NMTGetHashSize();
+ public native long NMTNewArena(long initSize);
+ public native void NMTFreeArena(long arena);
+ public native void NMTArenaMalloc(long arena, long size);
// Compiler
public native int matchesMethod(Executable method, String pattern);